feat: redesign drawer component with icon integration and refactor count section
This commit is contained in:
@@ -3,19 +3,23 @@ import { GearFineIcon } from "@phosphor-icons/react";
|
|||||||
interface DrawerSectionProps {
|
interface DrawerSectionProps {
|
||||||
id: string;
|
id: string;
|
||||||
title: string;
|
title: string;
|
||||||
count: string;
|
count: number;
|
||||||
|
subtext: string;
|
||||||
isOpen: boolean;
|
isOpen: boolean;
|
||||||
onClick: () => void;
|
onClick: () => void;
|
||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
|
icon: React.ReactNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function DrawerSection({
|
export function DrawerSection({
|
||||||
id,
|
id,
|
||||||
title,
|
title,
|
||||||
count,
|
count,
|
||||||
|
subtext,
|
||||||
isOpen,
|
isOpen,
|
||||||
onClick,
|
onClick,
|
||||||
children,
|
children,
|
||||||
|
icon,
|
||||||
}: DrawerSectionProps) {
|
}: DrawerSectionProps) {
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
@@ -23,20 +27,29 @@ export function DrawerSection({
|
|||||||
className={`join-item group flex flex-col transition-colors duration-3000 ease-in-out ${isOpen ? "bg-base-300/30" : ""}`}
|
className={`join-item group flex flex-col transition-colors duration-3000 ease-in-out ${isOpen ? "bg-base-300/30" : ""}`}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className={`transition-all duration-1500 ease-in-out bg-neutral/10 ${
|
className={`bg-neutral/10 transition-all duration-1000 ease-in-out overflow-visible ${isOpen ? "max-h-125" : "max-h-0 pointer-events-none"}`}
|
||||||
isOpen
|
|
||||||
? "max-h-125 opacity-100 py-3 border-b border-base-content/5 overflow-visible"
|
|
||||||
: "max-h-0 opacity-0 pointer-events-none"
|
|
||||||
}`}
|
|
||||||
>
|
>
|
||||||
{children}
|
<div
|
||||||
|
className={`transition-opacity ease-in-out ${
|
||||||
|
isOpen
|
||||||
|
? "opacity-100 py-3 border-b border-base-content/5 duration-700 delay-500"
|
||||||
|
: "opacity-0 duration-100"
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
{count === 0 && (
|
||||||
|
<div className="text-sm text-center text-neutral">
|
||||||
|
This drawer remains silent...
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={onClick}
|
onClick={onClick}
|
||||||
data-testid={`drawer-section-${id}`}
|
data-testid={`drawer-section-${id}`}
|
||||||
className={`w-full p-[24px_28px] cursor-pointer flex items-center gap-5 transition-all duration-2000 ease-in-out outline-none focus-visible:ring-2 focus-visible:ring-primary/50 border border-base-content/10 text-left bg-linear-to-r from-transparent to-base-100/40`}
|
className="w-full relative p-[24px_28px] cursor-pointer flex items-center gap-5 transition-all duration-2000 ease-in-out outline-none focus-visible:ring-2 overflow-hidden focus-visible:ring-primary/50 border border-base-content/10 text-left bg-linear-to-r from-transparent to-base-100/40"
|
||||||
>
|
>
|
||||||
<div className="flex-1">
|
<div className="flex-1">
|
||||||
<div
|
<div
|
||||||
@@ -48,8 +61,14 @@ export function DrawerSection({
|
|||||||
>
|
>
|
||||||
{title}
|
{title}
|
||||||
</div>
|
</div>
|
||||||
<div className="font-sans text-[0.6rem] text-base-content/20 mt-1">
|
<div className="font-sans text-xs text-base-content/20 mt-1">
|
||||||
{count}
|
<span className="font-mono text-xs md:text-base -mt-1 absolute text-primary/30">
|
||||||
|
{count}
|
||||||
|
</span>{" "}
|
||||||
|
<span className="ml-3">{subtext}</span>
|
||||||
|
</div>
|
||||||
|
<div className="absolute right-5 -translate-y-15 text-base-content/4">
|
||||||
|
{icon}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ export function LetterItem({
|
|||||||
data-testid={`letter-item-${id}`}
|
data-testid={`letter-item-${id}`}
|
||||||
className={`${isLocked ? "pointer-events-none" : ""} p-4 border-base-content/3 flex items-start gap-4 hover:bg-base-300 transition-all delay-75 duration-100 group text-left cursor-pointer w-9/12 mx-auto hover:scale-120 hover:h-24 hover:-translate-y-3 hover:pb-4 hover:border-x-5 hover:border-t-5 border-t-2 hover:-mb-2`}
|
className={`${isLocked ? "pointer-events-none" : ""} p-4 border-base-content/3 flex items-start gap-4 hover:bg-base-300 transition-all delay-75 duration-100 group text-left cursor-pointer w-9/12 mx-auto hover:scale-120 hover:h-24 hover:-translate-y-3 hover:pb-4 hover:border-x-5 hover:border-t-5 border-t-2 hover:-mb-2`}
|
||||||
>
|
>
|
||||||
<div className="text-[0.85rem] italic text-base-content/40 flex-1 truncate group-hover:text-base-content/60 transition-none animate-[opacity_200ms_linear_forwards]">
|
<div className="text-sm italic text-base-content/40 flex-1 truncate group-hover:text-base-content/60">
|
||||||
{preview}
|
{preview}
|
||||||
</div>
|
</div>
|
||||||
{unlock_at ? (
|
{unlock_at ? (
|
||||||
@@ -53,7 +53,7 @@ export function LetterItem({
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div className="font-sans text-[0.6rem] text-base-content/20 transition-none">
|
<div className="font-sans text-xs text-base-content/20">
|
||||||
{timestamp}
|
{timestamp}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -1,4 +1,10 @@
|
|||||||
import { FeatherIcon } from "@phosphor-icons/react";
|
import {
|
||||||
|
ArchiveIcon,
|
||||||
|
FeatherIcon,
|
||||||
|
FileDashedIcon,
|
||||||
|
PaperPlaneTiltIcon,
|
||||||
|
VaultIcon,
|
||||||
|
} from "@phosphor-icons/react";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import { useLocation, useNavigate } from "react-router-dom";
|
import { useLocation, useNavigate } from "react-router-dom";
|
||||||
import { DrawerSection } from "../components/drawer/DrawerSection.tsx";
|
import { DrawerSection } from "../components/drawer/DrawerSection.tsx";
|
||||||
@@ -47,7 +53,7 @@ export default function Drawer() {
|
|||||||
|
|
||||||
{isAuthRequired && <PasskeyModal />}
|
{isAuthRequired && <PasskeyModal />}
|
||||||
<header className="text-center mb-12 z-10 animate-in fade-in slide-in-from-top-4 duration-500">
|
<header className="text-center mb-12 z-10 animate-in fade-in slide-in-from-top-4 duration-500">
|
||||||
<Logo />
|
<Logo type="logo" />
|
||||||
<div className="font-sans text-xs tracking-widester uppercase text-base-content/40 mt-2">
|
<div className="font-sans text-xs tracking-widester uppercase text-base-content/40 mt-2">
|
||||||
Personal Archive
|
Personal Archive
|
||||||
</div>
|
</div>
|
||||||
@@ -77,9 +83,11 @@ export default function Drawer() {
|
|||||||
<DrawerSection
|
<DrawerSection
|
||||||
id="drafts"
|
id="drafts"
|
||||||
title="Drafts"
|
title="Drafts"
|
||||||
count={`${drafts.length} unfinished whispers`}
|
count={drafts.length}
|
||||||
|
subtext="unfinished whispers"
|
||||||
isOpen={openSection === "drafts"}
|
isOpen={openSection === "drafts"}
|
||||||
onClick={() => toggleSection("drafts")}
|
onClick={() => toggleSection("drafts")}
|
||||||
|
icon={<FileDashedIcon weight="thin" size={128} />}
|
||||||
>
|
>
|
||||||
{drafts.map((draft) => (
|
{drafts.map((draft) => (
|
||||||
<LetterItem
|
<LetterItem
|
||||||
@@ -95,9 +103,11 @@ export default function Drawer() {
|
|||||||
<DrawerSection
|
<DrawerSection
|
||||||
id="kept"
|
id="kept"
|
||||||
title="Kept"
|
title="Kept"
|
||||||
count={`${kept.length} private letters`}
|
count={kept.length}
|
||||||
|
subtext="private letters"
|
||||||
isOpen={openSection === "kept"}
|
isOpen={openSection === "kept"}
|
||||||
onClick={() => toggleSection("kept")}
|
onClick={() => toggleSection("kept")}
|
||||||
|
icon={<ArchiveIcon weight="thin" size={128} />}
|
||||||
>
|
>
|
||||||
{kept.map((letter) => (
|
{kept.map((letter) => (
|
||||||
<LetterItem
|
<LetterItem
|
||||||
@@ -112,9 +122,11 @@ export default function Drawer() {
|
|||||||
<DrawerSection
|
<DrawerSection
|
||||||
id="sent"
|
id="sent"
|
||||||
title="Sent"
|
title="Sent"
|
||||||
count={`${sent.length} shared truths`}
|
count={sent.length}
|
||||||
|
subtext="shared truths"
|
||||||
isOpen={openSection === "sent"}
|
isOpen={openSection === "sent"}
|
||||||
onClick={() => toggleSection("sent")}
|
onClick={() => toggleSection("sent")}
|
||||||
|
icon={<PaperPlaneTiltIcon weight="thin" size={128} />}
|
||||||
>
|
>
|
||||||
{sent.map((letter) => (
|
{sent.map((letter) => (
|
||||||
<LetterItem
|
<LetterItem
|
||||||
@@ -125,18 +137,15 @@ export default function Drawer() {
|
|||||||
timestamp={formatRelativeDate(letter.updated_at)}
|
timestamp={formatRelativeDate(letter.updated_at)}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
{sent.length === 0 && (
|
|
||||||
<p className="text-center text-base-content/20 mt-4">
|
|
||||||
This drawer remains silent
|
|
||||||
</p>
|
|
||||||
)}
|
|
||||||
</DrawerSection>
|
</DrawerSection>
|
||||||
<DrawerSection
|
<DrawerSection
|
||||||
id="vault"
|
id="vault"
|
||||||
title="Vault"
|
title="Vault"
|
||||||
count={`${vault.length} things locked;not lost;in time`}
|
count={vault.length}
|
||||||
|
subtext="things locked—not lost—in time"
|
||||||
isOpen={openSection === "vault"}
|
isOpen={openSection === "vault"}
|
||||||
onClick={() => toggleSection("vault")}
|
onClick={() => toggleSection("vault")}
|
||||||
|
icon={<VaultIcon weight="thin" size={128} />}
|
||||||
>
|
>
|
||||||
{vault.map((letter) => (
|
{vault.map((letter) => (
|
||||||
<LetterItem
|
<LetterItem
|
||||||
@@ -179,7 +188,7 @@ export default function Drawer() {
|
|||||||
</span>
|
</span>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<footer className="mt-25 font-sans text-[0.6rem] tracking-widester uppercase text-base-content/10 z-10">
|
<footer className="mt-25 font-sans text-xs tracking-widester uppercase text-base-content/10 z-10">
|
||||||
For your unsaid.
|
For your unsaid.
|
||||||
</footer>
|
</footer>
|
||||||
{!showWelcomeLetter && (
|
{!showWelcomeLetter && (
|
||||||
|
|||||||
Reference in New Issue
Block a user