@takuhon/ui 0.10.0 → 0.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/ActivitySection.module-SQFQYFCW.module.css +18 -0
- package/dist/ImageField.module-CC3IBMDB.module.css +23 -0
- package/dist/admin/index.d.ts +62 -6
- package/dist/admin/index.js +343 -261
- package/dist/admin/index.js.map +1 -1
- package/dist/index.d.ts +29 -4
- package/dist/index.js +294 -270
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/admin/index.js
CHANGED
|
@@ -178,10 +178,185 @@ function CheckboxField({ label, checked, onChange }) {
|
|
|
178
178
|
] });
|
|
179
179
|
}
|
|
180
180
|
|
|
181
|
-
// src/admin/primitives/
|
|
181
|
+
// src/admin/primitives/ImageField.tsx
|
|
182
182
|
import { useId as useId3, useRef, useState } from "react";
|
|
183
|
-
|
|
183
|
+
|
|
184
|
+
// src/admin/admin-labels.ts
|
|
185
|
+
var EN = {
|
|
186
|
+
"app.title": "takuhon admin",
|
|
187
|
+
"toolbar.label": "Editor actions",
|
|
188
|
+
"mode.label": "Editing mode",
|
|
189
|
+
"mode.form": "Form",
|
|
190
|
+
"mode.advanced": "Advanced (JSON)",
|
|
191
|
+
"action.save": "Save",
|
|
192
|
+
"action.reload": "Reload",
|
|
193
|
+
"action.export": "Export",
|
|
194
|
+
"action.import": "Import",
|
|
195
|
+
"action.add": "Add",
|
|
196
|
+
"action.remove": "Remove",
|
|
197
|
+
"action.moveUp": "Move up",
|
|
198
|
+
"action.moveDown": "Move down",
|
|
199
|
+
"status.saving": "Saving\u2026",
|
|
200
|
+
"status.saved": "Saved.",
|
|
201
|
+
"status.loading": "Loading\u2026",
|
|
202
|
+
"status.conflict": "The profile changed on the server since it was loaded. Reload, then reapply the edits.",
|
|
203
|
+
"status.invalid": "Some fields need attention before saving.",
|
|
204
|
+
"status.fixSummary": "Please fix the following:",
|
|
205
|
+
"status.error": "Something went wrong. Please try again.",
|
|
206
|
+
"status.imported": "Imported. Review the fields, then save to apply.",
|
|
207
|
+
"status.importInvalid": "The imported file is not a valid takuhon document.",
|
|
208
|
+
"status.uploading": "Uploading\u2026",
|
|
209
|
+
"status.uploadError": "Upload failed. Please try again.",
|
|
210
|
+
"section.profile": "Profile",
|
|
211
|
+
"section.about": "About",
|
|
212
|
+
"section.links": "Links",
|
|
213
|
+
"section.careers": "Experience",
|
|
214
|
+
"section.projects": "Projects",
|
|
215
|
+
"section.skills": "Skills",
|
|
216
|
+
"section.settings": "Settings",
|
|
217
|
+
"field.displayName": "Display name",
|
|
218
|
+
"field.tagline": "Tagline",
|
|
219
|
+
"field.bio": "Bio",
|
|
220
|
+
"field.avatarUrl": "Avatar URL",
|
|
221
|
+
"field.avatarUpload": "Upload image",
|
|
222
|
+
"field.avatarAlt": "Avatar alternative text",
|
|
223
|
+
"field.location.country": "Country",
|
|
224
|
+
"field.location.region": "Region",
|
|
225
|
+
"field.location.locality": "Locality",
|
|
226
|
+
"field.location.display": "Location (display)",
|
|
227
|
+
"field.link.type": "Type",
|
|
228
|
+
"field.link.url": "URL",
|
|
229
|
+
"field.link.label": "Label",
|
|
230
|
+
"field.link.iconUrl": "Icon URL",
|
|
231
|
+
"field.link.featured": "Featured",
|
|
232
|
+
"field.career.organization": "Organization",
|
|
233
|
+
"field.career.role": "Role",
|
|
234
|
+
"field.career.description": "Description",
|
|
235
|
+
"field.career.startDate": "Start",
|
|
236
|
+
"field.career.endDate": "End",
|
|
237
|
+
"field.career.isCurrent": "Current position",
|
|
238
|
+
"field.career.url": "URL",
|
|
239
|
+
"field.project.title": "Title",
|
|
240
|
+
"field.project.description": "Description",
|
|
241
|
+
"field.project.url": "URL",
|
|
242
|
+
"field.project.tags": "Tags",
|
|
243
|
+
"field.project.highlighted": "Highlighted",
|
|
244
|
+
"field.project.startDate": "Start",
|
|
245
|
+
"field.project.endDate": "End",
|
|
246
|
+
"field.skill.label": "Label",
|
|
247
|
+
"field.skill.category": "Category",
|
|
248
|
+
"field.settings.defaultLocale": "Default locale",
|
|
249
|
+
"field.settings.fallbackLocale": "Fallback locale",
|
|
250
|
+
"field.settings.availableLocales": "Available locales",
|
|
251
|
+
"field.settings.theme": "Theme",
|
|
252
|
+
"field.settings.showPoweredBy": 'Show the "Powered by takuhon" footer',
|
|
253
|
+
"field.settings.enableJsonLd": "Emit Schema.org JSON-LD",
|
|
254
|
+
"field.settings.enableApi": "Expose the public read API",
|
|
255
|
+
"field.settings.enableAnalytics": "Enable first-party analytics",
|
|
256
|
+
"item.link": "Link",
|
|
257
|
+
"item.career": "Position",
|
|
258
|
+
"item.project": "Project",
|
|
259
|
+
"item.skill": "Skill",
|
|
260
|
+
"empty.links": "No links yet.",
|
|
261
|
+
"empty.careers": "No positions yet.",
|
|
262
|
+
"empty.projects": "No projects yet.",
|
|
263
|
+
"empty.skills": "No skills yet.",
|
|
264
|
+
"hint.avatarNoUpload": "Paste an image URL. Uploading image files is not available yet.",
|
|
265
|
+
"hint.avatarUpload": "Paste an image URL, or upload a JPEG, PNG, WebP, or GIF.",
|
|
266
|
+
"hint.month": "Format: YYYY-MM (e.g. 2024-03).",
|
|
267
|
+
"hint.country": "ISO 3166-1 alpha-2 code, e.g. US.",
|
|
268
|
+
"hint.tags": "Comma-separated.",
|
|
269
|
+
"hint.locales": "Comma-separated BCP-47 tags, e.g. en, ja. Drives the language tabs above.",
|
|
270
|
+
"advanced.hint": "Edit the entire document as JSON. Edits apply only while the JSON is valid.",
|
|
271
|
+
"advanced.invalid": "The JSON is not a valid takuhon document:",
|
|
272
|
+
"option.none": "(none)"
|
|
273
|
+
};
|
|
274
|
+
var DICTIONARIES = {
|
|
275
|
+
en: EN
|
|
276
|
+
};
|
|
277
|
+
function getAdminLabel(key, locale = "en") {
|
|
278
|
+
const exact = DICTIONARIES[locale]?.[key];
|
|
279
|
+
if (exact !== void 0) return exact;
|
|
280
|
+
const base = locale.split("-")[0];
|
|
281
|
+
const baseMatch = base ? DICTIONARIES[base]?.[key] : void 0;
|
|
282
|
+
return baseMatch ?? EN[key];
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
// src/admin/primitives/ImageField.tsx
|
|
286
|
+
import styles6 from "../ImageField.module-CC3IBMDB.module.css";
|
|
287
|
+
import controls from "../controls.module-CMB7V22N.module.css";
|
|
184
288
|
import { Fragment, jsx as jsx6, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
289
|
+
var ACCEPT = "image/jpeg,image/png,image/webp,image/gif";
|
|
290
|
+
function ImageField({
|
|
291
|
+
label,
|
|
292
|
+
value,
|
|
293
|
+
onChange,
|
|
294
|
+
errors,
|
|
295
|
+
hint,
|
|
296
|
+
uploadAsset
|
|
297
|
+
}) {
|
|
298
|
+
const fileId = useId3();
|
|
299
|
+
const statusId = useId3();
|
|
300
|
+
const fileRef = useRef(null);
|
|
301
|
+
const [busy, setBusy] = useState(false);
|
|
302
|
+
const [uploadError, setUploadError] = useState(null);
|
|
303
|
+
const handleFile = (event) => {
|
|
304
|
+
const file = event.target.files?.[0];
|
|
305
|
+
if (!file || uploadAsset === void 0) return;
|
|
306
|
+
setBusy(true);
|
|
307
|
+
setUploadError(null);
|
|
308
|
+
uploadAsset(file).then((result) => {
|
|
309
|
+
if (result.status === "uploaded") {
|
|
310
|
+
onChange(result.url);
|
|
311
|
+
} else {
|
|
312
|
+
setUploadError(result.message ?? getAdminLabel("status.uploadError"));
|
|
313
|
+
}
|
|
314
|
+
}).catch(() => {
|
|
315
|
+
setUploadError(getAdminLabel("status.uploadError"));
|
|
316
|
+
}).finally(() => {
|
|
317
|
+
setBusy(false);
|
|
318
|
+
if (fileRef.current) fileRef.current.value = "";
|
|
319
|
+
});
|
|
320
|
+
};
|
|
321
|
+
return /* @__PURE__ */ jsx6(Field, { label, errors, hint, children: ({ controlId, describedBy, invalid }) => /* @__PURE__ */ jsxs3(Fragment, { children: [
|
|
322
|
+
/* @__PURE__ */ jsx6(
|
|
323
|
+
"input",
|
|
324
|
+
{
|
|
325
|
+
id: controlId,
|
|
326
|
+
className: controls.control,
|
|
327
|
+
type: "url",
|
|
328
|
+
value,
|
|
329
|
+
"aria-invalid": invalid || void 0,
|
|
330
|
+
"aria-describedby": describedBy,
|
|
331
|
+
onChange: (event) => {
|
|
332
|
+
onChange(event.target.value);
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
),
|
|
336
|
+
uploadAsset !== void 0 ? /* @__PURE__ */ jsxs3("div", { className: styles6.uploadRow, children: [
|
|
337
|
+
/* @__PURE__ */ jsx6("label", { className: styles6.uploadLabel, htmlFor: fileId, children: getAdminLabel("field.avatarUpload") }),
|
|
338
|
+
/* @__PURE__ */ jsx6(
|
|
339
|
+
"input",
|
|
340
|
+
{
|
|
341
|
+
id: fileId,
|
|
342
|
+
ref: fileRef,
|
|
343
|
+
type: "file",
|
|
344
|
+
accept: ACCEPT,
|
|
345
|
+
disabled: busy,
|
|
346
|
+
"aria-describedby": statusId,
|
|
347
|
+
onChange: handleFile
|
|
348
|
+
}
|
|
349
|
+
),
|
|
350
|
+
/* @__PURE__ */ jsx6("span", { className: styles6.uploadStatus, id: statusId, role: "status", "aria-live": "polite", children: busy ? getAdminLabel("status.uploading") : "" }),
|
|
351
|
+
uploadError !== null ? /* @__PURE__ */ jsx6("span", { className: styles6.uploadError, role: "alert", children: uploadError }) : null
|
|
352
|
+
] }) : null
|
|
353
|
+
] }) });
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
// src/admin/primitives/LocaleTabs.tsx
|
|
357
|
+
import { useId as useId4, useRef as useRef2, useState as useState2 } from "react";
|
|
358
|
+
import styles7 from "../LocaleTabs.module-IEEC6Q27.module.css";
|
|
359
|
+
import { Fragment as Fragment2, jsx as jsx7, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
185
360
|
function LocaleTabs({
|
|
186
361
|
label,
|
|
187
362
|
value,
|
|
@@ -194,17 +369,17 @@ function LocaleTabs({
|
|
|
194
369
|
pointer,
|
|
195
370
|
formatLocale
|
|
196
371
|
}) {
|
|
197
|
-
const baseId =
|
|
198
|
-
const hintId =
|
|
199
|
-
const errorId =
|
|
200
|
-
const [active, setActive] =
|
|
201
|
-
const tabRefs =
|
|
372
|
+
const baseId = useId4();
|
|
373
|
+
const hintId = useId4();
|
|
374
|
+
const errorId = useId4();
|
|
375
|
+
const [active, setActive] = useState2(() => locales[0] ?? "");
|
|
376
|
+
const tabRefs = useRef2({});
|
|
202
377
|
const format = formatLocale ?? ((locale) => locale);
|
|
203
378
|
const labelId = `${baseId}-label`;
|
|
204
379
|
if (locales.length === 0) {
|
|
205
|
-
return /* @__PURE__ */
|
|
206
|
-
/* @__PURE__ */
|
|
207
|
-
/* @__PURE__ */
|
|
380
|
+
return /* @__PURE__ */ jsxs4("div", { className: styles7.group, role: "group", "aria-labelledby": labelId, children: [
|
|
381
|
+
/* @__PURE__ */ jsx7("span", { className: styles7.groupLabel, id: labelId, children: label }),
|
|
382
|
+
/* @__PURE__ */ jsx7("p", { className: styles7.hint, children: "No locales are configured yet; add one under Settings." })
|
|
208
383
|
] });
|
|
209
384
|
}
|
|
210
385
|
const activeLocale = locales.includes(active) ? active : locales[0];
|
|
@@ -249,16 +424,16 @@ function LocaleTabs({
|
|
|
249
424
|
}
|
|
250
425
|
};
|
|
251
426
|
const controlName = `${label} (${format(activeLocale)})`;
|
|
252
|
-
return /* @__PURE__ */
|
|
253
|
-
/* @__PURE__ */
|
|
427
|
+
return /* @__PURE__ */ jsxs4("div", { className: styles7.group, role: "group", "aria-labelledby": labelId, children: [
|
|
428
|
+
/* @__PURE__ */ jsxs4("span", { className: styles7.groupLabel, id: labelId, children: [
|
|
254
429
|
label,
|
|
255
|
-
required ? /* @__PURE__ */
|
|
430
|
+
required ? /* @__PURE__ */ jsx7("span", { "aria-hidden": "true", children: " *" }) : null
|
|
256
431
|
] }),
|
|
257
|
-
hint ? /* @__PURE__ */
|
|
258
|
-
/* @__PURE__ */
|
|
432
|
+
hint ? /* @__PURE__ */ jsx7("p", { className: styles7.hint, id: hintId, children: hint }) : null,
|
|
433
|
+
/* @__PURE__ */ jsx7("div", { className: styles7.tablist, role: "tablist", "aria-label": label, children: locales.map((locale) => {
|
|
259
434
|
const selected = locale === activeLocale;
|
|
260
435
|
const tabHasErrors = pointer ? hasErrorsUnder(errors, `${pointer}/${locale}`) : false;
|
|
261
|
-
return /* @__PURE__ */
|
|
436
|
+
return /* @__PURE__ */ jsxs4(
|
|
262
437
|
"button",
|
|
263
438
|
{
|
|
264
439
|
ref: (element) => {
|
|
@@ -270,37 +445,37 @@ function LocaleTabs({
|
|
|
270
445
|
"aria-selected": selected,
|
|
271
446
|
"aria-controls": `${baseId}-panel`,
|
|
272
447
|
tabIndex: selected ? 0 : -1,
|
|
273
|
-
className: `${
|
|
448
|
+
className: `${styles7.tab} ${selected ? styles7.tabActive : ""}`,
|
|
274
449
|
onClick: () => {
|
|
275
450
|
setActive(locale);
|
|
276
451
|
},
|
|
277
452
|
onKeyDown: onTabKeyDown,
|
|
278
453
|
children: [
|
|
279
454
|
format(locale),
|
|
280
|
-
tabHasErrors ? /* @__PURE__ */
|
|
281
|
-
/* @__PURE__ */
|
|
455
|
+
tabHasErrors ? /* @__PURE__ */ jsxs4(Fragment2, { children: [
|
|
456
|
+
/* @__PURE__ */ jsxs4("span", { className: styles7.tabError, "aria-hidden": "true", children: [
|
|
282
457
|
" ",
|
|
283
458
|
"\u25CF"
|
|
284
459
|
] }),
|
|
285
|
-
/* @__PURE__ */
|
|
460
|
+
/* @__PURE__ */ jsx7("span", { className: styles7.srOnly, children: " (has errors)" })
|
|
286
461
|
] }) : null
|
|
287
462
|
]
|
|
288
463
|
},
|
|
289
464
|
locale
|
|
290
465
|
);
|
|
291
466
|
}) }),
|
|
292
|
-
/* @__PURE__ */
|
|
467
|
+
/* @__PURE__ */ jsxs4(
|
|
293
468
|
"div",
|
|
294
469
|
{
|
|
295
470
|
role: "tabpanel",
|
|
296
471
|
id: `${baseId}-panel`,
|
|
297
472
|
"aria-labelledby": `${baseId}-tab-${activeLocale}`,
|
|
298
|
-
className:
|
|
473
|
+
className: styles7.panel,
|
|
299
474
|
children: [
|
|
300
|
-
multiline ? /* @__PURE__ */
|
|
475
|
+
multiline ? /* @__PURE__ */ jsx7(
|
|
301
476
|
"textarea",
|
|
302
477
|
{
|
|
303
|
-
className: `${
|
|
478
|
+
className: `${styles7.control} ${styles7.textarea}`,
|
|
304
479
|
value: text,
|
|
305
480
|
rows: 4,
|
|
306
481
|
"aria-label": controlName,
|
|
@@ -311,10 +486,10 @@ function LocaleTabs({
|
|
|
311
486
|
setText(event.target.value);
|
|
312
487
|
}
|
|
313
488
|
}
|
|
314
|
-
) : /* @__PURE__ */
|
|
489
|
+
) : /* @__PURE__ */ jsx7(
|
|
315
490
|
"input",
|
|
316
491
|
{
|
|
317
|
-
className:
|
|
492
|
+
className: styles7.control,
|
|
318
493
|
type: "text",
|
|
319
494
|
value: text,
|
|
320
495
|
"aria-label": controlName,
|
|
@@ -326,7 +501,7 @@ function LocaleTabs({
|
|
|
326
501
|
}
|
|
327
502
|
}
|
|
328
503
|
),
|
|
329
|
-
hasErrors ? /* @__PURE__ */
|
|
504
|
+
hasErrors ? /* @__PURE__ */ jsx7("ul", { className: styles7.errors, id: errorId, children: shownErrors.map((message, i) => /* @__PURE__ */ jsx7("li", { children: message }, i)) }) : null
|
|
330
505
|
]
|
|
331
506
|
}
|
|
332
507
|
)
|
|
@@ -334,8 +509,8 @@ function LocaleTabs({
|
|
|
334
509
|
}
|
|
335
510
|
|
|
336
511
|
// src/admin/primitives/Repeater.tsx
|
|
337
|
-
import
|
|
338
|
-
import { jsx as
|
|
512
|
+
import styles8 from "../Repeater.module-MWSEKS4G.module.css";
|
|
513
|
+
import { jsx as jsx8, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
339
514
|
function Repeater({
|
|
340
515
|
legend,
|
|
341
516
|
items,
|
|
@@ -367,20 +542,20 @@ function Repeater({
|
|
|
367
542
|
copy.splice(to, 0, moved);
|
|
368
543
|
onChange(copy);
|
|
369
544
|
};
|
|
370
|
-
return /* @__PURE__ */
|
|
371
|
-
/* @__PURE__ */
|
|
372
|
-
items.length === 0 && emptyHint ? /* @__PURE__ */
|
|
373
|
-
/* @__PURE__ */
|
|
545
|
+
return /* @__PURE__ */ jsxs5("fieldset", { className: styles8.fieldset, children: [
|
|
546
|
+
/* @__PURE__ */ jsx8("legend", { className: styles8.legend, children: legend }),
|
|
547
|
+
items.length === 0 && emptyHint ? /* @__PURE__ */ jsx8("p", { className: styles8.empty, children: emptyHint }) : null,
|
|
548
|
+
/* @__PURE__ */ jsx8("ol", { className: styles8.list, children: items.map((item, index) => {
|
|
374
549
|
const caption = itemLabel(item, index);
|
|
375
|
-
return /* @__PURE__ */
|
|
376
|
-
/* @__PURE__ */
|
|
377
|
-
/* @__PURE__ */
|
|
378
|
-
/* @__PURE__ */
|
|
379
|
-
/* @__PURE__ */
|
|
550
|
+
return /* @__PURE__ */ jsx8("li", { className: styles8.item, children: /* @__PURE__ */ jsxs5("div", { role: "group", "aria-label": caption, children: [
|
|
551
|
+
/* @__PURE__ */ jsxs5("div", { className: styles8.itemHeader, children: [
|
|
552
|
+
/* @__PURE__ */ jsx8("span", { className: styles8.itemCaption, children: caption }),
|
|
553
|
+
/* @__PURE__ */ jsxs5("div", { className: styles8.itemActions, children: [
|
|
554
|
+
/* @__PURE__ */ jsx8(
|
|
380
555
|
"button",
|
|
381
556
|
{
|
|
382
557
|
type: "button",
|
|
383
|
-
className:
|
|
558
|
+
className: styles8.iconButton,
|
|
384
559
|
"aria-label": `${moveUpLabel}: ${caption}`,
|
|
385
560
|
disabled: index === 0,
|
|
386
561
|
onClick: () => {
|
|
@@ -389,11 +564,11 @@ function Repeater({
|
|
|
389
564
|
children: "\u2191"
|
|
390
565
|
}
|
|
391
566
|
),
|
|
392
|
-
/* @__PURE__ */
|
|
567
|
+
/* @__PURE__ */ jsx8(
|
|
393
568
|
"button",
|
|
394
569
|
{
|
|
395
570
|
type: "button",
|
|
396
|
-
className:
|
|
571
|
+
className: styles8.iconButton,
|
|
397
572
|
"aria-label": `${moveDownLabel}: ${caption}`,
|
|
398
573
|
disabled: index === items.length - 1,
|
|
399
574
|
onClick: () => {
|
|
@@ -402,11 +577,11 @@ function Repeater({
|
|
|
402
577
|
children: "\u2193"
|
|
403
578
|
}
|
|
404
579
|
),
|
|
405
|
-
/* @__PURE__ */
|
|
580
|
+
/* @__PURE__ */ jsx8(
|
|
406
581
|
"button",
|
|
407
582
|
{
|
|
408
583
|
type: "button",
|
|
409
|
-
className:
|
|
584
|
+
className: styles8.removeButton,
|
|
410
585
|
"aria-label": `${removeLabel}: ${caption}`,
|
|
411
586
|
onClick: () => {
|
|
412
587
|
remove(index);
|
|
@@ -416,7 +591,7 @@ function Repeater({
|
|
|
416
591
|
)
|
|
417
592
|
] })
|
|
418
593
|
] }),
|
|
419
|
-
/* @__PURE__ */
|
|
594
|
+
/* @__PURE__ */ jsx8("div", { className: styles8.itemBody, children: renderItem(
|
|
420
595
|
item,
|
|
421
596
|
(next) => {
|
|
422
597
|
update(index, next);
|
|
@@ -425,11 +600,11 @@ function Repeater({
|
|
|
425
600
|
) })
|
|
426
601
|
] }) }, key(item, index));
|
|
427
602
|
}) }),
|
|
428
|
-
/* @__PURE__ */
|
|
603
|
+
/* @__PURE__ */ jsx8(
|
|
429
604
|
"button",
|
|
430
605
|
{
|
|
431
606
|
type: "button",
|
|
432
|
-
className:
|
|
607
|
+
className: styles8.addButton,
|
|
433
608
|
onClick: () => {
|
|
434
609
|
onChange([...items, createItem()]);
|
|
435
610
|
},
|
|
@@ -439,106 +614,9 @@ function Repeater({
|
|
|
439
614
|
] });
|
|
440
615
|
}
|
|
441
616
|
|
|
442
|
-
// src/admin/admin-labels.ts
|
|
443
|
-
var EN = {
|
|
444
|
-
"app.title": "takuhon admin",
|
|
445
|
-
"toolbar.label": "Editor actions",
|
|
446
|
-
"mode.label": "Editing mode",
|
|
447
|
-
"mode.form": "Form",
|
|
448
|
-
"mode.advanced": "Advanced (JSON)",
|
|
449
|
-
"action.save": "Save",
|
|
450
|
-
"action.reload": "Reload",
|
|
451
|
-
"action.export": "Export",
|
|
452
|
-
"action.import": "Import",
|
|
453
|
-
"action.add": "Add",
|
|
454
|
-
"action.remove": "Remove",
|
|
455
|
-
"action.moveUp": "Move up",
|
|
456
|
-
"action.moveDown": "Move down",
|
|
457
|
-
"status.saving": "Saving\u2026",
|
|
458
|
-
"status.saved": "Saved.",
|
|
459
|
-
"status.loading": "Loading\u2026",
|
|
460
|
-
"status.conflict": "The profile changed on the server since it was loaded. Reload, then reapply the edits.",
|
|
461
|
-
"status.invalid": "Some fields need attention before saving.",
|
|
462
|
-
"status.fixSummary": "Please fix the following:",
|
|
463
|
-
"status.error": "Something went wrong. Please try again.",
|
|
464
|
-
"status.imported": "Imported. Review the fields, then save to apply.",
|
|
465
|
-
"status.importInvalid": "The imported file is not a valid takuhon document.",
|
|
466
|
-
"section.profile": "Profile",
|
|
467
|
-
"section.about": "About",
|
|
468
|
-
"section.links": "Links",
|
|
469
|
-
"section.careers": "Experience",
|
|
470
|
-
"section.projects": "Projects",
|
|
471
|
-
"section.skills": "Skills",
|
|
472
|
-
"section.settings": "Settings",
|
|
473
|
-
"field.displayName": "Display name",
|
|
474
|
-
"field.tagline": "Tagline",
|
|
475
|
-
"field.bio": "Bio",
|
|
476
|
-
"field.avatarUrl": "Avatar URL",
|
|
477
|
-
"field.avatarAlt": "Avatar alternative text",
|
|
478
|
-
"field.location.country": "Country",
|
|
479
|
-
"field.location.region": "Region",
|
|
480
|
-
"field.location.locality": "Locality",
|
|
481
|
-
"field.location.display": "Location (display)",
|
|
482
|
-
"field.link.type": "Type",
|
|
483
|
-
"field.link.url": "URL",
|
|
484
|
-
"field.link.label": "Label",
|
|
485
|
-
"field.link.iconUrl": "Icon URL",
|
|
486
|
-
"field.link.featured": "Featured",
|
|
487
|
-
"field.career.organization": "Organization",
|
|
488
|
-
"field.career.role": "Role",
|
|
489
|
-
"field.career.description": "Description",
|
|
490
|
-
"field.career.startDate": "Start",
|
|
491
|
-
"field.career.endDate": "End",
|
|
492
|
-
"field.career.isCurrent": "Current position",
|
|
493
|
-
"field.career.url": "URL",
|
|
494
|
-
"field.project.title": "Title",
|
|
495
|
-
"field.project.description": "Description",
|
|
496
|
-
"field.project.url": "URL",
|
|
497
|
-
"field.project.tags": "Tags",
|
|
498
|
-
"field.project.highlighted": "Highlighted",
|
|
499
|
-
"field.project.startDate": "Start",
|
|
500
|
-
"field.project.endDate": "End",
|
|
501
|
-
"field.skill.label": "Label",
|
|
502
|
-
"field.skill.category": "Category",
|
|
503
|
-
"field.settings.defaultLocale": "Default locale",
|
|
504
|
-
"field.settings.fallbackLocale": "Fallback locale",
|
|
505
|
-
"field.settings.availableLocales": "Available locales",
|
|
506
|
-
"field.settings.theme": "Theme",
|
|
507
|
-
"field.settings.showPoweredBy": 'Show the "Powered by takuhon" footer',
|
|
508
|
-
"field.settings.enableJsonLd": "Emit Schema.org JSON-LD",
|
|
509
|
-
"field.settings.enableApi": "Expose the public read API",
|
|
510
|
-
"field.settings.enableAnalytics": "Enable first-party analytics",
|
|
511
|
-
"item.link": "Link",
|
|
512
|
-
"item.career": "Position",
|
|
513
|
-
"item.project": "Project",
|
|
514
|
-
"item.skill": "Skill",
|
|
515
|
-
"empty.links": "No links yet.",
|
|
516
|
-
"empty.careers": "No positions yet.",
|
|
517
|
-
"empty.projects": "No projects yet.",
|
|
518
|
-
"empty.skills": "No skills yet.",
|
|
519
|
-
"hint.avatarNoUpload": "Paste an image URL. Uploading image files is not available yet.",
|
|
520
|
-
"hint.month": "Format: YYYY-MM (e.g. 2024-03).",
|
|
521
|
-
"hint.country": "ISO 3166-1 alpha-2 code, e.g. US.",
|
|
522
|
-
"hint.tags": "Comma-separated.",
|
|
523
|
-
"hint.locales": "Comma-separated BCP-47 tags, e.g. en, ja. Drives the language tabs above.",
|
|
524
|
-
"advanced.hint": "Edit the entire document as JSON. Edits apply only while the JSON is valid.",
|
|
525
|
-
"advanced.invalid": "The JSON is not a valid takuhon document:",
|
|
526
|
-
"option.none": "(none)"
|
|
527
|
-
};
|
|
528
|
-
var DICTIONARIES = {
|
|
529
|
-
en: EN
|
|
530
|
-
};
|
|
531
|
-
function getAdminLabel(key, locale = "en") {
|
|
532
|
-
const exact = DICTIONARIES[locale]?.[key];
|
|
533
|
-
if (exact !== void 0) return exact;
|
|
534
|
-
const base = locale.split("-")[0];
|
|
535
|
-
const baseMatch = base ? DICTIONARIES[base]?.[key] : void 0;
|
|
536
|
-
return baseMatch ?? EN[key];
|
|
537
|
-
}
|
|
538
|
-
|
|
539
617
|
// src/admin/sections/ProfileForm.tsx
|
|
540
|
-
import
|
|
541
|
-
import { jsx as
|
|
618
|
+
import styles9 from "../sections.module-ZVBKZHDE.module.css";
|
|
619
|
+
import { jsx as jsx9, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
542
620
|
var POINTER = "/profile";
|
|
543
621
|
function isEmptyRecord(record) {
|
|
544
622
|
return !record || Object.keys(record).length === 0;
|
|
@@ -548,7 +626,8 @@ function ProfileForm({
|
|
|
548
626
|
onChange,
|
|
549
627
|
locales,
|
|
550
628
|
errors = NO_FIELD_ERRORS,
|
|
551
|
-
formatLocale
|
|
629
|
+
formatLocale,
|
|
630
|
+
uploadAsset
|
|
552
631
|
}) {
|
|
553
632
|
const updateAvatar = (patch) => {
|
|
554
633
|
const merged = { url: "", ...value.avatar, ...patch };
|
|
@@ -561,9 +640,9 @@ function ProfileForm({
|
|
|
561
640
|
onChange({ ...value, location: empty ? void 0 : merged });
|
|
562
641
|
};
|
|
563
642
|
const headingId = "admin-section-profile";
|
|
564
|
-
return /* @__PURE__ */
|
|
565
|
-
/* @__PURE__ */
|
|
566
|
-
/* @__PURE__ */
|
|
643
|
+
return /* @__PURE__ */ jsxs6("section", { className: styles9.section, "aria-labelledby": headingId, children: [
|
|
644
|
+
/* @__PURE__ */ jsx9("h2", { className: styles9.heading, id: headingId, children: getAdminLabel("section.profile") }),
|
|
645
|
+
/* @__PURE__ */ jsx9(
|
|
567
646
|
LocaleTabs,
|
|
568
647
|
{
|
|
569
648
|
label: getAdminLabel("field.displayName"),
|
|
@@ -578,7 +657,7 @@ function ProfileForm({
|
|
|
578
657
|
formatLocale
|
|
579
658
|
}
|
|
580
659
|
),
|
|
581
|
-
/* @__PURE__ */
|
|
660
|
+
/* @__PURE__ */ jsx9(
|
|
582
661
|
LocaleTabs,
|
|
583
662
|
{
|
|
584
663
|
label: getAdminLabel("field.tagline"),
|
|
@@ -592,8 +671,8 @@ function ProfileForm({
|
|
|
592
671
|
formatLocale
|
|
593
672
|
}
|
|
594
673
|
),
|
|
595
|
-
/* @__PURE__ */
|
|
596
|
-
/* @__PURE__ */
|
|
674
|
+
/* @__PURE__ */ jsx9("h3", { className: styles9.subheading, children: getAdminLabel("section.about") }),
|
|
675
|
+
/* @__PURE__ */ jsx9(
|
|
597
676
|
LocaleTabs,
|
|
598
677
|
{
|
|
599
678
|
label: getAdminLabel("field.bio"),
|
|
@@ -608,20 +687,20 @@ function ProfileForm({
|
|
|
608
687
|
formatLocale
|
|
609
688
|
}
|
|
610
689
|
),
|
|
611
|
-
/* @__PURE__ */
|
|
612
|
-
|
|
690
|
+
/* @__PURE__ */ jsx9(
|
|
691
|
+
ImageField,
|
|
613
692
|
{
|
|
614
693
|
label: getAdminLabel("field.avatarUrl"),
|
|
615
|
-
type: "url",
|
|
616
694
|
value: value.avatar?.url ?? "",
|
|
617
695
|
onChange: (url) => {
|
|
618
696
|
updateAvatar({ url });
|
|
619
697
|
},
|
|
620
|
-
hint: getAdminLabel("hint.avatarNoUpload"),
|
|
621
|
-
errors: errorsAt(errors, `${POINTER}/avatar/url`)
|
|
698
|
+
hint: getAdminLabel(uploadAsset ? "hint.avatarUpload" : "hint.avatarNoUpload"),
|
|
699
|
+
errors: errorsAt(errors, `${POINTER}/avatar/url`),
|
|
700
|
+
uploadAsset
|
|
622
701
|
}
|
|
623
702
|
),
|
|
624
|
-
/* @__PURE__ */
|
|
703
|
+
/* @__PURE__ */ jsx9(
|
|
625
704
|
LocaleTabs,
|
|
626
705
|
{
|
|
627
706
|
label: getAdminLabel("field.avatarAlt"),
|
|
@@ -635,7 +714,7 @@ function ProfileForm({
|
|
|
635
714
|
formatLocale
|
|
636
715
|
}
|
|
637
716
|
),
|
|
638
|
-
/* @__PURE__ */
|
|
717
|
+
/* @__PURE__ */ jsx9(
|
|
639
718
|
TextField,
|
|
640
719
|
{
|
|
641
720
|
label: getAdminLabel("field.location.country"),
|
|
@@ -647,7 +726,7 @@ function ProfileForm({
|
|
|
647
726
|
errors: errorsAt(errors, `${POINTER}/location/country`)
|
|
648
727
|
}
|
|
649
728
|
),
|
|
650
|
-
/* @__PURE__ */
|
|
729
|
+
/* @__PURE__ */ jsx9(
|
|
651
730
|
TextField,
|
|
652
731
|
{
|
|
653
732
|
label: getAdminLabel("field.location.region"),
|
|
@@ -658,7 +737,7 @@ function ProfileForm({
|
|
|
658
737
|
errors: errorsAt(errors, `${POINTER}/location/region`)
|
|
659
738
|
}
|
|
660
739
|
),
|
|
661
|
-
/* @__PURE__ */
|
|
740
|
+
/* @__PURE__ */ jsx9(
|
|
662
741
|
LocaleTabs,
|
|
663
742
|
{
|
|
664
743
|
label: getAdminLabel("field.location.locality"),
|
|
@@ -685,7 +764,7 @@ function makeId(prefix, taken) {
|
|
|
685
764
|
}
|
|
686
765
|
|
|
687
766
|
// src/admin/sections/LinksForm.tsx
|
|
688
|
-
import { Fragment as
|
|
767
|
+
import { Fragment as Fragment3, jsx as jsx10, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
689
768
|
var LINK_TYPES = [
|
|
690
769
|
"website",
|
|
691
770
|
"blog",
|
|
@@ -737,7 +816,7 @@ function LinksForm({
|
|
|
737
816
|
errors = NO_FIELD_ERRORS,
|
|
738
817
|
formatLocale
|
|
739
818
|
}) {
|
|
740
|
-
return /* @__PURE__ */
|
|
819
|
+
return /* @__PURE__ */ jsx10(
|
|
741
820
|
Repeater,
|
|
742
821
|
{
|
|
743
822
|
legend: getAdminLabel("section.links"),
|
|
@@ -760,8 +839,8 @@ function LinksForm({
|
|
|
760
839
|
emptyHint: getAdminLabel("empty.links"),
|
|
761
840
|
renderItem: (link, update, index) => {
|
|
762
841
|
const at = `/links/${String(index)}`;
|
|
763
|
-
return /* @__PURE__ */
|
|
764
|
-
/* @__PURE__ */
|
|
842
|
+
return /* @__PURE__ */ jsxs7(Fragment3, { children: [
|
|
843
|
+
/* @__PURE__ */ jsx10(
|
|
765
844
|
SelectField,
|
|
766
845
|
{
|
|
767
846
|
label: getAdminLabel("field.link.type"),
|
|
@@ -773,7 +852,7 @@ function LinksForm({
|
|
|
773
852
|
errors: errorsAt(errors, `${at}/type`)
|
|
774
853
|
}
|
|
775
854
|
),
|
|
776
|
-
/* @__PURE__ */
|
|
855
|
+
/* @__PURE__ */ jsx10(
|
|
777
856
|
TextField,
|
|
778
857
|
{
|
|
779
858
|
label: getAdminLabel("field.link.url"),
|
|
@@ -786,7 +865,7 @@ function LinksForm({
|
|
|
786
865
|
errors: errorsAt(errors, `${at}/url`)
|
|
787
866
|
}
|
|
788
867
|
),
|
|
789
|
-
/* @__PURE__ */
|
|
868
|
+
/* @__PURE__ */ jsx10(
|
|
790
869
|
LocaleTabs,
|
|
791
870
|
{
|
|
792
871
|
label: getAdminLabel("field.link.label"),
|
|
@@ -800,7 +879,7 @@ function LinksForm({
|
|
|
800
879
|
formatLocale
|
|
801
880
|
}
|
|
802
881
|
),
|
|
803
|
-
/* @__PURE__ */
|
|
882
|
+
/* @__PURE__ */ jsx10(
|
|
804
883
|
TextField,
|
|
805
884
|
{
|
|
806
885
|
label: getAdminLabel("field.link.iconUrl"),
|
|
@@ -813,7 +892,7 @@ function LinksForm({
|
|
|
813
892
|
errors: errorsAt(errors, `${at}/iconUrl`)
|
|
814
893
|
}
|
|
815
894
|
),
|
|
816
|
-
/* @__PURE__ */
|
|
895
|
+
/* @__PURE__ */ jsx10(
|
|
817
896
|
CheckboxField,
|
|
818
897
|
{
|
|
819
898
|
label: getAdminLabel("field.link.featured"),
|
|
@@ -840,7 +919,7 @@ function firstLocalized(record, locales) {
|
|
|
840
919
|
}
|
|
841
920
|
|
|
842
921
|
// src/admin/sections/CareersForm.tsx
|
|
843
|
-
import { Fragment as
|
|
922
|
+
import { Fragment as Fragment4, jsx as jsx11, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
844
923
|
function CareersForm({
|
|
845
924
|
value,
|
|
846
925
|
onChange,
|
|
@@ -848,7 +927,7 @@ function CareersForm({
|
|
|
848
927
|
errors = NO_FIELD_ERRORS,
|
|
849
928
|
formatLocale
|
|
850
929
|
}) {
|
|
851
|
-
return /* @__PURE__ */
|
|
930
|
+
return /* @__PURE__ */ jsx11(
|
|
852
931
|
Repeater,
|
|
853
932
|
{
|
|
854
933
|
legend: getAdminLabel("section.careers"),
|
|
@@ -872,8 +951,8 @@ function CareersForm({
|
|
|
872
951
|
emptyHint: getAdminLabel("empty.careers"),
|
|
873
952
|
renderItem: (career, update, index) => {
|
|
874
953
|
const at = `/careers/${String(index)}`;
|
|
875
|
-
return /* @__PURE__ */
|
|
876
|
-
/* @__PURE__ */
|
|
954
|
+
return /* @__PURE__ */ jsxs8(Fragment4, { children: [
|
|
955
|
+
/* @__PURE__ */ jsx11(
|
|
877
956
|
LocaleTabs,
|
|
878
957
|
{
|
|
879
958
|
label: getAdminLabel("field.career.organization"),
|
|
@@ -888,7 +967,7 @@ function CareersForm({
|
|
|
888
967
|
formatLocale
|
|
889
968
|
}
|
|
890
969
|
),
|
|
891
|
-
/* @__PURE__ */
|
|
970
|
+
/* @__PURE__ */ jsx11(
|
|
892
971
|
LocaleTabs,
|
|
893
972
|
{
|
|
894
973
|
label: getAdminLabel("field.career.role"),
|
|
@@ -903,7 +982,7 @@ function CareersForm({
|
|
|
903
982
|
formatLocale
|
|
904
983
|
}
|
|
905
984
|
),
|
|
906
|
-
/* @__PURE__ */
|
|
985
|
+
/* @__PURE__ */ jsx11(
|
|
907
986
|
TextField,
|
|
908
987
|
{
|
|
909
988
|
label: getAdminLabel("field.career.startDate"),
|
|
@@ -917,7 +996,7 @@ function CareersForm({
|
|
|
917
996
|
errors: errorsAt(errors, `${at}/startDate`)
|
|
918
997
|
}
|
|
919
998
|
),
|
|
920
|
-
/* @__PURE__ */
|
|
999
|
+
/* @__PURE__ */ jsx11(
|
|
921
1000
|
TextField,
|
|
922
1001
|
{
|
|
923
1002
|
label: getAdminLabel("field.career.endDate"),
|
|
@@ -930,7 +1009,7 @@ function CareersForm({
|
|
|
930
1009
|
errors: errorsAt(errors, `${at}/endDate`)
|
|
931
1010
|
}
|
|
932
1011
|
),
|
|
933
|
-
/* @__PURE__ */
|
|
1012
|
+
/* @__PURE__ */ jsx11(
|
|
934
1013
|
CheckboxField,
|
|
935
1014
|
{
|
|
936
1015
|
label: getAdminLabel("field.career.isCurrent"),
|
|
@@ -940,7 +1019,7 @@ function CareersForm({
|
|
|
940
1019
|
}
|
|
941
1020
|
}
|
|
942
1021
|
),
|
|
943
|
-
/* @__PURE__ */
|
|
1022
|
+
/* @__PURE__ */ jsx11(
|
|
944
1023
|
LocaleTabs,
|
|
945
1024
|
{
|
|
946
1025
|
label: getAdminLabel("field.career.description"),
|
|
@@ -955,7 +1034,7 @@ function CareersForm({
|
|
|
955
1034
|
formatLocale
|
|
956
1035
|
}
|
|
957
1036
|
),
|
|
958
|
-
/* @__PURE__ */
|
|
1037
|
+
/* @__PURE__ */ jsx11(
|
|
959
1038
|
TextField,
|
|
960
1039
|
{
|
|
961
1040
|
label: getAdminLabel("field.career.url"),
|
|
@@ -974,7 +1053,7 @@ function CareersForm({
|
|
|
974
1053
|
}
|
|
975
1054
|
|
|
976
1055
|
// src/admin/sections/ProjectsForm.tsx
|
|
977
|
-
import { Fragment as
|
|
1056
|
+
import { Fragment as Fragment5, jsx as jsx12, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
978
1057
|
function parseTags(input) {
|
|
979
1058
|
const tags = input.split(",").map((tag) => tag.trim()).filter((tag) => tag !== "");
|
|
980
1059
|
return tags.length > 0 ? tags : void 0;
|
|
@@ -986,7 +1065,7 @@ function ProjectsForm({
|
|
|
986
1065
|
errors = NO_FIELD_ERRORS,
|
|
987
1066
|
formatLocale
|
|
988
1067
|
}) {
|
|
989
|
-
return /* @__PURE__ */
|
|
1068
|
+
return /* @__PURE__ */ jsx12(
|
|
990
1069
|
Repeater,
|
|
991
1070
|
{
|
|
992
1071
|
legend: getAdminLabel("section.projects"),
|
|
@@ -1008,8 +1087,8 @@ function ProjectsForm({
|
|
|
1008
1087
|
emptyHint: getAdminLabel("empty.projects"),
|
|
1009
1088
|
renderItem: (project, update, index) => {
|
|
1010
1089
|
const at = `/projects/${String(index)}`;
|
|
1011
|
-
return /* @__PURE__ */
|
|
1012
|
-
/* @__PURE__ */
|
|
1090
|
+
return /* @__PURE__ */ jsxs9(Fragment5, { children: [
|
|
1091
|
+
/* @__PURE__ */ jsx12(
|
|
1013
1092
|
LocaleTabs,
|
|
1014
1093
|
{
|
|
1015
1094
|
label: getAdminLabel("field.project.title"),
|
|
@@ -1024,7 +1103,7 @@ function ProjectsForm({
|
|
|
1024
1103
|
formatLocale
|
|
1025
1104
|
}
|
|
1026
1105
|
),
|
|
1027
|
-
/* @__PURE__ */
|
|
1106
|
+
/* @__PURE__ */ jsx12(
|
|
1028
1107
|
LocaleTabs,
|
|
1029
1108
|
{
|
|
1030
1109
|
label: getAdminLabel("field.project.description"),
|
|
@@ -1039,7 +1118,7 @@ function ProjectsForm({
|
|
|
1039
1118
|
formatLocale
|
|
1040
1119
|
}
|
|
1041
1120
|
),
|
|
1042
|
-
/* @__PURE__ */
|
|
1121
|
+
/* @__PURE__ */ jsx12(
|
|
1043
1122
|
TextField,
|
|
1044
1123
|
{
|
|
1045
1124
|
label: getAdminLabel("field.project.url"),
|
|
@@ -1051,7 +1130,7 @@ function ProjectsForm({
|
|
|
1051
1130
|
errors: errorsAt(errors, `${at}/url`)
|
|
1052
1131
|
}
|
|
1053
1132
|
),
|
|
1054
|
-
/* @__PURE__ */
|
|
1133
|
+
/* @__PURE__ */ jsx12(
|
|
1055
1134
|
TextField,
|
|
1056
1135
|
{
|
|
1057
1136
|
label: getAdminLabel("field.project.tags"),
|
|
@@ -1063,7 +1142,7 @@ function ProjectsForm({
|
|
|
1063
1142
|
errors: collectErrorsUnder(errors, `${at}/tags`)
|
|
1064
1143
|
}
|
|
1065
1144
|
),
|
|
1066
|
-
/* @__PURE__ */
|
|
1145
|
+
/* @__PURE__ */ jsx12(
|
|
1067
1146
|
TextField,
|
|
1068
1147
|
{
|
|
1069
1148
|
label: getAdminLabel("field.project.startDate"),
|
|
@@ -1076,7 +1155,7 @@ function ProjectsForm({
|
|
|
1076
1155
|
errors: errorsAt(errors, `${at}/startDate`)
|
|
1077
1156
|
}
|
|
1078
1157
|
),
|
|
1079
|
-
/* @__PURE__ */
|
|
1158
|
+
/* @__PURE__ */ jsx12(
|
|
1080
1159
|
TextField,
|
|
1081
1160
|
{
|
|
1082
1161
|
label: getAdminLabel("field.project.endDate"),
|
|
@@ -1089,7 +1168,7 @@ function ProjectsForm({
|
|
|
1089
1168
|
errors: errorsAt(errors, `${at}/endDate`)
|
|
1090
1169
|
}
|
|
1091
1170
|
),
|
|
1092
|
-
/* @__PURE__ */
|
|
1171
|
+
/* @__PURE__ */ jsx12(
|
|
1093
1172
|
CheckboxField,
|
|
1094
1173
|
{
|
|
1095
1174
|
label: getAdminLabel("field.project.highlighted"),
|
|
@@ -1106,13 +1185,13 @@ function ProjectsForm({
|
|
|
1106
1185
|
}
|
|
1107
1186
|
|
|
1108
1187
|
// src/admin/sections/SkillsForm.tsx
|
|
1109
|
-
import { Fragment as
|
|
1188
|
+
import { Fragment as Fragment6, jsx as jsx13, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
1110
1189
|
function SkillsForm({
|
|
1111
1190
|
value,
|
|
1112
1191
|
onChange,
|
|
1113
1192
|
errors = NO_FIELD_ERRORS
|
|
1114
1193
|
}) {
|
|
1115
|
-
return /* @__PURE__ */
|
|
1194
|
+
return /* @__PURE__ */ jsx13(
|
|
1116
1195
|
Repeater,
|
|
1117
1196
|
{
|
|
1118
1197
|
legend: getAdminLabel("section.skills"),
|
|
@@ -1134,8 +1213,8 @@ function SkillsForm({
|
|
|
1134
1213
|
emptyHint: getAdminLabel("empty.skills"),
|
|
1135
1214
|
renderItem: (skill, update, index) => {
|
|
1136
1215
|
const at = `/skills/${String(index)}`;
|
|
1137
|
-
return /* @__PURE__ */
|
|
1138
|
-
/* @__PURE__ */
|
|
1216
|
+
return /* @__PURE__ */ jsxs10(Fragment6, { children: [
|
|
1217
|
+
/* @__PURE__ */ jsx13(
|
|
1139
1218
|
TextField,
|
|
1140
1219
|
{
|
|
1141
1220
|
label: getAdminLabel("field.skill.label"),
|
|
@@ -1147,7 +1226,7 @@ function SkillsForm({
|
|
|
1147
1226
|
errors: errorsAt(errors, `${at}/label`)
|
|
1148
1227
|
}
|
|
1149
1228
|
),
|
|
1150
|
-
/* @__PURE__ */
|
|
1229
|
+
/* @__PURE__ */ jsx13(
|
|
1151
1230
|
TextField,
|
|
1152
1231
|
{
|
|
1153
1232
|
label: getAdminLabel("field.skill.category"),
|
|
@@ -1165,8 +1244,8 @@ function SkillsForm({
|
|
|
1165
1244
|
}
|
|
1166
1245
|
|
|
1167
1246
|
// src/admin/sections/SettingsForm.tsx
|
|
1168
|
-
import
|
|
1169
|
-
import { jsx as
|
|
1247
|
+
import styles10 from "../sections.module-ZVBKZHDE.module.css";
|
|
1248
|
+
import { jsx as jsx14, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
1170
1249
|
function parseLocales(input) {
|
|
1171
1250
|
return input.split(",").map((tag) => tag.trim()).filter((tag) => tag !== "");
|
|
1172
1251
|
}
|
|
@@ -1182,9 +1261,9 @@ function SettingsForm({
|
|
|
1182
1261
|
label: format(locale)
|
|
1183
1262
|
}));
|
|
1184
1263
|
const headingId = "admin-section-settings";
|
|
1185
|
-
return /* @__PURE__ */
|
|
1186
|
-
/* @__PURE__ */
|
|
1187
|
-
/* @__PURE__ */
|
|
1264
|
+
return /* @__PURE__ */ jsxs11("section", { className: styles10.section, "aria-labelledby": headingId, children: [
|
|
1265
|
+
/* @__PURE__ */ jsx14("h2", { className: styles10.heading, id: headingId, children: getAdminLabel("section.settings") }),
|
|
1266
|
+
/* @__PURE__ */ jsx14(
|
|
1188
1267
|
TextField,
|
|
1189
1268
|
{
|
|
1190
1269
|
label: getAdminLabel("field.settings.availableLocales"),
|
|
@@ -1197,7 +1276,7 @@ function SettingsForm({
|
|
|
1197
1276
|
errors: collectErrorsUnder(errors, "/settings/availableLocales")
|
|
1198
1277
|
}
|
|
1199
1278
|
),
|
|
1200
|
-
/* @__PURE__ */
|
|
1279
|
+
/* @__PURE__ */ jsx14(
|
|
1201
1280
|
SelectField,
|
|
1202
1281
|
{
|
|
1203
1282
|
label: getAdminLabel("field.settings.defaultLocale"),
|
|
@@ -1210,7 +1289,7 @@ function SettingsForm({
|
|
|
1210
1289
|
errors: errorsAt(errors, "/settings/defaultLocale")
|
|
1211
1290
|
}
|
|
1212
1291
|
),
|
|
1213
|
-
/* @__PURE__ */
|
|
1292
|
+
/* @__PURE__ */ jsx14(
|
|
1214
1293
|
SelectField,
|
|
1215
1294
|
{
|
|
1216
1295
|
label: getAdminLabel("field.settings.fallbackLocale"),
|
|
@@ -1222,7 +1301,7 @@ function SettingsForm({
|
|
|
1222
1301
|
errors: errorsAt(errors, "/settings/fallbackLocale")
|
|
1223
1302
|
}
|
|
1224
1303
|
),
|
|
1225
|
-
/* @__PURE__ */
|
|
1304
|
+
/* @__PURE__ */ jsx14(
|
|
1226
1305
|
TextField,
|
|
1227
1306
|
{
|
|
1228
1307
|
label: getAdminLabel("field.settings.theme"),
|
|
@@ -1233,7 +1312,7 @@ function SettingsForm({
|
|
|
1233
1312
|
errors: errorsAt(errors, "/settings/theme")
|
|
1234
1313
|
}
|
|
1235
1314
|
),
|
|
1236
|
-
/* @__PURE__ */
|
|
1315
|
+
/* @__PURE__ */ jsx14(
|
|
1237
1316
|
CheckboxField,
|
|
1238
1317
|
{
|
|
1239
1318
|
label: getAdminLabel("field.settings.showPoweredBy"),
|
|
@@ -1243,7 +1322,7 @@ function SettingsForm({
|
|
|
1243
1322
|
}
|
|
1244
1323
|
}
|
|
1245
1324
|
),
|
|
1246
|
-
/* @__PURE__ */
|
|
1325
|
+
/* @__PURE__ */ jsx14(
|
|
1247
1326
|
CheckboxField,
|
|
1248
1327
|
{
|
|
1249
1328
|
label: getAdminLabel("field.settings.enableJsonLd"),
|
|
@@ -1253,7 +1332,7 @@ function SettingsForm({
|
|
|
1253
1332
|
}
|
|
1254
1333
|
}
|
|
1255
1334
|
),
|
|
1256
|
-
/* @__PURE__ */
|
|
1335
|
+
/* @__PURE__ */ jsx14(
|
|
1257
1336
|
CheckboxField,
|
|
1258
1337
|
{
|
|
1259
1338
|
label: getAdminLabel("field.settings.enableApi"),
|
|
@@ -1263,7 +1342,7 @@ function SettingsForm({
|
|
|
1263
1342
|
}
|
|
1264
1343
|
}
|
|
1265
1344
|
),
|
|
1266
|
-
/* @__PURE__ */
|
|
1345
|
+
/* @__PURE__ */ jsx14(
|
|
1267
1346
|
CheckboxField,
|
|
1268
1347
|
{
|
|
1269
1348
|
label: getAdminLabel("field.settings.enableAnalytics"),
|
|
@@ -1278,15 +1357,15 @@ function SettingsForm({
|
|
|
1278
1357
|
|
|
1279
1358
|
// src/admin/RawJsonEditor.tsx
|
|
1280
1359
|
import { validate } from "@takuhon/core";
|
|
1281
|
-
import { useId as
|
|
1282
|
-
import
|
|
1283
|
-
import { jsx as
|
|
1360
|
+
import { useId as useId5, useState as useState3 } from "react";
|
|
1361
|
+
import styles11 from "../RawJsonEditor.module-NGGM3IBY.module.css";
|
|
1362
|
+
import { jsx as jsx15, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
1284
1363
|
var MAX_SHOWN_PROBLEMS = 50;
|
|
1285
1364
|
function RawJsonEditor({ value, onChange }) {
|
|
1286
|
-
const [text, setText] =
|
|
1287
|
-
const [problems, setProblems] =
|
|
1288
|
-
const labelId =
|
|
1289
|
-
const errorId =
|
|
1365
|
+
const [text, setText] = useState3(() => JSON.stringify(value, null, 2));
|
|
1366
|
+
const [problems, setProblems] = useState3([]);
|
|
1367
|
+
const labelId = useId5();
|
|
1368
|
+
const errorId = useId5();
|
|
1290
1369
|
const apply = (next) => {
|
|
1291
1370
|
setText(next);
|
|
1292
1371
|
let parsed;
|
|
@@ -1307,13 +1386,13 @@ function RawJsonEditor({ value, onChange }) {
|
|
|
1307
1386
|
onChange(result.data);
|
|
1308
1387
|
};
|
|
1309
1388
|
const hasProblems = problems.length > 0;
|
|
1310
|
-
return /* @__PURE__ */
|
|
1311
|
-
/* @__PURE__ */
|
|
1312
|
-
/* @__PURE__ */
|
|
1313
|
-
/* @__PURE__ */
|
|
1389
|
+
return /* @__PURE__ */ jsxs12("section", { className: styles11.wrapper, "aria-labelledby": labelId, children: [
|
|
1390
|
+
/* @__PURE__ */ jsx15("h2", { className: styles11.heading, id: labelId, children: getAdminLabel("mode.advanced") }),
|
|
1391
|
+
/* @__PURE__ */ jsx15("p", { className: styles11.hint, children: getAdminLabel("advanced.hint") }),
|
|
1392
|
+
/* @__PURE__ */ jsx15(
|
|
1314
1393
|
"textarea",
|
|
1315
1394
|
{
|
|
1316
|
-
className:
|
|
1395
|
+
className: styles11.textarea,
|
|
1317
1396
|
value: text,
|
|
1318
1397
|
spellCheck: false,
|
|
1319
1398
|
"aria-label": getAdminLabel("mode.advanced"),
|
|
@@ -1324,33 +1403,34 @@ function RawJsonEditor({ value, onChange }) {
|
|
|
1324
1403
|
}
|
|
1325
1404
|
}
|
|
1326
1405
|
),
|
|
1327
|
-
hasProblems ? /* @__PURE__ */
|
|
1328
|
-
/* @__PURE__ */
|
|
1329
|
-
/* @__PURE__ */
|
|
1406
|
+
hasProblems ? /* @__PURE__ */ jsxs12("div", { className: styles11.problems, id: errorId, role: "alert", children: [
|
|
1407
|
+
/* @__PURE__ */ jsx15("p", { className: styles11.problemsTitle, children: getAdminLabel("advanced.invalid") }),
|
|
1408
|
+
/* @__PURE__ */ jsx15("ul", { children: problems.map((problem, i) => /* @__PURE__ */ jsx15("li", { children: problem }, i)) })
|
|
1330
1409
|
] }) : null
|
|
1331
1410
|
] });
|
|
1332
1411
|
}
|
|
1333
1412
|
|
|
1334
1413
|
// src/admin/AdminEditor.tsx
|
|
1335
1414
|
import { validate as validate2 } from "@takuhon/core";
|
|
1336
|
-
import { useRef as
|
|
1337
|
-
import
|
|
1338
|
-
import { jsx as
|
|
1415
|
+
import { useRef as useRef3, useState as useState4 } from "react";
|
|
1416
|
+
import styles12 from "../AdminEditor.module-ABYQXFN4.module.css";
|
|
1417
|
+
import { jsx as jsx16, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
1339
1418
|
function AdminEditor({
|
|
1340
1419
|
initialDocument,
|
|
1341
1420
|
onSave,
|
|
1342
1421
|
onReload,
|
|
1343
1422
|
onExport,
|
|
1344
1423
|
onImport,
|
|
1345
|
-
formatLocale
|
|
1424
|
+
formatLocale,
|
|
1425
|
+
uploadAsset
|
|
1346
1426
|
}) {
|
|
1347
|
-
const [draft, setDraft] =
|
|
1348
|
-
const [mode, setMode] =
|
|
1349
|
-
const [errors, setErrors] =
|
|
1350
|
-
const [status, setStatus] =
|
|
1351
|
-
const [busy, setBusy] =
|
|
1352
|
-
const [loadGen, setLoadGen] =
|
|
1353
|
-
const intentRef =
|
|
1427
|
+
const [draft, setDraft] = useState4(initialDocument);
|
|
1428
|
+
const [mode, setMode] = useState4("form");
|
|
1429
|
+
const [errors, setErrors] = useState4(NO_FIELD_ERRORS);
|
|
1430
|
+
const [status, setStatus] = useState4(null);
|
|
1431
|
+
const [busy, setBusy] = useState4(false);
|
|
1432
|
+
const [loadGen, setLoadGen] = useState4(0);
|
|
1433
|
+
const intentRef = useRef3(0);
|
|
1354
1434
|
const locales = draft.settings.availableLocales;
|
|
1355
1435
|
const updateDraft = (next) => {
|
|
1356
1436
|
intentRef.current += 1;
|
|
@@ -1437,14 +1517,14 @@ function AdminEditor({
|
|
|
1437
1517
|
const errorEntries = [...errors].flatMap(
|
|
1438
1518
|
([pointer, messages]) => messages.map((message) => ({ pointer, message }))
|
|
1439
1519
|
);
|
|
1440
|
-
return /* @__PURE__ */
|
|
1441
|
-
/* @__PURE__ */
|
|
1442
|
-
/* @__PURE__ */
|
|
1443
|
-
/* @__PURE__ */
|
|
1520
|
+
return /* @__PURE__ */ jsxs13("div", { className: styles12.editor, children: [
|
|
1521
|
+
/* @__PURE__ */ jsxs13("div", { className: styles12.toolbar, role: "toolbar", "aria-label": getAdminLabel("toolbar.label"), children: [
|
|
1522
|
+
/* @__PURE__ */ jsxs13("div", { className: styles12.modes, role: "group", "aria-label": getAdminLabel("mode.label"), children: [
|
|
1523
|
+
/* @__PURE__ */ jsx16(
|
|
1444
1524
|
"button",
|
|
1445
1525
|
{
|
|
1446
1526
|
type: "button",
|
|
1447
|
-
className: `${
|
|
1527
|
+
className: `${styles12.modeButton} ${mode === "form" ? styles12.modeActive : ""}`,
|
|
1448
1528
|
"aria-pressed": mode === "form",
|
|
1449
1529
|
onClick: () => {
|
|
1450
1530
|
setMode("form");
|
|
@@ -1452,11 +1532,11 @@ function AdminEditor({
|
|
|
1452
1532
|
children: getAdminLabel("mode.form")
|
|
1453
1533
|
}
|
|
1454
1534
|
),
|
|
1455
|
-
/* @__PURE__ */
|
|
1535
|
+
/* @__PURE__ */ jsx16(
|
|
1456
1536
|
"button",
|
|
1457
1537
|
{
|
|
1458
1538
|
type: "button",
|
|
1459
|
-
className: `${
|
|
1539
|
+
className: `${styles12.modeButton} ${mode === "advanced" ? styles12.modeActive : ""}`,
|
|
1460
1540
|
"aria-pressed": mode === "advanced",
|
|
1461
1541
|
onClick: () => {
|
|
1462
1542
|
setMode("advanced");
|
|
@@ -1465,12 +1545,12 @@ function AdminEditor({
|
|
|
1465
1545
|
}
|
|
1466
1546
|
)
|
|
1467
1547
|
] }),
|
|
1468
|
-
/* @__PURE__ */
|
|
1469
|
-
/* @__PURE__ */
|
|
1548
|
+
/* @__PURE__ */ jsxs13("div", { className: styles12.actions, children: [
|
|
1549
|
+
/* @__PURE__ */ jsx16(
|
|
1470
1550
|
"button",
|
|
1471
1551
|
{
|
|
1472
1552
|
type: "button",
|
|
1473
|
-
className:
|
|
1553
|
+
className: styles12.primary,
|
|
1474
1554
|
disabled: busy,
|
|
1475
1555
|
onClick: () => {
|
|
1476
1556
|
void handleSave();
|
|
@@ -1478,11 +1558,11 @@ function AdminEditor({
|
|
|
1478
1558
|
children: getAdminLabel("action.save")
|
|
1479
1559
|
}
|
|
1480
1560
|
),
|
|
1481
|
-
onReload ? /* @__PURE__ */
|
|
1561
|
+
onReload ? /* @__PURE__ */ jsx16(
|
|
1482
1562
|
"button",
|
|
1483
1563
|
{
|
|
1484
1564
|
type: "button",
|
|
1485
|
-
className:
|
|
1565
|
+
className: styles12.secondary,
|
|
1486
1566
|
disabled: busy,
|
|
1487
1567
|
onClick: () => {
|
|
1488
1568
|
void handleReload();
|
|
@@ -1490,22 +1570,22 @@ function AdminEditor({
|
|
|
1490
1570
|
children: getAdminLabel("action.reload")
|
|
1491
1571
|
}
|
|
1492
1572
|
) : null,
|
|
1493
|
-
onExport ? /* @__PURE__ */
|
|
1573
|
+
onExport ? /* @__PURE__ */ jsx16(
|
|
1494
1574
|
"button",
|
|
1495
1575
|
{
|
|
1496
1576
|
type: "button",
|
|
1497
|
-
className:
|
|
1577
|
+
className: styles12.secondary,
|
|
1498
1578
|
onClick: () => {
|
|
1499
1579
|
onExport(draft);
|
|
1500
1580
|
},
|
|
1501
1581
|
children: getAdminLabel("action.export")
|
|
1502
1582
|
}
|
|
1503
1583
|
) : null,
|
|
1504
|
-
onImport ? /* @__PURE__ */
|
|
1584
|
+
onImport ? /* @__PURE__ */ jsx16(
|
|
1505
1585
|
"button",
|
|
1506
1586
|
{
|
|
1507
1587
|
type: "button",
|
|
1508
|
-
className:
|
|
1588
|
+
className: styles12.secondary,
|
|
1509
1589
|
disabled: busy,
|
|
1510
1590
|
onClick: () => {
|
|
1511
1591
|
void handleImport();
|
|
@@ -1515,13 +1595,13 @@ function AdminEditor({
|
|
|
1515
1595
|
) : null
|
|
1516
1596
|
] })
|
|
1517
1597
|
] }),
|
|
1518
|
-
/* @__PURE__ */
|
|
1519
|
-
errorEntries.length > 0 ? /* @__PURE__ */
|
|
1520
|
-
/* @__PURE__ */
|
|
1521
|
-
/* @__PURE__ */
|
|
1598
|
+
/* @__PURE__ */ jsx16("p", { className: styles12.status, role: "status", "aria-live": "polite", "data-tone": status?.tone, children: status?.message ?? "" }),
|
|
1599
|
+
errorEntries.length > 0 ? /* @__PURE__ */ jsxs13("section", { className: styles12.summary, "aria-labelledby": "admin-error-summary", children: [
|
|
1600
|
+
/* @__PURE__ */ jsx16("h2", { className: styles12.summaryHeading, id: "admin-error-summary", children: getAdminLabel("status.fixSummary") }),
|
|
1601
|
+
/* @__PURE__ */ jsx16("ul", { children: errorEntries.map((entry, i) => /* @__PURE__ */ jsx16("li", { children: entry.pointer === "" ? entry.message : `${entry.pointer.replace(/^\//, "")}: ${entry.message}` }, i)) })
|
|
1522
1602
|
] }) : null,
|
|
1523
|
-
mode === "form" ? /* @__PURE__ */
|
|
1524
|
-
/* @__PURE__ */
|
|
1603
|
+
mode === "form" ? /* @__PURE__ */ jsxs13("div", { className: styles12.sections, children: [
|
|
1604
|
+
/* @__PURE__ */ jsx16(
|
|
1525
1605
|
ProfileForm,
|
|
1526
1606
|
{
|
|
1527
1607
|
value: draft.profile,
|
|
@@ -1530,10 +1610,11 @@ function AdminEditor({
|
|
|
1530
1610
|
},
|
|
1531
1611
|
locales,
|
|
1532
1612
|
errors,
|
|
1533
|
-
formatLocale
|
|
1613
|
+
formatLocale,
|
|
1614
|
+
uploadAsset
|
|
1534
1615
|
}
|
|
1535
1616
|
),
|
|
1536
|
-
/* @__PURE__ */
|
|
1617
|
+
/* @__PURE__ */ jsx16(
|
|
1537
1618
|
LinksForm,
|
|
1538
1619
|
{
|
|
1539
1620
|
value: draft.links,
|
|
@@ -1545,7 +1626,7 @@ function AdminEditor({
|
|
|
1545
1626
|
formatLocale
|
|
1546
1627
|
}
|
|
1547
1628
|
),
|
|
1548
|
-
/* @__PURE__ */
|
|
1629
|
+
/* @__PURE__ */ jsx16(
|
|
1549
1630
|
CareersForm,
|
|
1550
1631
|
{
|
|
1551
1632
|
value: draft.careers,
|
|
@@ -1557,7 +1638,7 @@ function AdminEditor({
|
|
|
1557
1638
|
formatLocale
|
|
1558
1639
|
}
|
|
1559
1640
|
),
|
|
1560
|
-
/* @__PURE__ */
|
|
1641
|
+
/* @__PURE__ */ jsx16(
|
|
1561
1642
|
ProjectsForm,
|
|
1562
1643
|
{
|
|
1563
1644
|
value: draft.projects,
|
|
@@ -1569,7 +1650,7 @@ function AdminEditor({
|
|
|
1569
1650
|
formatLocale
|
|
1570
1651
|
}
|
|
1571
1652
|
),
|
|
1572
|
-
/* @__PURE__ */
|
|
1653
|
+
/* @__PURE__ */ jsx16(
|
|
1573
1654
|
SkillsForm,
|
|
1574
1655
|
{
|
|
1575
1656
|
value: draft.skills,
|
|
@@ -1579,7 +1660,7 @@ function AdminEditor({
|
|
|
1579
1660
|
errors
|
|
1580
1661
|
}
|
|
1581
1662
|
),
|
|
1582
|
-
/* @__PURE__ */
|
|
1663
|
+
/* @__PURE__ */ jsx16(
|
|
1583
1664
|
SettingsForm,
|
|
1584
1665
|
{
|
|
1585
1666
|
value: draft.settings,
|
|
@@ -1590,7 +1671,7 @@ function AdminEditor({
|
|
|
1590
1671
|
formatLocale
|
|
1591
1672
|
}
|
|
1592
1673
|
)
|
|
1593
|
-
] }) : /* @__PURE__ */
|
|
1674
|
+
] }) : /* @__PURE__ */ jsx16(RawJsonEditor, { value: draft, onChange: updateDraft }, loadGen)
|
|
1594
1675
|
] });
|
|
1595
1676
|
}
|
|
1596
1677
|
export {
|
|
@@ -1598,6 +1679,7 @@ export {
|
|
|
1598
1679
|
CareersForm,
|
|
1599
1680
|
CheckboxField,
|
|
1600
1681
|
Field,
|
|
1682
|
+
ImageField,
|
|
1601
1683
|
LinksForm,
|
|
1602
1684
|
LocaleTabs,
|
|
1603
1685
|
NO_FIELD_ERRORS,
|