@aphexcms/cms-core 9.0.0 → 9.1.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.
Files changed (114) hide show
  1. package/dist/cli/generate-types.d.ts.map +1 -1
  2. package/dist/cli/generate-types.js +197 -8
  3. package/dist/cli/generate-types.js.map +1 -1
  4. package/dist/components/AdminApp.svelte +46 -137
  5. package/dist/components/AdminApp.svelte.d.ts.map +1 -1
  6. package/dist/components/admin/DocumentEditor.svelte +237 -206
  7. package/dist/components/admin/DocumentEditor.svelte.d.ts.map +1 -1
  8. package/dist/components/admin/DocumentVersionPanel.svelte +3 -2
  9. package/dist/components/admin/DocumentVersionPanel.svelte.d.ts.map +1 -1
  10. package/dist/components/admin/MediaBrowser.svelte +22 -4
  11. package/dist/components/admin/MediaBrowser.svelte.d.ts.map +1 -1
  12. package/dist/components/admin/ObjectModal.svelte +62 -75
  13. package/dist/components/admin/ObjectModal.svelte.d.ts.map +1 -1
  14. package/dist/components/admin/SchemaField.svelte +2 -2
  15. package/dist/components/admin/fields/ArrayField.svelte +9 -1
  16. package/dist/components/admin/fields/ArrayField.svelte.d.ts.map +1 -1
  17. package/dist/components/admin/fields/ReferenceField.svelte +37 -8
  18. package/dist/components/admin/fields/ReferenceField.svelte.d.ts.map +1 -1
  19. package/dist/components/admin/fields/richtext/PortableTextImageView.svelte +116 -0
  20. package/dist/components/admin/fields/richtext/PortableTextImageView.svelte.d.ts +12 -0
  21. package/dist/components/admin/fields/richtext/PortableTextImageView.svelte.d.ts.map +1 -0
  22. package/dist/components/admin/fields/richtext/PortableTextInlineView.svelte +111 -0
  23. package/dist/components/admin/fields/richtext/PortableTextInlineView.svelte.d.ts +12 -0
  24. package/dist/components/admin/fields/richtext/PortableTextInlineView.svelte.d.ts.map +1 -0
  25. package/dist/components/admin/fields/richtext/PortableTextObjectView.svelte +67 -0
  26. package/dist/components/admin/fields/richtext/PortableTextObjectView.svelte.d.ts +12 -0
  27. package/dist/components/admin/fields/richtext/PortableTextObjectView.svelte.d.ts.map +1 -0
  28. package/dist/components/admin/fields/richtext/RichtextField.svelte +1296 -0
  29. package/dist/components/admin/fields/richtext/RichtextField.svelte.d.ts +15 -0
  30. package/dist/components/admin/fields/richtext/RichtextField.svelte.d.ts.map +1 -0
  31. package/dist/components/admin/fields/richtext/custom-annotation-mark.d.ts +7 -0
  32. package/dist/components/admin/fields/richtext/custom-annotation-mark.d.ts.map +1 -0
  33. package/dist/components/admin/fields/richtext/custom-annotation-mark.js +33 -0
  34. package/dist/components/admin/fields/richtext/portable-text-inline-object.d.ts +11 -0
  35. package/dist/components/admin/fields/richtext/portable-text-inline-object.d.ts.map +1 -0
  36. package/dist/components/admin/fields/richtext/portable-text-inline-object.js +31 -0
  37. package/dist/components/admin/fields/richtext/portable-text-object-node.d.ts +11 -0
  38. package/dist/components/admin/fields/richtext/portable-text-object-node.d.ts.map +1 -0
  39. package/dist/components/admin/fields/richtext/portable-text-object-node.js +31 -0
  40. package/dist/components/admin/fields/richtext/portable-text-serializer.d.ts +38 -0
  41. package/dist/components/admin/fields/richtext/portable-text-serializer.d.ts.map +1 -0
  42. package/dist/components/admin/fields/richtext/portable-text-serializer.js +297 -0
  43. package/dist/components/admin/fields/richtext/svelte-inline-node-view.d.ts +8 -0
  44. package/dist/components/admin/fields/richtext/svelte-inline-node-view.d.ts.map +1 -0
  45. package/dist/components/admin/fields/richtext/svelte-inline-node-view.js +67 -0
  46. package/dist/components/admin/fields/richtext/svelte-node-view.d.ts +8 -0
  47. package/dist/components/admin/fields/richtext/svelte-node-view.d.ts.map +1 -0
  48. package/dist/components/admin/fields/richtext/svelte-node-view.js +63 -0
  49. package/dist/db/interfaces/document.d.ts +8 -2
  50. package/dist/db/interfaces/document.d.ts.map +1 -1
  51. package/dist/graphql/resolvers.d.ts.map +1 -1
  52. package/dist/graphql/resolvers.js +13 -11
  53. package/dist/graphql/schema.d.ts.map +1 -1
  54. package/dist/graphql/schema.js +7 -3
  55. package/dist/lib/components/admin/fields/richtext/custom-annotation-mark.d.ts +7 -0
  56. package/dist/lib/components/admin/fields/richtext/custom-annotation-mark.d.ts.map +1 -0
  57. package/dist/lib/components/admin/fields/richtext/custom-annotation-mark.js +34 -0
  58. package/dist/lib/components/admin/fields/richtext/custom-annotation-mark.js.map +1 -0
  59. package/dist/lib/components/admin/fields/richtext/portable-text-inline-object.d.ts +11 -0
  60. package/dist/lib/components/admin/fields/richtext/portable-text-inline-object.d.ts.map +1 -0
  61. package/dist/lib/components/admin/fields/richtext/portable-text-inline-object.js +32 -0
  62. package/dist/lib/components/admin/fields/richtext/portable-text-inline-object.js.map +1 -0
  63. package/dist/lib/components/admin/fields/richtext/portable-text-object-node.d.ts +11 -0
  64. package/dist/lib/components/admin/fields/richtext/portable-text-object-node.d.ts.map +1 -0
  65. package/dist/lib/components/admin/fields/richtext/portable-text-object-node.js +32 -0
  66. package/dist/lib/components/admin/fields/richtext/portable-text-object-node.js.map +1 -0
  67. package/dist/lib/components/admin/fields/richtext/portable-text-serializer.d.ts +38 -0
  68. package/dist/lib/components/admin/fields/richtext/portable-text-serializer.d.ts.map +1 -0
  69. package/dist/lib/components/admin/fields/richtext/portable-text-serializer.js +298 -0
  70. package/dist/lib/components/admin/fields/richtext/portable-text-serializer.js.map +1 -0
  71. package/dist/lib/components/admin/fields/richtext/svelte-inline-node-view.d.ts +8 -0
  72. package/dist/lib/components/admin/fields/richtext/svelte-inline-node-view.d.ts.map +1 -0
  73. package/dist/lib/components/admin/fields/richtext/svelte-inline-node-view.js +68 -0
  74. package/dist/lib/components/admin/fields/richtext/svelte-inline-node-view.js.map +1 -0
  75. package/dist/lib/components/admin/fields/richtext/svelte-node-view.d.ts +8 -0
  76. package/dist/lib/components/admin/fields/richtext/svelte-node-view.d.ts.map +1 -0
  77. package/dist/lib/components/admin/fields/richtext/svelte-node-view.js +64 -0
  78. package/dist/lib/components/admin/fields/richtext/svelte-node-view.js.map +1 -0
  79. package/dist/lib/db/interfaces/document.d.ts +8 -2
  80. package/dist/lib/db/interfaces/document.d.ts.map +1 -1
  81. package/dist/lib/graphql/resolvers.d.ts.map +1 -1
  82. package/dist/lib/graphql/resolvers.js +13 -11
  83. package/dist/lib/graphql/resolvers.js.map +1 -1
  84. package/dist/lib/graphql/schema.d.ts.map +1 -1
  85. package/dist/lib/graphql/schema.js +7 -3
  86. package/dist/lib/graphql/schema.js.map +1 -1
  87. package/dist/lib/local-api/collection-api.d.ts.map +1 -1
  88. package/dist/lib/local-api/collection-api.js +7 -0
  89. package/dist/lib/local-api/collection-api.js.map +1 -1
  90. package/dist/lib/schema-utils/validator.d.ts.map +1 -1
  91. package/dist/lib/schema-utils/validator.js +5 -1
  92. package/dist/lib/schema-utils/validator.js.map +1 -1
  93. package/dist/lib/server/api/routes/assets-by-id.d.ts.map +1 -1
  94. package/dist/lib/server/api/routes/assets-by-id.js +10 -2
  95. package/dist/lib/server/api/routes/assets-by-id.js.map +1 -1
  96. package/dist/lib/server/api/routes/assets-references.d.ts.map +1 -1
  97. package/dist/lib/server/api/routes/assets-references.js +6 -4
  98. package/dist/lib/server/api/routes/assets-references.js.map +1 -1
  99. package/dist/lib/types/schemas.d.ts +27 -0
  100. package/dist/lib/types/schemas.d.ts.map +1 -1
  101. package/dist/lib/types/schemas.js +3 -1
  102. package/dist/lib/types/schemas.js.map +1 -1
  103. package/dist/local-api/collection-api.d.ts.map +1 -1
  104. package/dist/local-api/collection-api.js +7 -0
  105. package/dist/schema-utils/validator.d.ts.map +1 -1
  106. package/dist/schema-utils/validator.js +5 -1
  107. package/dist/server/api/routes/assets-by-id.d.ts.map +1 -1
  108. package/dist/server/api/routes/assets-by-id.js +10 -2
  109. package/dist/server/api/routes/assets-references.d.ts.map +1 -1
  110. package/dist/server/api/routes/assets-references.js +6 -4
  111. package/dist/types/schemas.d.ts +27 -0
  112. package/dist/types/schemas.d.ts.map +1 -1
  113. package/dist/types/schemas.js +3 -1
  114. package/package.json +6 -1
@@ -68,6 +68,7 @@
68
68
  }: Props = $props();
69
69
 
70
70
  // Set schema context for child components (ArrayField, etc.)
71
+ // svelte-ignore state_referenced_locally
71
72
  setSchemaContext(schemas);
72
73
 
73
74
  // Read permissions from the AdminApp context for per-action gating.
@@ -181,6 +182,7 @@
181
182
  return str.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
182
183
  }
183
184
  let inspectTab = $state<'parsed' | 'raw'>('parsed');
185
+ let inspectPerspective = $state<'draft' | 'published'>('draft');
184
186
 
185
187
  // Header options dropdown
186
188
  let showHeaderMenu = $state(false);
@@ -1027,7 +1029,7 @@
1027
1029
  <div class="relative flex h-full w-full min-w-0 flex-col overflow-hidden">
1028
1030
  <!-- Hero Header -->
1029
1031
  <div class="bg-background w-full min-w-0 overflow-x-clip px-4 pt-4 pb-5 lg:px-6 lg:pt-5">
1030
- <div class="mx-auto w-full max-w-3xl">
1032
+ <div class="w-full">
1031
1033
  <!-- Top row: breadcrumb + actions -->
1032
1034
  <div class="mb-4 flex items-center justify-between gap-3">
1033
1035
  <div
@@ -1121,7 +1123,7 @@
1121
1123
  </Button>
1122
1124
  {#if showHeaderMenu}
1123
1125
  <div
1124
- class="bg-background border-rule absolute top-full right-0 z-50 mt-1 min-w-[160px] rounded-md border py-1 shadow-lg"
1126
+ class="bg-background border-rule absolute top-full right-0 z-[60] mt-1 min-w-[160px] rounded-md border py-1 shadow-lg"
1125
1127
  >
1126
1128
  <button
1127
1129
  onclick={() => {
@@ -1146,7 +1148,9 @@
1146
1148
  <Code class="h-3.5 w-3.5" /> Inspect
1147
1149
  </button>
1148
1150
  </div>
1149
- <div class="fixed inset-0 z-40" onclick={() => (showHeaderMenu = false)}></div>
1151
+ <!-- svelte-ignore a11y_click_events_have_key_events -->
1152
+ <!-- svelte-ignore a11y_no_static_element_interactions -->
1153
+ <div class="fixed inset-0 z-[55]" onclick={() => (showHeaderMenu = false)}></div>
1150
1154
  {/if}
1151
1155
  </div>
1152
1156
  {/if}
@@ -1231,181 +1235,184 @@
1231
1235
  </div>
1232
1236
 
1233
1237
  <!-- Content Form -->
1234
- <div class="flex-1 overflow-auto p-4 lg:p-6">
1235
- <div class="mx-auto w-full max-w-3xl space-y-4 lg:space-y-6">
1236
- {#if saveError}
1237
- <div class="bg-destructive/10 border-destructive/20 rounded-md border p-3">
1238
- <p class="text-destructive text-sm">{saveError}</p>
1239
- </div>
1240
- {/if}
1241
-
1242
- {#if schemaError}
1243
- <div class="bg-destructive/10 border-destructive/20 rounded-md border p-3">
1244
- <p class="text-destructive text-sm">Schema Error: {schemaError}</p>
1245
- </div>
1246
- {:else if schemaLoading}
1247
- <div class="p-6 text-center">
1248
- <div class="text-muted-foreground text-sm">Loading schema...</div>
1249
- </div>
1250
- {:else if schema}
1251
- <!-- Orphaned Fields Warning -->
1252
- {#if showOrphanedFields && orphanedFields.length > 0}
1253
- <div class="space-y-3 rounded-md border border-orange-200 bg-orange-50 p-4">
1254
- <div class="flex items-center gap-2">
1255
- <svg
1256
- class="h-5 w-5 text-orange-600"
1257
- fill="none"
1258
- viewBox="0 0 24 24"
1259
- stroke="currentColor"
1260
- >
1261
- <path
1262
- stroke-linecap="round"
1263
- stroke-linejoin="round"
1264
- stroke-width="2"
1265
- d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-2.5L13.732 4c-.77-.833-1.964-.833-2.732 0L5.081 16.5c-.77.833.192 2.5 1.732 2.5z"
1266
- />
1267
- </svg>
1268
- <h4 class="text-sm font-medium text-orange-800">
1269
- {orphanedFields.length} orphaned field{orphanedFields.length === 1 ? '' : 's'} detected
1270
- </h4>
1271
- </div>
1272
-
1273
- <p class="text-sm text-orange-700">
1274
- These fields exist in your document but are no longer defined in the schema:
1275
- </p>
1238
+ <div data-document-editor class="relative flex min-h-0 flex-1 flex-col">
1239
+ <div class="flex flex-1 flex-col overflow-auto p-4 lg:p-6">
1240
+ <div class="flex w-full flex-1 flex-col gap-4 lg:gap-6">
1241
+ {#if saveError}
1242
+ <div class="bg-destructive/10 border-destructive/20 rounded-md border p-3">
1243
+ <p class="text-destructive text-sm">{saveError}</p>
1244
+ </div>
1245
+ {/if}
1276
1246
 
1277
- <div class="space-y-2">
1278
- {#each orphanedFields as field, index (index)}
1279
- <div
1280
- class="flex items-center justify-between rounded border border-orange-200 bg-white p-3"
1247
+ {#if schemaError}
1248
+ <div class="bg-destructive/10 border-destructive/20 rounded-md border p-3">
1249
+ <p class="text-destructive text-sm">Schema Error: {schemaError}</p>
1250
+ </div>
1251
+ {:else if schemaLoading}
1252
+ <div class="p-6 text-center">
1253
+ <div class="text-muted-foreground text-sm">Loading schema...</div>
1254
+ </div>
1255
+ {:else if schema}
1256
+ <!-- Orphaned Fields Warning -->
1257
+ {#if showOrphanedFields && orphanedFields.length > 0}
1258
+ <div class="space-y-3 rounded-md border border-orange-200 bg-orange-50 p-4">
1259
+ <div class="flex items-center gap-2">
1260
+ <svg
1261
+ class="h-5 w-5 text-orange-600"
1262
+ fill="none"
1263
+ viewBox="0 0 24 24"
1264
+ stroke="currentColor"
1281
1265
  >
1282
- <div class="flex-1">
1283
- <div class="font-mono text-sm font-medium text-orange-800">
1284
- {field.path || field.key}
1285
- </div>
1286
- <div class="mt-1 text-xs text-orange-600">
1287
- <code class="rounded bg-orange-100 px-1">{JSON.stringify(field.value)}</code>
1266
+ <path
1267
+ stroke-linecap="round"
1268
+ stroke-linejoin="round"
1269
+ stroke-width="2"
1270
+ d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-2.5L13.732 4c-.77-.833-1.964-.833-2.732 0L5.081 16.5c-.77.833.192 2.5 1.732 2.5z"
1271
+ />
1272
+ </svg>
1273
+ <h4 class="text-sm font-medium text-orange-800">
1274
+ {orphanedFields.length} orphaned field{orphanedFields.length === 1 ? '' : 's'} detected
1275
+ </h4>
1276
+ </div>
1277
+
1278
+ <p class="text-sm text-orange-700">
1279
+ These fields exist in your document but are no longer defined in the schema:
1280
+ </p>
1281
+
1282
+ <div class="space-y-2">
1283
+ {#each orphanedFields as field, index (index)}
1284
+ <div
1285
+ class="flex items-center justify-between rounded border border-orange-200 bg-white p-3"
1286
+ >
1287
+ <div class="flex-1">
1288
+ <div class="font-mono text-sm font-medium text-orange-800">
1289
+ {field.path || field.key}
1290
+ </div>
1291
+ <div class="mt-1 text-xs text-orange-600">
1292
+ <code class="rounded bg-orange-100 px-1">{JSON.stringify(field.value)}</code
1293
+ >
1294
+ </div>
1288
1295
  </div>
1296
+ <Button
1297
+ size="sm"
1298
+ variant="outline"
1299
+ onclick={() => removeOrphanedField(field)}
1300
+ class="ml-3 h-8 border-red-200 px-3 text-red-600 hover:border-red-300 hover:bg-red-50"
1301
+ >
1302
+ Remove
1303
+ </Button>
1289
1304
  </div>
1290
- <Button
1291
- size="sm"
1292
- variant="outline"
1293
- onclick={() => removeOrphanedField(field)}
1294
- class="ml-3 h-8 border-red-200 px-3 text-red-600 hover:border-red-300 hover:bg-red-50"
1295
- >
1296
- Remove
1297
- </Button>
1298
- </div>
1299
- {/each}
1300
- </div>
1301
-
1302
- <div class="flex gap-2 border-t border-orange-200 pt-2">
1303
- <Button
1304
- size="sm"
1305
- variant="outline"
1306
- onclick={cleanupAllOrphanedFields}
1307
- class="border-orange-600 bg-orange-600 text-white hover:bg-orange-700"
1308
- >
1309
- Remove All
1310
- </Button>
1311
- <Button
1312
- size="sm"
1313
- variant="ghost"
1314
- onclick={dismissOrphanedFields}
1315
- class="text-orange-700 hover:text-orange-800"
1316
- >
1317
- Dismiss
1318
- </Button>
1305
+ {/each}
1306
+ </div>
1307
+
1308
+ <div class="flex gap-2 border-t border-orange-200 pt-2">
1309
+ <Button
1310
+ size="sm"
1311
+ variant="outline"
1312
+ onclick={cleanupAllOrphanedFields}
1313
+ class="border-orange-600 bg-orange-600 text-white hover:bg-orange-700"
1314
+ >
1315
+ Remove All
1316
+ </Button>
1317
+ <Button
1318
+ size="sm"
1319
+ variant="ghost"
1320
+ onclick={dismissOrphanedFields}
1321
+ class="text-orange-700 hover:text-orange-800"
1322
+ >
1323
+ Dismiss
1324
+ </Button>
1325
+ </div>
1319
1326
  </div>
1320
- </div>
1321
- {/if}
1327
+ {/if}
1322
1328
 
1323
- <!-- Field Group Tabs -->
1324
- {#if schema.groups && schema.groups.length > 0}
1325
- {@const visibleGroups = schema.groups.filter((g) => !g.hidden)}
1326
- <div class="mb-4 flex items-center gap-1 overflow-x-auto py-1">
1327
- <button
1328
- type="button"
1329
- onclick={() => (activeGroup = 'all')}
1330
- class="cursor-pointer rounded-md px-3 py-1.5 text-sm font-medium whitespace-nowrap transition-colors {activeGroup ===
1331
- 'all'
1332
- ? 'bg-muted text-foreground'
1333
- : 'text-muted-foreground hover:text-foreground'}"
1334
- >
1335
- All fields
1336
- </button>
1337
- {#each visibleGroups as group (group.name)}
1329
+ <!-- Field Group Tabs -->
1330
+ {#if schema.groups && schema.groups.length > 0}
1331
+ {@const visibleGroups = schema.groups.filter((g) => !g.hidden)}
1332
+ <div class="mb-4 flex items-center gap-1 overflow-x-auto py-1">
1338
1333
  <button
1339
1334
  type="button"
1340
- onclick={() => (activeGroup = group.name)}
1341
- class="flex cursor-pointer items-center gap-1.5 rounded-md px-3 py-1.5 text-sm font-medium whitespace-nowrap transition-colors {activeGroup ===
1342
- group.name
1335
+ onclick={() => (activeGroup = 'all')}
1336
+ class="cursor-pointer rounded-md px-3 py-1.5 text-sm font-medium whitespace-nowrap transition-colors {activeGroup ===
1337
+ 'all'
1343
1338
  ? 'bg-muted text-foreground'
1344
1339
  : 'text-muted-foreground hover:text-foreground'}"
1345
1340
  >
1346
- {#if group.icon}
1347
- {@const Icon = group.icon}
1348
- <Icon class="h-4 w-4" />
1349
- {/if}
1350
- {group.title}
1341
+ All fields
1351
1342
  </button>
1343
+ {#each visibleGroups as group (group.name)}
1344
+ <button
1345
+ type="button"
1346
+ onclick={() => (activeGroup = group.name)}
1347
+ class="flex cursor-pointer items-center gap-1.5 rounded-md px-3 py-1.5 text-sm font-medium whitespace-nowrap transition-colors {activeGroup ===
1348
+ group.name
1349
+ ? 'bg-muted text-foreground'
1350
+ : 'text-muted-foreground hover:text-foreground'}"
1351
+ >
1352
+ {#if group.icon}
1353
+ {@const Icon = group.icon}
1354
+ <Icon class="h-4 w-4" />
1355
+ {/if}
1356
+ {group.title}
1357
+ </button>
1358
+ {/each}
1359
+ </div>
1360
+ {/if}
1361
+
1362
+ <!-- Dynamic Schema Fields -->
1363
+ <svelte:boundary
1364
+ onerror={(error) =>
1365
+ cmsLogger.error('[DocumentEditor]', 'Error in editor content:', error)}
1366
+ >
1367
+ {#each schema.fields.filter((f) => fieldInGroup(f, activeGroup) && !hiddenFieldNames.has(f.name)) as field (field.name)}
1368
+ {@const viewData =
1369
+ isPreviewingVersion && activePreview
1370
+ ? activePreview.data
1371
+ : isViewingPublished && publishedData
1372
+ ? publishedData
1373
+ : documentData}
1374
+ <SchemaField
1375
+ {field}
1376
+ value={viewData[field.name]}
1377
+ documentData={viewData}
1378
+ onUpdate={(newValue) => {
1379
+ if (isViewingPublished) return;
1380
+ documentData = { ...documentData, [field.name]: newValue };
1381
+ hasUnsavedChanges = true;
1382
+ }}
1383
+ {onOpenReference}
1384
+ schemaType={documentType}
1385
+ readonly={isReadOnly ||
1386
+ isViewingPublished ||
1387
+ isPreviewingVersion ||
1388
+ isFieldReadonly(field.name)}
1389
+ organizationId={fullDocument?._meta?.organizationId}
1390
+ />
1352
1391
  {/each}
1392
+
1393
+ {#snippet failed(error, reset)}
1394
+ <div class="border-destructive/30 bg-destructive/5 rounded-md border p-4 text-center">
1395
+ <p class="text-destructive font-medium">Document editor encountered an error</p>
1396
+ <p class="text-muted-foreground mt-1 text-sm">
1397
+ {error instanceof Error ? error.message : 'Unknown error'}
1398
+ </p>
1399
+ <button
1400
+ class="bg-primary text-primary-foreground mt-3 rounded px-4 py-2 text-sm"
1401
+ onclick={reset}
1402
+ >
1403
+ Reload editor
1404
+ </button>
1405
+ </div>
1406
+ {/snippet}
1407
+ </svelte:boundary>
1408
+ {:else}
1409
+ <div class="border-muted-foreground/30 rounded-md border border-dashed p-4">
1410
+ <p class="text-muted-foreground text-center text-sm">
1411
+ No schema found for document type: {documentType}
1412
+ </p>
1353
1413
  </div>
1354
1414
  {/if}
1355
-
1356
- <!-- Dynamic Schema Fields -->
1357
- <svelte:boundary
1358
- onerror={(error) =>
1359
- cmsLogger.error('[DocumentEditor]', 'Error in editor content:', error)}
1360
- >
1361
- {#each schema.fields.filter((f) => fieldInGroup(f, activeGroup) && !hiddenFieldNames.has(f.name)) as field (field.name)}
1362
- {@const viewData =
1363
- isPreviewingVersion && activePreview
1364
- ? activePreview.data
1365
- : isViewingPublished && publishedData
1366
- ? publishedData
1367
- : documentData}
1368
- <SchemaField
1369
- {field}
1370
- value={viewData[field.name]}
1371
- documentData={viewData}
1372
- onUpdate={(newValue) => {
1373
- if (isViewingPublished) return;
1374
- documentData = { ...documentData, [field.name]: newValue };
1375
- hasUnsavedChanges = true;
1376
- }}
1377
- {onOpenReference}
1378
- schemaType={documentType}
1379
- readonly={isReadOnly ||
1380
- isViewingPublished ||
1381
- isPreviewingVersion ||
1382
- isFieldReadonly(field.name)}
1383
- organizationId={fullDocument?._meta?.organizationId}
1384
- />
1385
- {/each}
1386
-
1387
- {#snippet failed(error, reset)}
1388
- <div class="border-destructive/30 bg-destructive/5 rounded-md border p-4 text-center">
1389
- <p class="text-destructive font-medium">Document editor encountered an error</p>
1390
- <p class="text-muted-foreground mt-1 text-sm">
1391
- {error instanceof Error ? error.message : 'Unknown error'}
1392
- </p>
1393
- <button
1394
- class="bg-primary text-primary-foreground mt-3 rounded px-4 py-2 text-sm"
1395
- onclick={reset}
1396
- >
1397
- Reload editor
1398
- </button>
1399
- </div>
1400
- {/snippet}
1401
- </svelte:boundary>
1402
- {:else}
1403
- <div class="border-muted-foreground/30 rounded-md border border-dashed p-4">
1404
- <p class="text-muted-foreground text-center text-sm">
1405
- No schema found for document type: {documentType}
1406
- </p>
1407
- </div>
1408
- {/if}
1415
+ </div>
1409
1416
  </div>
1410
1417
  </div>
1411
1418
 
@@ -1547,6 +1554,7 @@
1547
1554
  showVersionHistory = false;
1548
1555
  previewingVersion = null;
1549
1556
  }}
1557
+ aria-label="Close version history"
1550
1558
  ></button>
1551
1559
  <!-- Panel -->
1552
1560
  <div class="bg-background border-rule flex w-80 flex-col border-l shadow-lg">
@@ -1558,6 +1566,7 @@
1558
1566
  showVersionHistory = false;
1559
1567
  previewingVersion = null;
1560
1568
  }}
1569
+ aria-label="Close version history"
1561
1570
  >
1562
1571
  <svg class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
1563
1572
  <path
@@ -1658,54 +1667,76 @@
1658
1667
  </div>
1659
1668
 
1660
1669
  <!-- Tabs -->
1661
- <div class="flex border-b">
1662
- <button
1663
- class="px-4 py-2 text-sm font-medium transition-colors {inspectTab === 'parsed'
1664
- ? 'border-primary text-foreground border-b-2'
1665
- : 'text-muted-foreground hover:text-foreground'}"
1666
- onclick={() => (inspectTab = 'parsed')}
1667
- >
1668
- Parsed
1669
- </button>
1670
- <button
1671
- class="px-4 py-2 text-sm font-medium transition-colors {inspectTab === 'raw'
1672
- ? 'border-primary text-foreground border-b-2'
1673
- : 'text-muted-foreground hover:text-foreground'}"
1674
- onclick={() => (inspectTab = 'raw')}
1675
- >
1676
- Raw JSON
1677
- </button>
1670
+ <div class="flex items-center justify-between border-b">
1671
+ <div class="flex">
1672
+ <button
1673
+ class="px-4 py-2 text-sm font-medium transition-colors {inspectTab === 'parsed'
1674
+ ? 'border-primary text-foreground border-b-2'
1675
+ : 'text-muted-foreground hover:text-foreground'}"
1676
+ onclick={() => (inspectTab = 'parsed')}
1677
+ >
1678
+ Parsed
1679
+ </button>
1680
+ <button
1681
+ class="px-4 py-2 text-sm font-medium transition-colors {inspectTab === 'raw'
1682
+ ? 'border-primary text-foreground border-b-2'
1683
+ : 'text-muted-foreground hover:text-foreground'}"
1684
+ onclick={() => (inspectTab = 'raw')}
1685
+ >
1686
+ Raw JSON
1687
+ </button>
1688
+ </div>
1689
+ <div class="flex gap-1 pr-2">
1690
+ <button
1691
+ class="rounded px-2 py-1 text-xs font-medium transition-colors {inspectPerspective ===
1692
+ 'draft'
1693
+ ? 'bg-muted text-foreground'
1694
+ : 'text-muted-foreground hover:text-foreground'}"
1695
+ onclick={() => (inspectPerspective = 'draft')}
1696
+ >
1697
+ Draft
1698
+ </button>
1699
+ <button
1700
+ class="rounded px-2 py-1 text-xs font-medium transition-colors {inspectPerspective ===
1701
+ 'published'
1702
+ ? 'bg-muted text-foreground'
1703
+ : 'text-muted-foreground hover:text-foreground'}"
1704
+ onclick={() => (inspectPerspective = 'published')}
1705
+ >
1706
+ Published
1707
+ </button>
1708
+ </div>
1678
1709
  </div>
1679
1710
 
1680
1711
  <!-- Content -->
1681
1712
  <div class="flex-1 overflow-auto p-4 font-mono text-sm">
1682
- {#if inspectTab === 'raw'}
1683
- <pre
1684
- class="text-xs break-all whitespace-pre-wrap select-text"
1685
- tabindex="0"
1686
- onkeydown={(e) => {
1687
- if ((e.metaKey || e.ctrlKey) && e.key === 'a') {
1688
- e.preventDefault();
1689
- e.stopPropagation();
1690
- const sel = window.getSelection();
1691
- const range = document.createRange();
1692
- range.selectNodeContents(e.currentTarget);
1693
- sel?.removeAllRanges();
1694
- sel?.addRange(range);
1695
- }
1696
- }}>{@html syntaxHighlightJson(
1697
- JSON.stringify(
1698
- { id: documentId, _meta: fullDocument?._meta, ...documentData },
1699
- null,
1700
- 2
1701
- )
1702
- )}</pre>
1713
+ {#if inspectPerspective === 'published' && !publishedData}
1714
+ <p class="text-muted-foreground text-sm">No published data available.</p>
1703
1715
  {:else}
1704
- {@render parsedValue(
1705
- null,
1706
- { id: documentId, _meta: fullDocument?._meta, ...documentData },
1707
- 0
1708
- )}
1716
+ {@const inspectData =
1717
+ inspectPerspective === 'published' && publishedData
1718
+ ? { id: documentId, _meta: fullDocument?._meta, ...publishedData }
1719
+ : { id: documentId, _meta: fullDocument?._meta, ...documentData }}
1720
+ {#if inspectTab === 'raw'}
1721
+ <!-- svelte-ignore a11y_no_noninteractive_tabindex -->
1722
+ <!-- svelte-ignore a11y_no_noninteractive_element_interactions -->
1723
+ <pre
1724
+ class="text-xs break-all whitespace-pre-wrap select-text"
1725
+ tabindex="0"
1726
+ onkeydown={(e) => {
1727
+ if ((e.metaKey || e.ctrlKey) && e.key === 'a') {
1728
+ e.preventDefault();
1729
+ e.stopPropagation();
1730
+ const sel = window.getSelection();
1731
+ const range = document.createRange();
1732
+ range.selectNodeContents(e.currentTarget);
1733
+ sel?.removeAllRanges();
1734
+ sel?.addRange(range);
1735
+ }
1736
+ }}>{@html syntaxHighlightJson(JSON.stringify(inspectData, null, 2))}</pre>
1737
+ {:else}
1738
+ {@render parsedValue(null, inspectData, 0)}
1739
+ {/if}
1709
1740
  {/if}
1710
1741
  </div>
1711
1742
  </div>
@@ -1 +1 @@
1
- {"version":3,"file":"DocumentEditor.svelte.d.ts","sourceRoot":"","sources":["../../../src/lib/components/admin/DocumentEditor.svelte.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAexD,UAAU,KAAK;IACd,OAAO,EAAE,UAAU,EAAE,CAAC;IACtB,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,UAAU,EAAE,OAAO,CAAC;IACpB,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB,OAAO,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,WAAW,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAC1D,SAAS,CAAC,EAAE,MAAM,IAAI,CAAC;IACvB,WAAW,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,IAAI,CAAC;IAC3C,aAAa,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,IAAI,CAAC;IAC7C,UAAU,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,IAAI,CAAC;IAC1C,eAAe,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,KAAK,IAAI,CAAC;IACrE,oBAAoB,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,IAAI,CAAC;IACpD,sBAAsB,CAAC,EAAE;QACxB,aAAa,EAAE,MAAM,CAAC;QACtB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;QAC1B,SAAS,EAAE,MAAM,CAAC;QAClB,SAAS,CAAC,EAAE,MAAM,CAAC;KACnB,GAAG,IAAI,CAAC;IACT,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,2EAA2E;IAC3E,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,6EAA6E;IAC7E,aAAa,CAAC,EAAE,MAAM,IAAI,CAAC;CAC3B;AAgiDF,QAAA,MAAM,cAAc,2CAAwC,CAAC;AAC7D,KAAK,cAAc,GAAG,UAAU,CAAC,OAAO,cAAc,CAAC,CAAC;AACxD,eAAe,cAAc,CAAC"}
1
+ {"version":3,"file":"DocumentEditor.svelte.d.ts","sourceRoot":"","sources":["../../../src/lib/components/admin/DocumentEditor.svelte.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAexD,UAAU,KAAK;IACd,OAAO,EAAE,UAAU,EAAE,CAAC;IACtB,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,UAAU,EAAE,OAAO,CAAC;IACpB,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB,OAAO,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,WAAW,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAC1D,SAAS,CAAC,EAAE,MAAM,IAAI,CAAC;IACvB,WAAW,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,IAAI,CAAC;IAC3C,aAAa,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,IAAI,CAAC;IAC7C,UAAU,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,IAAI,CAAC;IAC1C,eAAe,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,KAAK,IAAI,CAAC;IACrE,oBAAoB,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,IAAI,CAAC;IACpD,sBAAsB,CAAC,EAAE;QACxB,aAAa,EAAE,MAAM,CAAC;QACtB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;QAC1B,SAAS,EAAE,MAAM,CAAC;QAClB,SAAS,CAAC,EAAE,MAAM,CAAC;KACnB,GAAG,IAAI,CAAC;IACT,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,2EAA2E;IAC3E,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,6EAA6E;IAC7E,aAAa,CAAC,EAAE,MAAM,IAAI,CAAC;CAC3B;AAsjDF,QAAA,MAAM,cAAc,2CAAwC,CAAC;AAC7D,KAAK,cAAc,GAAG,UAAU,CAAC,OAAO,cAAc,CAAC,CAAC;AACxD,eAAe,cAAc,CAAC"}
@@ -18,8 +18,7 @@
18
18
  ) => void;
19
19
  }
20
20
 
21
- let { documentId, onClose, onRestored, onPreviewVersion }: Props = $props();
22
- void onRestored;
21
+ let { documentId, onClose, onPreviewVersion }: Props = $props();
23
22
 
24
23
  let versions = $state<any[]>([]);
25
24
  let loading = $state(true);
@@ -120,6 +119,8 @@
120
119
  </div>
121
120
  {:else}
122
121
  {#each filteredVersions as version, i}
122
+ <!-- svelte-ignore a11y_click_events_have_key_events -->
123
+ <!-- svelte-ignore a11y_no_static_element_interactions -->
123
124
  <div
124
125
  data-version-id={i}
125
126
  class="hover:bg-muted w-full cursor-pointer border-b px-3 py-2.5 text-left transition-colors {previewVersion?.versionNumber ===
@@ -1 +1 @@
1
- {"version":3,"file":"DocumentVersionPanel.svelte.d.ts","sourceRoot":"","sources":["../../../src/lib/components/admin/DocumentVersionPanel.svelte.ts"],"names":[],"mappings":"AASC,UAAU,KAAK;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,IAAI,CAAC;IACxB,gBAAgB,CAAC,EAAE,CAClB,OAAO,EAAE;QACR,aAAa,EAAE,MAAM,CAAC;QACtB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;QAC1B,SAAS,EAAE,MAAM,CAAC;QAClB,SAAS,CAAC,EAAE,MAAM,CAAC;KACnB,GAAG,IAAI,KACJ,IAAI,CAAC;CACV;AAkIF,QAAA,MAAM,oBAAoB;;MAAwC,CAAC;AACnE,KAAK,oBAAoB,GAAG,UAAU,CAAC,OAAO,oBAAoB,CAAC,CAAC;AACpE,eAAe,oBAAoB,CAAC"}
1
+ {"version":3,"file":"DocumentVersionPanel.svelte.d.ts","sourceRoot":"","sources":["../../../src/lib/components/admin/DocumentVersionPanel.svelte.ts"],"names":[],"mappings":"AASC,UAAU,KAAK;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,IAAI,CAAC;IACxB,gBAAgB,CAAC,EAAE,CAClB,OAAO,EAAE;QACR,aAAa,EAAE,MAAM,CAAC;QACtB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;QAC1B,SAAS,EAAE,MAAM,CAAC;QAClB,SAAS,CAAC,EAAE,MAAM,CAAC;KACnB,GAAG,IAAI,KACJ,IAAI,CAAC;CACV;AAmIF,QAAA,MAAM,oBAAoB;;MAAwC,CAAC;AACnE,KAAK,oBAAoB,GAAG,UAAU,CAAC,OAAO,oBAAoB,CAAC,CAAC;AACpE,eAAe,oBAAoB,CAAC"}
@@ -106,7 +106,8 @@
106
106
  // Bulk selection state
107
107
  let selectMode = $state(false);
108
108
  let selectedIds = $state<Set<string>>(
109
- selectable && multiSelect && existingAssetIds ? new Set(existingAssetIds) : new Set()
109
+ (() =>
110
+ selectable && multiSelect && existingAssetIds ? new Set(existingAssetIds) : new Set())()
110
111
  );
111
112
  let isBulkDeleting = $state(false);
112
113
 
@@ -433,6 +434,14 @@
433
434
 
434
435
  // Delete asset
435
436
  async function deleteAsset(asset: Asset) {
437
+ try {
438
+ const result = await assets.getReferenceCounts([asset.id]);
439
+ if (result.success && result.data) {
440
+ referenceCounts = { ...referenceCounts, ...result.data };
441
+ }
442
+ } catch {
443
+ // Fall through to cached count
444
+ }
436
445
  const refCount = referenceCounts[asset.id] || 0;
437
446
  if (refCount > 0) {
438
447
  toast.error(
@@ -826,12 +835,21 @@
826
835
  </div>
827
836
  {/if}
828
837
  {#if selectable}
829
- <!-- Info button to view details without selecting -->
830
- <button
838
+ <!-- svelte-ignore a11y_no_static_element_interactions -->
839
+ <div
840
+ role="button"
841
+ tabindex="0"
831
842
  onclick={(e) => {
832
843
  e.stopPropagation();
833
844
  openAssetDetail(asset);
834
845
  }}
846
+ onkeydown={(e) => {
847
+ if (e.key === 'Enter' || e.key === ' ') {
848
+ e.preventDefault();
849
+ e.stopPropagation();
850
+ openAssetDetail(asset);
851
+ }
852
+ }}
835
853
  class="bg-background/80 absolute top-1.5 right-1.5 rounded p-1 opacity-0 transition-opacity group-hover:opacity-100"
836
854
  title="View details"
837
855
  >
@@ -848,7 +866,7 @@
848
866
  d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"
849
867
  />
850
868
  </svg>
851
- </button>
869
+ </div>
852
870
  {:else if isSelectMode}
853
871
  <!-- Checkbox overlay for bulk mode -->
854
872
  <div class="absolute top-1.5 left-1.5">
@@ -1 +1 @@
1
- {"version":3,"file":"MediaBrowser.svelte.d.ts","sourceRoot":"","sources":["../../../src/lib/components/admin/MediaBrowser.svelte.ts"],"names":[],"mappings":"AAgCA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAS9C,UAAU,KAAK;IACd,8DAA8D;IAC9D,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,yEAAyE;IACzE,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,8DAA8D;IAC9D,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IAClC,qEAAqE;IACrE,gBAAgB,CAAC,EAAE,CAAC,MAAM,EAAE,KAAK,EAAE,KAAK,IAAI,CAAC;IAC7C,oCAAoC;IACpC,eAAe,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;IACnC,gCAAgC;IAChC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,mFAAmF;IACnF,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,6DAA6D;IAC7D,gBAAgB,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;CAC/B;AAgqCF,QAAA,MAAM,YAAY,2CAAwC,CAAC;AAC3D,KAAK,YAAY,GAAG,UAAU,CAAC,OAAO,YAAY,CAAC,CAAC;AACpD,eAAe,YAAY,CAAC"}
1
+ {"version":3,"file":"MediaBrowser.svelte.d.ts","sourceRoot":"","sources":["../../../src/lib/components/admin/MediaBrowser.svelte.ts"],"names":[],"mappings":"AAgCA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAS9C,UAAU,KAAK;IACd,8DAA8D;IAC9D,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,yEAAyE;IACzE,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,8DAA8D;IAC9D,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IAClC,qEAAqE;IACrE,gBAAgB,CAAC,EAAE,CAAC,MAAM,EAAE,KAAK,EAAE,KAAK,IAAI,CAAC;IAC7C,oCAAoC;IACpC,eAAe,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;IACnC,gCAAgC;IAChC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,mFAAmF;IACnF,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,6DAA6D;IAC7D,gBAAgB,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;CAC/B;AA+qCF,QAAA,MAAM,YAAY,2CAAwC,CAAC;AAC3D,KAAK,YAAY,GAAG,UAAU,CAAC,OAAO,YAAY,CAAC,CAAC;AACpD,eAAe,YAAY,CAAC"}