shadcn-theme-menu 1.1.4 → 1.1.8

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.
package/README.md CHANGED
@@ -1,5 +1,5 @@
1
1
  <p align="center">
2
- <img width="350px" src="https://i.imgur.com/7yMcnSI.png" />
2
+ <img width="350px" src="https://i.imgur.com/mgErPzk.png" />
3
3
  <p align="center">
4
4
  <a href="https://discord.gg/SJdBqBz3tV">
5
5
  <img src="https://img.shields.io/discord/1110227955554209923.svg?label=Chat&logo=Discord&colorB=7289da&style=flat"
@@ -31,6 +31,17 @@
31
31
 
32
32
  Beautiful theme components for shadcn/ui with 24+ color themes, dark/light mode, and animations.
33
33
 
34
+ ## Features
35
+
36
+ - **24+ pre-made themes** – from minimal and elegant to cyberpunk and app-inspired designs
37
+ - **OKLCH colors** – modern color space for perceptually uniform colors and better accessibility
38
+ - **Drop-in components** – `ThemeToggle`, `ThemeDropdown`, and `CinematicThemeSwitcher` with particle effects
39
+ - **Fully type-safe** – complete TypeScript support with exported types
40
+ - **Customizable** – pass your own Button/DropdownMenu components or set themes programmatically
41
+ - **Persistent** – automatic `localStorage` support for color theme preferences
42
+
43
+ ---
44
+
34
45
  ## Installation
35
46
 
36
47
  ```bash
@@ -75,6 +86,7 @@ Simple light/dark mode toggle.
75
86
  ```
76
87
 
77
88
  **Props:**
89
+
78
90
  - `mode?` - Include system option (default: `'light-dark-system'`)
79
91
  - `Button?` - Custom Button component
80
92
  - `DropdownMenu?` - Custom DropdownMenu components
@@ -93,6 +105,7 @@ Full dropdown with 24+ color themes and live preview.
93
105
  ```
94
106
 
95
107
  **Props:**
108
+
96
109
  - `iconSrc?` - Custom icon path (default: Palette icon)
97
110
  - `Button?` - Custom Button component
98
111
  - `DropdownMenu?` - Custom DropdownMenu components
@@ -116,8 +129,8 @@ Animated toggle with particle effects.
116
129
  Pass your own Button or DropdownMenu components:
117
130
 
118
131
  ```tsx
119
- import { Button } from '@/components/ui/button';
120
- import * as DropdownMenu from '@radix-ui/react-dropdown-menu';
132
+ import { Button } from "@/components/ui/button";
133
+ import * as DropdownMenu from "@radix-ui/react-dropdown-menu";
121
134
 
122
135
  <ThemeDropdown
123
136
  Button={Button}
@@ -127,27 +140,29 @@ import * as DropdownMenu from '@radix-ui/react-dropdown-menu';
127
140
  Content: DropdownMenu.Content,
128
141
  Item: DropdownMenu.Item,
129
142
  Label: DropdownMenu.Label,
130
- Separator: DropdownMenu.Separator
143
+ Separator: DropdownMenu.Separator,
131
144
  }}
132
- />
145
+ />;
133
146
  ```
134
147
 
135
148
  ## Programmatic Usage
136
149
 
137
150
  ```tsx
138
- import { themeNames, themeColors, formatThemeName } from 'shadcn-theme-menu';
151
+ import { themeNames, themeColors, formatThemeName } from "shadcn-theme-menu";
139
152
 
140
153
  // Set theme programmatically
141
154
  const setTheme = (themeName: string) => {
142
- localStorage.setItem('color-theme', themeName);
143
- themeNames.forEach(t => document.documentElement.classList.remove(`theme-${t}`));
155
+ localStorage.setItem("color-theme", themeName);
156
+ themeNames.forEach((t) =>
157
+ document.documentElement.classList.remove(`theme-${t}`),
158
+ );
144
159
  document.documentElement.classList.add(`theme-${themeName}`);
145
160
  };
146
161
 
147
162
  // Get theme info
148
163
  console.log(themeNames); // Array of all theme names
149
- console.log(themeColors['cyberpunk']); // { primary: '#ff00c8', secondary: '#f0f0ff' }
150
- console.log(formatThemeName('modern-minimal')); // 'Modern Minimal'
164
+ console.log(themeColors["cyberpunk"]); // { primary: '#ff00c8', secondary: '#f0f0ff' }
165
+ console.log(formatThemeName("modern-minimal")); // 'Modern Minimal'
151
166
  ```
152
167
 
153
168
  ## TypeScript
@@ -155,7 +170,7 @@ console.log(formatThemeName('modern-minimal')); // 'Modern Minimal'
155
170
  Full TypeScript support with exported types:
156
171
 
157
172
  ```tsx
158
- import type { ThemeProviderProps } from 'shadcn-theme-menu';
173
+ import type { ThemeProviderProps } from "shadcn-theme-menu";
159
174
  ```
160
175
 
161
176
  ## Demo
@@ -167,6 +182,7 @@ pnpm demo
167
182
  ```
168
183
 
169
184
  Or manually:
185
+
170
186
  ```bash
171
187
  cd demo
172
188
  pnpm install
@@ -0,0 +1,206 @@
1
+ "use client";
2
+ import { useTheme as e } from "next-themes";
3
+ import { jsx as t, jsxs as n } from "react/jsx-runtime";
4
+ import { Moon as r, Sun as i } from "lucide-react";
5
+ import { useEffect as a, useRef as o, useState as s } from "react";
6
+ import { motion as c } from "framer-motion";
7
+ //#region src/cinematic-theme-switcher.tsx
8
+ function l() {
9
+ let { theme: l, setTheme: u, resolvedTheme: d } = e(), [f, p] = s(!1), [m, h] = s([]), [g, _] = s(!1), v = o(null), y = f && (l === "dark" || d === "dark");
10
+ a(() => {
11
+ p(!0);
12
+ }, []);
13
+ let b = () => {
14
+ let e = [];
15
+ for (let t = 0; t < 3; t++) e.push({
16
+ id: t,
17
+ delay: t * .1,
18
+ duration: .6 + t * .1
19
+ });
20
+ h(e), _(!0), setTimeout(() => {
21
+ _(!1), h([]);
22
+ }, 1e3);
23
+ };
24
+ return f ? /* @__PURE__ */ n("div", {
25
+ className: "relative inline-block",
26
+ children: [/* @__PURE__ */ t("svg", {
27
+ className: "absolute w-0 h-0",
28
+ children: /* @__PURE__ */ n("defs", { children: [/* @__PURE__ */ n("filter", {
29
+ id: "grain-light",
30
+ children: [
31
+ /* @__PURE__ */ t("feTurbulence", {
32
+ type: "fractalNoise",
33
+ baseFrequency: "0.9",
34
+ numOctaves: "4",
35
+ result: "noise"
36
+ }),
37
+ /* @__PURE__ */ t("feColorMatrix", {
38
+ in: "noise",
39
+ type: "saturate",
40
+ values: "0",
41
+ result: "desaturatedNoise"
42
+ }),
43
+ /* @__PURE__ */ t("feComponentTransfer", {
44
+ in: "desaturatedNoise",
45
+ result: "lightGrain",
46
+ children: /* @__PURE__ */ t("feFuncA", {
47
+ type: "linear",
48
+ slope: "0.3"
49
+ })
50
+ }),
51
+ /* @__PURE__ */ t("feBlend", {
52
+ in: "SourceGraphic",
53
+ in2: "lightGrain",
54
+ mode: "overlay"
55
+ })
56
+ ]
57
+ }), /* @__PURE__ */ n("filter", {
58
+ id: "grain-dark",
59
+ children: [
60
+ /* @__PURE__ */ t("feTurbulence", {
61
+ type: "fractalNoise",
62
+ baseFrequency: "0.9",
63
+ numOctaves: "4",
64
+ result: "noise"
65
+ }),
66
+ /* @__PURE__ */ t("feColorMatrix", {
67
+ in: "noise",
68
+ type: "saturate",
69
+ values: "0",
70
+ result: "desaturatedNoise"
71
+ }),
72
+ /* @__PURE__ */ t("feComponentTransfer", {
73
+ in: "desaturatedNoise",
74
+ result: "darkGrain",
75
+ children: /* @__PURE__ */ t("feFuncA", {
76
+ type: "linear",
77
+ slope: "0.5"
78
+ })
79
+ }),
80
+ /* @__PURE__ */ t("feBlend", {
81
+ in: "SourceGraphic",
82
+ in2: "darkGrain",
83
+ mode: "overlay"
84
+ })
85
+ ]
86
+ })] })
87
+ }), /* @__PURE__ */ n(c.button, {
88
+ ref: v,
89
+ onClick: () => {
90
+ b(), u(y ? "light" : "dark");
91
+ },
92
+ className: "relative flex h-[64px] w-[104px] items-center rounded-full p-[6px] transition-all duration-300 focus:outline-none",
93
+ style: {
94
+ background: y ? "radial-gradient(ellipse at top left, #1e293b 0%, #0f172a 40%, #020617 100%)" : "radial-gradient(ellipse at top left, #ffffff 0%, #f1f5f9 40%, #cbd5e1 100%)",
95
+ boxShadow: y ? "\n inset 5px 5px 12px rgba(0, 0, 0, 0.9),\n inset -5px -5px 12px rgba(71, 85, 105, 0.4),\n inset 8px 8px 16px rgba(0, 0, 0, 0.7),\n inset -8px -8px 16px rgba(100, 116, 139, 0.2),\n inset 0 2px 4px rgba(0, 0, 0, 1),\n inset 0 -2px 4px rgba(71, 85, 105, 0.4),\n inset 0 0 20px rgba(0, 0, 0, 0.6),\n 0 1px 1px rgba(255, 255, 255, 0.05),\n 0 2px 4px rgba(0, 0, 0, 0.4),\n 0 8px 16px rgba(0, 0, 0, 0.4),\n 0 16px 32px rgba(0, 0, 0, 0.3),\n 0 24px 48px rgba(0, 0, 0, 0.2)\n " : "\n inset 5px 5px 12px rgba(148, 163, 184, 0.5),\n inset -5px -5px 12px rgba(255, 255, 255, 1),\n inset 8px 8px 16px rgba(100, 116, 139, 0.3),\n inset -8px -8px 16px rgba(255, 255, 255, 0.9),\n inset 0 2px 4px rgba(148, 163, 184, 0.4),\n inset 0 -2px 4px rgba(255, 255, 255, 1),\n inset 0 0 20px rgba(203, 213, 225, 0.3),\n 0 1px 2px rgba(255, 255, 255, 1),\n 0 2px 4px rgba(0, 0, 0, 0.1),\n 0 8px 16px rgba(0, 0, 0, 0.08),\n 0 16px 32px rgba(0, 0, 0, 0.06),\n 0 24px 48px rgba(0, 0, 0, 0.04)\n ",
96
+ border: y ? "2px solid rgba(51, 65, 85, 0.6)" : "2px solid rgba(203, 213, 225, 0.6)",
97
+ position: "relative"
98
+ },
99
+ "aria-label": `Switch to ${y ? "light" : "dark"} mode`,
100
+ role: "switch",
101
+ "aria-checked": y,
102
+ whileTap: { scale: .98 },
103
+ children: [
104
+ /* @__PURE__ */ t("div", {
105
+ className: "absolute inset-[3px] rounded-full pointer-events-none",
106
+ style: { boxShadow: y ? "inset 0 2px 6px rgba(0, 0, 0, 0.9), inset 0 -1px 3px rgba(71, 85, 105, 0.3)" : "inset 0 2px 6px rgba(100, 116, 139, 0.4), inset 0 -1px 3px rgba(255, 255, 255, 0.8)" }
107
+ }),
108
+ /* @__PURE__ */ t("div", {
109
+ className: "absolute inset-0 rounded-full pointer-events-none",
110
+ style: {
111
+ background: y ? "\n radial-gradient(ellipse at top, rgba(71, 85, 105, 0.15) 0%, transparent 50%),\n linear-gradient(to bottom, rgba(71, 85, 105, 0.2) 0%, transparent 30%, transparent 70%, rgba(0, 0, 0, 0.3) 100%)\n " : "\n radial-gradient(ellipse at top, rgba(255, 255, 255, 0.8) 0%, transparent 50%),\n linear-gradient(to bottom, rgba(255, 255, 255, 0.7) 0%, transparent 30%, transparent 70%, rgba(148, 163, 184, 0.15) 100%)\n ",
112
+ mixBlendMode: "overlay"
113
+ }
114
+ }),
115
+ /* @__PURE__ */ t("div", {
116
+ className: "absolute inset-0 rounded-full pointer-events-none",
117
+ style: { boxShadow: y ? "inset 0 0 15px rgba(0, 0, 0, 0.5)" : "inset 0 0 15px rgba(148, 163, 184, 0.2)" }
118
+ }),
119
+ /* @__PURE__ */ n("div", {
120
+ className: "absolute inset-0 flex items-center justify-between px-4",
121
+ children: [/* @__PURE__ */ t(i, {
122
+ size: 20,
123
+ className: y ? "text-yellow-100" : "text-amber-600"
124
+ }), /* @__PURE__ */ t(r, {
125
+ size: 20,
126
+ className: y ? "text-yellow-100" : "text-slate-700"
127
+ })]
128
+ }),
129
+ /* @__PURE__ */ n(c.div, {
130
+ className: "relative z-10 flex h-[44px] w-[44px] items-center justify-center rounded-full overflow-hidden",
131
+ style: {
132
+ background: y ? "linear-gradient(145deg, #64748b 0%, #475569 50%, #334155 100%)" : "linear-gradient(145deg, #ffffff 0%, #fefefe 50%, #f8fafc 100%)",
133
+ boxShadow: y ? "\n inset 2px 2px 4px rgba(100, 116, 139, 0.4),\n inset -2px -2px 4px rgba(0, 0, 0, 0.8),\n inset 0 1px 1px rgba(255, 255, 255, 0.15),\n 0 1px 2px rgba(255, 255, 255, 0.1),\n 0 8px 32px rgba(0, 0, 0, 0.6),\n 0 4px 12px rgba(0, 0, 0, 0.5),\n 0 2px 4px rgba(0, 0, 0, 0.4)\n " : "\n inset 2px 2px 4px rgba(203, 213, 225, 0.3),\n inset -2px -2px 4px rgba(255, 255, 255, 1),\n inset 0 1px 2px rgba(255, 255, 255, 1),\n 0 1px 2px rgba(255, 255, 255, 1),\n 0 8px 32px rgba(0, 0, 0, 0.18),\n 0 4px 12px rgba(0, 0, 0, 0.12),\n 0 2px 4px rgba(0, 0, 0, 0.08)\n ",
134
+ border: y ? "2px solid rgba(148, 163, 184, 0.3)" : "2px solid rgba(255, 255, 255, 0.9)"
135
+ },
136
+ animate: { x: y ? 46 : 0 },
137
+ transition: {
138
+ type: "spring",
139
+ stiffness: 300,
140
+ damping: 20
141
+ },
142
+ children: [
143
+ /* @__PURE__ */ t("div", {
144
+ className: "absolute inset-0 rounded-full pointer-events-none",
145
+ style: {
146
+ background: "linear-gradient(to bottom, rgba(255, 255, 255, 0.4) 0%, transparent 40%, rgba(0, 0, 0, 0.1) 100%)",
147
+ mixBlendMode: "overlay"
148
+ }
149
+ }),
150
+ g && m.map((e) => /* @__PURE__ */ t(c.div, {
151
+ className: "absolute inset-0 flex items-center justify-center pointer-events-none",
152
+ children: /* @__PURE__ */ t(c.div, {
153
+ className: "absolute rounded-full",
154
+ style: {
155
+ width: "10px",
156
+ height: "10px",
157
+ background: y ? "radial-gradient(circle, rgba(147, 197, 253, 0.5) 0%, rgba(147, 197, 253, 0) 70%)" : "radial-gradient(circle, rgba(251, 191, 36, 0.7) 0%, rgba(251, 191, 36, 0) 70%)",
158
+ mixBlendMode: "normal"
159
+ },
160
+ initial: {
161
+ scale: 0,
162
+ opacity: 0
163
+ },
164
+ animate: {
165
+ scale: y ? 6 : 8,
166
+ opacity: [
167
+ 0,
168
+ 1,
169
+ 0
170
+ ]
171
+ },
172
+ transition: {
173
+ duration: y ? .5 : e.duration,
174
+ delay: e.delay,
175
+ ease: "easeOut"
176
+ },
177
+ children: /* @__PURE__ */ t("div", {
178
+ className: "absolute inset-0 rounded-full opacity-40",
179
+ style: {
180
+ backgroundImage: "url(\"data:image/svg+xml,%3Csvg viewBox='0 0 200 200' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='noiseFilter'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23noiseFilter)'/%3E%3C/svg%3E\")",
181
+ mixBlendMode: "overlay"
182
+ }
183
+ })
184
+ })
185
+ }, e.id)),
186
+ /* @__PURE__ */ t("div", {
187
+ className: "relative z-10",
188
+ children: y ? /* @__PURE__ */ t(r, {
189
+ size: 20,
190
+ className: "text-yellow-200"
191
+ }) : /* @__PURE__ */ t(i, {
192
+ size: 20,
193
+ className: "text-amber-500"
194
+ })
195
+ })
196
+ ]
197
+ })
198
+ ]
199
+ })]
200
+ }) : /* @__PURE__ */ t("div", {
201
+ className: "relative inline-block",
202
+ children: /* @__PURE__ */ t("div", { className: "relative flex h-[64px] w-[104px] items-center rounded-full bg-gray-200 p-1" })
203
+ });
204
+ }
205
+ //#endregion
206
+ export { l as default };
@@ -0,0 +1,30 @@
1
+ import { cn as e } from "../../lib/utils.js";
2
+ import { jsx as t } from "react/jsx-runtime";
3
+ import * as n from "react";
4
+ //#region src/components/ui/avatar.tsx
5
+ function r({ children: n, className: r, ...i }) {
6
+ return /* @__PURE__ */ t("div", {
7
+ className: e("relative flex h-10 w-10 shrink-0 overflow-hidden rounded-full", r),
8
+ ...i,
9
+ children: n
10
+ });
11
+ }
12
+ function i({ src: r, alt: i, className: a, ...o }) {
13
+ let [s, c] = n.useState(!1);
14
+ return !r || s ? null : /* @__PURE__ */ t("img", {
15
+ src: r,
16
+ alt: i,
17
+ className: e("aspect-square h-full w-full object-cover", a),
18
+ onError: () => c(!0),
19
+ ...o
20
+ });
21
+ }
22
+ function a({ children: n, className: r, ...i }) {
23
+ return /* @__PURE__ */ t("div", {
24
+ className: e("flex h-full w-full items-center justify-center rounded-full bg-muted text-xs font-medium", r),
25
+ ...i,
26
+ children: n
27
+ });
28
+ }
29
+ //#endregion
30
+ export { r as Avatar, a as AvatarFallback, i as AvatarImage };
@@ -0,0 +1,39 @@
1
+ import { cn as e } from "../../lib/utils.js";
2
+ import { jsx as t } from "react/jsx-runtime";
3
+ import * as n from "react";
4
+ import { Slot as r } from "@radix-ui/react-slot";
5
+ import { cva as i } from "class-variance-authority";
6
+ //#region src/components/ui/button.tsx
7
+ var a = i("inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0", {
8
+ variants: {
9
+ variant: {
10
+ default: "bg-primary text-primary-foreground shadow hover:bg-primary/90",
11
+ destructive: "bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90",
12
+ outline: "border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground",
13
+ secondary: "bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80",
14
+ ghost: "hover:bg-accent hover:text-accent-foreground",
15
+ link: "text-primary underline-offset-4 hover:underline"
16
+ },
17
+ size: {
18
+ default: "h-9 px-4 py-2",
19
+ sm: "h-8 rounded-md px-3 text-xs",
20
+ lg: "h-10 rounded-md px-8",
21
+ icon: "h-9 w-9"
22
+ }
23
+ },
24
+ defaultVariants: {
25
+ variant: "default",
26
+ size: "default"
27
+ }
28
+ }), o = n.forwardRef(({ className: n, variant: i, size: o, asChild: s = !1, ...c }, l) => /* @__PURE__ */ t(s ? r : "button", {
29
+ className: e(a({
30
+ variant: i,
31
+ size: o,
32
+ className: n
33
+ })),
34
+ ref: l,
35
+ ...c
36
+ }));
37
+ o.displayName = "Button";
38
+ //#endregion
39
+ export { o as Button };
@@ -0,0 +1,72 @@
1
+ import { cn as e } from "../../lib/utils.js";
2
+ import { jsx as t, jsxs as n } from "react/jsx-runtime";
3
+ import { Check as r, ChevronRight as i, Circle as a } from "lucide-react";
4
+ import * as o from "react";
5
+ import * as s from "@radix-ui/react-dropdown-menu";
6
+ //#region src/components/ui/dropdown-menu.tsx
7
+ var c = s.Root, l = s.Trigger, u = s.Portal, d = s.Sub, f = o.forwardRef(({ className: r, inset: a, children: o, ...c }, l) => /* @__PURE__ */ n(s.SubTrigger, {
8
+ ref: l,
9
+ className: e("flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none focus:bg-accent data-[state=open]:bg-accent", a && "pl-8", r),
10
+ ...c,
11
+ children: [o, /* @__PURE__ */ t(i, { className: "ml-auto h-4 w-4" })]
12
+ }));
13
+ f.displayName = s.SubTrigger.displayName;
14
+ var p = o.forwardRef(({ className: n, ...r }, i) => /* @__PURE__ */ t(s.SubContent, {
15
+ ref: i,
16
+ className: e("z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-lg data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2", n),
17
+ ...r
18
+ }));
19
+ p.displayName = s.SubContent.displayName;
20
+ var m = o.forwardRef(({ className: n, sideOffset: r = 4, ...i }, a) => /* @__PURE__ */ t(s.Portal, { children: /* @__PURE__ */ t(s.Content, {
21
+ ref: a,
22
+ sideOffset: r,
23
+ className: e("z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2", n),
24
+ ...i
25
+ }) }));
26
+ m.displayName = s.Content.displayName;
27
+ var h = o.forwardRef(({ className: n, inset: r, ...i }, a) => /* @__PURE__ */ t(s.Item, {
28
+ ref: a,
29
+ className: e("relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50", r && "pl-8", n),
30
+ ...i
31
+ }));
32
+ h.displayName = s.Item.displayName;
33
+ var g = o.forwardRef(({ className: i, children: a, checked: o, ...c }, l) => /* @__PURE__ */ n(s.CheckboxItem, {
34
+ ref: l,
35
+ className: e("relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50", i),
36
+ checked: o,
37
+ ...c,
38
+ children: [/* @__PURE__ */ t("span", {
39
+ className: "absolute left-2 flex h-3.5 w-3.5 items-center justify-center",
40
+ children: /* @__PURE__ */ t(s.ItemIndicator, { children: /* @__PURE__ */ t(r, { className: "h-4 w-4" }) })
41
+ }), a]
42
+ }));
43
+ g.displayName = s.CheckboxItem.displayName;
44
+ var _ = o.forwardRef(({ className: r, children: i, ...o }, c) => /* @__PURE__ */ n(s.RadioItem, {
45
+ ref: c,
46
+ className: e("relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50", r),
47
+ ...o,
48
+ children: [/* @__PURE__ */ t("span", {
49
+ className: "absolute left-2 flex h-3.5 w-3.5 items-center justify-center",
50
+ children: /* @__PURE__ */ t(s.ItemIndicator, { children: /* @__PURE__ */ t(a, { className: "h-2 w-2 fill-current" }) })
51
+ }), i]
52
+ }));
53
+ _.displayName = s.RadioItem.displayName;
54
+ var v = o.forwardRef(({ className: n, inset: r, ...i }, a) => /* @__PURE__ */ t(s.Label, {
55
+ ref: a,
56
+ className: e("px-2 py-1.5 text-sm font-semibold", r && "pl-8", n),
57
+ ...i
58
+ }));
59
+ v.displayName = s.Label.displayName;
60
+ var y = o.forwardRef(({ className: n, ...r }, i) => /* @__PURE__ */ t(s.Separator, {
61
+ ref: i,
62
+ className: e("-mx-1 my-1 h-px bg-muted", n),
63
+ ...r
64
+ }));
65
+ y.displayName = s.Separator.displayName;
66
+ var b = ({ className: n, ...r }) => /* @__PURE__ */ t("span", {
67
+ className: e("ml-auto text-xs tracking-widest opacity-60", n),
68
+ ...r
69
+ });
70
+ b.displayName = "DropdownMenuShortcut";
71
+ //#endregion
72
+ export { c as DropdownMenu, m as DropdownMenuContent, h as DropdownMenuItem, v as DropdownMenuLabel, u as DropdownMenuPortal, y as DropdownMenuSeparator, d as DropdownMenuSub, p as DropdownMenuSubContent, f as DropdownMenuSubTrigger, l as DropdownMenuTrigger };
@@ -0,0 +1,31 @@
1
+ import { cn as e } from "../../lib/utils.js";
2
+ import { jsx as t } from "react/jsx-runtime";
3
+ import * as n from "react";
4
+ //#region src/components/ui/sidebar.tsx
5
+ function r({ children: n, className: r, ...i }) {
6
+ return /* @__PURE__ */ t("ul", {
7
+ className: e("flex flex-col gap-1", r),
8
+ ...i,
9
+ children: n
10
+ });
11
+ }
12
+ function i({ children: n, className: r, ...i }) {
13
+ return /* @__PURE__ */ t("li", {
14
+ className: e("", r),
15
+ ...i,
16
+ children: n
17
+ });
18
+ }
19
+ function a({ children: r, className: i, size: a = "default", asChild: o, ...s }) {
20
+ let c = a === "lg" ? "h-12 text-sm" : a === "sm" ? "h-7 text-xs" : "h-8 text-sm";
21
+ return o && n.isValidElement(r) ? n.cloneElement(r, {
22
+ className: e("flex w-full items-center gap-2 rounded-md px-2 py-1.5 hover:bg-accent", c, i),
23
+ ...s
24
+ }) : /* @__PURE__ */ t("button", {
25
+ className: e("flex w-full items-center gap-2 rounded-md px-2 py-1.5 hover:bg-accent", c, i),
26
+ ...s,
27
+ children: r
28
+ });
29
+ }
30
+ //#endregion
31
+ export { r as SidebarMenu, a as SidebarMenuButton, i as SidebarMenuItem };
package/dist/index.js ADDED
@@ -0,0 +1,6 @@
1
+ import { ThemeProvider as e } from "./theme-provider.js";
2
+ import { ThemeToggle as t } from "./theme-toggle.js";
3
+ import { ThemeDropdown as n, formatThemeName as r, themeColors as i, themeNames as a } from "./theme-dropdown.js";
4
+ import o from "./cinematic-theme-switcher.js";
5
+ import { SidebarUserMenu as s } from "./sidebar-user-menu.js";
6
+ export { o as CinematicThemeSwitcher, s as SidebarUserMenu, n as ThemeDropdown, e as ThemeProvider, t as ThemeToggle, r as formatThemeName, i as themeColors, a as themeNames };
@@ -0,0 +1,8 @@
1
+ import { clsx as e } from "clsx";
2
+ import { twMerge as t } from "tailwind-merge";
3
+ //#region src/lib/utils.ts
4
+ function n(...n) {
5
+ return t(e(n));
6
+ }
7
+ //#endregion
8
+ export { n as cn };
@@ -0,0 +1,149 @@
1
+ "use client";
2
+ import { DropdownMenu as e, DropdownMenuContent as t, DropdownMenuItem as n, DropdownMenuPortal as r, DropdownMenuSeparator as i, DropdownMenuSub as a, DropdownMenuSubContent as o, DropdownMenuSubTrigger as s, DropdownMenuTrigger as c } from "./components/ui/dropdown-menu.js";
3
+ import { formatThemeName as l, themeColors as u, themeNames as d } from "./theme-dropdown.js";
4
+ import f from "./cinematic-theme-switcher.js";
5
+ import { SidebarMenu as p, SidebarMenuButton as m, SidebarMenuItem as h } from "./components/ui/sidebar.js";
6
+ import { Avatar as g, AvatarFallback as _, AvatarImage as v } from "./components/ui/avatar.js";
7
+ import { Fragment as y, jsx as b, jsxs as x } from "react/jsx-runtime";
8
+ import { Bell as S, ChevronUp as C, CreditCard as w, LogOut as T, Palette as E, User2 as D } from "lucide-react";
9
+ import * as O from "react";
10
+ //#region src/sidebar-user-menu.tsx
11
+ function k({ trigger: e }) {
12
+ return /* @__PURE__ */ b(y, { children: e });
13
+ }
14
+ function A({ user: y, onSignOut: A } = {}) {
15
+ let j = y || {
16
+ name: "Guest User",
17
+ email: "guest@example.com",
18
+ image: null
19
+ }, [M, N] = O.useState("minimal"), [P, F] = O.useState(!1), [I, L] = O.useState(null);
20
+ O.useEffect(() => {
21
+ F(!0);
22
+ let e = localStorage.getItem("color-theme");
23
+ e && d.includes(e) && N(e);
24
+ }, []);
25
+ let R = (e) => {
26
+ N(e), localStorage.setItem("color-theme", e), document.cookie = `color-theme=${e}; path=/; max-age=31536000`, d.forEach((e) => document.documentElement.classList.remove(`theme-${e}`)), document.documentElement.classList.add(`theme-${e}`), L(null);
27
+ }, z = (e) => {
28
+ L(e), d.forEach((e) => document.documentElement.classList.remove(`theme-${e}`)), document.documentElement.classList.add(`theme-${e}`);
29
+ }, B = () => {
30
+ I && (d.forEach((e) => document.documentElement.classList.remove(`theme-${e}`)), document.documentElement.classList.add(`theme-${M}`), L(null));
31
+ }, V = j.name?.split(" ").map((e) => e[0]).join("").toUpperCase().substring(0, 2) || "GU";
32
+ return /* @__PURE__ */ b(p, { children: /* @__PURE__ */ b(h, { children: /* @__PURE__ */ x(e, {
33
+ onOpenChange: (e) => !e && B(),
34
+ children: [/* @__PURE__ */ b(c, {
35
+ asChild: !0,
36
+ children: /* @__PURE__ */ x(m, {
37
+ size: "lg",
38
+ className: "data-[state=open]:bg-sidebar-accent data-[state=open]:text-sidebar-accent-foreground",
39
+ children: [
40
+ /* @__PURE__ */ x(g, {
41
+ className: "h-8 w-8 rounded-lg",
42
+ children: [/* @__PURE__ */ b(v, {
43
+ src: j.image || void 0,
44
+ alt: j.name || "User"
45
+ }), /* @__PURE__ */ b(_, {
46
+ className: "rounded-lg",
47
+ children: V
48
+ })]
49
+ }),
50
+ /* @__PURE__ */ x("div", {
51
+ className: "grid flex-1 text-left text-sm leading-tight group-data-[collapsible=icon]:hidden",
52
+ children: [/* @__PURE__ */ b("span", {
53
+ className: "truncate font-semibold",
54
+ children: j.name || "Guest"
55
+ }), /* @__PURE__ */ b("span", {
56
+ className: "truncate text-xs text-muted-foreground",
57
+ children: j.email
58
+ })]
59
+ }),
60
+ /* @__PURE__ */ b(C, { className: "ml-2 size-4 group-data-[collapsible=icon]:hidden" })
61
+ ]
62
+ })
63
+ }), /* @__PURE__ */ x(t, {
64
+ className: "w-[--radix-dropdown-menu-trigger-width] min-w-56 rounded-lg",
65
+ side: "bottom",
66
+ align: "end",
67
+ sideOffset: 4,
68
+ children: [
69
+ /* @__PURE__ */ x("div", {
70
+ className: "flex items-center gap-2 px-1 py-1.5 text-left text-sm",
71
+ children: [/* @__PURE__ */ x(g, {
72
+ className: "h-8 w-8 rounded-lg",
73
+ children: [/* @__PURE__ */ b(v, {
74
+ src: j.image || void 0,
75
+ alt: j.name || "User"
76
+ }), /* @__PURE__ */ b(_, {
77
+ className: "rounded-lg",
78
+ children: V
79
+ })]
80
+ }), /* @__PURE__ */ x("div", {
81
+ className: "grid flex-1 text-left text-sm leading-tight",
82
+ children: [/* @__PURE__ */ b("span", {
83
+ className: "truncate font-semibold",
84
+ children: j.name || "Guest"
85
+ }), /* @__PURE__ */ b("span", {
86
+ className: "truncate text-xs text-muted-foreground",
87
+ children: j.email
88
+ })]
89
+ })]
90
+ }),
91
+ /* @__PURE__ */ b(i, {}),
92
+ /* @__PURE__ */ b(k, { trigger: /* @__PURE__ */ x(n, {
93
+ onSelect: (e) => e.preventDefault(),
94
+ children: [/* @__PURE__ */ b(D, { className: "mr-2 h-4 w-4" }), "Profile"]
95
+ }) }),
96
+ /* @__PURE__ */ x(n, { children: [/* @__PURE__ */ b(w, { className: "mr-2 h-4 w-4" }), "Billing"] }),
97
+ /* @__PURE__ */ x(n, { children: [/* @__PURE__ */ b(S, { className: "mr-2 h-4 w-4" }), "Notifications"] }),
98
+ /* @__PURE__ */ b(i, {}),
99
+ /* @__PURE__ */ x(a, { children: [/* @__PURE__ */ x(s, { children: [/* @__PURE__ */ b(E, { className: "mr-2 h-4 w-4" }), /* @__PURE__ */ b("span", { children: "Color Theme" })] }), /* @__PURE__ */ b(r, { children: /* @__PURE__ */ x(o, {
100
+ className: "max-h-[400px] overflow-y-auto",
101
+ children: [
102
+ /* @__PURE__ */ b("div", {
103
+ className: "px-2 py-1.5 flex items-center justify-center",
104
+ children: /* @__PURE__ */ b(f, {})
105
+ }),
106
+ /* @__PURE__ */ b(i, {}),
107
+ d.map((e) => {
108
+ let t = u[e];
109
+ return /* @__PURE__ */ b(n, {
110
+ onClick: () => R(e),
111
+ onMouseEnter: () => z(e),
112
+ onMouseLeave: B,
113
+ className: M === e ? "bg-accent" : "",
114
+ children: /* @__PURE__ */ x("div", {
115
+ className: "flex items-center justify-between w-full",
116
+ children: [/* @__PURE__ */ x("div", {
117
+ className: "flex items-center gap-2",
118
+ children: [t && /* @__PURE__ */ x("div", {
119
+ className: "flex items-center gap-1",
120
+ children: [/* @__PURE__ */ b("div", {
121
+ className: "w-3 h-3 rounded-full border border-border",
122
+ style: { backgroundColor: t.primary }
123
+ }), /* @__PURE__ */ b("div", {
124
+ className: "w-3 h-3 rounded-full border border-border",
125
+ style: { backgroundColor: t.secondary }
126
+ })]
127
+ }), /* @__PURE__ */ b("span", { children: l(e) })]
128
+ }), M === e && /* @__PURE__ */ b("span", {
129
+ className: "text-xs",
130
+ children: "✓"
131
+ })]
132
+ })
133
+ }, e);
134
+ })
135
+ ]
136
+ }) })] }),
137
+ /* @__PURE__ */ b(i, {}),
138
+ /* @__PURE__ */ x(n, {
139
+ onClick: async () => {
140
+ await A?.();
141
+ },
142
+ children: [/* @__PURE__ */ b(T, { className: "mr-2 h-4 w-4" }), "Sign out"]
143
+ })
144
+ ]
145
+ })]
146
+ }) }) });
147
+ }
148
+ //#endregion
149
+ export { A as SidebarUserMenu };