@jant/core 0.2.17 → 0.2.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/dist/app.d.ts +1 -0
- package/dist/app.d.ts.map +1 -1
- package/dist/app.js +319 -115
- package/dist/i18n/context.d.ts +2 -2
- package/dist/i18n/context.js +1 -1
- package/dist/i18n/i18n.d.ts +1 -1
- package/dist/i18n/i18n.js +1 -1
- package/dist/i18n/index.d.ts +1 -1
- package/dist/i18n/index.js +1 -1
- package/dist/i18n/locales/en.d.ts.map +1 -1
- package/dist/i18n/locales/en.js +1 -1
- package/dist/i18n/locales/zh-Hans.d.ts.map +1 -1
- package/dist/i18n/locales/zh-Hans.js +1 -1
- package/dist/i18n/locales/zh-Hant.d.ts.map +1 -1
- package/dist/i18n/locales/zh-Hant.js +1 -1
- package/dist/lib/config.d.ts +44 -10
- package/dist/lib/config.d.ts.map +1 -1
- package/dist/lib/config.js +69 -44
- package/dist/lib/constants.d.ts +2 -1
- package/dist/lib/constants.d.ts.map +1 -1
- package/dist/lib/constants.js +5 -2
- package/dist/lib/sse.d.ts +15 -0
- package/dist/lib/sse.d.ts.map +1 -1
- package/dist/lib/sse.js +13 -0
- package/dist/lib/theme.d.ts +44 -0
- package/dist/lib/theme.d.ts.map +1 -0
- package/dist/lib/theme.js +65 -0
- package/dist/routes/dash/appearance.d.ts +13 -0
- package/dist/routes/dash/appearance.d.ts.map +1 -0
- package/dist/routes/dash/appearance.js +164 -0
- package/dist/routes/dash/settings.d.ts.map +1 -1
- package/dist/routes/dash/settings.js +38 -37
- package/dist/services/settings.d.ts +1 -0
- package/dist/services/settings.d.ts.map +1 -1
- package/dist/services/settings.js +3 -0
- package/dist/theme/color-themes.d.ts +30 -0
- package/dist/theme/color-themes.d.ts.map +1 -0
- package/dist/theme/color-themes.js +268 -0
- package/dist/theme/layouts/BaseLayout.d.ts +5 -0
- package/dist/theme/layouts/BaseLayout.d.ts.map +1 -1
- package/dist/theme/layouts/BaseLayout.js +70 -3
- package/dist/theme/layouts/DashLayout.d.ts +2 -0
- package/dist/theme/layouts/DashLayout.d.ts.map +1 -1
- package/dist/theme/layouts/DashLayout.js +10 -1
- package/dist/theme/layouts/index.d.ts +1 -1
- package/dist/theme/layouts/index.d.ts.map +1 -1
- package/dist/types.d.ts +53 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +52 -0
- package/package.json +1 -1
- package/src/app.tsx +272 -55
- package/src/db/migrations/{0000_solid_moon_knight.sql → 0000_square_wallflower.sql} +3 -3
- package/src/db/migrations/meta/0000_snapshot.json +9 -9
- package/src/db/migrations/meta/_journal.json +2 -30
- package/src/i18n/context.tsx +2 -2
- package/src/i18n/i18n.ts +1 -1
- package/src/i18n/index.ts +1 -1
- package/src/i18n/locales/en.po +328 -252
- package/src/i18n/locales/en.ts +1 -1
- package/src/i18n/locales/zh-Hans.po +315 -278
- package/src/i18n/locales/zh-Hans.ts +1 -1
- package/src/i18n/locales/zh-Hant.po +315 -278
- package/src/i18n/locales/zh-Hant.ts +1 -1
- package/src/lib/config.ts +73 -47
- package/src/lib/constants.ts +3 -0
- package/src/lib/sse.ts +38 -0
- package/src/lib/theme.ts +86 -0
- package/src/preset.css +9 -0
- package/src/routes/dash/appearance.tsx +180 -0
- package/src/routes/dash/settings.tsx +50 -52
- package/src/services/settings.ts +5 -0
- package/src/styles/components.css +93 -0
- package/src/theme/color-themes.ts +321 -0
- package/src/theme/layouts/BaseLayout.tsx +61 -1
- package/src/theme/layouts/DashLayout.tsx +13 -2
- package/src/theme/layouts/index.ts +5 -1
- package/src/types.ts +62 -1
- package/src/db/migrations/0001_add_search_fts.sql +0 -40
- package/src/db/migrations/0002_collection_path.sql +0 -2
- package/src/db/migrations/0003_collection_path_nullable.sql +0 -21
- package/src/db/migrations/0004_media_uuid.sql +0 -35
|
@@ -8,11 +8,7 @@ import type { Bindings } from "../../types.js";
|
|
|
8
8
|
import type { AppVariables } from "../../app.js";
|
|
9
9
|
import { DashLayout } from "../../theme/layouts/index.js";
|
|
10
10
|
import { sse } from "../../lib/sse.js";
|
|
11
|
-
import {
|
|
12
|
-
getSiteName,
|
|
13
|
-
getSiteDescription,
|
|
14
|
-
getSiteLanguage,
|
|
15
|
-
} from "../../lib/config.js";
|
|
11
|
+
import { getSiteLanguage, getConfigFallback } from "../../lib/config.js";
|
|
16
12
|
|
|
17
13
|
type Env = { Bindings: Bindings; Variables: AppVariables };
|
|
18
14
|
|
|
@@ -22,12 +18,14 @@ function SettingsContent({
|
|
|
22
18
|
siteName,
|
|
23
19
|
siteDescription,
|
|
24
20
|
siteLanguage,
|
|
25
|
-
|
|
21
|
+
siteNameFallback,
|
|
22
|
+
siteDescriptionFallback,
|
|
26
23
|
}: {
|
|
27
24
|
siteName: string;
|
|
28
25
|
siteDescription: string;
|
|
29
26
|
siteLanguage: string;
|
|
30
|
-
|
|
27
|
+
siteNameFallback: string;
|
|
28
|
+
siteDescriptionFallback: string;
|
|
31
29
|
}) {
|
|
32
30
|
const { t } = useLingui();
|
|
33
31
|
|
|
@@ -43,27 +41,11 @@ function SettingsContent({
|
|
|
43
41
|
{t({ message: "Settings", comment: "@context: Dashboard heading" })}
|
|
44
42
|
</h1>
|
|
45
43
|
|
|
46
|
-
{saved && (
|
|
47
|
-
<div
|
|
48
|
-
id="settings-saved-toast"
|
|
49
|
-
class="alert mb-4 max-w-lg transition-opacity duration-300"
|
|
50
|
-
data-init={`console.log('[toast] init fired at', Date.now()); history.replaceState({}, '', '/dash/settings'); setTimeout(() => { console.log('[toast] hiding at', Date.now()); const el = document.getElementById('settings-saved-toast'); if (el) { el.style.opacity = '0'; setTimeout(() => el.remove(), 300) } }, 3000)`}
|
|
51
|
-
>
|
|
52
|
-
<h2>
|
|
53
|
-
{t({
|
|
54
|
-
message: "Settings saved successfully.",
|
|
55
|
-
comment: "@context: Toast message after saving settings",
|
|
56
|
-
})}
|
|
57
|
-
</h2>
|
|
58
|
-
</div>
|
|
59
|
-
)}
|
|
60
|
-
|
|
61
44
|
<div class="flex flex-col gap-6 max-w-lg">
|
|
62
45
|
<form
|
|
63
46
|
data-signals={generalSignals}
|
|
64
47
|
data-on:submit__prevent="@post('/dash/settings')"
|
|
65
48
|
>
|
|
66
|
-
<div id="settings-message"></div>
|
|
67
49
|
<div class="card">
|
|
68
50
|
<header>
|
|
69
51
|
<h2>
|
|
@@ -85,7 +67,7 @@ function SettingsContent({
|
|
|
85
67
|
type="text"
|
|
86
68
|
data-bind="siteName"
|
|
87
69
|
class="input"
|
|
88
|
-
|
|
70
|
+
placeholder={siteNameFallback}
|
|
89
71
|
/>
|
|
90
72
|
</div>
|
|
91
73
|
|
|
@@ -96,7 +78,12 @@ function SettingsContent({
|
|
|
96
78
|
comment: "@context: Settings form field",
|
|
97
79
|
})}
|
|
98
80
|
</label>
|
|
99
|
-
<textarea
|
|
81
|
+
<textarea
|
|
82
|
+
data-bind="siteDescription"
|
|
83
|
+
class="textarea"
|
|
84
|
+
rows={3}
|
|
85
|
+
placeholder={siteDescriptionFallback}
|
|
86
|
+
>
|
|
100
87
|
{siteDescription}
|
|
101
88
|
</textarea>
|
|
102
89
|
</div>
|
|
@@ -135,7 +122,6 @@ function SettingsContent({
|
|
|
135
122
|
data-signals="{currentPassword: '', newPassword: '', confirmPassword: ''}"
|
|
136
123
|
data-on:submit__prevent="@post('/dash/settings/password')"
|
|
137
124
|
>
|
|
138
|
-
<div id="password-message"></div>
|
|
139
125
|
<div class="card">
|
|
140
126
|
<header>
|
|
141
127
|
<h2>
|
|
@@ -212,23 +198,33 @@ function SettingsContent({
|
|
|
212
198
|
|
|
213
199
|
// Settings page
|
|
214
200
|
settingsRoutes.get("/", async (c) => {
|
|
215
|
-
const
|
|
216
|
-
|
|
201
|
+
const { settings } = c.var.services;
|
|
202
|
+
|
|
203
|
+
// Fetch raw DB values (null if not set)
|
|
204
|
+
const dbSiteName = await settings.get("SITE_NAME");
|
|
205
|
+
const dbSiteDescription = await settings.get("SITE_DESCRIPTION");
|
|
217
206
|
const siteLanguage = await getSiteLanguage(c);
|
|
207
|
+
|
|
208
|
+
// Fallback values (ENV > Default) for placeholders
|
|
209
|
+
const siteNameFallback = getConfigFallback(c, "SITE_NAME");
|
|
210
|
+
const siteDescriptionFallback = getConfigFallback(c, "SITE_DESCRIPTION");
|
|
211
|
+
|
|
218
212
|
const saved = c.req.query("saved") !== undefined;
|
|
219
213
|
|
|
220
214
|
return c.html(
|
|
221
215
|
<DashLayout
|
|
222
216
|
c={c}
|
|
223
217
|
title="Settings"
|
|
224
|
-
siteName={
|
|
218
|
+
siteName={dbSiteName || siteNameFallback}
|
|
225
219
|
currentPath="/dash/settings"
|
|
220
|
+
toast={saved ? { message: "Settings saved successfully." } : undefined}
|
|
226
221
|
>
|
|
227
222
|
<SettingsContent
|
|
228
|
-
siteName={
|
|
229
|
-
siteDescription={
|
|
223
|
+
siteName={dbSiteName || ""}
|
|
224
|
+
siteDescription={dbSiteDescription || ""}
|
|
230
225
|
siteLanguage={siteLanguage}
|
|
231
|
-
|
|
226
|
+
siteNameFallback={siteNameFallback}
|
|
227
|
+
siteDescriptionFallback={siteDescriptionFallback}
|
|
232
228
|
/>
|
|
233
229
|
</DashLayout>,
|
|
234
230
|
);
|
|
@@ -242,14 +238,25 @@ settingsRoutes.post("/", async (c) => {
|
|
|
242
238
|
siteLanguage: string;
|
|
243
239
|
}>();
|
|
244
240
|
|
|
245
|
-
const
|
|
246
|
-
(await c.var.services.settings.get("SITE_LANGUAGE")) ?? "en";
|
|
241
|
+
const { settings } = c.var.services;
|
|
247
242
|
|
|
248
|
-
await
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
243
|
+
const oldLanguage = (await settings.get("SITE_LANGUAGE")) ?? "en";
|
|
244
|
+
|
|
245
|
+
// For text fields: empty = remove from DB (fall back to ENV > Default)
|
|
246
|
+
if (body.siteName.trim()) {
|
|
247
|
+
await settings.set("SITE_NAME", body.siteName.trim());
|
|
248
|
+
} else {
|
|
249
|
+
await settings.remove("SITE_NAME");
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
if (body.siteDescription.trim()) {
|
|
253
|
+
await settings.set("SITE_DESCRIPTION", body.siteDescription.trim());
|
|
254
|
+
} else {
|
|
255
|
+
await settings.remove("SITE_DESCRIPTION");
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
// Language always has a value from the select
|
|
259
|
+
await settings.set("SITE_LANGUAGE", body.siteLanguage);
|
|
253
260
|
|
|
254
261
|
const languageChanged = oldLanguage !== body.siteLanguage;
|
|
255
262
|
|
|
@@ -258,10 +265,7 @@ settingsRoutes.post("/", async (c) => {
|
|
|
258
265
|
// Language changed - full reload needed to update all UI text
|
|
259
266
|
await stream.redirect("/dash/settings?saved");
|
|
260
267
|
} else {
|
|
261
|
-
|
|
262
|
-
await stream.patchElements(
|
|
263
|
-
'<div id="settings-message"><div class="alert mb-4 transition-opacity duration-300" data-init="setTimeout(() => { el.style.opacity = \'0\'; setTimeout(() => el.remove(), 300) }, 3000)"><h2>Settings saved successfully.</h2></div></div>',
|
|
264
|
-
);
|
|
268
|
+
await stream.toast("Settings saved successfully.");
|
|
265
269
|
}
|
|
266
270
|
});
|
|
267
271
|
});
|
|
@@ -276,9 +280,7 @@ settingsRoutes.post("/password", async (c) => {
|
|
|
276
280
|
|
|
277
281
|
if (body.newPassword !== body.confirmPassword) {
|
|
278
282
|
return sse(c, async (stream) => {
|
|
279
|
-
await stream.
|
|
280
|
-
'<div id="password-message"><div class="alert-destructive mb-4"><h2>Passwords do not match.</h2></div></div>',
|
|
281
|
-
);
|
|
283
|
+
await stream.toast("Passwords do not match.", "error");
|
|
282
284
|
});
|
|
283
285
|
}
|
|
284
286
|
|
|
@@ -293,16 +295,12 @@ settingsRoutes.post("/password", async (c) => {
|
|
|
293
295
|
});
|
|
294
296
|
} catch {
|
|
295
297
|
return sse(c, async (stream) => {
|
|
296
|
-
await stream.
|
|
297
|
-
'<div id="password-message"><div class="alert-destructive mb-4"><h2>Current password is incorrect.</h2></div></div>',
|
|
298
|
-
);
|
|
298
|
+
await stream.toast("Current password is incorrect.", "error");
|
|
299
299
|
});
|
|
300
300
|
}
|
|
301
301
|
|
|
302
302
|
return sse(c, async (stream) => {
|
|
303
|
-
await stream.
|
|
304
|
-
'<div id="password-message"><div class="alert mb-4"><h2>Password changed successfully.</h2></div></div>',
|
|
305
|
-
);
|
|
303
|
+
await stream.toast("Password changed successfully.");
|
|
306
304
|
await stream.patchSignals({
|
|
307
305
|
currentPassword: "",
|
|
308
306
|
newPassword: "",
|
package/src/services/settings.ts
CHANGED
|
@@ -19,6 +19,7 @@ export interface SettingsService {
|
|
|
19
19
|
getAll(): Promise<Record<string, string>>;
|
|
20
20
|
set(key: SettingsKey, value: string): Promise<void>;
|
|
21
21
|
setMany(entries: Partial<Record<SettingsKey, string>>): Promise<void>;
|
|
22
|
+
remove(key: SettingsKey): Promise<void>;
|
|
22
23
|
isOnboardingComplete(): Promise<boolean>;
|
|
23
24
|
completeOnboarding(): Promise<void>;
|
|
24
25
|
}
|
|
@@ -54,6 +55,10 @@ export function createSettingsService(db: Database): SettingsService {
|
|
|
54
55
|
});
|
|
55
56
|
},
|
|
56
57
|
|
|
58
|
+
async remove(key) {
|
|
59
|
+
await db.delete(settings).where(eq(settings.key, key));
|
|
60
|
+
},
|
|
61
|
+
|
|
57
62
|
async setMany(entries) {
|
|
58
63
|
const timestamp = now();
|
|
59
64
|
const keys = Object.keys(entries) as SettingsKey[];
|
|
@@ -12,6 +12,32 @@
|
|
|
12
12
|
}
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
+
/* Alert variants */
|
|
16
|
+
@layer components {
|
|
17
|
+
.alert-success {
|
|
18
|
+
@apply relative w-full rounded-lg border px-4 py-3 text-sm grid has-[>svg]:grid-cols-[calc(var(--spacing)*4)_1fr] grid-cols-[0_1fr] has-[>svg]:gap-x-3 gap-y-0.5 items-start [&>svg]:size-4 [&>svg]:translate-y-0.5 [&>svg]:text-current;
|
|
19
|
+
@apply text-success bg-card [&>svg]:text-current;
|
|
20
|
+
|
|
21
|
+
> h2,
|
|
22
|
+
> h3,
|
|
23
|
+
> h4,
|
|
24
|
+
> h5,
|
|
25
|
+
> h6,
|
|
26
|
+
> strong,
|
|
27
|
+
> [data-title] {
|
|
28
|
+
@apply col-start-2 line-clamp-1 min-h-4 font-medium tracking-tight;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
> section {
|
|
32
|
+
@apply text-success col-start-2 grid justify-items-start gap-1 text-sm [&_p]:leading-relaxed;
|
|
33
|
+
|
|
34
|
+
ul {
|
|
35
|
+
@apply list-inside list-disc text-sm;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
15
41
|
/* Badge components */
|
|
16
42
|
@layer components {
|
|
17
43
|
.badge {
|
|
@@ -45,3 +71,70 @@
|
|
|
45
71
|
color: white;
|
|
46
72
|
}
|
|
47
73
|
}
|
|
74
|
+
|
|
75
|
+
/* Toast notifications */
|
|
76
|
+
@layer components {
|
|
77
|
+
.toast-container {
|
|
78
|
+
@apply fixed top-4 right-4 z-50 flex flex-col gap-2 pointer-events-none;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
.toast {
|
|
82
|
+
@apply pointer-events-auto rounded-lg border px-4 py-3 text-sm shadow-lg;
|
|
83
|
+
@apply flex items-start gap-2.5 min-w-64 max-w-sm;
|
|
84
|
+
background-color: var(--color-card);
|
|
85
|
+
animation: toast-in 0.3s ease-out;
|
|
86
|
+
|
|
87
|
+
> svg:first-child {
|
|
88
|
+
@apply size-4 shrink-0 translate-y-0.5;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
> span {
|
|
92
|
+
@apply flex-1;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
.toast-success {
|
|
97
|
+
color: var(--color-success);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
.toast-error {
|
|
101
|
+
color: var(--color-destructive);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
.toast-close {
|
|
105
|
+
@apply shrink-0 translate-y-0.5 cursor-pointer rounded-sm p-0 border-0 bg-transparent;
|
|
106
|
+
color: var(--color-muted-foreground);
|
|
107
|
+
|
|
108
|
+
&:hover {
|
|
109
|
+
color: var(--color-foreground);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
> svg {
|
|
113
|
+
@apply size-3.5;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
.toast-out {
|
|
118
|
+
animation: toast-out 0.3s ease-in forwards;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
@keyframes toast-in {
|
|
123
|
+
from {
|
|
124
|
+
opacity: 0;
|
|
125
|
+
transform: translateY(-0.5rem);
|
|
126
|
+
}
|
|
127
|
+
to {
|
|
128
|
+
opacity: 1;
|
|
129
|
+
transform: translateY(0);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
@keyframes toast-out {
|
|
134
|
+
from {
|
|
135
|
+
opacity: 1;
|
|
136
|
+
}
|
|
137
|
+
to {
|
|
138
|
+
opacity: 0;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
@@ -0,0 +1,321 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Built-in Color Themes
|
|
3
|
+
*
|
|
4
|
+
* Each theme defines CSS variable overrides for light and dark modes,
|
|
5
|
+
* plus preview colors for the theme picker UI.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* A color theme definition with light and dark mode CSS variable overrides.
|
|
10
|
+
*/
|
|
11
|
+
export interface ColorTheme {
|
|
12
|
+
/** Stored in DB settings, e.g. "beach" */
|
|
13
|
+
id: string;
|
|
14
|
+
/** Display name, e.g. "Beach" */
|
|
15
|
+
name: string;
|
|
16
|
+
/** CSS variable overrides for :root (light mode) */
|
|
17
|
+
light: Record<string, string>;
|
|
18
|
+
/** CSS variable overrides for .dark (dark mode) */
|
|
19
|
+
dark: Record<string, string>;
|
|
20
|
+
/** Preview colors (hex) for theme picker cards */
|
|
21
|
+
preview: {
|
|
22
|
+
lightBg: string;
|
|
23
|
+
lightText: string;
|
|
24
|
+
lightLink: string;
|
|
25
|
+
darkBg: string;
|
|
26
|
+
darkText: string;
|
|
27
|
+
darkLink: string;
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Create a comprehensive color theme from key colors.
|
|
33
|
+
* Derives card, popover, muted, secondary, accent, and sidebar variables.
|
|
34
|
+
*/
|
|
35
|
+
function defineTheme(opts: {
|
|
36
|
+
id: string;
|
|
37
|
+
name: string;
|
|
38
|
+
preview: ColorTheme["preview"];
|
|
39
|
+
light: {
|
|
40
|
+
bg: string;
|
|
41
|
+
fg: string;
|
|
42
|
+
primary: string;
|
|
43
|
+
primaryFg: string;
|
|
44
|
+
muted: string;
|
|
45
|
+
mutedFg: string;
|
|
46
|
+
border: string;
|
|
47
|
+
};
|
|
48
|
+
dark: {
|
|
49
|
+
bg: string;
|
|
50
|
+
fg: string;
|
|
51
|
+
primary: string;
|
|
52
|
+
primaryFg: string;
|
|
53
|
+
muted: string;
|
|
54
|
+
mutedFg: string;
|
|
55
|
+
border: string;
|
|
56
|
+
};
|
|
57
|
+
}): ColorTheme {
|
|
58
|
+
const { light, dark } = opts;
|
|
59
|
+
return {
|
|
60
|
+
id: opts.id,
|
|
61
|
+
name: opts.name,
|
|
62
|
+
preview: opts.preview,
|
|
63
|
+
light: {
|
|
64
|
+
"--background": light.bg,
|
|
65
|
+
"--foreground": light.fg,
|
|
66
|
+
"--card": light.bg,
|
|
67
|
+
"--card-foreground": light.fg,
|
|
68
|
+
"--popover": light.bg,
|
|
69
|
+
"--popover-foreground": light.fg,
|
|
70
|
+
"--primary": light.primary,
|
|
71
|
+
"--primary-foreground": light.primaryFg,
|
|
72
|
+
"--secondary": light.muted,
|
|
73
|
+
"--secondary-foreground": light.fg,
|
|
74
|
+
"--muted": light.muted,
|
|
75
|
+
"--muted-foreground": light.mutedFg,
|
|
76
|
+
"--accent": light.muted,
|
|
77
|
+
"--accent-foreground": light.fg,
|
|
78
|
+
"--border": light.border,
|
|
79
|
+
"--input": light.border,
|
|
80
|
+
"--ring": light.primary,
|
|
81
|
+
"--sidebar": light.bg,
|
|
82
|
+
"--sidebar-foreground": light.fg,
|
|
83
|
+
"--sidebar-primary": light.primary,
|
|
84
|
+
"--sidebar-primary-foreground": light.primaryFg,
|
|
85
|
+
"--sidebar-accent": light.muted,
|
|
86
|
+
"--sidebar-accent-foreground": light.fg,
|
|
87
|
+
"--sidebar-border": light.border,
|
|
88
|
+
"--sidebar-ring": light.primary,
|
|
89
|
+
},
|
|
90
|
+
dark: {
|
|
91
|
+
"--background": dark.bg,
|
|
92
|
+
"--foreground": dark.fg,
|
|
93
|
+
"--card": dark.bg,
|
|
94
|
+
"--card-foreground": dark.fg,
|
|
95
|
+
"--popover": dark.bg,
|
|
96
|
+
"--popover-foreground": dark.fg,
|
|
97
|
+
"--primary": dark.primary,
|
|
98
|
+
"--primary-foreground": dark.primaryFg,
|
|
99
|
+
"--secondary": dark.muted,
|
|
100
|
+
"--secondary-foreground": dark.fg,
|
|
101
|
+
"--muted": dark.muted,
|
|
102
|
+
"--muted-foreground": dark.mutedFg,
|
|
103
|
+
"--accent": dark.muted,
|
|
104
|
+
"--accent-foreground": dark.fg,
|
|
105
|
+
"--border": dark.border,
|
|
106
|
+
"--input": dark.border,
|
|
107
|
+
"--ring": dark.primary,
|
|
108
|
+
"--sidebar": dark.bg,
|
|
109
|
+
"--sidebar-foreground": dark.fg,
|
|
110
|
+
"--sidebar-primary": dark.primary,
|
|
111
|
+
"--sidebar-primary-foreground": dark.primaryFg,
|
|
112
|
+
"--sidebar-accent": dark.muted,
|
|
113
|
+
"--sidebar-accent-foreground": dark.fg,
|
|
114
|
+
"--sidebar-border": dark.border,
|
|
115
|
+
"--sidebar-ring": dark.primary,
|
|
116
|
+
},
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
export const BUILTIN_COLOR_THEMES: ColorTheme[] = [
|
|
121
|
+
{
|
|
122
|
+
id: "default",
|
|
123
|
+
name: "Default",
|
|
124
|
+
light: {},
|
|
125
|
+
dark: {},
|
|
126
|
+
preview: {
|
|
127
|
+
lightBg: "#ffffff",
|
|
128
|
+
lightText: "#1e1e1e",
|
|
129
|
+
lightLink: "#1e1e1e",
|
|
130
|
+
darkBg: "#262626",
|
|
131
|
+
darkText: "#fafafa",
|
|
132
|
+
darkLink: "#eaeaea",
|
|
133
|
+
},
|
|
134
|
+
},
|
|
135
|
+
|
|
136
|
+
defineTheme({
|
|
137
|
+
id: "beach",
|
|
138
|
+
name: "Beach",
|
|
139
|
+
preview: {
|
|
140
|
+
lightBg: "#f9f3ea",
|
|
141
|
+
lightText: "#3d3527",
|
|
142
|
+
lightLink: "#2d6a59",
|
|
143
|
+
darkBg: "#2d4553",
|
|
144
|
+
darkText: "#e2d6c4",
|
|
145
|
+
darkLink: "#7cc5a2",
|
|
146
|
+
},
|
|
147
|
+
light: {
|
|
148
|
+
bg: "oklch(0.97 0.01 85)",
|
|
149
|
+
fg: "oklch(0.28 0.02 65)",
|
|
150
|
+
primary: "oklch(0.46 0.1 170)",
|
|
151
|
+
primaryFg: "oklch(0.98 0.005 85)",
|
|
152
|
+
muted: "oklch(0.93 0.015 85)",
|
|
153
|
+
mutedFg: "oklch(0.52 0.015 65)",
|
|
154
|
+
border: "oklch(0.88 0.018 85)",
|
|
155
|
+
},
|
|
156
|
+
dark: {
|
|
157
|
+
bg: "oklch(0.27 0.03 210)",
|
|
158
|
+
fg: "oklch(0.88 0.015 80)",
|
|
159
|
+
primary: "oklch(0.72 0.1 165)",
|
|
160
|
+
primaryFg: "oklch(0.22 0.03 210)",
|
|
161
|
+
muted: "oklch(0.33 0.025 210)",
|
|
162
|
+
mutedFg: "oklch(0.65 0.015 80)",
|
|
163
|
+
border: "oklch(0.38 0.02 210)",
|
|
164
|
+
},
|
|
165
|
+
}),
|
|
166
|
+
|
|
167
|
+
defineTheme({
|
|
168
|
+
id: "gameboy",
|
|
169
|
+
name: "Gameboy",
|
|
170
|
+
preview: {
|
|
171
|
+
lightBg: "#d3d7c0",
|
|
172
|
+
lightText: "#2b3326",
|
|
173
|
+
lightLink: "#466740",
|
|
174
|
+
darkBg: "#1b1f18",
|
|
175
|
+
darkText: "#a6b09a",
|
|
176
|
+
darkLink: "#6d9660",
|
|
177
|
+
},
|
|
178
|
+
light: {
|
|
179
|
+
bg: "oklch(0.87 0.03 130)",
|
|
180
|
+
fg: "oklch(0.25 0.04 140)",
|
|
181
|
+
primary: "oklch(0.4 0.08 145)",
|
|
182
|
+
primaryFg: "oklch(0.92 0.02 130)",
|
|
183
|
+
muted: "oklch(0.83 0.035 130)",
|
|
184
|
+
mutedFg: "oklch(0.48 0.03 140)",
|
|
185
|
+
border: "oklch(0.79 0.035 130)",
|
|
186
|
+
},
|
|
187
|
+
dark: {
|
|
188
|
+
bg: "oklch(0.18 0.02 140)",
|
|
189
|
+
fg: "oklch(0.78 0.025 130)",
|
|
190
|
+
primary: "oklch(0.6 0.08 145)",
|
|
191
|
+
primaryFg: "oklch(0.15 0.02 140)",
|
|
192
|
+
muted: "oklch(0.24 0.02 140)",
|
|
193
|
+
mutedFg: "oklch(0.58 0.02 130)",
|
|
194
|
+
border: "oklch(0.3 0.02 140)",
|
|
195
|
+
},
|
|
196
|
+
}),
|
|
197
|
+
|
|
198
|
+
defineTheme({
|
|
199
|
+
id: "grayscale",
|
|
200
|
+
name: "Grayscale",
|
|
201
|
+
preview: {
|
|
202
|
+
lightBg: "#efefef",
|
|
203
|
+
lightText: "#3a3a3a",
|
|
204
|
+
lightLink: "#555555",
|
|
205
|
+
darkBg: "#1e1e1e",
|
|
206
|
+
darkText: "#c8c8c8",
|
|
207
|
+
darkLink: "#999999",
|
|
208
|
+
},
|
|
209
|
+
light: {
|
|
210
|
+
bg: "oklch(0.96 0 0)",
|
|
211
|
+
fg: "oklch(0.3 0 0)",
|
|
212
|
+
primary: "oklch(0.4 0 0)",
|
|
213
|
+
primaryFg: "oklch(0.96 0 0)",
|
|
214
|
+
muted: "oklch(0.92 0 0)",
|
|
215
|
+
mutedFg: "oklch(0.55 0 0)",
|
|
216
|
+
border: "oklch(0.87 0 0)",
|
|
217
|
+
},
|
|
218
|
+
dark: {
|
|
219
|
+
bg: "oklch(0.18 0 0)",
|
|
220
|
+
fg: "oklch(0.82 0 0)",
|
|
221
|
+
primary: "oklch(0.7 0 0)",
|
|
222
|
+
primaryFg: "oklch(0.18 0 0)",
|
|
223
|
+
muted: "oklch(0.24 0 0)",
|
|
224
|
+
mutedFg: "oklch(0.6 0 0)",
|
|
225
|
+
border: "oklch(0.3 0 0)",
|
|
226
|
+
},
|
|
227
|
+
}),
|
|
228
|
+
|
|
229
|
+
defineTheme({
|
|
230
|
+
id: "halloween",
|
|
231
|
+
name: "Halloween",
|
|
232
|
+
preview: {
|
|
233
|
+
lightBg: "#f9f2e3",
|
|
234
|
+
lightText: "#352200",
|
|
235
|
+
lightLink: "#cc5500",
|
|
236
|
+
darkBg: "#1e1000",
|
|
237
|
+
darkText: "#dfc390",
|
|
238
|
+
darkLink: "#ff8c00",
|
|
239
|
+
},
|
|
240
|
+
light: {
|
|
241
|
+
bg: "oklch(0.97 0.015 75)",
|
|
242
|
+
fg: "oklch(0.25 0.04 55)",
|
|
243
|
+
primary: "oklch(0.6 0.2 50)",
|
|
244
|
+
primaryFg: "oklch(0.98 0.01 75)",
|
|
245
|
+
muted: "oklch(0.93 0.02 75)",
|
|
246
|
+
mutedFg: "oklch(0.5 0.025 55)",
|
|
247
|
+
border: "oklch(0.88 0.025 75)",
|
|
248
|
+
},
|
|
249
|
+
dark: {
|
|
250
|
+
bg: "oklch(0.16 0.03 50)",
|
|
251
|
+
fg: "oklch(0.85 0.025 75)",
|
|
252
|
+
primary: "oklch(0.72 0.19 55)",
|
|
253
|
+
primaryFg: "oklch(0.14 0.03 50)",
|
|
254
|
+
muted: "oklch(0.22 0.025 50)",
|
|
255
|
+
mutedFg: "oklch(0.62 0.02 75)",
|
|
256
|
+
border: "oklch(0.28 0.025 50)",
|
|
257
|
+
},
|
|
258
|
+
}),
|
|
259
|
+
|
|
260
|
+
defineTheme({
|
|
261
|
+
id: "notepad",
|
|
262
|
+
name: "Notepad",
|
|
263
|
+
preview: {
|
|
264
|
+
lightBg: "#fdfce8",
|
|
265
|
+
lightText: "#333333",
|
|
266
|
+
lightLink: "#2060b8",
|
|
267
|
+
darkBg: "#2a291a",
|
|
268
|
+
darkText: "#d2d2b8",
|
|
269
|
+
darkLink: "#6695cc",
|
|
270
|
+
},
|
|
271
|
+
light: {
|
|
272
|
+
bg: "oklch(0.985 0.018 95)",
|
|
273
|
+
fg: "oklch(0.27 0 0)",
|
|
274
|
+
primary: "oklch(0.5 0.17 260)",
|
|
275
|
+
primaryFg: "oklch(0.985 0.01 95)",
|
|
276
|
+
muted: "oklch(0.94 0.022 95)",
|
|
277
|
+
mutedFg: "oklch(0.52 0 0)",
|
|
278
|
+
border: "oklch(0.88 0.025 95)",
|
|
279
|
+
},
|
|
280
|
+
dark: {
|
|
281
|
+
bg: "oklch(0.2 0.02 90)",
|
|
282
|
+
fg: "oklch(0.87 0.015 95)",
|
|
283
|
+
primary: "oklch(0.65 0.14 260)",
|
|
284
|
+
primaryFg: "oklch(0.98 0.01 95)",
|
|
285
|
+
muted: "oklch(0.26 0.018 90)",
|
|
286
|
+
mutedFg: "oklch(0.62 0.012 95)",
|
|
287
|
+
border: "oklch(0.32 0.018 90)",
|
|
288
|
+
},
|
|
289
|
+
}),
|
|
290
|
+
|
|
291
|
+
defineTheme({
|
|
292
|
+
id: "sonnet",
|
|
293
|
+
name: "Sonnet",
|
|
294
|
+
preview: {
|
|
295
|
+
lightBg: "#f7eef5",
|
|
296
|
+
lightText: "#2e1e2c",
|
|
297
|
+
lightLink: "#9845c8",
|
|
298
|
+
darkBg: "#1d1428",
|
|
299
|
+
darkText: "#d4c2d0",
|
|
300
|
+
darkLink: "#c080fc",
|
|
301
|
+
},
|
|
302
|
+
light: {
|
|
303
|
+
bg: "oklch(0.97 0.012 325)",
|
|
304
|
+
fg: "oklch(0.25 0.02 310)",
|
|
305
|
+
primary: "oklch(0.55 0.2 300)",
|
|
306
|
+
primaryFg: "oklch(0.98 0.008 325)",
|
|
307
|
+
muted: "oklch(0.93 0.016 325)",
|
|
308
|
+
mutedFg: "oklch(0.52 0.015 310)",
|
|
309
|
+
border: "oklch(0.88 0.016 325)",
|
|
310
|
+
},
|
|
311
|
+
dark: {
|
|
312
|
+
bg: "oklch(0.18 0.025 300)",
|
|
313
|
+
fg: "oklch(0.87 0.012 325)",
|
|
314
|
+
primary: "oklch(0.72 0.18 300)",
|
|
315
|
+
primaryFg: "oklch(0.98 0.008 325)",
|
|
316
|
+
muted: "oklch(0.24 0.022 300)",
|
|
317
|
+
mutedFg: "oklch(0.62 0.012 325)",
|
|
318
|
+
border: "oklch(0.3 0.022 300)",
|
|
319
|
+
},
|
|
320
|
+
}),
|
|
321
|
+
];
|