@glw907/cairn-cms 0.60.1 → 0.62.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.
- package/CHANGELOG.md +69 -0
- package/dist/components/AdminLayout.svelte +22 -0
- package/dist/components/CairnAdmin.svelte +3 -0
- package/dist/components/CairnTidySettings.svelte +2 -2
- package/dist/components/CairnTidySettings.svelte.d.ts +1 -1
- package/dist/components/EditPage.svelte +116 -39
- package/dist/components/HelpHome.svelte +824 -0
- package/dist/components/HelpHome.svelte.d.ts +22 -0
- package/dist/components/MarkdownHelpDialog.svelte +4 -15
- package/dist/components/client-ingest.d.ts +16 -8
- package/dist/components/client-ingest.js +12 -6
- package/dist/components/editor-media.js +16 -8
- package/dist/components/editor-placeholder.d.ts +4 -2
- package/dist/components/editor-tidy.d.ts +24 -12
- package/dist/components/editor-tidy.js +8 -4
- package/dist/components/index.d.ts +1 -0
- package/dist/components/index.js +1 -0
- package/dist/components/link-completion.d.ts +12 -6
- package/dist/components/link-completion.js +12 -6
- package/dist/components/markdown-directives.d.ts +9 -6
- package/dist/components/markdown-directives.js +9 -6
- package/dist/components/markdown-format.d.ts +7 -2
- package/dist/components/markdown-format.js +59 -28
- package/dist/components/markdown-reference.d.ts +8 -0
- package/dist/components/markdown-reference.js +22 -0
- package/dist/components/media-upload-outcome.d.ts +12 -6
- package/dist/components/objective-errors.d.ts +8 -4
- package/dist/components/objective-errors.js +8 -4
- package/dist/components/preview-doc.d.ts +4 -2
- package/dist/components/preview-doc.js +4 -2
- package/dist/components/spellcheck.d.ts +55 -29
- package/dist/components/spellcheck.js +39 -21
- package/dist/components/tidy-categorize.d.ts +20 -10
- package/dist/components/tidy-categorize.js +16 -8
- package/dist/components/tidy-validate.d.ts +12 -6
- package/dist/components/tidy-validate.js +20 -10
- package/dist/components/topbar-context.d.ts +4 -2
- package/dist/content/advisories.d.ts +51 -0
- package/dist/content/advisories.js +79 -0
- package/dist/content/compose.d.ts +4 -2
- package/dist/content/compose.js +1 -0
- package/dist/content/excerpt.js +4 -2
- package/dist/content/getting-started.d.ts +18 -0
- package/dist/content/getting-started.js +12 -0
- package/dist/content/links.d.ts +16 -8
- package/dist/content/links.js +12 -6
- package/dist/content/manifest.d.ts +36 -18
- package/dist/content/manifest.js +32 -16
- package/dist/content/media-refs.d.ts +4 -2
- package/dist/content/media-refs.js +4 -2
- package/dist/content/media-rewrite.d.ts +8 -4
- package/dist/content/media-rewrite.js +76 -38
- package/dist/content/schema.d.ts +20 -10
- package/dist/content/site-dictionary.d.ts +4 -2
- package/dist/content/site-dictionary.js +8 -4
- package/dist/content/types.d.ts +97 -42
- package/dist/delivery/content-index.d.ts +16 -8
- package/dist/delivery/feeds.js +4 -2
- package/dist/delivery/json-ld.d.ts +3 -0
- package/dist/delivery/json-ld.js +3 -0
- package/dist/delivery/manifest.d.ts +4 -2
- package/dist/delivery/manifest.js +4 -2
- package/dist/delivery/public-routes.d.ts +12 -6
- package/dist/delivery/public-routes.js +4 -2
- package/dist/delivery/seo-fields.d.ts +12 -6
- package/dist/delivery/seo-fields.js +8 -4
- package/dist/delivery/site-indexes.d.ts +4 -2
- package/dist/delivery/site-resolver.d.ts +4 -2
- package/dist/delivery/site-resolver.js +4 -2
- package/dist/doctor/cloudflare-api.d.ts +6 -0
- package/dist/doctor/cloudflare-api.js +6 -0
- package/dist/doctor/index.d.ts +12 -6
- package/dist/doctor/report.d.ts +3 -0
- package/dist/doctor/report.js +3 -0
- package/dist/doctor/run.d.ts +3 -0
- package/dist/doctor/run.js +3 -0
- package/dist/doctor/types.d.ts +10 -2
- package/dist/doctor/types.js +6 -0
- package/dist/doctor/wrangler-config.d.ts +7 -2
- package/dist/doctor/wrangler-config.js +3 -0
- package/dist/email.d.ts +4 -2
- package/dist/env.d.ts +0 -3
- package/dist/env.js +0 -3
- package/dist/github/branches.d.ts +4 -2
- package/dist/github/branches.js +4 -2
- package/dist/github/signing.d.ts +1 -1
- package/dist/github/signing.js +2 -2
- package/dist/log/events.d.ts +1 -1
- package/dist/media/bulk-delete-plan.d.ts +8 -4
- package/dist/media/config.d.ts +12 -6
- package/dist/media/config.js +16 -8
- package/dist/media/delivery-bucket.d.ts +4 -2
- package/dist/media/library-entry.d.ts +4 -2
- package/dist/media/library-entry.js +4 -2
- package/dist/media/manifest.d.ts +29 -15
- package/dist/media/manifest.js +29 -16
- package/dist/media/naming.d.ts +12 -6
- package/dist/media/naming.js +24 -12
- package/dist/media/orphan-scan.d.ts +4 -2
- package/dist/media/reconcile.d.ts +21 -11
- package/dist/media/reconcile.js +12 -6
- package/dist/media/reference.d.ts +8 -4
- package/dist/media/reference.js +12 -6
- package/dist/media/rewrite-plan.d.ts +12 -6
- package/dist/media/sniff.d.ts +4 -2
- package/dist/media/sniff.js +28 -14
- package/dist/media/store.d.ts +16 -8
- package/dist/media/store.js +4 -2
- package/dist/media/transform-url.d.ts +12 -6
- package/dist/media/transform-url.js +8 -4
- package/dist/media/usage.d.ts +8 -4
- package/dist/nav/site-config.d.ts +16 -8
- package/dist/render/component-grammar.d.ts +23 -10
- package/dist/render/component-grammar.js +19 -8
- package/dist/render/component-insert.d.ts +8 -4
- package/dist/render/component-insert.js +4 -2
- package/dist/render/component-reference.d.ts +4 -2
- package/dist/render/component-reference.js +4 -2
- package/dist/render/component-validate.d.ts +3 -0
- package/dist/render/component-validate.js +3 -0
- package/dist/render/glyph.d.ts +4 -2
- package/dist/render/glyph.js +4 -2
- package/dist/render/pipeline.d.ts +20 -10
- package/dist/render/pipeline.js +4 -2
- package/dist/render/registry.d.ts +40 -20
- package/dist/render/registry.js +16 -8
- package/dist/render/rehype-dispatch.d.ts +22 -8
- package/dist/render/rehype-dispatch.js +22 -8
- package/dist/render/remark-directives.d.ts +3 -0
- package/dist/render/remark-directives.js +3 -0
- package/dist/render/remark-figure.d.ts +4 -2
- package/dist/render/remark-figure.js +4 -2
- package/dist/render/resolve-links.d.ts +4 -2
- package/dist/render/resolve-links.js +4 -2
- package/dist/render/resolve-media.d.ts +16 -8
- package/dist/render/resolve-media.js +12 -6
- package/dist/sveltekit/admin-dispatch.d.ts +2 -0
- package/dist/sveltekit/admin-dispatch.js +9 -3
- package/dist/sveltekit/auth-routes.d.ts +3 -0
- package/dist/sveltekit/auth-routes.js +3 -0
- package/dist/sveltekit/cairn-admin.d.ts +16 -5
- package/dist/sveltekit/cairn-admin.js +26 -10
- package/dist/sveltekit/content-routes.d.ts +191 -86
- package/dist/sveltekit/content-routes.js +295 -107
- package/dist/sveltekit/editors-routes.d.ts +3 -0
- package/dist/sveltekit/editors-routes.js +3 -0
- package/dist/sveltekit/guard.d.ts +4 -2
- package/dist/sveltekit/guard.js +4 -2
- package/dist/sveltekit/https-required-page.d.ts +1 -1
- package/dist/sveltekit/https-required-page.js +1 -1
- package/dist/sveltekit/index.d.ts +1 -1
- package/dist/sveltekit/media-route.d.ts +1 -2
- package/dist/sveltekit/media-route.js +13 -8
- package/dist/sveltekit/nav-routes.d.ts +7 -2
- package/dist/sveltekit/nav-routes.js +3 -0
- package/dist/sveltekit/types.d.ts +4 -2
- package/dist/vite/index.d.ts +32 -16
- package/dist/vite/index.js +52 -26
- package/dist/vite/resolve-root.d.ts +8 -4
- package/dist/vite/resolve-root.js +4 -2
- package/package.json +7 -1
- package/src/lib/components/AdminLayout.svelte +22 -0
- package/src/lib/components/CairnAdmin.svelte +3 -0
- package/src/lib/components/CairnTidySettings.svelte +2 -2
- package/src/lib/components/ComponentForm.svelte +0 -1
- package/src/lib/components/EditPage.svelte +133 -41
- package/src/lib/components/HelpHome.svelte +850 -0
- package/src/lib/components/MarkdownHelpDialog.svelte +4 -15
- package/src/lib/components/client-ingest.ts +20 -10
- package/src/lib/components/editor-media.ts +20 -10
- package/src/lib/components/editor-placeholder.ts +12 -6
- package/src/lib/components/editor-tidy.ts +28 -14
- package/src/lib/components/index.ts +1 -0
- package/src/lib/components/link-completion.ts +12 -6
- package/src/lib/components/markdown-directives.ts +13 -8
- package/src/lib/components/markdown-format.ts +63 -30
- package/src/lib/components/markdown-reference.ts +30 -0
- package/src/lib/components/media-upload-outcome.ts +12 -6
- package/src/lib/components/objective-errors.ts +16 -8
- package/src/lib/components/preview-doc.ts +4 -2
- package/src/lib/components/spellcheck.ts +79 -41
- package/src/lib/components/tidy-categorize.ts +28 -14
- package/src/lib/components/tidy-validate.ts +28 -14
- package/src/lib/components/topbar-context.ts +4 -2
- package/src/lib/content/advisories.ts +141 -0
- package/src/lib/content/compose.ts +5 -2
- package/src/lib/content/excerpt.ts +4 -2
- package/src/lib/content/getting-started.ts +31 -0
- package/src/lib/content/links.ts +16 -8
- package/src/lib/content/manifest.ts +36 -18
- package/src/lib/content/media-refs.ts +4 -2
- package/src/lib/content/media-rewrite.ts +100 -50
- package/src/lib/content/schema.ts +20 -10
- package/src/lib/content/site-dictionary.ts +8 -4
- package/src/lib/content/types.ts +97 -42
- package/src/lib/delivery/content-index.ts +16 -8
- package/src/lib/delivery/feeds.ts +4 -2
- package/src/lib/delivery/json-ld.ts +3 -0
- package/src/lib/delivery/manifest.ts +4 -2
- package/src/lib/delivery/public-routes.ts +16 -8
- package/src/lib/delivery/seo-fields.ts +12 -6
- package/src/lib/delivery/site-indexes.ts +4 -2
- package/src/lib/delivery/site-resolver.ts +4 -2
- package/src/lib/doctor/cloudflare-api.ts +6 -0
- package/src/lib/doctor/index.ts +12 -6
- package/src/lib/doctor/report.ts +3 -0
- package/src/lib/doctor/run.ts +3 -0
- package/src/lib/doctor/types.ts +10 -2
- package/src/lib/doctor/wrangler-config.ts +7 -2
- package/src/lib/email.ts +4 -2
- package/src/lib/env.ts +0 -3
- package/src/lib/github/branches.ts +4 -2
- package/src/lib/github/signing.ts +2 -2
- package/src/lib/log/events.ts +1 -0
- package/src/lib/media/bulk-delete-plan.ts +8 -4
- package/src/lib/media/config.ts +24 -12
- package/src/lib/media/delivery-bucket.ts +4 -2
- package/src/lib/media/library-entry.ts +4 -2
- package/src/lib/media/manifest.ts +33 -18
- package/src/lib/media/naming.ts +24 -12
- package/src/lib/media/orphan-scan.ts +4 -2
- package/src/lib/media/reconcile.ts +21 -11
- package/src/lib/media/reference.ts +12 -6
- package/src/lib/media/rewrite-plan.ts +12 -6
- package/src/lib/media/sniff.ts +28 -14
- package/src/lib/media/store.ts +16 -8
- package/src/lib/media/transform-url.ts +12 -6
- package/src/lib/media/usage.ts +8 -4
- package/src/lib/nav/site-config.ts +16 -8
- package/src/lib/render/component-grammar.ts +23 -10
- package/src/lib/render/component-insert.ts +8 -4
- package/src/lib/render/component-reference.ts +4 -2
- package/src/lib/render/component-validate.ts +3 -0
- package/src/lib/render/glyph.ts +4 -2
- package/src/lib/render/pipeline.ts +20 -10
- package/src/lib/render/registry.ts +44 -22
- package/src/lib/render/rehype-dispatch.ts +22 -8
- package/src/lib/render/remark-directives.ts +3 -0
- package/src/lib/render/remark-figure.ts +4 -2
- package/src/lib/render/resolve-links.ts +4 -2
- package/src/lib/render/resolve-media.ts +16 -8
- package/src/lib/sveltekit/admin-dispatch.ts +10 -4
- package/src/lib/sveltekit/auth-routes.ts +3 -0
- package/src/lib/sveltekit/cairn-admin.ts +37 -15
- package/src/lib/sveltekit/content-routes.ts +492 -197
- package/src/lib/sveltekit/editors-routes.ts +3 -0
- package/src/lib/sveltekit/guard.ts +4 -2
- package/src/lib/sveltekit/https-required-page.ts +1 -1
- package/src/lib/sveltekit/index.ts +3 -0
- package/src/lib/sveltekit/media-route.ts +13 -8
- package/src/lib/sveltekit/nav-routes.ts +7 -2
- package/src/lib/sveltekit/types.ts +4 -2
- package/src/lib/vite/index.ts +60 -30
- package/src/lib/vite/resolve-root.ts +8 -4
|
@@ -90,6 +90,11 @@ count, the Prose/Markup posture pair, the focus and typewriter toggles, and the
|
|
|
90
90
|
|
|
91
91
|
let { data, registry, render, icons, form }: Props = $props();
|
|
92
92
|
|
|
93
|
+
/** One action row in an advisory notice: an `href` row renders a link, an `onAct` row a button. */
|
|
94
|
+
type AdvisoryRow = { rowLabel?: string; rowCode?: boolean; label: string; href?: string; onAct?: () => void };
|
|
95
|
+
/** A notice ready to render: the server advisory and the client needs-alt notice both map to this. */
|
|
96
|
+
type RenderNotice = { kind: string; message: string; detail?: string; rows: AdvisoryRow[] };
|
|
97
|
+
|
|
93
98
|
// The client-side tidy deadline (spec 2.1, Task 14): a slow call becomes a cancel/retry rather than a
|
|
94
99
|
// hung review. Set above the action's own 30s Worker deadline so the server's retryable fail lands
|
|
95
100
|
// first when the model is merely slow; this catches a stalled connection past that.
|
|
@@ -150,7 +155,6 @@ count, the Prose/Markup posture pair, the focus and typewriter toggles, and the
|
|
|
150
155
|
const bodyDirty = $derived(body !== (form?.body ?? data.body));
|
|
151
156
|
let fieldsDirty = $state(false);
|
|
152
157
|
const dirty = $derived(bodyDirty || fieldsDirty);
|
|
153
|
-
// What the header's save-state indicator says.
|
|
154
158
|
const saveState = $derived(dirty ? 'Unsaved changes' : data.saved ? 'Saved' : '');
|
|
155
159
|
function onFormInput(e: Event) {
|
|
156
160
|
const target = e.target as Element | null;
|
|
@@ -976,6 +980,41 @@ count, the Prose/Markup posture pair, the focus and typewriter toggles, and the
|
|
|
976
980
|
const heroRows = $derived(imageFields.filter((f) => heroNeedsAlt[f.name]));
|
|
977
981
|
const needsAltCount = $derived(needsAlt.length + heroRows.length);
|
|
978
982
|
|
|
983
|
+
// The advisory region renders two notice sources through one shape: the server's data-only
|
|
984
|
+
// advisories (an action carries an href) and the client-derived needs-alt notice (its rows carry
|
|
985
|
+
// callbacks the editor must run, so they cannot ride the serializable server shape). Both map into
|
|
986
|
+
// this local render type, where the snippet draws an href row as a link and an onAct row as a button.
|
|
987
|
+
const renderNotices = $derived<RenderNotice[]>([
|
|
988
|
+
...data.advisories.map((notice) => ({
|
|
989
|
+
kind: notice.kind,
|
|
990
|
+
message: notice.message,
|
|
991
|
+
rows: (notice.actions ?? []).map((action) => ({ label: action.label, href: action.href })),
|
|
992
|
+
})),
|
|
993
|
+
...(needsAltCount
|
|
994
|
+
? [
|
|
995
|
+
{
|
|
996
|
+
kind: 'needs-alt',
|
|
997
|
+
message: `${needsAltCount} ${needsAltCount === 1 ? 'image needs' : 'images need'} alt text`,
|
|
998
|
+
detail:
|
|
999
|
+
'Alt text describes an image for readers who cannot see it. Add it now, or save and come back to it.',
|
|
1000
|
+
rows: [
|
|
1001
|
+
...needsAlt.map((item) => ({
|
|
1002
|
+
rowLabel: item.ref,
|
|
1003
|
+
rowCode: true,
|
|
1004
|
+
label: 'Add alt text',
|
|
1005
|
+
onAct: () => selectRange(item.from, item.to),
|
|
1006
|
+
})),
|
|
1007
|
+
...heroRows.map((hero) => ({
|
|
1008
|
+
rowLabel: hero.label,
|
|
1009
|
+
label: 'Add alt text',
|
|
1010
|
+
onAct: () => heroFieldRefs[hero.name]?.focusAlt(),
|
|
1011
|
+
})),
|
|
1012
|
+
],
|
|
1013
|
+
},
|
|
1014
|
+
]
|
|
1015
|
+
: []),
|
|
1016
|
+
]);
|
|
1017
|
+
|
|
979
1018
|
// The delete guard's inbound linkers, from a refused delete (fail 409). Empty when the delete was
|
|
980
1019
|
// not refused. When set, a delete was blocked by a link that appeared since the page loaded.
|
|
981
1020
|
const deleteRefusedLinks = $derived(form?.inboundLinks ?? []);
|
|
@@ -1201,7 +1240,6 @@ count, the Prose/Markup posture pair, the focus and typewriter toggles, and the
|
|
|
1201
1240
|
};
|
|
1202
1241
|
});
|
|
1203
1242
|
|
|
1204
|
-
// Coerce a frontmatter value to a string for text/date/textarea inputs.
|
|
1205
1243
|
function str(v: unknown): string {
|
|
1206
1244
|
return v == null ? '' : String(v);
|
|
1207
1245
|
}
|
|
@@ -1216,6 +1254,11 @@ count, the Prose/Markup posture pair, the focus and typewriter toggles, and the
|
|
|
1216
1254
|
const titleField = $derived(data.fields.find((f) => f.name === 'title'));
|
|
1217
1255
|
const draftField = $derived(data.fields.find((f) => f.type === 'boolean' && f.name === 'draft'));
|
|
1218
1256
|
const detailFields = $derived(data.fields.filter((f) => f !== titleField && f !== draftField));
|
|
1257
|
+
|
|
1258
|
+
// The built-in hint a date field carries when its adapter sets no description. The control reads as
|
|
1259
|
+
// if it might schedule publishing, so this reassures the editor that the date is metadata and that
|
|
1260
|
+
// publishing is the separate, deliberate step. A field-level description overrides it.
|
|
1261
|
+
const DATE_PUBLISH_HINT = 'Sets the date for this post. Publishing is a separate step you choose.';
|
|
1219
1262
|
</script>
|
|
1220
1263
|
|
|
1221
1264
|
<!-- The desk controls live in the one header band: AdminLayout renders this snippet through the
|
|
@@ -1342,6 +1385,17 @@ count, the Prose/Markup posture pair, the focus and typewriter toggles, and the
|
|
|
1342
1385
|
</div>
|
|
1343
1386
|
{/snippet}
|
|
1344
1387
|
|
|
1388
|
+
<!-- The author-facing hint under a Details field. The id pairs with the input's aria-describedby
|
|
1389
|
+
(`<name>-hint`); its uniqueness rests on schema field names being unique within a concept, which
|
|
1390
|
+
is also the loop key. So assistive tech announces the sentence without bloating the accessible
|
|
1391
|
+
name. Each field branch decides whether and where to render it; this snippet holds the one shape.
|
|
1392
|
+
The `fld-hint` class is a styling hook with no rule today; the Tailwind utilities do the work. -->
|
|
1393
|
+
{#snippet fieldHint(name: string, text: string)}
|
|
1394
|
+
<p id={`${name}-hint`} class="fld-hint mt-1 text-sm text-[var(--color-muted)]">
|
|
1395
|
+
{text}
|
|
1396
|
+
</p>
|
|
1397
|
+
{/snippet}
|
|
1398
|
+
|
|
1345
1399
|
<!-- The whole edit surface remounts when navigation lands on another entry (see the entryKey
|
|
1346
1400
|
reset above); script-level state and the beforeNavigate registration sit outside the block,
|
|
1347
1401
|
so only the template rebuilds. -->
|
|
@@ -1388,44 +1442,61 @@ count, the Prose/Markup posture pair, the focus and typewriter toggles, and the
|
|
|
1388
1442
|
</ul>
|
|
1389
1443
|
</div>
|
|
1390
1444
|
{/if}
|
|
1391
|
-
<!-- The
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1445
|
+
<!-- The shared advisory notices: one live-region surface for every non-blocking editor warning. It
|
|
1446
|
+
carries the server's address-collision advisory and the client-derived needs-alt notice through
|
|
1447
|
+
one snippet. Each renders as one alert-warning row: the caution glyph, the message, an optional
|
|
1448
|
+
detail sentence, and a list of action rows. Each is a warning, never a block: the author can act
|
|
1449
|
+
on it or save without it. The leading glyph carries the state alongside the message, so the
|
|
1450
|
+
caution reads without relying on hue. A row with an href is a server advisory's link; a row with
|
|
1451
|
+
onAct is the needs-alt jump that runs an editor callback (selecting the image source, or focusing
|
|
1452
|
+
a hero alt input). -->
|
|
1453
|
+
<!-- Keyed by index, not by notice.kind: the kind is a free string with no uniqueness constraint, so
|
|
1454
|
+
two notices of one kind would otherwise throw each_key_duplicate. The list is append-only and
|
|
1455
|
+
never reordered, so the index is a stable key here. -->
|
|
1456
|
+
{#snippet advisoryNotices(notices: RenderNotice[])}
|
|
1457
|
+
{#each notices as notice, i (i)}
|
|
1403
1458
|
<div class="alert alert-warning mb-4 flex-col items-start text-sm">
|
|
1404
1459
|
<p class="flex items-center gap-2 font-medium">
|
|
1405
1460
|
<svg class="h-4 w-4 shrink-0" viewBox="0 0 24 24" fill="none" stroke="currentColor" aria-hidden="true">
|
|
1406
1461
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v4m0 4h.01M10.29 3.86 1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z" />
|
|
1407
1462
|
</svg>
|
|
1408
|
-
<span>{
|
|
1463
|
+
<span>{notice.message}</span>
|
|
1409
1464
|
</p>
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1465
|
+
{#if notice.detail}
|
|
1466
|
+
<p>{notice.detail}</p>
|
|
1467
|
+
{/if}
|
|
1468
|
+
{#if notice.rows.length}
|
|
1469
|
+
<ul class="mt-1 w-full">
|
|
1470
|
+
{#each notice.rows as row, i (i)}
|
|
1471
|
+
<li class="flex items-center justify-between gap-2">
|
|
1472
|
+
{#if row.rowLabel}
|
|
1473
|
+
<!-- A body needs-alt row labels with its source reference in a code span; a hero row
|
|
1474
|
+
and any future labelled row use a plain label. -->
|
|
1475
|
+
{#if row.rowCode}
|
|
1476
|
+
<code class="text-xs">{row.rowLabel}</code>
|
|
1477
|
+
{:else}
|
|
1478
|
+
<span class="text-xs font-medium">{row.rowLabel}</span>
|
|
1479
|
+
{/if}
|
|
1480
|
+
{/if}
|
|
1481
|
+
{#if row.href}
|
|
1482
|
+
<a class="btn btn-xs" href={row.href}>{row.label}</a>
|
|
1483
|
+
{:else}
|
|
1484
|
+
<button type="button" class="btn btn-xs" onclick={row.onAct}>{row.label}</button>
|
|
1485
|
+
{/if}
|
|
1486
|
+
</li>
|
|
1487
|
+
{/each}
|
|
1488
|
+
</ul>
|
|
1489
|
+
{/if}
|
|
1427
1490
|
</div>
|
|
1428
|
-
{/
|
|
1491
|
+
{/each}
|
|
1492
|
+
{/snippet}
|
|
1493
|
+
<!-- The role="status" live region renders unconditionally (present and empty at load), so when the
|
|
1494
|
+
first notice appears it announces; a region conditionally mounted with its first content may not
|
|
1495
|
+
be observed by assistive tech (WCAG 4.1.3). The notices gate on their own presence, so an empty
|
|
1496
|
+
region shows nothing. A plain wrapper (not display:contents) carries the role, since some
|
|
1497
|
+
assistive tech drops a role off a display:contents box. -->
|
|
1498
|
+
<div role="status">
|
|
1499
|
+
{@render advisoryNotices(renderNotices)}
|
|
1429
1500
|
</div>
|
|
1430
1501
|
{#if draftWarning}
|
|
1431
1502
|
<div class="alert alert-warning mb-4 text-sm">
|
|
@@ -1817,23 +1888,37 @@ count, the Prose/Markup posture pair, the focus and typewriter toggles, and the
|
|
|
1817
1888
|
{@const f = field as TextareaField}
|
|
1818
1889
|
<label class="flex flex-col gap-1">
|
|
1819
1890
|
<span class="text-sm font-medium">{f.label}</span>
|
|
1820
|
-
<textarea class="textarea textarea-sm" name={f.name} aria-label={f.label} rows={f.rows ?? 3}>{str(data.frontmatter[f.name])}</textarea>
|
|
1891
|
+
<textarea class="textarea textarea-sm" name={f.name} aria-label={f.label} aria-describedby={f.description ? `${f.name}-hint` : undefined} rows={f.rows ?? 3}>{str(data.frontmatter[f.name])}</textarea>
|
|
1892
|
+
{#if f.description}
|
|
1893
|
+
{@render fieldHint(f.name, f.description)}
|
|
1894
|
+
{/if}
|
|
1821
1895
|
</label>
|
|
1822
1896
|
{:else if field.type === 'date'}
|
|
1823
1897
|
<label class="flex flex-col gap-1">
|
|
1824
1898
|
<span class="text-sm font-medium">{field.label}</span>
|
|
1825
|
-
|
|
1899
|
+
<!-- A date field always carries a hint: the adapter's description when set, else the
|
|
1900
|
+
built-in publish-clarity default. So aria-describedby always points at the paragraph. -->
|
|
1901
|
+
<input class="input input-sm" type="date" name={field.name} aria-label={field.label} aria-describedby={`${field.name}-hint`} value={str(data.frontmatter[field.name])} />
|
|
1902
|
+
{@render fieldHint(field.name, field.description || DATE_PUBLISH_HINT)}
|
|
1826
1903
|
</label>
|
|
1827
1904
|
{:else if field.type === 'boolean'}
|
|
1828
|
-
<
|
|
1829
|
-
<
|
|
1830
|
-
|
|
1831
|
-
|
|
1905
|
+
<div class="flex flex-col gap-1">
|
|
1906
|
+
<label class="label cursor-pointer justify-start gap-2">
|
|
1907
|
+
<input class="checkbox checkbox-sm" type="checkbox" name={field.name} aria-label={field.label} aria-describedby={field.description ? `${field.name}-hint` : undefined} checked={data.frontmatter[field.name] === true} />
|
|
1908
|
+
<span class="text-sm">{field.label}</span>
|
|
1909
|
+
</label>
|
|
1910
|
+
{#if field.description}
|
|
1911
|
+
{@render fieldHint(field.name, field.description)}
|
|
1912
|
+
{/if}
|
|
1913
|
+
</div>
|
|
1832
1914
|
{:else if field.type === 'tags'}
|
|
1833
1915
|
{@const f = field as TagsField}
|
|
1834
1916
|
{@const selected = (data.frontmatter[f.name] ?? []) as string[]}
|
|
1835
|
-
<fieldset class="fieldset">
|
|
1917
|
+
<fieldset class="fieldset" aria-describedby={f.description ? `${f.name}-hint` : undefined}>
|
|
1836
1918
|
<legend class="fieldset-legend">{f.label}</legend>
|
|
1919
|
+
{#if f.description}
|
|
1920
|
+
{@render fieldHint(f.name, f.description)}
|
|
1921
|
+
{/if}
|
|
1837
1922
|
<div class="flex flex-wrap gap-2">
|
|
1838
1923
|
{#each f.options as option (option)}
|
|
1839
1924
|
<label class="label cursor-pointer justify-start gap-2">
|
|
@@ -1858,9 +1943,13 @@ count, the Prose/Markup posture pair, the focus and typewriter toggles, and the
|
|
|
1858
1943
|
class="input input-sm"
|
|
1859
1944
|
name={f.name}
|
|
1860
1945
|
aria-label={f.label}
|
|
1946
|
+
aria-describedby={f.description ? `${f.name}-hint` : undefined}
|
|
1861
1947
|
placeholder={f.placeholder}
|
|
1862
1948
|
value={tagValue}
|
|
1863
1949
|
/>
|
|
1950
|
+
{#if f.description}
|
|
1951
|
+
{@render fieldHint(f.name, f.description)}
|
|
1952
|
+
{/if}
|
|
1864
1953
|
</label>
|
|
1865
1954
|
{:else if field.type === 'image'}
|
|
1866
1955
|
{@const heroValue = data.frontmatter[field.name] as ImageValue | undefined}
|
|
@@ -1879,7 +1968,10 @@ count, the Prose/Markup posture pair, the focus and typewriter toggles, and the
|
|
|
1879
1968
|
{:else}
|
|
1880
1969
|
<label class="flex flex-col gap-1">
|
|
1881
1970
|
<span class="text-sm font-medium">{field.label}</span>
|
|
1882
|
-
<input class="input input-sm" name={field.name} aria-label={field.label} value={str(data.frontmatter[field.name])} required={field.required} />
|
|
1971
|
+
<input class="input input-sm" name={field.name} aria-label={field.label} aria-describedby={field.description ? `${field.name}-hint` : undefined} value={str(data.frontmatter[field.name])} required={field.required} />
|
|
1972
|
+
{#if field.description}
|
|
1973
|
+
{@render fieldHint(field.name, field.description)}
|
|
1974
|
+
{/if}
|
|
1883
1975
|
</label>
|
|
1884
1976
|
{/if}
|
|
1885
1977
|
{/each}
|