@elytracms/studio 0.0.32 → 0.0.34
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/components/app-views/default-modules.js +20 -11
- package/dist/components/app-views/default-modules.js.map +1 -1
- package/dist/components/assets/asset-library.js +21 -13
- package/dist/components/assets/asset-library.js.map +1 -1
- package/dist/components/assets/asset-thumb.js +3 -2
- package/dist/components/assets/asset-thumb.js.map +1 -1
- package/dist/components/backend-gate.js +4 -3
- package/dist/components/backend-gate.js.map +1 -1
- package/dist/components/builder/blocks-panel.js +11 -2
- package/dist/components/builder/blocks-panel.js.map +1 -1
- package/dist/components/builder/canvas.js +6 -5
- package/dist/components/builder/canvas.js.map +1 -1
- package/dist/components/builder/clipboard-actions.js +12 -6
- package/dist/components/builder/clipboard-actions.js.map +1 -1
- package/dist/components/builder/composition-field-editor.js +7 -4
- package/dist/components/builder/composition-field-editor.js.map +1 -1
- package/dist/components/builder/fixture-thumbnail.js +2 -1
- package/dist/components/builder/fixture-thumbnail.js.map +1 -1
- package/dist/components/builder/layout-inspector.d.ts +5 -5
- package/dist/components/builder/layout-inspector.js +21 -20
- package/dist/components/builder/layout-inspector.js.map +1 -1
- package/dist/components/builder/page-tree.js +5 -4
- package/dist/components/builder/page-tree.js.map +1 -1
- package/dist/components/builder/property-inspector.js +10 -10
- package/dist/components/builder/property-inspector.js.map +1 -1
- package/dist/components/builder/reuse-context.js +9 -9
- package/dist/components/builder/reuse-context.js.map +1 -1
- package/dist/components/builder/rich-text-toolbar.js +4 -3
- package/dist/components/builder/rich-text-toolbar.js.map +1 -1
- package/dist/components/builder/spacing-handles.js +4 -3
- package/dist/components/builder/spacing-handles.js.map +1 -1
- package/dist/components/cms/asset-picker.js +8 -7
- package/dist/components/cms/asset-picker.js.map +1 -1
- package/dist/components/cms/bulk-bar.js +8 -5
- package/dist/components/cms/bulk-bar.js.map +1 -1
- package/dist/components/cms/cell.js +9 -5
- package/dist/components/cms/cell.js.map +1 -1
- package/dist/components/cms/cms-store.d.ts +7 -6
- package/dist/components/cms/cms-store.js +21 -12
- package/dist/components/cms/cms-store.js.map +1 -1
- package/dist/components/cms/collection-table.js +18 -7
- package/dist/components/cms/collection-table.js.map +1 -1
- package/dist/components/cms/detail-editor.js +45 -29
- package/dist/components/cms/detail-editor.js.map +1 -1
- package/dist/components/cms/details-pane.js +4 -3
- package/dist/components/cms/details-pane.js.map +1 -1
- package/dist/components/cms/editable-cell.js +4 -4
- package/dist/components/cms/editable-cell.js.map +1 -1
- package/dist/components/cms/field-control.js +29 -21
- package/dist/components/cms/field-control.js.map +1 -1
- package/dist/components/cms/field-renderer.js +2 -1
- package/dist/components/cms/field-renderer.js.map +1 -1
- package/dist/components/cms/filter-builder.js +9 -8
- package/dist/components/cms/filter-builder.js.map +1 -1
- package/dist/components/cms/import-export.js +3 -2
- package/dist/components/cms/import-export.js.map +1 -1
- package/dist/components/cms/issues-pane.js +3 -2
- package/dist/components/cms/issues-pane.js.map +1 -1
- package/dist/components/cms/reference-confirm.js +24 -10
- package/dist/components/cms/reference-confirm.js.map +1 -1
- package/dist/components/cms/relation-picker.js +5 -4
- package/dist/components/cms/relation-picker.js.map +1 -1
- package/dist/components/cms/scalar-value-editor.js +5 -5
- package/dist/components/cms/scalar-value-editor.js.map +1 -1
- package/dist/components/cms/version-compare.js +36 -21
- package/dist/components/cms/version-compare.js.map +1 -1
- package/dist/components/cms/versions-pane.js +8 -5
- package/dist/components/cms/versions-pane.js.map +1 -1
- package/dist/components/cms/view-bar.js +3 -2
- package/dist/components/cms/view-bar.js.map +1 -1
- package/dist/components/components/component-detail.js +3 -2
- package/dist/components/components/component-detail.js.map +1 -1
- package/dist/components/components/component-status.js +8 -13
- package/dist/components/components/component-status.js.map +1 -1
- package/dist/components/components/components-index.js +5 -1
- package/dist/components/components/components-index.js.map +1 -1
- package/dist/components/components/field-inspector.js +4 -4
- package/dist/components/components/field-inspector.js.map +1 -1
- package/dist/components/components/fixture-runner.js +4 -1
- package/dist/components/components/fixture-runner.js.map +1 -1
- package/dist/components/components/registry-browser.js +4 -3
- package/dist/components/components/registry-browser.js.map +1 -1
- package/dist/components/delivery-health-banner.js +2 -1
- package/dist/components/delivery-health-banner.js.map +1 -1
- package/dist/components/dev-login-badge.js +2 -1
- package/dist/components/dev-login-badge.js.map +1 -1
- package/dist/components/extensions/extensions-view.js +22 -21
- package/dist/components/extensions/extensions-view.js.map +1 -1
- package/dist/components/guards.js +3 -2
- package/dist/components/guards.js.map +1 -1
- package/dist/components/operation-error.js +3 -2
- package/dist/components/operation-error.js.map +1 -1
- package/dist/components/playground-badge.js +2 -1
- package/dist/components/playground-badge.js.map +1 -1
- package/dist/components/project-list.js +5 -4
- package/dist/components/project-list.js.map +1 -1
- package/dist/components/project-session.js +3 -2
- package/dist/components/project-session.js.map +1 -1
- package/dist/components/project-switcher.js +4 -3
- package/dist/components/project-switcher.js.map +1 -1
- package/dist/components/redirects/redirects-module.js +3 -2
- package/dist/components/redirects/redirects-module.js.map +1 -1
- package/dist/components/references/references-panel.js +7 -6
- package/dist/components/references/references-panel.js.map +1 -1
- package/dist/components/section-nav.js +8 -5
- package/dist/components/section-nav.js.map +1 -1
- package/dist/components/section-state.js +13 -32
- package/dist/components/section-state.js.map +1 -1
- package/dist/components/settings-form.js +2 -1
- package/dist/components/settings-form.js.map +1 -1
- package/dist/components/studio-project-screen.js +3 -2
- package/dist/components/studio-project-screen.js.map +1 -1
- package/dist/components/studio-shell.js +3 -2
- package/dist/components/studio-shell.js.map +1 -1
- package/dist/components/users/users-module.js +5 -4
- package/dist/components/users/users-module.js.map +1 -1
- package/dist/components/workspace-gate.js +2 -1
- package/dist/components/workspace-gate.js.map +1 -1
- package/dist/lib/cms-views/view-model.js +3 -2
- package/dist/lib/cms-views/view-model.js.map +1 -1
- package/dist/lib/i18n/i18n.d.ts +19 -1
- package/dist/lib/i18n/i18n.js +45 -6
- package/dist/lib/i18n/i18n.js.map +1 -1
- package/dist/lib/i18n/index.d.ts +1 -1
- package/dist/lib/i18n/index.js +1 -1
- package/dist/lib/i18n/index.js.map +1 -1
- package/dist/lib/i18n/messages.en.d.ts +11 -4
- package/dist/lib/i18n/messages.en.js +660 -6
- package/dist/lib/i18n/messages.en.js.map +1 -1
- package/dist/lib/references/reference-model.js +6 -4
- package/dist/lib/references/reference-model.js.map +1 -1
- package/package.json +2 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"relation-picker.js","sourceRoot":"","sources":["../../../src/components/cms/relation-picker.tsx"],"names":[],"mappings":"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","sourcesContent":["import { Check, Search, X } from 'lucide-react'\nimport { useEffect, useState } from 'react'\nimport type { DocumentRef } from '@elytracms/core/cms-core'\nimport {\n Badge,\n Button,\n Code,\n Dialog,\n DialogContent,\n DialogDescription,\n DialogFooter,\n DialogHeader,\n DialogTitle,\n Input,\n Row,\n Spacer,\n Text,\n} from '@elytracms/studio/ui'\nimport { cn } from '@elytracms/studio/lib/utils'\nimport { useCollectionView } from '../collection-view/collection-view-context'\n\n/** Pick related document(s) from a target collection (brief §8.4, EC-074). */\nexport function RelationPicker({\n targetCollection,\n cardinality,\n value,\n open,\n onOpenChange,\n onChange,\n excludeIds,\n}: {\n targetCollection: string\n cardinality: 'one' | 'many'\n value: DocumentRef[]\n open: boolean\n onOpenChange: (open: boolean) => void\n onChange: (refs: DocumentRef[]) => void\n /**\n * Document ids to omit from the candidate list (EC-218): a `parent` self-relation\n * passes the editing document plus its descendants, so a page can never be set\n * as its own ancestor (which would form a cycle).\n */\n excludeIds?: ReadonlySet<string>\n}) {\n const source = useCollectionView()\n const [query, setQuery] = useState('')\n const [selected, setSelected] = useState<DocumentRef[]>(value)\n\n // Seed selection only on open transitions — `value` is a fresh array each\n // parent render, so depending on it would reset in-progress multi-selection.\n useEffect(() => {\n if (open) {\n setSelected(value)\n setQuery('')\n }\n }, [open])\n\n const candidates = source.referenceCandidates(targetCollection).filter((d) => {\n if (excludeIds?.has(d.id)) return false\n if (!query.trim()) return true\n return source.titleOf({ collection: targetCollection, id: d.id }).toLowerCase().includes(query.toLowerCase())\n })\n\n const isSelected = (id: string) => selected.some((r) => r.id === id)\n\n function toggle(id: string) {\n const ref: DocumentRef = { collection: targetCollection, id }\n if (cardinality === 'one') {\n setSelected([ref])\n onChange([ref])\n onOpenChange(false)\n return\n }\n setSelected((prev) => (isSelected(id) ? prev.filter((r) => r.id !== id) : [...prev, ref]))\n }\n\n return (\n <Dialog open={open} onOpenChange={onOpenChange}>\n <DialogContent className=\"max-w-md\">\n <DialogHeader>\n <DialogTitle>Pick {cardinality === 'many' ? 'related' : 'a related'} document</DialogTitle>\n <DialogDescription>\n From <Code tone=\"muted\">{targetCollection}</Code>\n {cardinality === 'many' ? ' · select multiple' : ''}\n </DialogDescription>\n </DialogHeader>\n\n <div className=\"relative\">\n <Search className=\"pointer-events-none absolute left-2.5 top-1/2 size-3.5 -translate-y-1/2 text-muted-foreground\" />\n <Input\n autoFocus\n value={query}\n onChange={(e) => setQuery(e.target.value)}\n placeholder=\"Search…\"\n className=\"pl-8\"\n />\n </div>\n\n <div className=\"max-h-72 overflow-auto\">\n {candidates.length === 0 ? (\n <Text size=\"sm\" tone=\"muted\" className=\"p-3\">\n No documents in {targetCollection}.\n </Text>\n ) : (\n candidates.map((doc) => {\n const title = source.titleOf({ collection: targetCollection, id: doc.id })\n const sel = isSelected(doc.id)\n return (\n <button\n key={doc.id}\n type=\"button\"\n onClick={() => toggle(doc.id)}\n className={cn(\n 'flex w-full items-center gap-2 rounded-md px-2 py-1.5 text-left text-sm transition-colors hover:bg-muted',\n sel && 'bg-accent text-accent-foreground',\n )}\n >\n <span className=\"min-w-0 flex-1 truncate font-medium\">{title}</span>\n <Code tone=\"muted\">{doc.id}</Code>\n {sel ? <Check className=\"size-4 text-primary\" /> : null}\n </button>\n )\n })\n )}\n </div>\n\n {value.length > 0 || cardinality === 'many' ? (\n <DialogFooter>\n <Row gap=\"2\" className=\"w-full\">\n {/* EC-246c: a way to CLEAR the relation from the picker — the only\n remove path for a cardinality-`one` relation edited inline in the\n list (the form field has its own per-row X). */}\n {value.length > 0 ? (\n <Button\n variant=\"ghost\"\n className=\"text-destructive hover:text-destructive\"\n data-testid=\"relation-remove\"\n onClick={() => {\n onChange([])\n onOpenChange(false)\n }}\n >\n <X /> Remove\n </Button>\n ) : null}\n <Spacer />\n {cardinality === 'many' ? (\n <>\n <Badge variant=\"outline\">{selected.length} selected</Badge>\n <Button variant=\"ghost\" onClick={() => onOpenChange(false)}>\n Cancel\n </Button>\n <Button\n onClick={() => {\n onChange(selected)\n onOpenChange(false)\n }}\n >\n Apply\n </Button>\n </>\n ) : null}\n </Row>\n </DialogFooter>\n ) : null}\n </DialogContent>\n </Dialog>\n )\n}\n"]}
|
|
1
|
+
{"version":3,"file":"relation-picker.js","sourceRoot":"","sources":["../../../src/components/cms/relation-picker.tsx"],"names":[],"mappings":"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","sourcesContent":["import { Check, Search, X } from 'lucide-react'\nimport { useEffect, useState } from 'react'\nimport type { DocumentRef } from '@elytracms/core/cms-core'\nimport {\n Badge,\n Button,\n Code,\n Dialog,\n DialogContent,\n DialogDescription,\n DialogFooter,\n DialogHeader,\n DialogTitle,\n Input,\n Row,\n Spacer,\n Text,\n} from '@elytracms/studio/ui'\nimport { cn } from '@elytracms/studio/lib/utils'\nimport { translate } from '@elytracms/studio/lib/i18n'\nimport { useCollectionView } from '../collection-view/collection-view-context'\n\n/** Pick related document(s) from a target collection (brief §8.4, EC-074). */\nexport function RelationPicker({\n targetCollection,\n cardinality,\n value,\n open,\n onOpenChange,\n onChange,\n excludeIds,\n}: {\n targetCollection: string\n cardinality: 'one' | 'many'\n value: DocumentRef[]\n open: boolean\n onOpenChange: (open: boolean) => void\n onChange: (refs: DocumentRef[]) => void\n /**\n * Document ids to omit from the candidate list (EC-218): a `parent` self-relation\n * passes the editing document plus its descendants, so a page can never be set\n * as its own ancestor (which would form a cycle).\n */\n excludeIds?: ReadonlySet<string>\n}) {\n const source = useCollectionView()\n const [query, setQuery] = useState('')\n const [selected, setSelected] = useState<DocumentRef[]>(value)\n\n // Seed selection only on open transitions — `value` is a fresh array each\n // parent render, so depending on it would reset in-progress multi-selection.\n useEffect(() => {\n if (open) {\n setSelected(value)\n setQuery('')\n }\n }, [open])\n\n const candidates = source.referenceCandidates(targetCollection).filter((d) => {\n if (excludeIds?.has(d.id)) return false\n if (!query.trim()) return true\n return source.titleOf({ collection: targetCollection, id: d.id }).toLowerCase().includes(query.toLowerCase())\n })\n\n const isSelected = (id: string) => selected.some((r) => r.id === id)\n\n function toggle(id: string) {\n const ref: DocumentRef = { collection: targetCollection, id }\n if (cardinality === 'one') {\n setSelected([ref])\n onChange([ref])\n onOpenChange(false)\n return\n }\n setSelected((prev) => (isSelected(id) ? prev.filter((r) => r.id !== id) : [...prev, ref]))\n }\n\n return (\n <Dialog open={open} onOpenChange={onOpenChange}>\n <DialogContent className=\"max-w-md\">\n <DialogHeader>\n <DialogTitle>\n {translate(cardinality === 'many' ? 'cms.relation.pickTitle.many' : 'cms.relation.pickTitle.one')}\n </DialogTitle>\n <DialogDescription>\n From <Code tone=\"muted\">{targetCollection}</Code>\n {cardinality === 'many' ? ` · ${translate('cms.relation.selectMultipleHint')}` : ''}\n </DialogDescription>\n </DialogHeader>\n\n <div className=\"relative\">\n <Search className=\"pointer-events-none absolute left-2.5 top-1/2 size-3.5 -translate-y-1/2 text-muted-foreground\" />\n <Input\n autoFocus\n value={query}\n onChange={(e) => setQuery(e.target.value)}\n placeholder={translate('common.searchPlaceholder')}\n className=\"pl-8\"\n />\n </div>\n\n <div className=\"max-h-72 overflow-auto\">\n {candidates.length === 0 ? (\n <Text size=\"sm\" tone=\"muted\" className=\"p-3\">\n {translate('cms.relation.noDocuments', { collection: targetCollection })}\n </Text>\n ) : (\n candidates.map((doc) => {\n const title = source.titleOf({ collection: targetCollection, id: doc.id })\n const sel = isSelected(doc.id)\n return (\n <button\n key={doc.id}\n type=\"button\"\n onClick={() => toggle(doc.id)}\n className={cn(\n 'flex w-full items-center gap-2 rounded-md px-2 py-1.5 text-left text-sm transition-colors hover:bg-muted',\n sel && 'bg-accent text-accent-foreground',\n )}\n >\n <span className=\"min-w-0 flex-1 truncate font-medium\">{title}</span>\n <Code tone=\"muted\">{doc.id}</Code>\n {sel ? <Check className=\"size-4 text-primary\" /> : null}\n </button>\n )\n })\n )}\n </div>\n\n {value.length > 0 || cardinality === 'many' ? (\n <DialogFooter>\n <Row gap=\"2\" className=\"w-full\">\n {/* EC-246c: a way to CLEAR the relation from the picker — the only\n remove path for a cardinality-`one` relation edited inline in the\n list (the form field has its own per-row X). */}\n {value.length > 0 ? (\n <Button\n variant=\"ghost\"\n className=\"text-destructive hover:text-destructive\"\n data-testid=\"relation-remove\"\n onClick={() => {\n onChange([])\n onOpenChange(false)\n }}\n >\n <X /> {translate('common.remove')}\n </Button>\n ) : null}\n <Spacer />\n {cardinality === 'many' ? (\n <>\n <Badge variant=\"outline\">{translate('cms.relation.selectedCount', { count: selected.length })}</Badge>\n <Button variant=\"ghost\" onClick={() => onOpenChange(false)}>\n {translate('common.cancel')}\n </Button>\n <Button\n onClick={() => {\n onChange(selected)\n onOpenChange(false)\n }}\n >\n {translate('common.apply')}\n </Button>\n </>\n ) : null}\n </Row>\n </DialogFooter>\n ) : null}\n </DialogContent>\n </Dialog>\n )\n}\n"]}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { useState } from 'react';
|
|
3
3
|
import { Input, Select } from '@elytracms/studio/ui';
|
|
4
|
-
import { localizedLabel } from '@elytracms/studio/lib/i18n';
|
|
4
|
+
import { localizedLabel, translate } from '@elytracms/studio/lib/i18n';
|
|
5
5
|
import { scalarFromText } from '@elytracms/studio/lib/cms-views';
|
|
6
6
|
/**
|
|
7
7
|
* The closed single-scalar value control (EC-247), shared by the filter
|
|
@@ -15,10 +15,10 @@ import { scalarFromText } from '@elytracms/studio/lib/cms-views';
|
|
|
15
15
|
* It is deliberately *closed* — no field type invents a new control — keeping
|
|
16
16
|
* value entry consistent and agent-inspectable across the two surfaces.
|
|
17
17
|
*/
|
|
18
|
-
export function ScalarFieldValueEditor({ option, value, testId, ariaLabel = '
|
|
18
|
+
export function ScalarFieldValueEditor({ option, value, testId, ariaLabel = translate('cms.field.value'), onChange, }) {
|
|
19
19
|
switch (option?.def?.type) {
|
|
20
20
|
case 'boolean':
|
|
21
|
-
return (_jsxs(Select, { "aria-label": ariaLabel, value: value === true ? 'true' : 'false', onChange: (event) => onChange(event.target.value === 'true'), className: "h-7 w-auto py-0 text-xs", "data-testid": testId, children: [_jsx("option", { value: "true", children:
|
|
21
|
+
return (_jsxs(Select, { "aria-label": ariaLabel, value: value === true ? 'true' : 'false', onChange: (event) => onChange(event.target.value === 'true'), className: "h-7 w-auto py-0 text-xs", "data-testid": testId, children: [_jsx("option", { value: "true", children: translate('common.true') }), _jsx("option", { value: "false", children: translate('common.false') })] }));
|
|
22
22
|
case 'select':
|
|
23
23
|
return (_jsxs(Select, { "aria-label": ariaLabel, value: String(value), onChange: (event) => onChange(event.target.value), className: "h-7 w-auto py-0 text-xs", "data-testid": testId, children: [_jsx("option", { value: "", children: "\u2014" }), option.def.options.map((opt) => (_jsx("option", { value: opt.value, children: localizedLabel(opt.label, opt.value) }, opt.value)))] }));
|
|
24
24
|
case 'date':
|
|
@@ -34,9 +34,9 @@ export function ScalarFieldValueEditor({ option, value, testId, ariaLabel = 'Val
|
|
|
34
34
|
* (e.g. a trailing comma in a filter `in` list). Remount (key it) when the
|
|
35
35
|
* field/operator changes so the draft resets to the new initial.
|
|
36
36
|
*/
|
|
37
|
-
export function DraftValueInput({ initial, type = 'text', placeholder, ariaLabel = '
|
|
37
|
+
export function DraftValueInput({ initial, type = 'text', placeholder, ariaLabel = translate('cms.field.value'), testId, onText, }) {
|
|
38
38
|
const [draft, setDraft] = useState(initial);
|
|
39
|
-
return (_jsx(Input, { "aria-label": ariaLabel, type: type, value: draft, placeholder: placeholder ?? '
|
|
39
|
+
return (_jsx(Input, { "aria-label": ariaLabel, type: type, value: draft, placeholder: placeholder ?? translate('cms.field.valuePlaceholder'), onChange: (event) => {
|
|
40
40
|
setDraft(event.target.value);
|
|
41
41
|
onText(event.target.value);
|
|
42
42
|
}, className: "h-7 w-36 text-xs", "data-testid": testId }));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scalar-value-editor.js","sourceRoot":"","sources":["../../../src/components/cms/scalar-value-editor.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAA;AAEhC,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAA;AACpD,OAAO,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAA;
|
|
1
|
+
{"version":3,"file":"scalar-value-editor.js","sourceRoot":"","sources":["../../../src/components/cms/scalar-value-editor.tsx"],"names":[],"mappings":"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","sourcesContent":["import { useState } from 'react'\nimport type { FilterScalar } from '@elytracms/core/content'\nimport { Input, Select } from '@elytracms/studio/ui'\nimport { localizedLabel, translate } from '@elytracms/studio/lib/i18n'\nimport { scalarFromText } from '@elytracms/studio/lib/cms-views'\nimport type { FilterableFieldOption } from '@elytracms/studio/lib/cms-views'\n\n/**\n * The closed single-scalar value control (EC-247), shared by the filter\n * builder's `eq`/comparison clauses and the bulk set-field action so both\n * surfaces enter a value the SAME way. It renders exactly the input the field's\n * schema type warrants — a select for boolean/select, a date input, a\n * number/text input otherwise. The `in` multi-value list and the\n * publication-state pseudo field stay in the filter builder: they are\n * filter-only and never a set-field target.\n *\n * It is deliberately *closed* — no field type invents a new control — keeping\n * value entry consistent and agent-inspectable across the two surfaces.\n */\nexport function ScalarFieldValueEditor({\n option,\n value,\n testId,\n ariaLabel = translate('cms.field.value'),\n onChange,\n}: {\n /** The field whose value is being entered (its `def` drives the control). */\n option: FilterableFieldOption | undefined\n value: FilterScalar\n testId: string\n ariaLabel?: string\n onChange: (value: FilterScalar) => void\n}) {\n switch (option?.def?.type) {\n case 'boolean':\n return (\n <Select\n aria-label={ariaLabel}\n value={value === true ? 'true' : 'false'}\n onChange={(event) => onChange(event.target.value === 'true')}\n className=\"h-7 w-auto py-0 text-xs\"\n data-testid={testId}\n >\n <option value=\"true\">{translate('common.true')}</option>\n <option value=\"false\">{translate('common.false')}</option>\n </Select>\n )\n case 'select':\n return (\n <Select\n aria-label={ariaLabel}\n value={String(value)}\n onChange={(event) => onChange(event.target.value)}\n className=\"h-7 w-auto py-0 text-xs\"\n data-testid={testId}\n >\n <option value=\"\">—</option>\n {option.def.options.map((opt) => (\n <option key={opt.value} value={opt.value}>\n {localizedLabel(opt.label, opt.value)}\n </option>\n ))}\n </Select>\n )\n case 'date':\n return (\n <Input\n aria-label={ariaLabel}\n type=\"date\"\n value={typeof value === 'string' ? value.slice(0, 10) : ''}\n onChange={(event) => onChange(scalarFromText(option, event.target.value))}\n className=\"h-7 w-36 text-xs\"\n data-testid={testId}\n />\n )\n case 'number':\n return (\n <DraftValueInput\n type=\"number\"\n initial={value === '' ? '' : String(value)}\n ariaLabel={ariaLabel}\n testId={testId}\n onText={(raw) => onChange(scalarFromText(option, raw))}\n />\n )\n default:\n return (\n <DraftValueInput\n initial={String(value)}\n ariaLabel={ariaLabel}\n testId={testId}\n onText={(raw) => onChange(scalarFromText(option, raw))}\n />\n )\n }\n}\n\n/**\n * Text input with a local draft so typing is never re-normalized mid-keystroke\n * (e.g. a trailing comma in a filter `in` list). Remount (key it) when the\n * field/operator changes so the draft resets to the new initial.\n */\nexport function DraftValueInput({\n initial,\n type = 'text',\n placeholder,\n ariaLabel = translate('cms.field.value'),\n testId,\n onText,\n}: {\n initial: string\n type?: 'text' | 'number'\n placeholder?: string\n ariaLabel?: string\n testId: string\n onText: (raw: string) => void\n}) {\n const [draft, setDraft] = useState(initial)\n return (\n <Input\n aria-label={ariaLabel}\n type={type}\n value={draft}\n placeholder={placeholder ?? translate('cms.field.valuePlaceholder')}\n onChange={(event) => {\n setDraft(event.target.value)\n onText(event.target.value)\n }}\n className=\"h-7 w-36 text-xs\"\n data-testid={testId}\n />\n )\n}\n"]}
|
|
@@ -5,6 +5,7 @@ import { diffDocuments } from '@elytracms/core/content';
|
|
|
5
5
|
import { isAssetNode, readAssetId, readDocumentRef } from '@elytracms/core/cms-core';
|
|
6
6
|
import { Badge, Button, Code, DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger, Row, Spacer, Stack, Text, } from '@elytracms/studio/ui';
|
|
7
7
|
import { useOperationCache } from '@elytracms/studio/lib/query';
|
|
8
|
+
import { translate } from '@elytracms/studio/lib/i18n';
|
|
8
9
|
import { localeChipLabel } from '@elytracms/studio/lib/locale';
|
|
9
10
|
import { cn } from '@elytracms/studio/lib/utils';
|
|
10
11
|
import { useCollectionView } from '../collection-view/collection-view-context';
|
|
@@ -61,11 +62,11 @@ export function VersionCompare() {
|
|
|
61
62
|
if (!compare)
|
|
62
63
|
return null;
|
|
63
64
|
if (view === null)
|
|
64
|
-
return _jsx(CompareNotice, { children:
|
|
65
|
+
return _jsx(CompareNotice, { children: translate('cms.version.loadingHistory') });
|
|
65
66
|
if (!baseRecord || !targetSnapshot)
|
|
66
|
-
return _jsx(CompareNotice, { children:
|
|
67
|
+
return _jsx(CompareNotice, { children: translate('cms.version.versionUnavailable') });
|
|
67
68
|
const canRestore = compare.target === 'draft' && !viewReadOnly;
|
|
68
|
-
const targetLabel = compare.target === 'draft' ? '
|
|
69
|
+
const targetLabel = compare.target === 'draft' ? translate('cms.version.currentDraft') : `v${compare.target}`;
|
|
69
70
|
// Step the base through history, skipping the target so the sides never collapse.
|
|
70
71
|
const baseIndex = versions.findIndex((v) => v.version === compare.base);
|
|
71
72
|
const nextBaseFor = (dir) => {
|
|
@@ -80,16 +81,22 @@ export function VersionCompare() {
|
|
|
80
81
|
.filter((v) => v.version !== compare.target)
|
|
81
82
|
.map((v) => ({ value: v.version, label: `v${v.version}`, meta: formatVersionTimestamp(v.createdAt) }));
|
|
82
83
|
const targetOptions = [
|
|
83
|
-
{
|
|
84
|
+
{
|
|
85
|
+
value: 'draft',
|
|
86
|
+
label: translate('cms.version.currentDraft'),
|
|
87
|
+
meta: dirty ? translate('cms.version.unsavedEdits') : undefined,
|
|
88
|
+
},
|
|
84
89
|
...versions
|
|
85
90
|
.filter((v) => v.version !== compare.base)
|
|
86
91
|
.map((v) => ({ value: v.version, label: `v${v.version}`, meta: formatVersionTimestamp(v.createdAt) })),
|
|
87
92
|
];
|
|
88
|
-
return (_jsxs(Stack, { gap: "3", className: "mx-auto w-full max-w-5xl p-4 sm:p-6", children: [_jsxs(Row, { gap: "2", align: "center", wrap: true, className: "rounded-md border border-border/70 bg-muted/30 px-3 py-2", children: [_jsx(VersionMenu, { caption:
|
|
89
|
-
? '
|
|
90
|
-
:
|
|
91
|
-
|
|
92
|
-
|
|
93
|
+
return (_jsxs(Stack, { gap: "3", className: "mx-auto w-full max-w-5xl p-4 sm:p-6", children: [_jsxs(Row, { gap: "2", align: "center", wrap: true, className: "rounded-md border border-border/70 bg-muted/30 px-3 py-2", children: [_jsx(VersionMenu, { caption: translate('cms.version.baseCaption'), current: `v${compare.base}`, meta: formatVersionTimestamp(baseRecord.createdAt), options: baseOptions, onSelect: (v) => setCompareBase(v) }), _jsx(ArrowRight, { className: "size-4 shrink-0 text-muted-foreground", "aria-hidden": true }), _jsx(VersionMenu, { caption: translate('cms.version.compareWithCaption'), current: targetLabel, options: targetOptions, onSelect: (v) => setCompareTarget(v) }), _jsx(Spacer, {}), _jsxs(Row, { gap: "1", children: [_jsx(Button, { variant: "outline", size: "icon-sm", onClick: () => newerBase !== undefined && setCompareBase(newerBase), disabled: newerBase === undefined, title: translate('cms.version.compareNewer'), "aria-label": translate('cms.version.compareNewer'), children: _jsx(ChevronLeft, {}) }), _jsx(Button, { variant: "outline", size: "icon-sm", onClick: () => olderBase !== undefined && setCompareBase(olderBase), disabled: olderBase === undefined, title: translate('cms.version.compareOlder'), "aria-label": translate('cms.version.compareOlder'), children: _jsx(ChevronRight, {}) })] }), canRestore ? (_jsxs(Button, { size: "sm", variant: "outline", onClick: () => void restore({ kind: 'all' }), disabled: busy || diff.changes.length === 0, title: translate('cms.version.restoreWholeTitle', { version: compare.base }), children: [_jsx(RotateCcw, {}), " ", translate('cms.version.restoreVersion')] })) : null] }), _jsxs(Text, { size: "xs", tone: "muted", className: "px-0.5", children: [diff.changes.length === 0
|
|
94
|
+
? translate('cms.version.noDifferences')
|
|
95
|
+
: translate(diff.changes.length === 1
|
|
96
|
+
? 'cms.version.changeSummary.one'
|
|
97
|
+
: 'cms.version.changeSummary.other', { count: diff.changes.length, unchanged: diff.unchangedCount }), !canRestore && diff.changes.length > 0
|
|
98
|
+
? translate('cms.version.comparingPastVersionsHint')
|
|
99
|
+
: ''] }), diff.changes.length === 0 ? (_jsx(CompareNotice, { children: translate('cms.version.versionsIdentical') })) : (_jsxs("div", { className: "relative", children: [_jsx("div", { className: "pointer-events-none absolute inset-y-0 left-1/2 w-0.5 -translate-x-1/2 bg-border", "aria-hidden": true }), _jsx(TwoCol, { className: "px-0.5 pb-1", before: _jsx(Text, { size: "xs", tone: "subtle", className: "uppercase tracking-wide", children: translate('cms.version.beforeVersion', { version: compare.base }) }), after: _jsx(Text, { size: "xs", tone: "subtle", className: "uppercase tracking-wide", children: translate('cms.version.afterTarget', { target: targetLabel }) }) }), groups.map((group) => (_jsx(FieldGroup, { group: group, canRestore: canRestore, busy: busy, onRestore: restore }, group.field)))] }))] }));
|
|
93
100
|
}
|
|
94
101
|
/** A before | after grid; the continuous centre divider lives behind it (in the
|
|
95
102
|
* parent), so the gap is where the two columns meet. */
|
|
@@ -105,9 +112,14 @@ function FieldGroup({ group, canRestore, busy, onRestore, }) {
|
|
|
105
112
|
const single = group.entries.length === 1 && group.entries[0].locale === undefined;
|
|
106
113
|
if (single) {
|
|
107
114
|
const entry = group.entries[0];
|
|
108
|
-
return (_jsxs("div", { className: "border-t border-border/30 py-3", children: [_jsxs(Row, { gap: "2", align: "center", className: "mb-1.5", children: [_jsx(Text, { size: "sm", weight: "medium", className: "min-w-0 truncate", children: group.label }), _jsx(KindTag, { kind: entry.kind }), _jsx(Spacer, {}), canRestore ? (_jsx(RestoreIcon, { busy: busy, title:
|
|
115
|
+
return (_jsxs("div", { className: "border-t border-border/30 py-3", children: [_jsxs(Row, { gap: "2", align: "center", className: "mb-1.5", children: [_jsx(Text, { size: "sm", weight: "medium", className: "min-w-0 truncate", children: group.label }), _jsx(KindTag, { kind: entry.kind }), _jsx(Spacer, {}), canRestore ? (_jsx(RestoreIcon, { busy: busy, title: translate('cms.version.restoreField', { field: group.label }), onClick: () => onRestore(fieldScope(entry)) })) : null] }), _jsx(EntryBody, { change: entry, canRestore: canRestore, busy: busy, onRestore: onRestore })] }));
|
|
109
116
|
}
|
|
110
|
-
return (_jsxs("div", { className: "border-t border-border/30 py-3", children: [_jsx(Text, { size: "sm", weight: "medium", className: "mb-2 block", children: group.label }), _jsx(Stack, { gap: "3", children: group.entries.map((entry) => (_jsxs("div", { children: [_jsxs(Row, { gap: "2", align: "center", className: "mb-1", children: [entry.locale ? (_jsx(Badge, { variant: "outline", className: "px-1 py-0 text-[0.6rem] uppercase tracking-wide text-muted-foreground", children: localeChipLabel(entry.locale) })) : null, _jsx(KindTag, { kind: entry.kind }), _jsx(Spacer, {}), canRestore ? (_jsx(RestoreIcon, { busy: busy, title:
|
|
117
|
+
return (_jsxs("div", { className: "border-t border-border/30 py-3", children: [_jsx(Text, { size: "sm", weight: "medium", className: "mb-2 block", children: group.label }), _jsx(Stack, { gap: "3", children: group.entries.map((entry) => (_jsxs("div", { children: [_jsxs(Row, { gap: "2", align: "center", className: "mb-1", children: [entry.locale ? (_jsx(Badge, { variant: "outline", className: "px-1 py-0 text-[0.6rem] uppercase tracking-wide text-muted-foreground", children: localeChipLabel(entry.locale) })) : null, _jsx(KindTag, { kind: entry.kind }), _jsx(Spacer, {}), canRestore ? (_jsx(RestoreIcon, { busy: busy, title: entry.locale
|
|
118
|
+
? translate('cms.version.restoreFieldLocale', {
|
|
119
|
+
field: group.label,
|
|
120
|
+
locale: localeChipLabel(entry.locale),
|
|
121
|
+
})
|
|
122
|
+
: translate('cms.version.restoreField', { field: group.label }), onClick: () => onRestore(fieldScope(entry)) })) : null] }), _jsx(EntryBody, { change: entry, canRestore: canRestore, busy: busy, onRestore: onRestore })] }, entry.locale ?? '__base__'))) })] }));
|
|
111
123
|
}
|
|
112
124
|
function EntryBody({ change, canRestore, busy, onRestore, }) {
|
|
113
125
|
const localeScope = change.locale !== undefined ? { locale: change.locale } : {};
|
|
@@ -118,7 +130,9 @@ function EntryBody({ change, canRestore, busy, onRestore, }) {
|
|
|
118
130
|
const before = richTextToText(change.before);
|
|
119
131
|
const after = richTextToText(change.after);
|
|
120
132
|
if (before === after)
|
|
121
|
-
return _jsx(MutedNote, { children: before
|
|
133
|
+
return (_jsx(MutedNote, { children: before
|
|
134
|
+
? translate('cms.version.textUnchanged')
|
|
135
|
+
: translate('cms.version.contentChanged') }));
|
|
122
136
|
return _jsx(WordDiffCols, { before: before, after: after });
|
|
123
137
|
}
|
|
124
138
|
if (change.kind === 'changed' && typeof change.before === 'string' && typeof change.after === 'string') {
|
|
@@ -128,7 +142,9 @@ function EntryBody({ change, canRestore, busy, onRestore, }) {
|
|
|
128
142
|
}
|
|
129
143
|
function BlockSection({ block, canRestore, busy, onRestore, }) {
|
|
130
144
|
const name = block.componentId.split('.').pop() ?? block.componentId;
|
|
131
|
-
return (_jsxs("div", { children: [_jsxs(Row, { gap: "2", align: "center", className: "mb-1", children: [_jsx(Text, { size: "xs", weight: "medium", className: "min-w-0 truncate", children: name }), _jsx(Code, { tone: "muted", children: block.componentId }), _jsx(KindTag, { kind: block.kind }), _jsx(Spacer, {}), canRestore ? _jsx(RestoreIcon, { busy: busy, title:
|
|
145
|
+
return (_jsxs("div", { children: [_jsxs(Row, { gap: "2", align: "center", className: "mb-1", children: [_jsx(Text, { size: "xs", weight: "medium", className: "min-w-0 truncate", children: name }), _jsx(Code, { tone: "muted", children: block.componentId }), _jsx(KindTag, { kind: block.kind }), _jsx(Spacer, {}), canRestore ? (_jsx(RestoreIcon, { busy: busy, title: translate('cms.version.restoreBlock'), onClick: onRestore })) : null] }), block.props && block.props.length > 0 ? (_jsx(Stack, { gap: "2", children: block.props.map((prop) => (_jsx(PropRow, { prop: prop }, prop.name))) })) : null, block.slotsChanged ? _jsx(MutedNote, { children: translate('cms.version.nestedContentChanged') }) : null, block.kind !== 'changed' && !block.props?.length ? (_jsx(MutedNote, { children: block.kind === 'added'
|
|
146
|
+
? translate('cms.version.blockAdded')
|
|
147
|
+
: translate('cms.version.blockRemoved') })) : null] }));
|
|
132
148
|
}
|
|
133
149
|
function PropRow({ prop }) {
|
|
134
150
|
const useWordDiff = prop.kind === 'changed' && typeof prop.before === 'string' && typeof prop.after === 'string';
|
|
@@ -137,7 +153,7 @@ function PropRow({ prop }) {
|
|
|
137
153
|
/** One side of a non-text change — the value, or an "empty" placeholder. */
|
|
138
154
|
function SideValue({ value, other, typeHint }) {
|
|
139
155
|
if (value === undefined || value === null || value === '') {
|
|
140
|
-
return (_jsx(Text, { size: "sm", tone: "subtle", className: "italic", children:
|
|
156
|
+
return (_jsx(Text, { size: "sm", tone: "subtle", className: "italic", children: translate('cms.version.emptyValue') }));
|
|
141
157
|
}
|
|
142
158
|
return _jsx(ValueView, { value: value, other: other, typeHint: typeHint });
|
|
143
159
|
}
|
|
@@ -152,13 +168,15 @@ function ValueView({ value, other, typeHint }) {
|
|
|
152
168
|
if (typeHint === 'relation' || readDocumentRef(value))
|
|
153
169
|
return _jsx(RelationValue, { value: value, other: other });
|
|
154
170
|
if (typeHint === 'richText')
|
|
155
|
-
return (_jsx(Text, { size: "sm", className: "whitespace-pre-wrap break-words", children: richTextToText(value) || '
|
|
171
|
+
return (_jsx(Text, { size: "sm", className: "whitespace-pre-wrap break-words", children: richTextToText(value) || translate('cms.version.richText') }));
|
|
156
172
|
if (typeHint === 'boolean' || typeof value === 'boolean')
|
|
157
|
-
return (_jsx(Text, { size: "sm", mono: true, children: value === true ? '
|
|
173
|
+
return (_jsx(Text, { size: "sm", mono: true, children: value === true ? translate('common.yes') : translate('common.no') }));
|
|
158
174
|
if (typeHint === 'date')
|
|
159
175
|
return (_jsx(Text, { size: "sm", mono: true, children: String(value).slice(0, 10) }));
|
|
160
176
|
if (typeof value === 'object')
|
|
161
|
-
return (_jsx(Text, { size: "sm", tone: "muted", children: Array.isArray(value)
|
|
177
|
+
return (_jsx(Text, { size: "sm", tone: "muted", children: Array.isArray(value)
|
|
178
|
+
? translate(value.length === 1 ? 'cms.version.itemCount.one' : 'cms.version.itemCount.other', { count: value.length })
|
|
179
|
+
: translate('cms.version.objectValue') }));
|
|
162
180
|
return (_jsx(Text, { size: "sm", className: "whitespace-pre-wrap break-words", children: String(value) }));
|
|
163
181
|
}
|
|
164
182
|
function RelationValue({ value, other }) {
|
|
@@ -216,7 +234,7 @@ function WordTokens({ tokens, side }) {
|
|
|
216
234
|
function KindTag({ kind }) {
|
|
217
235
|
if (kind === 'changed')
|
|
218
236
|
return null;
|
|
219
|
-
return (_jsxs(Text, { size: "xs", tone: "subtle", children: ["\u00B7 ", kind === 'added' ? '
|
|
237
|
+
return (_jsxs(Text, { size: "xs", tone: "subtle", children: ["\u00B7 ", kind === 'added' ? translate('cms.version.kindNew') : translate('cms.version.kindRemoved')] }));
|
|
220
238
|
}
|
|
221
239
|
function RestoreIcon({ busy, title, onClick }) {
|
|
222
240
|
return (_jsx(Button, { variant: "ghost", size: "icon-sm", disabled: busy, title: title, "aria-label": title, onClick: onClick, children: _jsx(RotateCcw, {}) }));
|
|
@@ -260,9 +278,6 @@ function localeCompare(a, b, rank) {
|
|
|
260
278
|
return 1;
|
|
261
279
|
return (rank.get(a) ?? 99) - (rank.get(b) ?? 99);
|
|
262
280
|
}
|
|
263
|
-
function countLabel(n, one, many) {
|
|
264
|
-
return `${n} ${n === 1 ? one : many}`;
|
|
265
|
-
}
|
|
266
281
|
/** camelCase / snake prop name → a readable label. */
|
|
267
282
|
function prettyName(name) {
|
|
268
283
|
const spaced = name.replace(/[_-]+/g, ' ').replace(/([a-z0-9])([A-Z])/g, '$1 $2');
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"version-compare.js","sourceRoot":"","sources":["../../../src/components/cms/version-compare.tsx"],"names":[],"mappings":"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","sourcesContent":["import { useCallback, useMemo, useState } from 'react'\nimport type { ReactNode } from 'react'\nimport { ArrowRight, ChevronDown, ChevronLeft, ChevronRight, Image as ImageIcon, RotateCcw } from 'lucide-react'\nimport { diffDocuments } from '@elytracms/core/content'\nimport type { BlockChange, FieldChange, PropChange } from '@elytracms/core/content'\nimport { isAssetNode, readAssetId, readDocumentRef } from '@elytracms/core/cms-core'\nimport type { CmsDocument, FieldDef, RestoreScope } from '@elytracms/core/cms-core'\nimport {\n Badge,\n Button,\n Code,\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuTrigger,\n Row,\n Spacer,\n Stack,\n Text,\n} from '@elytracms/studio/ui'\nimport { useOperationCache } from '@elytracms/studio/lib/query'\nimport { localeChipLabel } from '@elytracms/studio/lib/locale'\nimport { cn } from '@elytracms/studio/lib/utils'\nimport { useCollectionView } from '../collection-view/collection-view-context'\nimport { toRefArray } from './cell'\nimport { richTextToText, wordDiff } from './version-compare-text'\nimport type { WordToken } from './version-compare-text'\nimport { useDocumentEditor } from './document-editor-context'\nimport { useDocumentVersionsQuery } from './use-document-versions'\nimport { formatVersionTimestamp } from './versions-model'\n\n/**\n * EC-298 — the version compare view. Renders as the sticky **Compare** content tab\n * (the Versions sidebar pane stays on as the navigator).\n *\n * A calm change-list grouped BY FIELD (a localized field's per-locale variants sit\n * together): before | after across ONE continuous central divider. Text reads as a\n * prose diff (changed words lit in place — rich text via its markdown projection so\n * the content, not just \"changed\", is visible); assets as thumbnails; relations as\n * titles. Each field/locale (and each block, at property level) restores back to the\n * base version with a single ↩.\n */\nexport function VersionCompare() {\n const source = useCollectionView()\n const {\n collection,\n docRef,\n draft,\n dirty,\n viewReadOnly,\n save,\n replaceDraft,\n compare,\n setCompareBase,\n setCompareTarget,\n } = useDocumentEditor()\n const { versionsQuery, versionKey } = useDocumentVersionsQuery(docRef)\n const cache = useOperationCache()\n const [busy, setBusy] = useState(false)\n\n const view = versionsQuery.data ?? null\n const versions = useMemo(() => view?.versions ?? [], [view])\n\n const baseRecord = compare ? versions.find((v) => v.version === compare.base) : undefined\n const targetSnapshot: CmsDocument | undefined =\n compare?.target === 'draft'\n ? draft\n : versions.find((v) => v.version === compare?.target)?.snapshot\n\n const diff = useMemo(\n () =>\n baseRecord && targetSnapshot\n ? diffDocuments(collection, baseRecord.snapshot, targetSnapshot)\n : { changes: [], unchangedCount: 0 },\n [collection, baseRecord, targetSnapshot],\n )\n\n const fieldOrder = useMemo(\n () => new Map(collection.fields.map((f, i) => [f.name, i])),\n [collection],\n )\n const localeRank = useMemo(\n () => new Map(source.localeConfig.locales.map((l, i) => [l, i])),\n [source.localeConfig],\n )\n const groups = useMemo(\n () => groupByField(diff.changes, fieldOrder, localeRank),\n [diff.changes, fieldOrder, localeRank],\n )\n\n const restore = useCallback(\n async (scope: RestoreScope) => {\n if (!compare) return\n setBusy(true)\n try {\n if (dirty) save()\n const restored = await source.versioning?.restore(docRef, compare.base, scope)\n if (restored) replaceDraft(restored)\n await cache.invalidate(versionKey)\n } finally {\n setBusy(false)\n }\n },\n [compare, dirty, save, source, docRef, replaceDraft, cache, versionKey],\n )\n\n if (!compare) return null\n if (view === null) return <CompareNotice>Loading version history…</CompareNotice>\n if (!baseRecord || !targetSnapshot)\n return <CompareNotice>That version is no longer available. Pick another to compare.</CompareNotice>\n\n const canRestore = compare.target === 'draft' && !viewReadOnly\n const targetLabel = compare.target === 'draft' ? 'Current draft' : `v${compare.target}`\n\n // Step the base through history, skipping the target so the sides never collapse.\n const baseIndex = versions.findIndex((v) => v.version === compare.base)\n const nextBaseFor = (dir: -1 | 1): number | undefined => {\n let i = baseIndex + dir\n while (i >= 0 && i < versions.length && versions[i]!.version === compare.target) i += dir\n return i >= 0 && i < versions.length ? versions[i]!.version : undefined\n }\n const newerBase = nextBaseFor(-1) // versions are newest-first\n const olderBase = nextBaseFor(1)\n\n const baseOptions = versions\n .filter((v) => v.version !== compare.target)\n .map((v) => ({ value: v.version, label: `v${v.version}`, meta: formatVersionTimestamp(v.createdAt) }))\n const targetOptions = [\n { value: 'draft' as const, label: 'Current draft', meta: dirty ? 'unsaved edits' : undefined },\n ...versions\n .filter((v) => v.version !== compare.base)\n .map((v) => ({ value: v.version, label: `v${v.version}`, meta: formatVersionTimestamp(v.createdAt) })),\n ]\n\n return (\n <Stack gap=\"3\" className=\"mx-auto w-full max-w-5xl p-4 sm:p-6\">\n {/* The two sides — both re-pickable, so any pair can be compared; the\n Versions pane also sets the base on click. Stepper walks the base. */}\n <Row gap=\"2\" align=\"center\" wrap className=\"rounded-md border border-border/70 bg-muted/30 px-3 py-2\">\n <VersionMenu\n caption=\"Base\"\n current={`v${compare.base}`}\n meta={formatVersionTimestamp(baseRecord.createdAt)}\n options={baseOptions}\n onSelect={(v) => setCompareBase(v as number)}\n />\n <ArrowRight className=\"size-4 shrink-0 text-muted-foreground\" aria-hidden />\n <VersionMenu\n caption=\"Compare with\"\n current={targetLabel}\n options={targetOptions}\n onSelect={(v) => setCompareTarget(v as number | 'draft')}\n />\n <Spacer />\n <Row gap=\"1\">\n <Button\n variant=\"outline\"\n size=\"icon-sm\"\n onClick={() => newerBase !== undefined && setCompareBase(newerBase)}\n disabled={newerBase === undefined}\n title=\"Compare a newer version\"\n aria-label=\"Compare a newer version\"\n >\n <ChevronLeft />\n </Button>\n <Button\n variant=\"outline\"\n size=\"icon-sm\"\n onClick={() => olderBase !== undefined && setCompareBase(olderBase)}\n disabled={olderBase === undefined}\n title=\"Compare an older version\"\n aria-label=\"Compare an older version\"\n >\n <ChevronRight />\n </Button>\n </Row>\n {canRestore ? (\n <Button\n size=\"sm\"\n variant=\"outline\"\n onClick={() => void restore({ kind: 'all' })}\n disabled={busy || diff.changes.length === 0}\n title={`Restore the whole document to v${compare.base}`}\n >\n <RotateCcw /> Restore version\n </Button>\n ) : null}\n </Row>\n\n <Text size=\"xs\" tone=\"muted\" className=\"px-0.5\">\n {diff.changes.length === 0\n ? 'No differences'\n : `${countLabel(diff.changes.length, 'change', 'changes')} · ${diff.unchangedCount} unchanged`}\n {!canRestore && diff.changes.length > 0\n ? ' · comparing two past versions — set “Compare with” to Current draft to restore'\n : ''}\n </Text>\n\n {diff.changes.length === 0 ? (\n <CompareNotice>These two versions are identical.</CompareNotice>\n ) : (\n <div className=\"relative\">\n {/* One continuous 2px centre divider behind the before | after columns. */}\n <div\n className=\"pointer-events-none absolute inset-y-0 left-1/2 w-0.5 -translate-x-1/2 bg-border\"\n aria-hidden\n />\n <TwoCol\n className=\"px-0.5 pb-1\"\n before={\n <Text size=\"xs\" tone=\"subtle\" className=\"uppercase tracking-wide\">\n Before · v{compare.base}\n </Text>\n }\n after={\n <Text size=\"xs\" tone=\"subtle\" className=\"uppercase tracking-wide\">\n After · {targetLabel}\n </Text>\n }\n />\n {groups.map((group) => (\n <FieldGroup key={group.field} group={group} canRestore={canRestore} busy={busy} onRestore={restore} />\n ))}\n </div>\n )}\n </Stack>\n )\n}\n\n/** A before | after grid; the continuous centre divider lives behind it (in the\n * parent), so the gap is where the two columns meet. */\nfunction TwoCol({ before, after, className }: { before: ReactNode; after: ReactNode; className?: string }) {\n return (\n <div className={cn('grid grid-cols-2 gap-x-6', className)}>\n <div className=\"min-w-0\">{before}</div>\n <div className=\"min-w-0\">{after}</div>\n </div>\n )\n}\n\nfunction VersionMenu({\n caption,\n current,\n meta,\n options,\n onSelect,\n}: {\n caption: string\n current: string\n meta?: string\n options: { value: number | 'draft'; label: string; meta?: string }[]\n onSelect: (value: number | 'draft') => void\n}) {\n return (\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <Button variant=\"outline\" size=\"sm\" className=\"gap-1.5\">\n <Text size=\"xs\" tone=\"subtle\" className=\"uppercase tracking-wide\">\n {caption}\n </Text>\n <Text size=\"sm\" weight=\"medium\" mono>\n {current}\n </Text>\n {meta ? (\n <Text size=\"xs\" tone=\"muted\" className=\"hidden sm:inline\">\n {meta}\n </Text>\n ) : null}\n <ChevronDown className=\"size-3.5 text-muted-foreground\" />\n </Button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"start\" className=\"max-h-72 overflow-auto\">\n {options.map((o) => (\n <DropdownMenuItem key={String(o.value)} onClick={() => onSelect(o.value)} className=\"gap-2\">\n <Text size=\"sm\" weight=\"medium\" mono={o.value !== 'draft'}>\n {o.label}\n </Text>\n {o.meta ? (\n <Text size=\"xs\" tone=\"muted\">\n {o.meta}\n </Text>\n ) : null}\n </DropdownMenuItem>\n ))}\n </DropdownMenuContent>\n </DropdownMenu>\n )\n}\n\ninterface FieldGroupData {\n field: string\n label: string\n type: FieldDef['type']\n entries: FieldChange[]\n}\n\nfunction FieldGroup({\n group,\n canRestore,\n busy,\n onRestore,\n}: {\n group: FieldGroupData\n canRestore: boolean\n busy: boolean\n onRestore: (scope: RestoreScope) => void\n}) {\n // A plain (non-localized) field is a single entry — label + value inline. A\n // localized field groups its locale variants under one label.\n const single = group.entries.length === 1 && group.entries[0]!.locale === undefined\n if (single) {\n const entry = group.entries[0]!\n return (\n <div className=\"border-t border-border/30 py-3\">\n <Row gap=\"2\" align=\"center\" className=\"mb-1.5\">\n <Text size=\"sm\" weight=\"medium\" className=\"min-w-0 truncate\">\n {group.label}\n </Text>\n <KindTag kind={entry.kind} />\n <Spacer />\n {canRestore ? (\n <RestoreIcon busy={busy} title={`Restore ${group.label}`} onClick={() => onRestore(fieldScope(entry))} />\n ) : null}\n </Row>\n <EntryBody change={entry} canRestore={canRestore} busy={busy} onRestore={onRestore} />\n </div>\n )\n }\n return (\n <div className=\"border-t border-border/30 py-3\">\n <Text size=\"sm\" weight=\"medium\" className=\"mb-2 block\">\n {group.label}\n </Text>\n <Stack gap=\"3\">\n {group.entries.map((entry) => (\n <div key={entry.locale ?? '__base__'}>\n <Row gap=\"2\" align=\"center\" className=\"mb-1\">\n {entry.locale ? (\n <Badge variant=\"outline\" className=\"px-1 py-0 text-[0.6rem] uppercase tracking-wide text-muted-foreground\">\n {localeChipLabel(entry.locale)}\n </Badge>\n ) : null}\n <KindTag kind={entry.kind} />\n <Spacer />\n {canRestore ? (\n <RestoreIcon\n busy={busy}\n title={`Restore ${group.label}${entry.locale ? ` (${localeChipLabel(entry.locale)})` : ''}`}\n onClick={() => onRestore(fieldScope(entry))}\n />\n ) : null}\n </Row>\n <EntryBody change={entry} canRestore={canRestore} busy={busy} onRestore={onRestore} />\n </div>\n ))}\n </Stack>\n </div>\n )\n}\n\nfunction EntryBody({\n change,\n canRestore,\n busy,\n onRestore,\n}: {\n change: FieldChange\n canRestore: boolean\n busy: boolean\n onRestore: (scope: RestoreScope) => void\n}) {\n const localeScope = change.locale !== undefined ? { locale: change.locale } : {}\n if (change.blocks) {\n return (\n <Stack gap=\"3\" className=\"mt-1\">\n {change.blocks.map((block) => (\n <BlockSection\n key={block.blockId}\n block={block}\n canRestore={canRestore}\n busy={busy}\n onRestore={() =>\n onRestore({ kind: 'block', field: change.field, blockId: block.blockId, ...localeScope })\n }\n />\n ))}\n </Stack>\n )\n }\n if (change.type === 'richText') {\n const before = richTextToText(change.before)\n const after = richTextToText(change.after)\n if (before === after)\n return <MutedNote>{before ? 'Text unchanged — formatting or whitespace differs.' : 'Content changed.'}</MutedNote>\n return <WordDiffCols before={before} after={after} />\n }\n if (change.kind === 'changed' && typeof change.before === 'string' && typeof change.after === 'string') {\n return <WordDiffCols before={change.before} after={change.after} />\n }\n return (\n <TwoCol\n before={<SideValue value={change.before} other={change.after} typeHint={change.type} />}\n after={<SideValue value={change.after} other={change.before} typeHint={change.type} />}\n />\n )\n}\n\nfunction BlockSection({\n block,\n canRestore,\n busy,\n onRestore,\n}: {\n block: BlockChange\n canRestore: boolean\n busy: boolean\n onRestore: () => void\n}) {\n const name = block.componentId.split('.').pop() ?? block.componentId\n return (\n <div>\n <Row gap=\"2\" align=\"center\" className=\"mb-1\">\n <Text size=\"xs\" weight=\"medium\" className=\"min-w-0 truncate\">\n {name}\n </Text>\n <Code tone=\"muted\">{block.componentId}</Code>\n <KindTag kind={block.kind} />\n <Spacer />\n {canRestore ? <RestoreIcon busy={busy} title=\"Restore this block\" onClick={onRestore} /> : null}\n </Row>\n {block.props && block.props.length > 0 ? (\n <Stack gap=\"2\">\n {block.props.map((prop) => (\n <PropRow key={prop.name} prop={prop} />\n ))}\n </Stack>\n ) : null}\n {block.slotsChanged ? <MutedNote>Nested content changed.</MutedNote> : null}\n {block.kind !== 'changed' && !block.props?.length ? (\n <MutedNote>{block.kind === 'added' ? 'Block added.' : 'Block removed.'}</MutedNote>\n ) : null}\n </div>\n )\n}\n\nfunction PropRow({ prop }: { prop: PropChange }) {\n const useWordDiff =\n prop.kind === 'changed' && typeof prop.before === 'string' && typeof prop.after === 'string'\n return (\n <div>\n <Text size=\"xs\" tone=\"subtle\" className=\"mb-0.5 block uppercase tracking-wide\">\n {prettyName(prop.name)}\n </Text>\n {useWordDiff ? (\n <WordDiffCols before={String(prop.before)} after={String(prop.after)} />\n ) : (\n <TwoCol\n before={<SideValue value={prop.before} other={prop.after} />}\n after={<SideValue value={prop.after} other={prop.before} />}\n />\n )}\n </div>\n )\n}\n\n/** One side of a non-text change — the value, or an \"empty\" placeholder. */\nfunction SideValue({ value, other, typeHint }: { value: unknown; other?: unknown; typeHint?: FieldDef['type'] }) {\n if (value === undefined || value === null || value === '') {\n return (\n <Text size=\"sm\" tone=\"subtle\" className=\"italic\">\n empty\n </Text>\n )\n }\n return <ValueView value={value} other={other} typeHint={typeHint} />\n}\n\n/**\n * Read-only value display, dispatching on the field type where known and on the\n * self-describing value shape otherwise (block props carry no schema) — assets as\n * thumbnails, relations as titles, everything else as calm text.\n */\nfunction ValueView({ value, other, typeHint }: { value: unknown; other?: unknown; typeHint?: FieldDef['type'] }) {\n if (typeHint === 'asset' || isAssetNode(value)) return <AssetValue value={value} />\n if (typeHint === 'relation' || readDocumentRef(value)) return <RelationValue value={value} other={other} />\n if (typeHint === 'richText')\n return (\n <Text size=\"sm\" className=\"whitespace-pre-wrap break-words\">\n {richTextToText(value) || 'rich text'}\n </Text>\n )\n if (typeHint === 'boolean' || typeof value === 'boolean')\n return (\n <Text size=\"sm\" mono>\n {value === true ? 'Yes' : 'No'}\n </Text>\n )\n if (typeHint === 'date')\n return (\n <Text size=\"sm\" mono>\n {String(value).slice(0, 10)}\n </Text>\n )\n if (typeof value === 'object')\n return (\n <Text size=\"sm\" tone=\"muted\">\n {Array.isArray(value) ? countLabel(value.length, 'item', 'items') : 'object'}\n </Text>\n )\n return (\n <Text size=\"sm\" className=\"whitespace-pre-wrap break-words\">\n {String(value)}\n </Text>\n )\n}\n\nfunction RelationValue({ value, other }: { value: unknown; other?: unknown }) {\n const source = useCollectionView()\n const refs = toRefArray(value)\n if (refs.length === 0)\n return (\n <Text size=\"sm\" className=\"whitespace-pre-wrap break-words\">\n {String(value)}\n </Text>\n )\n const otherRefs = other !== undefined ? toRefArray(other) : []\n // Disambiguate a same-titled but different target (the \"Ada → Ada\" trap): show\n // the id only when the titles would otherwise read identically.\n const label = refs\n .map((ref) => {\n const title = source.titleOf(ref)\n const collision = otherRefs.some((o) => o.id !== ref.id && source.titleOf(o) === title)\n return collision ? `${title} · ${ref.id}` : title\n })\n .join(', ')\n return <Text size=\"sm\">{label}</Text>\n}\n\nfunction AssetValue({ value }: { value: unknown }) {\n const ids = (Array.isArray(value) ? value : [value])\n .map(readAssetId)\n .filter((id): id is string => id !== undefined)\n if (ids.length === 0)\n return (\n <Text size=\"sm\" className=\"whitespace-pre-wrap break-words\">\n {String(value)}\n </Text>\n )\n return (\n <div className=\"flex flex-wrap gap-2\">\n {ids.map((id) => (\n <AssetThumb key={id} id={id} />\n ))}\n </div>\n )\n}\n\n/** An asset as a thumbnail (image with a resolvable URL) or a labelled badge —\n * the visual diff for a cover-image change, not two identical filenames. */\nfunction AssetThumb({ id }: { id: string }) {\n const source = useCollectionView()\n const assetCollectionId = source.assetCollectionId ?? 'asset'\n const record = source.resolveAsset?.(id)\n const label = record?.title ?? record?.filename ?? source.titleOf({ collection: assetCollectionId, id })\n const isImage = record?.contentType?.startsWith('image/') ?? false\n const url = record?.url\n if (isImage && url && url.startsWith('http')) {\n return (\n <span className=\"inline-flex min-w-0 items-center gap-2\">\n <img\n src={url}\n alt={record?.alt ?? label}\n loading=\"lazy\"\n className=\"size-12 shrink-0 rounded border border-border bg-muted object-cover\"\n />\n <Text size=\"xs\" tone=\"muted\" className=\"min-w-0 truncate\">\n {label}\n </Text>\n </span>\n )\n }\n return (\n <Badge variant=\"outline\">\n <ImageIcon className=\"size-3\" /> {label}\n </Badge>\n )\n}\n\n// --- Prose word diff --------------------------------------------------------------\n\n/** Prose-diff across the central divider, both sides from one LCS. */\nfunction WordDiffCols({ before, after }: { before: string; after: string }) {\n const wd = useMemo(() => wordDiff(before, after), [before, after])\n return (\n <TwoCol\n before={<WordTokens tokens={wd.before} side=\"before\" />}\n after={<WordTokens tokens={wd.after} side=\"after\" />}\n />\n )\n}\n\nfunction WordTokens({ tokens, side }: { tokens: WordToken[]; side: 'before' | 'after' }) {\n return (\n <Text size=\"sm\" className=\"whitespace-pre-wrap break-words leading-relaxed\">\n {tokens.map((token, i) =>\n token.changed ? (\n <mark\n key={i}\n className={cn(\n 'rounded-sm px-0.5',\n side === 'before'\n ? 'bg-destructive/15 text-destructive line-through decoration-destructive/40'\n : 'bg-success/20 text-foreground',\n )}\n >\n {token.text}\n </mark>\n ) : (\n <span key={i} className=\"text-muted-foreground\">\n {token.text}\n </span>\n ),\n )}\n </Text>\n )\n}\n\n// --- Small shared bits ------------------------------------------------------------\n\n/** A quiet \"· new\" / \"· removed\" tag; nothing for a plain change (implicit). */\nfunction KindTag({ kind }: { kind: FieldChange['kind'] }) {\n if (kind === 'changed') return null\n return (\n <Text size=\"xs\" tone=\"subtle\">\n · {kind === 'added' ? 'new' : 'removed'}\n </Text>\n )\n}\n\nfunction RestoreIcon({ busy, title, onClick }: { busy: boolean; title: string; onClick: () => void }) {\n return (\n <Button variant=\"ghost\" size=\"icon-sm\" disabled={busy} title={title} aria-label={title} onClick={onClick}>\n <RotateCcw />\n </Button>\n )\n}\n\nfunction MutedNote({ children }: { children: ReactNode }) {\n return (\n <Text size=\"sm\" tone=\"muted\" className=\"italic\">\n {children}\n </Text>\n )\n}\n\nfunction CompareNotice({ children }: { children: ReactNode }) {\n return (\n <div className=\"mx-auto w-full max-w-5xl p-4 sm:p-6\">\n <div className=\"rounded-md border border-dashed border-border/70 px-4 py-8 text-center\">\n <Text size=\"sm\" tone=\"muted\">\n {children}\n </Text>\n </div>\n </div>\n )\n}\n\nfunction fieldScope(change: FieldChange): RestoreScope {\n return { kind: 'field', field: change.field, ...(change.locale !== undefined ? { locale: change.locale } : {}) }\n}\n\n/**\n * Group changes BY FIELD (a localized field's per-locale variants together),\n * fields in schema order, locales in project order (base bucket first).\n */\nfunction groupByField(\n changes: FieldChange[],\n fieldOrder: Map<string, number>,\n localeRank: Map<string, number>,\n): FieldGroupData[] {\n const map = new Map<string, FieldGroupData>()\n for (const change of changes) {\n let group = map.get(change.field)\n if (!group) {\n group = { field: change.field, label: change.label, type: change.type, entries: [] }\n map.set(change.field, group)\n }\n group.entries.push(change)\n }\n const groups = [...map.values()]\n groups.sort(\n (a, b) => (fieldOrder.get(a.field) ?? Number.MAX_SAFE_INTEGER) - (fieldOrder.get(b.field) ?? Number.MAX_SAFE_INTEGER),\n )\n for (const group of groups) {\n group.entries.sort((a, b) => localeCompare(a.locale, b.locale, localeRank))\n }\n return groups\n}\n\nfunction localeCompare(a: string | undefined, b: string | undefined, rank: Map<string, number>): number {\n if (a === b) return 0\n if (a === undefined) return -1 // base bucket first\n if (b === undefined) return 1\n return (rank.get(a) ?? 99) - (rank.get(b) ?? 99)\n}\n\nfunction countLabel(n: number, one: string, many: string): string {\n return `${n} ${n === 1 ? one : many}`\n}\n\n/** camelCase / snake prop name → a readable label. */\nfunction prettyName(name: string): string {\n const spaced = name.replace(/[_-]+/g, ' ').replace(/([a-z0-9])([A-Z])/g, '$1 $2')\n return spaced.charAt(0).toUpperCase() + spaced.slice(1)\n}\n"]}
|
|
1
|
+
{"version":3,"file":"version-compare.js","sourceRoot":"","sources":["../../../src/components/cms/version-compare.tsx"],"names":[],"mappings":"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","sourcesContent":["import { useCallback, useMemo, useState } from 'react'\nimport type { ReactNode } from 'react'\nimport { ArrowRight, ChevronDown, ChevronLeft, ChevronRight, Image as ImageIcon, RotateCcw } from 'lucide-react'\nimport { diffDocuments } from '@elytracms/core/content'\nimport type { BlockChange, FieldChange, PropChange } from '@elytracms/core/content'\nimport { isAssetNode, readAssetId, readDocumentRef } from '@elytracms/core/cms-core'\nimport type { CmsDocument, FieldDef, RestoreScope } from '@elytracms/core/cms-core'\nimport {\n Badge,\n Button,\n Code,\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuTrigger,\n Row,\n Spacer,\n Stack,\n Text,\n} from '@elytracms/studio/ui'\nimport { useOperationCache } from '@elytracms/studio/lib/query'\nimport { translate } from '@elytracms/studio/lib/i18n'\nimport { localeChipLabel } from '@elytracms/studio/lib/locale'\nimport { cn } from '@elytracms/studio/lib/utils'\nimport { useCollectionView } from '../collection-view/collection-view-context'\nimport { toRefArray } from './cell'\nimport { richTextToText, wordDiff } from './version-compare-text'\nimport type { WordToken } from './version-compare-text'\nimport { useDocumentEditor } from './document-editor-context'\nimport { useDocumentVersionsQuery } from './use-document-versions'\nimport { formatVersionTimestamp } from './versions-model'\n\n/**\n * EC-298 — the version compare view. Renders as the sticky **Compare** content tab\n * (the Versions sidebar pane stays on as the navigator).\n *\n * A calm change-list grouped BY FIELD (a localized field's per-locale variants sit\n * together): before | after across ONE continuous central divider. Text reads as a\n * prose diff (changed words lit in place — rich text via its markdown projection so\n * the content, not just \"changed\", is visible); assets as thumbnails; relations as\n * titles. Each field/locale (and each block, at property level) restores back to the\n * base version with a single ↩.\n */\nexport function VersionCompare() {\n const source = useCollectionView()\n const {\n collection,\n docRef,\n draft,\n dirty,\n viewReadOnly,\n save,\n replaceDraft,\n compare,\n setCompareBase,\n setCompareTarget,\n } = useDocumentEditor()\n const { versionsQuery, versionKey } = useDocumentVersionsQuery(docRef)\n const cache = useOperationCache()\n const [busy, setBusy] = useState(false)\n\n const view = versionsQuery.data ?? null\n const versions = useMemo(() => view?.versions ?? [], [view])\n\n const baseRecord = compare ? versions.find((v) => v.version === compare.base) : undefined\n const targetSnapshot: CmsDocument | undefined =\n compare?.target === 'draft'\n ? draft\n : versions.find((v) => v.version === compare?.target)?.snapshot\n\n const diff = useMemo(\n () =>\n baseRecord && targetSnapshot\n ? diffDocuments(collection, baseRecord.snapshot, targetSnapshot)\n : { changes: [], unchangedCount: 0 },\n [collection, baseRecord, targetSnapshot],\n )\n\n const fieldOrder = useMemo(\n () => new Map(collection.fields.map((f, i) => [f.name, i])),\n [collection],\n )\n const localeRank = useMemo(\n () => new Map(source.localeConfig.locales.map((l, i) => [l, i])),\n [source.localeConfig],\n )\n const groups = useMemo(\n () => groupByField(diff.changes, fieldOrder, localeRank),\n [diff.changes, fieldOrder, localeRank],\n )\n\n const restore = useCallback(\n async (scope: RestoreScope) => {\n if (!compare) return\n setBusy(true)\n try {\n if (dirty) save()\n const restored = await source.versioning?.restore(docRef, compare.base, scope)\n if (restored) replaceDraft(restored)\n await cache.invalidate(versionKey)\n } finally {\n setBusy(false)\n }\n },\n [compare, dirty, save, source, docRef, replaceDraft, cache, versionKey],\n )\n\n if (!compare) return null\n if (view === null) return <CompareNotice>{translate('cms.version.loadingHistory')}</CompareNotice>\n if (!baseRecord || !targetSnapshot)\n return <CompareNotice>{translate('cms.version.versionUnavailable')}</CompareNotice>\n\n const canRestore = compare.target === 'draft' && !viewReadOnly\n const targetLabel = compare.target === 'draft' ? translate('cms.version.currentDraft') : `v${compare.target}`\n\n // Step the base through history, skipping the target so the sides never collapse.\n const baseIndex = versions.findIndex((v) => v.version === compare.base)\n const nextBaseFor = (dir: -1 | 1): number | undefined => {\n let i = baseIndex + dir\n while (i >= 0 && i < versions.length && versions[i]!.version === compare.target) i += dir\n return i >= 0 && i < versions.length ? versions[i]!.version : undefined\n }\n const newerBase = nextBaseFor(-1) // versions are newest-first\n const olderBase = nextBaseFor(1)\n\n const baseOptions = versions\n .filter((v) => v.version !== compare.target)\n .map((v) => ({ value: v.version, label: `v${v.version}`, meta: formatVersionTimestamp(v.createdAt) }))\n const targetOptions = [\n {\n value: 'draft' as const,\n label: translate('cms.version.currentDraft'),\n meta: dirty ? translate('cms.version.unsavedEdits') : undefined,\n },\n ...versions\n .filter((v) => v.version !== compare.base)\n .map((v) => ({ value: v.version, label: `v${v.version}`, meta: formatVersionTimestamp(v.createdAt) })),\n ]\n\n return (\n <Stack gap=\"3\" className=\"mx-auto w-full max-w-5xl p-4 sm:p-6\">\n {/* The two sides — both re-pickable, so any pair can be compared; the\n Versions pane also sets the base on click. Stepper walks the base. */}\n <Row gap=\"2\" align=\"center\" wrap className=\"rounded-md border border-border/70 bg-muted/30 px-3 py-2\">\n <VersionMenu\n caption={translate('cms.version.baseCaption')}\n current={`v${compare.base}`}\n meta={formatVersionTimestamp(baseRecord.createdAt)}\n options={baseOptions}\n onSelect={(v) => setCompareBase(v as number)}\n />\n <ArrowRight className=\"size-4 shrink-0 text-muted-foreground\" aria-hidden />\n <VersionMenu\n caption={translate('cms.version.compareWithCaption')}\n current={targetLabel}\n options={targetOptions}\n onSelect={(v) => setCompareTarget(v as number | 'draft')}\n />\n <Spacer />\n <Row gap=\"1\">\n <Button\n variant=\"outline\"\n size=\"icon-sm\"\n onClick={() => newerBase !== undefined && setCompareBase(newerBase)}\n disabled={newerBase === undefined}\n title={translate('cms.version.compareNewer')}\n aria-label={translate('cms.version.compareNewer')}\n >\n <ChevronLeft />\n </Button>\n <Button\n variant=\"outline\"\n size=\"icon-sm\"\n onClick={() => olderBase !== undefined && setCompareBase(olderBase)}\n disabled={olderBase === undefined}\n title={translate('cms.version.compareOlder')}\n aria-label={translate('cms.version.compareOlder')}\n >\n <ChevronRight />\n </Button>\n </Row>\n {canRestore ? (\n <Button\n size=\"sm\"\n variant=\"outline\"\n onClick={() => void restore({ kind: 'all' })}\n disabled={busy || diff.changes.length === 0}\n title={translate('cms.version.restoreWholeTitle', { version: compare.base })}\n >\n <RotateCcw /> {translate('cms.version.restoreVersion')}\n </Button>\n ) : null}\n </Row>\n\n <Text size=\"xs\" tone=\"muted\" className=\"px-0.5\">\n {diff.changes.length === 0\n ? translate('cms.version.noDifferences')\n : translate(\n diff.changes.length === 1\n ? 'cms.version.changeSummary.one'\n : 'cms.version.changeSummary.other',\n { count: diff.changes.length, unchanged: diff.unchangedCount },\n )}\n {!canRestore && diff.changes.length > 0\n ? translate('cms.version.comparingPastVersionsHint')\n : ''}\n </Text>\n\n {diff.changes.length === 0 ? (\n <CompareNotice>{translate('cms.version.versionsIdentical')}</CompareNotice>\n ) : (\n <div className=\"relative\">\n {/* One continuous 2px centre divider behind the before | after columns. */}\n <div\n className=\"pointer-events-none absolute inset-y-0 left-1/2 w-0.5 -translate-x-1/2 bg-border\"\n aria-hidden\n />\n <TwoCol\n className=\"px-0.5 pb-1\"\n before={\n <Text size=\"xs\" tone=\"subtle\" className=\"uppercase tracking-wide\">\n {translate('cms.version.beforeVersion', { version: compare.base })}\n </Text>\n }\n after={\n <Text size=\"xs\" tone=\"subtle\" className=\"uppercase tracking-wide\">\n {translate('cms.version.afterTarget', { target: targetLabel })}\n </Text>\n }\n />\n {groups.map((group) => (\n <FieldGroup key={group.field} group={group} canRestore={canRestore} busy={busy} onRestore={restore} />\n ))}\n </div>\n )}\n </Stack>\n )\n}\n\n/** A before | after grid; the continuous centre divider lives behind it (in the\n * parent), so the gap is where the two columns meet. */\nfunction TwoCol({ before, after, className }: { before: ReactNode; after: ReactNode; className?: string }) {\n return (\n <div className={cn('grid grid-cols-2 gap-x-6', className)}>\n <div className=\"min-w-0\">{before}</div>\n <div className=\"min-w-0\">{after}</div>\n </div>\n )\n}\n\nfunction VersionMenu({\n caption,\n current,\n meta,\n options,\n onSelect,\n}: {\n caption: string\n current: string\n meta?: string\n options: { value: number | 'draft'; label: string; meta?: string }[]\n onSelect: (value: number | 'draft') => void\n}) {\n return (\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <Button variant=\"outline\" size=\"sm\" className=\"gap-1.5\">\n <Text size=\"xs\" tone=\"subtle\" className=\"uppercase tracking-wide\">\n {caption}\n </Text>\n <Text size=\"sm\" weight=\"medium\" mono>\n {current}\n </Text>\n {meta ? (\n <Text size=\"xs\" tone=\"muted\" className=\"hidden sm:inline\">\n {meta}\n </Text>\n ) : null}\n <ChevronDown className=\"size-3.5 text-muted-foreground\" />\n </Button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"start\" className=\"max-h-72 overflow-auto\">\n {options.map((o) => (\n <DropdownMenuItem key={String(o.value)} onClick={() => onSelect(o.value)} className=\"gap-2\">\n <Text size=\"sm\" weight=\"medium\" mono={o.value !== 'draft'}>\n {o.label}\n </Text>\n {o.meta ? (\n <Text size=\"xs\" tone=\"muted\">\n {o.meta}\n </Text>\n ) : null}\n </DropdownMenuItem>\n ))}\n </DropdownMenuContent>\n </DropdownMenu>\n )\n}\n\ninterface FieldGroupData {\n field: string\n label: string\n type: FieldDef['type']\n entries: FieldChange[]\n}\n\nfunction FieldGroup({\n group,\n canRestore,\n busy,\n onRestore,\n}: {\n group: FieldGroupData\n canRestore: boolean\n busy: boolean\n onRestore: (scope: RestoreScope) => void\n}) {\n // A plain (non-localized) field is a single entry — label + value inline. A\n // localized field groups its locale variants under one label.\n const single = group.entries.length === 1 && group.entries[0]!.locale === undefined\n if (single) {\n const entry = group.entries[0]!\n return (\n <div className=\"border-t border-border/30 py-3\">\n <Row gap=\"2\" align=\"center\" className=\"mb-1.5\">\n <Text size=\"sm\" weight=\"medium\" className=\"min-w-0 truncate\">\n {group.label}\n </Text>\n <KindTag kind={entry.kind} />\n <Spacer />\n {canRestore ? (\n <RestoreIcon\n busy={busy}\n title={translate('cms.version.restoreField', { field: group.label })}\n onClick={() => onRestore(fieldScope(entry))}\n />\n ) : null}\n </Row>\n <EntryBody change={entry} canRestore={canRestore} busy={busy} onRestore={onRestore} />\n </div>\n )\n }\n return (\n <div className=\"border-t border-border/30 py-3\">\n <Text size=\"sm\" weight=\"medium\" className=\"mb-2 block\">\n {group.label}\n </Text>\n <Stack gap=\"3\">\n {group.entries.map((entry) => (\n <div key={entry.locale ?? '__base__'}>\n <Row gap=\"2\" align=\"center\" className=\"mb-1\">\n {entry.locale ? (\n <Badge variant=\"outline\" className=\"px-1 py-0 text-[0.6rem] uppercase tracking-wide text-muted-foreground\">\n {localeChipLabel(entry.locale)}\n </Badge>\n ) : null}\n <KindTag kind={entry.kind} />\n <Spacer />\n {canRestore ? (\n <RestoreIcon\n busy={busy}\n title={\n entry.locale\n ? translate('cms.version.restoreFieldLocale', {\n field: group.label,\n locale: localeChipLabel(entry.locale),\n })\n : translate('cms.version.restoreField', { field: group.label })\n }\n onClick={() => onRestore(fieldScope(entry))}\n />\n ) : null}\n </Row>\n <EntryBody change={entry} canRestore={canRestore} busy={busy} onRestore={onRestore} />\n </div>\n ))}\n </Stack>\n </div>\n )\n}\n\nfunction EntryBody({\n change,\n canRestore,\n busy,\n onRestore,\n}: {\n change: FieldChange\n canRestore: boolean\n busy: boolean\n onRestore: (scope: RestoreScope) => void\n}) {\n const localeScope = change.locale !== undefined ? { locale: change.locale } : {}\n if (change.blocks) {\n return (\n <Stack gap=\"3\" className=\"mt-1\">\n {change.blocks.map((block) => (\n <BlockSection\n key={block.blockId}\n block={block}\n canRestore={canRestore}\n busy={busy}\n onRestore={() =>\n onRestore({ kind: 'block', field: change.field, blockId: block.blockId, ...localeScope })\n }\n />\n ))}\n </Stack>\n )\n }\n if (change.type === 'richText') {\n const before = richTextToText(change.before)\n const after = richTextToText(change.after)\n if (before === after)\n return (\n <MutedNote>\n {before\n ? translate('cms.version.textUnchanged')\n : translate('cms.version.contentChanged')}\n </MutedNote>\n )\n return <WordDiffCols before={before} after={after} />\n }\n if (change.kind === 'changed' && typeof change.before === 'string' && typeof change.after === 'string') {\n return <WordDiffCols before={change.before} after={change.after} />\n }\n return (\n <TwoCol\n before={<SideValue value={change.before} other={change.after} typeHint={change.type} />}\n after={<SideValue value={change.after} other={change.before} typeHint={change.type} />}\n />\n )\n}\n\nfunction BlockSection({\n block,\n canRestore,\n busy,\n onRestore,\n}: {\n block: BlockChange\n canRestore: boolean\n busy: boolean\n onRestore: () => void\n}) {\n const name = block.componentId.split('.').pop() ?? block.componentId\n return (\n <div>\n <Row gap=\"2\" align=\"center\" className=\"mb-1\">\n <Text size=\"xs\" weight=\"medium\" className=\"min-w-0 truncate\">\n {name}\n </Text>\n <Code tone=\"muted\">{block.componentId}</Code>\n <KindTag kind={block.kind} />\n <Spacer />\n {canRestore ? (\n <RestoreIcon busy={busy} title={translate('cms.version.restoreBlock')} onClick={onRestore} />\n ) : null}\n </Row>\n {block.props && block.props.length > 0 ? (\n <Stack gap=\"2\">\n {block.props.map((prop) => (\n <PropRow key={prop.name} prop={prop} />\n ))}\n </Stack>\n ) : null}\n {block.slotsChanged ? <MutedNote>{translate('cms.version.nestedContentChanged')}</MutedNote> : null}\n {block.kind !== 'changed' && !block.props?.length ? (\n <MutedNote>\n {block.kind === 'added'\n ? translate('cms.version.blockAdded')\n : translate('cms.version.blockRemoved')}\n </MutedNote>\n ) : null}\n </div>\n )\n}\n\nfunction PropRow({ prop }: { prop: PropChange }) {\n const useWordDiff =\n prop.kind === 'changed' && typeof prop.before === 'string' && typeof prop.after === 'string'\n return (\n <div>\n <Text size=\"xs\" tone=\"subtle\" className=\"mb-0.5 block uppercase tracking-wide\">\n {prettyName(prop.name)}\n </Text>\n {useWordDiff ? (\n <WordDiffCols before={String(prop.before)} after={String(prop.after)} />\n ) : (\n <TwoCol\n before={<SideValue value={prop.before} other={prop.after} />}\n after={<SideValue value={prop.after} other={prop.before} />}\n />\n )}\n </div>\n )\n}\n\n/** One side of a non-text change — the value, or an \"empty\" placeholder. */\nfunction SideValue({ value, other, typeHint }: { value: unknown; other?: unknown; typeHint?: FieldDef['type'] }) {\n if (value === undefined || value === null || value === '') {\n return (\n <Text size=\"sm\" tone=\"subtle\" className=\"italic\">\n {translate('cms.version.emptyValue')}\n </Text>\n )\n }\n return <ValueView value={value} other={other} typeHint={typeHint} />\n}\n\n/**\n * Read-only value display, dispatching on the field type where known and on the\n * self-describing value shape otherwise (block props carry no schema) — assets as\n * thumbnails, relations as titles, everything else as calm text.\n */\nfunction ValueView({ value, other, typeHint }: { value: unknown; other?: unknown; typeHint?: FieldDef['type'] }) {\n if (typeHint === 'asset' || isAssetNode(value)) return <AssetValue value={value} />\n if (typeHint === 'relation' || readDocumentRef(value)) return <RelationValue value={value} other={other} />\n if (typeHint === 'richText')\n return (\n <Text size=\"sm\" className=\"whitespace-pre-wrap break-words\">\n {richTextToText(value) || translate('cms.version.richText')}\n </Text>\n )\n if (typeHint === 'boolean' || typeof value === 'boolean')\n return (\n <Text size=\"sm\" mono>\n {value === true ? translate('common.yes') : translate('common.no')}\n </Text>\n )\n if (typeHint === 'date')\n return (\n <Text size=\"sm\" mono>\n {String(value).slice(0, 10)}\n </Text>\n )\n if (typeof value === 'object')\n return (\n <Text size=\"sm\" tone=\"muted\">\n {Array.isArray(value)\n ? translate(\n value.length === 1 ? 'cms.version.itemCount.one' : 'cms.version.itemCount.other',\n { count: value.length },\n )\n : translate('cms.version.objectValue')}\n </Text>\n )\n return (\n <Text size=\"sm\" className=\"whitespace-pre-wrap break-words\">\n {String(value)}\n </Text>\n )\n}\n\nfunction RelationValue({ value, other }: { value: unknown; other?: unknown }) {\n const source = useCollectionView()\n const refs = toRefArray(value)\n if (refs.length === 0)\n return (\n <Text size=\"sm\" className=\"whitespace-pre-wrap break-words\">\n {String(value)}\n </Text>\n )\n const otherRefs = other !== undefined ? toRefArray(other) : []\n // Disambiguate a same-titled but different target (the \"Ada → Ada\" trap): show\n // the id only when the titles would otherwise read identically.\n const label = refs\n .map((ref) => {\n const title = source.titleOf(ref)\n const collision = otherRefs.some((o) => o.id !== ref.id && source.titleOf(o) === title)\n return collision ? `${title} · ${ref.id}` : title\n })\n .join(', ')\n return <Text size=\"sm\">{label}</Text>\n}\n\nfunction AssetValue({ value }: { value: unknown }) {\n const ids = (Array.isArray(value) ? value : [value])\n .map(readAssetId)\n .filter((id): id is string => id !== undefined)\n if (ids.length === 0)\n return (\n <Text size=\"sm\" className=\"whitespace-pre-wrap break-words\">\n {String(value)}\n </Text>\n )\n return (\n <div className=\"flex flex-wrap gap-2\">\n {ids.map((id) => (\n <AssetThumb key={id} id={id} />\n ))}\n </div>\n )\n}\n\n/** An asset as a thumbnail (image with a resolvable URL) or a labelled badge —\n * the visual diff for a cover-image change, not two identical filenames. */\nfunction AssetThumb({ id }: { id: string }) {\n const source = useCollectionView()\n const assetCollectionId = source.assetCollectionId ?? 'asset'\n const record = source.resolveAsset?.(id)\n const label = record?.title ?? record?.filename ?? source.titleOf({ collection: assetCollectionId, id })\n const isImage = record?.contentType?.startsWith('image/') ?? false\n const url = record?.url\n if (isImage && url && url.startsWith('http')) {\n return (\n <span className=\"inline-flex min-w-0 items-center gap-2\">\n <img\n src={url}\n alt={record?.alt ?? label}\n loading=\"lazy\"\n className=\"size-12 shrink-0 rounded border border-border bg-muted object-cover\"\n />\n <Text size=\"xs\" tone=\"muted\" className=\"min-w-0 truncate\">\n {label}\n </Text>\n </span>\n )\n }\n return (\n <Badge variant=\"outline\">\n <ImageIcon className=\"size-3\" /> {label}\n </Badge>\n )\n}\n\n// --- Prose word diff --------------------------------------------------------------\n\n/** Prose-diff across the central divider, both sides from one LCS. */\nfunction WordDiffCols({ before, after }: { before: string; after: string }) {\n const wd = useMemo(() => wordDiff(before, after), [before, after])\n return (\n <TwoCol\n before={<WordTokens tokens={wd.before} side=\"before\" />}\n after={<WordTokens tokens={wd.after} side=\"after\" />}\n />\n )\n}\n\nfunction WordTokens({ tokens, side }: { tokens: WordToken[]; side: 'before' | 'after' }) {\n return (\n <Text size=\"sm\" className=\"whitespace-pre-wrap break-words leading-relaxed\">\n {tokens.map((token, i) =>\n token.changed ? (\n <mark\n key={i}\n className={cn(\n 'rounded-sm px-0.5',\n side === 'before'\n ? 'bg-destructive/15 text-destructive line-through decoration-destructive/40'\n : 'bg-success/20 text-foreground',\n )}\n >\n {token.text}\n </mark>\n ) : (\n <span key={i} className=\"text-muted-foreground\">\n {token.text}\n </span>\n ),\n )}\n </Text>\n )\n}\n\n// --- Small shared bits ------------------------------------------------------------\n\n/** A quiet \"· new\" / \"· removed\" tag; nothing for a plain change (implicit). */\nfunction KindTag({ kind }: { kind: FieldChange['kind'] }) {\n if (kind === 'changed') return null\n return (\n <Text size=\"xs\" tone=\"subtle\">\n · {kind === 'added' ? translate('cms.version.kindNew') : translate('cms.version.kindRemoved')}\n </Text>\n )\n}\n\nfunction RestoreIcon({ busy, title, onClick }: { busy: boolean; title: string; onClick: () => void }) {\n return (\n <Button variant=\"ghost\" size=\"icon-sm\" disabled={busy} title={title} aria-label={title} onClick={onClick}>\n <RotateCcw />\n </Button>\n )\n}\n\nfunction MutedNote({ children }: { children: ReactNode }) {\n return (\n <Text size=\"sm\" tone=\"muted\" className=\"italic\">\n {children}\n </Text>\n )\n}\n\nfunction CompareNotice({ children }: { children: ReactNode }) {\n return (\n <div className=\"mx-auto w-full max-w-5xl p-4 sm:p-6\">\n <div className=\"rounded-md border border-dashed border-border/70 px-4 py-8 text-center\">\n <Text size=\"sm\" tone=\"muted\">\n {children}\n </Text>\n </div>\n </div>\n )\n}\n\nfunction fieldScope(change: FieldChange): RestoreScope {\n return { kind: 'field', field: change.field, ...(change.locale !== undefined ? { locale: change.locale } : {}) }\n}\n\n/**\n * Group changes BY FIELD (a localized field's per-locale variants together),\n * fields in schema order, locales in project order (base bucket first).\n */\nfunction groupByField(\n changes: FieldChange[],\n fieldOrder: Map<string, number>,\n localeRank: Map<string, number>,\n): FieldGroupData[] {\n const map = new Map<string, FieldGroupData>()\n for (const change of changes) {\n let group = map.get(change.field)\n if (!group) {\n group = { field: change.field, label: change.label, type: change.type, entries: [] }\n map.set(change.field, group)\n }\n group.entries.push(change)\n }\n const groups = [...map.values()]\n groups.sort(\n (a, b) => (fieldOrder.get(a.field) ?? Number.MAX_SAFE_INTEGER) - (fieldOrder.get(b.field) ?? Number.MAX_SAFE_INTEGER),\n )\n for (const group of groups) {\n group.entries.sort((a, b) => localeCompare(a.locale, b.locale, localeRank))\n }\n return groups\n}\n\nfunction localeCompare(a: string | undefined, b: string | undefined, rank: Map<string, number>): number {\n if (a === b) return 0\n if (a === undefined) return -1 // base bucket first\n if (b === undefined) return 1\n return (rank.get(a) ?? 99) - (rank.get(b) ?? 99)\n}\n\n/** camelCase / snake prop name → a readable label. */\nfunction prettyName(name: string): string {\n const spaced = name.replace(/[_-]+/g, ' ').replace(/([a-z0-9])([A-Z])/g, '$1 $2')\n return spaced.charAt(0).toUpperCase() + spaced.slice(1)\n}\n"]}
|
|
@@ -4,6 +4,7 @@ import { Eye, GitCompareArrows, RotateCcw } from 'lucide-react';
|
|
|
4
4
|
import { Badge, Button, Code, Row, Spacer, Stack, Text } from '@elytracms/studio/ui';
|
|
5
5
|
import { documentsSemanticEqual } from '@elytracms/core/content';
|
|
6
6
|
import { useOperationCache } from '@elytracms/studio/lib/query';
|
|
7
|
+
import { translate } from '@elytracms/studio/lib/i18n';
|
|
7
8
|
import { cn } from '@elytracms/studio/lib/utils';
|
|
8
9
|
import { useCollectionView } from '../collection-view/collection-view-context';
|
|
9
10
|
import { useDocumentEditor } from './document-editor-context';
|
|
@@ -80,11 +81,13 @@ export function VersionsPane() {
|
|
|
80
81
|
setBusy(false);
|
|
81
82
|
}
|
|
82
83
|
}, [source, docRef, dirty, save, replaceDraft, cache, versionKey]);
|
|
83
|
-
return (_jsxs(Stack, { gap: "3", className: "p-3", children: [canPublish ? (_jsxs(Row, { gap: "2", align: "center", className: "rounded-md border border-primary/40 bg-primary/5 px-2.5 py-2", children: [_jsxs(Stack, { gap: "none", className: "min-w-0", children: [_jsx(Text, { size: "sm", weight: "medium", children:
|
|
84
|
-
|
|
84
|
+
return (_jsxs(Stack, { gap: "3", className: "p-3", children: [canPublish ? (_jsxs(Row, { gap: "2", align: "center", className: "rounded-md border border-primary/40 bg-primary/5 px-2.5 py-2", children: [_jsxs(Stack, { gap: "none", className: "min-w-0", children: [_jsx(Text, { size: "sm", weight: "medium", children: translate('cms.editor.draftState') }), _jsx(Text, { size: "xs", tone: "muted", children: published
|
|
85
|
+
? translate('cms.version.unpublishedChanges')
|
|
86
|
+
: translate('cms.version.notPublishedYet') })] }), _jsx(Spacer, {}), _jsxs(Button, { size: "sm", onClick: handlePublish, disabled: busy || hasErrors || viewReadOnly, title: viewReadOnly
|
|
87
|
+
? translate('cms.editor.switchToDraftToPublish')
|
|
85
88
|
: hasErrors
|
|
86
|
-
? '
|
|
87
|
-
: undefined, children: [_jsx(Eye, {}), "
|
|
89
|
+
? translate('cms.version.fixValidationToPublish')
|
|
90
|
+
: undefined, children: [_jsx(Eye, {}), " ", translate('cms.editor.publish')] })] })) : (_jsx(Text, { size: "xs", tone: "muted", className: "px-0.5", children: translate('cms.version.liveUpToDate') })), compareActive && compare ? (_jsxs(Text, { size: "xs", tone: "muted", className: "px-0.5", children: ["Comparing ", _jsxs("span", { className: "font-medium text-foreground", children: ["v", compare.base] }), " \u2192", ' ', compare.target === 'draft' ? 'Current draft' : `v${compare.target}`, ". Click a version to set it as the base."] })) : null, _jsx(Stack, { gap: "1", children: view === null ? (_jsx(Text, { size: "xs", tone: "muted", className: "px-0.5", children: translate('common.loading') })) : view.versions.length === 0 ? (_jsx(Text, { size: "xs", tone: "muted", className: "px-0.5", children: translate('cms.version.noVersionsYet') })) : (view.versions.map((entry) => {
|
|
88
91
|
const isLive = entry.version === view.publishedVersion;
|
|
89
92
|
const isBase = compareActive && compare?.base === entry.version;
|
|
90
93
|
const isTarget = compareActive && compare?.target === entry.version;
|
|
@@ -101,7 +104,7 @@ export function VersionsPane() {
|
|
|
101
104
|
}
|
|
102
105
|
},
|
|
103
106
|
}
|
|
104
|
-
: {}), className: cn('rounded-md border px-2.5 py-1.5', isBase ? 'border-primary bg-primary/5' : 'border-border/60', selectable && !isBase && 'cursor-pointer hover:bg-muted/60'), children: [_jsxs(Code, { tone: isLive ? 'primary' : 'muted', children: ["v", entry.version] }), isLive ? _jsx(Badge, { variant: "success", children:
|
|
107
|
+
: {}), className: cn('rounded-md border px-2.5 py-1.5', isBase ? 'border-primary bg-primary/5' : 'border-border/60', selectable && !isBase && 'cursor-pointer hover:bg-muted/60'), children: [_jsxs(Code, { tone: isLive ? 'primary' : 'muted', children: ["v", entry.version] }), isLive ? _jsx(Badge, { variant: "success", children: translate('cms.editor.publishedState') }) : null, isBase ? (_jsx(Badge, { variant: "outline", children: translate('cms.version.baseBadge') })) : isTarget ? (_jsx(Badge, { variant: "outline", children: translate('cms.version.comparedBadge') })) : null, _jsx(Text, { size: "xs", tone: "subtle", mono: true, className: "truncate", children: formatVersionTimestamp(entry.createdAt) }), _jsx(Spacer, {}), compareActive ? null : (_jsxs(_Fragment, { children: [_jsx(Button, { size: "icon-sm", variant: "ghost", onClick: () => startCompare(entry.version), title: translate('cms.version.compareWithDraft'), "aria-label": translate('cms.version.compareVersionLabel', { version: entry.version }), children: _jsx(GitCompareArrows, {}) }), isLive ? null : (_jsxs(Button, { size: "sm", variant: "outline", onClick: () => void handleRestore(entry.version), disabled: busy || viewReadOnly, title: viewReadOnly ? translate('cms.version.switchToDraftToRestore') : undefined, children: [_jsx(RotateCcw, {}), " ", translate('cms.version.restore')] }))] }))] }, entry.version));
|
|
105
108
|
})) })] }));
|
|
106
109
|
}
|
|
107
110
|
//# sourceMappingURL=versions-pane.js.map
|