@jant/core 0.3.1 → 0.3.3
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.map +1 -1
- package/dist/app.js +0 -2
- package/dist/lib/constants.d.ts +1 -1
- package/dist/lib/constants.d.ts.map +1 -1
- package/dist/lib/constants.js +1 -2
- package/dist/routes/api/posts.js +1 -1
- package/dist/routes/dash/settings.d.ts +2 -0
- package/dist/routes/dash/settings.d.ts.map +1 -1
- package/dist/routes/dash/settings.js +413 -93
- package/dist/theme/layouts/DashLayout.d.ts.map +1 -1
- package/dist/theme/layouts/DashLayout.js +0 -8
- package/package.json +10 -5
- package/src/__tests__/helpers/app.ts +97 -0
- package/src/__tests__/helpers/db.ts +85 -0
- package/src/app.tsx +0 -3
- package/src/db/migrations/0001_add_search_fts.sql +34 -0
- package/src/db/migrations/meta/_journal.json +7 -0
- package/src/lib/__tests__/constants.test.ts +44 -0
- package/src/lib/__tests__/markdown.test.ts +133 -0
- package/src/lib/__tests__/schemas.test.ts +220 -0
- package/src/lib/__tests__/sqid.test.ts +65 -0
- package/src/lib/__tests__/sse.test.ts +86 -0
- package/src/lib/__tests__/time.test.ts +112 -0
- package/src/lib/__tests__/url.test.ts +138 -0
- package/src/lib/constants.ts +0 -1
- package/src/middleware/__tests__/auth.test.ts +139 -0
- package/src/routes/api/__tests__/posts.test.ts +306 -0
- package/src/routes/api/__tests__/search.test.ts +77 -0
- package/src/routes/api/posts.ts +3 -1
- package/src/routes/dash/settings.tsx +350 -16
- package/src/services/__tests__/collection.test.ts +226 -0
- package/src/services/__tests__/media.test.ts +134 -0
- package/src/services/__tests__/post.test.ts +636 -0
- package/src/services/__tests__/redirect.test.ts +110 -0
- package/src/services/__tests__/search.test.ts +143 -0
- package/src/services/__tests__/settings.test.ts +110 -0
- package/src/theme/layouts/DashLayout.tsx +0 -9
- package/dist/routes/dash/appearance.d.ts +0 -13
- package/dist/routes/dash/appearance.d.ts.map +0 -1
- package/dist/routes/dash/appearance.js +0 -160
- package/src/routes/dash/appearance.tsx +0 -176
|
@@ -1,16 +1,60 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "hono/jsx/jsx-runtime";
|
|
2
2
|
/**
|
|
3
3
|
* Dashboard Settings Routes
|
|
4
|
+
*
|
|
5
|
+
* Sub-pages: General, Appearance, Account
|
|
4
6
|
*/ import { Hono } from "hono";
|
|
5
7
|
import { useLingui as $_useLingui } from "@jant/core/i18n";
|
|
6
8
|
import { DashLayout } from "../../theme/layouts/index.js";
|
|
7
|
-
import { sse, dsToast } from "../../lib/sse.js";
|
|
8
|
-
import { getSiteLanguage, getConfigFallback } from "../../lib/config.js";
|
|
9
|
+
import { sse, dsRedirect, dsToast } from "../../lib/sse.js";
|
|
10
|
+
import { getSiteLanguage, getSiteName, getConfigFallback } from "../../lib/config.js";
|
|
11
|
+
import { SETTINGS_KEYS } from "../../lib/constants.js";
|
|
12
|
+
import { getAvailableThemes } from "../../lib/theme.js";
|
|
9
13
|
/** Escape HTML special characters for safe insertion into HTML strings */ function escapeHtml(str) {
|
|
10
14
|
return str.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
11
15
|
}
|
|
12
16
|
export const settingsRoutes = new Hono();
|
|
13
|
-
function
|
|
17
|
+
function SettingsNav({ currentTab }) {
|
|
18
|
+
const { i18n: $__i18n, _: $__ } = $_useLingui();
|
|
19
|
+
const tabs = [
|
|
20
|
+
{
|
|
21
|
+
id: "general",
|
|
22
|
+
label: $__i18n._({
|
|
23
|
+
id: "Weq9zb",
|
|
24
|
+
message: "General"
|
|
25
|
+
}),
|
|
26
|
+
href: "/dash/settings"
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
id: "appearance",
|
|
30
|
+
label: $__i18n._({
|
|
31
|
+
id: "aAIQg2",
|
|
32
|
+
message: "Appearance"
|
|
33
|
+
}),
|
|
34
|
+
href: "/dash/settings/appearance"
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
id: "account",
|
|
38
|
+
label: $__i18n._({
|
|
39
|
+
id: "AeXO77",
|
|
40
|
+
message: "Account"
|
|
41
|
+
}),
|
|
42
|
+
href: "/dash/settings/account"
|
|
43
|
+
}
|
|
44
|
+
];
|
|
45
|
+
return /*#__PURE__*/ _jsx("nav", {
|
|
46
|
+
class: "flex gap-1 mb-6",
|
|
47
|
+
children: tabs.map((tab)=>/*#__PURE__*/ _jsx("a", {
|
|
48
|
+
href: tab.href,
|
|
49
|
+
class: `px-3 py-2 text-sm rounded-md ${tab.id === currentTab ? "bg-accent text-accent-foreground font-medium" : "text-muted-foreground hover:bg-accent hover:text-accent-foreground"}`,
|
|
50
|
+
children: tab.label
|
|
51
|
+
}, tab.id))
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
// ---------------------------------------------------------------------------
|
|
55
|
+
// General tab
|
|
56
|
+
// ---------------------------------------------------------------------------
|
|
57
|
+
function GeneralContent({ siteName, siteDescription, siteLanguage, siteNameFallback, siteDescriptionFallback }) {
|
|
14
58
|
const { i18n: $__i18n, _: $__ } = $_useLingui();
|
|
15
59
|
const generalSignals = JSON.stringify({
|
|
16
60
|
siteName,
|
|
@@ -20,18 +64,276 @@ function SettingsContent({ siteName, siteDescription, siteLanguage, siteNameFall
|
|
|
20
64
|
return /*#__PURE__*/ _jsxs(_Fragment, {
|
|
21
65
|
children: [
|
|
22
66
|
/*#__PURE__*/ _jsx("h1", {
|
|
23
|
-
class: "text-2xl font-semibold mb-
|
|
67
|
+
class: "text-2xl font-semibold mb-2",
|
|
68
|
+
children: $__i18n._({
|
|
69
|
+
id: "Tz0i8g",
|
|
70
|
+
message: "Settings"
|
|
71
|
+
})
|
|
72
|
+
}),
|
|
73
|
+
/*#__PURE__*/ _jsx(SettingsNav, {
|
|
74
|
+
currentTab: "general"
|
|
75
|
+
}),
|
|
76
|
+
/*#__PURE__*/ _jsx("div", {
|
|
77
|
+
class: "flex flex-col gap-6 max-w-lg",
|
|
78
|
+
children: /*#__PURE__*/ _jsxs("form", {
|
|
79
|
+
"data-signals": generalSignals,
|
|
80
|
+
"data-on:submit__prevent": "@post('/dash/settings')",
|
|
81
|
+
children: [
|
|
82
|
+
/*#__PURE__*/ _jsxs("div", {
|
|
83
|
+
class: "card",
|
|
84
|
+
children: [
|
|
85
|
+
/*#__PURE__*/ _jsx("header", {
|
|
86
|
+
children: /*#__PURE__*/ _jsx("h2", {
|
|
87
|
+
children: $__i18n._({
|
|
88
|
+
id: "Weq9zb",
|
|
89
|
+
message: "General"
|
|
90
|
+
})
|
|
91
|
+
})
|
|
92
|
+
}),
|
|
93
|
+
/*#__PURE__*/ _jsxs("section", {
|
|
94
|
+
class: "flex flex-col gap-4",
|
|
95
|
+
children: [
|
|
96
|
+
/*#__PURE__*/ _jsxs("div", {
|
|
97
|
+
class: "field",
|
|
98
|
+
children: [
|
|
99
|
+
/*#__PURE__*/ _jsx("label", {
|
|
100
|
+
class: "label",
|
|
101
|
+
children: $__i18n._({
|
|
102
|
+
id: "SJmfuf",
|
|
103
|
+
message: "Site Name"
|
|
104
|
+
})
|
|
105
|
+
}),
|
|
106
|
+
/*#__PURE__*/ _jsx("input", {
|
|
107
|
+
type: "text",
|
|
108
|
+
"data-bind": "siteName",
|
|
109
|
+
class: "input",
|
|
110
|
+
placeholder: siteNameFallback
|
|
111
|
+
})
|
|
112
|
+
]
|
|
113
|
+
}),
|
|
114
|
+
/*#__PURE__*/ _jsxs("div", {
|
|
115
|
+
class: "field",
|
|
116
|
+
children: [
|
|
117
|
+
/*#__PURE__*/ _jsx("label", {
|
|
118
|
+
class: "label",
|
|
119
|
+
children: $__i18n._({
|
|
120
|
+
id: "u2f7vd",
|
|
121
|
+
message: "Site Description"
|
|
122
|
+
})
|
|
123
|
+
}),
|
|
124
|
+
/*#__PURE__*/ _jsx("textarea", {
|
|
125
|
+
"data-bind": "siteDescription",
|
|
126
|
+
class: "textarea",
|
|
127
|
+
rows: 3,
|
|
128
|
+
placeholder: siteDescriptionFallback,
|
|
129
|
+
children: siteDescription
|
|
130
|
+
})
|
|
131
|
+
]
|
|
132
|
+
}),
|
|
133
|
+
/*#__PURE__*/ _jsxs("div", {
|
|
134
|
+
class: "field",
|
|
135
|
+
children: [
|
|
136
|
+
/*#__PURE__*/ _jsx("label", {
|
|
137
|
+
class: "label",
|
|
138
|
+
children: $__i18n._({
|
|
139
|
+
id: "vXIe7J",
|
|
140
|
+
message: "Language"
|
|
141
|
+
})
|
|
142
|
+
}),
|
|
143
|
+
/*#__PURE__*/ _jsxs("select", {
|
|
144
|
+
"data-bind": "siteLanguage",
|
|
145
|
+
class: "select",
|
|
146
|
+
children: [
|
|
147
|
+
/*#__PURE__*/ _jsx("option", {
|
|
148
|
+
value: "en",
|
|
149
|
+
selected: siteLanguage === "en",
|
|
150
|
+
children: "English"
|
|
151
|
+
}),
|
|
152
|
+
/*#__PURE__*/ _jsx("option", {
|
|
153
|
+
value: "zh-Hans",
|
|
154
|
+
selected: siteLanguage === "zh-Hans",
|
|
155
|
+
children: "简体中文"
|
|
156
|
+
}),
|
|
157
|
+
/*#__PURE__*/ _jsx("option", {
|
|
158
|
+
value: "zh-Hant",
|
|
159
|
+
selected: siteLanguage === "zh-Hant",
|
|
160
|
+
children: "繁體中文"
|
|
161
|
+
})
|
|
162
|
+
]
|
|
163
|
+
})
|
|
164
|
+
]
|
|
165
|
+
})
|
|
166
|
+
]
|
|
167
|
+
})
|
|
168
|
+
]
|
|
169
|
+
}),
|
|
170
|
+
/*#__PURE__*/ _jsx("button", {
|
|
171
|
+
type: "submit",
|
|
172
|
+
class: "btn mt-4",
|
|
173
|
+
children: $__i18n._({
|
|
174
|
+
id: "UGT5vp",
|
|
175
|
+
message: "Save Settings"
|
|
176
|
+
})
|
|
177
|
+
})
|
|
178
|
+
]
|
|
179
|
+
})
|
|
180
|
+
})
|
|
181
|
+
]
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
// ---------------------------------------------------------------------------
|
|
185
|
+
// Appearance tab
|
|
186
|
+
// ---------------------------------------------------------------------------
|
|
187
|
+
function ThemeCard({ theme, selected }) {
|
|
188
|
+
const expr = `$theme === '${theme.id}'`;
|
|
189
|
+
const { preview } = theme;
|
|
190
|
+
return /*#__PURE__*/ _jsx("label", {
|
|
191
|
+
class: `block cursor-pointer rounded-lg border overflow-hidden transition-colors ${selected ? "border-primary" : "border-border"}`,
|
|
192
|
+
"data-class:border-primary": expr,
|
|
193
|
+
"data-class:border-border": `$theme !== '${theme.id}'`,
|
|
194
|
+
children: /*#__PURE__*/ _jsxs("div", {
|
|
195
|
+
class: "grid grid-cols-2",
|
|
196
|
+
children: [
|
|
197
|
+
/*#__PURE__*/ _jsxs("div", {
|
|
198
|
+
class: "p-5",
|
|
199
|
+
style: `background-color:${preview.lightBg};color:${preview.lightText}`,
|
|
200
|
+
children: [
|
|
201
|
+
/*#__PURE__*/ _jsx("input", {
|
|
202
|
+
type: "radio",
|
|
203
|
+
name: "theme",
|
|
204
|
+
value: theme.id,
|
|
205
|
+
"data-bind": "theme",
|
|
206
|
+
checked: selected || undefined,
|
|
207
|
+
class: "mb-1"
|
|
208
|
+
}),
|
|
209
|
+
/*#__PURE__*/ _jsx("h3", {
|
|
210
|
+
class: "font-bold text-lg",
|
|
211
|
+
children: theme.name
|
|
212
|
+
}),
|
|
213
|
+
/*#__PURE__*/ _jsxs("p", {
|
|
214
|
+
class: "text-sm mt-2 leading-relaxed",
|
|
215
|
+
children: [
|
|
216
|
+
"This is the ",
|
|
217
|
+
theme.name,
|
|
218
|
+
" theme in light mode. Links",
|
|
219
|
+
" ",
|
|
220
|
+
/*#__PURE__*/ _jsx("a", {
|
|
221
|
+
tabIndex: -1,
|
|
222
|
+
class: "underline",
|
|
223
|
+
style: `color:${preview.lightLink}`,
|
|
224
|
+
children: "look like this"
|
|
225
|
+
}),
|
|
226
|
+
". We'll show the correct light or dark mode based on your visitor's settings."
|
|
227
|
+
]
|
|
228
|
+
})
|
|
229
|
+
]
|
|
230
|
+
}),
|
|
231
|
+
/*#__PURE__*/ _jsxs("div", {
|
|
232
|
+
class: "p-5",
|
|
233
|
+
style: `background-color:${preview.darkBg};color:${preview.darkText}`,
|
|
234
|
+
children: [
|
|
235
|
+
/*#__PURE__*/ _jsx("h3", {
|
|
236
|
+
class: "font-bold text-lg",
|
|
237
|
+
children: theme.name
|
|
238
|
+
}),
|
|
239
|
+
/*#__PURE__*/ _jsxs("p", {
|
|
240
|
+
class: "text-sm mt-2 leading-relaxed",
|
|
241
|
+
children: [
|
|
242
|
+
"This is the ",
|
|
243
|
+
theme.name,
|
|
244
|
+
" theme in dark mode. Links",
|
|
245
|
+
" ",
|
|
246
|
+
/*#__PURE__*/ _jsx("a", {
|
|
247
|
+
tabIndex: -1,
|
|
248
|
+
class: "underline",
|
|
249
|
+
style: `color:${preview.darkLink}`,
|
|
250
|
+
children: "look like this"
|
|
251
|
+
}),
|
|
252
|
+
". We'll show the correct light or dark mode based on your visitor's settings."
|
|
253
|
+
]
|
|
254
|
+
})
|
|
255
|
+
]
|
|
256
|
+
})
|
|
257
|
+
]
|
|
258
|
+
})
|
|
259
|
+
});
|
|
260
|
+
}
|
|
261
|
+
function AppearanceContent({ themes, currentThemeId }) {
|
|
262
|
+
const { i18n: $__i18n, _: $__ } = $_useLingui();
|
|
263
|
+
const signals = JSON.stringify({
|
|
264
|
+
theme: currentThemeId
|
|
265
|
+
}).replace(/</g, "\\u003c");
|
|
266
|
+
return /*#__PURE__*/ _jsxs(_Fragment, {
|
|
267
|
+
children: [
|
|
268
|
+
/*#__PURE__*/ _jsx("h1", {
|
|
269
|
+
class: "text-2xl font-semibold mb-2",
|
|
24
270
|
children: $__i18n._({
|
|
25
271
|
id: "Tz0i8g",
|
|
26
272
|
message: "Settings"
|
|
27
273
|
})
|
|
28
274
|
}),
|
|
275
|
+
/*#__PURE__*/ _jsx(SettingsNav, {
|
|
276
|
+
currentTab: "appearance"
|
|
277
|
+
}),
|
|
278
|
+
/*#__PURE__*/ _jsx("div", {
|
|
279
|
+
"data-signals": signals,
|
|
280
|
+
"data-on:change": "@post('/dash/settings/appearance')",
|
|
281
|
+
class: "max-w-3xl",
|
|
282
|
+
children: /*#__PURE__*/ _jsxs("fieldset", {
|
|
283
|
+
children: [
|
|
284
|
+
/*#__PURE__*/ _jsx("legend", {
|
|
285
|
+
class: "text-lg font-semibold",
|
|
286
|
+
children: $__i18n._({
|
|
287
|
+
id: "rFmBG3",
|
|
288
|
+
message: "Color theme"
|
|
289
|
+
})
|
|
290
|
+
}),
|
|
291
|
+
/*#__PURE__*/ _jsx("p", {
|
|
292
|
+
class: "text-sm text-muted-foreground mb-4",
|
|
293
|
+
children: $__i18n._({
|
|
294
|
+
id: "07Epll",
|
|
295
|
+
message: "This will theme both your site and your dashboard. All color themes support dark mode."
|
|
296
|
+
})
|
|
297
|
+
}),
|
|
298
|
+
/*#__PURE__*/ _jsx("div", {
|
|
299
|
+
class: "flex flex-col gap-4",
|
|
300
|
+
children: themes.map((theme)=>/*#__PURE__*/ _jsx(ThemeCard, {
|
|
301
|
+
theme: theme,
|
|
302
|
+
selected: theme.id === currentThemeId
|
|
303
|
+
}, theme.id))
|
|
304
|
+
})
|
|
305
|
+
]
|
|
306
|
+
})
|
|
307
|
+
})
|
|
308
|
+
]
|
|
309
|
+
});
|
|
310
|
+
}
|
|
311
|
+
// ---------------------------------------------------------------------------
|
|
312
|
+
// Account tab
|
|
313
|
+
// ---------------------------------------------------------------------------
|
|
314
|
+
function AccountContent({ userName }) {
|
|
315
|
+
const { i18n: $__i18n, _: $__ } = $_useLingui();
|
|
316
|
+
const profileSignals = JSON.stringify({
|
|
317
|
+
userName
|
|
318
|
+
}).replace(/</g, "\\u003c");
|
|
319
|
+
return /*#__PURE__*/ _jsxs(_Fragment, {
|
|
320
|
+
children: [
|
|
321
|
+
/*#__PURE__*/ _jsx("h1", {
|
|
322
|
+
class: "text-2xl font-semibold mb-2",
|
|
323
|
+
children: $__i18n._({
|
|
324
|
+
id: "Tz0i8g",
|
|
325
|
+
message: "Settings"
|
|
326
|
+
})
|
|
327
|
+
}),
|
|
328
|
+
/*#__PURE__*/ _jsx(SettingsNav, {
|
|
329
|
+
currentTab: "account"
|
|
330
|
+
}),
|
|
29
331
|
/*#__PURE__*/ _jsxs("div", {
|
|
30
332
|
class: "flex flex-col gap-6 max-w-lg",
|
|
31
333
|
children: [
|
|
32
334
|
/*#__PURE__*/ _jsxs("form", {
|
|
33
|
-
"data-signals":
|
|
34
|
-
"data-on:submit__prevent": "@post('/dash/settings')",
|
|
335
|
+
"data-signals": profileSignals,
|
|
336
|
+
"data-on:submit__prevent": "@post('/dash/settings/account')",
|
|
35
337
|
children: [
|
|
36
338
|
/*#__PURE__*/ _jsxs("div", {
|
|
37
339
|
class: "card",
|
|
@@ -39,85 +341,31 @@ function SettingsContent({ siteName, siteDescription, siteLanguage, siteNameFall
|
|
|
39
341
|
/*#__PURE__*/ _jsx("header", {
|
|
40
342
|
children: /*#__PURE__*/ _jsx("h2", {
|
|
41
343
|
children: $__i18n._({
|
|
42
|
-
id: "
|
|
43
|
-
message: "
|
|
344
|
+
id: "vERlcd",
|
|
345
|
+
message: "Profile"
|
|
44
346
|
})
|
|
45
347
|
})
|
|
46
348
|
}),
|
|
47
|
-
/*#__PURE__*/
|
|
349
|
+
/*#__PURE__*/ _jsx("section", {
|
|
48
350
|
class: "flex flex-col gap-4",
|
|
49
|
-
children:
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
message: "Site Name"
|
|
58
|
-
})
|
|
59
|
-
}),
|
|
60
|
-
/*#__PURE__*/ _jsx("input", {
|
|
61
|
-
type: "text",
|
|
62
|
-
"data-bind": "siteName",
|
|
63
|
-
class: "input",
|
|
64
|
-
placeholder: siteNameFallback
|
|
351
|
+
children: /*#__PURE__*/ _jsxs("div", {
|
|
352
|
+
class: "field",
|
|
353
|
+
children: [
|
|
354
|
+
/*#__PURE__*/ _jsx("label", {
|
|
355
|
+
class: "label",
|
|
356
|
+
children: $__i18n._({
|
|
357
|
+
id: "6YtxFj",
|
|
358
|
+
message: "Name"
|
|
65
359
|
})
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
message: "Site Description"
|
|
76
|
-
})
|
|
77
|
-
}),
|
|
78
|
-
/*#__PURE__*/ _jsx("textarea", {
|
|
79
|
-
"data-bind": "siteDescription",
|
|
80
|
-
class: "textarea",
|
|
81
|
-
rows: 3,
|
|
82
|
-
placeholder: siteDescriptionFallback,
|
|
83
|
-
children: siteDescription
|
|
84
|
-
})
|
|
85
|
-
]
|
|
86
|
-
}),
|
|
87
|
-
/*#__PURE__*/ _jsxs("div", {
|
|
88
|
-
class: "field",
|
|
89
|
-
children: [
|
|
90
|
-
/*#__PURE__*/ _jsx("label", {
|
|
91
|
-
class: "label",
|
|
92
|
-
children: $__i18n._({
|
|
93
|
-
id: "vXIe7J",
|
|
94
|
-
message: "Language"
|
|
95
|
-
})
|
|
96
|
-
}),
|
|
97
|
-
/*#__PURE__*/ _jsxs("select", {
|
|
98
|
-
"data-bind": "siteLanguage",
|
|
99
|
-
class: "select",
|
|
100
|
-
children: [
|
|
101
|
-
/*#__PURE__*/ _jsx("option", {
|
|
102
|
-
value: "en",
|
|
103
|
-
selected: siteLanguage === "en",
|
|
104
|
-
children: "English"
|
|
105
|
-
}),
|
|
106
|
-
/*#__PURE__*/ _jsx("option", {
|
|
107
|
-
value: "zh-Hans",
|
|
108
|
-
selected: siteLanguage === "zh-Hans",
|
|
109
|
-
children: "简体中文"
|
|
110
|
-
}),
|
|
111
|
-
/*#__PURE__*/ _jsx("option", {
|
|
112
|
-
value: "zh-Hant",
|
|
113
|
-
selected: siteLanguage === "zh-Hant",
|
|
114
|
-
children: "繁體中文"
|
|
115
|
-
})
|
|
116
|
-
]
|
|
117
|
-
})
|
|
118
|
-
]
|
|
119
|
-
})
|
|
120
|
-
]
|
|
360
|
+
}),
|
|
361
|
+
/*#__PURE__*/ _jsx("input", {
|
|
362
|
+
type: "text",
|
|
363
|
+
"data-bind": "userName",
|
|
364
|
+
class: "input",
|
|
365
|
+
required: true
|
|
366
|
+
})
|
|
367
|
+
]
|
|
368
|
+
})
|
|
121
369
|
})
|
|
122
370
|
]
|
|
123
371
|
}),
|
|
@@ -125,8 +373,8 @@ function SettingsContent({ siteName, siteDescription, siteLanguage, siteNameFall
|
|
|
125
373
|
type: "submit",
|
|
126
374
|
class: "btn mt-4",
|
|
127
375
|
children: $__i18n._({
|
|
128
|
-
id: "
|
|
129
|
-
message: "Save
|
|
376
|
+
id: "ssqvZi",
|
|
377
|
+
message: "Save Profile"
|
|
130
378
|
})
|
|
131
379
|
})
|
|
132
380
|
]
|
|
@@ -227,14 +475,15 @@ function SettingsContent({ siteName, siteDescription, siteLanguage, siteNameFall
|
|
|
227
475
|
]
|
|
228
476
|
});
|
|
229
477
|
}
|
|
230
|
-
//
|
|
478
|
+
// ===========================================================================
|
|
479
|
+
// Route handlers
|
|
480
|
+
// ===========================================================================
|
|
481
|
+
// General settings page
|
|
231
482
|
settingsRoutes.get("/", async (c)=>{
|
|
232
483
|
const { settings } = c.var.services;
|
|
233
|
-
// Fetch raw DB values (null if not set)
|
|
234
484
|
const dbSiteName = await settings.get("SITE_NAME");
|
|
235
485
|
const dbSiteDescription = await settings.get("SITE_DESCRIPTION");
|
|
236
486
|
const siteLanguage = await getSiteLanguage(c);
|
|
237
|
-
// Fallback values (ENV > Default) for placeholders
|
|
238
487
|
const siteNameFallback = getConfigFallback(c, "SITE_NAME");
|
|
239
488
|
const siteDescriptionFallback = getConfigFallback(c, "SITE_DESCRIPTION");
|
|
240
489
|
const saved = c.req.query("saved") !== undefined;
|
|
@@ -246,7 +495,7 @@ settingsRoutes.get("/", async (c)=>{
|
|
|
246
495
|
toast: saved ? {
|
|
247
496
|
message: "Settings saved successfully."
|
|
248
497
|
} : undefined,
|
|
249
|
-
children: /*#__PURE__*/ _jsx(
|
|
498
|
+
children: /*#__PURE__*/ _jsx(GeneralContent, {
|
|
250
499
|
siteName: dbSiteName || "",
|
|
251
500
|
siteDescription: dbSiteDescription || "",
|
|
252
501
|
siteLanguage: siteLanguage,
|
|
@@ -255,12 +504,11 @@ settingsRoutes.get("/", async (c)=>{
|
|
|
255
504
|
})
|
|
256
505
|
}));
|
|
257
506
|
});
|
|
258
|
-
//
|
|
507
|
+
// Save general settings
|
|
259
508
|
settingsRoutes.post("/", async (c)=>{
|
|
260
509
|
const body = await c.req.json();
|
|
261
510
|
const { settings } = c.var.services;
|
|
262
511
|
const oldLanguage = await settings.get("SITE_LANGUAGE") ?? "en";
|
|
263
|
-
// For text fields: empty = remove from DB (fall back to ENV > Default)
|
|
264
512
|
if (body.siteName.trim()) {
|
|
265
513
|
await settings.set("SITE_NAME", body.siteName.trim());
|
|
266
514
|
} else {
|
|
@@ -271,20 +519,15 @@ settingsRoutes.post("/", async (c)=>{
|
|
|
271
519
|
} else {
|
|
272
520
|
await settings.remove("SITE_DESCRIPTION");
|
|
273
521
|
}
|
|
274
|
-
// Language always has a value from the select
|
|
275
522
|
await settings.set("SITE_LANGUAGE", body.siteLanguage);
|
|
276
523
|
const languageChanged = oldLanguage !== body.siteLanguage;
|
|
277
|
-
// Determine the effective display name after save
|
|
278
524
|
const displayName = body.siteName.trim() || getConfigFallback(c, "SITE_NAME");
|
|
279
525
|
return sse(c, async (stream)=>{
|
|
280
526
|
if (languageChanged) {
|
|
281
|
-
// Language changed - full reload needed to update all UI text
|
|
282
527
|
await stream.redirect("/dash/settings?saved");
|
|
283
528
|
} else {
|
|
284
529
|
const escaped = escapeHtml(displayName);
|
|
285
|
-
// Update header site name
|
|
286
530
|
await stream.patchElements(`<a id="site-name" href="/dash" class="font-semibold">${escaped}</a>`);
|
|
287
|
-
// Update page title
|
|
288
531
|
await stream.patchElements(`Settings - ${escaped}`, {
|
|
289
532
|
mode: "inner",
|
|
290
533
|
selector: "title"
|
|
@@ -293,6 +536,83 @@ settingsRoutes.post("/", async (c)=>{
|
|
|
293
536
|
}
|
|
294
537
|
});
|
|
295
538
|
});
|
|
539
|
+
// Appearance page
|
|
540
|
+
settingsRoutes.get("/appearance", async (c)=>{
|
|
541
|
+
const { settings } = c.var.services;
|
|
542
|
+
const siteName = await getSiteName(c);
|
|
543
|
+
const currentThemeId = await settings.get(SETTINGS_KEYS.THEME) ?? "default";
|
|
544
|
+
const themes = getAvailableThemes(c.var.config);
|
|
545
|
+
const saved = c.req.query("saved") !== undefined;
|
|
546
|
+
return c.html(/*#__PURE__*/ _jsx(DashLayout, {
|
|
547
|
+
c: c,
|
|
548
|
+
title: "Settings",
|
|
549
|
+
siteName: siteName,
|
|
550
|
+
currentPath: "/dash/settings",
|
|
551
|
+
toast: saved ? {
|
|
552
|
+
message: "Theme saved successfully."
|
|
553
|
+
} : undefined,
|
|
554
|
+
children: /*#__PURE__*/ _jsx(AppearanceContent, {
|
|
555
|
+
themes: themes,
|
|
556
|
+
currentThemeId: currentThemeId
|
|
557
|
+
})
|
|
558
|
+
}));
|
|
559
|
+
});
|
|
560
|
+
// Save theme
|
|
561
|
+
settingsRoutes.post("/appearance", async (c)=>{
|
|
562
|
+
const body = await c.req.json();
|
|
563
|
+
const { settings } = c.var.services;
|
|
564
|
+
const themes = getAvailableThemes(c.var.config);
|
|
565
|
+
const validTheme = themes.find((t)=>t.id === body.theme);
|
|
566
|
+
if (!validTheme) {
|
|
567
|
+
return dsToast("Invalid theme selected.", "error");
|
|
568
|
+
}
|
|
569
|
+
if (validTheme.id === "default") {
|
|
570
|
+
await settings.remove(SETTINGS_KEYS.THEME);
|
|
571
|
+
} else {
|
|
572
|
+
await settings.set(SETTINGS_KEYS.THEME, validTheme.id);
|
|
573
|
+
}
|
|
574
|
+
return dsRedirect("/dash/settings/appearance?saved");
|
|
575
|
+
});
|
|
576
|
+
// Account page
|
|
577
|
+
settingsRoutes.get("/account", async (c)=>{
|
|
578
|
+
const siteName = await getSiteName(c);
|
|
579
|
+
const session = await c.var.auth.api.getSession({
|
|
580
|
+
headers: c.req.raw.headers
|
|
581
|
+
});
|
|
582
|
+
const userName = session?.user?.name ?? "";
|
|
583
|
+
const saved = c.req.query("saved") !== undefined;
|
|
584
|
+
return c.html(/*#__PURE__*/ _jsx(DashLayout, {
|
|
585
|
+
c: c,
|
|
586
|
+
title: "Settings",
|
|
587
|
+
siteName: siteName,
|
|
588
|
+
currentPath: "/dash/settings",
|
|
589
|
+
toast: saved ? {
|
|
590
|
+
message: "Profile saved successfully."
|
|
591
|
+
} : undefined,
|
|
592
|
+
children: /*#__PURE__*/ _jsx(AccountContent, {
|
|
593
|
+
userName: userName
|
|
594
|
+
})
|
|
595
|
+
}));
|
|
596
|
+
});
|
|
597
|
+
// Save account profile
|
|
598
|
+
settingsRoutes.post("/account", async (c)=>{
|
|
599
|
+
const body = await c.req.json();
|
|
600
|
+
const name = body.userName?.trim();
|
|
601
|
+
if (!name) {
|
|
602
|
+
return dsToast("Name is required.", "error");
|
|
603
|
+
}
|
|
604
|
+
try {
|
|
605
|
+
await c.var.auth.api.updateUser({
|
|
606
|
+
body: {
|
|
607
|
+
name
|
|
608
|
+
},
|
|
609
|
+
headers: c.req.raw.headers
|
|
610
|
+
});
|
|
611
|
+
} catch {
|
|
612
|
+
return dsToast("Failed to update profile.", "error");
|
|
613
|
+
}
|
|
614
|
+
return dsToast("Profile saved successfully.");
|
|
615
|
+
});
|
|
296
616
|
// Change password
|
|
297
617
|
settingsRoutes.post("/password", async (c)=>{
|
|
298
618
|
const body = await c.req.json();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DashLayout.d.ts","sourceRoot":"","sources":["../../../src/theme/layouts/DashLayout.tsx"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,EAAE,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;AACtD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAEpC,OAAO,EAAc,KAAK,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAE9D,MAAM,WAAW,eAAe;IAC9B,CAAC,EAAE,OAAO,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,UAAU,CAAC;CACpB;
|
|
1
|
+
{"version":3,"file":"DashLayout.d.ts","sourceRoot":"","sources":["../../../src/theme/layouts/DashLayout.tsx"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,EAAE,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;AACtD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAEpC,OAAO,EAAc,KAAK,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAE9D,MAAM,WAAW,eAAe;IAC9B,CAAC,EAAE,OAAO,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,UAAU,CAAC;CACpB;AAkID,eAAO,MAAM,UAAU,EAAE,EAAE,CAAC,iBAAiB,CAAC,eAAe,CAAC,CAe7D,CAAC"}
|
|
@@ -114,14 +114,6 @@ function DashLayoutContent({ siteName, currentPath, children }) {
|
|
|
114
114
|
id: "Tz0i8g",
|
|
115
115
|
message: "Settings"
|
|
116
116
|
})
|
|
117
|
-
}),
|
|
118
|
-
/*#__PURE__*/ _jsx("a", {
|
|
119
|
-
href: "/dash/appearance",
|
|
120
|
-
class: navClass("/dash/appearance", /^\/dash\/appearance/),
|
|
121
|
-
children: $__i18n._({
|
|
122
|
-
id: "aAIQg2",
|
|
123
|
-
message: "Appearance"
|
|
124
|
-
})
|
|
125
117
|
})
|
|
126
118
|
]
|
|
127
119
|
})
|