create-reactivite 1.4.0 → 1.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (150) hide show
  1. package/README.md +326 -290
  2. package/index.js +77 -2
  3. package/package.json +4 -2
  4. package/template/.storybook/main.ts +20 -0
  5. package/template/.storybook/preview.tsx +55 -0
  6. package/template/_gitignore +3 -0
  7. package/template/index.html +1 -1
  8. package/template/package.json +29 -23
  9. package/template/src/components/author-credit.tsx +25 -25
  10. package/template/src/components/ui-lib/auth-form.stories.tsx +26 -0
  11. package/template/src/components/ui-lib/auth-form.tsx +116 -0
  12. package/template/src/components/ui-lib/empty-state.stories.tsx +32 -0
  13. package/template/src/components/ui-lib/empty-state.tsx +54 -0
  14. package/template/src/components/ui-lib/feature-card.stories.tsx +45 -0
  15. package/template/src/components/ui-lib/feature-card.tsx +52 -0
  16. package/template/src/components/ui-lib/index.ts +13 -0
  17. package/template/src/components/ui-lib/page-header.stories.tsx +49 -0
  18. package/template/src/components/ui-lib/page-header.tsx +46 -0
  19. package/template/src/components/ui-lib/pricing-card.stories.tsx +58 -0
  20. package/template/src/components/ui-lib/pricing-card.tsx +86 -0
  21. package/template/src/components/ui-lib/stat-card.stories.tsx +55 -0
  22. package/template/src/components/ui-lib/stat-card.tsx +73 -0
  23. package/template/src/components/ui-lib/themes.stories.tsx +68 -0
  24. package/template/src/global.css +122 -0
  25. package/template2/.env.example +8 -8
  26. package/template2/.husky/pre-commit +4 -4
  27. package/template2/.prettierrc +5 -5
  28. package/template2/README.md +73 -73
  29. package/template2/__tests__/example.test.ts +20 -20
  30. package/template2/_gitignore +37 -37
  31. package/template2/app/[locale]/(private)/dashboard/page.tsx +52 -52
  32. package/template2/app/[locale]/(public)/login/page.tsx +83 -83
  33. package/template2/app/[locale]/layout.tsx +58 -58
  34. package/template2/app/[locale]/locales.ts +10 -10
  35. package/template2/app/[locale]/page.tsx +38 -38
  36. package/template2/app/api/clear-session/route.ts +10 -10
  37. package/template2/app/globals.css +127 -127
  38. package/template2/app/layout.tsx +7 -7
  39. package/template2/app/page.tsx +6 -6
  40. package/template2/components/AuthEventListener.tsx +22 -22
  41. package/template2/components/author-credit.tsx +25 -25
  42. package/template2/components/theme-provider.tsx +78 -78
  43. package/template2/components/ui/button.tsx +60 -60
  44. package/template2/components/ui/card.tsx +92 -92
  45. package/template2/components/ui/input.tsx +21 -21
  46. package/template2/components/ui/label.tsx +24 -24
  47. package/template2/components/ui/sonner.tsx +40 -40
  48. package/template2/components.json +22 -22
  49. package/template2/config/constants.ts +7 -7
  50. package/template2/config/env.ts +5 -5
  51. package/template2/contexts/translation-context.tsx +70 -70
  52. package/template2/eslint.config.mjs +18 -18
  53. package/template2/hoc/provider.tsx +27 -27
  54. package/template2/lib/paramsSerializer.ts +40 -40
  55. package/template2/lib/utils.ts +6 -6
  56. package/template2/locales/az.json +20 -20
  57. package/template2/locales/en.json +20 -20
  58. package/template2/next-env.d.ts +1 -1
  59. package/template2/next.config.ts +17 -17
  60. package/template2/orval.config.ts +66 -66
  61. package/template2/package.json +62 -62
  62. package/template2/postcss.config.mjs +7 -7
  63. package/template2/scripts/fix-generated-types.mjs +13 -13
  64. package/template2/services/generated/.gitkeep +2 -2
  65. package/template2/services/httpClient/httpClient.ts +70 -70
  66. package/template2/services/httpClient/orvalMutator.ts +10 -10
  67. package/template2/store/example-store.tsx +16 -16
  68. package/template2/store/user-store.tsx +29 -29
  69. package/template2/testing/msw/handlers/index.ts +6 -6
  70. package/template2/testing/msw/server.ts +4 -4
  71. package/template2/tsconfig.json +34 -34
  72. package/template2/vitest.config.ts +17 -17
  73. package/template2/vitest.setup.ts +7 -7
  74. package/template3/README.md +34 -34
  75. package/template3/_gitignore +16 -16
  76. package/template3/components.json +21 -0
  77. package/template3/index.html +8 -2
  78. package/template3/package.json +48 -22
  79. package/template3/postcss.config.mjs +5 -0
  80. package/template3/rspack.config.mjs +59 -51
  81. package/template3/src/App.tsx +16 -11
  82. package/template3/src/components/author-credit.tsx +42 -42
  83. package/template3/src/components/layout.tsx +59 -0
  84. package/template3/src/components/matrix-rain.tsx +71 -0
  85. package/template3/src/components/ui/accordion.tsx +64 -0
  86. package/template3/src/components/ui/alert-dialog.tsx +196 -0
  87. package/template3/src/components/ui/alert.tsx +66 -0
  88. package/template3/src/components/ui/aspect-ratio.tsx +11 -0
  89. package/template3/src/components/ui/avatar.tsx +107 -0
  90. package/template3/src/components/ui/badge.tsx +48 -0
  91. package/template3/src/components/ui/breadcrumb.tsx +109 -0
  92. package/template3/src/components/ui/button-group.tsx +83 -0
  93. package/template3/src/components/ui/button.tsx +64 -0
  94. package/template3/src/components/ui/calendar.tsx +218 -0
  95. package/template3/src/components/ui/card.tsx +92 -0
  96. package/template3/src/components/ui/carousel.tsx +241 -0
  97. package/template3/src/components/ui/chart.tsx +372 -0
  98. package/template3/src/components/ui/checkbox.tsx +32 -0
  99. package/template3/src/components/ui/collapsible.tsx +31 -0
  100. package/template3/src/components/ui/combobox.tsx +310 -0
  101. package/template3/src/components/ui/command.tsx +184 -0
  102. package/template3/src/components/ui/context-menu.tsx +252 -0
  103. package/template3/src/components/ui/dialog.tsx +156 -0
  104. package/template3/src/components/ui/direction.tsx +22 -0
  105. package/template3/src/components/ui/drawer.tsx +133 -0
  106. package/template3/src/components/ui/dropdown-menu.tsx +257 -0
  107. package/template3/src/components/ui/empty.tsx +104 -0
  108. package/template3/src/components/ui/field.tsx +248 -0
  109. package/template3/src/components/ui/form.tsx +165 -0
  110. package/template3/src/components/ui/hover-card.tsx +42 -0
  111. package/template3/src/components/ui/input-group.tsx +168 -0
  112. package/template3/src/components/ui/input-otp.tsx +77 -0
  113. package/template3/src/components/ui/input.tsx +21 -0
  114. package/template3/src/components/ui/item.tsx +193 -0
  115. package/template3/src/components/ui/kbd.tsx +28 -0
  116. package/template3/src/components/ui/label.tsx +22 -0
  117. package/template3/src/components/ui/menubar.tsx +276 -0
  118. package/template3/src/components/ui/native-select.tsx +62 -0
  119. package/template3/src/components/ui/navigation-menu.tsx +168 -0
  120. package/template3/src/components/ui/pagination.tsx +127 -0
  121. package/template3/src/components/ui/popover.tsx +87 -0
  122. package/template3/src/components/ui/progress.tsx +31 -0
  123. package/template3/src/components/ui/radio-group.tsx +43 -0
  124. package/template3/src/components/ui/resizable.tsx +53 -0
  125. package/template3/src/components/ui/scroll-area.tsx +56 -0
  126. package/template3/src/components/ui/select.tsx +190 -0
  127. package/template3/src/components/ui/separator.tsx +26 -0
  128. package/template3/src/components/ui/sheet.tsx +143 -0
  129. package/template3/src/components/ui/sidebar.tsx +724 -0
  130. package/template3/src/components/ui/skeleton.tsx +13 -0
  131. package/template3/src/components/ui/slider.tsx +61 -0
  132. package/template3/src/components/ui/sonner.tsx +40 -0
  133. package/template3/src/components/ui/spinner.tsx +16 -0
  134. package/template3/src/components/ui/switch.tsx +33 -0
  135. package/template3/src/components/ui/table.tsx +116 -0
  136. package/template3/src/components/ui/tabs.tsx +89 -0
  137. package/template3/src/components/ui/textarea.tsx +18 -0
  138. package/template3/src/components/ui/toggle-group.tsx +83 -0
  139. package/template3/src/components/ui/toggle.tsx +47 -0
  140. package/template3/src/components/ui/tooltip.tsx +55 -0
  141. package/template3/src/hooks/use-mobile.ts +19 -0
  142. package/template3/src/index.css +175 -32
  143. package/template3/src/lib/utils.ts +6 -0
  144. package/template3/src/main.tsx +10 -10
  145. package/template3/src/pages/about.tsx +113 -0
  146. package/template3/src/pages/contact.tsx +111 -0
  147. package/template3/src/pages/home.tsx +81 -0
  148. package/template3/tsconfig.json +24 -20
  149. package/template/pnpm-lock.yaml +0 -3274
  150. package/template2/tsconfig.tsbuildinfo +0 -1
@@ -0,0 +1,52 @@
1
+ import * as React from "react"
2
+ import { type LucideIcon } from "lucide-react"
3
+
4
+ import { cn } from "@/lib/utils"
5
+ import {
6
+ Card,
7
+ CardContent,
8
+ CardDescription,
9
+ CardHeader,
10
+ CardTitle,
11
+ } from "@/components/ui/card"
12
+
13
+ export interface FeatureCardProps extends React.ComponentProps<typeof Card> {
14
+ icon: LucideIcon
15
+ title: string
16
+ description: string
17
+ }
18
+
19
+ /**
20
+ * FeatureCard — marketing/feature tile composed from Card.
21
+ * The icon chip uses primary/accent vars so it re-skins per theme.
22
+ */
23
+ export function FeatureCard({
24
+ icon: Icon,
25
+ title,
26
+ description,
27
+ className,
28
+ ...props
29
+ }: FeatureCardProps) {
30
+ return (
31
+ <Card
32
+ className={cn(
33
+ "gap-4 transition-shadow hover:shadow-md",
34
+ className
35
+ )}
36
+ {...props}
37
+ >
38
+ <CardHeader>
39
+ <span className="bg-primary text-primary-foreground mb-2 flex size-11 items-center justify-center rounded-lg">
40
+ <Icon className="size-5" />
41
+ </span>
42
+ <CardTitle>{title}</CardTitle>
43
+ <CardDescription>{description}</CardDescription>
44
+ </CardHeader>
45
+ <CardContent className="text-muted-foreground text-sm">
46
+ <span className="text-foreground font-medium underline-offset-4 hover:underline cursor-pointer">
47
+ Learn more →
48
+ </span>
49
+ </CardContent>
50
+ </Card>
51
+ )
52
+ }
@@ -0,0 +1,13 @@
1
+ /**
2
+ * ui-lib — composed components built on top of shadcn/ui primitives
3
+ * (src/components/ui). These are the building blocks meant for use
4
+ * inside the template's pages. Every one is var-driven, so it adapts
5
+ * to the active `data-theme` (minimal | brutalist | aurora) with no
6
+ * per-theme code. See each component's Storybook story for variants.
7
+ */
8
+ export { StatCard, type StatCardProps } from "./stat-card"
9
+ export { FeatureCard, type FeatureCardProps } from "./feature-card"
10
+ export { PricingCard, type PricingCardProps } from "./pricing-card"
11
+ export { AuthForm, type AuthFormProps } from "./auth-form"
12
+ export { EmptyState, type EmptyStateProps } from "./empty-state"
13
+ export { PageHeader, type PageHeaderProps } from "./page-header"
@@ -0,0 +1,49 @@
1
+ import type { Meta, StoryObj } from "@storybook/react-vite";
2
+ import { Plus, Download } from "lucide-react";
3
+
4
+ import { PageHeader } from "./page-header";
5
+ import { Button } from "@/components/ui/button";
6
+
7
+ const meta = {
8
+ title: "UI Library/PageHeader",
9
+ component: PageHeader,
10
+ tags: ["autodocs"],
11
+ parameters: { layout: "padded" },
12
+ } satisfies Meta<typeof PageHeader>;
13
+
14
+ export default meta;
15
+ type Story = StoryObj<typeof meta>;
16
+
17
+ export const Default: Story = {
18
+ args: {
19
+ eyebrow: "Workspace",
20
+ title: "Projects",
21
+ description: "Manage and organize all of your team's projects.",
22
+ },
23
+ render: (args) => (
24
+ <div className="w-full max-w-3xl">
25
+ <PageHeader
26
+ {...args}
27
+ actions={
28
+ <>
29
+ <Button variant="outline">
30
+ <Download /> Export
31
+ </Button>
32
+ <Button>
33
+ <Plus /> New
34
+ </Button>
35
+ </>
36
+ }
37
+ />
38
+ </div>
39
+ ),
40
+ };
41
+
42
+ export const TitleOnly: Story = {
43
+ args: { title: "Settings" },
44
+ render: (args) => (
45
+ <div className="w-full max-w-3xl">
46
+ <PageHeader {...args} />
47
+ </div>
48
+ ),
49
+ };
@@ -0,0 +1,46 @@
1
+ import * as React from "react"
2
+
3
+ import { cn } from "@/lib/utils"
4
+ import { Separator } from "@/components/ui/separator"
5
+
6
+ export interface PageHeaderProps extends React.ComponentProps<"div"> {
7
+ title: string
8
+ description?: string
9
+ /** Right-aligned action slot, e.g. buttons. */
10
+ actions?: React.ReactNode
11
+ /** Optional eyebrow / breadcrumb line above the title. */
12
+ eyebrow?: string
13
+ }
14
+
15
+ /**
16
+ * PageHeader — the title block at the top of a page/section.
17
+ * title + description on the left, actions on the right, then a rule.
18
+ */
19
+ export function PageHeader({
20
+ title,
21
+ description,
22
+ actions,
23
+ eyebrow,
24
+ className,
25
+ ...props
26
+ }: PageHeaderProps) {
27
+ return (
28
+ <div className={cn("space-y-4", className)} {...props}>
29
+ <div className="flex flex-col gap-4 sm:flex-row sm:items-end sm:justify-between">
30
+ <div className="space-y-1">
31
+ {eyebrow && (
32
+ <p className="text-muted-foreground text-xs font-medium tracking-wide uppercase">
33
+ {eyebrow}
34
+ </p>
35
+ )}
36
+ <h1 className="text-2xl font-semibold tracking-tight">{title}</h1>
37
+ {description && (
38
+ <p className="text-muted-foreground text-sm">{description}</p>
39
+ )}
40
+ </div>
41
+ {actions && <div className="flex items-center gap-2">{actions}</div>}
42
+ </div>
43
+ <Separator />
44
+ </div>
45
+ )
46
+ }
@@ -0,0 +1,58 @@
1
+ import type { Meta, StoryObj } from "@storybook/react-vite";
2
+
3
+ import { PricingCard } from "./pricing-card";
4
+
5
+ const meta = {
6
+ title: "UI Library/PricingCard",
7
+ component: PricingCard,
8
+ tags: ["autodocs"],
9
+ } satisfies Meta<typeof PricingCard>;
10
+
11
+ export default meta;
12
+ type Story = StoryObj<typeof meta>;
13
+
14
+ export const Default: Story = {
15
+ args: {
16
+ plan: "Pro",
17
+ price: "$29",
18
+ description: "For growing teams that need more power.",
19
+ features: ["Unlimited projects", "Priority support", "Advanced analytics", "Custom domains"],
20
+ featured: false,
21
+ },
22
+ };
23
+
24
+ export const Featured: Story = {
25
+ args: {
26
+ ...Default.args,
27
+ featured: true,
28
+ },
29
+ };
30
+
31
+ export const Tiers: Story = {
32
+ args: { plan: "Pro", price: "$29", features: [] },
33
+ render: () => (
34
+ <div className="grid w-full max-w-4xl grid-cols-1 gap-6 sm:grid-cols-3">
35
+ <PricingCard
36
+ plan="Starter"
37
+ price="$0"
38
+ description="For side projects."
39
+ features={["1 project", "Community support", "1 GB storage"]}
40
+ cta="Start free"
41
+ />
42
+ <PricingCard
43
+ plan="Pro"
44
+ price="$29"
45
+ description="For growing teams."
46
+ features={["Unlimited projects", "Priority support", "Analytics"]}
47
+ featured
48
+ />
49
+ <PricingCard
50
+ plan="Enterprise"
51
+ price="$99"
52
+ description="For large orgs."
53
+ features={["SSO + SAML", "Dedicated support", "SLA", "Audit logs"]}
54
+ cta="Contact sales"
55
+ />
56
+ </div>
57
+ ),
58
+ };
@@ -0,0 +1,86 @@
1
+ import * as React from "react"
2
+ import { Check } from "lucide-react"
3
+
4
+ import { cn } from "@/lib/utils"
5
+ import { Badge } from "@/components/ui/badge"
6
+ import { Button } from "@/components/ui/button"
7
+ import {
8
+ Card,
9
+ CardContent,
10
+ CardDescription,
11
+ CardFooter,
12
+ CardHeader,
13
+ CardTitle,
14
+ } from "@/components/ui/card"
15
+
16
+ export interface PricingCardProps extends React.ComponentProps<typeof Card> {
17
+ plan: string
18
+ price: string
19
+ period?: string
20
+ description?: string
21
+ features: string[]
22
+ cta?: string
23
+ /** Highlights the card with a ring + badge — the "recommended" plan. */
24
+ featured?: boolean
25
+ onSelect?: () => void
26
+ }
27
+
28
+ /**
29
+ * PricingCard — pricing tier composed from Card + Badge + Button + check list.
30
+ */
31
+ export function PricingCard({
32
+ plan,
33
+ price,
34
+ period = "/mo",
35
+ description,
36
+ features,
37
+ cta = "Get started",
38
+ featured = false,
39
+ onSelect,
40
+ className,
41
+ ...props
42
+ }: PricingCardProps) {
43
+ return (
44
+ <Card
45
+ className={cn(
46
+ "relative gap-6",
47
+ featured && "ring-primary ring-2",
48
+ className
49
+ )}
50
+ {...props}
51
+ >
52
+ {featured && (
53
+ <Badge className="absolute -top-3 left-6">Most popular</Badge>
54
+ )}
55
+ <CardHeader>
56
+ <CardDescription>{plan}</CardDescription>
57
+ <CardTitle className="flex items-baseline gap-1">
58
+ <span className="text-4xl font-bold tracking-tight">{price}</span>
59
+ <span className="text-muted-foreground text-sm font-normal">
60
+ {period}
61
+ </span>
62
+ </CardTitle>
63
+ {description && <CardDescription>{description}</CardDescription>}
64
+ </CardHeader>
65
+ <CardContent>
66
+ <ul className="space-y-2.5 text-sm">
67
+ {features.map((f) => (
68
+ <li key={f} className="flex items-center gap-2">
69
+ <Check className="text-primary size-4 shrink-0" />
70
+ <span>{f}</span>
71
+ </li>
72
+ ))}
73
+ </ul>
74
+ </CardContent>
75
+ <CardFooter>
76
+ <Button
77
+ className="w-full"
78
+ variant={featured ? "default" : "outline"}
79
+ onClick={onSelect}
80
+ >
81
+ {cta}
82
+ </Button>
83
+ </CardFooter>
84
+ </Card>
85
+ )
86
+ }
@@ -0,0 +1,55 @@
1
+ import type { Meta, StoryObj } from "@storybook/react-vite";
2
+ import { DollarSign, Users, Activity } from "lucide-react";
3
+
4
+ import { StatCard } from "./stat-card";
5
+
6
+ const meta = {
7
+ title: "UI Library/StatCard",
8
+ component: StatCard,
9
+ tags: ["autodocs"],
10
+ argTypes: {
11
+ delta: { control: { type: "number" } },
12
+ },
13
+ } satisfies Meta<typeof StatCard>;
14
+
15
+ export default meta;
16
+ type Story = StoryObj<typeof meta>;
17
+
18
+ export const Default: Story = {
19
+ args: {
20
+ label: "Total revenue",
21
+ value: "$48,120",
22
+ delta: 12.4,
23
+ hint: "vs last month",
24
+ icon: DollarSign,
25
+ },
26
+ };
27
+
28
+ export const Negative: Story = {
29
+ args: {
30
+ label: "Churn rate",
31
+ value: "3.8%",
32
+ delta: -2.1,
33
+ hint: "vs last month",
34
+ icon: Activity,
35
+ },
36
+ };
37
+
38
+ export const NoDelta: Story = {
39
+ args: {
40
+ label: "Active users",
41
+ value: "12,840",
42
+ icon: Users,
43
+ },
44
+ };
45
+
46
+ export const Grid: Story = {
47
+ args: { label: "Total revenue", value: "$48,120", delta: 12.4, icon: DollarSign },
48
+ render: () => (
49
+ <div className="grid w-full max-w-3xl grid-cols-1 gap-4 sm:grid-cols-3">
50
+ <StatCard label="Revenue" value="$48,120" delta={12.4} icon={DollarSign} />
51
+ <StatCard label="Users" value="12,840" delta={4.2} icon={Users} />
52
+ <StatCard label="Churn" value="3.8%" delta={-2.1} icon={Activity} />
53
+ </div>
54
+ ),
55
+ };
@@ -0,0 +1,73 @@
1
+ import * as React from "react"
2
+ import { type LucideIcon, TrendingDown, TrendingUp } from "lucide-react"
3
+
4
+ import { cn } from "@/lib/utils"
5
+ import { Badge } from "@/components/ui/badge"
6
+ import {
7
+ Card,
8
+ CardAction,
9
+ CardContent,
10
+ CardDescription,
11
+ CardHeader,
12
+ CardTitle,
13
+ } from "@/components/ui/card"
14
+
15
+ export interface StatCardProps extends React.ComponentProps<typeof Card> {
16
+ /** Metric label, e.g. "Total revenue". */
17
+ label: string
18
+ /** Big value, e.g. "$48,120". */
19
+ value: React.ReactNode
20
+ /** Optional period / context line under the value. */
21
+ hint?: string
22
+ /** Signed percentage change. Positive renders up + accent, negative down + destructive. */
23
+ delta?: number
24
+ /** Icon shown top-right. */
25
+ icon?: LucideIcon
26
+ }
27
+
28
+ /**
29
+ * StatCard — a dashboard KPI tile composed from Card + Badge.
30
+ * Purely var-driven, so it adopts whatever `data-theme` is active.
31
+ */
32
+ export function StatCard({
33
+ label,
34
+ value,
35
+ hint,
36
+ delta,
37
+ icon: Icon,
38
+ className,
39
+ ...props
40
+ }: StatCardProps) {
41
+ const up = (delta ?? 0) >= 0
42
+ return (
43
+ <Card className={cn("gap-3", className)} {...props}>
44
+ <CardHeader>
45
+ <CardDescription>{label}</CardDescription>
46
+ <CardTitle className="text-3xl font-semibold tabular-nums tracking-tight">
47
+ {value}
48
+ </CardTitle>
49
+ {Icon ? (
50
+ <CardAction>
51
+ <span className="bg-muted text-muted-foreground flex size-9 items-center justify-center rounded-md">
52
+ <Icon className="size-4" />
53
+ </span>
54
+ </CardAction>
55
+ ) : null}
56
+ </CardHeader>
57
+ {(delta !== undefined || hint) && (
58
+ <CardContent className="flex items-center gap-2">
59
+ {delta !== undefined && (
60
+ <Badge variant={up ? "default" : "destructive"}>
61
+ {up ? <TrendingUp /> : <TrendingDown />}
62
+ {up ? "+" : ""}
63
+ {delta}%
64
+ </Badge>
65
+ )}
66
+ {hint && (
67
+ <span className="text-muted-foreground text-xs">{hint}</span>
68
+ )}
69
+ </CardContent>
70
+ )}
71
+ </Card>
72
+ )
73
+ }
@@ -0,0 +1,68 @@
1
+ import type { Meta, StoryObj } from "@storybook/react-vite";
2
+ import { DollarSign, Zap } from "lucide-react";
3
+
4
+ import { StatCard } from "./stat-card";
5
+ import { FeatureCard } from "./feature-card";
6
+ import { PricingCard } from "./pricing-card";
7
+ import { Button } from "@/components/ui/button";
8
+ import { Badge } from "@/components/ui/badge";
9
+
10
+ const THEMES = ["minimal", "brutalist", "aurora"] as const;
11
+
12
+ /** A compact sampler rendered once per theme, side by side. */
13
+ function Sampler() {
14
+ return (
15
+ <div className="grid w-72 gap-4">
16
+ <div className="flex flex-wrap items-center gap-2">
17
+ <Button size="sm">Primary</Button>
18
+ <Button size="sm" variant="outline">
19
+ Outline
20
+ </Button>
21
+ <Badge>New</Badge>
22
+ </div>
23
+ <StatCard label="Revenue" value="$48,120" delta={12.4} icon={DollarSign} />
24
+ <FeatureCard
25
+ icon={Zap}
26
+ title="Themeable"
27
+ description="One attribute re-skins everything."
28
+ />
29
+ <PricingCard
30
+ plan="Pro"
31
+ price="$29"
32
+ features={["Unlimited", "Support", "Analytics"]}
33
+ featured
34
+ />
35
+ </div>
36
+ );
37
+ }
38
+
39
+ const meta = {
40
+ title: "UI Library/Themes",
41
+ parameters: { layout: "fullscreen" },
42
+ } satisfies Meta;
43
+
44
+ export default meta;
45
+ type Story = StoryObj<typeof meta>;
46
+
47
+ /**
48
+ * All three themes at once. Each column hard-sets its own `data-theme`,
49
+ * overriding the toolbar selection — this is the "3 variants" overview.
50
+ */
51
+ export const AllThemes: Story = {
52
+ render: () => (
53
+ <div className="flex flex-wrap gap-6 p-2">
54
+ {THEMES.map((t) => (
55
+ <div
56
+ key={t}
57
+ data-theme={t}
58
+ className="bg-background text-foreground rounded-xl border p-5"
59
+ >
60
+ <p className="text-muted-foreground mb-4 text-xs font-medium tracking-wide uppercase">
61
+ {t}
62
+ </p>
63
+ <Sampler />
64
+ </div>
65
+ ))}
66
+ </div>
67
+ ),
68
+ };
@@ -74,6 +74,128 @@
74
74
  --sidebar-ring: oklch(0.439 0 0);
75
75
  }
76
76
 
77
+ /* ──────────────────────────────────────────────────────────────
78
+ UI LIBRARY THEMES
79
+ 3 distinct, var-driven looks. Switch by setting `data-theme` on
80
+ <html>: "minimal" | "brutalist" | "aurora". Every shadcn + ui-lib
81
+ component reads these vars, so themes need ZERO component changes.
82
+ Default theme is set in index.html. The base :root above stays the
83
+ neutral-dark fallback when no data-theme is present.
84
+ ────────────────────────────────────────────────────────────── */
85
+
86
+ /* Theme 1 — MINIMAL: light, calm neutrals, soft radius, editorial. */
87
+ [data-theme="minimal"] {
88
+ --background: oklch(1 0 0);
89
+ --foreground: oklch(0.18 0 0);
90
+ --card: oklch(1 0 0);
91
+ --card-foreground: oklch(0.18 0 0);
92
+ --popover: oklch(1 0 0);
93
+ --popover-foreground: oklch(0.18 0 0);
94
+ --primary: oklch(0.21 0 0);
95
+ --primary-foreground: oklch(0.98 0 0);
96
+ --secondary: oklch(0.97 0 0);
97
+ --secondary-foreground: oklch(0.21 0 0);
98
+ --muted: oklch(0.97 0 0);
99
+ --muted-foreground: oklch(0.52 0 0);
100
+ --accent: oklch(0.96 0 0);
101
+ --accent-foreground: oklch(0.21 0 0);
102
+ --destructive: oklch(0.577 0.245 27.325);
103
+ --destructive-foreground: oklch(0.98 0 0);
104
+ --border: oklch(0.92 0 0);
105
+ --input: oklch(0.92 0 0);
106
+ --ring: oklch(0.7 0 0);
107
+ --radius: 0.625rem;
108
+ --sidebar: oklch(0.985 0 0);
109
+ --sidebar-foreground: oklch(0.18 0 0);
110
+ --sidebar-primary: oklch(0.21 0 0);
111
+ --sidebar-primary-foreground: oklch(0.985 0 0);
112
+ --sidebar-accent: oklch(0.96 0 0);
113
+ --sidebar-accent-foreground: oklch(0.21 0 0);
114
+ --sidebar-border: oklch(0.92 0 0);
115
+ --sidebar-ring: oklch(0.7 0 0);
116
+ --chart-1: oklch(0.646 0.222 41.116);
117
+ --chart-2: oklch(0.6 0.118 184.704);
118
+ --chart-3: oklch(0.398 0.07 227.392);
119
+ --chart-4: oklch(0.828 0.189 84.429);
120
+ --chart-5: oklch(0.769 0.188 70.08);
121
+ }
122
+
123
+ /* Theme 2 — BRUTALIST: stark black/white, acid-yellow accent, 0 radius,
124
+ pure-black borders. High-contrast, raw, intentionally loud. */
125
+ [data-theme="brutalist"] {
126
+ --background: oklch(0.98 0 0);
127
+ --foreground: oklch(0 0 0);
128
+ --card: oklch(1 0 0);
129
+ --card-foreground: oklch(0 0 0);
130
+ --popover: oklch(1 0 0);
131
+ --popover-foreground: oklch(0 0 0);
132
+ --primary: oklch(0 0 0);
133
+ --primary-foreground: oklch(1 0 0);
134
+ --secondary: oklch(0.93 0.19 102);
135
+ --secondary-foreground: oklch(0 0 0);
136
+ --muted: oklch(0.95 0 0);
137
+ --muted-foreground: oklch(0.35 0 0);
138
+ --accent: oklch(0.93 0.19 102);
139
+ --accent-foreground: oklch(0 0 0);
140
+ --destructive: oklch(0.55 0.24 27);
141
+ --destructive-foreground: oklch(1 0 0);
142
+ --border: oklch(0 0 0);
143
+ --input: oklch(0 0 0);
144
+ --ring: oklch(0 0 0);
145
+ --radius: 0rem;
146
+ --sidebar: oklch(1 0 0);
147
+ --sidebar-foreground: oklch(0 0 0);
148
+ --sidebar-primary: oklch(0 0 0);
149
+ --sidebar-primary-foreground: oklch(1 0 0);
150
+ --sidebar-accent: oklch(0.93 0.19 102);
151
+ --sidebar-accent-foreground: oklch(0 0 0);
152
+ --sidebar-border: oklch(0 0 0);
153
+ --sidebar-ring: oklch(0 0 0);
154
+ --chart-1: oklch(0 0 0);
155
+ --chart-2: oklch(0.93 0.19 102);
156
+ --chart-3: oklch(0.55 0.24 27);
157
+ --chart-4: oklch(0.5 0 0);
158
+ --chart-5: oklch(0.75 0 0);
159
+ }
160
+
161
+ /* Theme 3 — AURORA: deep violet dark, neon violet/cyan accents,
162
+ generous radius. Glowy, premium, night-mode product feel. */
163
+ [data-theme="aurora"] {
164
+ --background: oklch(0.16 0.02 280);
165
+ --foreground: oklch(0.96 0.01 280);
166
+ --card: oklch(0.2 0.03 280);
167
+ --card-foreground: oklch(0.96 0.01 280);
168
+ --popover: oklch(0.2 0.03 280);
169
+ --popover-foreground: oklch(0.96 0.01 280);
170
+ --primary: oklch(0.7 0.18 295);
171
+ --primary-foreground: oklch(0.16 0.02 280);
172
+ --secondary: oklch(0.28 0.04 280);
173
+ --secondary-foreground: oklch(0.96 0.01 280);
174
+ --muted: oklch(0.26 0.03 280);
175
+ --muted-foreground: oklch(0.72 0.03 280);
176
+ --accent: oklch(0.55 0.16 230);
177
+ --accent-foreground: oklch(0.98 0 0);
178
+ --destructive: oklch(0.62 0.24 18);
179
+ --destructive-foreground: oklch(0.98 0 0);
180
+ --border: oklch(0.32 0.04 280);
181
+ --input: oklch(0.3 0.04 280);
182
+ --ring: oklch(0.7 0.18 295);
183
+ --radius: 1rem;
184
+ --sidebar: oklch(0.18 0.025 280);
185
+ --sidebar-foreground: oklch(0.96 0.01 280);
186
+ --sidebar-primary: oklch(0.7 0.18 295);
187
+ --sidebar-primary-foreground: oklch(0.16 0.02 280);
188
+ --sidebar-accent: oklch(0.28 0.04 280);
189
+ --sidebar-accent-foreground: oklch(0.96 0.01 280);
190
+ --sidebar-border: oklch(0.32 0.04 280);
191
+ --sidebar-ring: oklch(0.7 0.18 295);
192
+ --chart-1: oklch(0.7 0.18 295);
193
+ --chart-2: oklch(0.6 0.16 230);
194
+ --chart-3: oklch(0.75 0.17 160);
195
+ --chart-4: oklch(0.7 0.19 20);
196
+ --chart-5: oklch(0.8 0.16 90);
197
+ }
198
+
77
199
  @theme inline {
78
200
  --font-sans: var(--font-geist-sans);
79
201
  --font-mono: var(--font-geist-mono);
@@ -1,8 +1,8 @@
1
- # Public API base URL used by the browser (axios httpClient).
2
- NEXT_PUBLIC_API_BASE_URL=/api/backend
3
-
4
- # Server-side backend URL proxied via next.config.ts rewrites.
5
- API_BASE_URL=http://localhost:8080/api
6
-
7
- # OpenAPI schema used by orval (npm run generate:api).
8
- OPENAPI_TARGET=http://localhost:8080/v3/api-docs
1
+ # Public API base URL used by the browser (axios httpClient).
2
+ NEXT_PUBLIC_API_BASE_URL=/api/backend
3
+
4
+ # Server-side backend URL proxied via next.config.ts rewrites.
5
+ API_BASE_URL=http://localhost:8080/api
6
+
7
+ # OpenAPI schema used by orval (npm run generate:api).
8
+ OPENAPI_TARGET=http://localhost:8080/v3/api-docs
@@ -1,4 +1,4 @@
1
- npx figlet "Nextivite"
2
- echo "Pre-commit: lint + format + tests"
3
-
4
- npm run lint && npm run format && npm run test:run
1
+ npx figlet "Nextivite"
2
+ echo "Pre-commit: lint + format + tests"
3
+
4
+ npm run lint && npm run format && npm run test:run
@@ -1,5 +1,5 @@
1
- {
2
- "singleQuote": true,
3
- "trailingComma": "all",
4
- "printWidth": 80
5
- }
1
+ {
2
+ "singleQuote": true,
3
+ "trailingComma": "all",
4
+ "printWidth": 80
5
+ }