@takuhon/ui 0.17.0 → 0.18.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.
@@ -336,6 +336,23 @@ declare const EN: {
336
336
  readonly 'field.settings.enableJsonLd': "Emit Schema.org JSON-LD";
337
337
  readonly 'field.settings.enableApi': "Expose the public read API";
338
338
  readonly 'field.settings.enableAnalytics': "Enable first-party analytics";
339
+ readonly 'field.settings.publicVisibility': "Public sections";
340
+ readonly 'field.publicVisibility.links': "Links";
341
+ readonly 'field.publicVisibility.careers': "Experience";
342
+ readonly 'field.publicVisibility.projects': "Projects";
343
+ readonly 'field.publicVisibility.skills': "Skills";
344
+ readonly 'field.publicVisibility.certifications': "Certifications";
345
+ readonly 'field.publicVisibility.memberships': "Memberships";
346
+ readonly 'field.publicVisibility.volunteering': "Volunteering";
347
+ readonly 'field.publicVisibility.honors': "Honors & awards";
348
+ readonly 'field.publicVisibility.education': "Education";
349
+ readonly 'field.publicVisibility.publications': "Publications";
350
+ readonly 'field.publicVisibility.languages': "Languages";
351
+ readonly 'field.publicVisibility.courses': "Courses";
352
+ readonly 'field.publicVisibility.patents': "Patents";
353
+ readonly 'field.publicVisibility.testScores': "Test scores";
354
+ readonly 'field.publicVisibility.recommendations': "Recommendations";
355
+ readonly 'field.publicVisibility.contact': "Contact";
339
356
  readonly 'item.link': "Link";
340
357
  readonly 'item.career': "Position";
341
358
  readonly 'item.project': "Project";
@@ -351,6 +368,7 @@ declare const EN: {
351
368
  readonly 'hint.country': "ISO 3166-1 alpha-2 code, e.g. US.";
352
369
  readonly 'hint.tags': "Comma-separated.";
353
370
  readonly 'hint.locales': "Comma-separated BCP-47 tags, e.g. en, ja. Drives the language tabs above.";
371
+ readonly 'hint.publicVisibility': "Unchecked sections are hidden from every public surface (page, API, JSON-LD). All sections are public by default.";
354
372
  readonly 'advanced.hint': "Edit the entire document as JSON. Edits apply only while the JSON is valid.";
355
373
  readonly 'advanced.invalid': "The JSON is not a valid takuhon document:";
356
374
  readonly 'option.none': "(none)";
@@ -255,6 +255,23 @@ var EN = {
255
255
  "field.settings.enableJsonLd": "Emit Schema.org JSON-LD",
256
256
  "field.settings.enableApi": "Expose the public read API",
257
257
  "field.settings.enableAnalytics": "Enable first-party analytics",
258
+ "field.settings.publicVisibility": "Public sections",
259
+ "field.publicVisibility.links": "Links",
260
+ "field.publicVisibility.careers": "Experience",
261
+ "field.publicVisibility.projects": "Projects",
262
+ "field.publicVisibility.skills": "Skills",
263
+ "field.publicVisibility.certifications": "Certifications",
264
+ "field.publicVisibility.memberships": "Memberships",
265
+ "field.publicVisibility.volunteering": "Volunteering",
266
+ "field.publicVisibility.honors": "Honors & awards",
267
+ "field.publicVisibility.education": "Education",
268
+ "field.publicVisibility.publications": "Publications",
269
+ "field.publicVisibility.languages": "Languages",
270
+ "field.publicVisibility.courses": "Courses",
271
+ "field.publicVisibility.patents": "Patents",
272
+ "field.publicVisibility.testScores": "Test scores",
273
+ "field.publicVisibility.recommendations": "Recommendations",
274
+ "field.publicVisibility.contact": "Contact",
258
275
  "item.link": "Link",
259
276
  "item.career": "Position",
260
277
  "item.project": "Project",
@@ -270,6 +287,7 @@ var EN = {
270
287
  "hint.country": "ISO 3166-1 alpha-2 code, e.g. US.",
271
288
  "hint.tags": "Comma-separated.",
272
289
  "hint.locales": "Comma-separated BCP-47 tags, e.g. en, ja. Drives the language tabs above.",
290
+ "hint.publicVisibility": "Unchecked sections are hidden from every public surface (page, API, JSON-LD). All sections are public by default.",
273
291
  "advanced.hint": "Edit the entire document as JSON. Edits apply only while the JSON is valid.",
274
292
  "advanced.invalid": "The JSON is not a valid takuhon document:",
275
293
  "option.none": "(none)"
@@ -666,7 +684,7 @@ function Repeater({
666
684
  }
667
685
 
668
686
  // src/admin/sections/ProfileForm.tsx
669
- import styles10 from "../sections.module-ZVBKZHDE.module.css";
687
+ import styles10 from "../sections.module-7MUK6I3V.module.css";
670
688
  import { jsx as jsx10, jsxs as jsxs7 } from "react/jsx-runtime";
671
689
  var POINTER = "/profile";
672
690
  function isEmptyRecord(record) {
@@ -1303,8 +1321,26 @@ function SkillsForm({
1303
1321
  }
1304
1322
 
1305
1323
  // src/admin/sections/SettingsForm.tsx
1306
- import styles11 from "../sections.module-ZVBKZHDE.module.css";
1324
+ import styles11 from "../sections.module-7MUK6I3V.module.css";
1307
1325
  import { jsx as jsx15, jsxs as jsxs12 } from "react/jsx-runtime";
1326
+ var VISIBILITY_SECTIONS = [
1327
+ { key: "links", label: "field.publicVisibility.links" },
1328
+ { key: "careers", label: "field.publicVisibility.careers" },
1329
+ { key: "projects", label: "field.publicVisibility.projects" },
1330
+ { key: "skills", label: "field.publicVisibility.skills" },
1331
+ { key: "certifications", label: "field.publicVisibility.certifications" },
1332
+ { key: "memberships", label: "field.publicVisibility.memberships" },
1333
+ { key: "volunteering", label: "field.publicVisibility.volunteering" },
1334
+ { key: "honors", label: "field.publicVisibility.honors" },
1335
+ { key: "education", label: "field.publicVisibility.education" },
1336
+ { key: "publications", label: "field.publicVisibility.publications" },
1337
+ { key: "languages", label: "field.publicVisibility.languages" },
1338
+ { key: "courses", label: "field.publicVisibility.courses" },
1339
+ { key: "patents", label: "field.publicVisibility.patents" },
1340
+ { key: "testScores", label: "field.publicVisibility.testScores" },
1341
+ { key: "recommendations", label: "field.publicVisibility.recommendations" },
1342
+ { key: "contact", label: "field.publicVisibility.contact" }
1343
+ ];
1308
1344
  function parseLocales(input) {
1309
1345
  return input.split(",").map((tag) => tag.trim()).filter((tag) => tag !== "");
1310
1346
  }
@@ -1320,6 +1356,16 @@ function SettingsForm({
1320
1356
  label: format(locale)
1321
1357
  }));
1322
1358
  const headingId = "admin-section-settings";
1359
+ const setVisibility = (key, visible) => {
1360
+ const next = { ...value.publicVisibility };
1361
+ if (visible) {
1362
+ delete next[key];
1363
+ } else {
1364
+ next[key] = false;
1365
+ }
1366
+ const publicVisibility = Object.keys(next).length > 0 ? next : void 0;
1367
+ onChange({ ...value, publicVisibility });
1368
+ };
1323
1369
  return /* @__PURE__ */ jsxs12("section", { className: styles11.section, "aria-labelledby": headingId, children: [
1324
1370
  /* @__PURE__ */ jsx15("h2", { className: styles11.heading, id: headingId, children: getAdminLabel("section.settings") }),
1325
1371
  /* @__PURE__ */ jsx15(
@@ -1410,7 +1456,20 @@ function SettingsForm({
1410
1456
  onChange({ ...value, enableAnalytics });
1411
1457
  }
1412
1458
  }
1413
- )
1459
+ ),
1460
+ /* @__PURE__ */ jsx15("h3", { className: styles11.subheading, children: getAdminLabel("field.settings.publicVisibility") }),
1461
+ /* @__PURE__ */ jsx15("p", { className: styles11.hint, children: getAdminLabel("hint.publicVisibility") }),
1462
+ VISIBILITY_SECTIONS.map(({ key, label }) => /* @__PURE__ */ jsx15(
1463
+ CheckboxField,
1464
+ {
1465
+ label: getAdminLabel(label),
1466
+ checked: value.publicVisibility?.[key] ?? true,
1467
+ onChange: (visible) => {
1468
+ setVisibility(key, visible);
1469
+ }
1470
+ },
1471
+ key
1472
+ ))
1414
1473
  ] });
1415
1474
  }
1416
1475
 
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/admin/index.ts","../../src/admin/errors.ts","../../src/admin/primitives/Field.tsx","../../src/admin/primitives/TextField.tsx","../../src/admin/primitives/TextAreaField.tsx","../../src/admin/primitives/SelectField.tsx","../../src/admin/primitives/CheckboxField.tsx","../../src/admin/primitives/ImageField.tsx","../../src/admin/admin-labels.ts","../../src/admin/primitives/GravatarField.tsx","../../src/admin/primitives/LocaleTabs.tsx","../../src/admin/primitives/Repeater.tsx","../../src/admin/sections/ProfileForm.tsx","../../src/admin/ids.ts","../../src/admin/sections/LinksForm.tsx","../../src/admin/localized.ts","../../src/admin/sections/CareersForm.tsx","../../src/admin/sections/ProjectsForm.tsx","../../src/admin/sections/SkillsForm.tsx","../../src/admin/sections/SettingsForm.tsx","../../src/admin/RawJsonEditor.tsx","../../src/admin/AdminEditor.tsx"],"sourcesContent":["/**\n * @takuhon/ui/admin — React form components for the takuhon admin editor.\n *\n * These are the building blocks behind the Cloudflare admin form UI (spec\n * §14.1 Phase 5). They are presentational and transport-agnostic: each is a\n * controlled component that takes a value plus `onChange`, with field errors\n * supplied as a {@link FieldErrorIndex} so server (RFC 7807) and client\n * (`@takuhon/core` `validate`) failures map to the same fields. Co-located CSS\n * Modules are emitted to `dist/admin/` and bundled by the consumer.\n *\n * Importing this entry also pulls in the shared design tokens, so the admin\n * components are themed standalone without depending on the profile UI entry.\n */\n\nimport '../styles/tokens.css';\n\nexport {\n canonicalPointer,\n collectErrorsUnder,\n errorsAt,\n hasErrorsUnder,\n indexErrors,\n indexValidationErrors,\n NO_FIELD_ERRORS,\n type FieldErrorIndex,\n type FieldErrorLike,\n} from './errors.js';\n\nexport { Field, type FieldProps, type FieldControlProps } from './primitives/Field.js';\nexport { TextField, type TextFieldProps } from './primitives/TextField.js';\nexport { TextAreaField, type TextAreaFieldProps } from './primitives/TextAreaField.js';\nexport { SelectField, type SelectFieldProps, type SelectOption } from './primitives/SelectField.js';\nexport { CheckboxField, type CheckboxFieldProps } from './primitives/CheckboxField.js';\nexport {\n ImageField,\n type ImageFieldProps,\n type AssetUploadResult,\n type UploadAsset,\n} from './primitives/ImageField.js';\nexport { GravatarField, type GravatarFieldProps } from './primitives/GravatarField.js';\nexport { LocaleTabs, type LocaleTabsProps } from './primitives/LocaleTabs.js';\nexport { Repeater, type RepeaterProps } from './primitives/Repeater.js';\n\nexport { getAdminLabel, type AdminLabelKey } from './admin-labels.js';\n\nexport { ProfileForm, type ProfileFormProps } from './sections/ProfileForm.js';\nexport { LinksForm, type LinksFormProps } from './sections/LinksForm.js';\nexport { CareersForm, type CareersFormProps } from './sections/CareersForm.js';\nexport { ProjectsForm, type ProjectsFormProps } from './sections/ProjectsForm.js';\nexport { SkillsForm, type SkillsFormProps } from './sections/SkillsForm.js';\nexport { SettingsForm, type SettingsFormProps } from './sections/SettingsForm.js';\n\nexport { RawJsonEditor, type RawJsonEditorProps } from './RawJsonEditor.js';\nexport { AdminEditor, type AdminEditorProps, type AdminSaveOutcome } from './AdminEditor.js';\n","/**\n * Field-error plumbing shared by the admin form components.\n *\n * Validation failures reach the editor in two shapes that mean the same thing:\n *\n * - `@takuhon/core`'s {@link ValidationError}, produced by a client-side\n * `validate()` call, carries an RFC 6901 `pointer` such as\n * `\"/profile/displayName/en\"`.\n * - The server's RFC 7807 response (`api.md §5`) carries the same location as a\n * `path` with a leading `#` fragment marker, e.g. `\"#/profile/displayName/en\"`.\n *\n * Both are normalized to a single canonical pointer so a field can look up its\n * own errors regardless of where they came from.\n */\nimport type { ValidationError } from '@takuhon/core';\n\n/** A field error in either the core (`pointer`) or RFC 7807 wire (`path`) shape. */\nexport interface FieldErrorLike {\n pointer?: string;\n path?: string;\n message: string;\n}\n\n/**\n * Canonical RFC 6901 pointer: no leading `#`, a leading `/` for any non-root\n * location, and `\"\"` for the document root. Idempotent.\n */\nexport function canonicalPointer(raw: string): string {\n let pointer = raw.trim();\n if (pointer.startsWith('#')) pointer = pointer.slice(1);\n if (pointer !== '' && !pointer.startsWith('/')) pointer = `/${pointer}`;\n return pointer;\n}\n\n/** Maps a canonical pointer to the messages reported at that exact location. */\nexport type FieldErrorIndex = ReadonlyMap<string, readonly string[]>;\n\n/** Group a flat error list by canonical pointer, preserving message order. */\nexport function indexErrors(errors: readonly FieldErrorLike[]): FieldErrorIndex {\n const index = new Map<string, string[]>();\n for (const error of errors) {\n const key = canonicalPointer(error.pointer ?? error.path ?? '');\n const existing = index.get(key);\n if (existing) existing.push(error.message);\n else index.set(key, [error.message]);\n }\n return index;\n}\n\n/** Convenience over {@link indexErrors} for a core `validate()` failure list. */\nexport function indexValidationErrors(errors: readonly ValidationError[]): FieldErrorIndex {\n return indexErrors(errors);\n}\n\n/** Messages reported at exactly `pointer` (empty array when none). */\nexport function errorsAt(index: FieldErrorIndex, pointer: string): readonly string[] {\n return index.get(canonicalPointer(pointer)) ?? [];\n}\n\n/**\n * Whether any error sits at or below `prefix` — used to badge a section or a\n * repeater item that contains an invalid field deeper in the tree.\n */\nexport function hasErrorsUnder(index: FieldErrorIndex, prefix: string): boolean {\n const base = canonicalPointer(prefix);\n for (const key of index.keys()) {\n if (key === base || key.startsWith(`${base}/`)) return true;\n }\n return false;\n}\n\n/**\n * All messages at or below `prefix`, in pointer order. Used by aggregate\n * controls (a comma-separated list edited as one field) so item-level failures\n * reported at `${prefix}/${itemIndex}` still surface on the single input.\n */\nexport function collectErrorsUnder(index: FieldErrorIndex, prefix: string): string[] {\n const base = canonicalPointer(prefix);\n const messages: string[] = [];\n for (const [key, list] of index) {\n if (key === base || key.startsWith(`${base}/`)) messages.push(...list);\n }\n return messages;\n}\n\n/** An empty index, handy as a default prop. */\nexport const NO_FIELD_ERRORS: FieldErrorIndex = new Map();\n","import { useId } from 'react';\n\nimport styles from './Field.module.css';\n\n/** Identifiers a {@link Field} hands to the control it wraps. */\nexport interface FieldControlProps {\n /** `id` for the control, paired with the rendered `<label htmlFor>`. */\n controlId: string;\n /** `aria-describedby` value linking the control to its hint/error text. */\n describedBy: string | undefined;\n /** Whether the control should advertise `aria-invalid`. */\n invalid: boolean;\n}\n\nexport interface FieldProps {\n /** Visible label text. */\n label: string;\n /** Validation messages to render beneath the control. */\n errors?: readonly string[];\n /** Optional helper text shown between the label and the control. */\n hint?: string;\n /** Marks the field visually and via `aria-required` on the control. */\n required?: boolean;\n /** Render the control, wired with the supplied accessibility ids. */\n children: (props: FieldControlProps) => React.ReactNode;\n}\n\n/**\n * Layout + accessibility wrapper for a single form control. Owns the `id`\n * wiring so the label, hint, error list, and control stay associated for\n * screen readers (WCAG 2.1 AA, spec §8.5). Presentational only — it holds no\n * value state; the wrapped control is controlled by its parent.\n */\nexport function Field({ label, errors, hint, required, children }: FieldProps): React.JSX.Element {\n const controlId = useId();\n const hintId = useId();\n const errorId = useId();\n const hasErrors = (errors?.length ?? 0) > 0;\n const describedBy =\n [hint ? hintId : undefined, hasErrors ? errorId : undefined].filter(Boolean).join(' ') ||\n undefined;\n\n return (\n <div className={styles.field}>\n <label className={styles.label} htmlFor={controlId}>\n {label}\n {required ? <span aria-hidden=\"true\"> *</span> : null}\n </label>\n {hint ? (\n <p className={styles.hint} id={hintId}>\n {hint}\n </p>\n ) : null}\n {children({ controlId, describedBy, invalid: hasErrors })}\n {hasErrors ? (\n <ul className={styles.errors} id={errorId}>\n {errors!.map((message, i) => (\n <li key={i}>{message}</li>\n ))}\n </ul>\n ) : null}\n </div>\n );\n}\n","import { Field } from './Field.js';\nimport styles from './controls.module.css';\n\nexport interface TextFieldProps {\n label: string;\n value: string;\n onChange: (value: string) => void;\n errors?: readonly string[];\n hint?: string;\n required?: boolean;\n placeholder?: string;\n /**\n * HTML input type. Defaults to `'text'`; `'url'` for link/avatar URLs,\n * `'month'` for `YearMonth` values (a native month picker emits `YYYY-MM`).\n */\n type?: 'text' | 'url' | 'email' | 'month';\n inputMode?: React.HTMLAttributes<HTMLInputElement>['inputMode'];\n}\n\n/** A labelled single-line text input wired for accessibility via {@link Field}. */\nexport function TextField({\n label,\n value,\n onChange,\n errors,\n hint,\n required,\n placeholder,\n type = 'text',\n inputMode,\n}: TextFieldProps): React.JSX.Element {\n return (\n <Field label={label} errors={errors} hint={hint} required={required}>\n {({ controlId, describedBy, invalid }) => (\n <input\n id={controlId}\n className={styles.control}\n type={type}\n value={value}\n placeholder={placeholder}\n inputMode={inputMode}\n aria-invalid={invalid || undefined}\n aria-required={required ? true : undefined}\n aria-describedby={describedBy}\n onChange={(event) => {\n onChange(event.target.value);\n }}\n />\n )}\n </Field>\n );\n}\n","import { Field } from './Field.js';\nimport styles from './controls.module.css';\n\nexport interface TextAreaFieldProps {\n label: string;\n value: string;\n onChange: (value: string) => void;\n errors?: readonly string[];\n hint?: string;\n required?: boolean;\n placeholder?: string;\n rows?: number;\n}\n\n/** A labelled multi-line text input wired for accessibility via {@link Field}. */\nexport function TextAreaField({\n label,\n value,\n onChange,\n errors,\n hint,\n required,\n placeholder,\n rows = 4,\n}: TextAreaFieldProps): React.JSX.Element {\n return (\n <Field label={label} errors={errors} hint={hint} required={required}>\n {({ controlId, describedBy, invalid }) => (\n <textarea\n id={controlId}\n className={`${styles.control} ${styles.textarea}`}\n value={value}\n rows={rows}\n placeholder={placeholder}\n aria-invalid={invalid || undefined}\n aria-required={required ? true : undefined}\n aria-describedby={describedBy}\n onChange={(event) => {\n onChange(event.target.value);\n }}\n />\n )}\n </Field>\n );\n}\n","import { Field } from './Field.js';\nimport styles from './controls.module.css';\n\nexport interface SelectOption {\n value: string;\n label: string;\n}\n\nexport interface SelectFieldProps {\n label: string;\n value: string;\n options: readonly SelectOption[];\n onChange: (value: string) => void;\n errors?: readonly string[];\n hint?: string;\n required?: boolean;\n}\n\n/** A labelled `<select>` wired for accessibility via {@link Field}. */\nexport function SelectField({\n label,\n value,\n options,\n onChange,\n errors,\n hint,\n required,\n}: SelectFieldProps): React.JSX.Element {\n return (\n <Field label={label} errors={errors} hint={hint} required={required}>\n {({ controlId, describedBy, invalid }) => (\n <select\n id={controlId}\n className={styles.control}\n value={value}\n aria-invalid={invalid || undefined}\n aria-required={required ? true : undefined}\n aria-describedby={describedBy}\n onChange={(event) => {\n onChange(event.target.value);\n }}\n >\n {options.map((option) => (\n <option key={option.value} value={option.value}>\n {option.label}\n </option>\n ))}\n </select>\n )}\n </Field>\n );\n}\n","import { useId } from 'react';\n\nimport styles from './controls.module.css';\n\nexport interface CheckboxFieldProps {\n label: string;\n checked: boolean;\n onChange: (checked: boolean) => void;\n}\n\n/**\n * A labelled checkbox. Laid out checkbox-first (distinct from the stacked\n * {@link Field} controls), with the label associated via `htmlFor`.\n */\nexport function CheckboxField({ label, checked, onChange }: CheckboxFieldProps): React.JSX.Element {\n const id = useId();\n return (\n <div className={styles.checkboxRow}>\n <input\n id={id}\n className={styles.checkbox}\n type=\"checkbox\"\n checked={checked}\n onChange={(event) => {\n onChange(event.target.checked);\n }}\n />\n <label className={styles.checkboxLabel} htmlFor={id}>\n {label}\n </label>\n </div>\n );\n}\n","import { useId, useRef, useState } from 'react';\n\nimport { getAdminLabel } from '../admin-labels.js';\n\nimport { Field } from './Field.js';\nimport styles from './ImageField.module.css';\nimport controls from './controls.module.css';\n\n/** Outcome of an asset upload, returned by {@link UploadAsset}. */\nexport type AssetUploadResult =\n | { status: 'uploaded'; url: string; publicUrl: string }\n | { status: 'error'; message?: string };\n\n/**\n * Upload one image file and resolve where it now lives. Supplied by the host's\n * transport layer (it carries the admin token / origin); the UI stays\n * transport-agnostic.\n */\nexport type UploadAsset = (file: File) => Promise<AssetUploadResult>;\n\n/** `accept` attribute matching the MIME types the server accepts (security.md §4.1). */\nconst ACCEPT = 'image/jpeg,image/png,image/webp,image/gif';\n\nexport interface ImageFieldProps {\n label: string;\n /** Current image URL stored in the document. */\n value: string;\n onChange: (url: string) => void;\n errors?: readonly string[];\n hint?: string;\n /**\n * When provided, a file-upload control is rendered alongside the URL input;\n * a successful upload sets the URL to the returned (relative) path. When\n * omitted, the field is URL-only.\n */\n uploadAsset?: UploadAsset;\n}\n\n/**\n * Avatar / image field: a URL input plus, when {@link ImageFieldProps.uploadAsset}\n * is supplied, a file picker that uploads the chosen image and writes the\n * returned URL back into the field. The relative `url` (not the absolute\n * `publicUrl`) is stored so the reference stays valid across origins.\n *\n * No `<img>` preview is rendered: the admin CSP is `img-src 'self' blob:`, so a\n * preview of an arbitrary external URL would be blocked — the URL input is the\n * portable, CSP-safe surface, and the public preview shows the real image.\n */\nexport function ImageField({\n label,\n value,\n onChange,\n errors,\n hint,\n uploadAsset,\n}: ImageFieldProps): React.JSX.Element {\n const fileId = useId();\n const statusId = useId();\n const fileRef = useRef<HTMLInputElement>(null);\n const [busy, setBusy] = useState(false);\n const [uploadError, setUploadError] = useState<string | null>(null);\n\n const handleFile = (event: React.ChangeEvent<HTMLInputElement>): void => {\n const file = event.target.files?.[0];\n if (!file || uploadAsset === undefined) return;\n setBusy(true);\n setUploadError(null);\n uploadAsset(file)\n .then((result) => {\n if (result.status === 'uploaded') {\n onChange(result.url);\n } else {\n setUploadError(result.message ?? getAdminLabel('status.uploadError'));\n }\n })\n .catch(() => {\n setUploadError(getAdminLabel('status.uploadError'));\n })\n .finally(() => {\n setBusy(false);\n // Clear the picker so re-selecting the same file fires `change` again.\n if (fileRef.current) fileRef.current.value = '';\n });\n };\n\n return (\n <Field label={label} errors={errors} hint={hint}>\n {({ controlId, describedBy, invalid }) => (\n <>\n <input\n id={controlId}\n className={controls.control}\n type=\"url\"\n value={value}\n aria-invalid={invalid || undefined}\n aria-describedby={describedBy}\n onChange={(event) => {\n onChange(event.target.value);\n }}\n />\n {uploadAsset !== undefined ? (\n <div className={styles.uploadRow}>\n <label className={styles.uploadLabel} htmlFor={fileId}>\n {getAdminLabel('field.avatarUpload')}\n </label>\n <input\n id={fileId}\n ref={fileRef}\n type=\"file\"\n accept={ACCEPT}\n disabled={busy}\n aria-describedby={statusId}\n onChange={handleFile}\n />\n <span className={styles.uploadStatus} id={statusId} role=\"status\" aria-live=\"polite\">\n {busy ? getAdminLabel('status.uploading') : ''}\n </span>\n {uploadError !== null ? (\n <span className={styles.uploadError} role=\"alert\">\n {uploadError}\n </span>\n ) : null}\n </div>\n ) : null}\n </>\n )}\n </Field>\n );\n}\n","/**\n * UI strings for the admin editor.\n *\n * The admin surface is operator-only, so a single English dictionary ships\n * today; the lookup mirrors `getUILabel` (exact locale → base subtag →\n * English) so locales can be added later without touching call sites. Keys are\n * derived from the English dictionary, so every key is guaranteed to resolve.\n */\nimport type { LocaleTag } from '@takuhon/core';\n\nconst EN = {\n 'app.title': 'takuhon admin',\n 'toolbar.label': 'Editor actions',\n 'mode.label': 'Editing mode',\n 'mode.form': 'Form',\n 'mode.advanced': 'Advanced (JSON)',\n\n 'action.save': 'Save',\n 'action.reload': 'Reload',\n 'action.export': 'Export',\n 'action.import': 'Import',\n 'action.add': 'Add',\n 'action.remove': 'Remove',\n 'action.moveUp': 'Move up',\n 'action.moveDown': 'Move down',\n\n 'status.saving': 'Saving…',\n 'status.saved': 'Saved.',\n 'status.loading': 'Loading…',\n 'status.conflict':\n 'The profile changed on the server since it was loaded. Reload, then reapply the edits.',\n 'status.invalid': 'Some fields need attention before saving.',\n 'status.fixSummary': 'Please fix the following:',\n 'status.error': 'Something went wrong. Please try again.',\n 'status.imported': 'Imported. Review the fields, then save to apply.',\n 'status.importInvalid': 'The imported file is not a valid takuhon document.',\n 'status.uploading': 'Uploading…',\n 'status.uploadError': 'Upload failed. Please try again.',\n\n 'section.profile': 'Profile',\n 'section.about': 'About',\n 'section.links': 'Links',\n 'section.careers': 'Experience',\n 'section.projects': 'Projects',\n 'section.skills': 'Skills',\n 'section.settings': 'Settings',\n\n 'field.displayName': 'Display name',\n 'field.tagline': 'Tagline',\n 'field.bio': 'Bio',\n 'field.avatarUrl': 'Avatar URL',\n 'field.avatarUpload': 'Upload image',\n 'field.avatarAlt': 'Avatar alternative text',\n 'field.gravatarEmail': 'Gravatar email',\n 'field.gravatarApply': 'Use Gravatar',\n 'field.location.country': 'Country',\n 'field.location.region': 'Region',\n 'field.location.locality': 'Locality',\n 'field.location.display': 'Location (display)',\n\n 'field.link.type': 'Type',\n 'field.link.url': 'URL',\n 'field.link.label': 'Label',\n 'field.link.iconUrl': 'Icon URL',\n 'field.link.featured': 'Featured',\n\n 'field.career.organization': 'Organization',\n 'field.career.role': 'Role',\n 'field.career.description': 'Description',\n 'field.career.startDate': 'Start',\n 'field.career.endDate': 'End',\n 'field.career.isCurrent': 'Current position',\n 'field.career.url': 'URL',\n\n 'field.project.title': 'Title',\n 'field.project.description': 'Description',\n 'field.project.url': 'URL',\n 'field.project.tags': 'Tags',\n 'field.project.highlighted': 'Highlighted',\n 'field.project.startDate': 'Start',\n 'field.project.endDate': 'End',\n\n 'field.skill.label': 'Label',\n 'field.skill.category': 'Category',\n\n 'field.settings.defaultLocale': 'Default locale',\n 'field.settings.fallbackLocale': 'Fallback locale',\n 'field.settings.availableLocales': 'Available locales',\n 'field.settings.theme': 'Theme',\n 'field.settings.showPoweredBy': 'Show the \"Powered by takuhon\" footer',\n 'field.settings.enableJsonLd': 'Emit Schema.org JSON-LD',\n 'field.settings.enableApi': 'Expose the public read API',\n 'field.settings.enableAnalytics': 'Enable first-party analytics',\n\n 'item.link': 'Link',\n 'item.career': 'Position',\n 'item.project': 'Project',\n 'item.skill': 'Skill',\n\n 'empty.links': 'No links yet.',\n 'empty.careers': 'No positions yet.',\n 'empty.projects': 'No projects yet.',\n 'empty.skills': 'No skills yet.',\n\n 'hint.avatarNoUpload': 'Paste an image URL. Uploading image files is not available yet.',\n 'hint.avatarUpload': 'Paste an image URL, or upload a JPEG, PNG, WebP, or GIF.',\n 'hint.gravatar':\n 'Enter an email to generate a Gravatar avatar URL. The email is not saved — only the resulting URL is stored.',\n 'hint.month': 'Format: YYYY-MM (e.g. 2024-03).',\n 'hint.country': 'ISO 3166-1 alpha-2 code, e.g. US.',\n 'hint.tags': 'Comma-separated.',\n 'hint.locales': 'Comma-separated BCP-47 tags, e.g. en, ja. Drives the language tabs above.',\n 'advanced.hint': 'Edit the entire document as JSON. Edits apply only while the JSON is valid.',\n 'advanced.invalid': 'The JSON is not a valid takuhon document:',\n\n 'option.none': '(none)',\n} as const;\n\n/** Every label key understood by {@link getAdminLabel}. */\nexport type AdminLabelKey = keyof typeof EN;\n\nconst DICTIONARIES: Partial<Record<LocaleTag, Partial<Record<AdminLabelKey, string>>>> = {\n en: EN,\n};\n\n/**\n * Resolve an admin label for a locale, falling back to the base language\n * subtag and then English. English is always present, so the return is always\n * a string.\n */\nexport function getAdminLabel(key: AdminLabelKey, locale: LocaleTag = 'en'): string {\n const exact = DICTIONARIES[locale]?.[key];\n if (exact !== undefined) return exact;\n const base = locale.split('-')[0];\n const baseMatch = base ? DICTIONARIES[base]?.[key] : undefined;\n return baseMatch ?? EN[key];\n}\n","import { gravatarUrl } from '@takuhon/core';\nimport { useState } from 'react';\n\nimport { getAdminLabel } from '../admin-labels.js';\n\nimport { Field } from './Field.js';\nimport styles from './GravatarField.module.css';\nimport controls from './controls.module.css';\n\nexport interface GravatarFieldProps {\n /** Called with the generated Gravatar URL when the owner applies an email. */\n onApply: (url: string) => void;\n}\n\n/**\n * \"Use Gravatar\" control: an email input plus a button that turns the email into\n * a Gravatar avatar URL via core's pure {@link gravatarUrl}. This is the third\n * way to set an avatar, alongside pasting a URL and uploading an image.\n *\n * The email is local-only — it is never written to the document or sent\n * anywhere. Only the generated URL is handed to {@link GravatarFieldProps.onApply}\n * (which the parent writes into `avatar.url`); the email input is cleared once\n * applied, so nothing about the address lingers in the form.\n */\nexport function GravatarField({ onApply }: GravatarFieldProps): React.JSX.Element {\n const [email, setEmail] = useState('');\n const trimmed = email.trim();\n\n const apply = (): void => {\n if (trimmed === '') return;\n onApply(gravatarUrl(trimmed));\n setEmail('');\n };\n\n return (\n <Field label={getAdminLabel('field.gravatarEmail')} hint={getAdminLabel('hint.gravatar')}>\n {({ controlId, describedBy }) => (\n <>\n <input\n id={controlId}\n className={controls.control}\n type=\"email\"\n value={email}\n autoComplete=\"off\"\n aria-describedby={describedBy}\n onChange={(event) => {\n setEmail(event.target.value);\n }}\n onKeyDown={(event) => {\n if (event.key === 'Enter') {\n event.preventDefault();\n apply();\n }\n }}\n />\n <div className={styles.actionRow}>\n <button\n type=\"button\"\n className={styles.applyButton}\n disabled={trimmed === ''}\n onClick={apply}\n >\n {getAdminLabel('field.gravatarApply')}\n </button>\n </div>\n </>\n )}\n </Field>\n );\n}\n","import type { LocaleTag } from '@takuhon/core';\nimport { useId, useRef, useState } from 'react';\n\nimport { errorsAt, hasErrorsUnder, NO_FIELD_ERRORS, type FieldErrorIndex } from '../errors.js';\n\nimport styles from './LocaleTabs.module.css';\n\nexport interface LocaleTabsProps {\n /** Group label, e.g. `\"Display name\"`. */\n label: string;\n /** Current localized value (BCP-47 tag → string), or undefined when empty. */\n value: Record<LocaleTag, string> | undefined;\n /** Locales offered as tabs (typically `settings.availableLocales`). */\n locales: readonly LocaleTag[];\n /**\n * Receives the next localized record. Empty strings are pruned, and a record\n * that becomes empty is reported as `undefined` so the field is omitted\n * rather than emitted as `{}` (which fails the schema's `minProperties`).\n */\n onChange: (next: Record<LocaleTag, string> | undefined) => void;\n /** Render a `<textarea>` instead of an `<input>` for body-length text. */\n multiline?: boolean;\n required?: boolean;\n hint?: string;\n /** Full error index; per-locale errors are looked up at `${pointer}/${locale}`. */\n errors?: FieldErrorIndex;\n /** Base RFC 6901 pointer to this localized field, e.g. `/profile/displayName`. */\n pointer?: string;\n /** Render a friendlier tab label than the raw locale tag. */\n formatLocale?: (locale: LocaleTag) => string;\n}\n\n/**\n * Edits a localized string map (`LocalizedTitle` / `LocalizedBody`) behind one\n * tab per locale (spec §14.2 \"多言語タブ\"). Implements the WAI-ARIA Tabs\n * pattern — roving tabindex, arrow/Home/End navigation, a single shared\n * `tabpanel` — so it stays keyboard-operable and screen-reader-correct\n * (WCAG 2.1 AA, spec §8.5).\n */\nexport function LocaleTabs({\n label,\n value,\n locales,\n onChange,\n multiline = false,\n required,\n hint,\n errors = NO_FIELD_ERRORS,\n pointer,\n formatLocale,\n}: LocaleTabsProps): React.JSX.Element {\n const baseId = useId();\n const hintId = useId();\n const errorId = useId();\n const [active, setActive] = useState<LocaleTag>(() => locales[0] ?? '');\n const tabRefs = useRef<Record<string, HTMLButtonElement | null>>({});\n\n const format = formatLocale ?? ((locale: LocaleTag) => locale);\n const labelId = `${baseId}-label`;\n\n if (locales.length === 0) {\n return (\n <div className={styles.group} role=\"group\" aria-labelledby={labelId}>\n <span className={styles.groupLabel} id={labelId}>\n {label}\n </span>\n <p className={styles.hint}>No locales are configured yet; add one under Settings.</p>\n </div>\n );\n }\n\n // Reconcile the active tab against the current locale list so editing\n // `availableLocales` elsewhere never strands the selection on a stale tag.\n const activeLocale = locales.includes(active) ? active : locales[0]!;\n const text = value?.[activeLocale] ?? '';\n // Errors on the field itself (`required`, `minProperties`,\n // `propertyNames`) land on the base pointer, not on a locale key, so surface\n // both — otherwise a missing-value failure would be invisible.\n const baseErrors = pointer ? errorsAt(errors, pointer) : [];\n const localeErrors = pointer ? errorsAt(errors, `${pointer}/${activeLocale}`) : [];\n const shownErrors = [...baseErrors, ...localeErrors];\n const hasErrors = shownErrors.length > 0;\n const describedBy =\n [hint ? hintId : undefined, hasErrors ? errorId : undefined].filter(Boolean).join(' ') ||\n undefined;\n\n const setText = (next: string): void => {\n const record: Record<string, string> = { ...(value ?? {}) };\n if (next === '') delete record[activeLocale];\n else record[activeLocale] = next;\n onChange(Object.keys(record).length === 0 ? undefined : record);\n };\n\n const onTabKeyDown = (event: React.KeyboardEvent): void => {\n const current = locales.indexOf(activeLocale);\n let nextIndex: number;\n switch (event.key) {\n case 'ArrowRight':\n case 'ArrowDown':\n nextIndex = (current + 1) % locales.length;\n break;\n case 'ArrowLeft':\n case 'ArrowUp':\n nextIndex = (current - 1 + locales.length) % locales.length;\n break;\n case 'Home':\n nextIndex = 0;\n break;\n case 'End':\n nextIndex = locales.length - 1;\n break;\n default:\n return;\n }\n event.preventDefault();\n const nextLocale = locales[nextIndex];\n if (nextLocale !== undefined) {\n setActive(nextLocale);\n tabRefs.current[nextLocale]?.focus();\n }\n };\n\n const controlName = `${label} (${format(activeLocale)})`;\n\n return (\n <div className={styles.group} role=\"group\" aria-labelledby={labelId}>\n <span className={styles.groupLabel} id={labelId}>\n {label}\n {required ? <span aria-hidden=\"true\"> *</span> : null}\n </span>\n {hint ? (\n <p className={styles.hint} id={hintId}>\n {hint}\n </p>\n ) : null}\n <div className={styles.tablist} role=\"tablist\" aria-label={label}>\n {locales.map((locale) => {\n const selected = locale === activeLocale;\n const tabHasErrors = pointer ? hasErrorsUnder(errors, `${pointer}/${locale}`) : false;\n return (\n <button\n key={locale}\n ref={(element) => {\n tabRefs.current[locale] = element;\n }}\n type=\"button\"\n role=\"tab\"\n id={`${baseId}-tab-${locale}`}\n aria-selected={selected}\n aria-controls={`${baseId}-panel`}\n tabIndex={selected ? 0 : -1}\n className={`${styles.tab} ${selected ? styles.tabActive : ''}`}\n onClick={() => {\n setActive(locale);\n }}\n onKeyDown={onTabKeyDown}\n >\n {format(locale)}\n {tabHasErrors ? (\n <>\n <span className={styles.tabError} aria-hidden=\"true\">\n {' '}\n ●\n </span>\n <span className={styles.srOnly}> (has errors)</span>\n </>\n ) : null}\n </button>\n );\n })}\n </div>\n <div\n role=\"tabpanel\"\n id={`${baseId}-panel`}\n aria-labelledby={`${baseId}-tab-${activeLocale}`}\n className={styles.panel}\n >\n {multiline ? (\n <textarea\n className={`${styles.control} ${styles.textarea}`}\n value={text}\n rows={4}\n aria-label={controlName}\n aria-invalid={hasErrors || undefined}\n aria-required={required ? true : undefined}\n aria-describedby={describedBy}\n onChange={(event) => {\n setText(event.target.value);\n }}\n />\n ) : (\n <input\n className={styles.control}\n type=\"text\"\n value={text}\n aria-label={controlName}\n aria-invalid={hasErrors || undefined}\n aria-required={required ? true : undefined}\n aria-describedby={describedBy}\n onChange={(event) => {\n setText(event.target.value);\n }}\n />\n )}\n {hasErrors ? (\n <ul className={styles.errors} id={errorId}>\n {shownErrors.map((message, i) => (\n <li key={i}>{message}</li>\n ))}\n </ul>\n ) : null}\n </div>\n </div>\n );\n}\n","import styles from './Repeater.module.css';\n\nexport interface RepeaterProps<T> {\n /** Group caption rendered as the fieldset legend, e.g. `\"Links\"`. */\n legend: string;\n items: readonly T[];\n /** Receives the next array after an add / remove / reorder / item edit. */\n onChange: (next: T[]) => void;\n /** Render one item's fields; `update` replaces that item in place. */\n renderItem: (item: T, update: (next: T) => void, index: number) => React.ReactNode;\n /** Factory for the entry appended by the Add button. */\n createItem: () => T;\n /** Stable React key per item. Defaults to the index. */\n keyOf?: (item: T, index: number) => string;\n /** Human label for an item, used in the item caption and button names. */\n itemLabel: (item: T, index: number) => string;\n addLabel?: string;\n removeLabel?: string;\n moveUpLabel?: string;\n moveDownLabel?: string;\n /** Shown when there are no items yet. */\n emptyHint?: string;\n}\n\n/**\n * Add / remove / reorder editor for a repeating array field (spec §14.2\n * \"リピーター\"). Reordering uses keyboard-operable Move up / Move down buttons\n * rather than drag-and-drop so the control meets WCAG 2.1 AA (spec §8.5)\n * without a pointer.\n */\nexport function Repeater<T>({\n legend,\n items,\n onChange,\n renderItem,\n createItem,\n keyOf,\n itemLabel,\n addLabel = 'Add',\n removeLabel = 'Remove',\n moveUpLabel = 'Move up',\n moveDownLabel = 'Move down',\n emptyHint,\n}: RepeaterProps<T>): React.JSX.Element {\n const key = keyOf ?? ((_item: T, index: number) => String(index));\n\n const update = (index: number, next: T): void => {\n const copy = items.slice();\n copy[index] = next;\n onChange(copy);\n };\n\n const remove = (index: number): void => {\n onChange(items.filter((_item, i) => i !== index));\n };\n\n const move = (from: number, to: number): void => {\n if (to < 0 || to >= items.length) return;\n const copy = items.slice();\n const [moved] = copy.splice(from, 1);\n if (moved === undefined) return;\n copy.splice(to, 0, moved);\n onChange(copy);\n };\n\n return (\n <fieldset className={styles.fieldset}>\n <legend className={styles.legend}>{legend}</legend>\n {items.length === 0 && emptyHint ? <p className={styles.empty}>{emptyHint}</p> : null}\n <ol className={styles.list}>\n {items.map((item, index) => {\n const caption = itemLabel(item, index);\n return (\n <li key={key(item, index)} className={styles.item}>\n <div role=\"group\" aria-label={caption}>\n <div className={styles.itemHeader}>\n <span className={styles.itemCaption}>{caption}</span>\n <div className={styles.itemActions}>\n <button\n type=\"button\"\n className={styles.iconButton}\n aria-label={`${moveUpLabel}: ${caption}`}\n disabled={index === 0}\n onClick={() => {\n move(index, index - 1);\n }}\n >\n ↑\n </button>\n <button\n type=\"button\"\n className={styles.iconButton}\n aria-label={`${moveDownLabel}: ${caption}`}\n disabled={index === items.length - 1}\n onClick={() => {\n move(index, index + 1);\n }}\n >\n ↓\n </button>\n <button\n type=\"button\"\n className={styles.removeButton}\n aria-label={`${removeLabel}: ${caption}`}\n onClick={() => {\n remove(index);\n }}\n >\n {removeLabel}\n </button>\n </div>\n </div>\n <div className={styles.itemBody}>\n {renderItem(\n item,\n (next) => {\n update(index, next);\n },\n index,\n )}\n </div>\n </div>\n </li>\n );\n })}\n </ol>\n <button\n type=\"button\"\n className={styles.addButton}\n onClick={() => {\n onChange([...items, createItem()]);\n }}\n >\n {addLabel}\n </button>\n </fieldset>\n );\n}\n","import type { Address, Avatar, LocaleTag, Profile } from '@takuhon/core';\n\nimport { getAdminLabel } from '../admin-labels.js';\nimport { errorsAt, NO_FIELD_ERRORS, type FieldErrorIndex } from '../errors.js';\nimport { GravatarField } from '../primitives/GravatarField.js';\nimport { ImageField, type UploadAsset } from '../primitives/ImageField.js';\nimport { LocaleTabs } from '../primitives/LocaleTabs.js';\nimport { TextField } from '../primitives/TextField.js';\n\nimport styles from './sections.module.css';\n\nexport interface ProfileFormProps {\n value: Profile;\n onChange: (next: Profile) => void;\n locales: readonly LocaleTag[];\n errors?: FieldErrorIndex;\n formatLocale?: (locale: LocaleTag) => string;\n /**\n * Upload an avatar image file. When provided, the avatar field offers a file\n * picker; when omitted, it stays URL-only.\n */\n uploadAsset?: UploadAsset;\n}\n\nconst POINTER = '/profile';\n\nfunction isEmptyRecord(record: Record<string, string> | undefined): boolean {\n return !record || Object.keys(record).length === 0;\n}\n\n/**\n * Basic profile + About: display name, tagline, bio, avatar, and a structured\n * location (spec §6.5 / §14.2). The avatar accepts a URL and, when\n * `uploadAsset` is supplied by the host, an uploaded image file.\n */\nexport function ProfileForm({\n value,\n onChange,\n locales,\n errors = NO_FIELD_ERRORS,\n formatLocale,\n uploadAsset,\n}: ProfileFormProps): React.JSX.Element {\n const updateAvatar = (patch: Partial<Avatar>): void => {\n const merged: Avatar = { url: '', ...value.avatar, ...patch };\n const keep = merged.url !== '' || !isEmptyRecord(merged.alt);\n onChange({ ...value, avatar: keep ? merged : undefined });\n };\n\n const updateLocation = (patch: Partial<Address>): void => {\n const merged: Address = { ...value.location, ...patch };\n const empty =\n !merged.country &&\n !merged.region &&\n isEmptyRecord(merged.locality) &&\n isEmptyRecord(merged.display);\n onChange({ ...value, location: empty ? undefined : merged });\n };\n\n const headingId = 'admin-section-profile';\n\n return (\n <section className={styles.section} aria-labelledby={headingId}>\n <h2 className={styles.heading} id={headingId}>\n {getAdminLabel('section.profile')}\n </h2>\n\n <LocaleTabs\n label={getAdminLabel('field.displayName')}\n value={value.displayName}\n locales={locales}\n onChange={(next) => {\n onChange({ ...value, displayName: next ?? {} });\n }}\n required\n pointer={`${POINTER}/displayName`}\n errors={errors}\n formatLocale={formatLocale}\n />\n\n <LocaleTabs\n label={getAdminLabel('field.tagline')}\n value={value.tagline}\n locales={locales}\n onChange={(next) => {\n onChange({ ...value, tagline: next });\n }}\n pointer={`${POINTER}/tagline`}\n errors={errors}\n formatLocale={formatLocale}\n />\n\n <h3 className={styles.subheading}>{getAdminLabel('section.about')}</h3>\n <LocaleTabs\n label={getAdminLabel('field.bio')}\n value={value.bio}\n locales={locales}\n onChange={(next) => {\n onChange({ ...value, bio: next });\n }}\n multiline\n pointer={`${POINTER}/bio`}\n errors={errors}\n formatLocale={formatLocale}\n />\n\n <ImageField\n label={getAdminLabel('field.avatarUrl')}\n value={value.avatar?.url ?? ''}\n onChange={(url) => {\n updateAvatar({ url });\n }}\n hint={getAdminLabel(uploadAsset ? 'hint.avatarUpload' : 'hint.avatarNoUpload')}\n errors={errorsAt(errors, `${POINTER}/avatar/url`)}\n uploadAsset={uploadAsset}\n />\n <GravatarField\n onApply={(url) => {\n updateAvatar({ url });\n }}\n />\n <LocaleTabs\n label={getAdminLabel('field.avatarAlt')}\n value={value.avatar?.alt}\n locales={locales}\n onChange={(next) => {\n updateAvatar({ alt: next });\n }}\n pointer={`${POINTER}/avatar/alt`}\n errors={errors}\n formatLocale={formatLocale}\n />\n\n <TextField\n label={getAdminLabel('field.location.country')}\n value={value.location?.country ?? ''}\n onChange={(country) => {\n updateLocation({ country: country || undefined });\n }}\n hint={getAdminLabel('hint.country')}\n errors={errorsAt(errors, `${POINTER}/location/country`)}\n />\n <TextField\n label={getAdminLabel('field.location.region')}\n value={value.location?.region ?? ''}\n onChange={(region) => {\n updateLocation({ region: region || undefined });\n }}\n errors={errorsAt(errors, `${POINTER}/location/region`)}\n />\n <LocaleTabs\n label={getAdminLabel('field.location.locality')}\n value={value.location?.locality}\n locales={locales}\n onChange={(next) => {\n updateLocation({ locality: next });\n }}\n pointer={`${POINTER}/location/locality`}\n errors={errors}\n formatLocale={formatLocale}\n />\n </section>\n );\n}\n","/**\n * Build a unique slug like `link-1` that is not already in `taken`. The prefix\n * is lowercased and stripped to `[a-z0-9-]` (falling back to `item`) so the\n * result always matches the `Slug` pattern `^[a-z0-9][a-z0-9-]*$`.\n * Deterministic given the existing ids, so it needs no random source.\n */\nexport function makeId(prefix: string, taken: Iterable<string>): string {\n const safe = prefix.toLowerCase().replace(/[^a-z0-9-]/g, '') || 'item';\n const used = new Set(taken);\n let n = 1;\n while (used.has(`${safe}-${String(n)}`)) n += 1;\n return `${safe}-${String(n)}`;\n}\n","import type { LinkBuiltin, LinkCustom, LinkType, Link, LocaleTag } from '@takuhon/core';\n\nimport { getAdminLabel } from '../admin-labels.js';\nimport { NO_FIELD_ERRORS, errorsAt, type FieldErrorIndex } from '../errors.js';\nimport { makeId } from '../ids.js';\nimport { CheckboxField } from '../primitives/CheckboxField.js';\nimport { LocaleTabs } from '../primitives/LocaleTabs.js';\nimport { Repeater } from '../primitives/Repeater.js';\nimport { SelectField } from '../primitives/SelectField.js';\nimport { TextField } from '../primitives/TextField.js';\n\nexport interface LinksFormProps {\n value: readonly Link[];\n onChange: (next: Link[]) => void;\n locales: readonly LocaleTag[];\n errors?: FieldErrorIndex;\n formatLocale?: (locale: LocaleTag) => string;\n}\n\nconst LINK_TYPES: readonly LinkType[] = [\n 'website',\n 'blog',\n 'github',\n 'gitlab',\n 'linkedin',\n 'x',\n 'mastodon',\n 'bluesky',\n 'instagram',\n 'youtube',\n 'threads',\n 'facebook',\n 'email',\n 'rss',\n 'custom',\n];\n\n/** Re-key a link to a new `type`, preserving common fields and the icon. */\nfunction retypeLink(link: Link, type: LinkType): Link {\n if (type === 'custom') {\n return {\n id: link.id,\n url: link.url,\n label: link.label,\n featured: link.featured,\n order: link.order,\n type: 'custom',\n iconUrl: link.iconUrl ?? '',\n } satisfies LinkCustom;\n }\n const builtin: LinkBuiltin = {\n id: link.id,\n url: link.url,\n label: link.label,\n featured: link.featured,\n order: link.order,\n type,\n };\n if (link.iconUrl) builtin.iconUrl = link.iconUrl;\n return builtin;\n}\n\n/** Set the icon URL, keeping it required for custom links and optional otherwise. */\nfunction setIconUrl(link: Link, iconUrl: string): Link {\n if (link.type === 'custom') return { ...link, iconUrl };\n return { ...link, iconUrl: iconUrl || undefined };\n}\n\n/** SNS / profile links with builtin-vs-custom typing (spec §6.6 / §14.2). */\nexport function LinksForm({\n value,\n onChange,\n locales,\n errors = NO_FIELD_ERRORS,\n formatLocale,\n}: LinksFormProps): React.JSX.Element {\n return (\n <Repeater<Link>\n legend={getAdminLabel('section.links')}\n items={value}\n onChange={onChange}\n keyOf={(link) => link.id}\n itemLabel={(link, index) => link.url || `${getAdminLabel('item.link')} ${String(index + 1)}`}\n createItem={() => ({\n id: makeId(\n 'link',\n value.map((l) => l.id),\n ),\n type: 'website',\n url: '',\n })}\n addLabel={getAdminLabel('action.add')}\n removeLabel={getAdminLabel('action.remove')}\n moveUpLabel={getAdminLabel('action.moveUp')}\n moveDownLabel={getAdminLabel('action.moveDown')}\n emptyHint={getAdminLabel('empty.links')}\n renderItem={(link, update, index) => {\n const at = `/links/${String(index)}`;\n return (\n <>\n <SelectField\n label={getAdminLabel('field.link.type')}\n value={link.type}\n options={LINK_TYPES.map((t) => ({ value: t, label: t }))}\n onChange={(t) => {\n update(retypeLink(link, t as LinkType));\n }}\n errors={errorsAt(errors, `${at}/type`)}\n />\n <TextField\n label={getAdminLabel('field.link.url')}\n type=\"url\"\n value={link.url}\n onChange={(url) => {\n update({ ...link, url });\n }}\n required\n errors={errorsAt(errors, `${at}/url`)}\n />\n <LocaleTabs\n label={getAdminLabel('field.link.label')}\n value={link.label}\n locales={locales}\n onChange={(next) => {\n update({ ...link, label: next });\n }}\n pointer={`${at}/label`}\n errors={errors}\n formatLocale={formatLocale}\n />\n <TextField\n label={getAdminLabel('field.link.iconUrl')}\n type=\"url\"\n value={link.iconUrl ?? ''}\n onChange={(iconUrl) => {\n update(setIconUrl(link, iconUrl));\n }}\n required={link.type === 'custom'}\n errors={errorsAt(errors, `${at}/iconUrl`)}\n />\n <CheckboxField\n label={getAdminLabel('field.link.featured')}\n checked={link.featured ?? false}\n onChange={(featured) => {\n update({ ...link, featured: featured || undefined });\n }}\n />\n </>\n );\n }}\n />\n );\n}\n","import type { LocaleTag } from '@takuhon/core';\n\n/**\n * First non-empty localized value, preferring the order of `locales` and\n * falling back to any present value. Used for repeater item captions where a\n * single human-readable string is needed regardless of the active locale.\n */\nexport function firstLocalized(\n record: Record<LocaleTag, string> | undefined,\n locales: readonly LocaleTag[],\n): string {\n if (!record) return '';\n for (const locale of locales) {\n const value = record[locale];\n if (value) return value;\n }\n return Object.values(record).find((value) => value !== '') ?? '';\n}\n","import type { Career, LocaleTag } from '@takuhon/core';\n\nimport { getAdminLabel } from '../admin-labels.js';\nimport { NO_FIELD_ERRORS, errorsAt, type FieldErrorIndex } from '../errors.js';\nimport { makeId } from '../ids.js';\nimport { firstLocalized } from '../localized.js';\nimport { CheckboxField } from '../primitives/CheckboxField.js';\nimport { LocaleTabs } from '../primitives/LocaleTabs.js';\nimport { Repeater } from '../primitives/Repeater.js';\nimport { TextField } from '../primitives/TextField.js';\n\nexport interface CareersFormProps {\n value: readonly Career[];\n onChange: (next: Career[]) => void;\n locales: readonly LocaleTag[];\n errors?: FieldErrorIndex;\n formatLocale?: (locale: LocaleTag) => string;\n}\n\n/** Work experience (spec §6.7 / §14.2 \"職歴\"). */\nexport function CareersForm({\n value,\n onChange,\n locales,\n errors = NO_FIELD_ERRORS,\n formatLocale,\n}: CareersFormProps): React.JSX.Element {\n return (\n <Repeater<Career>\n legend={getAdminLabel('section.careers')}\n items={value}\n onChange={onChange}\n keyOf={(career) => career.id}\n itemLabel={(career, index) =>\n firstLocalized(career.organization, locales) ||\n `${getAdminLabel('item.career')} ${String(index + 1)}`\n }\n createItem={() => ({\n id: makeId(\n 'career',\n value.map((c) => c.id),\n ),\n organization: {},\n role: {},\n startDate: '',\n })}\n addLabel={getAdminLabel('action.add')}\n removeLabel={getAdminLabel('action.remove')}\n moveUpLabel={getAdminLabel('action.moveUp')}\n moveDownLabel={getAdminLabel('action.moveDown')}\n emptyHint={getAdminLabel('empty.careers')}\n renderItem={(career, update, index) => {\n const at = `/careers/${String(index)}`;\n return (\n <>\n <LocaleTabs\n label={getAdminLabel('field.career.organization')}\n value={career.organization}\n locales={locales}\n onChange={(next) => {\n update({ ...career, organization: next ?? {} });\n }}\n required\n pointer={`${at}/organization`}\n errors={errors}\n formatLocale={formatLocale}\n />\n <LocaleTabs\n label={getAdminLabel('field.career.role')}\n value={career.role}\n locales={locales}\n onChange={(next) => {\n update({ ...career, role: next ?? {} });\n }}\n required\n pointer={`${at}/role`}\n errors={errors}\n formatLocale={formatLocale}\n />\n <TextField\n label={getAdminLabel('field.career.startDate')}\n type=\"month\"\n value={career.startDate}\n onChange={(startDate) => {\n update({ ...career, startDate });\n }}\n required\n hint={getAdminLabel('hint.month')}\n errors={errorsAt(errors, `${at}/startDate`)}\n />\n <TextField\n label={getAdminLabel('field.career.endDate')}\n type=\"month\"\n value={career.endDate ?? ''}\n onChange={(endDate) => {\n update({ ...career, endDate: endDate || undefined });\n }}\n hint={getAdminLabel('hint.month')}\n errors={errorsAt(errors, `${at}/endDate`)}\n />\n <CheckboxField\n label={getAdminLabel('field.career.isCurrent')}\n checked={career.isCurrent ?? false}\n onChange={(isCurrent) => {\n update({ ...career, isCurrent: isCurrent || undefined });\n }}\n />\n <LocaleTabs\n label={getAdminLabel('field.career.description')}\n value={career.description}\n locales={locales}\n onChange={(next) => {\n update({ ...career, description: next });\n }}\n multiline\n pointer={`${at}/description`}\n errors={errors}\n formatLocale={formatLocale}\n />\n <TextField\n label={getAdminLabel('field.career.url')}\n type=\"url\"\n value={career.url ?? ''}\n onChange={(url) => {\n update({ ...career, url: url || undefined });\n }}\n errors={errorsAt(errors, `${at}/url`)}\n />\n </>\n );\n }}\n />\n );\n}\n","import type { LocaleTag, Project } from '@takuhon/core';\n\nimport { getAdminLabel } from '../admin-labels.js';\nimport { NO_FIELD_ERRORS, collectErrorsUnder, errorsAt, type FieldErrorIndex } from '../errors.js';\nimport { makeId } from '../ids.js';\nimport { firstLocalized } from '../localized.js';\nimport { CheckboxField } from '../primitives/CheckboxField.js';\nimport { LocaleTabs } from '../primitives/LocaleTabs.js';\nimport { Repeater } from '../primitives/Repeater.js';\nimport { TextField } from '../primitives/TextField.js';\n\nexport interface ProjectsFormProps {\n value: readonly Project[];\n onChange: (next: Project[]) => void;\n locales: readonly LocaleTag[];\n errors?: FieldErrorIndex;\n formatLocale?: (locale: LocaleTag) => string;\n}\n\nfunction parseTags(input: string): string[] | undefined {\n const tags = input\n .split(',')\n .map((tag) => tag.trim())\n .filter((tag) => tag !== '');\n return tags.length > 0 ? tags : undefined;\n}\n\n/** Projects (spec §6.8 / §14.2). */\nexport function ProjectsForm({\n value,\n onChange,\n locales,\n errors = NO_FIELD_ERRORS,\n formatLocale,\n}: ProjectsFormProps): React.JSX.Element {\n return (\n <Repeater<Project>\n legend={getAdminLabel('section.projects')}\n items={value}\n onChange={onChange}\n keyOf={(project) => project.id}\n itemLabel={(project, index) =>\n firstLocalized(project.title, locales) ||\n `${getAdminLabel('item.project')} ${String(index + 1)}`\n }\n createItem={() => ({\n id: makeId(\n 'project',\n value.map((p) => p.id),\n ),\n title: {},\n })}\n addLabel={getAdminLabel('action.add')}\n removeLabel={getAdminLabel('action.remove')}\n moveUpLabel={getAdminLabel('action.moveUp')}\n moveDownLabel={getAdminLabel('action.moveDown')}\n emptyHint={getAdminLabel('empty.projects')}\n renderItem={(project, update, index) => {\n const at = `/projects/${String(index)}`;\n return (\n <>\n <LocaleTabs\n label={getAdminLabel('field.project.title')}\n value={project.title}\n locales={locales}\n onChange={(next) => {\n update({ ...project, title: next ?? {} });\n }}\n required\n pointer={`${at}/title`}\n errors={errors}\n formatLocale={formatLocale}\n />\n <LocaleTabs\n label={getAdminLabel('field.project.description')}\n value={project.description}\n locales={locales}\n onChange={(next) => {\n update({ ...project, description: next });\n }}\n multiline\n pointer={`${at}/description`}\n errors={errors}\n formatLocale={formatLocale}\n />\n <TextField\n label={getAdminLabel('field.project.url')}\n type=\"url\"\n value={project.url ?? ''}\n onChange={(url) => {\n update({ ...project, url: url || undefined });\n }}\n errors={errorsAt(errors, `${at}/url`)}\n />\n <TextField\n label={getAdminLabel('field.project.tags')}\n value={(project.tags ?? []).join(', ')}\n onChange={(input) => {\n update({ ...project, tags: parseTags(input) });\n }}\n hint={getAdminLabel('hint.tags')}\n errors={collectErrorsUnder(errors, `${at}/tags`)}\n />\n <TextField\n label={getAdminLabel('field.project.startDate')}\n type=\"month\"\n value={project.startDate ?? ''}\n onChange={(startDate) => {\n update({ ...project, startDate: startDate || undefined });\n }}\n hint={getAdminLabel('hint.month')}\n errors={errorsAt(errors, `${at}/startDate`)}\n />\n <TextField\n label={getAdminLabel('field.project.endDate')}\n type=\"month\"\n value={project.endDate ?? ''}\n onChange={(endDate) => {\n update({ ...project, endDate: endDate || undefined });\n }}\n hint={getAdminLabel('hint.month')}\n errors={errorsAt(errors, `${at}/endDate`)}\n />\n <CheckboxField\n label={getAdminLabel('field.project.highlighted')}\n checked={project.highlighted ?? false}\n onChange={(highlighted) => {\n update({ ...project, highlighted: highlighted || undefined });\n }}\n />\n </>\n );\n }}\n />\n );\n}\n","import type { Skill } from '@takuhon/core';\n\nimport { getAdminLabel } from '../admin-labels.js';\nimport { NO_FIELD_ERRORS, errorsAt, type FieldErrorIndex } from '../errors.js';\nimport { makeId } from '../ids.js';\nimport { Repeater } from '../primitives/Repeater.js';\nimport { TextField } from '../primitives/TextField.js';\n\nexport interface SkillsFormProps {\n value: readonly Skill[];\n onChange: (next: Skill[]) => void;\n errors?: FieldErrorIndex;\n}\n\n/** Skills (spec §6.9 / §14.2). `label` is a plain string, not localized. */\nexport function SkillsForm({\n value,\n onChange,\n errors = NO_FIELD_ERRORS,\n}: SkillsFormProps): React.JSX.Element {\n return (\n <Repeater<Skill>\n legend={getAdminLabel('section.skills')}\n items={value}\n onChange={onChange}\n keyOf={(skill) => skill.id}\n itemLabel={(skill, index) =>\n skill.label || `${getAdminLabel('item.skill')} ${String(index + 1)}`\n }\n createItem={() => ({\n id: makeId(\n 'skill',\n value.map((s) => s.id),\n ),\n label: '',\n })}\n addLabel={getAdminLabel('action.add')}\n removeLabel={getAdminLabel('action.remove')}\n moveUpLabel={getAdminLabel('action.moveUp')}\n moveDownLabel={getAdminLabel('action.moveDown')}\n emptyHint={getAdminLabel('empty.skills')}\n renderItem={(skill, update, index) => {\n const at = `/skills/${String(index)}`;\n return (\n <>\n <TextField\n label={getAdminLabel('field.skill.label')}\n value={skill.label}\n onChange={(label) => {\n update({ ...skill, label });\n }}\n required\n errors={errorsAt(errors, `${at}/label`)}\n />\n <TextField\n label={getAdminLabel('field.skill.category')}\n value={skill.category ?? ''}\n onChange={(category) => {\n update({ ...skill, category: category || undefined });\n }}\n errors={errorsAt(errors, `${at}/category`)}\n />\n </>\n );\n }}\n />\n );\n}\n","import type { LocaleTag, Settings } from '@takuhon/core';\n\nimport { getAdminLabel } from '../admin-labels.js';\nimport { NO_FIELD_ERRORS, collectErrorsUnder, errorsAt, type FieldErrorIndex } from '../errors.js';\nimport { CheckboxField } from '../primitives/CheckboxField.js';\nimport { SelectField } from '../primitives/SelectField.js';\nimport { TextField } from '../primitives/TextField.js';\n\nimport styles from './sections.module.css';\n\nexport interface SettingsFormProps {\n value: Settings;\n onChange: (next: Settings) => void;\n errors?: FieldErrorIndex;\n formatLocale?: (locale: LocaleTag) => string;\n}\n\nfunction parseLocales(input: string): string[] {\n return input\n .split(',')\n .map((tag) => tag.trim())\n .filter((tag) => tag !== '');\n}\n\n/** Site settings: locales, theme, and feature toggles (spec §6.20 / §14.2). */\nexport function SettingsForm({\n value,\n onChange,\n errors = NO_FIELD_ERRORS,\n formatLocale,\n}: SettingsFormProps): React.JSX.Element {\n const format = formatLocale ?? ((locale: LocaleTag) => locale);\n const localeOptions = value.availableLocales.map((locale) => ({\n value: locale,\n label: format(locale),\n }));\n const headingId = 'admin-section-settings';\n\n return (\n <section className={styles.section} aria-labelledby={headingId}>\n <h2 className={styles.heading} id={headingId}>\n {getAdminLabel('section.settings')}\n </h2>\n\n <TextField\n label={getAdminLabel('field.settings.availableLocales')}\n value={value.availableLocales.join(', ')}\n onChange={(input) => {\n onChange({ ...value, availableLocales: parseLocales(input) });\n }}\n required\n hint={getAdminLabel('hint.locales')}\n errors={collectErrorsUnder(errors, '/settings/availableLocales')}\n />\n <SelectField\n label={getAdminLabel('field.settings.defaultLocale')}\n value={value.defaultLocale}\n options={localeOptions}\n onChange={(defaultLocale) => {\n onChange({ ...value, defaultLocale });\n }}\n required\n errors={errorsAt(errors, '/settings/defaultLocale')}\n />\n <SelectField\n label={getAdminLabel('field.settings.fallbackLocale')}\n value={value.fallbackLocale ?? ''}\n options={[{ value: '', label: getAdminLabel('option.none') }, ...localeOptions]}\n onChange={(fallbackLocale) => {\n onChange({ ...value, fallbackLocale: fallbackLocale || undefined });\n }}\n errors={errorsAt(errors, '/settings/fallbackLocale')}\n />\n <TextField\n label={getAdminLabel('field.settings.theme')}\n value={value.theme ?? ''}\n onChange={(theme) => {\n onChange({ ...value, theme: theme || undefined });\n }}\n errors={errorsAt(errors, '/settings/theme')}\n />\n\n <CheckboxField\n label={getAdminLabel('field.settings.showPoweredBy')}\n checked={value.showPoweredBy ?? true}\n onChange={(showPoweredBy) => {\n onChange({ ...value, showPoweredBy });\n }}\n />\n <CheckboxField\n label={getAdminLabel('field.settings.enableJsonLd')}\n checked={value.enableJsonLd ?? true}\n onChange={(enableJsonLd) => {\n onChange({ ...value, enableJsonLd });\n }}\n />\n <CheckboxField\n label={getAdminLabel('field.settings.enableApi')}\n checked={value.enableApi ?? true}\n onChange={(enableApi) => {\n onChange({ ...value, enableApi });\n }}\n />\n <CheckboxField\n label={getAdminLabel('field.settings.enableAnalytics')}\n checked={value.enableAnalytics ?? false}\n onChange={(enableAnalytics) => {\n onChange({ ...value, enableAnalytics });\n }}\n />\n </section>\n );\n}\n","import { validate, type Takuhon } from '@takuhon/core';\nimport { useId, useState } from 'react';\n\nimport styles from './RawJsonEditor.module.css';\nimport { getAdminLabel } from './admin-labels.js';\n\nexport interface RawJsonEditorProps {\n value: Takuhon;\n /** Called with the parsed document whenever the text is valid JSON + schema. */\n onChange: (next: Takuhon) => void;\n}\n\nconst MAX_SHOWN_PROBLEMS = 50;\n\n/**\n * Advanced editing surface: the entire document as JSON text. Edits commit to\n * the draft only when the text parses and passes schema validation, so the\n * structured form view it shares state with never sees a malformed document.\n * This is also the only way to edit sections without a dedicated form (spec\n * §14.1 Phase 5 — JSON editor retained as the advanced mode).\n */\nexport function RawJsonEditor({ value, onChange }: RawJsonEditorProps): React.JSX.Element {\n const [text, setText] = useState(() => JSON.stringify(value, null, 2));\n const [problems, setProblems] = useState<readonly string[]>([]);\n const labelId = useId();\n const errorId = useId();\n\n const apply = (next: string): void => {\n setText(next);\n let parsed: unknown;\n try {\n parsed = JSON.parse(next);\n } catch (error) {\n setProblems([error instanceof Error ? error.message : 'Invalid JSON.']);\n return;\n }\n const result = validate(parsed);\n if (!result.ok) {\n setProblems(\n result.errors\n .slice(0, MAX_SHOWN_PROBLEMS)\n .map((error) => `${error.pointer || '/'}: ${error.message}`),\n );\n return;\n }\n setProblems([]);\n onChange(result.data);\n };\n\n const hasProblems = problems.length > 0;\n\n return (\n <section className={styles.wrapper} aria-labelledby={labelId}>\n <h2 className={styles.heading} id={labelId}>\n {getAdminLabel('mode.advanced')}\n </h2>\n <p className={styles.hint}>{getAdminLabel('advanced.hint')}</p>\n <textarea\n className={styles.textarea}\n value={text}\n spellCheck={false}\n aria-label={getAdminLabel('mode.advanced')}\n aria-invalid={hasProblems || undefined}\n aria-describedby={hasProblems ? errorId : undefined}\n onChange={(event) => {\n apply(event.target.value);\n }}\n />\n {hasProblems ? (\n <div className={styles.problems} id={errorId} role=\"alert\">\n <p className={styles.problemsTitle}>{getAdminLabel('advanced.invalid')}</p>\n <ul>\n {problems.map((problem, i) => (\n <li key={i}>{problem}</li>\n ))}\n </ul>\n </div>\n ) : null}\n </section>\n );\n}\n","import { validate, type LocaleTag, type Takuhon } from '@takuhon/core';\nimport { useRef, useState } from 'react';\n\nimport styles from './AdminEditor.module.css';\nimport { RawJsonEditor } from './RawJsonEditor.js';\nimport { getAdminLabel } from './admin-labels.js';\nimport {\n indexErrors,\n indexValidationErrors,\n NO_FIELD_ERRORS,\n type FieldErrorIndex,\n type FieldErrorLike,\n} from './errors.js';\nimport { type UploadAsset } from './primitives/ImageField.js';\nimport { CareersForm } from './sections/CareersForm.js';\nimport { LinksForm } from './sections/LinksForm.js';\nimport { ProfileForm } from './sections/ProfileForm.js';\nimport { ProjectsForm } from './sections/ProjectsForm.js';\nimport { SettingsForm } from './sections/SettingsForm.js';\nimport { SkillsForm } from './sections/SkillsForm.js';\n\n/** Result of a save attempt, reported by the host's transport layer. */\nexport type AdminSaveOutcome =\n | { status: 'saved'; version?: string }\n | { status: 'conflict' }\n | { status: 'invalid'; errors: readonly FieldErrorLike[] }\n | { status: 'error'; message?: string };\n\nexport interface AdminEditorProps {\n /** Document to edit, typically loaded from `GET /api/admin/export`. */\n initialDocument: Takuhon;\n /** Persist the document. The editor validates client-side first. */\n onSave: (document: Takuhon) => Promise<AdminSaveOutcome>;\n /** Re-fetch the stored document, replacing the working draft. */\n onReload?: () => Promise<Takuhon>;\n /** Download / hand off the current draft (Export button). */\n onExport?: (document: Takuhon) => void;\n /**\n * Provide a document to load (Import button). Returns raw parsed JSON, which\n * the editor validates; `undefined` cancels. Validation lives here so an\n * invalid file cannot break the draft invariant.\n */\n onImport?: () => Promise<unknown>;\n formatLocale?: (locale: LocaleTag) => string;\n /**\n * Upload an avatar image file (host-supplied; carries the admin token). When\n * provided, the profile form's avatar field offers a file picker; otherwise\n * the avatar stays URL-only.\n */\n uploadAsset?: UploadAsset;\n}\n\ntype Mode = 'form' | 'advanced';\ntype Tone = 'info' | 'success' | 'error';\ninterface Status {\n tone: Tone;\n message: string;\n}\n\n/**\n * Top-level admin editor: holds the working draft, switches between the field\n * forms and the raw-JSON advanced mode, and runs client-side validation before\n * delegating persistence to the host via `onSave` (transport-agnostic). Server\n * (RFC 7807) and client (`validate`) errors map to the same fields.\n */\nexport function AdminEditor({\n initialDocument,\n onSave,\n onReload,\n onExport,\n onImport,\n formatLocale,\n uploadAsset,\n}: AdminEditorProps): React.JSX.Element {\n const [draft, setDraft] = useState<Takuhon>(initialDocument);\n const [mode, setMode] = useState<Mode>('form');\n const [errors, setErrors] = useState<FieldErrorIndex>(NO_FIELD_ERRORS);\n const [status, setStatus] = useState<Status | null>(null);\n const [busy, setBusy] = useState(false);\n // Bumped whenever the document is replaced wholesale (reload / import) to\n // remount the raw-JSON editor so its text re-seeds from the new draft.\n const [loadGen, setLoadGen] = useState(0);\n // Identifies the latest user intent. A save reads it after awaiting `onSave`\n // and discards its outcome if an edit (which bumps the counter) landed\n // meanwhile — preventing a stale \"Saved.\" or stale server errors.\n const intentRef = useRef(0);\n\n const locales = draft.settings.availableLocales;\n\n // Any edit clears the previous validation snapshot so resolved errors do not\n // linger while the operator works through them, and invalidates any in-flight\n // save outcome.\n const updateDraft = (next: Takuhon): void => {\n intentRef.current += 1;\n setDraft(next);\n setErrors(NO_FIELD_ERRORS);\n setStatus(null);\n };\n\n const loadDocument = (next: Takuhon, message: Status | null): void => {\n intentRef.current += 1;\n setDraft(next);\n setErrors(NO_FIELD_ERRORS);\n setStatus(message);\n setLoadGen((generation) => generation + 1);\n };\n\n const handleSave = async (): Promise<void> => {\n const result = validate(draft);\n if (!result.ok) {\n setErrors(indexValidationErrors(result.errors));\n setStatus({ tone: 'error', message: getAdminLabel('status.invalid') });\n return;\n }\n setErrors(NO_FIELD_ERRORS);\n intentRef.current += 1;\n const intent = intentRef.current;\n setBusy(true);\n setStatus({ tone: 'info', message: getAdminLabel('status.saving') });\n try {\n const outcome = await onSave(result.data);\n if (intent !== intentRef.current) return; // an edit landed mid-save; ignore\n switch (outcome.status) {\n case 'saved':\n setStatus({ tone: 'success', message: getAdminLabel('status.saved') });\n break;\n case 'conflict':\n setStatus({ tone: 'error', message: getAdminLabel('status.conflict') });\n break;\n case 'invalid':\n setErrors(indexErrors(outcome.errors));\n setStatus({ tone: 'error', message: getAdminLabel('status.invalid') });\n break;\n case 'error':\n setStatus({ tone: 'error', message: outcome.message ?? getAdminLabel('status.error') });\n break;\n }\n } catch {\n if (intent === intentRef.current) {\n setStatus({ tone: 'error', message: getAdminLabel('status.error') });\n }\n } finally {\n setBusy(false);\n }\n };\n\n const handleReload = async (): Promise<void> => {\n if (!onReload) return;\n setBusy(true);\n setStatus({ tone: 'info', message: getAdminLabel('status.loading') });\n try {\n const next = await onReload();\n loadDocument(next, null);\n } catch {\n setStatus({ tone: 'error', message: getAdminLabel('status.error') });\n } finally {\n setBusy(false);\n }\n };\n\n const handleImport = async (): Promise<void> => {\n if (!onImport) return;\n try {\n const raw = await onImport();\n if (raw === undefined) return;\n const result = validate(raw);\n if (!result.ok) {\n setStatus({ tone: 'error', message: getAdminLabel('status.importInvalid') });\n return;\n }\n loadDocument(result.data, {\n tone: 'info',\n message: getAdminLabel('status.imported'),\n });\n } catch {\n setStatus({ tone: 'error', message: getAdminLabel('status.error') });\n }\n };\n\n // Flattened error list for the summary. This is the safety net that surfaces\n // failures in sections without a dedicated form (e.g. meta, education): their\n // pointers would otherwise map to no visible field.\n const errorEntries = [...errors].flatMap(([pointer, messages]) =>\n messages.map((message) => ({ pointer, message })),\n );\n\n return (\n <div className={styles.editor}>\n <div className={styles.toolbar} role=\"toolbar\" aria-label={getAdminLabel('toolbar.label')}>\n <div className={styles.modes} role=\"group\" aria-label={getAdminLabel('mode.label')}>\n <button\n type=\"button\"\n className={`${styles.modeButton} ${mode === 'form' ? styles.modeActive : ''}`}\n aria-pressed={mode === 'form'}\n onClick={() => {\n setMode('form');\n }}\n >\n {getAdminLabel('mode.form')}\n </button>\n <button\n type=\"button\"\n className={`${styles.modeButton} ${mode === 'advanced' ? styles.modeActive : ''}`}\n aria-pressed={mode === 'advanced'}\n onClick={() => {\n setMode('advanced');\n }}\n >\n {getAdminLabel('mode.advanced')}\n </button>\n </div>\n <div className={styles.actions}>\n <button\n type=\"button\"\n className={styles.primary}\n disabled={busy}\n onClick={() => {\n void handleSave();\n }}\n >\n {getAdminLabel('action.save')}\n </button>\n {onReload ? (\n <button\n type=\"button\"\n className={styles.secondary}\n disabled={busy}\n onClick={() => {\n void handleReload();\n }}\n >\n {getAdminLabel('action.reload')}\n </button>\n ) : null}\n {onExport ? (\n <button\n type=\"button\"\n className={styles.secondary}\n onClick={() => {\n onExport(draft);\n }}\n >\n {getAdminLabel('action.export')}\n </button>\n ) : null}\n {onImport ? (\n <button\n type=\"button\"\n className={styles.secondary}\n disabled={busy}\n onClick={() => {\n void handleImport();\n }}\n >\n {getAdminLabel('action.import')}\n </button>\n ) : null}\n </div>\n </div>\n\n <p className={styles.status} role=\"status\" aria-live=\"polite\" data-tone={status?.tone}>\n {status?.message ?? ''}\n </p>\n\n {errorEntries.length > 0 ? (\n <section className={styles.summary} aria-labelledby=\"admin-error-summary\">\n <h2 className={styles.summaryHeading} id=\"admin-error-summary\">\n {getAdminLabel('status.fixSummary')}\n </h2>\n <ul>\n {errorEntries.map((entry, i) => (\n <li key={i}>\n {entry.pointer === ''\n ? entry.message\n : `${entry.pointer.replace(/^\\//, '')}: ${entry.message}`}\n </li>\n ))}\n </ul>\n </section>\n ) : null}\n\n {mode === 'form' ? (\n <div className={styles.sections}>\n <ProfileForm\n value={draft.profile}\n onChange={(profile) => {\n updateDraft({ ...draft, profile });\n }}\n locales={locales}\n errors={errors}\n formatLocale={formatLocale}\n uploadAsset={uploadAsset}\n />\n <LinksForm\n value={draft.links}\n onChange={(links) => {\n updateDraft({ ...draft, links });\n }}\n locales={locales}\n errors={errors}\n formatLocale={formatLocale}\n />\n <CareersForm\n value={draft.careers}\n onChange={(careers) => {\n updateDraft({ ...draft, careers });\n }}\n locales={locales}\n errors={errors}\n formatLocale={formatLocale}\n />\n <ProjectsForm\n value={draft.projects}\n onChange={(projects) => {\n updateDraft({ ...draft, projects });\n }}\n locales={locales}\n errors={errors}\n formatLocale={formatLocale}\n />\n <SkillsForm\n value={draft.skills}\n onChange={(skills) => {\n updateDraft({ ...draft, skills });\n }}\n errors={errors}\n />\n <SettingsForm\n value={draft.settings}\n onChange={(settings) => {\n updateDraft({ ...draft, settings });\n }}\n errors={errors}\n formatLocale={formatLocale}\n />\n </div>\n ) : (\n <RawJsonEditor key={loadGen} value={draft} onChange={updateDraft} />\n )}\n </div>\n );\n}\n"],"mappings":"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","names":["styles","jsx","styles","jsx","styles","jsx","useId","styles","jsx","jsxs","useId","styles","jsx","jsxs","useId","useState","styles","controls","Fragment","jsx","jsxs","useState","useId","useRef","useState","styles","Fragment","jsx","jsxs","useId","useState","useRef","styles","jsx","jsxs","styles","jsx","jsxs","Fragment","jsx","jsxs","Fragment","jsx","jsxs","Fragment","jsx","jsxs","Fragment","jsx","jsxs","styles","jsx","jsxs","useId","useState","styles","jsx","jsxs","useState","useId","styles","validate","useRef","useState","styles","jsx","jsxs","useState","useRef","validate","styles"]}
1
+ {"version":3,"sources":["../../src/admin/index.ts","../../src/admin/errors.ts","../../src/admin/primitives/Field.tsx","../../src/admin/primitives/TextField.tsx","../../src/admin/primitives/TextAreaField.tsx","../../src/admin/primitives/SelectField.tsx","../../src/admin/primitives/CheckboxField.tsx","../../src/admin/primitives/ImageField.tsx","../../src/admin/admin-labels.ts","../../src/admin/primitives/GravatarField.tsx","../../src/admin/primitives/LocaleTabs.tsx","../../src/admin/primitives/Repeater.tsx","../../src/admin/sections/ProfileForm.tsx","../../src/admin/ids.ts","../../src/admin/sections/LinksForm.tsx","../../src/admin/localized.ts","../../src/admin/sections/CareersForm.tsx","../../src/admin/sections/ProjectsForm.tsx","../../src/admin/sections/SkillsForm.tsx","../../src/admin/sections/SettingsForm.tsx","../../src/admin/RawJsonEditor.tsx","../../src/admin/AdminEditor.tsx"],"sourcesContent":["/**\n * @takuhon/ui/admin — React form components for the takuhon admin editor.\n *\n * These are the building blocks behind the Cloudflare admin form UI (spec\n * §14.1 Phase 5). They are presentational and transport-agnostic: each is a\n * controlled component that takes a value plus `onChange`, with field errors\n * supplied as a {@link FieldErrorIndex} so server (RFC 7807) and client\n * (`@takuhon/core` `validate`) failures map to the same fields. Co-located CSS\n * Modules are emitted to `dist/admin/` and bundled by the consumer.\n *\n * Importing this entry also pulls in the shared design tokens, so the admin\n * components are themed standalone without depending on the profile UI entry.\n */\n\nimport '../styles/tokens.css';\n\nexport {\n canonicalPointer,\n collectErrorsUnder,\n errorsAt,\n hasErrorsUnder,\n indexErrors,\n indexValidationErrors,\n NO_FIELD_ERRORS,\n type FieldErrorIndex,\n type FieldErrorLike,\n} from './errors.js';\n\nexport { Field, type FieldProps, type FieldControlProps } from './primitives/Field.js';\nexport { TextField, type TextFieldProps } from './primitives/TextField.js';\nexport { TextAreaField, type TextAreaFieldProps } from './primitives/TextAreaField.js';\nexport { SelectField, type SelectFieldProps, type SelectOption } from './primitives/SelectField.js';\nexport { CheckboxField, type CheckboxFieldProps } from './primitives/CheckboxField.js';\nexport {\n ImageField,\n type ImageFieldProps,\n type AssetUploadResult,\n type UploadAsset,\n} from './primitives/ImageField.js';\nexport { GravatarField, type GravatarFieldProps } from './primitives/GravatarField.js';\nexport { LocaleTabs, type LocaleTabsProps } from './primitives/LocaleTabs.js';\nexport { Repeater, type RepeaterProps } from './primitives/Repeater.js';\n\nexport { getAdminLabel, type AdminLabelKey } from './admin-labels.js';\n\nexport { ProfileForm, type ProfileFormProps } from './sections/ProfileForm.js';\nexport { LinksForm, type LinksFormProps } from './sections/LinksForm.js';\nexport { CareersForm, type CareersFormProps } from './sections/CareersForm.js';\nexport { ProjectsForm, type ProjectsFormProps } from './sections/ProjectsForm.js';\nexport { SkillsForm, type SkillsFormProps } from './sections/SkillsForm.js';\nexport { SettingsForm, type SettingsFormProps } from './sections/SettingsForm.js';\n\nexport { RawJsonEditor, type RawJsonEditorProps } from './RawJsonEditor.js';\nexport { AdminEditor, type AdminEditorProps, type AdminSaveOutcome } from './AdminEditor.js';\n","/**\n * Field-error plumbing shared by the admin form components.\n *\n * Validation failures reach the editor in two shapes that mean the same thing:\n *\n * - `@takuhon/core`'s {@link ValidationError}, produced by a client-side\n * `validate()` call, carries an RFC 6901 `pointer` such as\n * `\"/profile/displayName/en\"`.\n * - The server's RFC 7807 response (`api.md §5`) carries the same location as a\n * `path` with a leading `#` fragment marker, e.g. `\"#/profile/displayName/en\"`.\n *\n * Both are normalized to a single canonical pointer so a field can look up its\n * own errors regardless of where they came from.\n */\nimport type { ValidationError } from '@takuhon/core';\n\n/** A field error in either the core (`pointer`) or RFC 7807 wire (`path`) shape. */\nexport interface FieldErrorLike {\n pointer?: string;\n path?: string;\n message: string;\n}\n\n/**\n * Canonical RFC 6901 pointer: no leading `#`, a leading `/` for any non-root\n * location, and `\"\"` for the document root. Idempotent.\n */\nexport function canonicalPointer(raw: string): string {\n let pointer = raw.trim();\n if (pointer.startsWith('#')) pointer = pointer.slice(1);\n if (pointer !== '' && !pointer.startsWith('/')) pointer = `/${pointer}`;\n return pointer;\n}\n\n/** Maps a canonical pointer to the messages reported at that exact location. */\nexport type FieldErrorIndex = ReadonlyMap<string, readonly string[]>;\n\n/** Group a flat error list by canonical pointer, preserving message order. */\nexport function indexErrors(errors: readonly FieldErrorLike[]): FieldErrorIndex {\n const index = new Map<string, string[]>();\n for (const error of errors) {\n const key = canonicalPointer(error.pointer ?? error.path ?? '');\n const existing = index.get(key);\n if (existing) existing.push(error.message);\n else index.set(key, [error.message]);\n }\n return index;\n}\n\n/** Convenience over {@link indexErrors} for a core `validate()` failure list. */\nexport function indexValidationErrors(errors: readonly ValidationError[]): FieldErrorIndex {\n return indexErrors(errors);\n}\n\n/** Messages reported at exactly `pointer` (empty array when none). */\nexport function errorsAt(index: FieldErrorIndex, pointer: string): readonly string[] {\n return index.get(canonicalPointer(pointer)) ?? [];\n}\n\n/**\n * Whether any error sits at or below `prefix` — used to badge a section or a\n * repeater item that contains an invalid field deeper in the tree.\n */\nexport function hasErrorsUnder(index: FieldErrorIndex, prefix: string): boolean {\n const base = canonicalPointer(prefix);\n for (const key of index.keys()) {\n if (key === base || key.startsWith(`${base}/`)) return true;\n }\n return false;\n}\n\n/**\n * All messages at or below `prefix`, in pointer order. Used by aggregate\n * controls (a comma-separated list edited as one field) so item-level failures\n * reported at `${prefix}/${itemIndex}` still surface on the single input.\n */\nexport function collectErrorsUnder(index: FieldErrorIndex, prefix: string): string[] {\n const base = canonicalPointer(prefix);\n const messages: string[] = [];\n for (const [key, list] of index) {\n if (key === base || key.startsWith(`${base}/`)) messages.push(...list);\n }\n return messages;\n}\n\n/** An empty index, handy as a default prop. */\nexport const NO_FIELD_ERRORS: FieldErrorIndex = new Map();\n","import { useId } from 'react';\n\nimport styles from './Field.module.css';\n\n/** Identifiers a {@link Field} hands to the control it wraps. */\nexport interface FieldControlProps {\n /** `id` for the control, paired with the rendered `<label htmlFor>`. */\n controlId: string;\n /** `aria-describedby` value linking the control to its hint/error text. */\n describedBy: string | undefined;\n /** Whether the control should advertise `aria-invalid`. */\n invalid: boolean;\n}\n\nexport interface FieldProps {\n /** Visible label text. */\n label: string;\n /** Validation messages to render beneath the control. */\n errors?: readonly string[];\n /** Optional helper text shown between the label and the control. */\n hint?: string;\n /** Marks the field visually and via `aria-required` on the control. */\n required?: boolean;\n /** Render the control, wired with the supplied accessibility ids. */\n children: (props: FieldControlProps) => React.ReactNode;\n}\n\n/**\n * Layout + accessibility wrapper for a single form control. Owns the `id`\n * wiring so the label, hint, error list, and control stay associated for\n * screen readers (WCAG 2.1 AA, spec §8.5). Presentational only — it holds no\n * value state; the wrapped control is controlled by its parent.\n */\nexport function Field({ label, errors, hint, required, children }: FieldProps): React.JSX.Element {\n const controlId = useId();\n const hintId = useId();\n const errorId = useId();\n const hasErrors = (errors?.length ?? 0) > 0;\n const describedBy =\n [hint ? hintId : undefined, hasErrors ? errorId : undefined].filter(Boolean).join(' ') ||\n undefined;\n\n return (\n <div className={styles.field}>\n <label className={styles.label} htmlFor={controlId}>\n {label}\n {required ? <span aria-hidden=\"true\"> *</span> : null}\n </label>\n {hint ? (\n <p className={styles.hint} id={hintId}>\n {hint}\n </p>\n ) : null}\n {children({ controlId, describedBy, invalid: hasErrors })}\n {hasErrors ? (\n <ul className={styles.errors} id={errorId}>\n {errors!.map((message, i) => (\n <li key={i}>{message}</li>\n ))}\n </ul>\n ) : null}\n </div>\n );\n}\n","import { Field } from './Field.js';\nimport styles from './controls.module.css';\n\nexport interface TextFieldProps {\n label: string;\n value: string;\n onChange: (value: string) => void;\n errors?: readonly string[];\n hint?: string;\n required?: boolean;\n placeholder?: string;\n /**\n * HTML input type. Defaults to `'text'`; `'url'` for link/avatar URLs,\n * `'month'` for `YearMonth` values (a native month picker emits `YYYY-MM`).\n */\n type?: 'text' | 'url' | 'email' | 'month';\n inputMode?: React.HTMLAttributes<HTMLInputElement>['inputMode'];\n}\n\n/** A labelled single-line text input wired for accessibility via {@link Field}. */\nexport function TextField({\n label,\n value,\n onChange,\n errors,\n hint,\n required,\n placeholder,\n type = 'text',\n inputMode,\n}: TextFieldProps): React.JSX.Element {\n return (\n <Field label={label} errors={errors} hint={hint} required={required}>\n {({ controlId, describedBy, invalid }) => (\n <input\n id={controlId}\n className={styles.control}\n type={type}\n value={value}\n placeholder={placeholder}\n inputMode={inputMode}\n aria-invalid={invalid || undefined}\n aria-required={required ? true : undefined}\n aria-describedby={describedBy}\n onChange={(event) => {\n onChange(event.target.value);\n }}\n />\n )}\n </Field>\n );\n}\n","import { Field } from './Field.js';\nimport styles from './controls.module.css';\n\nexport interface TextAreaFieldProps {\n label: string;\n value: string;\n onChange: (value: string) => void;\n errors?: readonly string[];\n hint?: string;\n required?: boolean;\n placeholder?: string;\n rows?: number;\n}\n\n/** A labelled multi-line text input wired for accessibility via {@link Field}. */\nexport function TextAreaField({\n label,\n value,\n onChange,\n errors,\n hint,\n required,\n placeholder,\n rows = 4,\n}: TextAreaFieldProps): React.JSX.Element {\n return (\n <Field label={label} errors={errors} hint={hint} required={required}>\n {({ controlId, describedBy, invalid }) => (\n <textarea\n id={controlId}\n className={`${styles.control} ${styles.textarea}`}\n value={value}\n rows={rows}\n placeholder={placeholder}\n aria-invalid={invalid || undefined}\n aria-required={required ? true : undefined}\n aria-describedby={describedBy}\n onChange={(event) => {\n onChange(event.target.value);\n }}\n />\n )}\n </Field>\n );\n}\n","import { Field } from './Field.js';\nimport styles from './controls.module.css';\n\nexport interface SelectOption {\n value: string;\n label: string;\n}\n\nexport interface SelectFieldProps {\n label: string;\n value: string;\n options: readonly SelectOption[];\n onChange: (value: string) => void;\n errors?: readonly string[];\n hint?: string;\n required?: boolean;\n}\n\n/** A labelled `<select>` wired for accessibility via {@link Field}. */\nexport function SelectField({\n label,\n value,\n options,\n onChange,\n errors,\n hint,\n required,\n}: SelectFieldProps): React.JSX.Element {\n return (\n <Field label={label} errors={errors} hint={hint} required={required}>\n {({ controlId, describedBy, invalid }) => (\n <select\n id={controlId}\n className={styles.control}\n value={value}\n aria-invalid={invalid || undefined}\n aria-required={required ? true : undefined}\n aria-describedby={describedBy}\n onChange={(event) => {\n onChange(event.target.value);\n }}\n >\n {options.map((option) => (\n <option key={option.value} value={option.value}>\n {option.label}\n </option>\n ))}\n </select>\n )}\n </Field>\n );\n}\n","import { useId } from 'react';\n\nimport styles from './controls.module.css';\n\nexport interface CheckboxFieldProps {\n label: string;\n checked: boolean;\n onChange: (checked: boolean) => void;\n}\n\n/**\n * A labelled checkbox. Laid out checkbox-first (distinct from the stacked\n * {@link Field} controls), with the label associated via `htmlFor`.\n */\nexport function CheckboxField({ label, checked, onChange }: CheckboxFieldProps): React.JSX.Element {\n const id = useId();\n return (\n <div className={styles.checkboxRow}>\n <input\n id={id}\n className={styles.checkbox}\n type=\"checkbox\"\n checked={checked}\n onChange={(event) => {\n onChange(event.target.checked);\n }}\n />\n <label className={styles.checkboxLabel} htmlFor={id}>\n {label}\n </label>\n </div>\n );\n}\n","import { useId, useRef, useState } from 'react';\n\nimport { getAdminLabel } from '../admin-labels.js';\n\nimport { Field } from './Field.js';\nimport styles from './ImageField.module.css';\nimport controls from './controls.module.css';\n\n/** Outcome of an asset upload, returned by {@link UploadAsset}. */\nexport type AssetUploadResult =\n | { status: 'uploaded'; url: string; publicUrl: string }\n | { status: 'error'; message?: string };\n\n/**\n * Upload one image file and resolve where it now lives. Supplied by the host's\n * transport layer (it carries the admin token / origin); the UI stays\n * transport-agnostic.\n */\nexport type UploadAsset = (file: File) => Promise<AssetUploadResult>;\n\n/** `accept` attribute matching the MIME types the server accepts (security.md §4.1). */\nconst ACCEPT = 'image/jpeg,image/png,image/webp,image/gif';\n\nexport interface ImageFieldProps {\n label: string;\n /** Current image URL stored in the document. */\n value: string;\n onChange: (url: string) => void;\n errors?: readonly string[];\n hint?: string;\n /**\n * When provided, a file-upload control is rendered alongside the URL input;\n * a successful upload sets the URL to the returned (relative) path. When\n * omitted, the field is URL-only.\n */\n uploadAsset?: UploadAsset;\n}\n\n/**\n * Avatar / image field: a URL input plus, when {@link ImageFieldProps.uploadAsset}\n * is supplied, a file picker that uploads the chosen image and writes the\n * returned URL back into the field. The relative `url` (not the absolute\n * `publicUrl`) is stored so the reference stays valid across origins.\n *\n * No `<img>` preview is rendered: the admin CSP is `img-src 'self' blob:`, so a\n * preview of an arbitrary external URL would be blocked — the URL input is the\n * portable, CSP-safe surface, and the public preview shows the real image.\n */\nexport function ImageField({\n label,\n value,\n onChange,\n errors,\n hint,\n uploadAsset,\n}: ImageFieldProps): React.JSX.Element {\n const fileId = useId();\n const statusId = useId();\n const fileRef = useRef<HTMLInputElement>(null);\n const [busy, setBusy] = useState(false);\n const [uploadError, setUploadError] = useState<string | null>(null);\n\n const handleFile = (event: React.ChangeEvent<HTMLInputElement>): void => {\n const file = event.target.files?.[0];\n if (!file || uploadAsset === undefined) return;\n setBusy(true);\n setUploadError(null);\n uploadAsset(file)\n .then((result) => {\n if (result.status === 'uploaded') {\n onChange(result.url);\n } else {\n setUploadError(result.message ?? getAdminLabel('status.uploadError'));\n }\n })\n .catch(() => {\n setUploadError(getAdminLabel('status.uploadError'));\n })\n .finally(() => {\n setBusy(false);\n // Clear the picker so re-selecting the same file fires `change` again.\n if (fileRef.current) fileRef.current.value = '';\n });\n };\n\n return (\n <Field label={label} errors={errors} hint={hint}>\n {({ controlId, describedBy, invalid }) => (\n <>\n <input\n id={controlId}\n className={controls.control}\n type=\"url\"\n value={value}\n aria-invalid={invalid || undefined}\n aria-describedby={describedBy}\n onChange={(event) => {\n onChange(event.target.value);\n }}\n />\n {uploadAsset !== undefined ? (\n <div className={styles.uploadRow}>\n <label className={styles.uploadLabel} htmlFor={fileId}>\n {getAdminLabel('field.avatarUpload')}\n </label>\n <input\n id={fileId}\n ref={fileRef}\n type=\"file\"\n accept={ACCEPT}\n disabled={busy}\n aria-describedby={statusId}\n onChange={handleFile}\n />\n <span className={styles.uploadStatus} id={statusId} role=\"status\" aria-live=\"polite\">\n {busy ? getAdminLabel('status.uploading') : ''}\n </span>\n {uploadError !== null ? (\n <span className={styles.uploadError} role=\"alert\">\n {uploadError}\n </span>\n ) : null}\n </div>\n ) : null}\n </>\n )}\n </Field>\n );\n}\n","/**\n * UI strings for the admin editor.\n *\n * The admin surface is operator-only, so a single English dictionary ships\n * today; the lookup mirrors `getUILabel` (exact locale → base subtag →\n * English) so locales can be added later without touching call sites. Keys are\n * derived from the English dictionary, so every key is guaranteed to resolve.\n */\nimport type { LocaleTag } from '@takuhon/core';\n\nconst EN = {\n 'app.title': 'takuhon admin',\n 'toolbar.label': 'Editor actions',\n 'mode.label': 'Editing mode',\n 'mode.form': 'Form',\n 'mode.advanced': 'Advanced (JSON)',\n\n 'action.save': 'Save',\n 'action.reload': 'Reload',\n 'action.export': 'Export',\n 'action.import': 'Import',\n 'action.add': 'Add',\n 'action.remove': 'Remove',\n 'action.moveUp': 'Move up',\n 'action.moveDown': 'Move down',\n\n 'status.saving': 'Saving…',\n 'status.saved': 'Saved.',\n 'status.loading': 'Loading…',\n 'status.conflict':\n 'The profile changed on the server since it was loaded. Reload, then reapply the edits.',\n 'status.invalid': 'Some fields need attention before saving.',\n 'status.fixSummary': 'Please fix the following:',\n 'status.error': 'Something went wrong. Please try again.',\n 'status.imported': 'Imported. Review the fields, then save to apply.',\n 'status.importInvalid': 'The imported file is not a valid takuhon document.',\n 'status.uploading': 'Uploading…',\n 'status.uploadError': 'Upload failed. Please try again.',\n\n 'section.profile': 'Profile',\n 'section.about': 'About',\n 'section.links': 'Links',\n 'section.careers': 'Experience',\n 'section.projects': 'Projects',\n 'section.skills': 'Skills',\n 'section.settings': 'Settings',\n\n 'field.displayName': 'Display name',\n 'field.tagline': 'Tagline',\n 'field.bio': 'Bio',\n 'field.avatarUrl': 'Avatar URL',\n 'field.avatarUpload': 'Upload image',\n 'field.avatarAlt': 'Avatar alternative text',\n 'field.gravatarEmail': 'Gravatar email',\n 'field.gravatarApply': 'Use Gravatar',\n 'field.location.country': 'Country',\n 'field.location.region': 'Region',\n 'field.location.locality': 'Locality',\n 'field.location.display': 'Location (display)',\n\n 'field.link.type': 'Type',\n 'field.link.url': 'URL',\n 'field.link.label': 'Label',\n 'field.link.iconUrl': 'Icon URL',\n 'field.link.featured': 'Featured',\n\n 'field.career.organization': 'Organization',\n 'field.career.role': 'Role',\n 'field.career.description': 'Description',\n 'field.career.startDate': 'Start',\n 'field.career.endDate': 'End',\n 'field.career.isCurrent': 'Current position',\n 'field.career.url': 'URL',\n\n 'field.project.title': 'Title',\n 'field.project.description': 'Description',\n 'field.project.url': 'URL',\n 'field.project.tags': 'Tags',\n 'field.project.highlighted': 'Highlighted',\n 'field.project.startDate': 'Start',\n 'field.project.endDate': 'End',\n\n 'field.skill.label': 'Label',\n 'field.skill.category': 'Category',\n\n 'field.settings.defaultLocale': 'Default locale',\n 'field.settings.fallbackLocale': 'Fallback locale',\n 'field.settings.availableLocales': 'Available locales',\n 'field.settings.theme': 'Theme',\n 'field.settings.showPoweredBy': 'Show the \"Powered by takuhon\" footer',\n 'field.settings.enableJsonLd': 'Emit Schema.org JSON-LD',\n 'field.settings.enableApi': 'Expose the public read API',\n 'field.settings.enableAnalytics': 'Enable first-party analytics',\n\n 'field.settings.publicVisibility': 'Public sections',\n 'field.publicVisibility.links': 'Links',\n 'field.publicVisibility.careers': 'Experience',\n 'field.publicVisibility.projects': 'Projects',\n 'field.publicVisibility.skills': 'Skills',\n 'field.publicVisibility.certifications': 'Certifications',\n 'field.publicVisibility.memberships': 'Memberships',\n 'field.publicVisibility.volunteering': 'Volunteering',\n 'field.publicVisibility.honors': 'Honors & awards',\n 'field.publicVisibility.education': 'Education',\n 'field.publicVisibility.publications': 'Publications',\n 'field.publicVisibility.languages': 'Languages',\n 'field.publicVisibility.courses': 'Courses',\n 'field.publicVisibility.patents': 'Patents',\n 'field.publicVisibility.testScores': 'Test scores',\n 'field.publicVisibility.recommendations': 'Recommendations',\n 'field.publicVisibility.contact': 'Contact',\n\n 'item.link': 'Link',\n 'item.career': 'Position',\n 'item.project': 'Project',\n 'item.skill': 'Skill',\n\n 'empty.links': 'No links yet.',\n 'empty.careers': 'No positions yet.',\n 'empty.projects': 'No projects yet.',\n 'empty.skills': 'No skills yet.',\n\n 'hint.avatarNoUpload': 'Paste an image URL. Uploading image files is not available yet.',\n 'hint.avatarUpload': 'Paste an image URL, or upload a JPEG, PNG, WebP, or GIF.',\n 'hint.gravatar':\n 'Enter an email to generate a Gravatar avatar URL. The email is not saved — only the resulting URL is stored.',\n 'hint.month': 'Format: YYYY-MM (e.g. 2024-03).',\n 'hint.country': 'ISO 3166-1 alpha-2 code, e.g. US.',\n 'hint.tags': 'Comma-separated.',\n 'hint.locales': 'Comma-separated BCP-47 tags, e.g. en, ja. Drives the language tabs above.',\n 'hint.publicVisibility':\n 'Unchecked sections are hidden from every public surface (page, API, JSON-LD). All sections are public by default.',\n 'advanced.hint': 'Edit the entire document as JSON. Edits apply only while the JSON is valid.',\n 'advanced.invalid': 'The JSON is not a valid takuhon document:',\n\n 'option.none': '(none)',\n} as const;\n\n/** Every label key understood by {@link getAdminLabel}. */\nexport type AdminLabelKey = keyof typeof EN;\n\nconst DICTIONARIES: Partial<Record<LocaleTag, Partial<Record<AdminLabelKey, string>>>> = {\n en: EN,\n};\n\n/**\n * Resolve an admin label for a locale, falling back to the base language\n * subtag and then English. English is always present, so the return is always\n * a string.\n */\nexport function getAdminLabel(key: AdminLabelKey, locale: LocaleTag = 'en'): string {\n const exact = DICTIONARIES[locale]?.[key];\n if (exact !== undefined) return exact;\n const base = locale.split('-')[0];\n const baseMatch = base ? DICTIONARIES[base]?.[key] : undefined;\n return baseMatch ?? EN[key];\n}\n","import { gravatarUrl } from '@takuhon/core';\nimport { useState } from 'react';\n\nimport { getAdminLabel } from '../admin-labels.js';\n\nimport { Field } from './Field.js';\nimport styles from './GravatarField.module.css';\nimport controls from './controls.module.css';\n\nexport interface GravatarFieldProps {\n /** Called with the generated Gravatar URL when the owner applies an email. */\n onApply: (url: string) => void;\n}\n\n/**\n * \"Use Gravatar\" control: an email input plus a button that turns the email into\n * a Gravatar avatar URL via core's pure {@link gravatarUrl}. This is the third\n * way to set an avatar, alongside pasting a URL and uploading an image.\n *\n * The email is local-only — it is never written to the document or sent\n * anywhere. Only the generated URL is handed to {@link GravatarFieldProps.onApply}\n * (which the parent writes into `avatar.url`); the email input is cleared once\n * applied, so nothing about the address lingers in the form.\n */\nexport function GravatarField({ onApply }: GravatarFieldProps): React.JSX.Element {\n const [email, setEmail] = useState('');\n const trimmed = email.trim();\n\n const apply = (): void => {\n if (trimmed === '') return;\n onApply(gravatarUrl(trimmed));\n setEmail('');\n };\n\n return (\n <Field label={getAdminLabel('field.gravatarEmail')} hint={getAdminLabel('hint.gravatar')}>\n {({ controlId, describedBy }) => (\n <>\n <input\n id={controlId}\n className={controls.control}\n type=\"email\"\n value={email}\n autoComplete=\"off\"\n aria-describedby={describedBy}\n onChange={(event) => {\n setEmail(event.target.value);\n }}\n onKeyDown={(event) => {\n if (event.key === 'Enter') {\n event.preventDefault();\n apply();\n }\n }}\n />\n <div className={styles.actionRow}>\n <button\n type=\"button\"\n className={styles.applyButton}\n disabled={trimmed === ''}\n onClick={apply}\n >\n {getAdminLabel('field.gravatarApply')}\n </button>\n </div>\n </>\n )}\n </Field>\n );\n}\n","import type { LocaleTag } from '@takuhon/core';\nimport { useId, useRef, useState } from 'react';\n\nimport { errorsAt, hasErrorsUnder, NO_FIELD_ERRORS, type FieldErrorIndex } from '../errors.js';\n\nimport styles from './LocaleTabs.module.css';\n\nexport interface LocaleTabsProps {\n /** Group label, e.g. `\"Display name\"`. */\n label: string;\n /** Current localized value (BCP-47 tag → string), or undefined when empty. */\n value: Record<LocaleTag, string> | undefined;\n /** Locales offered as tabs (typically `settings.availableLocales`). */\n locales: readonly LocaleTag[];\n /**\n * Receives the next localized record. Empty strings are pruned, and a record\n * that becomes empty is reported as `undefined` so the field is omitted\n * rather than emitted as `{}` (which fails the schema's `minProperties`).\n */\n onChange: (next: Record<LocaleTag, string> | undefined) => void;\n /** Render a `<textarea>` instead of an `<input>` for body-length text. */\n multiline?: boolean;\n required?: boolean;\n hint?: string;\n /** Full error index; per-locale errors are looked up at `${pointer}/${locale}`. */\n errors?: FieldErrorIndex;\n /** Base RFC 6901 pointer to this localized field, e.g. `/profile/displayName`. */\n pointer?: string;\n /** Render a friendlier tab label than the raw locale tag. */\n formatLocale?: (locale: LocaleTag) => string;\n}\n\n/**\n * Edits a localized string map (`LocalizedTitle` / `LocalizedBody`) behind one\n * tab per locale (spec §14.2 \"多言語タブ\"). Implements the WAI-ARIA Tabs\n * pattern — roving tabindex, arrow/Home/End navigation, a single shared\n * `tabpanel` — so it stays keyboard-operable and screen-reader-correct\n * (WCAG 2.1 AA, spec §8.5).\n */\nexport function LocaleTabs({\n label,\n value,\n locales,\n onChange,\n multiline = false,\n required,\n hint,\n errors = NO_FIELD_ERRORS,\n pointer,\n formatLocale,\n}: LocaleTabsProps): React.JSX.Element {\n const baseId = useId();\n const hintId = useId();\n const errorId = useId();\n const [active, setActive] = useState<LocaleTag>(() => locales[0] ?? '');\n const tabRefs = useRef<Record<string, HTMLButtonElement | null>>({});\n\n const format = formatLocale ?? ((locale: LocaleTag) => locale);\n const labelId = `${baseId}-label`;\n\n if (locales.length === 0) {\n return (\n <div className={styles.group} role=\"group\" aria-labelledby={labelId}>\n <span className={styles.groupLabel} id={labelId}>\n {label}\n </span>\n <p className={styles.hint}>No locales are configured yet; add one under Settings.</p>\n </div>\n );\n }\n\n // Reconcile the active tab against the current locale list so editing\n // `availableLocales` elsewhere never strands the selection on a stale tag.\n const activeLocale = locales.includes(active) ? active : locales[0]!;\n const text = value?.[activeLocale] ?? '';\n // Errors on the field itself (`required`, `minProperties`,\n // `propertyNames`) land on the base pointer, not on a locale key, so surface\n // both — otherwise a missing-value failure would be invisible.\n const baseErrors = pointer ? errorsAt(errors, pointer) : [];\n const localeErrors = pointer ? errorsAt(errors, `${pointer}/${activeLocale}`) : [];\n const shownErrors = [...baseErrors, ...localeErrors];\n const hasErrors = shownErrors.length > 0;\n const describedBy =\n [hint ? hintId : undefined, hasErrors ? errorId : undefined].filter(Boolean).join(' ') ||\n undefined;\n\n const setText = (next: string): void => {\n const record: Record<string, string> = { ...(value ?? {}) };\n if (next === '') delete record[activeLocale];\n else record[activeLocale] = next;\n onChange(Object.keys(record).length === 0 ? undefined : record);\n };\n\n const onTabKeyDown = (event: React.KeyboardEvent): void => {\n const current = locales.indexOf(activeLocale);\n let nextIndex: number;\n switch (event.key) {\n case 'ArrowRight':\n case 'ArrowDown':\n nextIndex = (current + 1) % locales.length;\n break;\n case 'ArrowLeft':\n case 'ArrowUp':\n nextIndex = (current - 1 + locales.length) % locales.length;\n break;\n case 'Home':\n nextIndex = 0;\n break;\n case 'End':\n nextIndex = locales.length - 1;\n break;\n default:\n return;\n }\n event.preventDefault();\n const nextLocale = locales[nextIndex];\n if (nextLocale !== undefined) {\n setActive(nextLocale);\n tabRefs.current[nextLocale]?.focus();\n }\n };\n\n const controlName = `${label} (${format(activeLocale)})`;\n\n return (\n <div className={styles.group} role=\"group\" aria-labelledby={labelId}>\n <span className={styles.groupLabel} id={labelId}>\n {label}\n {required ? <span aria-hidden=\"true\"> *</span> : null}\n </span>\n {hint ? (\n <p className={styles.hint} id={hintId}>\n {hint}\n </p>\n ) : null}\n <div className={styles.tablist} role=\"tablist\" aria-label={label}>\n {locales.map((locale) => {\n const selected = locale === activeLocale;\n const tabHasErrors = pointer ? hasErrorsUnder(errors, `${pointer}/${locale}`) : false;\n return (\n <button\n key={locale}\n ref={(element) => {\n tabRefs.current[locale] = element;\n }}\n type=\"button\"\n role=\"tab\"\n id={`${baseId}-tab-${locale}`}\n aria-selected={selected}\n aria-controls={`${baseId}-panel`}\n tabIndex={selected ? 0 : -1}\n className={`${styles.tab} ${selected ? styles.tabActive : ''}`}\n onClick={() => {\n setActive(locale);\n }}\n onKeyDown={onTabKeyDown}\n >\n {format(locale)}\n {tabHasErrors ? (\n <>\n <span className={styles.tabError} aria-hidden=\"true\">\n {' '}\n ●\n </span>\n <span className={styles.srOnly}> (has errors)</span>\n </>\n ) : null}\n </button>\n );\n })}\n </div>\n <div\n role=\"tabpanel\"\n id={`${baseId}-panel`}\n aria-labelledby={`${baseId}-tab-${activeLocale}`}\n className={styles.panel}\n >\n {multiline ? (\n <textarea\n className={`${styles.control} ${styles.textarea}`}\n value={text}\n rows={4}\n aria-label={controlName}\n aria-invalid={hasErrors || undefined}\n aria-required={required ? true : undefined}\n aria-describedby={describedBy}\n onChange={(event) => {\n setText(event.target.value);\n }}\n />\n ) : (\n <input\n className={styles.control}\n type=\"text\"\n value={text}\n aria-label={controlName}\n aria-invalid={hasErrors || undefined}\n aria-required={required ? true : undefined}\n aria-describedby={describedBy}\n onChange={(event) => {\n setText(event.target.value);\n }}\n />\n )}\n {hasErrors ? (\n <ul className={styles.errors} id={errorId}>\n {shownErrors.map((message, i) => (\n <li key={i}>{message}</li>\n ))}\n </ul>\n ) : null}\n </div>\n </div>\n );\n}\n","import styles from './Repeater.module.css';\n\nexport interface RepeaterProps<T> {\n /** Group caption rendered as the fieldset legend, e.g. `\"Links\"`. */\n legend: string;\n items: readonly T[];\n /** Receives the next array after an add / remove / reorder / item edit. */\n onChange: (next: T[]) => void;\n /** Render one item's fields; `update` replaces that item in place. */\n renderItem: (item: T, update: (next: T) => void, index: number) => React.ReactNode;\n /** Factory for the entry appended by the Add button. */\n createItem: () => T;\n /** Stable React key per item. Defaults to the index. */\n keyOf?: (item: T, index: number) => string;\n /** Human label for an item, used in the item caption and button names. */\n itemLabel: (item: T, index: number) => string;\n addLabel?: string;\n removeLabel?: string;\n moveUpLabel?: string;\n moveDownLabel?: string;\n /** Shown when there are no items yet. */\n emptyHint?: string;\n}\n\n/**\n * Add / remove / reorder editor for a repeating array field (spec §14.2\n * \"リピーター\"). Reordering uses keyboard-operable Move up / Move down buttons\n * rather than drag-and-drop so the control meets WCAG 2.1 AA (spec §8.5)\n * without a pointer.\n */\nexport function Repeater<T>({\n legend,\n items,\n onChange,\n renderItem,\n createItem,\n keyOf,\n itemLabel,\n addLabel = 'Add',\n removeLabel = 'Remove',\n moveUpLabel = 'Move up',\n moveDownLabel = 'Move down',\n emptyHint,\n}: RepeaterProps<T>): React.JSX.Element {\n const key = keyOf ?? ((_item: T, index: number) => String(index));\n\n const update = (index: number, next: T): void => {\n const copy = items.slice();\n copy[index] = next;\n onChange(copy);\n };\n\n const remove = (index: number): void => {\n onChange(items.filter((_item, i) => i !== index));\n };\n\n const move = (from: number, to: number): void => {\n if (to < 0 || to >= items.length) return;\n const copy = items.slice();\n const [moved] = copy.splice(from, 1);\n if (moved === undefined) return;\n copy.splice(to, 0, moved);\n onChange(copy);\n };\n\n return (\n <fieldset className={styles.fieldset}>\n <legend className={styles.legend}>{legend}</legend>\n {items.length === 0 && emptyHint ? <p className={styles.empty}>{emptyHint}</p> : null}\n <ol className={styles.list}>\n {items.map((item, index) => {\n const caption = itemLabel(item, index);\n return (\n <li key={key(item, index)} className={styles.item}>\n <div role=\"group\" aria-label={caption}>\n <div className={styles.itemHeader}>\n <span className={styles.itemCaption}>{caption}</span>\n <div className={styles.itemActions}>\n <button\n type=\"button\"\n className={styles.iconButton}\n aria-label={`${moveUpLabel}: ${caption}`}\n disabled={index === 0}\n onClick={() => {\n move(index, index - 1);\n }}\n >\n ↑\n </button>\n <button\n type=\"button\"\n className={styles.iconButton}\n aria-label={`${moveDownLabel}: ${caption}`}\n disabled={index === items.length - 1}\n onClick={() => {\n move(index, index + 1);\n }}\n >\n ↓\n </button>\n <button\n type=\"button\"\n className={styles.removeButton}\n aria-label={`${removeLabel}: ${caption}`}\n onClick={() => {\n remove(index);\n }}\n >\n {removeLabel}\n </button>\n </div>\n </div>\n <div className={styles.itemBody}>\n {renderItem(\n item,\n (next) => {\n update(index, next);\n },\n index,\n )}\n </div>\n </div>\n </li>\n );\n })}\n </ol>\n <button\n type=\"button\"\n className={styles.addButton}\n onClick={() => {\n onChange([...items, createItem()]);\n }}\n >\n {addLabel}\n </button>\n </fieldset>\n );\n}\n","import type { Address, Avatar, LocaleTag, Profile } from '@takuhon/core';\n\nimport { getAdminLabel } from '../admin-labels.js';\nimport { errorsAt, NO_FIELD_ERRORS, type FieldErrorIndex } from '../errors.js';\nimport { GravatarField } from '../primitives/GravatarField.js';\nimport { ImageField, type UploadAsset } from '../primitives/ImageField.js';\nimport { LocaleTabs } from '../primitives/LocaleTabs.js';\nimport { TextField } from '../primitives/TextField.js';\n\nimport styles from './sections.module.css';\n\nexport interface ProfileFormProps {\n value: Profile;\n onChange: (next: Profile) => void;\n locales: readonly LocaleTag[];\n errors?: FieldErrorIndex;\n formatLocale?: (locale: LocaleTag) => string;\n /**\n * Upload an avatar image file. When provided, the avatar field offers a file\n * picker; when omitted, it stays URL-only.\n */\n uploadAsset?: UploadAsset;\n}\n\nconst POINTER = '/profile';\n\nfunction isEmptyRecord(record: Record<string, string> | undefined): boolean {\n return !record || Object.keys(record).length === 0;\n}\n\n/**\n * Basic profile + About: display name, tagline, bio, avatar, and a structured\n * location (spec §6.5 / §14.2). The avatar accepts a URL and, when\n * `uploadAsset` is supplied by the host, an uploaded image file.\n */\nexport function ProfileForm({\n value,\n onChange,\n locales,\n errors = NO_FIELD_ERRORS,\n formatLocale,\n uploadAsset,\n}: ProfileFormProps): React.JSX.Element {\n const updateAvatar = (patch: Partial<Avatar>): void => {\n const merged: Avatar = { url: '', ...value.avatar, ...patch };\n const keep = merged.url !== '' || !isEmptyRecord(merged.alt);\n onChange({ ...value, avatar: keep ? merged : undefined });\n };\n\n const updateLocation = (patch: Partial<Address>): void => {\n const merged: Address = { ...value.location, ...patch };\n const empty =\n !merged.country &&\n !merged.region &&\n isEmptyRecord(merged.locality) &&\n isEmptyRecord(merged.display);\n onChange({ ...value, location: empty ? undefined : merged });\n };\n\n const headingId = 'admin-section-profile';\n\n return (\n <section className={styles.section} aria-labelledby={headingId}>\n <h2 className={styles.heading} id={headingId}>\n {getAdminLabel('section.profile')}\n </h2>\n\n <LocaleTabs\n label={getAdminLabel('field.displayName')}\n value={value.displayName}\n locales={locales}\n onChange={(next) => {\n onChange({ ...value, displayName: next ?? {} });\n }}\n required\n pointer={`${POINTER}/displayName`}\n errors={errors}\n formatLocale={formatLocale}\n />\n\n <LocaleTabs\n label={getAdminLabel('field.tagline')}\n value={value.tagline}\n locales={locales}\n onChange={(next) => {\n onChange({ ...value, tagline: next });\n }}\n pointer={`${POINTER}/tagline`}\n errors={errors}\n formatLocale={formatLocale}\n />\n\n <h3 className={styles.subheading}>{getAdminLabel('section.about')}</h3>\n <LocaleTabs\n label={getAdminLabel('field.bio')}\n value={value.bio}\n locales={locales}\n onChange={(next) => {\n onChange({ ...value, bio: next });\n }}\n multiline\n pointer={`${POINTER}/bio`}\n errors={errors}\n formatLocale={formatLocale}\n />\n\n <ImageField\n label={getAdminLabel('field.avatarUrl')}\n value={value.avatar?.url ?? ''}\n onChange={(url) => {\n updateAvatar({ url });\n }}\n hint={getAdminLabel(uploadAsset ? 'hint.avatarUpload' : 'hint.avatarNoUpload')}\n errors={errorsAt(errors, `${POINTER}/avatar/url`)}\n uploadAsset={uploadAsset}\n />\n <GravatarField\n onApply={(url) => {\n updateAvatar({ url });\n }}\n />\n <LocaleTabs\n label={getAdminLabel('field.avatarAlt')}\n value={value.avatar?.alt}\n locales={locales}\n onChange={(next) => {\n updateAvatar({ alt: next });\n }}\n pointer={`${POINTER}/avatar/alt`}\n errors={errors}\n formatLocale={formatLocale}\n />\n\n <TextField\n label={getAdminLabel('field.location.country')}\n value={value.location?.country ?? ''}\n onChange={(country) => {\n updateLocation({ country: country || undefined });\n }}\n hint={getAdminLabel('hint.country')}\n errors={errorsAt(errors, `${POINTER}/location/country`)}\n />\n <TextField\n label={getAdminLabel('field.location.region')}\n value={value.location?.region ?? ''}\n onChange={(region) => {\n updateLocation({ region: region || undefined });\n }}\n errors={errorsAt(errors, `${POINTER}/location/region`)}\n />\n <LocaleTabs\n label={getAdminLabel('field.location.locality')}\n value={value.location?.locality}\n locales={locales}\n onChange={(next) => {\n updateLocation({ locality: next });\n }}\n pointer={`${POINTER}/location/locality`}\n errors={errors}\n formatLocale={formatLocale}\n />\n </section>\n );\n}\n","/**\n * Build a unique slug like `link-1` that is not already in `taken`. The prefix\n * is lowercased and stripped to `[a-z0-9-]` (falling back to `item`) so the\n * result always matches the `Slug` pattern `^[a-z0-9][a-z0-9-]*$`.\n * Deterministic given the existing ids, so it needs no random source.\n */\nexport function makeId(prefix: string, taken: Iterable<string>): string {\n const safe = prefix.toLowerCase().replace(/[^a-z0-9-]/g, '') || 'item';\n const used = new Set(taken);\n let n = 1;\n while (used.has(`${safe}-${String(n)}`)) n += 1;\n return `${safe}-${String(n)}`;\n}\n","import type { LinkBuiltin, LinkCustom, LinkType, Link, LocaleTag } from '@takuhon/core';\n\nimport { getAdminLabel } from '../admin-labels.js';\nimport { NO_FIELD_ERRORS, errorsAt, type FieldErrorIndex } from '../errors.js';\nimport { makeId } from '../ids.js';\nimport { CheckboxField } from '../primitives/CheckboxField.js';\nimport { LocaleTabs } from '../primitives/LocaleTabs.js';\nimport { Repeater } from '../primitives/Repeater.js';\nimport { SelectField } from '../primitives/SelectField.js';\nimport { TextField } from '../primitives/TextField.js';\n\nexport interface LinksFormProps {\n value: readonly Link[];\n onChange: (next: Link[]) => void;\n locales: readonly LocaleTag[];\n errors?: FieldErrorIndex;\n formatLocale?: (locale: LocaleTag) => string;\n}\n\nconst LINK_TYPES: readonly LinkType[] = [\n 'website',\n 'blog',\n 'github',\n 'gitlab',\n 'linkedin',\n 'x',\n 'mastodon',\n 'bluesky',\n 'instagram',\n 'youtube',\n 'threads',\n 'facebook',\n 'email',\n 'rss',\n 'custom',\n];\n\n/** Re-key a link to a new `type`, preserving common fields and the icon. */\nfunction retypeLink(link: Link, type: LinkType): Link {\n if (type === 'custom') {\n return {\n id: link.id,\n url: link.url,\n label: link.label,\n featured: link.featured,\n order: link.order,\n type: 'custom',\n iconUrl: link.iconUrl ?? '',\n } satisfies LinkCustom;\n }\n const builtin: LinkBuiltin = {\n id: link.id,\n url: link.url,\n label: link.label,\n featured: link.featured,\n order: link.order,\n type,\n };\n if (link.iconUrl) builtin.iconUrl = link.iconUrl;\n return builtin;\n}\n\n/** Set the icon URL, keeping it required for custom links and optional otherwise. */\nfunction setIconUrl(link: Link, iconUrl: string): Link {\n if (link.type === 'custom') return { ...link, iconUrl };\n return { ...link, iconUrl: iconUrl || undefined };\n}\n\n/** SNS / profile links with builtin-vs-custom typing (spec §6.6 / §14.2). */\nexport function LinksForm({\n value,\n onChange,\n locales,\n errors = NO_FIELD_ERRORS,\n formatLocale,\n}: LinksFormProps): React.JSX.Element {\n return (\n <Repeater<Link>\n legend={getAdminLabel('section.links')}\n items={value}\n onChange={onChange}\n keyOf={(link) => link.id}\n itemLabel={(link, index) => link.url || `${getAdminLabel('item.link')} ${String(index + 1)}`}\n createItem={() => ({\n id: makeId(\n 'link',\n value.map((l) => l.id),\n ),\n type: 'website',\n url: '',\n })}\n addLabel={getAdminLabel('action.add')}\n removeLabel={getAdminLabel('action.remove')}\n moveUpLabel={getAdminLabel('action.moveUp')}\n moveDownLabel={getAdminLabel('action.moveDown')}\n emptyHint={getAdminLabel('empty.links')}\n renderItem={(link, update, index) => {\n const at = `/links/${String(index)}`;\n return (\n <>\n <SelectField\n label={getAdminLabel('field.link.type')}\n value={link.type}\n options={LINK_TYPES.map((t) => ({ value: t, label: t }))}\n onChange={(t) => {\n update(retypeLink(link, t as LinkType));\n }}\n errors={errorsAt(errors, `${at}/type`)}\n />\n <TextField\n label={getAdminLabel('field.link.url')}\n type=\"url\"\n value={link.url}\n onChange={(url) => {\n update({ ...link, url });\n }}\n required\n errors={errorsAt(errors, `${at}/url`)}\n />\n <LocaleTabs\n label={getAdminLabel('field.link.label')}\n value={link.label}\n locales={locales}\n onChange={(next) => {\n update({ ...link, label: next });\n }}\n pointer={`${at}/label`}\n errors={errors}\n formatLocale={formatLocale}\n />\n <TextField\n label={getAdminLabel('field.link.iconUrl')}\n type=\"url\"\n value={link.iconUrl ?? ''}\n onChange={(iconUrl) => {\n update(setIconUrl(link, iconUrl));\n }}\n required={link.type === 'custom'}\n errors={errorsAt(errors, `${at}/iconUrl`)}\n />\n <CheckboxField\n label={getAdminLabel('field.link.featured')}\n checked={link.featured ?? false}\n onChange={(featured) => {\n update({ ...link, featured: featured || undefined });\n }}\n />\n </>\n );\n }}\n />\n );\n}\n","import type { LocaleTag } from '@takuhon/core';\n\n/**\n * First non-empty localized value, preferring the order of `locales` and\n * falling back to any present value. Used for repeater item captions where a\n * single human-readable string is needed regardless of the active locale.\n */\nexport function firstLocalized(\n record: Record<LocaleTag, string> | undefined,\n locales: readonly LocaleTag[],\n): string {\n if (!record) return '';\n for (const locale of locales) {\n const value = record[locale];\n if (value) return value;\n }\n return Object.values(record).find((value) => value !== '') ?? '';\n}\n","import type { Career, LocaleTag } from '@takuhon/core';\n\nimport { getAdminLabel } from '../admin-labels.js';\nimport { NO_FIELD_ERRORS, errorsAt, type FieldErrorIndex } from '../errors.js';\nimport { makeId } from '../ids.js';\nimport { firstLocalized } from '../localized.js';\nimport { CheckboxField } from '../primitives/CheckboxField.js';\nimport { LocaleTabs } from '../primitives/LocaleTabs.js';\nimport { Repeater } from '../primitives/Repeater.js';\nimport { TextField } from '../primitives/TextField.js';\n\nexport interface CareersFormProps {\n value: readonly Career[];\n onChange: (next: Career[]) => void;\n locales: readonly LocaleTag[];\n errors?: FieldErrorIndex;\n formatLocale?: (locale: LocaleTag) => string;\n}\n\n/** Work experience (spec §6.7 / §14.2 \"職歴\"). */\nexport function CareersForm({\n value,\n onChange,\n locales,\n errors = NO_FIELD_ERRORS,\n formatLocale,\n}: CareersFormProps): React.JSX.Element {\n return (\n <Repeater<Career>\n legend={getAdminLabel('section.careers')}\n items={value}\n onChange={onChange}\n keyOf={(career) => career.id}\n itemLabel={(career, index) =>\n firstLocalized(career.organization, locales) ||\n `${getAdminLabel('item.career')} ${String(index + 1)}`\n }\n createItem={() => ({\n id: makeId(\n 'career',\n value.map((c) => c.id),\n ),\n organization: {},\n role: {},\n startDate: '',\n })}\n addLabel={getAdminLabel('action.add')}\n removeLabel={getAdminLabel('action.remove')}\n moveUpLabel={getAdminLabel('action.moveUp')}\n moveDownLabel={getAdminLabel('action.moveDown')}\n emptyHint={getAdminLabel('empty.careers')}\n renderItem={(career, update, index) => {\n const at = `/careers/${String(index)}`;\n return (\n <>\n <LocaleTabs\n label={getAdminLabel('field.career.organization')}\n value={career.organization}\n locales={locales}\n onChange={(next) => {\n update({ ...career, organization: next ?? {} });\n }}\n required\n pointer={`${at}/organization`}\n errors={errors}\n formatLocale={formatLocale}\n />\n <LocaleTabs\n label={getAdminLabel('field.career.role')}\n value={career.role}\n locales={locales}\n onChange={(next) => {\n update({ ...career, role: next ?? {} });\n }}\n required\n pointer={`${at}/role`}\n errors={errors}\n formatLocale={formatLocale}\n />\n <TextField\n label={getAdminLabel('field.career.startDate')}\n type=\"month\"\n value={career.startDate}\n onChange={(startDate) => {\n update({ ...career, startDate });\n }}\n required\n hint={getAdminLabel('hint.month')}\n errors={errorsAt(errors, `${at}/startDate`)}\n />\n <TextField\n label={getAdminLabel('field.career.endDate')}\n type=\"month\"\n value={career.endDate ?? ''}\n onChange={(endDate) => {\n update({ ...career, endDate: endDate || undefined });\n }}\n hint={getAdminLabel('hint.month')}\n errors={errorsAt(errors, `${at}/endDate`)}\n />\n <CheckboxField\n label={getAdminLabel('field.career.isCurrent')}\n checked={career.isCurrent ?? false}\n onChange={(isCurrent) => {\n update({ ...career, isCurrent: isCurrent || undefined });\n }}\n />\n <LocaleTabs\n label={getAdminLabel('field.career.description')}\n value={career.description}\n locales={locales}\n onChange={(next) => {\n update({ ...career, description: next });\n }}\n multiline\n pointer={`${at}/description`}\n errors={errors}\n formatLocale={formatLocale}\n />\n <TextField\n label={getAdminLabel('field.career.url')}\n type=\"url\"\n value={career.url ?? ''}\n onChange={(url) => {\n update({ ...career, url: url || undefined });\n }}\n errors={errorsAt(errors, `${at}/url`)}\n />\n </>\n );\n }}\n />\n );\n}\n","import type { LocaleTag, Project } from '@takuhon/core';\n\nimport { getAdminLabel } from '../admin-labels.js';\nimport { NO_FIELD_ERRORS, collectErrorsUnder, errorsAt, type FieldErrorIndex } from '../errors.js';\nimport { makeId } from '../ids.js';\nimport { firstLocalized } from '../localized.js';\nimport { CheckboxField } from '../primitives/CheckboxField.js';\nimport { LocaleTabs } from '../primitives/LocaleTabs.js';\nimport { Repeater } from '../primitives/Repeater.js';\nimport { TextField } from '../primitives/TextField.js';\n\nexport interface ProjectsFormProps {\n value: readonly Project[];\n onChange: (next: Project[]) => void;\n locales: readonly LocaleTag[];\n errors?: FieldErrorIndex;\n formatLocale?: (locale: LocaleTag) => string;\n}\n\nfunction parseTags(input: string): string[] | undefined {\n const tags = input\n .split(',')\n .map((tag) => tag.trim())\n .filter((tag) => tag !== '');\n return tags.length > 0 ? tags : undefined;\n}\n\n/** Projects (spec §6.8 / §14.2). */\nexport function ProjectsForm({\n value,\n onChange,\n locales,\n errors = NO_FIELD_ERRORS,\n formatLocale,\n}: ProjectsFormProps): React.JSX.Element {\n return (\n <Repeater<Project>\n legend={getAdminLabel('section.projects')}\n items={value}\n onChange={onChange}\n keyOf={(project) => project.id}\n itemLabel={(project, index) =>\n firstLocalized(project.title, locales) ||\n `${getAdminLabel('item.project')} ${String(index + 1)}`\n }\n createItem={() => ({\n id: makeId(\n 'project',\n value.map((p) => p.id),\n ),\n title: {},\n })}\n addLabel={getAdminLabel('action.add')}\n removeLabel={getAdminLabel('action.remove')}\n moveUpLabel={getAdminLabel('action.moveUp')}\n moveDownLabel={getAdminLabel('action.moveDown')}\n emptyHint={getAdminLabel('empty.projects')}\n renderItem={(project, update, index) => {\n const at = `/projects/${String(index)}`;\n return (\n <>\n <LocaleTabs\n label={getAdminLabel('field.project.title')}\n value={project.title}\n locales={locales}\n onChange={(next) => {\n update({ ...project, title: next ?? {} });\n }}\n required\n pointer={`${at}/title`}\n errors={errors}\n formatLocale={formatLocale}\n />\n <LocaleTabs\n label={getAdminLabel('field.project.description')}\n value={project.description}\n locales={locales}\n onChange={(next) => {\n update({ ...project, description: next });\n }}\n multiline\n pointer={`${at}/description`}\n errors={errors}\n formatLocale={formatLocale}\n />\n <TextField\n label={getAdminLabel('field.project.url')}\n type=\"url\"\n value={project.url ?? ''}\n onChange={(url) => {\n update({ ...project, url: url || undefined });\n }}\n errors={errorsAt(errors, `${at}/url`)}\n />\n <TextField\n label={getAdminLabel('field.project.tags')}\n value={(project.tags ?? []).join(', ')}\n onChange={(input) => {\n update({ ...project, tags: parseTags(input) });\n }}\n hint={getAdminLabel('hint.tags')}\n errors={collectErrorsUnder(errors, `${at}/tags`)}\n />\n <TextField\n label={getAdminLabel('field.project.startDate')}\n type=\"month\"\n value={project.startDate ?? ''}\n onChange={(startDate) => {\n update({ ...project, startDate: startDate || undefined });\n }}\n hint={getAdminLabel('hint.month')}\n errors={errorsAt(errors, `${at}/startDate`)}\n />\n <TextField\n label={getAdminLabel('field.project.endDate')}\n type=\"month\"\n value={project.endDate ?? ''}\n onChange={(endDate) => {\n update({ ...project, endDate: endDate || undefined });\n }}\n hint={getAdminLabel('hint.month')}\n errors={errorsAt(errors, `${at}/endDate`)}\n />\n <CheckboxField\n label={getAdminLabel('field.project.highlighted')}\n checked={project.highlighted ?? false}\n onChange={(highlighted) => {\n update({ ...project, highlighted: highlighted || undefined });\n }}\n />\n </>\n );\n }}\n />\n );\n}\n","import type { Skill } from '@takuhon/core';\n\nimport { getAdminLabel } from '../admin-labels.js';\nimport { NO_FIELD_ERRORS, errorsAt, type FieldErrorIndex } from '../errors.js';\nimport { makeId } from '../ids.js';\nimport { Repeater } from '../primitives/Repeater.js';\nimport { TextField } from '../primitives/TextField.js';\n\nexport interface SkillsFormProps {\n value: readonly Skill[];\n onChange: (next: Skill[]) => void;\n errors?: FieldErrorIndex;\n}\n\n/** Skills (spec §6.9 / §14.2). `label` is a plain string, not localized. */\nexport function SkillsForm({\n value,\n onChange,\n errors = NO_FIELD_ERRORS,\n}: SkillsFormProps): React.JSX.Element {\n return (\n <Repeater<Skill>\n legend={getAdminLabel('section.skills')}\n items={value}\n onChange={onChange}\n keyOf={(skill) => skill.id}\n itemLabel={(skill, index) =>\n skill.label || `${getAdminLabel('item.skill')} ${String(index + 1)}`\n }\n createItem={() => ({\n id: makeId(\n 'skill',\n value.map((s) => s.id),\n ),\n label: '',\n })}\n addLabel={getAdminLabel('action.add')}\n removeLabel={getAdminLabel('action.remove')}\n moveUpLabel={getAdminLabel('action.moveUp')}\n moveDownLabel={getAdminLabel('action.moveDown')}\n emptyHint={getAdminLabel('empty.skills')}\n renderItem={(skill, update, index) => {\n const at = `/skills/${String(index)}`;\n return (\n <>\n <TextField\n label={getAdminLabel('field.skill.label')}\n value={skill.label}\n onChange={(label) => {\n update({ ...skill, label });\n }}\n required\n errors={errorsAt(errors, `${at}/label`)}\n />\n <TextField\n label={getAdminLabel('field.skill.category')}\n value={skill.category ?? ''}\n onChange={(category) => {\n update({ ...skill, category: category || undefined });\n }}\n errors={errorsAt(errors, `${at}/category`)}\n />\n </>\n );\n }}\n />\n );\n}\n","import type { LocaleTag, PublicVisibility, Settings } from '@takuhon/core';\n\nimport { getAdminLabel, type AdminLabelKey } from '../admin-labels.js';\nimport { NO_FIELD_ERRORS, collectErrorsUnder, errorsAt, type FieldErrorIndex } from '../errors.js';\nimport { CheckboxField } from '../primitives/CheckboxField.js';\nimport { SelectField } from '../primitives/SelectField.js';\nimport { TextField } from '../primitives/TextField.js';\n\nimport styles from './sections.module.css';\n\nexport interface SettingsFormProps {\n value: Settings;\n onChange: (next: Settings) => void;\n errors?: FieldErrorIndex;\n formatLocale?: (locale: LocaleTag) => string;\n}\n\n/**\n * Content sections the owner can hide via `settings.publicVisibility`. The\n * order mirrors the public page; `profile` is intentionally absent because the\n * identity is always public (spec §6.2).\n */\nconst VISIBILITY_SECTIONS: { key: keyof PublicVisibility; label: AdminLabelKey }[] = [\n { key: 'links', label: 'field.publicVisibility.links' },\n { key: 'careers', label: 'field.publicVisibility.careers' },\n { key: 'projects', label: 'field.publicVisibility.projects' },\n { key: 'skills', label: 'field.publicVisibility.skills' },\n { key: 'certifications', label: 'field.publicVisibility.certifications' },\n { key: 'memberships', label: 'field.publicVisibility.memberships' },\n { key: 'volunteering', label: 'field.publicVisibility.volunteering' },\n { key: 'honors', label: 'field.publicVisibility.honors' },\n { key: 'education', label: 'field.publicVisibility.education' },\n { key: 'publications', label: 'field.publicVisibility.publications' },\n { key: 'languages', label: 'field.publicVisibility.languages' },\n { key: 'courses', label: 'field.publicVisibility.courses' },\n { key: 'patents', label: 'field.publicVisibility.patents' },\n { key: 'testScores', label: 'field.publicVisibility.testScores' },\n { key: 'recommendations', label: 'field.publicVisibility.recommendations' },\n { key: 'contact', label: 'field.publicVisibility.contact' },\n];\n\nfunction parseLocales(input: string): string[] {\n return input\n .split(',')\n .map((tag) => tag.trim())\n .filter((tag) => tag !== '');\n}\n\n/** Site settings: locales, theme, and feature toggles (spec §6.20 / §14.2). */\nexport function SettingsForm({\n value,\n onChange,\n errors = NO_FIELD_ERRORS,\n formatLocale,\n}: SettingsFormProps): React.JSX.Element {\n const format = formatLocale ?? ((locale: LocaleTag) => locale);\n const localeOptions = value.availableLocales.map((locale) => ({\n value: locale,\n label: format(locale),\n }));\n const headingId = 'admin-section-settings';\n\n // Toggle a section's public visibility. Stored sparsely: only hidden\n // sections (`false`) are kept, and the block is dropped entirely once every\n // section is visible again, so the default (all-visible) stays absent.\n const setVisibility = (key: keyof PublicVisibility, visible: boolean): void => {\n const next: PublicVisibility = { ...value.publicVisibility };\n if (visible) {\n delete next[key];\n } else {\n next[key] = false;\n }\n const publicVisibility = Object.keys(next).length > 0 ? next : undefined;\n onChange({ ...value, publicVisibility });\n };\n\n return (\n <section className={styles.section} aria-labelledby={headingId}>\n <h2 className={styles.heading} id={headingId}>\n {getAdminLabel('section.settings')}\n </h2>\n\n <TextField\n label={getAdminLabel('field.settings.availableLocales')}\n value={value.availableLocales.join(', ')}\n onChange={(input) => {\n onChange({ ...value, availableLocales: parseLocales(input) });\n }}\n required\n hint={getAdminLabel('hint.locales')}\n errors={collectErrorsUnder(errors, '/settings/availableLocales')}\n />\n <SelectField\n label={getAdminLabel('field.settings.defaultLocale')}\n value={value.defaultLocale}\n options={localeOptions}\n onChange={(defaultLocale) => {\n onChange({ ...value, defaultLocale });\n }}\n required\n errors={errorsAt(errors, '/settings/defaultLocale')}\n />\n <SelectField\n label={getAdminLabel('field.settings.fallbackLocale')}\n value={value.fallbackLocale ?? ''}\n options={[{ value: '', label: getAdminLabel('option.none') }, ...localeOptions]}\n onChange={(fallbackLocale) => {\n onChange({ ...value, fallbackLocale: fallbackLocale || undefined });\n }}\n errors={errorsAt(errors, '/settings/fallbackLocale')}\n />\n <TextField\n label={getAdminLabel('field.settings.theme')}\n value={value.theme ?? ''}\n onChange={(theme) => {\n onChange({ ...value, theme: theme || undefined });\n }}\n errors={errorsAt(errors, '/settings/theme')}\n />\n\n <CheckboxField\n label={getAdminLabel('field.settings.showPoweredBy')}\n checked={value.showPoweredBy ?? true}\n onChange={(showPoweredBy) => {\n onChange({ ...value, showPoweredBy });\n }}\n />\n <CheckboxField\n label={getAdminLabel('field.settings.enableJsonLd')}\n checked={value.enableJsonLd ?? true}\n onChange={(enableJsonLd) => {\n onChange({ ...value, enableJsonLd });\n }}\n />\n <CheckboxField\n label={getAdminLabel('field.settings.enableApi')}\n checked={value.enableApi ?? true}\n onChange={(enableApi) => {\n onChange({ ...value, enableApi });\n }}\n />\n <CheckboxField\n label={getAdminLabel('field.settings.enableAnalytics')}\n checked={value.enableAnalytics ?? false}\n onChange={(enableAnalytics) => {\n onChange({ ...value, enableAnalytics });\n }}\n />\n\n <h3 className={styles.subheading}>{getAdminLabel('field.settings.publicVisibility')}</h3>\n <p className={styles.hint}>{getAdminLabel('hint.publicVisibility')}</p>\n {VISIBILITY_SECTIONS.map(({ key, label }) => (\n <CheckboxField\n key={key}\n label={getAdminLabel(label)}\n checked={value.publicVisibility?.[key] ?? true}\n onChange={(visible) => {\n setVisibility(key, visible);\n }}\n />\n ))}\n </section>\n );\n}\n","import { validate, type Takuhon } from '@takuhon/core';\nimport { useId, useState } from 'react';\n\nimport styles from './RawJsonEditor.module.css';\nimport { getAdminLabel } from './admin-labels.js';\n\nexport interface RawJsonEditorProps {\n value: Takuhon;\n /** Called with the parsed document whenever the text is valid JSON + schema. */\n onChange: (next: Takuhon) => void;\n}\n\nconst MAX_SHOWN_PROBLEMS = 50;\n\n/**\n * Advanced editing surface: the entire document as JSON text. Edits commit to\n * the draft only when the text parses and passes schema validation, so the\n * structured form view it shares state with never sees a malformed document.\n * This is also the only way to edit sections without a dedicated form (spec\n * §14.1 Phase 5 — JSON editor retained as the advanced mode).\n */\nexport function RawJsonEditor({ value, onChange }: RawJsonEditorProps): React.JSX.Element {\n const [text, setText] = useState(() => JSON.stringify(value, null, 2));\n const [problems, setProblems] = useState<readonly string[]>([]);\n const labelId = useId();\n const errorId = useId();\n\n const apply = (next: string): void => {\n setText(next);\n let parsed: unknown;\n try {\n parsed = JSON.parse(next);\n } catch (error) {\n setProblems([error instanceof Error ? error.message : 'Invalid JSON.']);\n return;\n }\n const result = validate(parsed);\n if (!result.ok) {\n setProblems(\n result.errors\n .slice(0, MAX_SHOWN_PROBLEMS)\n .map((error) => `${error.pointer || '/'}: ${error.message}`),\n );\n return;\n }\n setProblems([]);\n onChange(result.data);\n };\n\n const hasProblems = problems.length > 0;\n\n return (\n <section className={styles.wrapper} aria-labelledby={labelId}>\n <h2 className={styles.heading} id={labelId}>\n {getAdminLabel('mode.advanced')}\n </h2>\n <p className={styles.hint}>{getAdminLabel('advanced.hint')}</p>\n <textarea\n className={styles.textarea}\n value={text}\n spellCheck={false}\n aria-label={getAdminLabel('mode.advanced')}\n aria-invalid={hasProblems || undefined}\n aria-describedby={hasProblems ? errorId : undefined}\n onChange={(event) => {\n apply(event.target.value);\n }}\n />\n {hasProblems ? (\n <div className={styles.problems} id={errorId} role=\"alert\">\n <p className={styles.problemsTitle}>{getAdminLabel('advanced.invalid')}</p>\n <ul>\n {problems.map((problem, i) => (\n <li key={i}>{problem}</li>\n ))}\n </ul>\n </div>\n ) : null}\n </section>\n );\n}\n","import { validate, type LocaleTag, type Takuhon } from '@takuhon/core';\nimport { useRef, useState } from 'react';\n\nimport styles from './AdminEditor.module.css';\nimport { RawJsonEditor } from './RawJsonEditor.js';\nimport { getAdminLabel } from './admin-labels.js';\nimport {\n indexErrors,\n indexValidationErrors,\n NO_FIELD_ERRORS,\n type FieldErrorIndex,\n type FieldErrorLike,\n} from './errors.js';\nimport { type UploadAsset } from './primitives/ImageField.js';\nimport { CareersForm } from './sections/CareersForm.js';\nimport { LinksForm } from './sections/LinksForm.js';\nimport { ProfileForm } from './sections/ProfileForm.js';\nimport { ProjectsForm } from './sections/ProjectsForm.js';\nimport { SettingsForm } from './sections/SettingsForm.js';\nimport { SkillsForm } from './sections/SkillsForm.js';\n\n/** Result of a save attempt, reported by the host's transport layer. */\nexport type AdminSaveOutcome =\n | { status: 'saved'; version?: string }\n | { status: 'conflict' }\n | { status: 'invalid'; errors: readonly FieldErrorLike[] }\n | { status: 'error'; message?: string };\n\nexport interface AdminEditorProps {\n /** Document to edit, typically loaded from `GET /api/admin/export`. */\n initialDocument: Takuhon;\n /** Persist the document. The editor validates client-side first. */\n onSave: (document: Takuhon) => Promise<AdminSaveOutcome>;\n /** Re-fetch the stored document, replacing the working draft. */\n onReload?: () => Promise<Takuhon>;\n /** Download / hand off the current draft (Export button). */\n onExport?: (document: Takuhon) => void;\n /**\n * Provide a document to load (Import button). Returns raw parsed JSON, which\n * the editor validates; `undefined` cancels. Validation lives here so an\n * invalid file cannot break the draft invariant.\n */\n onImport?: () => Promise<unknown>;\n formatLocale?: (locale: LocaleTag) => string;\n /**\n * Upload an avatar image file (host-supplied; carries the admin token). When\n * provided, the profile form's avatar field offers a file picker; otherwise\n * the avatar stays URL-only.\n */\n uploadAsset?: UploadAsset;\n}\n\ntype Mode = 'form' | 'advanced';\ntype Tone = 'info' | 'success' | 'error';\ninterface Status {\n tone: Tone;\n message: string;\n}\n\n/**\n * Top-level admin editor: holds the working draft, switches between the field\n * forms and the raw-JSON advanced mode, and runs client-side validation before\n * delegating persistence to the host via `onSave` (transport-agnostic). Server\n * (RFC 7807) and client (`validate`) errors map to the same fields.\n */\nexport function AdminEditor({\n initialDocument,\n onSave,\n onReload,\n onExport,\n onImport,\n formatLocale,\n uploadAsset,\n}: AdminEditorProps): React.JSX.Element {\n const [draft, setDraft] = useState<Takuhon>(initialDocument);\n const [mode, setMode] = useState<Mode>('form');\n const [errors, setErrors] = useState<FieldErrorIndex>(NO_FIELD_ERRORS);\n const [status, setStatus] = useState<Status | null>(null);\n const [busy, setBusy] = useState(false);\n // Bumped whenever the document is replaced wholesale (reload / import) to\n // remount the raw-JSON editor so its text re-seeds from the new draft.\n const [loadGen, setLoadGen] = useState(0);\n // Identifies the latest user intent. A save reads it after awaiting `onSave`\n // and discards its outcome if an edit (which bumps the counter) landed\n // meanwhile — preventing a stale \"Saved.\" or stale server errors.\n const intentRef = useRef(0);\n\n const locales = draft.settings.availableLocales;\n\n // Any edit clears the previous validation snapshot so resolved errors do not\n // linger while the operator works through them, and invalidates any in-flight\n // save outcome.\n const updateDraft = (next: Takuhon): void => {\n intentRef.current += 1;\n setDraft(next);\n setErrors(NO_FIELD_ERRORS);\n setStatus(null);\n };\n\n const loadDocument = (next: Takuhon, message: Status | null): void => {\n intentRef.current += 1;\n setDraft(next);\n setErrors(NO_FIELD_ERRORS);\n setStatus(message);\n setLoadGen((generation) => generation + 1);\n };\n\n const handleSave = async (): Promise<void> => {\n const result = validate(draft);\n if (!result.ok) {\n setErrors(indexValidationErrors(result.errors));\n setStatus({ tone: 'error', message: getAdminLabel('status.invalid') });\n return;\n }\n setErrors(NO_FIELD_ERRORS);\n intentRef.current += 1;\n const intent = intentRef.current;\n setBusy(true);\n setStatus({ tone: 'info', message: getAdminLabel('status.saving') });\n try {\n const outcome = await onSave(result.data);\n if (intent !== intentRef.current) return; // an edit landed mid-save; ignore\n switch (outcome.status) {\n case 'saved':\n setStatus({ tone: 'success', message: getAdminLabel('status.saved') });\n break;\n case 'conflict':\n setStatus({ tone: 'error', message: getAdminLabel('status.conflict') });\n break;\n case 'invalid':\n setErrors(indexErrors(outcome.errors));\n setStatus({ tone: 'error', message: getAdminLabel('status.invalid') });\n break;\n case 'error':\n setStatus({ tone: 'error', message: outcome.message ?? getAdminLabel('status.error') });\n break;\n }\n } catch {\n if (intent === intentRef.current) {\n setStatus({ tone: 'error', message: getAdminLabel('status.error') });\n }\n } finally {\n setBusy(false);\n }\n };\n\n const handleReload = async (): Promise<void> => {\n if (!onReload) return;\n setBusy(true);\n setStatus({ tone: 'info', message: getAdminLabel('status.loading') });\n try {\n const next = await onReload();\n loadDocument(next, null);\n } catch {\n setStatus({ tone: 'error', message: getAdminLabel('status.error') });\n } finally {\n setBusy(false);\n }\n };\n\n const handleImport = async (): Promise<void> => {\n if (!onImport) return;\n try {\n const raw = await onImport();\n if (raw === undefined) return;\n const result = validate(raw);\n if (!result.ok) {\n setStatus({ tone: 'error', message: getAdminLabel('status.importInvalid') });\n return;\n }\n loadDocument(result.data, {\n tone: 'info',\n message: getAdminLabel('status.imported'),\n });\n } catch {\n setStatus({ tone: 'error', message: getAdminLabel('status.error') });\n }\n };\n\n // Flattened error list for the summary. This is the safety net that surfaces\n // failures in sections without a dedicated form (e.g. meta, education): their\n // pointers would otherwise map to no visible field.\n const errorEntries = [...errors].flatMap(([pointer, messages]) =>\n messages.map((message) => ({ pointer, message })),\n );\n\n return (\n <div className={styles.editor}>\n <div className={styles.toolbar} role=\"toolbar\" aria-label={getAdminLabel('toolbar.label')}>\n <div className={styles.modes} role=\"group\" aria-label={getAdminLabel('mode.label')}>\n <button\n type=\"button\"\n className={`${styles.modeButton} ${mode === 'form' ? styles.modeActive : ''}`}\n aria-pressed={mode === 'form'}\n onClick={() => {\n setMode('form');\n }}\n >\n {getAdminLabel('mode.form')}\n </button>\n <button\n type=\"button\"\n className={`${styles.modeButton} ${mode === 'advanced' ? styles.modeActive : ''}`}\n aria-pressed={mode === 'advanced'}\n onClick={() => {\n setMode('advanced');\n }}\n >\n {getAdminLabel('mode.advanced')}\n </button>\n </div>\n <div className={styles.actions}>\n <button\n type=\"button\"\n className={styles.primary}\n disabled={busy}\n onClick={() => {\n void handleSave();\n }}\n >\n {getAdminLabel('action.save')}\n </button>\n {onReload ? (\n <button\n type=\"button\"\n className={styles.secondary}\n disabled={busy}\n onClick={() => {\n void handleReload();\n }}\n >\n {getAdminLabel('action.reload')}\n </button>\n ) : null}\n {onExport ? (\n <button\n type=\"button\"\n className={styles.secondary}\n onClick={() => {\n onExport(draft);\n }}\n >\n {getAdminLabel('action.export')}\n </button>\n ) : null}\n {onImport ? (\n <button\n type=\"button\"\n className={styles.secondary}\n disabled={busy}\n onClick={() => {\n void handleImport();\n }}\n >\n {getAdminLabel('action.import')}\n </button>\n ) : null}\n </div>\n </div>\n\n <p className={styles.status} role=\"status\" aria-live=\"polite\" data-tone={status?.tone}>\n {status?.message ?? ''}\n </p>\n\n {errorEntries.length > 0 ? (\n <section className={styles.summary} aria-labelledby=\"admin-error-summary\">\n <h2 className={styles.summaryHeading} id=\"admin-error-summary\">\n {getAdminLabel('status.fixSummary')}\n </h2>\n <ul>\n {errorEntries.map((entry, i) => (\n <li key={i}>\n {entry.pointer === ''\n ? entry.message\n : `${entry.pointer.replace(/^\\//, '')}: ${entry.message}`}\n </li>\n ))}\n </ul>\n </section>\n ) : null}\n\n {mode === 'form' ? (\n <div className={styles.sections}>\n <ProfileForm\n value={draft.profile}\n onChange={(profile) => {\n updateDraft({ ...draft, profile });\n }}\n locales={locales}\n errors={errors}\n formatLocale={formatLocale}\n uploadAsset={uploadAsset}\n />\n <LinksForm\n value={draft.links}\n onChange={(links) => {\n updateDraft({ ...draft, links });\n }}\n locales={locales}\n errors={errors}\n formatLocale={formatLocale}\n />\n <CareersForm\n value={draft.careers}\n onChange={(careers) => {\n updateDraft({ ...draft, careers });\n }}\n locales={locales}\n errors={errors}\n formatLocale={formatLocale}\n />\n <ProjectsForm\n value={draft.projects}\n onChange={(projects) => {\n updateDraft({ ...draft, projects });\n }}\n locales={locales}\n errors={errors}\n formatLocale={formatLocale}\n />\n <SkillsForm\n value={draft.skills}\n onChange={(skills) => {\n updateDraft({ ...draft, skills });\n }}\n errors={errors}\n />\n <SettingsForm\n value={draft.settings}\n onChange={(settings) => {\n updateDraft({ ...draft, settings });\n }}\n errors={errors}\n formatLocale={formatLocale}\n />\n </div>\n ) : (\n <RawJsonEditor key={loadGen} value={draft} onChange={updateDraft} />\n )}\n </div>\n );\n}\n"],"mappings":"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","names":["styles","jsx","styles","jsx","styles","jsx","useId","styles","jsx","jsxs","useId","styles","jsx","jsxs","useId","useState","styles","controls","Fragment","jsx","jsxs","useState","useId","useRef","useState","styles","Fragment","jsx","jsxs","useId","useState","useRef","styles","jsx","jsxs","styles","jsx","jsxs","Fragment","jsx","jsxs","Fragment","jsx","jsxs","Fragment","jsx","jsxs","Fragment","jsx","jsxs","styles","jsx","jsxs","useId","useState","styles","jsx","jsxs","useState","useId","styles","validate","useRef","useState","styles","jsx","jsxs","useState","useRef","validate","styles"]}
@@ -20,3 +20,10 @@
20
20
  font-weight: 600;
21
21
  color: var(--takuhon-color-text);
22
22
  }
23
+
24
+ .hint {
25
+ margin: 0 0 var(--takuhon-space-3);
26
+ font-family: var(--takuhon-font-family);
27
+ font-size: var(--takuhon-font-size-sm);
28
+ color: var(--takuhon-color-text-muted);
29
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@takuhon/ui",
3
- "version": "0.17.0",
3
+ "version": "0.18.0",
4
4
  "description": "React mobile-first profile UI and minimal admin editor components for takuhon",
5
5
  "license": "Apache-2.0",
6
6
  "author": "Takuhon contributors",
@@ -47,7 +47,7 @@
47
47
  "node": ">=22.0.0"
48
48
  },
49
49
  "dependencies": {
50
- "@takuhon/core": "0.17.0"
50
+ "@takuhon/core": "0.18.0"
51
51
  },
52
52
  "peerDependencies": {
53
53
  "react": ">=19",