From a7557264ddd0d41e9e49360ee08956b709e3990f Mon Sep 17 00:00:00 2001 From: Piotr Kulpinski Date: Mon, 29 Jan 2024 21:24:47 +0100 Subject: [PATCH] update colors and remove theme provider and global themes --- .storybook/preview.ts | 30 +- package.json | 2 +- src/index.ts | 1 - src/layout/Container/Container.variants.ts | 2 +- src/providers/ThemeProvider.tsx | 29 -- src/providers/index.ts | 2 - src/styles/tailwind.css | 2 +- src/typography/Prose/Prose.tsx | 8 +- src/typography/Prose/Prose.variants.ts | 14 +- src/ui/Avatar/Avatar.tsx | 25 +- src/ui/Avatar/Avatar.variants.ts | 16 +- src/ui/Badge/Badge.tsx | 19 +- src/ui/Badge/Badge.variants.ts | 6 +- src/ui/Button/Button.stories.tsx | 22 +- src/ui/Button/Button.tsx | 26 +- src/ui/Button/Button.variants.ts | 273 ++++--------------- src/ui/Card/Card.variants.ts | 2 +- src/ui/Dot/Dot.tsx | 7 +- src/ui/FeatureCard/FeatureCard.tsx | 7 +- src/ui/FeatureCard/FeatureCard.variants.ts | 59 +--- src/ui/Loader/Loader.tsx | 8 +- src/ui/MenuItem/MenuItem.tsx | 15 +- src/ui/MenuItem/MenuItem.variants.ts | 40 +-- src/ui/ProgressBar/ProgressBar.tsx | 5 +- src/ui/ProgressBar/ProgressBar.variants.ts | 2 +- src/ui/ProgressRing/ProgressRing.tsx | 6 +- src/ui/ProgressRing/ProgressRing.variants.ts | 2 + src/ui/Status/Status.tsx | 17 +- src/ui/Status/Status.variants.ts | 6 +- tailwind.config.ts | 152 +++++------ 30 files changed, 216 insertions(+), 589 deletions(-) delete mode 100644 src/providers/ThemeProvider.tsx delete mode 100644 src/providers/index.ts diff --git a/.storybook/preview.ts b/.storybook/preview.ts index 5d2ea69..bf1e103 100644 --- a/.storybook/preview.ts +++ b/.storybook/preview.ts @@ -1,5 +1,4 @@ -import { ProviderStrategyConfiguration, withThemeFromJSXProvider } from "@storybook/addon-themes" -import { defaultTheme, ThemeProvider as Provider } from "../src/providers/ThemeProvider" +import { withThemeByClassName } from "@storybook/addon-themes" import "~/styles/tailwind.css" const preview = { @@ -9,29 +8,12 @@ const preview = { }, decorators: [ // Theme Light/Dark Switcher - // withThemeByClassName({ - // themes: { - // light: "light", - // dark: "dark", - // }, - // defaultTheme: "light", - // }), - - // Theme Color Switcher - withThemeFromJSXProvider({ + withThemeByClassName({ themes: { - blue: "blue", - orange: "orange", - yellow: "yellow", - red: "red", - green: "green", - purple: "purple", - pink: "pink", - teal: "teal", - gray: "gray", - } as any as ProviderStrategyConfiguration["themes"], - defaultTheme, - Provider, + light: "light", + dark: "dark", + }, + defaultTheme: "light", }), ], } diff --git a/package.json b/package.json index f938f38..8c5a921 100644 --- a/package.json +++ b/package.json @@ -42,8 +42,8 @@ "@radix-ui/react-slot": "^1.0.2", "@radix-ui/react-switch": "^1.0.3", "@radix-ui/react-tooltip": "^1.0.7", + "@tabler/icons-react": "^2.46.0", "cva": "^1.0.0-beta.1", - "lucide-react": "^0.311.0", "tailwind-merge": "^2.2.0" }, "devDependencies": { diff --git a/src/index.ts b/src/index.ts index dc6af4c..38686fe 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,5 +1,4 @@ export * from "./shared" -export * from "./providers" // UI export * from "./ui/Accordion" diff --git a/src/layout/Container/Container.variants.ts b/src/layout/Container/Container.variants.ts index 8abbee5..a083bc1 100644 --- a/src/layout/Container/Container.variants.ts +++ b/src/layout/Container/Container.variants.ts @@ -1,5 +1,5 @@ import { cva } from "../../shared" export const containerVariants = cva({ - base: "container mx-auto w-full px-5 md:px-6 lg:px-8", + base: "container mx-auto w-full px-5 md:px-6 lg:px-8 2xl:max-w-screen-xl", }) diff --git a/src/providers/ThemeProvider.tsx b/src/providers/ThemeProvider.tsx deleted file mode 100644 index e783edc..0000000 --- a/src/providers/ThemeProvider.tsx +++ /dev/null @@ -1,29 +0,0 @@ -/* eslint react-refresh/only-export-components: 0 */ -import { type PropsWithChildren } from "react" - -import { createSimpleContext } from "../shared" - -export type Theme = - | "blue" - | "orange" - | "yellow" - | "red" - | "green" - | "purple" - | "pink" - | "teal" - | "gray" - -type ThemeProviderProps = PropsWithChildren<{ - theme?: Theme -}> - -const ThemeContext = createSimpleContext("Theme") - -export const ThemeProvider = ({ children, theme }: ThemeProviderProps) => { - return {children} -} - -export const useTheme = ThemeContext.useOptionalValue - -export const defaultTheme: Theme = "blue" diff --git a/src/providers/index.ts b/src/providers/index.ts deleted file mode 100644 index b34794d..0000000 --- a/src/providers/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export { defaultTheme, useTheme, ThemeProvider } from "./ThemeProvider" -export type { Theme } from "./ThemeProvider" diff --git a/src/styles/tailwind.css b/src/styles/tailwind.css index 978f434..6c013fa 100644 --- a/src/styles/tailwind.css +++ b/src/styles/tailwind.css @@ -14,7 +14,7 @@ label[for], svg[stroke="currentColor"] { @apply stroke-[1.5]; - @apply size-[1.428em]; + @apply size-icon; } .dark { diff --git a/src/typography/Prose/Prose.tsx b/src/typography/Prose/Prose.tsx index 5ae0867..b8fcdf3 100644 --- a/src/typography/Prose/Prose.tsx +++ b/src/typography/Prose/Prose.tsx @@ -2,7 +2,6 @@ import { Slot } from "@radix-ui/react-slot" import type { HTMLAttributes } from "react" import { forwardRef, isValidElement } from "react" -import { useTheme } from "../../providers" import { type VariantProps, cx } from "../../shared" import { proseVariants } from "./Prose.variants" @@ -19,15 +18,12 @@ export type ProseProps = Omit, "size"> & } export const Prose = forwardRef((props, ref) => { - const { className, asChild, theme: propTheme, size, ...rest } = props - - const globalTheme = useTheme() - const theme = propTheme || globalTheme + const { className, asChild, size, ...rest } = props const useAsChild = asChild && isValidElement(rest.children) const Comp = useAsChild ? Slot : "div" - return + return }) Prose.defaultProps = { diff --git a/src/typography/Prose/Prose.variants.ts b/src/typography/Prose/Prose.variants.ts index be66c87..2383593 100644 --- a/src/typography/Prose/Prose.variants.ts +++ b/src/typography/Prose/Prose.variants.ts @@ -4,21 +4,10 @@ export const proseVariants = cva({ base: [ "text-pretty text-start prose", // Prose Headings - "prose-headings:font-medium prose-h1:-tracking-1 prose-h2:-tracking-1", + "prose-headings:font-medium prose-h1:-tracking-1 prose-h2:-tracking-1 prose-a:text-primary", ], variants: { - theme: { - blue: "prose-blue", - orange: "prose-orange", - yellow: "prose-yellow", - red: "prose-red", - green: "prose-green", - purple: "prose-purple", - pink: "prose-pink", - teal: "prose-teal", - gray: "prose-gray", - }, size: { sm: "prose-sm", md: "prose-base", @@ -27,7 +16,6 @@ export const proseVariants = cva({ }, defaultVariants: { - theme: "gray", size: "md", }, }) diff --git a/src/ui/Avatar/Avatar.tsx b/src/ui/Avatar/Avatar.tsx index 9402eee..14d94be 100644 --- a/src/ui/Avatar/Avatar.tsx +++ b/src/ui/Avatar/Avatar.tsx @@ -4,7 +4,6 @@ import { UserIcon } from "lucide-react" import { forwardRef, isValidElement } from "react" import type { ComponentPropsWithoutRef, ElementRef, ReactElement, RefObject } from "react" -import { useTheme } from "../../providers" import { type VariantProps, cx, getInitials, isReactElement } from "../../shared" import { Loader } from "../Loader" @@ -48,14 +47,11 @@ export type AvatarProps = ComponentPropsWithoutRef & const AvatarRoot = forwardRef< ElementRef, ComponentPropsWithoutRef & VariantProps ->(({ className, theme: propTheme, variant, size, shape, ...props }, ref) => { - const globalTheme = useTheme() - const theme = propTheme || globalTheme - +>(({ className, variant, size, shape, ...props }, ref) => { return ( ) @@ -89,22 +85,11 @@ const AvatarStatus = forwardRef< }) const AvatarBase = forwardRef((props, ref) => { - const { - children, - initials, - topStatus, - bottomStatus, - theme, - variant, - size, - shape, - src, - alt, - ...rest - } = props + const { children, initials, topStatus, bottomStatus, variant, size, shape, src, alt, ...rest } = + props return ( - + {/* Show image if available */} {src && } alt={alt} src={src} />} diff --git a/src/ui/Avatar/Avatar.variants.ts b/src/ui/Avatar/Avatar.variants.ts index 30075be..b167f36 100644 --- a/src/ui/Avatar/Avatar.variants.ts +++ b/src/ui/Avatar/Avatar.variants.ts @@ -4,23 +4,12 @@ export const avatarVariants = cva({ base: "relative flex items-center justify-center shrink-0 w-auto", variants: { - theme: { - blue: "from-blue-lighter to-blue-light text-blue-dark", - orange: "from-orange-lighter to-orange-light text-orange-dark", - yellow: "from-yellow-lighter to-yellow-light text-yellow-dark", - red: "from-red-lighter to-red-light text-red-dark", - green: "from-green-lighter to-green-light text-green-dark", - purple: "from-purple-lighter to-purple-light text-purple-dark", - pink: "from-pink-lighter to-pink-light text-pink-dark", - teal: "from-teal-lighter to-teal-light text-teal-dark", - gray: "from-gray-100 to-gray-200 text-gray-600", - }, variant: { - soft: "bg-gradient-to-b", + soft: "bg-gradient-to-b from-primary-lighter to-primary-light text-primary-dark", outline: "border border-gray-200", }, size: { - xs: "h-5 min-w-5 text-2xs", + xs: "h-5 min-w-5 text-3xs", sm: "h-6 min-w-6 text-2xs", md: "h-8 min-w-8 text-xs", lg: "h-10 min-w-10 text-sm", @@ -33,7 +22,6 @@ export const avatarVariants = cva({ }, defaultVariants: { - theme: "gray", variant: "soft", size: "md", shape: "circle", diff --git a/src/ui/Badge/Badge.tsx b/src/ui/Badge/Badge.tsx index f631d55..76b41af 100644 --- a/src/ui/Badge/Badge.tsx +++ b/src/ui/Badge/Badge.tsx @@ -2,7 +2,6 @@ import { Slot } from "@radix-ui/react-slot" import { forwardRef, isValidElement } from "react" import type { ReactElement, HTMLAttributes } from "react" -import { useTheme } from "../../providers" import { type VariantProps, cx } from "../../shared" import { Slottable } from "../../utils/Slottable" @@ -30,21 +29,8 @@ export type BadgeProps = Omit, "size" | "prefix"> & } export const Badge = forwardRef((props, ref) => { - const { - children, - className, - asChild, - prefix, - suffix, - theme: propTheme, - variant, - size, - shape, - ...rest - } = props - - const globalTheme = useTheme() - const theme = propTheme || globalTheme + const { children, className, asChild, prefix, suffix, theme, variant, size, shape, ...rest } = + props const useAsChild = asChild && isValidElement(children) const Component = useAsChild ? Slot : "span" @@ -79,6 +65,7 @@ export const Badge = forwardRef((props, ref) => { Badge.displayName = "Badge" Badge.defaultProps = { + theme: "blue", variant: "solid", size: "sm", shape: "pill", diff --git a/src/ui/Badge/Badge.variants.ts b/src/ui/Badge/Badge.variants.ts index 3a9f0b1..a3cac3b 100644 --- a/src/ui/Badge/Badge.variants.ts +++ b/src/ui/Badge/Badge.variants.ts @@ -24,9 +24,9 @@ export const badgeVariants = cva({ outline: "", }, size: { - sm: "text-2xs", - md: "text-xs", - lg: "text-sm", + sm: "text-3xs", + md: "text-2xs", + lg: "text-xs", }, shape: { rounded: "rounded-md", diff --git a/src/ui/Button/Button.stories.tsx b/src/ui/Button/Button.stories.tsx index aa22c0c..c15d425 100644 --- a/src/ui/Button/Button.stories.tsx +++ b/src/ui/Button/Button.stories.tsx @@ -1,5 +1,5 @@ import type { Meta, StoryObj } from "@storybook/react" -import { AppleIcon } from "lucide-react" +import { IconSquare } from "@tabler/icons-react" import { Button } from "./Button" @@ -9,15 +9,16 @@ type Story = StoryObj export default { title: "UI/Button", component: Button, -} satisfies Meta - -// Stories -export const Default = { args: { ...Button.defaultProps, children: "Button", disabled: false, }, +} satisfies Meta + +// Stories +export const Default = { + args: {}, } satisfies Story export const AsChild = { @@ -29,12 +30,19 @@ export const AsChild = { export const WithPrefix = { args: { - prefix: , + prefix: , }, } satisfies Story export const WithSuffix = { args: { - suffix: , + suffix: , + }, +} satisfies Story + +export const WithIconOnly = { + args: { + prefix: , + children: null, }, } satisfies Story diff --git a/src/ui/Button/Button.tsx b/src/ui/Button/Button.tsx index 84e18b3..7ff7621 100644 --- a/src/ui/Button/Button.tsx +++ b/src/ui/Button/Button.tsx @@ -2,7 +2,6 @@ import { Slot } from "@radix-ui/react-slot" import type { ButtonHTMLAttributes, ReactElement } from "react" import { forwardRef, isValidElement } from "react" -import { useTheme } from "../../providers" import { type VariantProps, cx, isChildrenEmpty } from "../../shared" import { Slottable } from "../../utils/Slottable" import { Loader } from "../Loader" @@ -12,7 +11,7 @@ import { buttonAffixVariants, buttonVariants } from "./Button.variants" export type ButtonElement = HTMLButtonElement export type ButtonProps = Omit, "size" | "prefix"> & - VariantProps & { + Omit, "iconOnly"> & { /** * If set to `true`, the button will be rendered as a child within the component. * This child component must be a valid React component. @@ -44,18 +43,17 @@ export const Button = forwardRef((props, ref) => { loading, prefix, suffix, - theme: propTheme, + theme, variant, size, - shape, ...rest } = props - const globalTheme = useTheme() - const theme = propTheme || globalTheme - const useAsChild = asChild && isValidElement(children) const Component = useAsChild ? Slot : "button" + // Determine if the button is icon-only. + const iconOnly = isChildrenEmpty(children) && (!prefix || !suffix) + // Render an affix with destructive properties applied. const renderAffix = (affix?: ReactElement) => { const AffixComponent = isValidElement(affix) ? Slot : "span" @@ -67,18 +65,16 @@ export const Button = forwardRef((props, ref) => { return ( {(child) => ( <> -
- {prefix && renderAffix(prefix)} - {!isChildrenEmpty(child) && {child}} - {suffix && renderAffix(suffix)} -
+ {prefix && renderAffix(prefix)} + {!isChildrenEmpty(child) && {child}} + {suffix && renderAffix(suffix)} {!!loading && } @@ -89,9 +85,9 @@ export const Button = forwardRef((props, ref) => { }) Button.defaultProps = { + theme: "primary", variant: "solid", - size: "lg", - shape: "rounded", + size: "md", asChild: false, } diff --git a/src/ui/Button/Button.variants.ts b/src/ui/Button/Button.variants.ts index b26df43..5de00aa 100644 --- a/src/ui/Button/Button.variants.ts +++ b/src/ui/Button/Button.variants.ts @@ -3,7 +3,7 @@ import { cva } from "../../shared" export const buttonVariants = cva({ base: [ "relative inline-flex items-center justify-center", - "font-medium border border-transparent text-center !leading-none", + "border border-transparent rounded-md font-medium leading-icon text-center", // Disabled "disabled:opacity-25 disabled:pointer-events-none", @@ -14,250 +14,75 @@ export const buttonVariants = cva({ variants: { theme: { - blue: "focus-visible:ring-blue-light focus-visible:border-blue", - orange: "focus-visible:ring-orange-light focus-visible:border-orange", - yellow: "focus-visible:ring-yellow-light focus-visible:border-yellow", - red: "focus-visible:ring-red-light focus-visible:border-red", - green: "focus-visible:ring-green-light focus-visible:border-green", - purple: "focus-visible:ring-purple-light focus-visible:border-purple", - pink: "focus-visible:ring-pink-light focus-visible:border-pink", - teal: "focus-visible:ring-teal-light focus-visible:border-teal", - gray: "focus-visible:ring-gray-300 focus-visible:border-gray-900", + primary: + "border-primary-dark/25 text-primary-dark hover:border-primary-dark/40 focus-visible:ring-primary/50", + secondary: + "border-gray-700/25 text-gray-600 hover:border-gray-700/40 focus-visible:ring-gray-500/50", + positive: + "border-green-dark/25 text-green-dark hover:border-green-dark/40 focus-visible:ring-green/50", + negative: + "border-red-dark/25 text-red-dark hover:border-red-dark/40 focus-visible:ring-red/50", + fancy: + "text-white *:z-10 before:absolute before:-inset-px before:rounded before:border before:border-transparent before:bg-gradient-to-br before:from-purple before:to-pink before:bg-origin-border after:absolute after:-inset-px after:rounded after:bg-black/10 after:opacity-0 after:transition hover:after:opacity-100 focus-visible:ring-pink/50", }, variant: { - solid: "", - outline: "", + solid: "shadow-sm", + outline: "shadow-sm", soft: "", ghost: "", }, size: { - sm: "text-xs gap-2 py-1.5 px-2", - md: "text-sm gap-3 py-2 px-3", - lg: "text-sm gap-4 py-3 px-5", + sm: "text-xs gap-[0.5ch] py-1 px-2", + md: "text-xs gap-[0.75ch] py-1.5 px-3", + lg: "text-sm gap-[1ch] py-2 px-4", }, - shape: { - rounded: "rounded-lg", - pill: "rounded-full", + iconOnly: { + true: "", + }, + loading: { + true: "[&>*:not(.animate-spin)]:text-transparent", }, }, compoundVariants: [ - // Blue - { - theme: "blue", - variant: "solid", - class: "bg-blue text-white hover:bg-blue-dark", - }, - { - theme: "blue", - variant: "outline", - class: "border-blue-light text-blue hover:bg-blue-lighter hover:border-blue", - }, - { - theme: "blue", - variant: "soft", - class: - "bg-blue-lighter text-blue hover:bg-transparent hover:border-blue focus-visible:bg-transparent", - }, - { - theme: "blue", - variant: "ghost", - class: "text-blue hover:bg-blue-lighter", - }, + // Primary + { theme: "primary", variant: "solid", class: "bg-primary text-white hover:bg-primary-dark" }, + { theme: "primary", variant: "outline", class: "hover:bg-primary-lighter" }, + { theme: "primary", variant: "soft", class: "border-transparent bg-primary-lighter" }, + { theme: "primary", variant: "ghost", class: "border-transparent hover:bg-primary-lighter" }, - // Orange - { - theme: "orange", - variant: "solid", - class: "bg-orange text-white hover:bg-orange-dark", - }, - { - theme: "orange", - variant: "outline", - class: "border-orange-light text-orange hover:bg-orange-lighter hover:border-orange", - }, - { - theme: "orange", - variant: "soft", - class: - "bg-orange-lighter text-orange hover:bg-transparent hover:border-orange focus-visible:bg-transparent", - }, - { - theme: "orange", - variant: "ghost", - class: "text-orange hover:bg-orange-lighter", - }, + // Secondary + { theme: "secondary", variant: "solid", class: "bg-gray-800 text-white hover:bg-gray-900" }, + { theme: "secondary", variant: "outline", class: "hover:bg-gray-100" }, + { theme: "secondary", variant: "soft", class: "border-transparent bg-gray-100" }, + { theme: "secondary", variant: "ghost", class: "border-transparent hover:bg-gray-100" }, - // Yellow - { - theme: "yellow", - variant: "solid", - class: "bg-yellow text-white hover:bg-yellow-dark", - }, - { - theme: "yellow", - variant: "outline", - class: "border-yellow-light text-yellow hover:bg-yellow-lighter hover:border-yellow", - }, - { - theme: "yellow", - variant: "soft", - class: - "bg-yellow-lighter text-yellow hover:bg-transparent hover:border-yellow focus-visible:bg-transparent", - }, - { - theme: "yellow", - variant: "ghost", - class: "text-yellow hover:bg-yellow-lighter", - }, + // Positive + { theme: "positive", variant: "solid", class: "bg-green text-white hover:bg-green-dark" }, + { theme: "positive", variant: "outline", class: "hover:bg-green-lighter" }, + { theme: "positive", variant: "soft", class: "border-transparent bg-green-lighter" }, + { theme: "positive", variant: "ghost", class: "border-transparent hover:bg-green-lighter" }, - // Red - { - theme: "red", - variant: "solid", - class: "bg-red text-white hover:bg-red-dark", - }, - { - theme: "red", - variant: "outline", - class: "border-red-light text-red hover:bg-red-lighter hover:border-red", - }, - { - theme: "red", - variant: "soft", - class: - "bg-red-lighter text-red hover:bg-transparent hover:border-red focus-visible:bg-transparent", - }, - { - theme: "red", - variant: "ghost", - class: "text-red hover:bg-red-lighter", - }, + // Negative + { theme: "negative", variant: "solid", class: "bg-red text-white hover:bg-red-dark" }, + { theme: "negative", variant: "outline", class: "hover:bg-red-lighter" }, + { theme: "negative", variant: "soft", class: "border-transparent bg-red-lighter" }, + { theme: "negative", variant: "ghost", class: "border-transparent hover:bg-red-lighter" }, - // Green - { - theme: "green", - variant: "solid", - class: "bg-green text-white hover:bg-green-dark", - }, - { - theme: "green", - variant: "outline", - class: "border-green-light text-green hover:bg-green-lighter hover:border-green", - }, - { - theme: "green", - variant: "soft", - class: - "bg-green-lighter text-green hover:bg-transparent hover:border-green focus-visible:bg-transparent", - }, - { - theme: "green", - variant: "ghost", - class: "text-green hover:bg-green-lighter", - }, - - // Purple - { - theme: "purple", - variant: "solid", - class: "bg-purple text-white hover:bg-purple-dark", - }, - { - theme: "purple", - variant: "outline", - class: "border-purple-light text-purple hover:bg-purple-lighter hover:border-purple", - }, - { - theme: "purple", - variant: "soft", - class: - "bg-purple-lighter text-purple hover:bg-transparent hover:border-purple focus-visible:bg-transparent", - }, - { - theme: "purple", - variant: "ghost", - class: "text-purple hover:bg-purple-lighter", - }, - - // Pink - { - theme: "pink", - variant: "solid", - class: "bg-pink text-white hover:bg-pink-dark", - }, - { - theme: "pink", - variant: "outline", - class: "border-pink-light text-pink hover:bg-pink-lighter hover:border-pink", - }, - { - theme: "pink", - variant: "soft", - class: - "bg-pink-lighter text-pink hover:bg-transparent hover:border-pink focus-visible:bg-transparent", - }, - { - theme: "pink", - variant: "ghost", - class: "text-pink hover:bg-pink-lighter", - }, - - // Teal - { - theme: "teal", - variant: "solid", - class: "bg-teal text-white hover:bg-teal-dark", - }, - { - theme: "teal", - variant: "outline", - class: "border-teal-light text-teal hover:bg-teal-lighter hover:border-teal", - }, - { - theme: "teal", - variant: "soft", - class: - "bg-teal-lighter text-teal hover:bg-transparent hover:border-teal focus-visible:bg-transparent", - }, - { - theme: "teal", - variant: "ghost", - class: "text-teal hover:bg-teal-lighter", - }, - - // Gray - { - theme: "gray", - variant: "solid", - class: "bg-gray-700 text-white hover:bg-gray-900", - }, - { - theme: "gray", - variant: "outline", - class: "border-gray-300 text-gray-500 hover:bg-gray-100 hover:border-gray-300", - }, - { - theme: "gray", - variant: "soft", - class: - "bg-gray-100 text-gray-600 hover:bg-transparent hover:border-gray-500 focus-visible:bg-transparent", - }, - { - theme: "gray", - variant: "ghost", - class: "text-gray-700 hover:bg-gray-100", - }, + // Is icon only + { size: "sm", iconOnly: true, class: "px-1" }, + { size: "md", iconOnly: true, class: "px-1.5" }, + { size: "lg", iconOnly: true, class: "px-2" }, ], defaultVariants: { - theme: "gray", + theme: "primary", variant: "solid", - size: "lg", - shape: "rounded", + size: "md", + iconOnly: false, }, }) export const buttonAffixVariants = cva({ - base: "-my-[0.21425em] -mx-[0.5em] shrink-0", + base: "shrink-0 first:-ml-[0.21425em] last:-mr-[0.21425em] only:m-0", }) diff --git a/src/ui/Card/Card.variants.ts b/src/ui/Card/Card.variants.ts index 5544adb..a06e65e 100644 --- a/src/ui/Card/Card.variants.ts +++ b/src/ui/Card/Card.variants.ts @@ -10,7 +10,7 @@ export const cardPanelVariants = cva({ variants: { position: { top: "-mt-6 -top-6 border-b md:-mt-8 md:-top-8", - bottom: "-mb-6 mt-auto bg-gray-100 -bottom-6 border-t md:-mb-8 md:-bottom-8", + bottom: "-mb-6 mt-auto bg-gray-50 -bottom-6 border-t md:-mb-8 md:-bottom-8", }, }, }) diff --git a/src/ui/Dot/Dot.tsx b/src/ui/Dot/Dot.tsx index aa6a8f5..aca7f6e 100644 --- a/src/ui/Dot/Dot.tsx +++ b/src/ui/Dot/Dot.tsx @@ -1,7 +1,6 @@ import { Slot } from "@radix-ui/react-slot" import { type HTMLAttributes, forwardRef, isValidElement } from "react" -import { useTheme } from "../../providers" import { type VariantProps } from "../../shared" import { dotVariants } from "./Dot.variants" @@ -18,10 +17,7 @@ export type DotProps = Omit, "size"> & } export const Dot = forwardRef((props, ref) => { - const { className, asChild, theme: propTheme, variant, size, ...rest } = props - - const globalTheme = useTheme() - const theme = propTheme || globalTheme + const { className, asChild, theme, variant, size, ...rest } = props const useAsChild = asChild && isValidElement(rest.children) const Component = useAsChild ? Slot : "span" @@ -32,6 +28,7 @@ export const Dot = forwardRef((props, ref) => { }) Dot.defaultProps = { + theme: "blue", variant: "solid", size: "md", asChild: false, diff --git a/src/ui/FeatureCard/FeatureCard.tsx b/src/ui/FeatureCard/FeatureCard.tsx index 7fcb91d..ec53240 100644 --- a/src/ui/FeatureCard/FeatureCard.tsx +++ b/src/ui/FeatureCard/FeatureCard.tsx @@ -3,7 +3,6 @@ import { XIcon } from "lucide-react" import { forwardRef, isValidElement } from "react" import type { ButtonHTMLAttributes, HTMLAttributes } from "react" -import { useTheme } from "../../providers" import { cx, type VariantProps } from "../../shared" import { Slottable } from "../../utils/Slottable" @@ -37,10 +36,7 @@ type FeatureCardCloserProps = ButtonHTMLAttributes & } const FeatureCardRoot = forwardRef((props, ref) => { - const { className, asChild, theme: propTheme, variant, ...rest } = props - - const globalTheme = useTheme() - const theme = propTheme || globalTheme + const { className, asChild, theme, variant, ...rest } = props const useAsChild = asChild && isValidElement(rest.children) const Component = useAsChild ? Slot : "div" @@ -90,6 +86,7 @@ export const FeatureCard = Object.assign(FeatureCardBase, { }) FeatureCard.defaultProps = { + theme: "secondary", variant: "soft", asChild: false, closeable: false, diff --git a/src/ui/FeatureCard/FeatureCard.variants.ts b/src/ui/FeatureCard/FeatureCard.variants.ts index 0b03b65..9aa1283 100644 --- a/src/ui/FeatureCard/FeatureCard.variants.ts +++ b/src/ui/FeatureCard/FeatureCard.variants.ts @@ -5,63 +5,30 @@ export const featureCardVariants = cva({ variants: { theme: { - blue: "", - orange: "", - red: "", - yellow: "", - green: "", - purple: "", - pink: "", - teal: "", - gray: "", + primary: "", + secondary: "", }, variant: { solid: "", soft: "", - outline: "border-gray-200", + outline: "", }, }, compoundVariants: [ - // Blue - { theme: "blue", variant: "solid", class: "bg-blue text-white" }, - { theme: "blue", variant: "soft", class: "bg-blue-lighter" }, - - // Orange - { theme: "orange", variant: "solid", class: "bg-orange text-white" }, - { theme: "orange", variant: "soft", class: "bg-orange-lighter" }, - - // Red - { theme: "red", variant: "solid", class: "bg-red text-white" }, - { theme: "red", variant: "soft", class: "bg-red-lighter" }, - - // Yellow - { theme: "yellow", variant: "solid", class: "bg-yellow text-white" }, - { theme: "yellow", variant: "soft", class: "bg-yellow-lighter" }, - - // Green - { theme: "green", variant: "solid", class: "bg-green text-white" }, - { theme: "green", variant: "soft", class: "bg-green-lighter" }, - - // Purple - { theme: "purple", variant: "solid", class: "bg-purple text-white" }, - { theme: "purple", variant: "soft", class: "bg-purple-lighter" }, - - // Pink - { theme: "pink", variant: "solid", class: "bg-pink text-white" }, - { theme: "pink", variant: "soft", class: "bg-pink-lighter" }, - - // Teal - { theme: "teal", variant: "solid", class: "bg-teal text-white" }, - { theme: "teal", variant: "soft", class: "bg-teal-lighter" }, - - // Gray - { theme: "gray", variant: "solid", class: "bg-gray-700 text-white" }, - { theme: "gray", variant: "soft", class: "bg-gray-100" }, + // Primary + { theme: "primary", variant: "solid", class: "bg-blue text-white" }, + { theme: "primary", variant: "soft", class: "bg-blue-lighter" }, + { theme: "primary", variant: "outline", class: "bg-white border-primary-light" }, + + // Secondary + { theme: "secondary", variant: "solid", class: "bg-gray-700 text-white" }, + { theme: "secondary", variant: "soft", class: "bg-gray-100" }, + { theme: "secondary", variant: "outline", class: "bg-white border-gray-200" }, ], defaultVariants: { - theme: "gray", + theme: "secondary", variant: "soft", }, }) diff --git a/src/ui/Loader/Loader.tsx b/src/ui/Loader/Loader.tsx index 0e737d0..cd0ac5d 100644 --- a/src/ui/Loader/Loader.tsx +++ b/src/ui/Loader/Loader.tsx @@ -1,14 +1,14 @@ -import { LoaderIcon } from "lucide-react" +import { IconLoader } from "@tabler/icons-react" import { forwardRef } from "react" import type { ComponentPropsWithoutRef, ElementRef } from "react" import { cx } from "../../shared" export const Loader = forwardRef< - ElementRef, - ComponentPropsWithoutRef + ElementRef, + ComponentPropsWithoutRef >((props, ref) => { const { className, ...rest } = props - return + return }) diff --git a/src/ui/MenuItem/MenuItem.tsx b/src/ui/MenuItem/MenuItem.tsx index 5e4d816..021832f 100644 --- a/src/ui/MenuItem/MenuItem.tsx +++ b/src/ui/MenuItem/MenuItem.tsx @@ -3,7 +3,6 @@ import { ChevronRightIcon } from "lucide-react" import { forwardRef, isValidElement } from "react" import type { ReactElement, ButtonHTMLAttributes } from "react" -import { useTheme } from "../../providers" import { cx, isChildrenEmpty, type VariantProps } from "../../shared" import { Slottable } from "../../utils/Slottable" import { Loader } from "../Loader" @@ -49,14 +48,10 @@ export const MenuItem = forwardRef((props, ref) prefix, suffix: propSuffix, loading, - theme: propTheme, active, ...rest } = props - const globalTheme = useTheme() - const theme = propTheme || globalTheme - const useAsChild = asChild && isValidElement(children) const Component = useAsChild ? Slot : "button" @@ -68,25 +63,23 @@ export const MenuItem = forwardRef((props, ref) propSuffix ) - const renderAffix = ({ children, theme }: Pick) => { + const renderAffix = (props: Pick) => { const AffixComponent = isValidElement(children) ? Slot : "span" - return ( - {children} - ) + return } return ( {(child) => ( <> - {prefix && renderAffix({ children: prefix, theme })} + {prefix && renderAffix({ children: prefix })} {!isChildrenEmpty(child) && {child}} {suffix && renderAffix({ children: suffix })} diff --git a/src/ui/MenuItem/MenuItem.variants.ts b/src/ui/MenuItem/MenuItem.variants.ts index 1c9f93a..b716319 100644 --- a/src/ui/MenuItem/MenuItem.variants.ts +++ b/src/ui/MenuItem/MenuItem.variants.ts @@ -2,51 +2,19 @@ import { cva } from "../../shared" export const menuItemVariants = cva({ base: [ - "group/menu-item relative flex items-center gap-2.5 min-w-0 px-3 py-2 rounded-md font-medium text-sm text-start text-gray-500 hover:bg-gray-200/50", + "group/menu-item relative flex items-center gap-2.5 min-w-0 px-3 py-2 rounded-md font-medium text-sm text-start text-gray-600 hover:bg-gray-100", // Pseudo - "before:absolute before:right-full before:top-1/2 before:h-2/3 before:w-1 before:mr-4 before:rounded-r-md before:-translate-y-1/2", + "before:hidden before:absolute before:right-full before:top-1/2 before:h-2/3 before:w-1 before:mr-4 before:bg-primary before:rounded-r-md before:-translate-y-1/2", // Active - "aria-[current=page]:bg-gray-200/50 aria-[current=page]:text-black aria-[current=page]:before:content-['']", + "aria-[current=page]:bg-gray-100 aria-[current=page]:text-gray-800 aria-[current=page]:before:block", // Disabled "disabled:opacity-50 disabled:cursor-not-allowed disabled:pointer-events-none", ], - - variants: { - theme: { - blue: "aria-[current=page]:before:bg-blue", - orange: "aria-[current=page]:before:bg-orange", - yellow: "aria-[current=page]:before:bg-yellow", - red: "aria-[current=page]:before:bg-red", - green: "aria-[current=page]:before:bg-green", - purple: "aria-[current=page]:before:bg-purple", - pink: "aria-[current=page]:before:bg-pink", - teal: "aria-[current=page]:before:bg-teal", - gray: "aria-[current=page]:before:bg-current", - }, - }, - - defaultVariants: { - theme: "blue", - }, }) export const menuItemAffixVariants = cva({ - base: "shrink-0", - - variants: { - theme: { - blue: "group-aria-[current=page]/menu-item:text-blue", - orange: "group-aria-[current=page]/menu-item:text-orange", - yellow: "group-aria-[current=page]/menu-item:text-yellow", - red: "group-aria-[current=page]/menu-item:text-red", - green: "group-aria-[current=page]/menu-item:text-green", - purple: "group-aria-[current=page]/menu-item:text-purple", - pink: "group-aria-[current=page]/menu-item:text-pink", - teal: "group-aria-[current=page]/menu-item:text-teal", - gray: "group-aria-[current=page]/menu-item:text-current", - }, - }, + base: "shrink-0 group-aria-[current=page]/menu-item:first:text-primary", }) diff --git a/src/ui/ProgressBar/ProgressBar.tsx b/src/ui/ProgressBar/ProgressBar.tsx index 69c03cd..4af0779 100644 --- a/src/ui/ProgressBar/ProgressBar.tsx +++ b/src/ui/ProgressBar/ProgressBar.tsx @@ -1,7 +1,6 @@ import { Slot } from "@radix-ui/react-slot" import { type HTMLAttributes, forwardRef, isValidElement } from "react" -import { useTheme } from "../../providers" import { cleanPercentage, cx, type VariantProps } from "../../shared" import type { ParagraphElement, ParagraphProps } from "../../typography/Paragraph" import { Paragraph } from "../../typography/Paragraph" @@ -47,10 +46,8 @@ const ProgressBarRoot = forwardRef((pr }) const ProgressBarBar = forwardRef((props, ref) => { - const { className, percent, theme: propTheme, ...rest } = props + const { className, percent, theme, ...rest } = props - const globalTheme = useTheme() - const theme = propTheme || globalTheme const percentage = cleanPercentage(percent) return ( diff --git a/src/ui/ProgressBar/ProgressBar.variants.ts b/src/ui/ProgressBar/ProgressBar.variants.ts index 119cb5e..2b065d0 100644 --- a/src/ui/ProgressBar/ProgressBar.variants.ts +++ b/src/ui/ProgressBar/ProgressBar.variants.ts @@ -9,7 +9,7 @@ export const progressBarLineVariants = cva({ }) export const progressBarProgressVariants = cva({ - base: "h-full rounded-full", + base: "h-full rounded-full bg-primary", variants: { theme: { diff --git a/src/ui/ProgressRing/ProgressRing.tsx b/src/ui/ProgressRing/ProgressRing.tsx index 5af2f0b..3b4997f 100644 --- a/src/ui/ProgressRing/ProgressRing.tsx +++ b/src/ui/ProgressRing/ProgressRing.tsx @@ -1,6 +1,5 @@ import { type HTMLAttributes, forwardRef } from "react" -import { useTheme } from "../../providers" import type { VariantProps } from "../../shared" import { cleanPercentage, cx } from "../../shared" @@ -18,10 +17,7 @@ export type ProgressRingProps = Omit, "size" } export const ProgressRing = forwardRef((props, ref) => { - const { className, percent, theme: propTheme, size, ...rest } = props - - const globalTheme = useTheme() - const theme = propTheme || globalTheme + const { className, percent, theme, size, ...rest } = props let svgSize = 0 diff --git a/src/ui/ProgressRing/ProgressRing.variants.ts b/src/ui/ProgressRing/ProgressRing.variants.ts index 74b2b8d..18fbbb2 100644 --- a/src/ui/ProgressRing/ProgressRing.variants.ts +++ b/src/ui/ProgressRing/ProgressRing.variants.ts @@ -17,6 +17,8 @@ export const progressRingVariants = cva({ }) export const progressRingCircleVariants = cva({ + base: "text-primary", + variants: { theme: { blue: "text-blue", diff --git a/src/ui/Status/Status.tsx b/src/ui/Status/Status.tsx index f08745e..18ae21f 100644 --- a/src/ui/Status/Status.tsx +++ b/src/ui/Status/Status.tsx @@ -2,7 +2,6 @@ import { Slot } from "@radix-ui/react-slot" import { forwardRef, isValidElement } from "react" import type { ReactElement, HTMLAttributes } from "react" -import { useTheme } from "../../providers" import type { VariantProps } from "../../shared" import { cx } from "../../shared" import { Slottable } from "../../utils/Slottable" @@ -31,20 +30,7 @@ export type StatusProps = Omit, "size" | "prefix"> } export const Status = forwardRef((props, ref) => { - const { - children, - className, - asChild, - prefix, - suffix, - theme: propTheme, - variant, - size, - ...rest - } = props - - const globalTheme = useTheme() - const theme = propTheme || globalTheme + const { children, className, asChild, prefix, suffix, theme, variant, size, ...rest } = props const useAsChild = asChild && isValidElement(children) const Component = useAsChild ? Slot : "span" @@ -77,6 +63,7 @@ export const Status = forwardRef((props, ref) => { }) Status.defaultProps = { + theme: "blue", variant: "outline", size: "sm", asChild: false, diff --git a/src/ui/Status/Status.variants.ts b/src/ui/Status/Status.variants.ts index c539995..2874ab4 100644 --- a/src/ui/Status/Status.variants.ts +++ b/src/ui/Status/Status.variants.ts @@ -23,9 +23,9 @@ export const statusVariants = cva({ outline: "bg-transparent border-gray-200 text-gray-500", }, size: { - sm: "text-2xs", - md: "text-xs", - lg: "text-sm", + sm: "text-3xs", + md: "text-2xs", + lg: "text-xs", }, }, diff --git a/tailwind.config.ts b/tailwind.config.ts index 6df424d..17ae579 100644 --- a/tailwind.config.ts +++ b/tailwind.config.ts @@ -1,4 +1,64 @@ import type { Config } from "tailwindcss" +import colors from "tailwindcss/colors" + +const colorTheme = { + blue: { + lighter: "#e6ecf8", + light: "#c8d7ef", + DEFAULT: "#3b71bc", + dark: "#244680", + darker: "#20355a", + }, + orange: { + lighter: "#FEF3EB", + light: "#FFDAC2", + DEFAULT: "#F17B2C", + dark: "#C2540A", + darker: "#6E330C", + }, + yellow: { + lighter: "#FEF7EC", + light: "#FBDFB1", + DEFAULT: "#F2AE40", + dark: "#B47818", + darker: "#693D11", + }, + red: { + lighter: "#FDEDF0", + light: "#F8C9D2", + DEFAULT: "#DF1C41", + dark: "#AF1D38", + darker: "#710E21", + }, + green: { + lighter: "#EFFAF6", + light: "#CBF5E5", + DEFAULT: "#38C793", + dark: "#2D9F75", + darker: "#176448", + }, + purple: { + lighter: "#EEEBFF", + light: "#CAC2FF", + DEFAULT: "#6E3FF3", + dark: "#5A36BF", + darker: "#2B1664", + }, + pink: { + lighter: "#FDEBFF", + light: "#F9C2FF", + DEFAULT: "#E255F2", + dark: "#9C23A9", + darker: "#620F6C", + }, + teal: { + lighter: "#EBFAFF", + light: "#C2EFFF", + DEFAULT: "#35B9E9", + dark: "#1F87AD", + darker: "#164564", + }, +} as const export default { content: ["./src/**/*.{js,ts,jsx,tsx}"], @@ -7,81 +67,18 @@ export default { theme: { colors: { - none: "none", - current: "currentColor", - transparent: "transparent", - white: "#FFFFFF", - gray: { - 100: "#F6F8FA", - 200: "#E2E4E9", - 300: "#CDD0D5", - 400: "#868C98", - 500: "#525866", - 600: "#31353F", - 700: "#20232D", - 800: "#161922", - 900: "#0A0D14", - }, - blue: { - lighter: "#EBF1FF", - light: "#C2D6FF", - DEFAULT: "#375DFB", - dark: "#253EA7", - darker: "#162664", - }, - orange: { - lighter: "#FEF3EB", - light: "#FFDAC2", - DEFAULT: "#F17B2C", - dark: "#C2540A", - darker: "#6E330C", - }, - yellow: { - lighter: "#FEF7EC", - light: "#FBDFB1", - DEFAULT: "#F2AE40", - dark: "#B47818", - darker: "#693D11", - }, - red: { - lighter: "#FDEDF0", - light: "#F8C9D2", - DEFAULT: "#DF1C41", - dark: "#AF1D38", - darker: "#710E21", - }, - green: { - lighter: "#EFFAF6", - light: "#CBF5E5", - DEFAULT: "#38C793", - dark: "#2D9F75", - darker: "#176448", - }, - purple: { - lighter: "#EEEBFF", - light: "#CAC2FF", - DEFAULT: "#6E3FF3", - dark: "#5A36BF", - darker: "#2B1664", - }, - pink: { - lighter: "#FDEBFF", - light: "#F9C2FF", - DEFAULT: "#E255F2", - dark: "#9C23A9", - darker: "#620F6C", - }, - teal: { - lighter: "#EBFAFF", - light: "#C2EFFF", - DEFAULT: "#35B9E9", - dark: "#1F87AD", - darker: "#164564", - }, + transparent: colors.transparent, + current: colors.current, + black: colors.black, + white: colors.white, + gray: colors.gray, + primary: colorTheme.orange, + ...colorTheme, }, fontSize: { - "2xs": ["11px", "12px"], - xs: ["12px", "16px"], + "3xs": ["11px", "12px"], + "2xs": ["12px", "14px"], + xs: ["13px", "16px"], sm: ["14px", "20px"], base: ["16px", "24px"], lg: ["18px", "26px"], @@ -106,15 +103,18 @@ export default { screens: { xs: "480px", }, - size: { - icon: "1.428em", - }, borderColor: { DEFAULT: "#E2E4E8", }, fontFamily: { sans: ["var(--font-sans)", "system-ui", "sans-serif"], }, + lineHeight: { + icon: "1.4285em", + }, + size: { + icon: "1.4285em", + }, typography: (theme: any) => ({ DEFAULT: { css: {