From f3b11eebe89de537cabfde0d1c773ca77b9f3999 Mon Sep 17 00:00:00 2001 From: Lloyd Richards <59728961+lloydrichards@users.noreply.github.com> Date: Mon, 12 Feb 2024 21:21:08 +0100 Subject: [PATCH] =?UTF-8?q?feat:=20=E2=9C=A8=20multi-theme=20and=20design?= =?UTF-8?q?=20tokens=20(#73)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * refactor(tokens): :recycle: abstract theme into tokens * feat(tokens): :lipstick: add warning, info and success variants to badge and toast * feat(theme): :lipstick: add theme selector and three themes * style(theme): :lipstick: setup multiple themes; light and dark * refactor(tokens): :recycle: abstract out stroke and shadow into tokens --- src/app/layout.tsx | 12 +- src/components/atom/badge/badge.stories.tsx | 28 ++ src/components/atom/badge/badge.tsx | 5 + src/components/atom/placeholder.tsx | 8 +- src/components/atom/toast/toast.stories.tsx | 51 +++- src/components/atom/toast/toast.tsx | 4 + .../{mode-toggle.tsx => theme-toggle.tsx} | 26 +- src/components/template/layout/navbar.tsx | 4 +- src/components/tokens/colors.stories.tsx | 169 +++++++++--- src/styles/globals.css | 164 ++++++++---- src/styles/root.css | 241 ++++++++++++++++++ src/styles/theme/dark-classic.css | 41 +++ src/styles/theme/dark-midnight.css | 54 ++++ src/styles/theme/dark-professional.css | 54 ++++ src/styles/theme/light-acid.css | 51 ++++ src/styles/theme/light-professional.css | 40 +++ src/styles/theme/light-soft.css | 38 +++ tailwind.config.ts | 31 ++- 18 files changed, 898 insertions(+), 123 deletions(-) rename src/components/molecule/{mode-toggle.tsx => theme-toggle.tsx} (57%) create mode 100644 src/styles/root.css create mode 100644 src/styles/theme/dark-classic.css create mode 100644 src/styles/theme/dark-midnight.css create mode 100644 src/styles/theme/dark-professional.css create mode 100644 src/styles/theme/light-acid.css create mode 100644 src/styles/theme/light-professional.css create mode 100644 src/styles/theme/light-soft.css diff --git a/src/app/layout.tsx b/src/app/layout.tsx index 9ea0e32..f2014f1 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -41,10 +41,18 @@ export default function RootLayout({ > {children} diff --git a/src/components/atom/badge/badge.stories.tsx b/src/components/atom/badge/badge.stories.tsx index ba01bc7..20aa741 100644 --- a/src/components/atom/badge/badge.stories.tsx +++ b/src/components/atom/badge/badge.stories.tsx @@ -51,6 +51,34 @@ export const Destructive: Story = { }, }; +/** + * Use the `warning` badge to indicate caution or a warning that requires + * attention. + */ +export const Warning: Story = { + args: { + variant: "warning", + }, +}; + +/** + * Use the `success` badge to indicate success or a positive change. + */ +export const Success: Story = { + args: { + variant: "success", + }, +}; + +/** + * Use the `info` badge to indicate information or a neutral change. + */ +export const Info: Story = { + args: { + variant: "info", + }, +}; + /** * Use the `outline` badge for overlaying without obscuring interface details, * emphasizing clarity and subtlety.. diff --git a/src/components/atom/badge/badge.tsx b/src/components/atom/badge/badge.tsx index d3d5d60..66ae9b4 100644 --- a/src/components/atom/badge/badge.tsx +++ b/src/components/atom/badge/badge.tsx @@ -14,6 +14,11 @@ const badgeVariants = cva( "border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80", destructive: "border-transparent bg-destructive text-destructive-foreground hover:bg-destructive/80", + warning: + "border-transparent bg-warning text-warning-foreground hover:bg-warning/80", + success: + "border-transparent bg-success text-success-foreground hover:bg-success/80", + info: "border-transparent bg-info text-info-foreground hover:bg-info/80", outline: "text-foreground", }, }, diff --git a/src/components/atom/placeholder.tsx b/src/components/atom/placeholder.tsx index c3e973d..aa2b39e 100644 --- a/src/components/atom/placeholder.tsx +++ b/src/components/atom/placeholder.tsx @@ -5,16 +5,16 @@ import { typefaceValue2 } from "../typeface"; const PlaceholderIcon = { image: ( - + ), icon: ( - + ), text: ( - + ), chart: ( - + ), }; export const Placeholder = React.forwardRef< diff --git a/src/components/atom/toast/toast.stories.tsx b/src/components/atom/toast/toast.stories.tsx index 5cad97f..7417e4d 100644 --- a/src/components/atom/toast/toast.stories.tsx +++ b/src/components/atom/toast/toast.stories.tsx @@ -3,6 +3,7 @@ import type { Meta, StoryObj } from "@storybook/react"; import { Toast, ToastAction, ToastActionElement, ToastProps } from "./toast"; import { Toaster } from "./toaster"; import { useToast } from "../../../hooks/use-toast"; +import { Button } from "../button/button"; /** * A succinct message that is displayed temporarily. @@ -13,9 +14,17 @@ const meta = { tags: ["autodocs"], argTypes: {}, parameters: { - layout: "centered", + layout: "fullscreen", }, render: (args) => , + decorators: [ + (Story) => ( +
+ + +
+ ), + ], } satisfies Meta; export default meta; @@ -34,16 +43,14 @@ type ToasterToast = ToastProps & { const ToastExample = (args: Story["args"]) => { const { toast } = useToast(); return ( -
- - -
+ ); }; @@ -88,3 +95,25 @@ export const Destructive: Story = { action: Try again, }, }; + +/** + * Use the `warning` variant to indicate a warning. + */ +export const Warning: Story = { + args: { + variant: "warning", + title: "Looks like you missed something!", + description: "Please fill out all required fields.", + }, +}; + +/** + * Use the `success` variant to indicate a successful action. + */ +export const Success: Story = { + args: { + variant: "success", + title: "Success!", + description: "Your message has been sent.", + }, +}; diff --git a/src/components/atom/toast/toast.tsx b/src/components/atom/toast/toast.tsx index 5a12c40..49b0e23 100644 --- a/src/components/atom/toast/toast.tsx +++ b/src/components/atom/toast/toast.tsx @@ -30,6 +30,10 @@ const toastVariants = cva( default: "border bg-background text-foreground", destructive: "destructive group border-destructive bg-destructive text-destructive-foreground", + warning: + "warning group border-warning bg-warning text-warning-foreground", + success: + "success group border-success bg-success text-success-foreground", }, }, defaultVariants: { diff --git a/src/components/molecule/mode-toggle.tsx b/src/components/molecule/theme-toggle.tsx similarity index 57% rename from src/components/molecule/mode-toggle.tsx rename to src/components/molecule/theme-toggle.tsx index bb3a598..801ef4f 100644 --- a/src/components/molecule/mode-toggle.tsx +++ b/src/components/molecule/theme-toggle.tsx @@ -9,10 +9,11 @@ import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, + DropdownMenuSeparator, DropdownMenuTrigger, } from "@/components/atom/dropdown-menu/dropdown-menu"; -export function ModeToggle() { +export function ThemeToggle() { const { setTheme } = useTheme(); return ( @@ -26,13 +27,26 @@ export function ModeToggle() { setTheme("light")}> - Light + Classic (Light) - setTheme("dark")}> - Dark + setTheme("dark-classic")}> + Classic (Dark) - setTheme("system")}> - System + + setTheme("light-professional")}> + Professional + + setTheme("dark-professional")}> + Professional (Dark) + + setTheme("light-soft")}> + Soft + + setTheme("light-acid")}> + Acid + + setTheme("dark-midnight")}> + Midnight (Dark) diff --git a/src/components/template/layout/navbar.tsx b/src/components/template/layout/navbar.tsx index 5ec0cba..374331f 100644 --- a/src/components/template/layout/navbar.tsx +++ b/src/components/template/layout/navbar.tsx @@ -1,7 +1,7 @@ "use client"; import { buttonVariants } from "@/components/atom/button/button"; -import { ModeToggle } from "@/components/molecule/mode-toggle"; +import { ThemeToggle } from "@/components/molecule/theme-toggle"; import { NavigationMenu, NavigationMenuContent, @@ -95,7 +95,7 @@ const NavRoutes: FC = ({ vertical }) => { - + ); }; diff --git a/src/components/tokens/colors.stories.tsx b/src/components/tokens/colors.stories.tsx index dcf89bd..366f9d1 100644 --- a/src/components/tokens/colors.stories.tsx +++ b/src/components/tokens/colors.stories.tsx @@ -11,99 +11,186 @@ export default meta; type Story = StoryObj; -export const Functional: Story = { +export const Core: Story = { render: () => ( + + ), +}; + +export const Functional: Story = { + render: () => ( + + + + + + + + + ), diff --git a/src/styles/globals.css b/src/styles/globals.css index e8ebb89..a7d0240 100644 --- a/src/styles/globals.css +++ b/src/styles/globals.css @@ -4,66 +4,118 @@ @layer base { :root { - --background: 0 0% 100%; - --foreground: 222.2 84% 4.9%; - - --card: 0 0% 100%; - --card-foreground: 222.2 84% 4.9%; - - --popover: 0 0% 100%; - --popover-foreground: 222.2 84% 4.9%; - - --primary: 222.2 47.4% 11.2%; - --primary-foreground: 210 40% 98%; - - --secondary: 210 40% 96.1%; - --secondary-foreground: 222.2 47.4% 11.2%; - - --muted: 210 40% 96.1%; - --muted-foreground: 215.4 16.3% 46.9%; - - --accent: 210 40% 96.1%; - --accent-foreground: 222.2 47.4% 11.2%; - - --destructive: 0 84.2% 60.2%; - --destructive-foreground: 210 40% 98%; - - --border: 214.3 31.8% 91.4%; - --input: 214.3 31.8% 91.4%; - --ring: 222.2 84% 4.9%; + /* Core Colors */ + --color-white: 0 0% 100%; /* #ffffff */ + + --color-mono-050: 210 40% 98%; /* #f8fafc */ + --color-mono-100: 210 40% 96.1%; /* #f1f5f9 */ + --color-mono-200: 214.3 31.8% 91.4%; /* #e2e8f0 */ + --color-mono-300: 212.7 26.8% 83%; /* #cbd5e1 */ + --color-mono-400: 215 20.2% 65.1%; /* #94a3b8 */ + --color-mono-500: 215.4 16.3% 46.9%; /* #64748b */ + --color-mono-600: 215.3 19.3% 34.5%; /* #475569 */ + --color-mono-700: 215.3 25% 26.7%; /* #334155 */ + --color-mono-800: 217.2 32.6% 17.5%; /* #1e293b */ + --color-mono-900: 222.2 47.4% 11.2%; /* #0f172a */ + + --color-primary-050: 151.8 81% 95.9%; /* #ecfdf5 */ + --color-primary-100: 149.3 80.4% 90%; /* #d1fae5 */ + --color-primary-200: 152.4 76% 80.4%; /* #a7f3d0 */ + --color-primary-300: 156.2 71.6% 66.9%; /* #6ee7b7 */ + --color-primary-400: 158.1 64.4% 51.6%; /* #34d399 */ + --color-primary-500: 160.1 84.1% 39.4%; /* #10b981 */ + --color-primary-600: 161.4 93.5% 30.4%; /* #059669 */ + --color-primary-700: 162.9 93.5% 24.3%; /* #047857 */ + --color-primary-800: 163.1 88.1% 19.8%; /* #065f46 */ + --color-primary-900: 164.2 85.7% 16.5%; /* #064e3b */ + + --color-secondary-050: 48 100% 96.1%; /* #fffbeb */ + --color-secondary-100: 48 96.5% 88.8%; /* #fef3c7 */ + --color-secondary-200: 48 96.6% 76.7%; /* #fde68a */ + --color-secondary-300: 45.9 96.7% 64.5%; /* #fcd34d */ + --color-secondary-400: 43.3 96.4% 56.3%; /* #fbbf24 */ + --color-secondary-500: 37.7 92.1% 50.2%; /* #f59e0b */ + --color-secondary-600: 32.1 94.6% 43.7%; /* #d97706 */ + --color-secondary-700: 26 90.5% 37.1%; /* #b45309 */ + --color-secondary-800: 22.7 82.5% 31.4%; /* #92400e */ + --color-secondary-900: 21.7 77.8% 26.5%; /* #78350f */ + + --color-ui-error: 0 84.2% 60.2%; /* #dc2626 */ + --color-ui-warning: 45.9 96.7% 64.5%; /* #fcd34d */ + --color-ui-success: 160.1 84.1% 39.4%; /* #10b981 */ + --color-ui-info: 215.4 16.3% 46.9%; /* #64748b */ + + /* Functional Colors */ + --background: var(--color-white); + --foreground: var(--color-mono-900); + + --primary: var(--color-primary-700); + --primary-foreground: var(--color-mono-050); + + --secondary: var(--color-mono-100); + --secondary-foreground: var(--color-mono-900); + + --card: var(--background); + --card-foreground: var(--color-mono-900); + + --popover: var(--color-mono-050); + --popover-foreground: var(--color-mono-900); + + --muted: var(--color-mono-100); + --muted-foreground: var(--color-mono-900); + + --accent: var(--color-mono-100); + --accent-foreground: var(--color-mono-900); + + --destructive: var(--color-ui-error); + --destructive-foreground: var(--color-mono-050); + + --warning: var(--color-ui-warning); + --warning-foreground: var(--color-mono-900); + + --success: var(--color-ui-success); + --success-foreground: var(--color-mono-900); + + --info: var(--color-ui-info); + --info-foreground: var(--color-mono-050); + + --border: var(--color-mono-200); + --input: var(--color-mono-200); + --ring: var(--color-primary-400); --radius: 0.5rem; - } - .dark { - --background: 20 14.3% 4.1%; - --foreground: 0 0% 95%; - - --card: 24 9.8% 10%; - --card-foreground: 0 0% 95%; - - --popover: 0 0% 9%; - --popover-foreground: 0 0% 95%; - - --primary: 142.1 70.6% 45.3%; - --primary-foreground: 144.9 80.4% 10%; - - --secondary: 240 3.7% 15.9%; - --secondary-foreground: 0 0% 98%; - - --muted: 0 0% 15%; - --muted-foreground: 240 5% 64.9%; - - --accent: 12 6.5% 15.1%; - --accent-foreground: 0 0% 98%; - - --destructive: 0 62.8% 30.6%; - --destructive-foreground: 0 85.7% 97.3%; + --border-base: 1px; + + --shadow-sm: 0 1px 2px 0 hsl(var(--border)); + --shadow: 0 1px 3px 0 hsl(var(--border)), 0 1px 2px -1px hsl(var(--border)); + --shadow-md: 0 4px 6px -1px hsl(var(--border)), + 0 2px 4px -2px hsl(var(--border)); + --shadow-lg: 0 10px 15px -3px hsl(var(--border)), + 0 4px 6px -4px hsl(var(--border)); + --shadow-xl: 0 20px 25px -5px hsl(var(--border)), + 0 8px 10px -6px hsl(var(--border)); + --shadow-2xl: 0 25px 50px -12px hsl(var(--border)); + --shadow-inner: inset 0 2px 4px 0 hsl(var(--border)); + } - --border: 240 3.7% 15.9%; - --input: 240 3.7% 15.9%; - --ring: 142.4 71.8% 29.2%; + html[data-theme^="dark-"] { + /* Anything that should be globally applied to dark themes */ + --shadow-sm: none; + --shadow: 0 none; + --shadow-md: none; + --shadow-lg: none; + --shadow-xl: none; + --shadow-2xl: none; + --shadow-inner: none; } + + @import "theme/dark-classic.css"; + @import "theme/dark-professional.css"; + @import "theme/dark-midnight.css"; + @import "theme/light-acid.css"; + @import "theme/light-professional.css"; + @import "theme/light-soft.css"; } @layer base { @@ -71,6 +123,6 @@ @apply border-border; } body { - @apply bg-background text-foreground; + @apply bg-background text-foreground transition duration-300; } } diff --git a/src/styles/root.css b/src/styles/root.css new file mode 100644 index 0000000..a2edca3 --- /dev/null +++ b/src/styles/root.css @@ -0,0 +1,241 @@ +--color-slate-050: 210 40% 98%; /* #f8fafc */ +--color-slate-100: 210 40% 96.1%; /* #f1f5f9 */ +--color-slate-200: 214.3 31.8% 91.4%; /* #e2e8f0 */ +--color-slate-300: 212.7 26.8% 83%; /* #cbd5e1 */ +--color-slate-400: 215 20.2% 65.1%; /* #94a3b8 */ +--color-slate-500: 215.4 16.3% 46.9%; /* #64748b */ +--color-slate-600: 215.3 19.3% 34.5%; /* #475569 */ +--color-slate-700: 215.3 25% 26.7%; /* #334155 */ +--color-slate-800: 217.2 32.6% 17.5%; /* #1e293b */ +--color-slate-900: 222.2 47.4% 11.2%; /* #0f172a */ + +--color-gray-050: 210 20% 98%; /* #f9fafb */ +--color-gray-100: 220 14.3% 95.9%; /* #f3f4f6 */ +--color-gray-200: 220 13% 91%; /* #e5e7eb */ +--color-gray-300: 216 12.2% 83.9%; /* #d1d5db */ +--color-gray-400: 217.9 10.6% 64.9%; /* #9ca3af */ +--color-gray-500: 220 8.9% 46.1%; /* #6b7280 */ +--color-gray-600: 215 13.8% 34.1%; /* #4b5563 */ +--color-gray-700: 216.9 19.1% 26.7%; /* #374151 */ +--color-gray-800: 215 27.9% 16.9%; /* #1f2937 */ +--color-gray-900: 220.9 39.3% 11%; /* #111827 */ + +--color-zinc-050: 0 0% 98%; /* #fafafa */ +--color-zinc-100: 240 4.8% 95.9%; /* #f4f4f5 */ +--color-zinc-200: 240 5.9% 90%; /* #e4e4e7 */ +--color-zinc-300: 240 4.9% 83.9%; /* #d4d4d8 */ +--color-zinc-400: 240 5% 64.9%; /* #a1a1aa */ +--color-zinc-500: 240 3.8% 46.1%; /* #71717a */ +--color-zinc-600: 240 5.2% 33.9%; /* #52525b */ +--color-zinc-700: 240 5.3% 26.1%; /* #3f3f46 */ +--color-zinc-800: 240 3.7% 15.9%; /* #27272a */ +--color-zinc-900: 240 5.9% 10%; /* #18181b */ + +--color-neutral-050: 0 0% 98%; /* #fafafa */ +--color-neutral-100: 0 0% 96.1%; /* #f5f5f5 */ +--color-neutral-200: 0 0% 89.8%; /* #e5e5e5 */ +--color-neutral-300: 0 0% 83.1%; /* #d4d4d4 */ +--color-neutral-400: 0 0% 63.9%; /* #a3a3a3 */ +--color-neutral-500: 0 0% 45.1%; /* #737373 */ +--color-neutral-600: 0 0% 32.2%; /* #525252 */ +--color-neutral-700: 0 0% 25.1%; /* #404040 */ +--color-neutral-800: 0 0% 14.9%; /* #262626 */ +--color-neutral-900: 0 0% 9%; /* #171717 */ + +--color-stone-050: 60 9.1% 97.8%; /* #fafaf9 */ +--color-stone-100: 60 4.8% 95.9%; /* #f5f5f4 */ +--color-stone-200: 20 5.9% 90%; /* #e7e5e4 */ +--color-stone-300: 24 5.7% 82.9%; /* #d6d3d1 */ +--color-stone-400: 24 5.4% 63.9%; /* #a8a29e */ +--color-stone-500: 25 5.3% 44.7%; /* #78716c */ +--color-stone-600: 33.3 5.5% 32.4%; /* #57534e */ +--color-stone-700: 30 6.3% 25.1%; /* #44403c */ +--color-stone-800: 12 6.5% 15.1%; /* #292524 */ +--color-stone-900: 24 9.8% 10%; /* #1c1917 */ + +--color-red-050: 0 85.7% 97.3%; /* #fef2f2 */ +--color-red-100: 0 93.3% 94.1%; /* #fee2e2 */ +--color-red-200: 0 96.3% 89.4%; /* #fecaca */ +--color-red-300: 0 93.5% 81.8%; /* #fca5a5 */ +--color-red-400: 0 90.6% 70.8%; /* #f87171 */ +--color-red-500: 0 84.2% 60.2%; /* #ef4444 */ +--color-red-600: 0 72.2% 50.6%; /* #dc2626 */ +--color-red-700: 0 73.7% 41.8%; /* #b91c1c */ +--color-red-800: 0 70% 35.3%; /* #991b1b */ +--color-red-900: 0 62.8% 30.6%; /* #7f1d1d */ + +--color-orange-050: 33.3 100% 96.5%; /* #fff7ed */ +--color-orange-100: 34.3 100% 91.8%; /* #ffedd5 */ +--color-orange-200: 32.1 97.7% 83.1%; /* #fed7aa */ +--color-orange-300: 30.7 97.2% 72.4%; /* #fdba74 */ +--color-orange-400: 27 96% 61%; /* #fb923c */ +--color-orange-500: 24.6 95% 53.1%; /* #f97316 */ +--color-orange-600: 20.5 90.2% 48.2%; /* #ea580c */ +--color-orange-700: 17.5 88.3% 40.4%; /* #c2410c */ +--color-orange-800: 15 79.1% 33.7%; /* #9a3412 */ +--color-orange-900: 15.3 74.6% 27.8%; /* #7c2d12 */ + +--color-amber-050: 48 100% 96.1%; /* #fffbeb */ +--color-amber-100: 48 96.5% 88.8%; /* #fef3c7 */ +--color-amber-200: 48 96.6% 76.7%; /* #fde68a */ +--color-amber-300: 45.9 96.7% 64.5%; /* #fcd34d */ +--color-amber-400: 43.3 96.4% 56.3%; /* #fbbf24 */ +--color-amber-500: 37.7 92.1% 50.2%; /* #f59e0b */ +--color-amber-600: 32.1 94.6% 43.7%; /* #d97706 */ +--color-amber-700: 26 90.5% 37.1%; /* #b45309 */ +--color-amber-800: 22.7 82.5% 31.4%; /* #92400e */ +--color-amber-900: 21.7 77.8% 26.5%; /* #78350f */ + +--color-yellow-050: 54.5 91.7% 95.3%; /* #fefce8 */ +--color-yellow-100: 54.9 96.7% 88%; /* #fef9c3 */ +--color-yellow-200: 52.8 98.3% 76.9%; /* #fef08a */ +--color-yellow-300: 50.4 97.8% 63.5%; /* #fde047 */ +--color-yellow-400: 47.9 95.8% 53.1%; /* #facc15 */ +--color-yellow-500: 45.4 93.4% 47.5%; /* #eab308 */ +--color-yellow-600: 40.6 96.1% 40.4%; /* #ca8a04 */ +--color-yellow-700: 35.5 91.7% 32.9%; /* #a16207 */ +--color-yellow-800: 31.8 81% 28.8%; /* #854d0e */ +--color-yellow-900: 28.4 72.5% 25.7%; /* #713f12 */ + +--color-lime-050: 78.3 92% 95.1%; /* #f7fee7 */ +--color-lime-100: 79.6 89.1% 89.2%; /* #ecfccb */ +--color-lime-200: 80.9 88.5% 79.6%; /* #d9f99d */ +--color-lime-300: 82 84.5% 67.1%; /* #bef264 */ +--color-lime-400: 82.7 78% 55.5%; /* #a3e635 */ +--color-lime-500: 83.7 80.5% 44.3%; /* #84cc16 */ +--color-lime-600: 84.8 85.2% 34.5%; /* #65a30d */ +--color-lime-700: 85.9 78.4% 27.3%; /* #4d7c0f */ +--color-lime-800: 86.3 69% 22.7%; /* #3f6212 */ +--color-lime-900: 87.6 61.2% 20.2%; /* #365314 */ + +--color-green-050: 138.5 76.5% 96.7%; /* #f0fdf4 */ +--color-green-100: 140.6 84.2% 92.5%; /* #dcfce7 */ +--color-green-200: 141 78.9% 85.1%; /* #bbf7d0 */ +--color-green-300: 141.7 76.6% 73.1%; /* #86efac */ +--color-green-400: 141.9 69.2% 58%; /* #4ade80 */ +--color-green-500: 142.1 70.6% 45.3%; /* #22c55e */ +--color-green-600: 142.1 76.2% 36.3%; /* #16a34a */ +--color-green-700: 142.4 71.8% 29.2%; /* #15803d */ +--color-green-800: 142.8 64.2% 24.1%; /* #166534 */ +--color-green-900: 143.8 61.2% 20.2%; /* #14532d */ + +--color-emerald-050: 151.8 81% 95.9%; /* #ecfdf5 */ +--color-emerald-100: 149.3 80.4% 90%; /* #d1fae5 */ +--color-emerald-200: 152.4 76% 80.4%; /* #a7f3d0 */ +--color-emerald-300: 156.2 71.6% 66.9%; /* #6ee7b7 */ +--color-emerald-400: 158.1 64.4% 51.6%; /* #34d399 */ +--color-emerald-500: 160.1 84.1% 39.4%; /* #10b981 */ +--color-emerald-600: 161.4 93.5% 30.4%; /* #059669 */ +--color-emerald-700: 162.9 93.5% 24.3%; /* #047857 */ +--color-emerald-800: 163.1 88.1% 19.8%; /* #065f46 */ +--color-emerald-900: 164.2 85.7% 16.5%; /* #064e3b */ + +--color-teal-050: 166.2 76.5% 96.7%; /* #f0fdfa */ +--color-teal-100: 167.2 85.5% 89.2%; /* #ccfbf1 */ +--color-teal-200: 168.4 83.8% 78.2%; /* #99f6e4 */ +--color-teal-300: 170.6 76.9% 64.3%; /* #5eead4 */ +--color-teal-400: 172.5 66% 50.4%; /* #2dd4bf */ +--color-teal-500: 173.4 80.4% 40%; /* #14b8a6 */ +--color-teal-600: 174.7 83.9% 31.6%; /* #0d9488 */ +--color-teal-700: 175.3 77.4% 26.1%; /* #0f766e */ +--color-teal-800: 176.1 69.4% 21.8%; /* #115e59 */ +--color-teal-900: 175.9 60.8% 19%; /* #134e4a */ + +--color-cyan-050: 183.2 100% 96.3%; /* #ecfeff */ +--color-cyan-100: 185.1 95.9% 90.4%; /* #cffafe */ +--color-cyan-200: 186.2 93.5% 81.8%; /* #a5f3fc */ +--color-cyan-300: 187 92.4% 69%; /* #67e8f9 */ +--color-cyan-400: 187.9 85.7% 53.3%; /* #22d3ee */ +--color-cyan-500: 188.7 94.5% 42.7%; /* #06b6d4 */ +--color-cyan-600: 191.6 91.4% 36.5%; /* #0891b2 */ +--color-cyan-700: 192.9 82.3% 31%; /* #0e7490 */ +--color-cyan-800: 194.4 69.6% 27.1%; /* #155e75 */ +--color-cyan-900: 196.4 63.6% 23.7%; /* #164e63 */ + +--color-sky-050: 204 100% 97.1%; /* #f0f9ff */ +--color-sky-100: 204 93.8% 93.7%; /* #e0f2fe */ +--color-sky-200: 200.6 94.4% 86.1%; /* #bae6fd */ +--color-sky-300: 199.4 95.5% 73.9%; /* #7dd3fc */ +--color-sky-400: 198.4 93.2% 59.6%; /* #38bdf8 */ +--color-sky-500: 198.6 88.7% 48.4%; /* #0ea5e9 */ +--color-sky-600: 200.4 98% 39.4%; /* #0284c7 */ +--color-sky-700: 201.3 96.3% 32.2%; /* #0369a1 */ +--color-sky-800: 201 90% 27.5%; /* #075985 */ +--color-sky-900: 202 80.3% 23.9%; /* #0c4a6e */ + +--color-blue-050: 213.8 100% 96.9%; /* #eff6ff */ +--color-blue-100: 214.3 94.6% 92.7%; /* #dbeafe */ +--color-blue-200: 213.3 96.9% 87.3%; /* #bfdbfe */ +--color-blue-300: 211.7 96.4% 78.4%; /* #93c5fd */ +--color-blue-400: 213.1 93.9% 67.8%; /* #60a5fa */ +--color-blue-500: 217.2 91.2% 59.8%; /* #3b82f6 */ +--color-blue-600: 221.2 83.2% 53.3%; /* #2563eb */ +--color-blue-700: 224.3 76.3% 48%; /* #1d4ed8 */ +--color-blue-800: 225.9 70.7% 40.2%; /* #1e40af */ +--color-blue-900: 224.4 64.3% 32.9%; /* #1e3a8a */ + +--color-indigo-050: 225.9 100% 96.7%; /* #eef2ff */ +--color-indigo-100: 226.5 100% 93.9%; /* #e0e7ff */ +--color-indigo-200: 228 96.5% 88.8%; /* #c7d2fe */ +--color-indigo-300: 229.7 93.5% 81.8%; /* #a5b4fc */ +--color-indigo-400: 234.5 89.5% 73.9%; /* #818cf8 */ +--color-indigo-500: 238.7 83.5% 66.7%; /* #6366f1 */ +--color-indigo-600: 243.4 75.4% 58.6%; /* #4f46e5 */ +--color-indigo-700: 244.5 57.9% 50.6%; /* #4338ca */ +--color-indigo-800: 243.7 54.5% 41.4%; /* #3730a3 */ +--color-indigo-900: 242.2 47.4% 34.3%; /* #312e81 */ + +--color-violet-050: 250 100% 97.6%; /* #f5f3ff */ +--color-violet-100: 251.4 91.3% 95.5%; /* #ede9fe */ +--color-violet-200: 250.5 95.2% 91.8%; /* #ddd6fe */ +--color-violet-300: 252.5 94.7% 85.1%; /* #c4b5fd */ +--color-violet-400: 255.1 91.7% 76.3%; /* #a78bfa */ +--color-violet-500: 258.3 89.5% 66.3%; /* #8b5cf6 */ +--color-violet-600: 262.1 83.3% 57.8%; /* #7c3aed */ +--color-violet-700: 263.4 70% 50.4%; /* #6d28d9 */ +--color-violet-800: 263.4 69.3% 42.2%; /* #5b21b6 */ +--color-violet-900: 263.5 67.4% 34.9%; /* #4c1d95 */ + +--color-purple-050: 270 100% 98%; /* #faf5ff */ +--color-purple-100: 268.7 100% 95.5%; /* #f3e8ff */ +--color-purple-200: 268.6 100% 91.8%; /* #e9d5ff */ +--color-purple-300: 269.2 97.4% 85.1%; /* #d8b4fe */ +--color-purple-400: 270 95.2% 75.3%; /* #c084fc */ +--color-purple-500: 270.7 91% 65.1%; /* #a855f7 */ +--color-purple-600: 271.5 81.3% 55.9%; /* #9333ea */ +--color-purple-700: 272.1 71.7% 47.1%; /* #7e22ce */ +--color-purple-800: 272.9 67.2% 39.4%; /* #6b21a8 */ +--color-purple-900: 273.6 65.6% 32%; /* #581c87 */ + +--color-fuchsia-050: 289.1 100% 97.8%; /* #fdf4ff */ +--color-fuchsia-100: 287 100% 95.5%; /* #fae8ff */ +--color-fuchsia-200: 288.3 95.8% 90.6%; /* #f5d0fe */ +--color-fuchsia-300: 291.1 93.1% 82.9%; /* #f0abfc */ +--color-fuchsia-400: 292 91.4% 72.5%; /* #e879f9 */ +--color-fuchsia-500: 292.2 84.1% 60.6%; /* #d946ef */ +--color-fuchsia-600: 293.4 69.5% 48.8%; /* #c026d3 */ +--color-fuchsia-700: 294.7 72.4% 39.8%; /* #a21caf */ +--color-fuchsia-800: 295.4 70.2% 32.9%; /* #86198f */ +--color-fuchsia-900: 296.7 63.6% 28%; /* #701a75 */ + +--color-pink-050: 327.3 73.3% 97.1%; /* #fdf2f8 */ +--color-pink-100: 325.7 77.8% 94.7%; /* #fce7f3 */ +--color-pink-200: 325.9 84.6% 89.8%; /* #fbcfe8 */ +--color-pink-300: 327.4 87.1% 81.8%; /* #f9a8d4 */ +--color-pink-400: 328.6 85.5% 70.2%; /* #f472b6 */ +--color-pink-500: 330.4 81.2% 60.4%; /* #ec4899 */ +--color-pink-600: 333.3 71.4% 50.6%; /* #db2777 */ +--color-pink-700: 335.1 77.6% 42%; /* #be185d */ +--color-pink-800: 335.8 74.4% 35.3%; /* #9d174d */ +--color-pink-900: 335.9 69% 30.4%; /* #831843 */ + +--color-rose-050: 355.7 100% 97.3%; /* #fff1f2 */ +--color-rose-100: 355.6 100% 94.7%; /* #ffe4e6 */ +--color-rose-200: 352.7 96.1% 90%; /* #fecdd3 */ +--color-rose-300: 352.6 95.7% 81.8%; /* #fda4af */ +--color-rose-400: 351.3 94.5% 71.4%; /* #fb7185 */ +--color-rose-500: 349.7 89.2% 60.2%; /* #f43f5e */ +--color-rose-600: 346.8 77.2% 49.8%; /* #e11d48 */ +--color-rose-700: 345.3 82.7% 40.8%; /* #be123c */ +--color-rose-800: 343.4 79.7% 34.7%; /* #9f1239 */ +--color-rose-900: 341.5 75.5% 30.4%; /* #881337 */ diff --git a/src/styles/theme/dark-classic.css b/src/styles/theme/dark-classic.css new file mode 100644 index 0000000..c1253b6 --- /dev/null +++ b/src/styles/theme/dark-classic.css @@ -0,0 +1,41 @@ +html[data-theme="dark-classic"] { + color-scheme: dark; + --background: var(--color-mono-900); + --foreground: var(--color-mono-050); + + --card: var(--color-mono-800); + --card-foreground: var(--color-mono-050); + + --popover: var(--color-mono-900); + --popover-foreground: var(--color-mono-050); + + --primary: var(--color-mono-050); + --primary-foreground: var(--color-mono-900); + + --secondary: var(--color-mono-800); + --secondary-foreground: var(--color-mono-050); + + --muted: var(--color-mono-800); + --muted-foreground: var(--color-mono-050); + + --accent: var(--color-mono-800); + --accent-foreground: var(--color-mono-050); + + --destructive: var(--color-ui-error); + --destructive-foreground: var(--color-mono-900); + + --warning: var(--color-ui-warning); + --warning-foreground: var(--color-mono-900); + + --success: var(--color-ui-success); + --success-foreground: var(--color-mono-900); + + --info: var(--color-ui-info); + --info-foreground: var(--color-mono-900); + + --border: var(--color-mono-300); + --input: var(--color-mono-200); + --ring: var(--color-primary-600); + + --radius: 0.5rem; +} diff --git a/src/styles/theme/dark-midnight.css b/src/styles/theme/dark-midnight.css new file mode 100644 index 0000000..a32ac85 --- /dev/null +++ b/src/styles/theme/dark-midnight.css @@ -0,0 +1,54 @@ +html[data-theme="dark-midnight"] { + --color-indigo-050: 225.9 100% 96.7%; /* #eef2ff */ + --color-indigo-100: 226.5 100% 93.9%; /* #e0e7ff */ + --color-indigo-200: 228 96.5% 88.8%; /* #c7d2fe */ + --color-indigo-300: 229.7 93.5% 81.8%; /* #a5b4fc */ + --color-indigo-400: 234.5 89.5% 73.9%; /* #818cf8 */ + --color-indigo-500: 238.7 83.5% 66.7%; /* #6366f1 */ + --color-indigo-600: 243.4 75.4% 58.6%; /* #4f46e5 */ + --color-indigo-700: 244.5 57.9% 50.6%; /* #4338ca */ + --color-indigo-800: 243.7 54.5% 41.4%; /* #3730a3 */ + --color-indigo-900: 242.2 47.4% 34.3%; /* #312e81 */ + + color-scheme: dark; + --background: var(--color-indigo-900); + --foreground: var(--color-indigo-050); + + --card: var(--color-indigo-900); + --card-foreground: var(--color-indigo-050); + + --popover: var(--color-indigo-900); + --popover-foreground: var(--color-indigo-050); + + --primary: var(--color-indigo-050); + --primary-foreground: var(--color-indigo-900); + + --secondary: var(--color-indigo-800); + --secondary-foreground: var(--color-indigo-050); + + --muted: var(--color-indigo-800); + --muted-foreground: var(--color-indigo-050); + + --accent: var(--color-indigo-800); + --accent-foreground: var(--color-indigo-050); + + --destructive: var(--color-ui-error); + --destructive-foreground: var(--color-indigo-900); + + --warning: var(--color-ui-warning); + --warning-foreground: var(--color-indigo-900); + + --success: var(--color-ui-success); + --success-foreground: var(--color-indigo-900); + + --info: var(--color-ui-info); + --info-foreground: var(--color-indigo-900); + + --border: var(--color-indigo-600); + --input: var(--color-indigo-050); + --ring: var(--color-primary-600); + + --radius: 0.5rem; + + --border-base: 4px; +} diff --git a/src/styles/theme/dark-professional.css b/src/styles/theme/dark-professional.css new file mode 100644 index 0000000..9b08ee0 --- /dev/null +++ b/src/styles/theme/dark-professional.css @@ -0,0 +1,54 @@ +html[data-theme="dark-professional"] { + --color-stone-050: 60 9.1% 97.8%; /* #fafaf9 */ + --color-stone-100: 60 4.8% 95.9%; /* #f5f5f4 */ + --color-stone-200: 20 5.9% 90%; /* #e7e5e4 */ + --color-stone-300: 24 5.7% 82.9%; /* #d6d3d1 */ + --color-stone-400: 24 5.4% 63.9%; /* #a8a29e */ + --color-stone-500: 25 5.3% 44.7%; /* #78716c */ + --color-stone-600: 33.3 5.5% 32.4%; /* #57534e */ + --color-stone-700: 30 6.3% 25.1%; /* #44403c */ + --color-stone-800: 12 6.5% 15.1%; /* #292524 */ + --color-stone-900: 24 9.8% 10%; /* #1c1917 */ + + color-scheme: dark; + --background: var(--color-stone-900); + --foreground: var(--color-stone-050); + + --card: var(--color-stone-800); + --card-foreground: var(--color-stone-050); + + --popover: var(--color-stone-900); + --popover-foreground: var(--color-stone-050); + + --primary: var(--color-stone-050); + --primary-foreground: var(--color-stone-900); + + --secondary: var(--color-stone-800); + --secondary-foreground: var(--color-stone-050); + + --muted: var(--color-stone-800); + --muted-foreground: var(--color-stone-050); + + --accent: var(--color-stone-800); + --accent-foreground: var(--color-stone-050); + + --destructive: var(--color-ui-error); + --destructive-foreground: var(--color-stone-900); + + --warning: var(--color-ui-warning); + --warning-foreground: var(--color-stone-900); + + --success: var(--color-ui-success); + --success-foreground: var(--color-stone-900); + + --info: var(--color-ui-info); + --info-foreground: var(--color-stone-900); + + --border: var(--color-stone-400); + --input: var(--color-stone-300); + --ring: var(--color-primary-600); + + --radius: 0rem; + + --border-base: 2px; +} diff --git a/src/styles/theme/light-acid.css b/src/styles/theme/light-acid.css new file mode 100644 index 0000000..52e4ceb --- /dev/null +++ b/src/styles/theme/light-acid.css @@ -0,0 +1,51 @@ +html[data-theme="light-acid"] { + --color-lime-050: 78.3 92% 95.1%; /* #f7fee7 */ + --color-lime-100: 79.6 89.1% 89.2%; /* #ecfccb */ + --color-lime-200: 80.9 88.5% 79.6%; /* #d9f99d */ + --color-lime-300: 82 84.5% 67.1%; /* #bef264 */ + --color-lime-400: 82.7 78% 55.5%; /* #a3e635 */ + --color-lime-500: 83.7 80.5% 44.3%; /* #84cc16 */ + --color-lime-600: 84.8 85.2% 34.5%; /* #65a30d */ + --color-lime-700: 85.9 78.4% 27.3%; /* #4d7c0f */ + --color-lime-800: 86.3 69% 22.7%; /* #3f6212 */ + --color-lime-900: 87.6 61.2% 20.2%; /* #365314 */ + + --color-orange-050: 33.3 100% 96.5%; /* #fff7ed */ + --color-orange-500: 24.6 95% 53.1%; /* #f97316 */ + + --background: var(--color-lime-050); + --foreground: var(--color-lime-900); + + --primary: var(--color-orange-500); + --primary-foreground: var(--color-orange-050); + + --secondary: var(--color-lime-100); + --secondary-foreground: var(--color-lime-900); + + --card: var(--background); + --card-foreground: var(--color-lime-900); + + --popover: var(--color-lime-050); + --popover-foreground: var(--color-lime-900); + + --muted: var(--color-lime-100); + --muted-foreground: var(--color-lime-900); + + --accent: var(--color-lime-100); + --accent-foreground: var(--color-lime-900); + + --border: var(--color-orange-500); + --input: var(--color-lime-200); + + --border-base: 3px; + + --shadow-sm: 1px 1px 0px hsl(var(--border)); + --shadow: 1px 1px 0px hsl(var(--border)), 0 1px 2px -1px hsl(var(--border)); + --shadow-md: 4px 4px 0px hsl(var(--border)), 0 2px 0px hsl(var(--border)); + --shadow-lg: 10px 10px 0px hsl(var(--border)), + 0 4px 0px -4px hsl(var(--border)); + --shadow-xl: 20px 20px 0pxhsl (var(--border)), + 0 8px 0px -6px hsl(var(--border)); + --shadow-2xl: 25px 25px 0px hsl(var(--border)); + --shadow-inner: inset 2px 2px 4px hsl(var(--border)); +} diff --git a/src/styles/theme/light-professional.css b/src/styles/theme/light-professional.css new file mode 100644 index 0000000..b27bf04 --- /dev/null +++ b/src/styles/theme/light-professional.css @@ -0,0 +1,40 @@ +html[data-theme="light-professional"] { + --color-stone-050: 60 9.1% 97.8%; /* #fafaf9 */ + --color-stone-100: 60 4.8% 95.9%; /* #f5f5f4 */ + --color-stone-200: 20 5.9% 90%; /* #e7e5e4 */ + --color-stone-300: 24 5.7% 82.9%; /* #d6d3d1 */ + --color-stone-400: 24 5.4% 63.9%; /* #a8a29e */ + --color-stone-500: 25 5.3% 44.7%; /* #78716c */ + --color-stone-600: 33.3 5.5% 32.4%; /* #57534e */ + --color-stone-700: 30 6.3% 25.1%; /* #44403c */ + --color-stone-800: 12 6.5% 15.1%; /* #292524 */ + --color-stone-900: 24 9.8% 10%; /* #1c1917 */ + + --background: var(--color-stone-050); + --foreground: var(--color-stone-900); + + --primary: var(--color-stone-700); + --primary-foreground: var(--color-stone-050); + + --secondary: var(--color-stone-100); + --secondary-foreground: var(--color-stone-900); + + --card: var(--background); + --card-foreground: var(--color-stone-900); + + --popover: var(--color-stone-050); + --popover-foreground: var(--color-stone-900); + + --muted: var(--color-stone-100); + --muted-foreground: var(--color-stone-900); + + --accent: var(--color-stone-100); + --accent-foreground: var(--color-stone-900); + + --border: var(--color-stone-400); + --input: var(--color-stone-300); + + --radius: 0rem; + + --border-base: 2px; +} diff --git a/src/styles/theme/light-soft.css b/src/styles/theme/light-soft.css new file mode 100644 index 0000000..cd94ea3 --- /dev/null +++ b/src/styles/theme/light-soft.css @@ -0,0 +1,38 @@ +html[data-theme="light-soft"] { + --color-red-050: 0 85.7% 97.3%; /* #fef2f2 */ + --color-red-100: 0 93.3% 94.1%; /* #fee2e2 */ + --color-red-200: 0 96.3% 89.4%; /* #fecaca */ + --color-red-300: 0 93.5% 81.8%; /* #fca5a5 */ + --color-red-400: 0 90.6% 70.8%; /* #f87171 */ + --color-red-500: 0 84.2% 60.2%; /* #ef4444 */ + --color-red-600: 0 72.2% 50.6%; /* #dc2626 */ + --color-red-700: 0 73.7% 41.8%; /* #b91c1c */ + --color-red-800: 0 70% 35.3%; /* #991b1b */ + --color-red-900: 0 62.8% 30.6%; /* #7f1d1d */ + + --background: var(--color-red-050); + --foreground: var(--color-red-900); + + --primary: var(--color-red-700); + --primary-foreground: var(--color-red-050); + + --secondary: var(--color-red-100); + --secondary-foreground: var(--color-red-900); + + --card: var(--background); + --card-foreground: var(--color-red-900); + + --popover: var(--color-red-050); + --popover-foreground: var(--color-red-900); + + --muted: var(--color-red-100); + --muted-foreground: var(--color-red-900); + + --accent: var(--color-red-100); + --accent-foreground: var(--color-red-900); + + --border: var(--color-red-200); + --input: var(--color-red-200); + + --radius: 1rem; +} diff --git a/tailwind.config.ts b/tailwind.config.ts index 86396b7..1bc8bf2 100644 --- a/tailwind.config.ts +++ b/tailwind.config.ts @@ -1,7 +1,7 @@ import type { Config } from "tailwindcss"; const config = { - darkMode: ["class"], + darkMode: ["class", '[data-theme^="dark-"]'], content: [ "./src/pages/**/*.{js,ts,jsx,tsx,mdx}", "./src/components/**/*.{js,ts,jsx,tsx,mdx}", @@ -18,6 +18,23 @@ const config = { "2xl": "1400px", }, }, + boxShadow: { + DEFAULT: "var(--shadow)", + sm: "var(--shadow-sm)", + md: "var(--shadow-md)", + lg: "var(--shadow-lg)", + xl: "var(--shadow-xl)", + "2xl": "var(--shadow-2xl)", + inner: "var(--shadow-inner)", + none: "none", + }, + borderWidth: { + DEFAULT: "var(--border-base)", + "0": "0", + "2": "calc(var(--border-base) * 2)", + "4": "calc(var(--border-base) * 4)", + "8": "calc(var(--border-base) * 8)", + }, extend: { fontFamily: { serif: ["var(--font-josefin-sans)"], @@ -42,6 +59,18 @@ const config = { DEFAULT: "hsl(var(--destructive))", foreground: "hsl(var(--destructive-foreground))", }, + warning: { + DEFAULT: "hsl(var(--warning))", + foreground: "hsl(var(--warning-foreground))", + }, + success: { + DEFAULT: "hsl(var(--success))", + foreground: "hsl(var(--success-foreground))", + }, + info: { + DEFAULT: "hsl(var(--info))", + foreground: "hsl(var(--info-foreground))", + }, muted: { DEFAULT: "hsl(var(--muted))", foreground: "hsl(var(--muted-foreground))",