@takuhon/ui 1.3.0 → 1.4.1

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.
@@ -306,6 +306,7 @@ declare const EN: {
306
306
  readonly 'section.patents': "Patents";
307
307
  readonly 'section.testScores': "Test scores";
308
308
  readonly 'section.recommendations': "Recommendations";
309
+ readonly 'section.highlights': "Selected posts";
309
310
  readonly 'section.contact': "Contact";
310
311
  readonly 'section.meta': "Metadata";
311
312
  readonly 'field.displayName': "Display name";
@@ -369,6 +370,7 @@ declare const EN: {
369
370
  readonly 'field.publicVisibility.patents': "Patents";
370
371
  readonly 'field.publicVisibility.testScores': "Test scores";
371
372
  readonly 'field.publicVisibility.recommendations': "Recommendations";
373
+ readonly 'field.publicVisibility.highlights': "Selected posts";
372
374
  readonly 'field.publicVisibility.contact': "Contact";
373
375
  readonly 'item.link': "Link";
374
376
  readonly 'item.career': "Position";
@@ -225,6 +225,7 @@ var EN = {
225
225
  "section.patents": "Patents",
226
226
  "section.testScores": "Test scores",
227
227
  "section.recommendations": "Recommendations",
228
+ "section.highlights": "Selected posts",
228
229
  "section.contact": "Contact",
229
230
  "section.meta": "Metadata",
230
231
  "field.displayName": "Display name",
@@ -288,6 +289,7 @@ var EN = {
288
289
  "field.publicVisibility.patents": "Patents",
289
290
  "field.publicVisibility.testScores": "Test scores",
290
291
  "field.publicVisibility.recommendations": "Recommendations",
292
+ "field.publicVisibility.highlights": "Selected posts",
291
293
  "field.publicVisibility.contact": "Contact",
292
294
  "item.link": "Link",
293
295
  "item.career": "Position",
@@ -757,6 +759,13 @@ function classifyNode(root, node) {
757
759
  const known = REF_WIDGET[ref];
758
760
  if (known) return known;
759
761
  }
762
+ const localizedVariant = resolved.anyOf?.find((variant) => {
763
+ const name = refName(variant);
764
+ return name === "LocalizedTitle" || name === "LocalizedBody";
765
+ });
766
+ if (localizedVariant) {
767
+ return refName(localizedVariant) === "LocalizedBody" ? { widget: "localizedBody" } : { widget: "localizedTitle" };
768
+ }
760
769
  if (Array.isArray(resolved.enum)) {
761
770
  return { widget: "select", options: resolved.enum.map((value) => String(value)) };
762
771
  }
@@ -827,6 +836,14 @@ function asRecord(value) {
827
836
  function asLocalized(value) {
828
837
  return value && typeof value === "object" ? value : void 0;
829
838
  }
839
+ function coerceLocalized(value, locales) {
840
+ if (typeof value === "string") {
841
+ if (value === "") return void 0;
842
+ const key = locales[0] ?? "en";
843
+ return { [key]: value };
844
+ }
845
+ return asLocalized(value);
846
+ }
830
847
  function asString(value) {
831
848
  return typeof value === "string" ? value : "";
832
849
  }
@@ -871,7 +888,8 @@ function captionOf(item, itemKind, locales) {
871
888
  const obj = asRecord(item);
872
889
  for (const field of itemKind.fields) {
873
890
  if (field.kind.widget === "localizedTitle") {
874
- const caption = firstLocalized(asLocalized(obj[field.name]), locales);
891
+ const raw = obj[field.name];
892
+ const caption = typeof raw === "string" ? raw : firstLocalized(asLocalized(raw), locales);
875
893
  if (caption) return caption;
876
894
  }
877
895
  }
@@ -892,7 +910,7 @@ function renderScalar(kind, value, onChange, ctx) {
892
910
  LocaleTabs,
893
911
  {
894
912
  label: ctx.label,
895
- value: asLocalized(value),
913
+ value: coerceLocalized(value, ctx.locales),
896
914
  locales: ctx.locales,
897
915
  onChange: (next) => {
898
916
  onChange(next);
@@ -1076,7 +1094,7 @@ function SchemaForm(props) {
1076
1094
  }
1077
1095
 
1078
1096
  // src/admin/schema-form/section-registry.tsx
1079
- import "@takuhon/core";
1097
+ import { LABEL_KEYS } from "@takuhon/core";
1080
1098
 
1081
1099
  // src/admin/schema-form/custom-fields.tsx
1082
1100
  import styles10 from "../custom-fields.module-3T2M3DO3.module.css";
@@ -1182,6 +1200,7 @@ var VISIBILITY_SECTIONS = [
1182
1200
  { key: "patents", label: "field.publicVisibility.patents" },
1183
1201
  { key: "testScores", label: "field.publicVisibility.testScores" },
1184
1202
  { key: "recommendations", label: "field.publicVisibility.recommendations" },
1203
+ { key: "highlights", label: "field.publicVisibility.highlights" },
1185
1204
  { key: "contact", label: "field.publicVisibility.contact" }
1186
1205
  ];
1187
1206
  function renderVisibilityMatrix(ctx) {
@@ -1247,6 +1266,9 @@ function referenceSelect(spec) {
1247
1266
  }
1248
1267
 
1249
1268
  // src/admin/schema-form/section-registry.tsx
1269
+ var SECTION_LABEL_HINTS = Object.fromEntries(
1270
+ LABEL_KEYS.map((key) => [`settings.sectionLabels.${key}`, { label: `${humanize(key)} label` }])
1271
+ );
1250
1272
  var ADMIN_SECTIONS = [
1251
1273
  { key: "profile", label: "section.profile" },
1252
1274
  { key: "links", label: "section.links" },
@@ -1265,6 +1287,7 @@ var ADMIN_SECTIONS = [
1265
1287
  { key: "patents", label: "section.patents" },
1266
1288
  { key: "testScores", label: "section.testScores" },
1267
1289
  { key: "recommendations", label: "section.recommendations" },
1290
+ { key: "highlights", label: "section.highlights" },
1268
1291
  { key: "contact", label: "section.contact" },
1269
1292
  { key: "meta", label: "section.meta" }
1270
1293
  ];
@@ -1307,6 +1330,10 @@ var SECTION_REGISTRY = {
1307
1330
  "settings.activity.github": { label: "GitHub" },
1308
1331
  "settings.activity.wakatime": { label: "WakaTime" },
1309
1332
  "settings.publicVisibility": { render: renderVisibilityMatrix },
1333
+ // Section order + data-driven heading overrides (1.4.0).
1334
+ "settings.sectionOrder": { label: "Section order" },
1335
+ "settings.sectionLabels": { label: "Section headings" },
1336
+ ...SECTION_LABEL_HINTS,
1310
1337
  // Contact form (1.1.0) — labelled "Contact form" so its group legend does not
1311
1338
  // collide with the profile "Contact" section. Only public config lives here;
1312
1339
  // the Turnstile secret and recipient are environment configuration.
@@ -1334,6 +1361,16 @@ var SECTION_REGISTRY = {
1334
1361
  },
1335
1362
  // Languages — disambiguate from the profile's "Display name".
1336
1363
  "languages.displayName": { label: "Language name" },
1364
+ // Highlights (selected posts) — tags are a comma-separated list like projects;
1365
+ // the rest carry format hints. Localized/text fields render generically.
1366
+ "highlights.tags": { render: csvListRenderer({ hint: "hint.tags", emptyToUndefined: true }) },
1367
+ "highlights.platform": {
1368
+ hint: "Free-form, e.g. instagram, x, github, blog. Known platforms show a brand glyph."
1369
+ },
1370
+ "highlights.image": {
1371
+ hint: "Absolute URL or root-relative path, e.g. /images/social/post.jpg. Serving the file is the deployment responsibility."
1372
+ },
1373
+ "highlights.postedAt": { hint: "Format: YYYY-MM-DD (e.g. 2025-12-22)." },
1337
1374
  // Metadata — auto-managed, never hand-edited.
1338
1375
  "meta.createdAt": { hidden: true },
1339
1376
  "meta.updatedAt": { hidden: true },