includio-cms 0.1.4 → 0.5.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 +83 -0
- package/ROADMAP.md +26 -13
- package/dist/admin/api/accept-invite.js +1 -5
- package/dist/admin/api/invite.js +7 -16
- package/dist/admin/client/account/account-page.svelte +20 -50
- package/dist/admin/client/account/lang.d.ts +15 -23
- package/dist/admin/client/account/lang.js +51 -67
- package/dist/admin/client/account/preferences-section.svelte +26 -84
- package/dist/admin/client/account/profile-section.svelte +60 -40
- package/dist/admin/client/account/schema.d.ts +11 -3
- package/dist/admin/client/account/schema.js +25 -16
- package/dist/admin/client/account/security-section.svelte +139 -105
- package/dist/admin/client/account/sessions-section.svelte +35 -34
- package/dist/admin/client/admin/admin-after-login-layout-content.svelte +3 -5
- package/dist/admin/client/admin/admin-layout.svelte +3 -2
- package/dist/admin/client/admin/admin-preloader.svelte +36 -0
- package/dist/admin/client/admin/admin-preloader.svelte.d.ts +18 -0
- package/dist/admin/client/admin/dashboard-page.svelte +35 -67
- package/dist/admin/client/collection/a11y-score-cell.svelte +45 -0
- package/dist/admin/client/collection/a11y-score-cell.svelte.d.ts +6 -0
- package/dist/admin/client/collection/bulk-actions-bar.svelte +100 -0
- package/dist/admin/client/collection/bulk-actions-bar.svelte.d.ts +10 -0
- package/dist/admin/client/collection/collection-entries.svelte +277 -258
- package/dist/admin/client/collection/collection-view.svelte.d.ts +4 -3
- package/dist/admin/client/collection/collection-view.svelte.js +9 -5
- package/dist/admin/client/collection/collection.svelte +22 -12
- package/dist/admin/client/collection/data-table.svelte +50 -39
- package/dist/admin/client/collection/data-table.svelte.d.ts +1 -0
- package/dist/admin/client/collection/date-cell.svelte +7 -5
- package/dist/admin/client/collection/date-cell.svelte.d.ts +1 -1
- package/dist/admin/client/collection/empty-state.svelte +28 -0
- package/dist/admin/client/collection/empty-state.svelte.d.ts +9 -0
- package/dist/admin/client/collection/entry-link.svelte +10 -4
- package/dist/admin/client/collection/entry-link.svelte.d.ts +1 -0
- package/dist/admin/client/collection/grid-view.svelte +21 -23
- package/dist/admin/client/collection/grid-view.svelte.d.ts +1 -2
- package/dist/admin/client/collection/row-actions.svelte +69 -0
- package/dist/admin/client/collection/row-actions.svelte.d.ts +10 -0
- package/dist/admin/client/collection/status-badge.svelte +7 -8
- package/dist/admin/client/collection/table-pagination.svelte +122 -79
- package/dist/admin/client/collection/table-pagination.svelte.d.ts +1 -0
- package/dist/admin/client/collection/table-toolbar.svelte +108 -88
- package/dist/admin/client/collection/table-toolbar.svelte.d.ts +8 -9
- package/dist/admin/client/entry/entry-form.svelte +109 -1
- package/dist/admin/client/entry/entry-header.svelte +143 -37
- package/dist/admin/client/entry/entry-header.svelte.d.ts +8 -0
- package/dist/admin/client/entry/entry.svelte +272 -61
- package/dist/admin/client/entry/header/a11y-validator.d.ts +47 -0
- package/dist/admin/client/entry/header/a11y-validator.js +352 -0
- package/dist/admin/client/entry/header/publish-panel.svelte +531 -129
- package/dist/admin/client/entry/header/publish-panel.svelte.d.ts +4 -0
- package/dist/admin/client/entry/header/save-indicator.svelte +33 -23
- package/dist/admin/client/entry/header/schedule-popover.svelte +1 -1
- package/dist/admin/client/entry/header/status-badge.svelte +25 -118
- package/dist/admin/client/entry/header/version-history-sheet.svelte +322 -98
- package/dist/admin/client/form/form-submission/form-submission.svelte +271 -83
- package/dist/admin/client/form/form-submission/submission-field.svelte +12 -12
- package/dist/admin/client/form/form-submissions.svelte +421 -139
- package/dist/admin/client/form/submission-link.svelte +8 -2
- package/dist/admin/client/form/submission-link.svelte.d.ts +1 -0
- package/dist/admin/client/form/submission-status-badge.svelte +18 -4
- package/dist/admin/client/form/submission-status-badge.svelte.d.ts +1 -0
- package/dist/admin/client/login/lang.d.ts +32 -0
- package/dist/admin/client/login/lang.js +66 -2
- package/dist/admin/client/login/login-form.svelte +237 -95
- package/dist/admin/client/login/login-form.svelte.d.ts +2 -17
- package/dist/admin/client/login/login-page.svelte +34 -98
- package/dist/admin/client/login/reset-password-page.svelte +235 -0
- package/dist/admin/client/login/reset-password-page.svelte.d.ts +4 -0
- package/dist/admin/client/login/schema.d.ts +15 -0
- package/dist/admin/client/login/schema.js +21 -0
- package/dist/admin/client/users/accept-invite-page.svelte +166 -37
- package/dist/admin/client/users/create-user-dialog.svelte +15 -7
- package/dist/admin/client/users/delete-user-dialog.svelte +81 -16
- package/dist/admin/client/users/delete-user-dialog.svelte.d.ts +4 -1
- package/dist/admin/client/users/edit-user-dialog.svelte +3 -0
- package/dist/admin/client/users/invite-user-dialog.svelte +16 -3
- package/dist/admin/client/users/lang.d.ts +27 -0
- package/dist/admin/client/users/lang.js +64 -10
- package/dist/admin/client/users/pending-invitations.svelte +59 -23
- package/dist/admin/client/users/users-page.svelte +471 -72
- package/dist/admin/components/accessibility/accessibility-overview.svelte +2 -7
- package/dist/admin/components/dashboard/a11y-gauge.svelte +90 -0
- package/dist/admin/components/dashboard/a11y-gauge.svelte.d.ts +18 -0
- package/dist/admin/components/dashboard/accessibility-hub.svelte +13 -12
- package/dist/admin/components/dashboard/changelog-dialog.svelte +157 -0
- package/dist/admin/components/dashboard/changelog-dialog.svelte.d.ts +6 -0
- package/dist/admin/components/dashboard/form-submissions-widget.svelte +71 -113
- package/dist/admin/components/dashboard/index.d.ts +4 -2
- package/dist/admin/components/dashboard/index.js +4 -2
- package/dist/admin/components/dashboard/orphaned-entries-notice.svelte +240 -0
- package/dist/admin/components/dashboard/orphaned-entries-notice.svelte.d.ts +13 -0
- package/dist/admin/components/dashboard/recent-activity.svelte +53 -75
- package/dist/admin/components/dashboard/recent-entries.svelte +94 -0
- package/dist/admin/components/dashboard/recent-entries.svelte.d.ts +18 -0
- package/dist/admin/components/dashboard/stat-card.svelte +2 -2
- package/dist/admin/components/dashboard/tip-of-the-day.svelte +109 -0
- package/dist/admin/components/dashboard/tip-of-the-day.svelte.d.ts +3 -0
- package/dist/admin/components/dashboard/welcome-header.svelte +45 -0
- package/dist/admin/components/dashboard/welcome-header.svelte.d.ts +3 -0
- package/dist/admin/components/fields/{array-field.svelte → blocks-field.svelte} +4 -4
- package/dist/admin/components/fields/{array-field.svelte.d.ts → blocks-field.svelte.d.ts} +5 -5
- package/dist/admin/components/fields/content-field.svelte +27 -0
- package/dist/admin/components/fields/content-field.svelte.d.ts +31 -0
- package/dist/admin/components/fields/field-renderer.svelte +9 -7
- package/dist/admin/components/fields/image-field.svelte +2 -2
- package/dist/admin/components/fields/media-field.svelte +2 -2
- package/dist/admin/components/fields/seo-field.svelte +205 -25
- package/dist/admin/components/fields/simple-array-field.svelte +289 -0
- package/dist/admin/components/fields/simple-array-field.svelte.d.ts +30 -0
- package/dist/admin/components/fields/slug-field.svelte +3 -2
- package/dist/admin/components/fields/standalone-field-renderer.svelte +148 -0
- package/dist/admin/components/fields/standalone-field-renderer.svelte.d.ts +9 -0
- package/dist/admin/components/fields/text-field-wrapper.svelte +147 -3
- package/dist/admin/components/fields/text-field-wrapper.svelte.d.ts +2 -2
- package/dist/admin/components/fields/url-field.svelte +5 -4
- package/dist/admin/components/layout/app-sidebar.svelte +27 -24
- package/dist/admin/components/layout/lang.d.ts +6 -0
- package/dist/admin/components/layout/lang.js +13 -1
- package/dist/admin/components/layout/layout-renderer.svelte +352 -0
- package/dist/admin/components/layout/layout-renderer.svelte.d.ts +14 -0
- package/dist/admin/components/layout/nav-breadcrumbs.svelte +4 -4
- package/dist/admin/components/layout/nav-collections.svelte +65 -36
- package/dist/admin/components/layout/nav-footer.svelte +38 -0
- package/dist/admin/components/layout/nav-footer.svelte.d.ts +3 -0
- package/dist/admin/components/layout/nav-forms.svelte +55 -30
- package/dist/admin/components/layout/nav-main.svelte +14 -52
- package/dist/admin/components/layout/nav-search.svelte +4 -3
- package/dist/admin/components/layout/nav-singletons.svelte +59 -17
- package/dist/admin/components/layout/nav-singletons.svelte.d.ts +17 -8
- package/dist/admin/components/layout/site-header.svelte +74 -13
- package/dist/admin/components/media/alt-input.svelte +32 -22
- package/dist/admin/components/media/bulk-action-bar.svelte +139 -150
- package/dist/admin/components/media/file/file-details.svelte +299 -217
- package/dist/admin/components/media/file/file-miniature.svelte +54 -41
- package/dist/admin/components/media/file/file-miniature.svelte.d.ts +1 -0
- package/dist/admin/components/media/file/file-preview.svelte +1 -1
- package/dist/admin/components/media/file-upload.svelte +24 -26
- package/dist/admin/components/media/files-list.svelte +112 -40
- package/dist/admin/components/media/files-list.svelte.d.ts +2 -0
- package/dist/admin/components/media/focal-point-input.svelte +122 -26
- package/dist/admin/components/media/media-library.svelte +127 -70
- package/dist/admin/components/media/media-search.svelte +6 -6
- package/dist/admin/components/media/media-sort.svelte +3 -1
- package/dist/admin/components/media/multi-file-summary.svelte +88 -68
- package/dist/admin/components/media/tag-combobox.svelte +141 -66
- package/dist/admin/components/media/tag-combobox.svelte.d.ts +1 -0
- package/dist/admin/components/media/tag-sidebar.svelte +139 -121
- package/dist/admin/components/tiptap/FigureNodeView.svelte +144 -15
- package/dist/admin/components/tiptap/InlineBlockNodeView.svelte +254 -0
- package/dist/admin/components/tiptap/InlineBlockNodeView.svelte.d.ts +4 -0
- package/dist/admin/components/tiptap/SlashCommandPopup.svelte +212 -0
- package/dist/admin/components/tiptap/SlashCommandPopup.svelte.d.ts +8 -0
- package/dist/admin/components/tiptap/content-editor.svelte +280 -0
- package/dist/admin/components/tiptap/content-editor.svelte.d.ts +9 -0
- package/dist/admin/components/tiptap/editor-toolbar.svelte +230 -0
- package/dist/admin/components/tiptap/editor-toolbar.svelte.d.ts +16 -0
- package/dist/admin/components/tiptap/heading-a11y-plugin.d.ts +2 -0
- package/dist/admin/components/tiptap/heading-a11y-plugin.js +67 -0
- package/dist/admin/components/tiptap/image-dialog.svelte +172 -11
- package/dist/admin/components/tiptap/inline-block-node.d.ts +19 -0
- package/dist/admin/components/tiptap/inline-block-node.js +98 -0
- package/dist/admin/components/tiptap/link-dialog.svelte +9 -4
- package/dist/admin/components/tiptap/slash-command.d.ts +17 -0
- package/dist/admin/components/tiptap/slash-command.js +181 -0
- package/dist/admin/components/tiptap/structured-content-utils.d.ts +21 -0
- package/dist/admin/components/tiptap/structured-content-utils.js +150 -0
- package/dist/admin/components/tiptap/tiptap-editor.svelte +18 -190
- package/dist/admin/email/invite-template.d.ts +8 -0
- package/dist/admin/email/invite-template.js +99 -0
- package/dist/admin/email/reset-password-template.d.ts +7 -0
- package/dist/admin/email/reset-password-template.js +96 -0
- package/dist/admin/remote/ai.remote.d.ts +1 -0
- package/dist/admin/remote/ai.remote.js +4 -1
- package/dist/admin/remote/entry.remote.d.ts +9 -0
- package/dist/admin/remote/entry.remote.js +58 -8
- package/dist/admin/remote/preview.remote.js +2 -1
- package/dist/admin/shared/password-schema.d.ts +5 -0
- package/dist/admin/shared/password-schema.js +10 -0
- package/dist/admin/state/content-language.svelte.d.ts +3 -0
- package/dist/admin/state/content-language.svelte.js +8 -0
- package/dist/admin/styles/admin.css +1530 -151
- package/dist/admin/utils/formatDate.d.ts +1 -0
- package/dist/admin/utils/formatDate.js +8 -0
- package/dist/admin/utils/roleLabel.d.ts +2 -0
- package/dist/admin/utils/roleLabel.js +13 -0
- package/dist/admin/utils/translationStatus.d.ts +17 -0
- package/dist/admin/utils/translationStatus.js +134 -0
- package/dist/ai-claude/index.d.ts +2 -0
- package/dist/ai-claude/index.js +56 -0
- package/dist/cms/runtime/api.d.ts +6 -1
- package/dist/cms/runtime/api.js +3 -0
- package/dist/cms/runtime/schemas.d.ts +9 -1
- package/dist/cms/runtime/schemas.js +8 -0
- package/dist/cms/runtime/types.d.ts +82 -10
- package/dist/cms/runtime/types.js +4 -0
- package/dist/components/ui/accordion/accordion.stories.svelte +39 -0
- package/dist/components/ui/accordion/accordion.stories.svelte.d.ts +27 -0
- package/dist/components/ui/alert/alert.stories.svelte +53 -0
- package/dist/components/ui/alert/alert.stories.svelte.d.ts +27 -0
- package/dist/components/ui/alert/alert.svelte +5 -0
- package/dist/components/ui/alert/alert.svelte.d.ts +9 -0
- package/dist/components/ui/avatar/avatar.stories.svelte +16 -0
- package/dist/components/ui/avatar/avatar.stories.svelte.d.ts +27 -0
- package/dist/components/ui/badge/badge.stories.svelte +33 -0
- package/dist/components/ui/badge/badge.stories.svelte.d.ts +27 -0
- package/dist/components/ui/breadcrumb/breadcrumb.stories.svelte +33 -0
- package/dist/components/ui/breadcrumb/breadcrumb.stories.svelte.d.ts +27 -0
- package/dist/components/ui/button/button.stories.svelte +43 -0
- package/dist/components/ui/button/button.stories.svelte.d.ts +27 -0
- package/dist/components/ui/button/button.svelte +1 -2
- package/dist/components/ui/button/button.svelte.d.ts +0 -3
- package/dist/components/ui/button-group/button-group-separator.svelte.d.ts +1 -1
- package/dist/components/ui/card/card.stories.svelte +42 -0
- package/dist/components/ui/card/card.stories.svelte.d.ts +27 -0
- package/dist/components/ui/command/command.stories.svelte +51 -0
- package/dist/components/ui/command/command.stories.svelte.d.ts +27 -0
- package/dist/components/ui/dialog/dialog.stories.svelte +29 -0
- package/dist/components/ui/dialog/dialog.stories.svelte.d.ts +27 -0
- package/dist/components/ui/field/field-label.svelte.d.ts +1 -1
- package/dist/components/ui/field/field.stories.svelte +21 -0
- package/dist/components/ui/field/field.stories.svelte.d.ts +27 -0
- package/dist/components/ui/input/input.stories.svelte +40 -0
- package/dist/components/ui/input/input.stories.svelte.d.ts +27 -0
- package/dist/components/ui/input/input.svelte +2 -4
- package/dist/components/ui/item/item-separator.svelte.d.ts +1 -1
- package/dist/components/ui/label/label.stories.svelte +20 -0
- package/dist/components/ui/label/label.stories.svelte.d.ts +27 -0
- package/dist/components/ui/popover/popover.stories.svelte +29 -0
- package/dist/components/ui/popover/popover.stories.svelte.d.ts +27 -0
- package/dist/components/ui/select/select-group-heading.svelte.d.ts +1 -1
- package/dist/components/ui/select/select.stories.svelte +23 -0
- package/dist/components/ui/select/select.stories.svelte.d.ts +27 -0
- package/dist/components/ui/separator/separator.stories.svelte +24 -0
- package/dist/components/ui/separator/separator.stories.svelte.d.ts +27 -0
- package/dist/components/ui/sheet/sheet.stories.svelte +29 -0
- package/dist/components/ui/sheet/sheet.stories.svelte.d.ts +27 -0
- package/dist/components/ui/sidebar/sidebar-group.svelte +3 -3
- package/dist/components/ui/sidebar/sidebar-group.svelte.d.ts +2 -2
- package/dist/components/ui/sidebar/sidebar-menu-button.svelte +28 -30
- package/dist/components/ui/sidebar/sidebar-menu-button.svelte.d.ts +7 -7
- package/dist/components/ui/sidebar/sidebar-separator.svelte.d.ts +1 -1
- package/dist/components/ui/sidebar/sidebar-trigger.svelte +4 -4
- package/dist/components/ui/sonner/sonner.stories.svelte +22 -0
- package/dist/components/ui/sonner/sonner.stories.svelte.d.ts +26 -0
- package/dist/components/ui/sonner/sonner.svelte +8 -2
- package/dist/components/ui/sonner/toast-demo.svelte +29 -0
- package/dist/components/ui/sonner/toast-demo.svelte.d.ts +6 -0
- package/dist/components/ui/textarea/textarea.stories.svelte +22 -0
- package/dist/components/ui/textarea/textarea.stories.svelte.d.ts +27 -0
- package/dist/components/ui/textarea/textarea.svelte +0 -2
- package/dist/components/ui/toggle/toggle.stories.svelte +22 -0
- package/dist/components/ui/toggle/toggle.stories.svelte.d.ts +27 -0
- package/dist/components/ui/toggle-group/toggle-group.stories.svelte +17 -0
- package/dist/components/ui/toggle-group/toggle-group.stories.svelte.d.ts +27 -0
- package/dist/components/ui/tooltip/tooltip.stories.svelte +26 -0
- package/dist/components/ui/tooltip/tooltip.stories.svelte.d.ts +27 -0
- package/dist/core/fields/fieldSchemaToTs.d.ts +1 -0
- package/dist/core/fields/fieldSchemaToTs.js +133 -1
- package/dist/core/fields/layoutUtils.d.ts +17 -0
- package/dist/core/fields/layoutUtils.js +149 -0
- package/dist/core/fields/structuredToHtml.d.ts +9 -0
- package/dist/core/fields/structuredToHtml.js +161 -0
- package/dist/core/server/entries/operations/create.js +2 -1
- package/dist/core/server/entries/operations/get.js +10 -7
- package/dist/core/server/entries/operations/update.d.ts +3 -0
- package/dist/core/server/entries/operations/update.js +30 -2
- package/dist/core/server/fields/queryStructuredContent.d.ts +15 -0
- package/dist/core/server/fields/queryStructuredContent.js +65 -0
- package/dist/core/server/fields/resolveImageFields.js +51 -2
- package/dist/core/server/fields/resolveRelationFields.js +2 -2
- package/dist/core/server/fields/resolveRichtextLinks.js +80 -13
- package/dist/core/server/fields/resolveUrlFields.js +57 -6
- package/dist/core/server/fields/slugResolver.d.ts +10 -0
- package/dist/core/server/fields/slugResolver.js +34 -0
- package/dist/core/server/generator/fields.js +15 -4
- package/dist/core/server/generator/generator.js +3 -2
- package/dist/db-postgres/index.js +10 -6
- package/dist/files-local/index.js +126 -64
- package/dist/server/auth.d.ts +5 -0
- package/dist/server/auth.js +12 -1
- package/dist/sveltekit/components/structured-content.svelte +204 -0
- package/dist/sveltekit/components/structured-content.svelte.d.ts +21 -0
- package/dist/sveltekit/config.d.ts +13 -3
- package/dist/sveltekit/index.d.ts +3 -0
- package/dist/sveltekit/index.js +3 -0
- package/dist/sveltekit/server/handle.js +1 -0
- package/dist/types/config.d.ts +3 -0
- package/dist/types/entries.d.ts +3 -0
- package/dist/types/fields.d.ts +19 -2
- package/dist/types/index.d.ts +2 -0
- package/dist/types/index.js +2 -0
- package/dist/types/layout.d.ts +54 -0
- package/dist/types/layout.js +6 -0
- package/dist/types/structured-content.d.ts +63 -0
- package/dist/types/structured-content.js +1 -0
- package/dist/updates/0.1.5/index.d.ts +2 -0
- package/dist/updates/0.1.5/index.js +18 -0
- package/dist/updates/0.2.0/index.d.ts +2 -0
- package/dist/updates/0.2.0/index.js +11 -0
- package/dist/updates/0.2.2/index.d.ts +2 -0
- package/dist/updates/0.2.2/index.js +13 -0
- package/dist/updates/0.5.0/index.d.ts +2 -0
- package/dist/updates/0.5.0/index.js +14 -0
- package/dist/updates/0.5.1/index.d.ts +2 -0
- package/dist/updates/0.5.1/index.js +17 -0
- package/dist/updates/index.js +6 -1
- package/package.json +16 -9
- package/dist/admin/components/dashboard/updates-banner.svelte +0 -170
- package/dist/admin/components/dashboard/updates-banner.svelte.d.ts +0 -3
|
@@ -9,6 +9,10 @@
|
|
|
9
9
|
import { getLocalizedLabel } from '../../utils/collectionLabel.js';
|
|
10
10
|
import { useInterfaceLanguage } from '../../state/interface-language.svelte.js';
|
|
11
11
|
import type { InterfaceLanguage } from '../../../types/languages.js';
|
|
12
|
+
import AlertCircle from '@tabler/icons-svelte/icons/alert-circle';
|
|
13
|
+
import ArchiveIcon from '@tabler/icons-svelte/icons/archive';
|
|
14
|
+
import XIcon from '@tabler/icons-svelte/icons/x';
|
|
15
|
+
import Button from '../../../components/ui/button/button.svelte';
|
|
12
16
|
import { ElementSize, useDebounce } from 'runed';
|
|
13
17
|
import { defaults, superForm, type SuperForm } from 'sveltekit-superforms';
|
|
14
18
|
import { zod4, zod4Client } from 'sveltekit-superforms/adapters';
|
|
@@ -18,10 +22,12 @@
|
|
|
18
22
|
import type { UpdateEntryVersionCommandType } from '../../../core/server/entries/operations/update.js';
|
|
19
23
|
import { getRawCollectionEntryLabel } from '../../utils/entryLabel.js';
|
|
20
24
|
import type { Field } from '../../../types/fields.js';
|
|
25
|
+
import { getFieldsFromConfig, hasLayout } from '../../../core/fields/layoutUtils.js';
|
|
21
26
|
import type { ValidationErrors } from 'sveltekit-superforms';
|
|
22
27
|
import { createHybridContext } from './hybrid/hybrid-context.svelte.js';
|
|
23
28
|
import { onMount } from 'svelte';
|
|
24
29
|
import { get } from 'svelte/store';
|
|
30
|
+
import { computeTranslationStatus } from '../../utils/translationStatus.js';
|
|
25
31
|
|
|
26
32
|
const contentLanguage = getContentLanguage();
|
|
27
33
|
const remotes = getRemotes();
|
|
@@ -56,7 +62,11 @@
|
|
|
56
62
|
} else if (typeof value === 'object' && value !== null) {
|
|
57
63
|
// Nested errors - recurse
|
|
58
64
|
const nestedFields = field && 'fields' in field ? (field.fields as Field[]) : [];
|
|
59
|
-
const nested = flattenErrors(
|
|
65
|
+
const nested = flattenErrors(
|
|
66
|
+
value as ValidationErrors<Record<string, unknown>>,
|
|
67
|
+
nestedFields,
|
|
68
|
+
path
|
|
69
|
+
);
|
|
60
70
|
if (nested.length > 0) {
|
|
61
71
|
result.push(...nested.map((e) => `${label} > ${e}`));
|
|
62
72
|
}
|
|
@@ -70,31 +80,55 @@
|
|
|
70
80
|
InterfaceLanguage,
|
|
71
81
|
{
|
|
72
82
|
entryArchived: string;
|
|
83
|
+
entryRestored: string;
|
|
84
|
+
archivedBanner: string;
|
|
85
|
+
restore: string;
|
|
73
86
|
saveToast: string;
|
|
74
|
-
saveDraftToast: string;
|
|
75
87
|
publishToast: string;
|
|
76
88
|
scheduledToast: string;
|
|
89
|
+
unpublishToast: string;
|
|
77
90
|
saveFailed: string;
|
|
78
91
|
cannotPublish: string;
|
|
92
|
+
validationHint: string;
|
|
93
|
+
newerDraft: string;
|
|
94
|
+
switchToDraft: string;
|
|
95
|
+
editingDraft: string;
|
|
96
|
+
switchToPublished: string;
|
|
79
97
|
}
|
|
80
98
|
> = {
|
|
81
99
|
en: {
|
|
82
100
|
entryArchived: 'Entry archived successfully',
|
|
101
|
+
entryRestored: 'Entry restored successfully',
|
|
102
|
+
archivedBanner: 'This entry is archived. Restore it to edit.',
|
|
103
|
+
restore: 'Restore',
|
|
83
104
|
saveToast: 'Entry saved successfully',
|
|
84
|
-
saveDraftToast: 'Draft saved successfully',
|
|
85
105
|
publishToast: 'Entry published successfully',
|
|
86
106
|
scheduledToast: 'Entry scheduled successfully',
|
|
107
|
+
unpublishToast: 'Publication withdrawn',
|
|
87
108
|
saveFailed: 'Save failed',
|
|
88
|
-
cannotPublish: 'Cannot publish'
|
|
109
|
+
cannotPublish: 'Cannot publish',
|
|
110
|
+
validationHint: 'Fix the highlighted fields below to publish',
|
|
111
|
+
newerDraft: 'A newer unpublished draft exists',
|
|
112
|
+
switchToDraft: 'Switch to draft',
|
|
113
|
+
editingDraft: 'You are editing an unpublished draft',
|
|
114
|
+
switchToPublished: 'View published'
|
|
89
115
|
},
|
|
90
116
|
pl: {
|
|
91
117
|
entryArchived: 'Wpis został zarchiwizowany pomyślnie',
|
|
118
|
+
entryRestored: 'Wpis został przywrócony',
|
|
119
|
+
archivedBanner: 'Ten wpis jest zarchiwizowany. Przywróć go, żeby edytować.',
|
|
120
|
+
restore: 'Przywróć',
|
|
92
121
|
saveToast: 'Wpis został pomyślnie zapisany',
|
|
93
|
-
saveDraftToast: 'Wersja robocza została pomyślnie zapisana',
|
|
94
122
|
publishToast: 'Wpis został pomyślnie opublikowany',
|
|
95
123
|
scheduledToast: 'Wpis został zaplanowany pomyślnie',
|
|
124
|
+
unpublishToast: 'Wycofano publikację',
|
|
96
125
|
saveFailed: 'Błąd zapisu',
|
|
97
|
-
cannotPublish: 'Nie można opublikować'
|
|
126
|
+
cannotPublish: 'Nie można opublikować',
|
|
127
|
+
validationHint: 'Popraw wyróżnione pola, żeby opublikować',
|
|
128
|
+
newerDraft: 'Istnieje nowszy nieopublikowany szkic',
|
|
129
|
+
switchToDraft: 'Przejdź do szkicu',
|
|
130
|
+
editingDraft: 'Edytujesz nieopublikowany szkic',
|
|
131
|
+
switchToPublished: 'Zobacz opublikowaną'
|
|
98
132
|
}
|
|
99
133
|
};
|
|
100
134
|
|
|
@@ -105,9 +139,13 @@
|
|
|
105
139
|
|
|
106
140
|
let { entry, editingEntry }: Props = $props();
|
|
107
141
|
let { collection } = entry;
|
|
142
|
+
const isArchived = $derived(!!entry.archivedAt);
|
|
108
143
|
|
|
109
144
|
// Create form once at component level
|
|
110
|
-
const collectionSchema = generateZodSchemaFromFields(
|
|
145
|
+
const collectionSchema = generateZodSchemaFromFields(
|
|
146
|
+
getFieldsFromConfig(collection),
|
|
147
|
+
contentLanguage.all
|
|
148
|
+
);
|
|
111
149
|
const form = superForm(defaults(editingEntry.data, zod4(collectionSchema)), {
|
|
112
150
|
validators: zod4Client(collectionSchema),
|
|
113
151
|
SPA: true,
|
|
@@ -115,15 +153,29 @@
|
|
|
115
153
|
resetForm: false
|
|
116
154
|
});
|
|
117
155
|
|
|
156
|
+
let validationErrors = $state<string[]>([]);
|
|
157
|
+
|
|
118
158
|
// Autosave state
|
|
119
159
|
type SaveStatus = 'idle' | 'saving' | 'saved' | 'unsaved' | 'error';
|
|
120
160
|
let saveStatus = $state<SaveStatus>('idle');
|
|
121
|
-
let lastSavedData = $state<string>(JSON.stringify(
|
|
161
|
+
let lastSavedData = $state<string>(JSON.stringify(get(form.form)));
|
|
122
162
|
let autosaveTimer: ReturnType<typeof setTimeout> | null = null;
|
|
163
|
+
// Tracks draft version created via autosave while editing a published version
|
|
164
|
+
let savedDraftVersionId = $state<string | null>(null);
|
|
123
165
|
|
|
124
166
|
const AUTOSAVE_DELAY = 30000; // 30 seconds
|
|
125
167
|
|
|
168
|
+
// Reactive translation status — must live here where we can subscribe to form.form store
|
|
169
|
+
const formStore = form.form;
|
|
170
|
+
const collectionFields = getFieldsFromConfig(collection);
|
|
171
|
+
const translationStatus = $derived.by(() => {
|
|
172
|
+
if (contentLanguage.all.length <= 1) return null;
|
|
173
|
+
const data = $formStore;
|
|
174
|
+
return computeTranslationStatus(data, collectionFields, contentLanguage.all);
|
|
175
|
+
});
|
|
176
|
+
|
|
126
177
|
function scheduleAutosave() {
|
|
178
|
+
if (isArchived) return;
|
|
127
179
|
if (autosaveTimer) {
|
|
128
180
|
clearTimeout(autosaveTimer);
|
|
129
181
|
}
|
|
@@ -133,22 +185,26 @@
|
|
|
133
185
|
}
|
|
134
186
|
|
|
135
187
|
async function performAutosave() {
|
|
188
|
+
if (isArchived) return;
|
|
136
189
|
const currentFormData = get(form.form);
|
|
137
190
|
const currentData = JSON.stringify(currentFormData);
|
|
138
191
|
if (currentData === lastSavedData) {
|
|
139
|
-
saveStatus = 'saved';
|
|
140
192
|
return;
|
|
141
193
|
}
|
|
142
194
|
|
|
143
195
|
saveStatus = 'saving';
|
|
144
196
|
try {
|
|
145
|
-
await remotes.updateEntryVersionCommand({
|
|
197
|
+
const result = await remotes.updateEntryVersionCommand({
|
|
146
198
|
entryId: entry.id,
|
|
147
199
|
data: currentFormData,
|
|
148
200
|
type: 'draft'
|
|
149
201
|
});
|
|
150
202
|
lastSavedData = currentData;
|
|
151
203
|
saveStatus = 'saved';
|
|
204
|
+
// If we're editing the published version and saved a draft, track it for the banner
|
|
205
|
+
if (entry.publishedVersion && editingEntry.id === entry.publishedVersion.id && result?.id) {
|
|
206
|
+
savedDraftVersionId = result.id;
|
|
207
|
+
}
|
|
152
208
|
// Reset to idle after 3s
|
|
153
209
|
setTimeout(() => {
|
|
154
210
|
if (saveStatus === 'saved') saveStatus = 'idle';
|
|
@@ -158,7 +214,7 @@
|
|
|
158
214
|
}
|
|
159
215
|
}
|
|
160
216
|
|
|
161
|
-
// Track form changes for autosave
|
|
217
|
+
// Track form changes for autosave + Ctrl/Cmd+S shortcut
|
|
162
218
|
onMount(() => {
|
|
163
219
|
const unsub = form.form.subscribe((data) => {
|
|
164
220
|
const currentData = JSON.stringify(data);
|
|
@@ -167,8 +223,23 @@
|
|
|
167
223
|
scheduleAutosave();
|
|
168
224
|
}
|
|
169
225
|
});
|
|
226
|
+
|
|
227
|
+
function handleKeydown(e: KeyboardEvent) {
|
|
228
|
+
if ((e.ctrlKey || e.metaKey) && e.key === 's') {
|
|
229
|
+
e.preventDefault();
|
|
230
|
+
if (isArchived) return;
|
|
231
|
+
if (autosaveTimer) {
|
|
232
|
+
clearTimeout(autosaveTimer);
|
|
233
|
+
autosaveTimer = null;
|
|
234
|
+
}
|
|
235
|
+
performAutosave();
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
window.addEventListener('keydown', handleKeydown);
|
|
239
|
+
|
|
170
240
|
return () => {
|
|
171
241
|
unsub();
|
|
242
|
+
window.removeEventListener('keydown', handleKeydown);
|
|
172
243
|
if (autosaveTimer) clearTimeout(autosaveTimer);
|
|
173
244
|
};
|
|
174
245
|
});
|
|
@@ -179,6 +250,12 @@
|
|
|
179
250
|
goto(`/admin/collections/${collection.slug}`);
|
|
180
251
|
}
|
|
181
252
|
|
|
253
|
+
async function onRestore() {
|
|
254
|
+
await remotes.unarchiveEntryCommand(entry.id);
|
|
255
|
+
toast.success(lang[interfaceLanguage.current].entryRestored);
|
|
256
|
+
goto(window.location.pathname, { invalidateAll: true });
|
|
257
|
+
}
|
|
258
|
+
|
|
182
259
|
async function onSave(type: UpdateEntryVersionCommandType, scheduledAt?: Date) {
|
|
183
260
|
// Cancel pending autosave
|
|
184
261
|
if (autosaveTimer) {
|
|
@@ -186,24 +263,23 @@
|
|
|
186
263
|
autosaveTimer = null;
|
|
187
264
|
}
|
|
188
265
|
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
const currentFormData = get(form.form);
|
|
266
|
+
// Unpublish — skip validation, call remote directly
|
|
267
|
+
if (type === 'cancel-published') {
|
|
192
268
|
saveStatus = 'saving';
|
|
193
269
|
try {
|
|
194
270
|
await remotes.updateEntryVersionCommand({
|
|
195
271
|
entryId: entry.id,
|
|
196
|
-
data:
|
|
197
|
-
type
|
|
272
|
+
data: get(form.form),
|
|
273
|
+
type
|
|
198
274
|
});
|
|
199
|
-
lastSavedData = JSON.stringify(currentFormData);
|
|
200
275
|
saveStatus = 'saved';
|
|
201
|
-
toast.success(lang[interfaceLanguage.current].
|
|
276
|
+
toast.success(lang[interfaceLanguage.current].unpublishToast);
|
|
277
|
+
|
|
202
278
|
setTimeout(() => {
|
|
203
279
|
if (saveStatus === 'saved') saveStatus = 'idle';
|
|
204
280
|
}, 3000);
|
|
205
281
|
} catch (e) {
|
|
206
|
-
console.error('
|
|
282
|
+
console.error('Unpublish error:', e);
|
|
207
283
|
saveStatus = 'error';
|
|
208
284
|
toast.error(lang[interfaceLanguage.current].saveFailed, {
|
|
209
285
|
description: e instanceof Error ? e.message : undefined
|
|
@@ -213,9 +289,10 @@
|
|
|
213
289
|
}
|
|
214
290
|
|
|
215
291
|
// Publish requires validation
|
|
216
|
-
const validatedForm = await form.validateForm();
|
|
292
|
+
const validatedForm = await form.validateForm({ update: true });
|
|
217
293
|
|
|
218
294
|
if (validatedForm.valid) {
|
|
295
|
+
validationErrors = [];
|
|
219
296
|
saveStatus = 'saving';
|
|
220
297
|
try {
|
|
221
298
|
await remotes.updateEntryVersionCommand({
|
|
@@ -245,14 +322,16 @@
|
|
|
245
322
|
});
|
|
246
323
|
}
|
|
247
324
|
} else {
|
|
248
|
-
const errors = flattenErrors(validatedForm.errors, collection
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
}
|
|
325
|
+
const errors = flattenErrors(validatedForm.errors, getFieldsFromConfig(collection));
|
|
326
|
+
validationErrors = errors;
|
|
327
|
+
|
|
328
|
+
// Scroll to first errored field
|
|
329
|
+
const firstErrorKey = Object.keys(validatedForm.errors).find(
|
|
330
|
+
(k) => k !== '_errors'
|
|
255
331
|
);
|
|
332
|
+
if (firstErrorKey) {
|
|
333
|
+
scrollToIssue(firstErrorKey);
|
|
334
|
+
}
|
|
256
335
|
}
|
|
257
336
|
}
|
|
258
337
|
|
|
@@ -292,7 +371,7 @@
|
|
|
292
371
|
|
|
293
372
|
type SizePreset = keyof typeof sizePresets;
|
|
294
373
|
|
|
295
|
-
let sizePreset: SizePreset = $state('
|
|
374
|
+
let sizePreset: SizePreset = $state('desktop');
|
|
296
375
|
|
|
297
376
|
function getOriginFromUrl(url: string): string {
|
|
298
377
|
try {
|
|
@@ -302,7 +381,9 @@
|
|
|
302
381
|
}
|
|
303
382
|
}
|
|
304
383
|
|
|
305
|
-
const previewOrigin = collection.previewUrl
|
|
384
|
+
const previewOrigin = collection.previewUrl
|
|
385
|
+
? getOriginFromUrl(collection.previewUrl)
|
|
386
|
+
: window.location.origin;
|
|
306
387
|
|
|
307
388
|
const updatePreview = useDebounce(
|
|
308
389
|
async (window: Window, form: SuperForm<Record<string, unknown>>) => {
|
|
@@ -420,46 +501,176 @@
|
|
|
420
501
|
}
|
|
421
502
|
}
|
|
422
503
|
});
|
|
504
|
+
|
|
505
|
+
// Banner: viewing published version + a separate draft exists
|
|
506
|
+
const showDraftBanner = $derived(
|
|
507
|
+
entry.publishedVersion != null &&
|
|
508
|
+
editingEntry.id === entry.publishedVersion.id &&
|
|
509
|
+
entry.draftVersion != null &&
|
|
510
|
+
entry.draftVersion.id !== entry.publishedVersion.id &&
|
|
511
|
+
entry.draftVersion.createdAt > entry.publishedVersion.createdAt
|
|
512
|
+
);
|
|
513
|
+
|
|
514
|
+
// Banner: viewing draft + a published version exists
|
|
515
|
+
const showPublishedBanner = $derived(
|
|
516
|
+
entry.publishedVersion != null && editingEntry.id !== entry.publishedVersion.id
|
|
517
|
+
);
|
|
518
|
+
|
|
519
|
+
const draftVersionId = $derived(entry.draftVersion?.id ?? savedDraftVersionId);
|
|
520
|
+
|
|
521
|
+
const scrollToIssue = (fieldSlug: string) => {
|
|
522
|
+
const fieldEl = document.querySelector(`[data-field-path="${fieldSlug}"]`);
|
|
523
|
+
if (fieldEl) {
|
|
524
|
+
fieldEl.scrollIntoView({ behavior: 'smooth', block: 'center' });
|
|
525
|
+
const proseMirror = fieldEl.querySelector('.ProseMirror') as HTMLElement | null;
|
|
526
|
+
if (proseMirror) {
|
|
527
|
+
proseMirror.focus();
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
};
|
|
531
|
+
|
|
532
|
+
// Auto-dismiss validation banner when user starts editing
|
|
533
|
+
onMount(() => {
|
|
534
|
+
const unsub = form.tainted.subscribe((tainted) => {
|
|
535
|
+
if (tainted && validationErrors.length > 0) {
|
|
536
|
+
validationErrors = [];
|
|
537
|
+
}
|
|
538
|
+
});
|
|
539
|
+
return () => unsub();
|
|
540
|
+
});
|
|
541
|
+
|
|
542
|
+
const t = $derived(lang[interfaceLanguage.current]);
|
|
423
543
|
</script>
|
|
424
544
|
|
|
425
|
-
<EntryHeader
|
|
545
|
+
<EntryHeader
|
|
546
|
+
{entry}
|
|
547
|
+
version={editingEntry}
|
|
548
|
+
{onSave}
|
|
549
|
+
onSaveDraft={performAutosave}
|
|
550
|
+
{onArchive}
|
|
551
|
+
{saveStatus}
|
|
552
|
+
{isArchived}
|
|
553
|
+
fields={getFieldsFromConfig(collection)}
|
|
554
|
+
getFormData={() => get(form.form)}
|
|
555
|
+
onScrollToIssue={scrollToIssue}
|
|
556
|
+
{translationStatus}
|
|
557
|
+
/>
|
|
558
|
+
|
|
559
|
+
{#if validationErrors.length > 0}
|
|
560
|
+
<div
|
|
561
|
+
role="alert"
|
|
562
|
+
aria-live="assertive"
|
|
563
|
+
class="flex items-start gap-3 border-b border-[var(--error)]/20 bg-[#FDF0F0] px-6 py-3 text-sm text-[var(--error)]"
|
|
564
|
+
>
|
|
565
|
+
<AlertCircle class="mt-0.5 size-4 shrink-0" />
|
|
566
|
+
<div class="min-w-0 flex-1">
|
|
567
|
+
<p class="font-semibold">{t.cannotPublish}</p>
|
|
568
|
+
<p class="text-xs opacity-80">{t.validationHint}</p>
|
|
569
|
+
<ul class="mt-1 text-xs">
|
|
570
|
+
{#each validationErrors.slice(0, 5) as error}
|
|
571
|
+
<li>— {error}</li>
|
|
572
|
+
{/each}
|
|
573
|
+
</ul>
|
|
574
|
+
</div>
|
|
575
|
+
<button
|
|
576
|
+
type="button"
|
|
577
|
+
onclick={() => (validationErrors = [])}
|
|
578
|
+
class="shrink-0 rounded p-0.5 opacity-60 hover:opacity-100"
|
|
579
|
+
aria-label="Zamknij"
|
|
580
|
+
>
|
|
581
|
+
<XIcon class="size-4" />
|
|
582
|
+
</button>
|
|
583
|
+
</div>
|
|
584
|
+
{/if}
|
|
585
|
+
|
|
586
|
+
{#if isArchived}
|
|
587
|
+
<div
|
|
588
|
+
role="alert"
|
|
589
|
+
class="flex items-center justify-between gap-3 border-b border-[var(--warning)]/20 bg-[#FDF6EC] px-6 py-3 text-sm"
|
|
590
|
+
>
|
|
591
|
+
<div class="flex items-center gap-2 text-[var(--warning)]">
|
|
592
|
+
<ArchiveIcon class="size-4 shrink-0" />
|
|
593
|
+
<span>{t.archivedBanner}</span>
|
|
594
|
+
</div>
|
|
595
|
+
<Button size="sm" onclick={onRestore}>{t.restore}</Button>
|
|
596
|
+
</div>
|
|
597
|
+
{/if}
|
|
598
|
+
|
|
599
|
+
{#if showDraftBanner}
|
|
600
|
+
<div
|
|
601
|
+
class="flex items-center justify-between border-b bg-[var(--lavender-lighter)] px-6 py-2 text-sm"
|
|
602
|
+
>
|
|
603
|
+
<span class="text-[var(--text-secondary)]">{lang[interfaceLanguage.current].newerDraft}</span>
|
|
604
|
+
<button
|
|
605
|
+
type="button"
|
|
606
|
+
class="font-semibold text-[var(--primary)] hover:underline"
|
|
607
|
+
onclick={() => goto(`?version=${draftVersionId}`)}
|
|
608
|
+
>
|
|
609
|
+
{lang[interfaceLanguage.current].switchToDraft}
|
|
610
|
+
</button>
|
|
611
|
+
</div>
|
|
612
|
+
{:else if showPublishedBanner}
|
|
613
|
+
<div
|
|
614
|
+
class="flex items-center justify-between border-b bg-[var(--lavender-lighter)] px-6 py-2 text-sm"
|
|
615
|
+
>
|
|
616
|
+
<span class="text-[var(--text-secondary)]">{lang[interfaceLanguage.current].editingDraft}</span>
|
|
617
|
+
<button
|
|
618
|
+
type="button"
|
|
619
|
+
class="font-semibold text-[var(--primary)] hover:underline"
|
|
620
|
+
onclick={() => goto(`?version=${entry.publishedVersion!.id}`)}
|
|
621
|
+
>
|
|
622
|
+
{lang[interfaceLanguage.current].switchToPublished}
|
|
623
|
+
</button>
|
|
624
|
+
</div>
|
|
625
|
+
{/if}
|
|
426
626
|
|
|
627
|
+
<div class={isArchived ? 'pointer-events-none opacity-60' : ''}>
|
|
427
628
|
{#if hybridContext.mode === 'hybrid' && collection.previewUrl}
|
|
428
|
-
<div class="flex min-h-0 flex-1 overflow-hidden">
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
{
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
629
|
+
<div class="flex min-h-0 flex-1 overflow-hidden">
|
|
630
|
+
{#await import('./hybrid/hybrid-layout.svelte')}
|
|
631
|
+
<div class="bg-accent h-full animate-pulse rounded-md"></div>
|
|
632
|
+
{:then { default: HybridLayout }}
|
|
633
|
+
<HybridLayout>
|
|
634
|
+
{#snippet preview()}
|
|
635
|
+
{#await import('./hybrid/hybrid-preview.svelte')}
|
|
636
|
+
<div class="bg-accent h-full animate-pulse rounded-md"></div>
|
|
637
|
+
{:then { default: HybridPreview }}
|
|
638
|
+
<HybridPreview
|
|
639
|
+
{collection}
|
|
640
|
+
{editingEntry}
|
|
641
|
+
bind:previewIframe
|
|
642
|
+
bind:sizePreset
|
|
643
|
+
{size}
|
|
644
|
+
bind:el
|
|
645
|
+
/>
|
|
646
|
+
{:catch}
|
|
647
|
+
<p class="text-destructive p-4 text-sm">Failed to load preview</p>
|
|
648
|
+
{/await}
|
|
649
|
+
{/snippet}
|
|
650
|
+
{#snippet formPanel()}
|
|
651
|
+
<EntryForm
|
|
652
|
+
{form}
|
|
653
|
+
{entry}
|
|
654
|
+
focusedPath={hybridContext.focusedPath}
|
|
655
|
+
onPathSelect={(path) => (hybridContext.focusedPath = path)}
|
|
656
|
+
/>
|
|
657
|
+
{/snippet}
|
|
658
|
+
</HybridLayout>
|
|
659
|
+
{:catch}
|
|
660
|
+
<p class="text-destructive p-4 text-sm">Failed to load layout</p>
|
|
661
|
+
{/await}
|
|
662
|
+
</div>
|
|
663
|
+
{:else if hasLayout(collection)}
|
|
664
|
+
<div class="overflow-y-auto" style="scroll-padding-top: 48px;">
|
|
665
|
+
<EntryForm {form} {entry} />
|
|
666
|
+
</div>
|
|
455
667
|
{:else}
|
|
456
|
-
<div class="flex items-stretch justify-center">
|
|
668
|
+
<div class="flex items-stretch justify-center" style="scroll-padding-top: 48px;">
|
|
457
669
|
<div class="max-w-2xl grow p-4 lg:p-6">
|
|
458
|
-
<div
|
|
459
|
-
class="glass-panel rounded-2xl border-slate-200/50 bg-white/80 p-4 backdrop-blur-xl dark:border-white/10 dark:bg-slate-900/60 lg:p-6"
|
|
460
|
-
>
|
|
670
|
+
<div class="bg-card rounded-2xl border p-4 shadow-sm lg:p-6">
|
|
461
671
|
<EntryForm {form} {entry} />
|
|
462
672
|
</div>
|
|
463
673
|
</div>
|
|
464
674
|
</div>
|
|
465
675
|
{/if}
|
|
676
|
+
</div>
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import type { Field } from '../../../../types/fields.js';
|
|
2
|
+
export type A11yIssueType = 'warning' | 'success';
|
|
3
|
+
export interface A11yIssue {
|
|
4
|
+
type: A11yIssueType;
|
|
5
|
+
message: string;
|
|
6
|
+
fieldSlug?: string;
|
|
7
|
+
firstNodePos?: number;
|
|
8
|
+
}
|
|
9
|
+
/** Get heading issue positions for inline decoration in the editor.
|
|
10
|
+
* Works with TipTap JSON doc format (with `type`, `attrs.level`, `content`).
|
|
11
|
+
* Returns issues for: first heading not H2, H3 appearing before any H2. */
|
|
12
|
+
export interface HeadingIssue {
|
|
13
|
+
pos: number;
|
|
14
|
+
message: string;
|
|
15
|
+
}
|
|
16
|
+
export declare function getHeadingIssuePositions(doc: {
|
|
17
|
+
type: string;
|
|
18
|
+
content?: any[];
|
|
19
|
+
}): HeadingIssue[];
|
|
20
|
+
/** Find position of first image without alt in TipTap JSON doc. */
|
|
21
|
+
export declare function findFirstImageWithoutAlt(doc: {
|
|
22
|
+
type: string;
|
|
23
|
+
content?: any[];
|
|
24
|
+
}): number | null;
|
|
25
|
+
/** Find position of first heading hierarchy issue in TipTap JSON doc. */
|
|
26
|
+
export declare function findFirstHeadingIssue(doc: {
|
|
27
|
+
type: string;
|
|
28
|
+
content?: any[];
|
|
29
|
+
}): number | null;
|
|
30
|
+
/** Find position of first generic link in TipTap JSON doc. */
|
|
31
|
+
export declare function findFirstGenericLink(doc: {
|
|
32
|
+
type: string;
|
|
33
|
+
content?: any[];
|
|
34
|
+
}): number | null;
|
|
35
|
+
export interface A11yLang {
|
|
36
|
+
imagesWithoutAlt: (count: number) => string;
|
|
37
|
+
headingsOk: string;
|
|
38
|
+
headingsSkipped: string;
|
|
39
|
+
genericLinks: (count: number) => string;
|
|
40
|
+
allImagesHaveAlt: string;
|
|
41
|
+
noGenericLinks: string;
|
|
42
|
+
}
|
|
43
|
+
export declare const a11yLangPl: A11yLang;
|
|
44
|
+
export declare const a11yLangEn: A11yLang;
|
|
45
|
+
/** Run a11y validation on entry data and return issues list.
|
|
46
|
+
* When `languages` is provided, validates each language separately with prefix tags. */
|
|
47
|
+
export declare function validateA11y(data: Record<string, unknown>, fields: Field[], lang?: A11yLang, languages?: string[]): A11yIssue[];
|