includio-cms 0.1.3 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +76 -0
- package/ROADMAP.md +23 -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 +55 -41
- 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 +83 -0
- package/dist/admin/client/collection/bulk-actions-bar.svelte.d.ts +9 -0
- package/dist/admin/client/collection/collection-entries.svelte +255 -256
- 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 +60 -0
- package/dist/admin/client/collection/row-actions.svelte.d.ts +9 -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 +96 -37
- package/dist/admin/client/entry/entry-header.svelte.d.ts +5 -0
- package/dist/admin/client/entry/entry.svelte +171 -60
- package/dist/admin/client/entry/header/a11y-validator.d.ts +46 -0
- package/dist/admin/client/entry/header/a11y-validator.js +311 -0
- package/dist/admin/client/entry/header/publish-panel.svelte +373 -131
- 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 +314 -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/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/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 +13 -1
- 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 +31 -0
- package/dist/admin/components/layout/nav-footer.svelte.d.ts +18 -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 +8 -0
- package/dist/admin/remote/entry.remote.js +53 -4
- 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/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/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 +8 -6
- 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/files-local/index.js +126 -64
- package/dist/paraglide/.prettierignore +3 -0
- package/dist/paraglide/messages/_index.d.ts +36 -0
- package/dist/paraglide/messages/_index.js +72 -0
- package/dist/paraglide/messages/en.d.ts +5 -0
- package/dist/paraglide/messages/en.js +14 -0
- package/dist/paraglide/messages/pl.d.ts +5 -0
- package/dist/paraglide/messages/pl.js +14 -0
- package/dist/paraglide/messages.d.ts +2 -0
- package/dist/paraglide/messages.js +4 -0
- package/dist/paraglide/registry.d.ts +21 -0
- package/dist/paraglide/registry.js +31 -0
- package/dist/paraglide/runtime.d.ts +583 -0
- package/dist/paraglide/runtime.js +1402 -0
- package/dist/paraglide/server.d.ts +67 -0
- package/dist/paraglide/server.js +175 -0
- 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/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.4/index.d.ts +2 -0
- package/dist/updates/0.1.4/index.js +11 -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/index.js +6 -1
- package/package.json +17 -10
|
@@ -1,16 +1,20 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import { getContentLanguage } from '../../state/content-language.svelte.js';
|
|
3
|
-
import type { DbEntryVersion,
|
|
4
|
-
import * as ToggleGroup from '../../../components/ui/toggle-group/index.js';
|
|
3
|
+
import type { DbEntryVersion, RawEntry } from '../../../types/entries.js';
|
|
5
4
|
import Button from '../../../components/ui/button/button.svelte';
|
|
6
5
|
import { useInterfaceLanguage } from '../../state/interface-language.svelte.js';
|
|
7
6
|
import type { InterfaceLanguage } from '../../../types/languages.js';
|
|
8
7
|
import StatusBadge from './header/status-badge.svelte';
|
|
9
8
|
import SaveIndicator from './header/save-indicator.svelte';
|
|
10
9
|
import type { UpdateEntryVersionCommandType } from '../../../core/server/entries/operations/update.js';
|
|
10
|
+
import type { Field } from '../../../types/fields.js';
|
|
11
11
|
import LayoutSidebar from '@tabler/icons-svelte/icons/layout-sidebar';
|
|
12
|
+
import SendIcon from '@tabler/icons-svelte/icons/send';
|
|
13
|
+
import ChevronDownIcon from '@tabler/icons-svelte/icons/chevron-down';
|
|
14
|
+
import * as DropdownMenu from '../../../components/ui/dropdown-menu/index.js';
|
|
12
15
|
import { hasHybridContext, getHybridContext } from './hybrid/hybrid-context.svelte.js';
|
|
13
16
|
import { getEntryStatus } from './utils.js';
|
|
17
|
+
import { onMount } from 'svelte';
|
|
14
18
|
|
|
15
19
|
const contentLanguage = getContentLanguage();
|
|
16
20
|
const interfaceLanguage = useInterfaceLanguage();
|
|
@@ -26,7 +30,7 @@
|
|
|
26
30
|
en: {
|
|
27
31
|
publish: 'Publish',
|
|
28
32
|
update: 'Update',
|
|
29
|
-
saveDraft: 'Save
|
|
33
|
+
saveDraft: 'Save draft'
|
|
30
34
|
},
|
|
31
35
|
pl: {
|
|
32
36
|
publish: 'Publikuj',
|
|
@@ -40,12 +44,26 @@
|
|
|
40
44
|
type Props = {
|
|
41
45
|
entry: RawEntry;
|
|
42
46
|
version: DbEntryVersion;
|
|
47
|
+
fields?: Field[];
|
|
48
|
+
getFormData?: () => Record<string, unknown>;
|
|
43
49
|
onSave: (type: UpdateEntryVersionCommandType, scheduledAt?: Date) => void;
|
|
50
|
+
onSaveDraft: () => void;
|
|
44
51
|
onArchive: () => void;
|
|
45
52
|
saveStatus?: SaveStatus;
|
|
53
|
+
onScrollToIssue?: (fieldSlug: string, nodePos: number) => void;
|
|
46
54
|
};
|
|
47
55
|
|
|
48
|
-
let {
|
|
56
|
+
let {
|
|
57
|
+
entry,
|
|
58
|
+
onSave,
|
|
59
|
+
onSaveDraft,
|
|
60
|
+
onArchive,
|
|
61
|
+
version,
|
|
62
|
+
fields = [],
|
|
63
|
+
getFormData,
|
|
64
|
+
saveStatus = 'idle',
|
|
65
|
+
onScrollToIssue
|
|
66
|
+
}: Props = $props();
|
|
49
67
|
let { collection } = entry;
|
|
50
68
|
|
|
51
69
|
const hybridContext = hasHybridContext() ? getHybridContext() : null;
|
|
@@ -62,52 +80,93 @@
|
|
|
62
80
|
return t.publish;
|
|
63
81
|
}
|
|
64
82
|
});
|
|
83
|
+
|
|
84
|
+
let isMac = $state(false);
|
|
85
|
+
onMount(() => {
|
|
86
|
+
isMac = /Mac|iPhone|iPad|iPod/.test(navigator.platform);
|
|
87
|
+
});
|
|
88
|
+
const shortcutLabel = $derived(isMac ? '⌘S' : 'Ctrl+S');
|
|
65
89
|
</script>
|
|
66
90
|
|
|
67
91
|
<div
|
|
68
|
-
class="sticky top-0 z-50 flex items-center justify-between gap-4 border-b
|
|
92
|
+
class="bg-background/60 sticky top-0 z-50 flex h-12 shrink-0 items-center justify-between gap-4 border-b px-6 backdrop-blur-xl"
|
|
69
93
|
>
|
|
70
|
-
|
|
94
|
+
<!-- Left: Status + Save indicator -->
|
|
95
|
+
<div class="flex items-center gap-2.5">
|
|
71
96
|
<StatusBadge {entry} {version} />
|
|
72
97
|
<SaveIndicator status={saveStatus} />
|
|
73
98
|
</div>
|
|
74
99
|
|
|
75
|
-
|
|
100
|
+
<!-- Right: grouped actions -->
|
|
101
|
+
<div class="flex items-center gap-1.5">
|
|
102
|
+
<!-- Language switcher -->
|
|
76
103
|
{#if contentLanguage.all.length > 1}
|
|
77
|
-
<
|
|
78
|
-
size="sm"
|
|
79
|
-
type="single"
|
|
80
|
-
variant="outline"
|
|
81
|
-
onValueChange={(val) => {
|
|
82
|
-
if (val) {
|
|
83
|
-
contentLanguage.current = val;
|
|
84
|
-
}
|
|
85
|
-
}}
|
|
86
|
-
value={contentLanguage.current}
|
|
87
|
-
>
|
|
104
|
+
<div class="border-border bg-muted inline-flex overflow-hidden rounded-lg border">
|
|
88
105
|
{#each contentLanguage.all as lang}
|
|
89
|
-
<
|
|
106
|
+
<button
|
|
107
|
+
type="button"
|
|
108
|
+
role="tab"
|
|
109
|
+
aria-selected={lang === contentLanguage.current}
|
|
110
|
+
class="px-2.5 py-1 text-xs font-semibold transition-colors {lang ===
|
|
111
|
+
contentLanguage.current
|
|
112
|
+
? 'text-primary bg-white shadow-sm'
|
|
113
|
+
: 'text-muted-foreground hover:text-foreground bg-transparent'}"
|
|
114
|
+
onclick={() => (contentLanguage.current = lang)}
|
|
115
|
+
>
|
|
90
116
|
{lang.toUpperCase()}
|
|
91
|
-
</
|
|
117
|
+
</button>
|
|
92
118
|
{/each}
|
|
93
|
-
</
|
|
94
|
-
{/if}
|
|
119
|
+
</div>
|
|
95
120
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
>
|
|
99
|
-
|
|
100
|
-
<Button
|
|
101
|
-
size="sm"
|
|
102
|
-
type="button"
|
|
103
|
-
variant="gradient"
|
|
104
|
-
onclick={() => onSave('published-now')}
|
|
105
|
-
>
|
|
106
|
-
{primaryButtonLabel}
|
|
107
|
-
</Button>
|
|
121
|
+
<div class="bg-border mx-1 h-5 w-px shrink-0"></div>
|
|
122
|
+
{/if}
|
|
108
123
|
|
|
124
|
+
<!-- Split button: Publish + Save Draft -->
|
|
125
|
+
<div class="inline-flex items-stretch rounded-lg shadow-[0_1px_3px_rgba(91,74,158,0.3)]">
|
|
126
|
+
<button
|
|
127
|
+
type="button"
|
|
128
|
+
class="bg-primary text-primary-foreground hover:bg-primary/90 inline-flex items-center gap-1.5 rounded-l-lg px-4 py-1.5 text-[13px] font-semibold transition-colors"
|
|
129
|
+
onclick={() => onSave('published-now')}
|
|
130
|
+
>
|
|
131
|
+
<SendIcon class="size-3.5" />
|
|
132
|
+
{primaryButtonLabel}
|
|
133
|
+
</button>
|
|
134
|
+
|
|
135
|
+
<DropdownMenu.Root>
|
|
136
|
+
<DropdownMenu.Trigger>
|
|
137
|
+
{#snippet child({ props })}
|
|
138
|
+
<button
|
|
139
|
+
{...props}
|
|
140
|
+
type="button"
|
|
141
|
+
class="bg-primary text-primary-foreground hover:bg-primary/90 inline-flex items-center rounded-r-lg border-l border-white/20 px-1.5 py-1.5 transition-colors"
|
|
142
|
+
aria-label={lang[interfaceLanguage.current].saveDraft}
|
|
143
|
+
>
|
|
144
|
+
<ChevronDownIcon class="size-3.5" />
|
|
145
|
+
</button>
|
|
146
|
+
{/snippet}
|
|
147
|
+
</DropdownMenu.Trigger>
|
|
148
|
+
<DropdownMenu.Content align="end" class="w-48">
|
|
149
|
+
<DropdownMenu.Item onclick={onSaveDraft}>
|
|
150
|
+
{lang[interfaceLanguage.current].saveDraft}
|
|
151
|
+
<DropdownMenu.Shortcut>{shortcutLabel}</DropdownMenu.Shortcut>
|
|
152
|
+
</DropdownMenu.Item>
|
|
153
|
+
</DropdownMenu.Content>
|
|
154
|
+
</DropdownMenu.Root>
|
|
155
|
+
</div>
|
|
156
|
+
|
|
157
|
+
<div class="bg-border mx-1 h-5 w-px shrink-0"></div>
|
|
158
|
+
|
|
159
|
+
<!-- Panel triggers + Hybrid toggle -->
|
|
109
160
|
{#await import('./header/publish-panel.svelte') then { default: PublishPanel }}
|
|
110
|
-
<PublishPanel
|
|
161
|
+
<PublishPanel
|
|
162
|
+
{entry}
|
|
163
|
+
{version}
|
|
164
|
+
{fields}
|
|
165
|
+
{getFormData}
|
|
166
|
+
{onSave}
|
|
167
|
+
{onArchive}
|
|
168
|
+
{onScrollToIssue}
|
|
169
|
+
/>
|
|
111
170
|
{/await}
|
|
112
171
|
|
|
113
172
|
{#await import('./header/version-history-sheet.svelte') then { default: VersionHistorySheet }}
|
|
@@ -116,14 +175,14 @@
|
|
|
116
175
|
|
|
117
176
|
{#if hybridContext?.enabled}
|
|
118
177
|
<Button
|
|
119
|
-
variant=
|
|
178
|
+
variant="ghost"
|
|
120
179
|
size="icon"
|
|
180
|
+
class={hybridContext.mode === 'hybrid' ? 'text-primary bg-[var(--lavender-lighter)]' : ''}
|
|
121
181
|
onclick={() => hybridContext.toggle()}
|
|
122
182
|
title="Hybrid Editor"
|
|
123
183
|
>
|
|
124
184
|
<LayoutSidebar class="size-4" />
|
|
125
185
|
</Button>
|
|
126
186
|
{/if}
|
|
127
|
-
|
|
128
187
|
</div>
|
|
129
188
|
</div>
|
|
@@ -1,12 +1,17 @@
|
|
|
1
1
|
import type { DbEntryVersion, RawEntry } from '../../../types/entries.js';
|
|
2
2
|
import type { UpdateEntryVersionCommandType } from '../../../core/server/entries/operations/update.js';
|
|
3
|
+
import type { Field } from '../../../types/fields.js';
|
|
3
4
|
type SaveStatus = 'idle' | 'saving' | 'saved' | 'unsaved' | 'error';
|
|
4
5
|
type Props = {
|
|
5
6
|
entry: RawEntry;
|
|
6
7
|
version: DbEntryVersion;
|
|
8
|
+
fields?: Field[];
|
|
9
|
+
getFormData?: () => Record<string, unknown>;
|
|
7
10
|
onSave: (type: UpdateEntryVersionCommandType, scheduledAt?: Date) => void;
|
|
11
|
+
onSaveDraft: () => void;
|
|
8
12
|
onArchive: () => void;
|
|
9
13
|
saveStatus?: SaveStatus;
|
|
14
|
+
onScrollToIssue?: (fieldSlug: string, nodePos: number) => void;
|
|
10
15
|
};
|
|
11
16
|
declare const EntryHeader: import("svelte").Component<Props, {}, "">;
|
|
12
17
|
type EntryHeader = ReturnType<typeof EntryHeader>;
|
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
import type { UpdateEntryVersionCommandType } from '../../../core/server/entries/operations/update.js';
|
|
19
19
|
import { getRawCollectionEntryLabel } from '../../utils/entryLabel.js';
|
|
20
20
|
import type { Field } from '../../../types/fields.js';
|
|
21
|
+
import { getFieldsFromConfig, hasLayout } from '../../../core/fields/layoutUtils.js';
|
|
21
22
|
import type { ValidationErrors } from 'sveltekit-superforms';
|
|
22
23
|
import { createHybridContext } from './hybrid/hybrid-context.svelte.js';
|
|
23
24
|
import { onMount } from 'svelte';
|
|
@@ -56,7 +57,11 @@
|
|
|
56
57
|
} else if (typeof value === 'object' && value !== null) {
|
|
57
58
|
// Nested errors - recurse
|
|
58
59
|
const nestedFields = field && 'fields' in field ? (field.fields as Field[]) : [];
|
|
59
|
-
const nested = flattenErrors(
|
|
60
|
+
const nested = flattenErrors(
|
|
61
|
+
value as ValidationErrors<Record<string, unknown>>,
|
|
62
|
+
nestedFields,
|
|
63
|
+
path
|
|
64
|
+
);
|
|
60
65
|
if (nested.length > 0) {
|
|
61
66
|
result.push(...nested.map((e) => `${label} > ${e}`));
|
|
62
67
|
}
|
|
@@ -71,30 +76,42 @@
|
|
|
71
76
|
{
|
|
72
77
|
entryArchived: string;
|
|
73
78
|
saveToast: string;
|
|
74
|
-
saveDraftToast: string;
|
|
75
79
|
publishToast: string;
|
|
76
80
|
scheduledToast: string;
|
|
81
|
+
unpublishToast: string;
|
|
77
82
|
saveFailed: string;
|
|
78
83
|
cannotPublish: string;
|
|
84
|
+
newerDraft: string;
|
|
85
|
+
switchToDraft: string;
|
|
86
|
+
editingDraft: string;
|
|
87
|
+
switchToPublished: string;
|
|
79
88
|
}
|
|
80
89
|
> = {
|
|
81
90
|
en: {
|
|
82
91
|
entryArchived: 'Entry archived successfully',
|
|
83
92
|
saveToast: 'Entry saved successfully',
|
|
84
|
-
saveDraftToast: 'Draft saved successfully',
|
|
85
93
|
publishToast: 'Entry published successfully',
|
|
86
94
|
scheduledToast: 'Entry scheduled successfully',
|
|
95
|
+
unpublishToast: 'Publication withdrawn',
|
|
87
96
|
saveFailed: 'Save failed',
|
|
88
|
-
cannotPublish: 'Cannot publish'
|
|
97
|
+
cannotPublish: 'Cannot publish',
|
|
98
|
+
newerDraft: 'A newer unpublished draft exists',
|
|
99
|
+
switchToDraft: 'Switch to draft',
|
|
100
|
+
editingDraft: 'You are editing an unpublished draft',
|
|
101
|
+
switchToPublished: 'View published'
|
|
89
102
|
},
|
|
90
103
|
pl: {
|
|
91
104
|
entryArchived: 'Wpis został zarchiwizowany pomyślnie',
|
|
92
105
|
saveToast: 'Wpis został pomyślnie zapisany',
|
|
93
|
-
saveDraftToast: 'Wersja robocza została pomyślnie zapisana',
|
|
94
106
|
publishToast: 'Wpis został pomyślnie opublikowany',
|
|
95
107
|
scheduledToast: 'Wpis został zaplanowany pomyślnie',
|
|
108
|
+
unpublishToast: 'Wycofano publikację',
|
|
96
109
|
saveFailed: 'Błąd zapisu',
|
|
97
|
-
cannotPublish: 'Nie można opublikować'
|
|
110
|
+
cannotPublish: 'Nie można opublikować',
|
|
111
|
+
newerDraft: 'Istnieje nowszy nieopublikowany szkic',
|
|
112
|
+
switchToDraft: 'Przejdź do szkicu',
|
|
113
|
+
editingDraft: 'Edytujesz nieopublikowany szkic',
|
|
114
|
+
switchToPublished: 'Zobacz opublikowaną'
|
|
98
115
|
}
|
|
99
116
|
};
|
|
100
117
|
|
|
@@ -107,7 +124,10 @@
|
|
|
107
124
|
let { collection } = entry;
|
|
108
125
|
|
|
109
126
|
// Create form once at component level
|
|
110
|
-
const collectionSchema = generateZodSchemaFromFields(
|
|
127
|
+
const collectionSchema = generateZodSchemaFromFields(
|
|
128
|
+
getFieldsFromConfig(collection),
|
|
129
|
+
contentLanguage.all
|
|
130
|
+
);
|
|
111
131
|
const form = superForm(defaults(editingEntry.data, zod4(collectionSchema)), {
|
|
112
132
|
validators: zod4Client(collectionSchema),
|
|
113
133
|
SPA: true,
|
|
@@ -120,6 +140,8 @@
|
|
|
120
140
|
let saveStatus = $state<SaveStatus>('idle');
|
|
121
141
|
let lastSavedData = $state<string>(JSON.stringify(editingEntry.data));
|
|
122
142
|
let autosaveTimer: ReturnType<typeof setTimeout> | null = null;
|
|
143
|
+
// Tracks draft version created via autosave while editing a published version
|
|
144
|
+
let savedDraftVersionId = $state<string | null>(null);
|
|
123
145
|
|
|
124
146
|
const AUTOSAVE_DELAY = 30000; // 30 seconds
|
|
125
147
|
|
|
@@ -136,19 +158,22 @@
|
|
|
136
158
|
const currentFormData = get(form.form);
|
|
137
159
|
const currentData = JSON.stringify(currentFormData);
|
|
138
160
|
if (currentData === lastSavedData) {
|
|
139
|
-
saveStatus = 'saved';
|
|
140
161
|
return;
|
|
141
162
|
}
|
|
142
163
|
|
|
143
164
|
saveStatus = 'saving';
|
|
144
165
|
try {
|
|
145
|
-
await remotes.updateEntryVersionCommand({
|
|
166
|
+
const result = await remotes.updateEntryVersionCommand({
|
|
146
167
|
entryId: entry.id,
|
|
147
168
|
data: currentFormData,
|
|
148
169
|
type: 'draft'
|
|
149
170
|
});
|
|
150
171
|
lastSavedData = currentData;
|
|
151
172
|
saveStatus = 'saved';
|
|
173
|
+
// If we're editing the published version and saved a draft, track it for the banner
|
|
174
|
+
if (entry.publishedVersion && editingEntry.id === entry.publishedVersion.id && result?.id) {
|
|
175
|
+
savedDraftVersionId = result.id;
|
|
176
|
+
}
|
|
152
177
|
// Reset to idle after 3s
|
|
153
178
|
setTimeout(() => {
|
|
154
179
|
if (saveStatus === 'saved') saveStatus = 'idle';
|
|
@@ -158,7 +183,7 @@
|
|
|
158
183
|
}
|
|
159
184
|
}
|
|
160
185
|
|
|
161
|
-
// Track form changes for autosave
|
|
186
|
+
// Track form changes for autosave + Ctrl/Cmd+S shortcut
|
|
162
187
|
onMount(() => {
|
|
163
188
|
const unsub = form.form.subscribe((data) => {
|
|
164
189
|
const currentData = JSON.stringify(data);
|
|
@@ -167,8 +192,22 @@
|
|
|
167
192
|
scheduleAutosave();
|
|
168
193
|
}
|
|
169
194
|
});
|
|
195
|
+
|
|
196
|
+
function handleKeydown(e: KeyboardEvent) {
|
|
197
|
+
if ((e.ctrlKey || e.metaKey) && e.key === 's') {
|
|
198
|
+
e.preventDefault();
|
|
199
|
+
if (autosaveTimer) {
|
|
200
|
+
clearTimeout(autosaveTimer);
|
|
201
|
+
autosaveTimer = null;
|
|
202
|
+
}
|
|
203
|
+
performAutosave();
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
window.addEventListener('keydown', handleKeydown);
|
|
207
|
+
|
|
170
208
|
return () => {
|
|
171
209
|
unsub();
|
|
210
|
+
window.removeEventListener('keydown', handleKeydown);
|
|
172
211
|
if (autosaveTimer) clearTimeout(autosaveTimer);
|
|
173
212
|
};
|
|
174
213
|
});
|
|
@@ -186,24 +225,23 @@
|
|
|
186
225
|
autosaveTimer = null;
|
|
187
226
|
}
|
|
188
227
|
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
const currentFormData = get(form.form);
|
|
228
|
+
// Unpublish — skip validation, call remote directly
|
|
229
|
+
if (type === 'cancel-published') {
|
|
192
230
|
saveStatus = 'saving';
|
|
193
231
|
try {
|
|
194
232
|
await remotes.updateEntryVersionCommand({
|
|
195
233
|
entryId: entry.id,
|
|
196
|
-
data:
|
|
197
|
-
type
|
|
234
|
+
data: get(form.form),
|
|
235
|
+
type
|
|
198
236
|
});
|
|
199
|
-
lastSavedData = JSON.stringify(currentFormData);
|
|
200
237
|
saveStatus = 'saved';
|
|
201
|
-
toast.success(lang[interfaceLanguage.current].
|
|
238
|
+
toast.success(lang[interfaceLanguage.current].unpublishToast);
|
|
239
|
+
|
|
202
240
|
setTimeout(() => {
|
|
203
241
|
if (saveStatus === 'saved') saveStatus = 'idle';
|
|
204
242
|
}, 3000);
|
|
205
243
|
} catch (e) {
|
|
206
|
-
console.error('
|
|
244
|
+
console.error('Unpublish error:', e);
|
|
207
245
|
saveStatus = 'error';
|
|
208
246
|
toast.error(lang[interfaceLanguage.current].saveFailed, {
|
|
209
247
|
description: e instanceof Error ? e.message : undefined
|
|
@@ -245,14 +283,11 @@
|
|
|
245
283
|
});
|
|
246
284
|
}
|
|
247
285
|
} else {
|
|
248
|
-
const errors = flattenErrors(validatedForm.errors, collection
|
|
249
|
-
toast.error(
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
duration: 5000
|
|
254
|
-
}
|
|
255
|
-
);
|
|
286
|
+
const errors = flattenErrors(validatedForm.errors, getFieldsFromConfig(collection));
|
|
287
|
+
toast.error(lang[interfaceLanguage.current].cannotPublish, {
|
|
288
|
+
description: errors.slice(0, 3).join('\n') + (errors.length > 3 ? '\n...' : ''),
|
|
289
|
+
duration: 5000
|
|
290
|
+
});
|
|
256
291
|
}
|
|
257
292
|
}
|
|
258
293
|
|
|
@@ -292,7 +327,7 @@
|
|
|
292
327
|
|
|
293
328
|
type SizePreset = keyof typeof sizePresets;
|
|
294
329
|
|
|
295
|
-
let sizePreset: SizePreset = $state('
|
|
330
|
+
let sizePreset: SizePreset = $state('desktop');
|
|
296
331
|
|
|
297
332
|
function getOriginFromUrl(url: string): string {
|
|
298
333
|
try {
|
|
@@ -302,7 +337,9 @@
|
|
|
302
337
|
}
|
|
303
338
|
}
|
|
304
339
|
|
|
305
|
-
const previewOrigin = collection.previewUrl
|
|
340
|
+
const previewOrigin = collection.previewUrl
|
|
341
|
+
? getOriginFromUrl(collection.previewUrl)
|
|
342
|
+
: window.location.origin;
|
|
306
343
|
|
|
307
344
|
const updatePreview = useDebounce(
|
|
308
345
|
async (window: Window, form: SuperForm<Record<string, unknown>>) => {
|
|
@@ -420,44 +457,118 @@
|
|
|
420
457
|
}
|
|
421
458
|
}
|
|
422
459
|
});
|
|
460
|
+
|
|
461
|
+
// Banner: viewing published version + a separate draft exists
|
|
462
|
+
const showDraftBanner = $derived(
|
|
463
|
+
entry.publishedVersion != null &&
|
|
464
|
+
editingEntry.id === entry.publishedVersion.id &&
|
|
465
|
+
entry.draftVersion != null &&
|
|
466
|
+
entry.draftVersion.id !== entry.publishedVersion.id &&
|
|
467
|
+
entry.draftVersion.createdAt > entry.publishedVersion.createdAt
|
|
468
|
+
);
|
|
469
|
+
|
|
470
|
+
// Banner: viewing draft + a published version exists
|
|
471
|
+
const showPublishedBanner = $derived(
|
|
472
|
+
entry.publishedVersion != null && editingEntry.id !== entry.publishedVersion.id
|
|
473
|
+
);
|
|
474
|
+
|
|
475
|
+
const draftVersionId = $derived(entry.draftVersion?.id ?? savedDraftVersionId);
|
|
476
|
+
|
|
477
|
+
const scrollToIssue = (fieldSlug: string) => {
|
|
478
|
+
const fieldEl = document.querySelector(`[data-field-path="${fieldSlug}"]`);
|
|
479
|
+
if (fieldEl) {
|
|
480
|
+
fieldEl.scrollIntoView({ behavior: 'smooth', block: 'center' });
|
|
481
|
+
const proseMirror = fieldEl.querySelector('.ProseMirror') as HTMLElement | null;
|
|
482
|
+
if (proseMirror) {
|
|
483
|
+
proseMirror.focus();
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
};
|
|
423
487
|
</script>
|
|
424
488
|
|
|
425
|
-
<EntryHeader
|
|
489
|
+
<EntryHeader
|
|
490
|
+
{entry}
|
|
491
|
+
version={editingEntry}
|
|
492
|
+
{onSave}
|
|
493
|
+
onSaveDraft={performAutosave}
|
|
494
|
+
{onArchive}
|
|
495
|
+
{saveStatus}
|
|
496
|
+
fields={getFieldsFromConfig(collection)}
|
|
497
|
+
getFormData={() => get(form.form)}
|
|
498
|
+
onScrollToIssue={scrollToIssue}
|
|
499
|
+
/>
|
|
500
|
+
|
|
501
|
+
{#if showDraftBanner}
|
|
502
|
+
<div
|
|
503
|
+
class="flex items-center justify-between border-b bg-[var(--lavender-lighter)] px-6 py-2 text-sm"
|
|
504
|
+
>
|
|
505
|
+
<span class="text-[var(--text-secondary)]">{lang[interfaceLanguage.current].newerDraft}</span>
|
|
506
|
+
<button
|
|
507
|
+
type="button"
|
|
508
|
+
class="font-semibold text-[var(--primary)] hover:underline"
|
|
509
|
+
onclick={() => goto(`?version=${draftVersionId}`)}
|
|
510
|
+
>
|
|
511
|
+
{lang[interfaceLanguage.current].switchToDraft}
|
|
512
|
+
</button>
|
|
513
|
+
</div>
|
|
514
|
+
{:else if showPublishedBanner}
|
|
515
|
+
<div
|
|
516
|
+
class="flex items-center justify-between border-b bg-[var(--lavender-lighter)] px-6 py-2 text-sm"
|
|
517
|
+
>
|
|
518
|
+
<span class="text-[var(--text-secondary)]">{lang[interfaceLanguage.current].editingDraft}</span>
|
|
519
|
+
<button
|
|
520
|
+
type="button"
|
|
521
|
+
class="font-semibold text-[var(--primary)] hover:underline"
|
|
522
|
+
onclick={() => goto(`?version=${entry.publishedVersion!.id}`)}
|
|
523
|
+
>
|
|
524
|
+
{lang[interfaceLanguage.current].switchToPublished}
|
|
525
|
+
</button>
|
|
526
|
+
</div>
|
|
527
|
+
{/if}
|
|
426
528
|
|
|
427
529
|
{#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
|
-
|
|
530
|
+
<div class="flex min-h-0 flex-1 overflow-hidden">
|
|
531
|
+
{#await import('./hybrid/hybrid-layout.svelte')}
|
|
532
|
+
<div class="bg-accent h-full animate-pulse rounded-md"></div>
|
|
533
|
+
{:then { default: HybridLayout }}
|
|
534
|
+
<HybridLayout>
|
|
535
|
+
{#snippet preview()}
|
|
536
|
+
{#await import('./hybrid/hybrid-preview.svelte')}
|
|
537
|
+
<div class="bg-accent h-full animate-pulse rounded-md"></div>
|
|
538
|
+
{:then { default: HybridPreview }}
|
|
539
|
+
<HybridPreview
|
|
540
|
+
{collection}
|
|
541
|
+
{editingEntry}
|
|
542
|
+
bind:previewIframe
|
|
543
|
+
bind:sizePreset
|
|
544
|
+
{size}
|
|
545
|
+
bind:el
|
|
546
|
+
/>
|
|
547
|
+
{:catch}
|
|
548
|
+
<p class="text-destructive p-4 text-sm">Failed to load preview</p>
|
|
549
|
+
{/await}
|
|
550
|
+
{/snippet}
|
|
551
|
+
{#snippet formPanel()}
|
|
552
|
+
<EntryForm
|
|
553
|
+
{form}
|
|
554
|
+
{entry}
|
|
555
|
+
focusedPath={hybridContext.focusedPath}
|
|
556
|
+
onPathSelect={(path) => (hybridContext.focusedPath = path)}
|
|
557
|
+
/>
|
|
558
|
+
{/snippet}
|
|
559
|
+
</HybridLayout>
|
|
560
|
+
{:catch}
|
|
561
|
+
<p class="text-destructive p-4 text-sm">Failed to load layout</p>
|
|
562
|
+
{/await}
|
|
563
|
+
</div>
|
|
564
|
+
{:else if hasLayout(collection)}
|
|
565
|
+
<div class="overflow-y-auto" style="scroll-padding-top: 48px;">
|
|
566
|
+
<EntryForm {form} {entry} />
|
|
567
|
+
</div>
|
|
455
568
|
{:else}
|
|
456
|
-
<div class="flex items-stretch justify-center">
|
|
569
|
+
<div class="flex items-stretch justify-center" style="scroll-padding-top: 48px;">
|
|
457
570
|
<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
|
-
>
|
|
571
|
+
<div class="bg-card rounded-2xl border p-4 shadow-sm lg:p-6">
|
|
461
572
|
<EntryForm {form} {entry} />
|
|
462
573
|
</div>
|
|
463
574
|
</div>
|
|
@@ -0,0 +1,46 @@
|
|
|
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
|
+
export declare function validateA11y(data: Record<string, unknown>, fields: Field[], lang?: A11yLang): A11yIssue[];
|