add: dark theme to a few components

This commit is contained in:
Mahyar Khanbolooki
2025-08-12 19:01:54 +03:30
parent e92c33963d
commit 5936f66665
7 changed files with 92 additions and 53 deletions
+3 -3
View File
@@ -310,16 +310,16 @@ const MenuIndex = () => {
selectedId={selectedDeliveryId} selectedId={selectedDeliveryId}
onSelectionChange={changeSelectedDelivery} /> onSelectionChange={changeSelectedDelivery} />
<div <div
className="flex w-full mt-[23px] h-11 items-center justify-between gap-2 px-3 py-4 relative bg-white/29 rounded-xl border border-solid border-neutral-200 cursor-pointer focus:outline-none focus:ring-2 focus:ring-black" className="flex w-full mt-[23px] h-11 items-center justify-between gap-2 px-3 py-4 relative bg-container/29 rounded-xl border border-solid border-border cursor-pointer focus:outline-none focus:ring-2 focus:ring-black"
> >
<span className="inline-flex items-center gap-2.5 text-sm2"> <span className="inline-flex items-center gap-2.5 text-sm2">
<MedalStar size="16" color="#333333" /> <MedalStar size="16" className="stroke-foreground" />
{tMenu('MenuFilterDrawer.PlusPoint')} {tMenu('MenuFilterDrawer.PlusPoint')}
</span> </span>
<Switch className="w-12 h-6" /> <Switch className="w-12 h-6" />
</div> </div>
<div <div
className="flex w-full mt-[23px] h-11 items-center justify-between gap-2 px-3 py-4 relative bg-white/29 rounded-xl border border-solid border-neutral-200 cursor-pointer focus:outline-none focus:ring-2 focus:ring-black" className="flex w-full mt-[23px] h-11 items-center justify-between gap-2 px-3 py-4 relative bg-container/29 rounded-xl border border-solid border-border cursor-pointer focus:outline-none focus:ring-2 focus:ring-black"
> >
<span className="inline-flex items-center gap-2.5 text-sm2"> <span className="inline-flex items-center gap-2.5 text-sm2">
<TicketPercentIcon size={16} /> <TicketPercentIcon size={16} />
+74 -35
View File
@@ -147,7 +147,14 @@ input:autofill {
} }
@theme inline { @theme {
--font-irancell: var(--font-irancell);
--radius-normal: var(--radius-normal);
--text-sm2: var(--text-sm2);
--text-xs2: var(--text-xs2);
--radius-container: var(--radius-container);
--color-background: var(--background); --color-background: var(--background);
--color-foreground: var(--foreground); --color-foreground: var(--foreground);
--color-card: var(--card); --color-card: var(--card);
@@ -179,12 +186,37 @@ input:autofill {
--color-sidebar-accent-foreground: var(--sidebar-accent-foreground); --color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
--color-sidebar-border: var(--sidebar-border); --color-sidebar-border: var(--sidebar-border);
--color-sidebar-ring: var(--sidebar-ring); --color-sidebar-ring: var(--sidebar-ring);
--color-background: var(--background); /* oklch(0.963 0.008 289.2) */
--color-container: var(--container); /* oklch(1 0 0) */
--color-primary: var(--primary); /* oklch(0.14 0 0) */
--color-border: var(--border); /* oklch(0.885 0.007 248.3) */
--color-invalid: var(--invalid); /* oklch(0.515 0.118 27.5) */
--color-valid: var(--valid); /* oklch(0.46 0.107 132.7) */
--color-foreground: var(--foreground); /* oklch(0.202 0 0) */
--color-disabled: var(--disabled); /* oklch(0.91 0.004 295.2) */
--color-disabled2: var(--disabled2); /* oklch(0.5 0 0) */
--color-disabled3: var(--disabled3); /* oklch(0.949 0.002 277.1) */
--color-disabled-text: var(--disabled-text); /* oklch(0.34 0.006 257.4) */
--color-menu-header: var(--menu-header); /* oklch(0.79 0.03 237.3) */
--color-icon-deactive: var(--icon-deactive); /* oklch(0.65 0.027 234.8) */
--color-icon-active: var(--icon-active); /* oklch(0.12 0.002 304.5) */
} }
:root { /* unified theme */
--radius: 0.625rem; :root {
--font-irancell: "Irancell";
--radius-normal: 10px;
--text-sm2: 13px;
--text-xs2: 10px;
--radius-container: 24px;
}
html[data-theme="light"] {
/* --radius: 0.625rem;
--background: oklch(1 0 0); --background: oklch(1 0 0);
--foreground: oklch(0.145 0 0); --foreground: oklch(21% 0.006 285.885);
--card: oklch(1 0 0); --card: oklch(1 0 0);
--card-foreground: oklch(0.145 0 0); --card-foreground: oklch(0.145 0 0);
--popover: oklch(1 0 0); --popover: oklch(1 0 0);
@@ -193,12 +225,12 @@ input:autofill {
--primary-foreground: oklch(0.985 0 0); --primary-foreground: oklch(0.985 0 0);
--secondary: oklch(0.97 0 0); --secondary: oklch(0.97 0 0);
--secondary-foreground: oklch(0.205 0 0); --secondary-foreground: oklch(0.205 0 0);
--muted: oklch(0.97 0 0); --muted: oklch(0.928 0 0);
--muted-foreground: oklch(0.556 0 0); --muted-foreground: oklch(0.556 0 0);
--accent: oklch(0.97 0 0); --accent: oklch(0.97 0 0);
--accent-foreground: oklch(0.205 0 0); --accent-foreground: oklch(0.205 0 0);
--destructive: oklch(0.577 0.245 27.325); --destructive: oklch(0.577 0.245 27.325);
--border: oklch(0.922 0 0); --border: oklch(0.9219 0 0);
--input: oklch(0.922 0 0); --input: oklch(0.922 0 0);
--ring: oklch(0.708 0 0); --ring: oklch(0.708 0 0);
--chart-1: oklch(0.646 0.222 41.116); --chart-1: oklch(0.646 0.222 41.116);
@@ -213,11 +245,26 @@ input:autofill {
--sidebar-accent: oklch(0.97 0 0); --sidebar-accent: oklch(0.97 0 0);
--sidebar-accent-foreground: oklch(0.205 0 0); --sidebar-accent-foreground: oklch(0.205 0 0);
--sidebar-border: oklch(0.922 0 0); --sidebar-border: oklch(0.922 0 0);
--sidebar-ring: oklch(0.708 0 0); --sidebar-ring: oklch(0.708 0 0); */
--background: oklch(0.963 0.008 289.2); /* #F4F5F9 */
--container: oklch(1 0 0); /* #FFFFFF */
--primary: oklch(0.14 0 0); /* #000000 */
--border: oklch(0.885 0.007 248.3); /* #E5E5E5 */
--invalid: oklch(0.515 0.118 27.5); /* red (#FF0000 approx) */
--valid: oklch(0.46 0.107 132.7); /* #439C46 */
--foreground: oklch(0.202 0 0); /* #333333 */
--disabled: oklch(0.91 0.004 295.2); /* #E7E7E7 */
--disabled2: oklch(0.5 0 0); /* #7F7F7F */
--disabled3: oklch(0.949 0.002 277.1); /* #F2F2F2 */
--disabled-text: oklch(0.34 0.006 257.4); /* #8C90A3 */
--menu-header: oklch(0.79 0.03 237.3); /* #C3C7DD */
--icon-deactive: oklch(0.65 0.027 234.8); /* #A8ABBF */
--icon-active: oklch(0.12 0.002 304.5); /* #292D32 */
} }
.dark { html[data-theme="dark"] {
--background: oklch(0.145 0 0); /* --background: oklch(0.145 0 0);
--foreground: oklch(0.985 0 0); --foreground: oklch(0.985 0 0);
--card: oklch(0.205 0 0); --card: oklch(0.205 0 0);
--card-foreground: oklch(0.985 0 0); --card-foreground: oklch(0.985 0 0);
@@ -247,10 +294,25 @@ input:autofill {
--sidebar-accent: oklch(0.269 0 0); --sidebar-accent: oklch(0.269 0 0);
--sidebar-accent-foreground: oklch(0.985 0 0); --sidebar-accent-foreground: oklch(0.985 0 0);
--sidebar-border: oklch(1 0 0 / 10%); --sidebar-border: oklch(1 0 0 / 10%);
--sidebar-ring: oklch(0.556 0 0); --sidebar-ring: oklch(0.556 0 0); */
--background: oklch(23.26% 0.014 253.1); /* #F4F5F9 */
--container: oklch(25.33% 0.016 252.42); /* #FFFFFF */
--primary: oklch(14% 0.005 285.823); /* #000000 */
--border: oklch(21.15% 0.012 254.09); /* #E5E5E5 */
--invalid: oklch(0.515 0.118 27.5); /* red (#FF0000 approx) */
--valid: oklch(0.46 0.107 132.7); /* #439C46 */
--foreground: oklch(97.807% 0.029 256.847); /* #333333 */
--disabled: oklch(42.866% 0.00494 286.051); /* #E7E7E7 */
--disabled2: oklch(0.5 0 0); /* #7F7F7F */
--disabled3: oklch(0.949 0.002 277.1); /* #F2F2F2 */
--disabled-text: oklch(75.73% 0.01398 251.72); /* #8C90A3 */
--menu-header: oklch(0.79 0.03 237.3); /* #C3C7DD */
--icon-deactive: oklch(0.65 0.027 234.8); /* #A8ABBF */
--icon-active: oklch(0.12 0.002 304.5); /* #292D32 */
} }
@layer base { /* @layer base {
* { * {
@apply border-border outline-ring/50; @apply border-border outline-ring/50;
} }
@@ -258,27 +320,4 @@ input:autofill {
body { body {
@apply bg-background text-foreground; @apply bg-background text-foreground;
} }
} } */
@theme {
--font-irancell: "Irancell";
--color-background: #F4F5F9;
--color-container: #FFFFFF;
--color-primary: #000000;
--color-border: #E5E5E5;
--color-invalid: red;
--color-valid: #439C46;
--color-foreground: #333333;
--color-disabled: #E7E7E7;
--color-disabled2: #7F7F7F;
--color-disabled3: #F2F2F2;
--color-disabled-text: #8C90A3;
--color-menu-header: #C3C7DD;
--color-icon-deactive: #A8ABBF;
--color-icon-active: #292D32;
--radius-normal: 10px;
--text-sm2: 13px;
--text-xs2: 10px;
--radius-container: 24px;
}
@@ -53,7 +53,7 @@ const AnimatedBottomSheet = ({ blurOpacity = 64, overrideClassName = '', showTit
overrideClassName ?? '', overrideClassName ?? '',
'absolute left-0 w-full rounded-t-4xl pt-[39px] pb-6', 'absolute left-0 w-full rounded-t-4xl pt-[39px] pb-6',
'bottom-0', 'bottom-0',
'bg-container/64' 'bg-container/64 dark:bg-container/80'
)} )}
initial="hidden" initial="hidden"
animate={props.visible ? 'visible' : 'hidden'} animate={props.visible ? 'visible' : 'hidden'}
@@ -61,12 +61,12 @@ const AnimatedBottomSheet = ({ blurOpacity = 64, overrideClassName = '', showTit
> >
<div className="ps-[31px] pe-[33px] flex justify-between"> <div className="ps-[31px] pe-[33px] flex justify-between">
{showTitle && {showTitle &&
<div className='text-lg font-medium text-black leading-8 mt-2.5'> <div className='text-lg font-medium text-foreground leading-8 mt-2.5'>
{props.title} {props.title}
</div> </div>
} }
{showCloseButton && {showCloseButton &&
<div ref={closeRef} onClick={props.onClick} className="bg-white/38 w-8 h-8 rounded-full p-1.5"> <div ref={closeRef} onClick={props.onClick} className="bg-container/38 w-8 h-8 rounded-full p-1.5">
<CloseIcon size={20} /> <CloseIcon size={20} />
</div> </div>
} }
+3 -3
View File
@@ -16,14 +16,14 @@ function Button({ children, className, disabled, pending, ...rest }: Props) {
disabled={disabled} disabled={disabled}
className={clsx( className={clsx(
className, className,
disabled ? 'bg-disabled text-disabled-text' : 'bg-primary text-white hover:bg-[#222222] active:brightness-110', disabled ? 'bg-disabled text-disabled-text' : 'bg-primary text-background dark:text-foreground hover:bg-primary/60 active:brightness-110',
pending && 'bg-transparent! text-transparent! cursor-auto!', pending && 'bg-transparent! text-transparent! cursor-auto!',
'relative transition-all duration-200 cursor-pointer w-full rounded-normal p-3 font-normal text-sm overflow-clip' 'relative transition-all duration-200 cursor-pointer w-full rounded-normal p-3 font-normal text-sm overflow-clip'
)} )}
{...rest} {...rest}
> >
<motion.div <motion.div
className='absolute left-0 top-0 h-full w-full bg-neutral-200' className='absolute left-0 top-0 h-full w-full bg-border'
initial={{ y: '100%' }} initial={{ y: '100%' }}
animate={!pending ? { y: '100%' } : { y: 0 }} animate={!pending ? { y: '100%' } : { y: 0 }}
> >
@@ -33,7 +33,7 @@ function Button({ children, className, disabled, pending, ...rest }: Props) {
whileHover={{ scale: 1.1 }} whileHover={{ scale: 1.1 }}
whileTap={{ scale: 0.9 }} whileTap={{ scale: 0.9 }}
className='-translate-x-1/2 -translate-y-1/2 top-1/2 left-1/2 absolute'> className='-translate-x-1/2 -translate-y-1/2 top-1/2 left-1/2 absolute'>
<Refresh stroke='#333333' size={24} /> <Refresh className='stroke-foreground' size={24} />
</motion.div> </motion.div>
</motion.div> </motion.div>
{children} {children}
+5 -5
View File
@@ -97,7 +97,7 @@ function Combobox({ title, options, placeholder, icon: Icon, expanded, selectedI
{...props} {...props}
> >
<div <div
className="flex w-full h-11 items-center justify-end gap-2 px-3 py-4 relative bg-white/29 rounded-xl border border-solid border-neutral-200 cursor-pointer" className="flex w-full h-11 items-center justify-end gap-2 px-3 py-4 relative bg-container/29 rounded-xl border border-solid border-border cursor-pointer"
tabIndex={0} tabIndex={0}
onClick={toggleExpand} onClick={toggleExpand}
role="combobox" role="combobox"
@@ -110,7 +110,7 @@ function Combobox({ title, options, placeholder, icon: Icon, expanded, selectedI
htmlFor="content-select" htmlFor="content-select"
className="pointer-events-none inline-flex flex-col items-end justify-center px-1 py-0 absolute -top-6 right-0 z-[2]" className="pointer-events-none inline-flex flex-col items-end justify-center px-1 py-0 absolute -top-6 right-0 z-[2]"
> >
<span className="relative w-fit mt-[-1px] text-xs tracking-[0] leading-4 whitespace-nowrap"> <span className="relative text-foreground w-fit mt-[-1px] text-xs tracking-[0] leading-4 whitespace-nowrap">
{title} {title}
</span> </span>
</label> </label>
@@ -137,7 +137,7 @@ function Combobox({ title, options, placeholder, icon: Icon, expanded, selectedI
<motion.div <motion.div
data-expand={expand} data-expand={expand}
aria-hidden={!expand} aria-hidden={!expand}
className="absolute top-full left-0 w-full mt-1 text-foreground bg-white rounded-xl outline outline-solid outline-neutral-200 shadow-lg z-10" className="absolute top-full left-0 w-full mt-1 text-foreground bg-container rounded-xl outline outline-solid outline-border shadow-lg z-10"
role="listbox" role="listbox"
aria-label={`${title} options`} aria-label={`${title} options`}
onClick={(e) => e.stopPropagation()} onClick={(e) => e.stopPropagation()}
@@ -147,7 +147,7 @@ function Combobox({ title, options, placeholder, icon: Icon, expanded, selectedI
> >
{searchable && {searchable &&
<div className="w-full flex gap-2 border-b px-3 items-center"> <div className="w-full flex gap-2 border-b border-border px-3 items-center">
<SearchNormal size={16} className='stroke-gray-400' /> <SearchNormal size={16} className='stroke-gray-400' />
<input <input
placeholder="جستجو ..." placeholder="جستجو ..."
@@ -165,7 +165,7 @@ function Combobox({ title, options, placeholder, icon: Icon, expanded, selectedI
onClick={(e) => setSelection(e, i)} onClick={(e) => setSelection(e, i)}
key={v.id} key={v.id}
data-selected={v.id === selectedId} data-selected={v.id === selectedId}
className="flex gap-3 items-center justify-end px-2 py-1 cursor-pointer hover:bg-gray-50 rounded-md last:rounded-b-xl" className="flex gap-3 items-center justify-end px-2 py-1 cursor-pointer hover:bg-current/10 rounded-md last:rounded-b-xl"
tabIndex={0} tabIndex={0}
role="option" role="option"
aria-selected aria-selected
+2 -2
View File
@@ -14,7 +14,7 @@ function Switch({
dir="ltr" dir="ltr"
data-slot="switch" data-slot="switch"
className={cn( className={cn(
"cursor-pointer peer data-[state=checked]:bg-primary data-[state=unchecked]:bg-input focus-visible:border-ring focus-visible:ring-ring/50 dark:data-[state=unchecked]:bg-input/80 inline-flex h-6 w-12 shrink-0 items-center rounded-full border border-transparent shadow-xs transition-all outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50", "cursor-pointer peer dark:data-[state=unchecked]:bg-neutral-600 dark:data-[state=checked]:bg-primary/80 data-[state=checked]:bg-primary data-[state=unchecked]:bg-input focus-visible:border-ring focus-visible:ring-ring/50 inline-flex h-6 w-12 shrink-0 items-center rounded-full border border-transparent shadow-xs transition-all outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50",
className className
)} )}
{...props} {...props}
@@ -22,7 +22,7 @@ function Switch({
<SwitchPrimitive.Thumb <SwitchPrimitive.Thumb
data-slot="switch-thumb" data-slot="switch-thumb"
className={cn( className={cn(
"bg-background dark:data-[state=unchecked]:bg-foreground dark:data-[state=checked]:bg-primary-foreground pointer-events-none block size-5 rounded-full ring-0 transition-transform data-[state=checked]:translate-x-[calc(140%-3px)] data-[state=unchecked]:translate-x-[1px]" "bg-background dark:data-[state=checked]:bg-foreground dark:data-[state=unchecked]:bg-border pointer-events-none block size-5 rounded-full ring-0 transition-transform data-[state=checked]:translate-x-[calc(140%-3px)] data-[state=unchecked]:translate-x-[1px]"
)} )}
/> />
</SwitchPrimitive.Root> </SwitchPrimitive.Root>
@@ -42,14 +42,14 @@ function ClientMenuRouteWrapper({ children }: Props) {
}, [location]) }, [location])
useEffect(() => { useEffect(() => {
const theme = nightMode || window.matchMedia("(prefers-color-scheme: dark)").matches; const theme = nightMode// || window.matchMedia("(prefers-color-scheme: dark)").matches;
document.documentElement.setAttribute("data-theme", theme ? "dark" : "light"); document.documentElement.setAttribute("data-theme", theme ? "dark" : "light");
}, [nightMode]); }, [nightMode]);
return ( return (
<div className="h-svh overflow-hidden pt-10 flex flex-col pb-4 xl:pt-12"> <div className="h-svh overflow-hidden pt-10 flex flex-col pb-4 xl:pt-12">
<div className="z-50 fixed right-4 left-4 xl:right-[285px] top-4 xl:h-16 h-12 flex items-center px-4 bg-white justify-between rounded-[32px] xl:w-[calc(100%-305px)]"> <div className="z-50 fixed right-4 left-4 xl:right-[285px] top-4 xl:h-16 h-12 flex items-center px-4 bg-container justify-between rounded-[32px] xl:w-[calc(100%-305px)]">
<TopBar <TopBar
profileDropState={profileDrop} profileDropState={profileDrop}
toggleProfileDropState={toggleProfileDrop} toggleProfileDropState={toggleProfileDrop}