@ekkolyth/ui 0.1.17 → 0.1.18
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/LICENSE +21 -0
- package/README.md +153 -97
- package/dist/base.css +263 -0
- package/dist/blocks.d.ts +4 -0
- package/dist/blocks.js +4 -0
- package/dist/container-BBg21poC.js +10 -0
- package/dist/convex.d.ts +2 -0
- package/dist/convex.js +2 -0
- package/dist/hooks.d.ts +2 -0
- package/dist/hooks.js +2 -0
- package/dist/icon-picker-ByfHyJ7i.js +4078 -0
- package/dist/index-Bwp0YMmG.d.ts +5 -0
- package/dist/index-BxcqwZNT.d.ts +30 -0
- package/dist/index-DHF8OR1R.d.ts +60 -0
- package/dist/index-DsLGf2HX.d.ts +9 -0
- package/dist/index-qji4ohJZ.d.ts +24 -0
- package/dist/index.d.ts +793 -533
- package/dist/index.js +3236 -5578
- package/dist/layout.d.ts +2 -0
- package/dist/layout.js +2 -0
- package/dist/loading-screen-DB3youyT.js +63 -0
- package/dist/shiki-code-Bg__Vnt1.js +29 -0
- package/dist/text.d.ts +17 -0
- package/dist/text.js +177 -0
- package/dist/themes/catpuccin/frappe.css +33 -33
- package/dist/themes/catpuccin/latte.css +33 -33
- package/dist/themes/catpuccin/macchiato.css +33 -33
- package/dist/themes/catpuccin/mocha.css +33 -33
- package/dist/themes/ekko-os.css +92 -37
- package/dist/themes/ekkolyth.css +2 -2
- package/dist/themes/index.css +7 -66
- package/dist/themes/provider.d.ts +62 -0
- package/dist/themes/provider.js +271 -0
- package/dist/themes/tokyo-night.css +33 -33
- package/dist/themes.css +7 -66
- package/dist/toggle-B2PFPImC.js +182 -0
- package/dist/use-mobile-BVGje-2e.d.ts +4 -0
- package/dist/use-mobile-CqHXB_Nc.js +18 -0
- package/dist/utils-C_uf36nf.js +8 -0
- package/dist/widget-C2vjxQms.js +94 -0
- package/dist/widget.d.ts +6 -0
- package/dist/widget.js +19 -0
- package/package.json +125 -170
- package/dist/catpuccin/frappe.css +0 -35
- package/dist/catpuccin/latte.css +0 -35
- package/dist/catpuccin/macchiato.css +0 -35
- package/dist/catpuccin/mocha.css +0 -35
- package/dist/ekko-os.css +0 -71
- package/dist/ekko-playlist.css +0 -71
- package/dist/ekkolyth.css +0 -70
- package/dist/index-C3ceanPz.d.ts +0 -18
- package/dist/index-C7t_lwpi.d.ts +0 -13
- package/dist/next.d.ts +0 -13
- package/dist/next.js +0 -271
- package/dist/providers/next.d.ts +0 -25
- package/dist/providers/next.js +0 -216
- package/dist/providers/tanstack.d.ts +0 -24
- package/dist/providers/tanstack.js +0 -120
- package/dist/tanstack.d.ts +0 -12
- package/dist/tanstack.js +0 -203
- package/dist/themes/ekko-playlist.css +0 -71
- package/dist/themes/theme-select.d.ts +0 -12
- package/dist/themes/theme-select.js +0 -357
- package/dist/themes/theme-toggle.d.ts +0 -15
- package/dist/themes/theme-toggle.js +0 -179
- package/dist/tokyo-night.css +0 -35
- package/dist/types-fUfvw1Mz.d.ts +0 -8
package/dist/themes/ekko-os.css
CHANGED
|
@@ -1,8 +1,61 @@
|
|
|
1
|
-
/*
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
/* Canonical ekko-os tokens. apps/web imports this and no longer carries
|
|
2
|
+
* its own :root / .dark blocks, so edits land here, not there. */
|
|
3
|
+
|
|
4
|
+
@theme inline {
|
|
5
|
+
--color-background: var(--background);
|
|
6
|
+
--color-foreground: var(--foreground);
|
|
7
|
+
--color-background-notes: var(--background-notes);
|
|
8
|
+
--color-foreground-notes: var(--foreground-notes);
|
|
9
|
+
--color-sidebar-ring: var(--sidebar-ring);
|
|
10
|
+
--color-sidebar-border: var(--sidebar-border);
|
|
11
|
+
--color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
|
|
12
|
+
--color-sidebar-accent: var(--sidebar-accent);
|
|
13
|
+
--color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
|
|
14
|
+
--color-sidebar-primary: var(--sidebar-primary);
|
|
15
|
+
--color-sidebar-foreground: var(--sidebar-foreground);
|
|
16
|
+
--color-sidebar: var(--sidebar);
|
|
17
|
+
--color-chart-5: var(--chart-5);
|
|
18
|
+
--color-chart-4: var(--chart-4);
|
|
19
|
+
--color-chart-3: var(--chart-3);
|
|
20
|
+
--color-chart-2: var(--chart-2);
|
|
21
|
+
--color-chart-1: var(--chart-1);
|
|
22
|
+
--color-ring: var(--ring);
|
|
23
|
+
--color-input: var(--input);
|
|
24
|
+
--color-border: var(--border);
|
|
25
|
+
--color-destructive: var(--destructive);
|
|
26
|
+
--color-success: var(--success);
|
|
27
|
+
--color-warning: var(--warning);
|
|
28
|
+
--color-info: var(--info);
|
|
29
|
+
--color-accent-foreground: var(--accent-foreground);
|
|
30
|
+
--color-accent: var(--accent);
|
|
31
|
+
--color-muted-foreground: var(--muted-foreground);
|
|
32
|
+
--color-muted: var(--muted);
|
|
33
|
+
--color-secondary-foreground: var(--secondary-foreground);
|
|
34
|
+
--color-secondary: var(--secondary);
|
|
35
|
+
--color-primary-foreground: var(--primary-foreground);
|
|
36
|
+
--color-primary: var(--primary);
|
|
37
|
+
--color-popover-foreground: var(--popover-foreground);
|
|
38
|
+
--color-popover: var(--popover);
|
|
39
|
+
--color-card-foreground: var(--card-foreground);
|
|
40
|
+
--color-card: var(--card);
|
|
41
|
+
--radius-sm: calc(var(--radius) - 4px);
|
|
42
|
+
--radius-md: calc(var(--radius) - 2px);
|
|
43
|
+
--radius-lg: var(--radius);
|
|
44
|
+
--radius-xl: calc(var(--radius) + 4px);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
:root,
|
|
48
|
+
html[data-theme='ekkoos-light'] {
|
|
49
|
+
/* EkkoOS is the one palette that overrides the package's default face.
|
|
50
|
+
* Scoped, not global: a @theme entry here would set it for every theme. */
|
|
51
|
+
--font-sans: 'SatoshiVariable', sans-serif;
|
|
52
|
+
--font-atkinson-mono:
|
|
53
|
+
'Atkinson Hyperlegible Mono Variable', ui-monospace, monospace;
|
|
54
|
+
--radius: 0.625rem;
|
|
55
|
+
--background: oklch(0.98 0.001 286.375);
|
|
5
56
|
--foreground: oklch(0.141 0.005 285.823);
|
|
57
|
+
--background-notes: oklch(0.98 0.001 286.375);
|
|
58
|
+
--foreground-notes: oklch(0.141 0.005 285.823);
|
|
6
59
|
--card: oklch(1 0 0);
|
|
7
60
|
--card-foreground: oklch(0.141 0.005 285.823);
|
|
8
61
|
--popover: oklch(1 0 0);
|
|
@@ -15,31 +68,37 @@ html[data-theme="ekkoos-light"] {
|
|
|
15
68
|
--muted-foreground: oklch(0.552 0.016 285.938);
|
|
16
69
|
--accent: oklch(0.967 0.001 286.375);
|
|
17
70
|
--accent-foreground: oklch(0.21 0.006 285.885);
|
|
18
|
-
--destructive: oklch(0.
|
|
19
|
-
--
|
|
20
|
-
--
|
|
71
|
+
--destructive: oklch(0.645 0.246 16.439);
|
|
72
|
+
--success: oklch(0.696 0.17 162.48);
|
|
73
|
+
--warning: oklch(0.769 0.188 70.08);
|
|
74
|
+
--info: oklch(0.62 0.14 250);
|
|
75
|
+
--border: oklch(0.885 0.004 286.32);
|
|
76
|
+
--input: oklch(0.94 0.002 286.375);
|
|
21
77
|
--ring: oklch(0.705 0.015 286.067);
|
|
22
78
|
--chart-1: oklch(0.646 0.222 41.116);
|
|
23
79
|
--chart-2: oklch(0.6 0.118 184.704);
|
|
24
80
|
--chart-3: oklch(0.398 0.07 227.392);
|
|
25
81
|
--chart-4: oklch(0.828 0.189 84.429);
|
|
26
82
|
--chart-5: oklch(0.769 0.188 70.08);
|
|
27
|
-
--sidebar: oklch(0.
|
|
28
|
-
--sidebar-foreground: oklch(0
|
|
29
|
-
--sidebar-primary: oklch(0.
|
|
30
|
-
--sidebar-primary-foreground: oklch(0
|
|
31
|
-
--sidebar-accent: oklch(0.
|
|
32
|
-
--sidebar-accent-foreground: oklch(0.
|
|
33
|
-
--sidebar-border: oklch(0.
|
|
34
|
-
--sidebar-ring: oklch(0.
|
|
83
|
+
--sidebar: oklch(0.1221 0 0);
|
|
84
|
+
--sidebar-foreground: oklch(1 0 0);
|
|
85
|
+
--sidebar-primary: oklch(0.8 0 0);
|
|
86
|
+
--sidebar-primary-foreground: oklch(0 0 0);
|
|
87
|
+
--sidebar-accent: oklch(0.2 0 0);
|
|
88
|
+
--sidebar-accent-foreground: oklch(0.9 0 0);
|
|
89
|
+
--sidebar-border: oklch(0.25 0 0);
|
|
90
|
+
--sidebar-ring: oklch(0.8 0 0);
|
|
35
91
|
}
|
|
36
92
|
|
|
37
|
-
|
|
38
|
-
html[data-theme=
|
|
39
|
-
--
|
|
40
|
-
--background: oklch(0 0 0);
|
|
93
|
+
.dark,
|
|
94
|
+
html[data-theme='ekkoos-dark'] {
|
|
95
|
+
--font-sans: 'SatoshiVariable', sans-serif;
|
|
96
|
+
--background: oklch(0.1221 0 0);
|
|
41
97
|
--foreground: oklch(1 0 0);
|
|
98
|
+
--background-notes: oklch(0.1719 0.0016 197);
|
|
99
|
+
--foreground-notes: oklch(1 0 0);
|
|
42
100
|
--card: oklch(0.05 0 0 / 0.8);
|
|
101
|
+
--sidebar: oklch(0.05 0 0 / 0.8);
|
|
43
102
|
--card-foreground: oklch(1 0 0);
|
|
44
103
|
--popover: oklch(0.05 0 0);
|
|
45
104
|
--popover-foreground: oklch(1 0 0);
|
|
@@ -49,23 +108,19 @@ html[data-theme="ekkoos-dark"] {
|
|
|
49
108
|
--secondary-foreground: oklch(0.9 0 0);
|
|
50
109
|
--muted: oklch(0.1 0 0);
|
|
51
110
|
--muted-foreground: oklch(0.6 0 0);
|
|
52
|
-
--accent: oklch(0.
|
|
53
|
-
--accent-foreground: oklch(
|
|
54
|
-
--destructive: oklch(0.
|
|
55
|
-
--
|
|
56
|
-
--
|
|
111
|
+
--accent: oklch(0.206 0.006 286);
|
|
112
|
+
--accent-foreground: oklch(0.985 0 0);
|
|
113
|
+
--destructive: oklch(0.712 0.194 13.428);
|
|
114
|
+
--success: oklch(0.765 0.177 163.223);
|
|
115
|
+
--warning: oklch(0.828 0.189 84.429);
|
|
116
|
+
--info: oklch(0.7 0.14 250);
|
|
117
|
+
--border: oklch(0.25 0 0);
|
|
118
|
+
--input: oklch(0.18 0 0);
|
|
57
119
|
--ring: oklch(0.8 0 0);
|
|
58
|
-
--chart-1: oklch(0.
|
|
59
|
-
--chart-2: oklch(0.
|
|
60
|
-
--chart-3: oklch(0.
|
|
61
|
-
--chart-4: oklch(0.
|
|
62
|
-
--chart-5: oklch(0.
|
|
63
|
-
--
|
|
64
|
-
--sidebar-foreground: oklch(1 0 0);
|
|
65
|
-
--sidebar-primary: oklch(0.8 0 0);
|
|
66
|
-
--sidebar-primary-foreground: oklch(0 0 0);
|
|
67
|
-
--sidebar-accent: oklch(0.2 0 0);
|
|
68
|
-
--sidebar-accent-foreground: oklch(0.9 0 0);
|
|
69
|
-
--sidebar-border: oklch(0.1 0 0);
|
|
70
|
-
--sidebar-ring: oklch(0.8 0 0);
|
|
120
|
+
--chart-1: oklch(0.646 0.222 41.116);
|
|
121
|
+
--chart-2: oklch(0.6 0.118 184.704);
|
|
122
|
+
--chart-3: oklch(0.398 0.07 227.392);
|
|
123
|
+
--chart-4: oklch(0.828 0.189 84.429);
|
|
124
|
+
--chart-5: oklch(0.769 0.188 70.08);
|
|
125
|
+
--radius: 0.75rem;
|
|
71
126
|
}
|
package/dist/themes/ekkolyth.css
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/* Ekkolyth - Light */
|
|
2
|
-
html[data-theme=
|
|
2
|
+
html[data-theme='ekkolyth-light'] {
|
|
3
3
|
--background: oklch(1 0 0);
|
|
4
4
|
--foreground: oklch(0.141 0.005 285.823);
|
|
5
5
|
--card: oklch(1 0 0);
|
|
@@ -35,7 +35,7 @@ html[data-theme="ekkolyth-light"] {
|
|
|
35
35
|
}
|
|
36
36
|
|
|
37
37
|
/* Ekkolyth - Dark */
|
|
38
|
-
html[data-theme=
|
|
38
|
+
html[data-theme='ekkolyth-dark'] {
|
|
39
39
|
--background: oklch(0.141 0.005 285.823);
|
|
40
40
|
--foreground: oklch(0.985 0 0);
|
|
41
41
|
--card: oklch(0.21 0.006 285.885);
|
package/dist/themes/index.css
CHANGED
|
@@ -1,66 +1,7 @@
|
|
|
1
|
-
@import
|
|
2
|
-
@import
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
@import
|
|
6
|
-
@import
|
|
7
|
-
@import
|
|
8
|
-
@import "./themes/catpuccin/mocha.css";
|
|
9
|
-
@import "./themes/ekko-os.css";
|
|
10
|
-
@import "./themes/tokyo-night.css";
|
|
11
|
-
@import "./themes/ekkolyth.css";
|
|
12
|
-
@import "./themes/ekko-playlist.css";
|
|
13
|
-
|
|
14
|
-
@custom-variant dark (&:is(.dark *));
|
|
15
|
-
|
|
16
|
-
@theme inline {
|
|
17
|
-
--color-background: var(--background);
|
|
18
|
-
--color-foreground: var(--foreground);
|
|
19
|
-
--font-sans: var(--font-sans);
|
|
20
|
-
--font-mono: var(--font-geist-mono);
|
|
21
|
-
--color-sidebar-ring: var(--sidebar-ring);
|
|
22
|
-
--color-sidebar-border: var(--sidebar-border);
|
|
23
|
-
--color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
|
|
24
|
-
--color-sidebar-accent: var(--sidebar-accent);
|
|
25
|
-
--color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
|
|
26
|
-
--color-sidebar-primary: var(--sidebar-primary);
|
|
27
|
-
--color-sidebar-foreground: var(--sidebar-foreground);
|
|
28
|
-
--color-sidebar: var(--sidebar);
|
|
29
|
-
--color-chart-5: var(--chart-5);
|
|
30
|
-
--color-chart-4: var(--chart-4);
|
|
31
|
-
--color-chart-3: var(--chart-3);
|
|
32
|
-
--color-chart-2: var(--chart-2);
|
|
33
|
-
--color-chart-1: var(--chart-1);
|
|
34
|
-
--color-ring: var(--ring);
|
|
35
|
-
--color-input: var(--input);
|
|
36
|
-
--color-border: var(--border);
|
|
37
|
-
--color-destructive: var(--destructive);
|
|
38
|
-
--color-accent-foreground: var(--accent-foreground);
|
|
39
|
-
--color-accent: var(--accent);
|
|
40
|
-
--color-muted-foreground: var(--muted-foreground);
|
|
41
|
-
--color-muted: var(--muted);
|
|
42
|
-
--color-secondary-foreground: var(--secondary-foreground);
|
|
43
|
-
--color-secondary: var(--secondary);
|
|
44
|
-
--color-primary-foreground: var(--primary-foreground);
|
|
45
|
-
--color-primary: var(--primary);
|
|
46
|
-
--color-popover-foreground: var(--popover-foreground);
|
|
47
|
-
--color-popover: var(--popover);
|
|
48
|
-
--color-card-foreground: var(--card-foreground);
|
|
49
|
-
--color-card: var(--card);
|
|
50
|
-
--radius-sm: calc(var(--radius) - 4px);
|
|
51
|
-
--radius-md: calc(var(--radius) - 2px);
|
|
52
|
-
--radius-lg: var(--radius);
|
|
53
|
-
--radius-xl: calc(var(--radius) + 4px);
|
|
54
|
-
--radius-2xl: calc(var(--radius) + 8px);
|
|
55
|
-
--radius-3xl: calc(var(--radius) + 12px);
|
|
56
|
-
--radius-4xl: calc(var(--radius) + 16px);
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
@layer base {
|
|
60
|
-
* {
|
|
61
|
-
@apply border-border outline-ring/50;
|
|
62
|
-
}
|
|
63
|
-
body {
|
|
64
|
-
@apply bg-background text-foreground;
|
|
65
|
-
}
|
|
66
|
-
}
|
|
1
|
+
@import './catpuccin/latte.css';
|
|
2
|
+
@import './catpuccin/frappe.css';
|
|
3
|
+
@import './catpuccin/macchiato.css';
|
|
4
|
+
@import './catpuccin/mocha.css';
|
|
5
|
+
@import './ekko-os.css';
|
|
6
|
+
@import './tokyo-night.css';
|
|
7
|
+
@import './ekkolyth.css';
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { i as Select, r as Toaster, t as Toggle } from "../index-BxcqwZNT.js";
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
import { PropsWithChildren, ReactNode } from "react";
|
|
4
|
+
//#region src/components/themes/components/theme-select/index.d.ts
|
|
5
|
+
interface ThemeSelectProps extends React.ComponentProps<typeof Select> {
|
|
6
|
+
className?: string;
|
|
7
|
+
size?: 'sm' | 'default';
|
|
8
|
+
}
|
|
9
|
+
declare function ThemeSelect({ size, className, ...props }: ThemeSelectProps): React.JSX.Element;
|
|
10
|
+
//#endregion
|
|
11
|
+
//#region src/components/themes/components/theme-toggle/index.d.ts
|
|
12
|
+
interface ThemeToggleProps extends React.ComponentProps<typeof Toggle> {
|
|
13
|
+
className?: string;
|
|
14
|
+
size?: 'default' | 'sm' | 'lg';
|
|
15
|
+
variant?: 'default' | 'outline';
|
|
16
|
+
}
|
|
17
|
+
declare function ThemeToggle({ variant, size, className, ...props }: ThemeToggleProps): React.JSX.Element;
|
|
18
|
+
//#endregion
|
|
19
|
+
//#region src/lib/types.d.ts
|
|
20
|
+
declare const APPEARANCE: readonly ["light", "dark", "system", "normal"];
|
|
21
|
+
type Appearance = (typeof APPEARANCE)[number];
|
|
22
|
+
declare const LIGHT_THEMES: readonly ["latte", "ekkoos-light", "ekkolyth-light"];
|
|
23
|
+
declare const DARK_THEMES: readonly ["mocha", "frappe", "macchiato", "tokyo-night", "ekkoos-dark", "ekkolyth-dark"];
|
|
24
|
+
type LightThemes = (typeof LIGHT_THEMES)[number];
|
|
25
|
+
type DarkThemes = (typeof DARK_THEMES)[number];
|
|
26
|
+
type ThemeName = LightThemes | DarkThemes;
|
|
27
|
+
//#endregion
|
|
28
|
+
//#region src/components/themes/context.d.ts
|
|
29
|
+
interface ThemeContextState {
|
|
30
|
+
appearance: Appearance;
|
|
31
|
+
availableThemes: {
|
|
32
|
+
dark: DarkThemes[];
|
|
33
|
+
light: LightThemes[];
|
|
34
|
+
};
|
|
35
|
+
resolvedMode: 'light' | 'dark';
|
|
36
|
+
resolvedTheme: ThemeName;
|
|
37
|
+
setAppearance: (appearance: Appearance) => void;
|
|
38
|
+
setSpecificTheme: (mode: 'light' | 'dark', theme: LightThemes | DarkThemes) => void;
|
|
39
|
+
}
|
|
40
|
+
interface ThemeProviderProps {
|
|
41
|
+
children?: ReactNode;
|
|
42
|
+
darkTheme?: DarkThemes | DarkThemes[];
|
|
43
|
+
defaultAppearance?: Appearance;
|
|
44
|
+
lightTheme?: LightThemes | LightThemes[];
|
|
45
|
+
storageKey?: string;
|
|
46
|
+
}
|
|
47
|
+
declare function useTheme(): ThemeContextState;
|
|
48
|
+
declare function useThemeContext(): ThemeContextState | null;
|
|
49
|
+
//#endregion
|
|
50
|
+
//#region src/components/themes/provider.d.ts
|
|
51
|
+
declare function ThemeProvider({ children, darkTheme, defaultAppearance, lightTheme, storageKey }: PropsWithChildren<ThemeProviderProps>): import("react").JSX.Element;
|
|
52
|
+
//#endregion
|
|
53
|
+
//#region src/components/themes/theme-script.d.ts
|
|
54
|
+
interface ThemeScriptProps {
|
|
55
|
+
darkTheme?: DarkThemes | DarkThemes[];
|
|
56
|
+
defaultAppearance?: Appearance;
|
|
57
|
+
lightTheme?: LightThemes | LightThemes[];
|
|
58
|
+
storageKey?: string;
|
|
59
|
+
}
|
|
60
|
+
declare function ThemeScript({ darkTheme, defaultAppearance, lightTheme, storageKey }: ThemeScriptProps): import("react").JSX.Element;
|
|
61
|
+
//#endregion
|
|
62
|
+
export { type Appearance, type DarkThemes, type LightThemes, type ThemeContextState, type ThemeName, ThemeProvider, type ThemeProviderProps, ThemeScript, type ThemeScriptProps, ThemeSelect, ThemeToggle, Toaster, useTheme, useThemeContext };
|
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
import { t as cn } from "../utils-C_uf36nf.js";
|
|
2
|
+
import { _ as SelectTrigger, a as applyTheme, c as useThemeContext, d as SelectGroup, f as SelectItem, i as ThemeContext, l as Select, o as normalizeMode, p as SelectLabel, r as Toaster, s as useTheme, t as Toggle, u as SelectContent, v as SelectValue } from "../toggle-B2PFPImC.js";
|
|
3
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
4
|
+
import { Monitor, Moon, Sun } from "lucide-react";
|
|
5
|
+
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
6
|
+
//#region src/lib/types.ts
|
|
7
|
+
const APPEARANCE = [
|
|
8
|
+
"light",
|
|
9
|
+
"dark",
|
|
10
|
+
"system",
|
|
11
|
+
"normal"
|
|
12
|
+
];
|
|
13
|
+
const LIGHT_THEMES = [
|
|
14
|
+
"latte",
|
|
15
|
+
"ekkoos-light",
|
|
16
|
+
"ekkolyth-light"
|
|
17
|
+
];
|
|
18
|
+
const DARK_THEMES = [
|
|
19
|
+
"mocha",
|
|
20
|
+
"frappe",
|
|
21
|
+
"macchiato",
|
|
22
|
+
"tokyo-night",
|
|
23
|
+
"ekkoos-dark",
|
|
24
|
+
"ekkolyth-dark"
|
|
25
|
+
];
|
|
26
|
+
//#endregion
|
|
27
|
+
//#region src/lib/theme.ts
|
|
28
|
+
function isLightTheme(theme) {
|
|
29
|
+
return LIGHT_THEMES.includes(theme);
|
|
30
|
+
}
|
|
31
|
+
function isDarkTheme(theme) {
|
|
32
|
+
return DARK_THEMES.includes(theme);
|
|
33
|
+
}
|
|
34
|
+
//#endregion
|
|
35
|
+
//#region src/components/themes/components/theme-select/index.tsx
|
|
36
|
+
function ThemeSelect({ size = "default", className, ...props }) {
|
|
37
|
+
const { availableThemes, resolvedTheme, setSpecificTheme, setAppearance } = useTheme();
|
|
38
|
+
const handleThemeChange = (value) => {
|
|
39
|
+
const theme = value;
|
|
40
|
+
if (isLightTheme(theme)) {
|
|
41
|
+
setSpecificTheme("light", theme);
|
|
42
|
+
setAppearance("light");
|
|
43
|
+
} else if (isDarkTheme(theme)) {
|
|
44
|
+
setSpecificTheme("dark", theme);
|
|
45
|
+
setAppearance("dark");
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
const formatThemeName = (theme) => {
|
|
49
|
+
if (theme === "ekkoos-light") return "EkkoOS Light";
|
|
50
|
+
if (theme === "ekkoos-dark") return "EkkoOS Dark";
|
|
51
|
+
if (theme === "tokyo-night") return "Tokyo Night";
|
|
52
|
+
return theme.charAt(0).toUpperCase() + theme.slice(1);
|
|
53
|
+
};
|
|
54
|
+
return /* @__PURE__ */ jsxs(Select, {
|
|
55
|
+
onValueChange: handleThemeChange,
|
|
56
|
+
value: resolvedTheme,
|
|
57
|
+
...props,
|
|
58
|
+
children: [/* @__PURE__ */ jsx(SelectTrigger, {
|
|
59
|
+
className: cn(className),
|
|
60
|
+
size,
|
|
61
|
+
children: /* @__PURE__ */ jsx(SelectValue, { placeholder: "Select theme" })
|
|
62
|
+
}), /* @__PURE__ */ jsxs(SelectContent, { children: [availableThemes.light.length > 0 && /* @__PURE__ */ jsxs(SelectGroup, { children: [/* @__PURE__ */ jsx(SelectLabel, { children: "Light Themes" }), availableThemes.light.map((theme) => /* @__PURE__ */ jsx(SelectItem, {
|
|
63
|
+
value: theme,
|
|
64
|
+
children: formatThemeName(theme)
|
|
65
|
+
}, theme))] }), availableThemes.dark.length > 0 && /* @__PURE__ */ jsxs(SelectGroup, { children: [/* @__PURE__ */ jsx(SelectLabel, { children: "Dark Themes" }), availableThemes.dark.map((theme) => /* @__PURE__ */ jsx(SelectItem, {
|
|
66
|
+
value: theme,
|
|
67
|
+
children: formatThemeName(theme)
|
|
68
|
+
}, theme))] })] })]
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
//#endregion
|
|
72
|
+
//#region src/components/themes/components/theme-toggle/index.tsx
|
|
73
|
+
function ThemeToggle({ variant = "default", size = "default", className, ...props }) {
|
|
74
|
+
const { setAppearance, appearance } = useTheme();
|
|
75
|
+
const cycleTheme = () => {
|
|
76
|
+
const cycle = [
|
|
77
|
+
"light",
|
|
78
|
+
"dark",
|
|
79
|
+
"system"
|
|
80
|
+
];
|
|
81
|
+
const nextIndex = (cycle.indexOf(appearance === "normal" ? "light" : appearance) + 1) % cycle.length;
|
|
82
|
+
setAppearance(cycle[nextIndex]);
|
|
83
|
+
};
|
|
84
|
+
const getIcon = () => {
|
|
85
|
+
switch (appearance === "normal" ? "light" : appearance) {
|
|
86
|
+
case "light": return /* @__PURE__ */ jsx(Sun, { className: "size-4" });
|
|
87
|
+
case "dark": return /* @__PURE__ */ jsx(Moon, { className: "size-4" });
|
|
88
|
+
case "system": return /* @__PURE__ */ jsx(Monitor, { className: "size-4" });
|
|
89
|
+
default: return /* @__PURE__ */ jsx(Monitor, { className: "size-4" });
|
|
90
|
+
}
|
|
91
|
+
};
|
|
92
|
+
return /* @__PURE__ */ jsx(Toggle, {
|
|
93
|
+
"aria-label": `Switch theme. Current: ${appearance}`,
|
|
94
|
+
className: cn(className),
|
|
95
|
+
onClick: cycleTheme,
|
|
96
|
+
size,
|
|
97
|
+
variant,
|
|
98
|
+
...props,
|
|
99
|
+
children: getIcon()
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
//#endregion
|
|
103
|
+
//#region src/components/themes/storage.ts
|
|
104
|
+
const isMemberOf = (values) => (value) => values.includes(value);
|
|
105
|
+
const isAppearance = isMemberOf(APPEARANCE);
|
|
106
|
+
function readItem(key) {
|
|
107
|
+
if (typeof window === "undefined") return null;
|
|
108
|
+
try {
|
|
109
|
+
return window.localStorage.getItem(key);
|
|
110
|
+
} catch {
|
|
111
|
+
return null;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
function readStoredTheme(storageKey, lightThemes, darkThemes) {
|
|
115
|
+
const stored = {};
|
|
116
|
+
const isLightTheme = isMemberOf(lightThemes);
|
|
117
|
+
const isDarkTheme = isMemberOf(darkThemes);
|
|
118
|
+
const mode = readItem(`${storageKey}.theme-mode`);
|
|
119
|
+
if (mode !== null && isAppearance(mode)) stored.mode = mode;
|
|
120
|
+
const light = readItem(`${storageKey}.theme-light`);
|
|
121
|
+
if (light !== null && isLightTheme(light)) stored.light = light;
|
|
122
|
+
const dark = readItem(`${storageKey}.theme-dark`);
|
|
123
|
+
if (dark !== null && isDarkTheme(dark)) stored.dark = dark;
|
|
124
|
+
return stored;
|
|
125
|
+
}
|
|
126
|
+
function writeStoredTheme(storageKey, key, value) {
|
|
127
|
+
if (typeof window === "undefined") return;
|
|
128
|
+
try {
|
|
129
|
+
window.localStorage.setItem(`${storageKey}.${key}`, value);
|
|
130
|
+
} catch {
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
//#endregion
|
|
135
|
+
//#region src/components/themes/provider.tsx
|
|
136
|
+
function systemPrefersDark() {
|
|
137
|
+
if (typeof window === "undefined" || typeof window.matchMedia !== "function") return false;
|
|
138
|
+
return window.matchMedia("(prefers-color-scheme: dark)").matches;
|
|
139
|
+
}
|
|
140
|
+
function ThemeProvider({ children, darkTheme = ["ekkolyth-dark"], defaultAppearance = "system", lightTheme = ["ekkolyth-light"], storageKey = "ekko-ui" }) {
|
|
141
|
+
const lightThemes = useMemo(() => Array.isArray(lightTheme) ? lightTheme : [lightTheme], [lightTheme]);
|
|
142
|
+
const darkThemes = useMemo(() => Array.isArray(darkTheme) ? darkTheme : [darkTheme], [darkTheme]);
|
|
143
|
+
const [appearance, setAppearanceState] = useState(defaultAppearance);
|
|
144
|
+
const [lightName, setLightName] = useState(lightThemes[0]);
|
|
145
|
+
const [darkName, setDarkName] = useState(darkThemes[0]);
|
|
146
|
+
const [systemIsDark, setSystemIsDark] = useState(false);
|
|
147
|
+
const [hasRestored, setHasRestored] = useState(false);
|
|
148
|
+
const normalizedAppearance = normalizeMode(appearance);
|
|
149
|
+
const resolvedMode = normalizedAppearance === "system" ? systemIsDark ? "dark" : "light" : normalizedAppearance;
|
|
150
|
+
const resolvedTheme = resolvedMode === "light" ? lightName : darkName;
|
|
151
|
+
const restoring = useRef(false);
|
|
152
|
+
useEffect(() => {
|
|
153
|
+
if (restoring.current) return;
|
|
154
|
+
restoring.current = true;
|
|
155
|
+
const stored = readStoredTheme(storageKey, lightThemes, darkThemes);
|
|
156
|
+
if (stored.mode !== void 0) setAppearanceState(stored.mode);
|
|
157
|
+
if (stored.light !== void 0) setLightName(stored.light);
|
|
158
|
+
if (stored.dark !== void 0) setDarkName(stored.dark);
|
|
159
|
+
setSystemIsDark(systemPrefersDark());
|
|
160
|
+
setHasRestored(true);
|
|
161
|
+
}, [
|
|
162
|
+
darkThemes,
|
|
163
|
+
lightThemes,
|
|
164
|
+
storageKey
|
|
165
|
+
]);
|
|
166
|
+
useEffect(() => {
|
|
167
|
+
if (!hasRestored) return;
|
|
168
|
+
applyTheme(resolvedTheme, resolvedMode);
|
|
169
|
+
}, [
|
|
170
|
+
hasRestored,
|
|
171
|
+
resolvedMode,
|
|
172
|
+
resolvedTheme
|
|
173
|
+
]);
|
|
174
|
+
useEffect(() => {
|
|
175
|
+
if (normalizeMode(appearance) !== "system") return;
|
|
176
|
+
const media = window.matchMedia("(prefers-color-scheme: dark)");
|
|
177
|
+
const sync = () => setSystemIsDark(media.matches);
|
|
178
|
+
sync();
|
|
179
|
+
media.addEventListener("change", sync);
|
|
180
|
+
return () => media.removeEventListener("change", sync);
|
|
181
|
+
}, [appearance]);
|
|
182
|
+
useEffect(() => {
|
|
183
|
+
const onStorage = (event) => {
|
|
184
|
+
if (event.key !== null && !event.key.startsWith(`${storageKey}.`)) return;
|
|
185
|
+
const stored = readStoredTheme(storageKey, lightThemes, darkThemes);
|
|
186
|
+
if (stored.mode !== void 0) setAppearanceState(stored.mode);
|
|
187
|
+
if (stored.light !== void 0) setLightName(stored.light);
|
|
188
|
+
if (stored.dark !== void 0) setDarkName(stored.dark);
|
|
189
|
+
};
|
|
190
|
+
window.addEventListener("storage", onStorage);
|
|
191
|
+
return () => window.removeEventListener("storage", onStorage);
|
|
192
|
+
}, [
|
|
193
|
+
darkThemes,
|
|
194
|
+
lightThemes,
|
|
195
|
+
storageKey
|
|
196
|
+
]);
|
|
197
|
+
const setAppearance = useCallback((next) => {
|
|
198
|
+
writeStoredTheme(storageKey, "theme-mode", next);
|
|
199
|
+
setAppearanceState(next);
|
|
200
|
+
}, [storageKey]);
|
|
201
|
+
const setSpecificTheme = useCallback((mode, theme) => {
|
|
202
|
+
if (mode === "light" && lightThemes.includes(theme)) {
|
|
203
|
+
writeStoredTheme(storageKey, "theme-light", theme);
|
|
204
|
+
setLightName(theme);
|
|
205
|
+
} else if (mode === "dark" && darkThemes.includes(theme)) {
|
|
206
|
+
writeStoredTheme(storageKey, "theme-dark", theme);
|
|
207
|
+
setDarkName(theme);
|
|
208
|
+
}
|
|
209
|
+
setAppearance(mode);
|
|
210
|
+
}, [
|
|
211
|
+
darkThemes,
|
|
212
|
+
lightThemes,
|
|
213
|
+
setAppearance,
|
|
214
|
+
storageKey
|
|
215
|
+
]);
|
|
216
|
+
const value = useMemo(() => ({
|
|
217
|
+
appearance,
|
|
218
|
+
availableThemes: {
|
|
219
|
+
dark: darkThemes,
|
|
220
|
+
light: lightThemes
|
|
221
|
+
},
|
|
222
|
+
resolvedMode,
|
|
223
|
+
resolvedTheme,
|
|
224
|
+
setAppearance,
|
|
225
|
+
setSpecificTheme
|
|
226
|
+
}), [
|
|
227
|
+
appearance,
|
|
228
|
+
darkThemes,
|
|
229
|
+
lightThemes,
|
|
230
|
+
resolvedMode,
|
|
231
|
+
resolvedTheme,
|
|
232
|
+
setAppearance,
|
|
233
|
+
setSpecificTheme
|
|
234
|
+
]);
|
|
235
|
+
return /* @__PURE__ */ jsx(ThemeContext, {
|
|
236
|
+
value,
|
|
237
|
+
children
|
|
238
|
+
});
|
|
239
|
+
}
|
|
240
|
+
//#endregion
|
|
241
|
+
//#region src/components/themes/theme-script.tsx
|
|
242
|
+
function applyStoredTheme(storageKey, lightThemes, darkThemes, defaultAppearance) {
|
|
243
|
+
try {
|
|
244
|
+
const read = (key) => window.localStorage.getItem(`${storageKey}.${key}`);
|
|
245
|
+
const stored = read("theme-mode");
|
|
246
|
+
const appearance = stored !== null && [
|
|
247
|
+
"light",
|
|
248
|
+
"dark",
|
|
249
|
+
"system",
|
|
250
|
+
"normal"
|
|
251
|
+
].includes(stored) ? stored : defaultAppearance;
|
|
252
|
+
const normalized = appearance === "normal" ? "light" : appearance;
|
|
253
|
+
const mode = normalized === "dark" ? "dark" : normalized === "light" ? "light" : window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
|
|
254
|
+
const themes = mode === "dark" ? darkThemes : lightThemes;
|
|
255
|
+
const storedTheme = read(mode === "dark" ? "theme-dark" : "theme-light");
|
|
256
|
+
const theme = storedTheme !== null && themes.includes(storedTheme) ? storedTheme : themes[0];
|
|
257
|
+
document.documentElement.setAttribute("data-theme", theme);
|
|
258
|
+
document.documentElement.classList.toggle("dark", mode === "dark");
|
|
259
|
+
} catch {}
|
|
260
|
+
}
|
|
261
|
+
function ThemeScript({ darkTheme = "ekkolyth-dark", defaultAppearance = "system", lightTheme = "ekkolyth-light", storageKey = "ekko-ui" }) {
|
|
262
|
+
const lightThemes = Array.isArray(lightTheme) ? lightTheme : [lightTheme];
|
|
263
|
+
const darkThemes = Array.isArray(darkTheme) ? darkTheme : [darkTheme];
|
|
264
|
+
const call = `(${applyStoredTheme.toString()})(${JSON.stringify(storageKey)},${JSON.stringify(lightThemes)},${JSON.stringify(darkThemes)},${JSON.stringify(defaultAppearance)})`;
|
|
265
|
+
return /* @__PURE__ */ jsx("script", {
|
|
266
|
+
dangerouslySetInnerHTML: { __html: call },
|
|
267
|
+
suppressHydrationWarning: true
|
|
268
|
+
});
|
|
269
|
+
}
|
|
270
|
+
//#endregion
|
|
271
|
+
export { ThemeProvider, ThemeScript, ThemeSelect, ThemeToggle, Toaster, useTheme, useThemeContext };
|
|
@@ -1,35 +1,35 @@
|
|
|
1
1
|
/* Tokyo Night Theme - Dark Mode */
|
|
2
|
-
html[data-theme=
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
2
|
+
html[data-theme='tokyo-night'] {
|
|
3
|
+
--radius: 0.625rem;
|
|
4
|
+
--background: hsl(233 16.00% 13.33%); /* #1a1b26 - dark blue-gray */
|
|
5
|
+
--foreground: hsl(228 23.53% 87.06%); /* #c0caf5 - light blue-gray */
|
|
6
|
+
--card: hsl(233 16.00% 13.33%); /* #1a1b26 */
|
|
7
|
+
--card-foreground: hsl(228 23.53% 87.06%); /* #c0caf5 */
|
|
8
|
+
--popover: hsl(233 16.00% 13.33%); /* #1a1b26 */
|
|
9
|
+
--popover-foreground: hsl(228 23.53% 87.06%); /* #c0caf5 */
|
|
10
|
+
--primary: hsl(217 91.67% 79.80%); /* #7aa2f7 - Tokyo Night blue */
|
|
11
|
+
--primary-foreground: hsl(233 16.00% 13.33%); /* #1a1b26 */
|
|
12
|
+
--secondary: hsl(233 18.18% 15.29%); /* #24283b - darker blue-gray */
|
|
13
|
+
--secondary-foreground: hsl(228 23.53% 87.06%); /* #c0caf5 */
|
|
14
|
+
--muted: hsl(233 18.18% 15.29%); /* #24283b */
|
|
15
|
+
--muted-foreground: hsl(230 13.33% 66.67%); /* #565f89 - muted text */
|
|
16
|
+
--accent: hsl(233 18.18% 15.29%); /* #24283b */
|
|
17
|
+
--accent-foreground: hsl(228 23.53% 87.06%); /* #c0caf5 */
|
|
18
|
+
--destructive: hsl(354 65.22% 78.24%); /* #f7768e - Tokyo Night red */
|
|
19
|
+
--border: hsl(233 18.18% 20.00%); /* #2f3549 - border color */
|
|
20
|
+
--input: hsl(233 18.18% 20.00%); /* #2f3549 */
|
|
21
|
+
--ring: hsl(217 91.67% 79.80%); /* #7aa2f7 - primary blue */
|
|
22
|
+
--chart-1: hsl(354 65.22% 78.24%); /* #f7768e - red */
|
|
23
|
+
--chart-2: hsl(158 64.00% 71.37%); /* #9ece6a - green */
|
|
24
|
+
--chart-3: hsl(217 91.67% 79.80%); /* #7aa2f7 - blue */
|
|
25
|
+
--chart-4: hsl(38 92.00% 72.16%); /* #e0af68 - yellow */
|
|
26
|
+
--chart-5: hsl(266 85.00% 78.24%); /* #bb9af7 - purple */
|
|
27
|
+
--sidebar: hsl(233 18.18% 12.94%); /* #16161e - darker background */
|
|
28
|
+
--sidebar-foreground: hsl(228 23.53% 87.06%); /* #c0caf5 */
|
|
29
|
+
--sidebar-primary: hsl(217 91.67% 79.80%); /* #7aa2f7 */
|
|
30
|
+
--sidebar-primary-foreground: hsl(233 16.00% 13.33%); /* #1a1b26 */
|
|
31
|
+
--sidebar-accent: hsl(233 18.18% 15.29%); /* #24283b */
|
|
32
|
+
--sidebar-accent-foreground: hsl(228 23.53% 87.06%); /* #c0caf5 */
|
|
33
|
+
--sidebar-border: hsl(233 18.18% 20.00%); /* #2f3549 */
|
|
34
|
+
--sidebar-ring: hsl(233 18.18% 20.00%); /* #2f3549 */
|
|
35
35
|
}
|