@takuhon/ui 0.8.2 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/AdminEditor.module-ABYQXFN4.module.css +116 -0
- package/dist/Field.module-CJPK45H7.module.css +34 -0
- package/dist/LocaleTabs.module-IEEC6Q27.module.css +116 -0
- package/dist/RawJsonEditor.module-NGGM3IBY.module.css +64 -0
- package/dist/Repeater.module-MWSEKS4G.module.css +102 -0
- package/dist/admin/index.d.ts +416 -0
- package/dist/admin/index.js +1621 -0
- package/dist/admin/index.js.map +1 -0
- package/dist/controls.module-CMB7V22N.module.css +48 -0
- package/dist/sections.module-ZVBKZHDE.module.css +22 -0
- package/package.json +6 -2
|
@@ -0,0 +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/LocaleTabs.tsx","../../src/admin/primitives/Repeater.tsx","../../src/admin/admin-labels.ts","../../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 { 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 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","/**\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\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.avatarAlt': 'Avatar alternative text',\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.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 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 { 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\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 URL, and a\n * structured location (spec §6.5 / §14.2). Image upload is not wired yet, so\n * the avatar is a URL field only.\n */\nexport function ProfileForm({\n value,\n onChange,\n locales,\n errors = NO_FIELD_ERRORS,\n formatLocale,\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 <TextField\n label={getAdminLabel('field.avatarUrl')}\n type=\"url\"\n value={value.avatar?.url ?? ''}\n onChange={(url) => {\n updateAvatar({ url });\n }}\n hint={getAdminLabel('hint.avatarNoUpload')}\n errors={errorsAt(errors, `${POINTER}/avatar/url`)}\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 { 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\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}: 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 />\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","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"]}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
.control {
|
|
2
|
+
inline-size: 100%;
|
|
3
|
+
box-sizing: border-box;
|
|
4
|
+
min-height: var(--takuhon-tap-target);
|
|
5
|
+
padding-inline: var(--takuhon-space-3);
|
|
6
|
+
padding-block: var(--takuhon-space-2);
|
|
7
|
+
border: 1px solid var(--takuhon-color-border);
|
|
8
|
+
border-radius: var(--takuhon-radius-sm);
|
|
9
|
+
background-color: var(--takuhon-color-bg);
|
|
10
|
+
color: var(--takuhon-color-text);
|
|
11
|
+
font-family: var(--takuhon-font-family);
|
|
12
|
+
font-size: var(--takuhon-font-size-base);
|
|
13
|
+
line-height: var(--takuhon-line-height);
|
|
14
|
+
transition: border-color var(--takuhon-transition-fast);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
.control:focus-visible {
|
|
18
|
+
outline: 2px solid var(--takuhon-color-primary);
|
|
19
|
+
outline-offset: 2px;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
.control[aria-invalid='true'] {
|
|
23
|
+
border-color: #b42318;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
.textarea {
|
|
27
|
+
min-height: calc(var(--takuhon-tap-target) * 2);
|
|
28
|
+
resize: vertical;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
.checkboxRow {
|
|
32
|
+
display: flex;
|
|
33
|
+
align-items: center;
|
|
34
|
+
gap: var(--takuhon-space-2);
|
|
35
|
+
margin-block-end: var(--takuhon-space-4);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
.checkbox {
|
|
39
|
+
inline-size: var(--takuhon-space-5);
|
|
40
|
+
block-size: var(--takuhon-space-5);
|
|
41
|
+
accent-color: var(--takuhon-color-primary);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
.checkboxLabel {
|
|
45
|
+
font-family: var(--takuhon-font-family);
|
|
46
|
+
font-size: var(--takuhon-font-size-base);
|
|
47
|
+
color: var(--takuhon-color-text);
|
|
48
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
.section {
|
|
2
|
+
margin-block-end: var(--takuhon-space-5);
|
|
3
|
+
padding: var(--takuhon-space-4);
|
|
4
|
+
border: 1px solid var(--takuhon-color-border);
|
|
5
|
+
border-radius: var(--takuhon-radius-md);
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
.heading {
|
|
9
|
+
margin: 0 0 var(--takuhon-space-4);
|
|
10
|
+
font-family: var(--takuhon-font-family);
|
|
11
|
+
font-size: var(--takuhon-font-size-xl);
|
|
12
|
+
font-weight: 700;
|
|
13
|
+
color: var(--takuhon-color-text);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
.subheading {
|
|
17
|
+
margin: var(--takuhon-space-4) 0 var(--takuhon-space-3);
|
|
18
|
+
font-family: var(--takuhon-font-family);
|
|
19
|
+
font-size: var(--takuhon-font-size-lg);
|
|
20
|
+
font-weight: 600;
|
|
21
|
+
color: var(--takuhon-color-text);
|
|
22
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@takuhon/ui",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.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",
|
|
@@ -27,6 +27,10 @@
|
|
|
27
27
|
".": {
|
|
28
28
|
"types": "./dist/index.d.ts",
|
|
29
29
|
"import": "./dist/index.js"
|
|
30
|
+
},
|
|
31
|
+
"./admin": {
|
|
32
|
+
"types": "./dist/admin/index.d.ts",
|
|
33
|
+
"import": "./dist/admin/index.js"
|
|
30
34
|
}
|
|
31
35
|
},
|
|
32
36
|
"files": [
|
|
@@ -43,7 +47,7 @@
|
|
|
43
47
|
"node": ">=22.0.0"
|
|
44
48
|
},
|
|
45
49
|
"dependencies": {
|
|
46
|
-
"@takuhon/core": "0.
|
|
50
|
+
"@takuhon/core": "0.10.0"
|
|
47
51
|
},
|
|
48
52
|
"peerDependencies": {
|
|
49
53
|
"react": ">=19",
|