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
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { authClient } from '../../auth-client.js';
|
|
3
|
+
import { useInterfaceLanguage } from '../../state/interface-language.svelte.js';
|
|
4
|
+
import type { InterfaceLanguage } from '../../../types/languages.js';
|
|
5
|
+
|
|
6
|
+
let session = authClient.useSession();
|
|
7
|
+
const interfaceLanguage = useInterfaceLanguage();
|
|
8
|
+
|
|
9
|
+
const firstName = $derived($session.data?.user?.name?.split(' ')[0] ?? '');
|
|
10
|
+
|
|
11
|
+
const lang: Record<InterfaceLanguage, { greeting: (name: string) => string }> = {
|
|
12
|
+
pl: {
|
|
13
|
+
greeting: (name) => {
|
|
14
|
+
const h = new Date().getHours();
|
|
15
|
+
if (h < 12) return `Dzień dobry, ${name}`;
|
|
16
|
+
if (h < 18) return `Cześć, ${name}`;
|
|
17
|
+
return `Dobry wieczór, ${name}`;
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
en: {
|
|
21
|
+
greeting: (name) => {
|
|
22
|
+
const h = new Date().getHours();
|
|
23
|
+
if (h < 12) return `Good morning, ${name}`;
|
|
24
|
+
if (h < 18) return `Good afternoon, ${name}`;
|
|
25
|
+
return `Good evening, ${name}`;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
const formattedDate = $derived(
|
|
31
|
+
new Date().toLocaleDateString(interfaceLanguage.current === 'pl' ? 'pl-PL' : 'en-US', {
|
|
32
|
+
weekday: 'long',
|
|
33
|
+
year: 'numeric',
|
|
34
|
+
month: 'long',
|
|
35
|
+
day: 'numeric'
|
|
36
|
+
})
|
|
37
|
+
);
|
|
38
|
+
</script>
|
|
39
|
+
|
|
40
|
+
<section class="welcome-header" aria-label={interfaceLanguage.current === 'pl' ? 'Powitanie' : 'Welcome'}>
|
|
41
|
+
<div>
|
|
42
|
+
<h1 class="welcome-title">{lang[interfaceLanguage.current].greeting(firstName)}</h1>
|
|
43
|
+
<p class="welcome-date"><time datetime={new Date().toISOString().split('T')[0]}>{formattedDate}</time></p>
|
|
44
|
+
</div>
|
|
45
|
+
</section>
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
} from 'sveltekit-superforms';
|
|
14
14
|
import { joinPath, normalizePath } from '../../utils/objectPath.js';
|
|
15
15
|
import type {
|
|
16
|
-
|
|
16
|
+
BlocksField,
|
|
17
17
|
ObjectField as ObjectFieldType,
|
|
18
18
|
ObjectFieldData
|
|
19
19
|
} from '../../../types/fields.js';
|
|
@@ -46,7 +46,7 @@
|
|
|
46
46
|
}
|
|
47
47
|
|
|
48
48
|
type Props = {
|
|
49
|
-
field:
|
|
49
|
+
field: BlocksField;
|
|
50
50
|
form: SuperForm<T>;
|
|
51
51
|
path: FormPathLeaves<T, ObjectFieldData[] | undefined>;
|
|
52
52
|
focusedPath?: string | null;
|
|
@@ -295,7 +295,7 @@
|
|
|
295
295
|
{#if objectField}
|
|
296
296
|
<Accordion.Item value={index.toString()} class="border-0" data-depth={depth + 1}>
|
|
297
297
|
<Accordion.Trigger
|
|
298
|
-
class="items-center border px-4 text-base font-normal data-[state=open]:rounded-b-none
|
|
298
|
+
class="items-center border px-4 text-base font-normal data-[state=open]:rounded-b-none"
|
|
299
299
|
>
|
|
300
300
|
<div class="flex grow items-center justify-between gap-4">
|
|
301
301
|
<div class="flex items-center gap-4">
|
|
@@ -353,7 +353,7 @@
|
|
|
353
353
|
</div>
|
|
354
354
|
</Accordion.Trigger>
|
|
355
355
|
<Accordion.Content
|
|
356
|
-
class="space-y-4 rounded-b-md border border-t-0
|
|
356
|
+
class="space-y-4 rounded-b-md border border-t-0"
|
|
357
357
|
style="padding: {Math.max(4, 16 - depth * 3)}px;"
|
|
358
358
|
>
|
|
359
359
|
{@const itemPath = joinPath(path, index)}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { type FormPathLeaves, type SuperForm } from 'sveltekit-superforms';
|
|
2
|
-
import type {
|
|
2
|
+
import type { BlocksField, ObjectFieldData } from '../../../types/fields.js';
|
|
3
3
|
declare function $$render<T extends Record<string, unknown>>(): {
|
|
4
4
|
props: {
|
|
5
|
-
field:
|
|
5
|
+
field: BlocksField;
|
|
6
6
|
form: SuperForm<T>;
|
|
7
7
|
path: FormPathLeaves<T, ObjectFieldData[] | undefined>;
|
|
8
8
|
focusedPath?: string | null;
|
|
@@ -28,6 +28,6 @@ interface $$IsomorphicComponent {
|
|
|
28
28
|
<T extends Record<string, unknown>>(internal: unknown, props: ReturnType<__sveltets_Render<T>['props']> & {}): ReturnType<__sveltets_Render<T>['exports']>;
|
|
29
29
|
z_$$bindings?: ReturnType<__sveltets_Render<any>['bindings']>;
|
|
30
30
|
}
|
|
31
|
-
declare const
|
|
32
|
-
type
|
|
33
|
-
export default
|
|
31
|
+
declare const BlocksField: $$IsomorphicComponent;
|
|
32
|
+
type BlocksField<T extends Record<string, unknown>> = InstanceType<typeof BlocksField<T>>;
|
|
33
|
+
export default BlocksField;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
<script lang="ts" module>
|
|
2
|
+
type T = Record<string, unknown>;
|
|
3
|
+
</script>
|
|
4
|
+
|
|
5
|
+
<script lang="ts" generics="T extends Record<string, unknown>">
|
|
6
|
+
import {
|
|
7
|
+
formFieldProxy,
|
|
8
|
+
type FormFieldProxy,
|
|
9
|
+
type FormPathLeaves,
|
|
10
|
+
type SuperForm
|
|
11
|
+
} from 'sveltekit-superforms';
|
|
12
|
+
import ContentEditor from '../tiptap/content-editor.svelte';
|
|
13
|
+
import type { ContentField } from '../../../types/fields.js';
|
|
14
|
+
import type { StructuredContentDoc } from '../../../types/structured-content.js';
|
|
15
|
+
|
|
16
|
+
type Props = {
|
|
17
|
+
field: ContentField;
|
|
18
|
+
form: SuperForm<T>;
|
|
19
|
+
path: FormPathLeaves<T, StructuredContentDoc | undefined>;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
let { field, form, path, ...props }: Props = $props();
|
|
23
|
+
|
|
24
|
+
const { value } = formFieldProxy(form, path) satisfies FormFieldProxy<StructuredContentDoc | undefined>;
|
|
25
|
+
</script>
|
|
26
|
+
|
|
27
|
+
<ContentEditor bind:value={$value} inlineBlocks={field.inlineBlocks} />
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { type FormPathLeaves, type SuperForm } from 'sveltekit-superforms';
|
|
2
|
+
import type { ContentField } from '../../../types/fields.js';
|
|
3
|
+
import type { StructuredContentDoc } from '../../../types/structured-content.js';
|
|
4
|
+
declare function $$render<T extends Record<string, unknown>>(): {
|
|
5
|
+
props: {
|
|
6
|
+
field: ContentField;
|
|
7
|
+
form: SuperForm<T>;
|
|
8
|
+
path: FormPathLeaves<T, StructuredContentDoc | undefined>;
|
|
9
|
+
};
|
|
10
|
+
exports: {};
|
|
11
|
+
bindings: "";
|
|
12
|
+
slots: {};
|
|
13
|
+
events: {};
|
|
14
|
+
};
|
|
15
|
+
declare class __sveltets_Render<T extends Record<string, unknown>> {
|
|
16
|
+
props(): ReturnType<typeof $$render<T>>['props'];
|
|
17
|
+
events(): ReturnType<typeof $$render<T>>['events'];
|
|
18
|
+
slots(): ReturnType<typeof $$render<T>>['slots'];
|
|
19
|
+
bindings(): "";
|
|
20
|
+
exports(): {};
|
|
21
|
+
}
|
|
22
|
+
interface $$IsomorphicComponent {
|
|
23
|
+
new <T extends Record<string, unknown>>(options: import('svelte').ComponentConstructorOptions<ReturnType<__sveltets_Render<T>['props']>>): import('svelte').SvelteComponent<ReturnType<__sveltets_Render<T>['props']>, ReturnType<__sveltets_Render<T>['events']>, ReturnType<__sveltets_Render<T>['slots']>> & {
|
|
24
|
+
$$bindings?: ReturnType<__sveltets_Render<T>['bindings']>;
|
|
25
|
+
} & ReturnType<__sveltets_Render<T>['exports']>;
|
|
26
|
+
<T extends Record<string, unknown>>(internal: unknown, props: ReturnType<__sveltets_Render<T>['props']> & {}): ReturnType<__sveltets_Render<T>['exports']>;
|
|
27
|
+
z_$$bindings?: ReturnType<__sveltets_Render<any>['bindings']>;
|
|
28
|
+
}
|
|
29
|
+
declare const ContentField: $$IsomorphicComponent;
|
|
30
|
+
type ContentField<T extends Record<string, unknown>> = InstanceType<typeof ContentField<T>>;
|
|
31
|
+
export default ContentField;
|
|
@@ -32,13 +32,13 @@
|
|
|
32
32
|
|
|
33
33
|
const interfaceLanguage = useInterfaceLanguage();
|
|
34
34
|
|
|
35
|
-
const fieldsWithNoDescription: FieldType[] = ['boolean', 'object', '
|
|
36
|
-
const fieldsWithNoLabel: FieldType[] = ['boolean', 'object', '
|
|
35
|
+
const fieldsWithNoDescription: FieldType[] = ['boolean', 'object', 'blocks', 'seo'];
|
|
36
|
+
const fieldsWithNoLabel: FieldType[] = ['boolean', 'object', 'blocks', 'seo'];
|
|
37
37
|
|
|
38
|
-
const fieldsWithAlternativeDescription: FieldType[] = ['image', 'media', 'object', '
|
|
38
|
+
const fieldsWithAlternativeDescription: FieldType[] = ['image', 'media', 'object', 'blocks'];
|
|
39
39
|
|
|
40
|
-
function isTextField(field: Field): field is Extract<Field, { type: 'text' | 'richtext' }> {
|
|
41
|
-
return ['text', 'richtext'].includes(field.type);
|
|
40
|
+
function isTextField(field: Field): field is Extract<Field, { type: 'text' | 'richtext' | 'content' }> {
|
|
41
|
+
return ['text', 'richtext', 'content'].includes(field.type);
|
|
42
42
|
}
|
|
43
43
|
|
|
44
44
|
function isRadioField(field: Field): field is Extract<Field, { type: 'radio' }> {
|
|
@@ -106,7 +106,7 @@
|
|
|
106
106
|
{#snippet children({ props })}
|
|
107
107
|
<div class="space-y-2">
|
|
108
108
|
{#if field.label && !fieldsWithNoLabel.includes(field.type)}
|
|
109
|
-
<RequiredLabel required={field.required} class={field.type === '
|
|
109
|
+
<RequiredLabel required={field.required} class={field.type === 'blocks' ? 'text-lg font-medium' : ''}>
|
|
110
110
|
{getLocalizedLabel(field.label, interfaceLanguage.current)}
|
|
111
111
|
</RequiredLabel>
|
|
112
112
|
{/if}
|
|
@@ -121,8 +121,10 @@
|
|
|
121
121
|
<LazyField loader={() => import('./media-field.svelte')} props={{ field, form, path, ...props }} skeletonClass="h-24" />
|
|
122
122
|
{:else if field.type === 'file'}
|
|
123
123
|
<LazyField loader={() => import('./file-field.svelte')} props={{ field, form, path, ...props }} skeletonClass="h-12" />
|
|
124
|
+
{:else if field.type === 'blocks'}
|
|
125
|
+
<LazyField loader={() => import('./blocks-field.svelte')} props={{ field, form, path, focusedPath, flashingPath, depth, ...props }} skeletonClass="h-20" />
|
|
124
126
|
{:else if field.type === 'array'}
|
|
125
|
-
<LazyField loader={() => import('./array-field.svelte')} props={{ field, form, path,
|
|
127
|
+
<LazyField loader={() => import('./simple-array-field.svelte')} props={{ field, form, path, ...props }} skeletonClass="h-12" />
|
|
126
128
|
{:else if field.type === 'object'}
|
|
127
129
|
<LazyField loader={() => import('./object-field.svelte')} props={{ field, form, path, objectFieldType, focusedPath, flashingPath, depth, ...props }} skeletonClass="h-20" />
|
|
128
130
|
{:else if field.type === 'slug'}
|
|
@@ -108,7 +108,7 @@
|
|
|
108
108
|
<div class="absolute inset-x-0 top-1/2 flex -translate-y-1/2 justify-between px-1 pointer-events-none">
|
|
109
109
|
<button
|
|
110
110
|
type="button"
|
|
111
|
-
class="pointer-events-auto flex h-8 w-8 items-center justify-center rounded-full bg-white/80 backdrop-blur shadow-md transition hover:bg-white hover:scale-105 dark:bg-
|
|
111
|
+
class="pointer-events-auto flex h-8 w-8 items-center justify-center rounded-full bg-white/80 backdrop-blur shadow-md transition hover:bg-white hover:scale-105 dark:bg-background/80 dark:hover:bg-background"
|
|
112
112
|
onclick={(e) => {
|
|
113
113
|
e.stopPropagation();
|
|
114
114
|
currentIndex = currentIndex > 0 ? currentIndex - 1 : valueArr.length - 1;
|
|
@@ -118,7 +118,7 @@
|
|
|
118
118
|
</button>
|
|
119
119
|
<button
|
|
120
120
|
type="button"
|
|
121
|
-
class="pointer-events-auto flex h-8 w-8 items-center justify-center rounded-full bg-white/80 backdrop-blur shadow-md transition hover:bg-white hover:scale-105 dark:bg-
|
|
121
|
+
class="pointer-events-auto flex h-8 w-8 items-center justify-center rounded-full bg-white/80 backdrop-blur shadow-md transition hover:bg-white hover:scale-105 dark:bg-background/80 dark:hover:bg-background"
|
|
122
122
|
onclick={(e) => {
|
|
123
123
|
e.stopPropagation();
|
|
124
124
|
currentIndex = currentIndex < valueArr.length - 1 ? currentIndex + 1 : 0;
|
|
@@ -280,14 +280,14 @@
|
|
|
280
280
|
<div class="absolute inset-x-0 top-1/2 flex -translate-y-1/2 justify-between px-1 pointer-events-none">
|
|
281
281
|
<button
|
|
282
282
|
type="button"
|
|
283
|
-
class="pointer-events-auto flex h-8 w-8 items-center justify-center rounded-full bg-white/80 backdrop-blur shadow-md transition hover:bg-white hover:scale-105 dark:bg-
|
|
283
|
+
class="pointer-events-auto flex h-8 w-8 items-center justify-center rounded-full bg-white/80 backdrop-blur shadow-md transition hover:bg-white hover:scale-105 dark:bg-background/80 dark:hover:bg-background"
|
|
284
284
|
onclick={(e) => { e.stopPropagation(); currentIndex = currentIndex > 0 ? currentIndex - 1 : valueArr.length - 1; }}
|
|
285
285
|
>
|
|
286
286
|
<ChevronLeft class="h-5 w-5" />
|
|
287
287
|
</button>
|
|
288
288
|
<button
|
|
289
289
|
type="button"
|
|
290
|
-
class="pointer-events-auto flex h-8 w-8 items-center justify-center rounded-full bg-white/80 backdrop-blur shadow-md transition hover:bg-white hover:scale-105 dark:bg-
|
|
290
|
+
class="pointer-events-auto flex h-8 w-8 items-center justify-center rounded-full bg-white/80 backdrop-blur shadow-md transition hover:bg-white hover:scale-105 dark:bg-background/80 dark:hover:bg-background"
|
|
291
291
|
onclick={(e) => { e.stopPropagation(); currentIndex = currentIndex < valueArr.length - 1 ? currentIndex + 1 : 0; }}
|
|
292
292
|
>
|
|
293
293
|
<ChevronRight class="h-5 w-5" />
|
|
@@ -4,23 +4,27 @@
|
|
|
4
4
|
|
|
5
5
|
<script lang="ts" generics="T extends Record<string, unknown>">
|
|
6
6
|
import {
|
|
7
|
-
formFieldProxy,
|
|
8
|
-
type FormFieldProxy,
|
|
9
7
|
type FormPathLeaves,
|
|
10
8
|
type SuperForm
|
|
11
9
|
} from 'sveltekit-superforms';
|
|
12
10
|
import FieldRenderer from './field-renderer.svelte';
|
|
13
11
|
import { joinPath } from '../../utils/objectPath.js';
|
|
12
|
+
import { getAtPath, setAtPath } from '../../utils/objectPath.js';
|
|
14
13
|
import type {
|
|
15
14
|
Field,
|
|
16
15
|
ImageField,
|
|
17
|
-
ObjectFieldData,
|
|
18
16
|
SeoField,
|
|
19
17
|
SeoFieldData,
|
|
20
18
|
TextField
|
|
21
19
|
} from '../../../types/fields.js';
|
|
22
|
-
|
|
23
|
-
import
|
|
20
|
+
import { untrack } from 'svelte';
|
|
21
|
+
import slugify from '../../imports/slugify.js';
|
|
22
|
+
import { useInterfaceLanguage } from '../../state/interface-language.svelte.js';
|
|
23
|
+
import { getContentLanguage } from '../../state/content-language.svelte.js';
|
|
24
|
+
import { getLocalizedLabel } from '../../utils/collectionLabel.js';
|
|
25
|
+
|
|
26
|
+
const interfaceLanguage = useInterfaceLanguage();
|
|
27
|
+
const contentLanguage = getContentLanguage();
|
|
24
28
|
|
|
25
29
|
type Props = {
|
|
26
30
|
field: SeoField;
|
|
@@ -30,31 +34,89 @@
|
|
|
30
34
|
|
|
31
35
|
let { field, form, path, ...props }: Props = $props();
|
|
32
36
|
|
|
37
|
+
const { form: formData } = form;
|
|
38
|
+
|
|
39
|
+
const labels = {
|
|
40
|
+
slug: {
|
|
41
|
+
label: { en: 'URL Slug', pl: 'Slug URL' },
|
|
42
|
+
description: {
|
|
43
|
+
en: 'Page address shown in the browser bar',
|
|
44
|
+
pl: 'Adres strony widoczny w pasku przeglądarki'
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
canonicalUrl: {
|
|
48
|
+
label: { en: 'Canonical URL', pl: 'Adres kanoniczny' },
|
|
49
|
+
description: {
|
|
50
|
+
en: 'If this content appears at another address, enter the original URL',
|
|
51
|
+
pl: 'Jeśli ta treść pojawia się pod innym adresem, podaj oryginalny URL'
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
title: {
|
|
55
|
+
label: { en: 'SEO Title', pl: 'Tytuł SEO' },
|
|
56
|
+
description: {
|
|
57
|
+
en: 'Appears in search results and browser tabs (50–60 characters)',
|
|
58
|
+
pl: 'Widoczny w wynikach wyszukiwania i zakładce przeglądarki (50–60 znaków)'
|
|
59
|
+
}
|
|
60
|
+
},
|
|
61
|
+
description: {
|
|
62
|
+
label: { en: 'Description', pl: 'Opis' },
|
|
63
|
+
description: {
|
|
64
|
+
en: 'Short summary for search engines (120–160 characters)',
|
|
65
|
+
pl: 'Krótkie podsumowanie dla wyszukiwarek (120–160 znaków)'
|
|
66
|
+
}
|
|
67
|
+
},
|
|
68
|
+
keywords: {
|
|
69
|
+
label: { en: 'Keywords', pl: 'Słowa kluczowe' },
|
|
70
|
+
description: {
|
|
71
|
+
en: 'Comma-separated list of keywords',
|
|
72
|
+
pl: 'Lista słów kluczowych oddzielonych przecinkami'
|
|
73
|
+
}
|
|
74
|
+
},
|
|
75
|
+
ogImage: {
|
|
76
|
+
label: { en: 'Social media image', pl: 'Obraz w mediach społecznościowych' },
|
|
77
|
+
description: {
|
|
78
|
+
en: 'Image displayed when sharing this page on social media',
|
|
79
|
+
pl: 'Obraz wyświetlany przy udostępnianiu strony w mediach społecznościowych'
|
|
80
|
+
}
|
|
81
|
+
},
|
|
82
|
+
customCode: {
|
|
83
|
+
label: { en: 'Custom code', pl: 'Własny kod' },
|
|
84
|
+
description: {
|
|
85
|
+
en: 'Additional HTML inserted into the page <head>',
|
|
86
|
+
pl: 'Dodatkowy HTML wstawiany do sekcji <head> strony'
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
};
|
|
90
|
+
|
|
33
91
|
const slugField: TextField = {
|
|
34
92
|
type: 'text',
|
|
35
93
|
slug: 'slug',
|
|
36
|
-
label:
|
|
94
|
+
label: labels.slug.label,
|
|
95
|
+
description: labels.slug.description,
|
|
37
96
|
required: true
|
|
38
97
|
};
|
|
39
98
|
|
|
40
99
|
const canonicalUrlField: TextField = {
|
|
41
100
|
type: 'text',
|
|
42
101
|
slug: 'canonicalUrl',
|
|
43
|
-
label:
|
|
102
|
+
label: labels.canonicalUrl.label,
|
|
103
|
+
description: labels.canonicalUrl.description,
|
|
44
104
|
required: false
|
|
45
105
|
};
|
|
46
106
|
|
|
47
107
|
const titleField: TextField = {
|
|
48
108
|
type: 'text',
|
|
49
109
|
slug: 'title',
|
|
50
|
-
label:
|
|
110
|
+
label: labels.title.label,
|
|
111
|
+
description: labels.title.description,
|
|
51
112
|
required: true
|
|
52
113
|
};
|
|
53
114
|
|
|
54
115
|
const descriptionField: TextField = {
|
|
55
116
|
type: 'text',
|
|
56
117
|
slug: 'description',
|
|
57
|
-
label:
|
|
118
|
+
label: labels.description.label,
|
|
119
|
+
description: labels.description.description,
|
|
58
120
|
required: false,
|
|
59
121
|
multiline: true
|
|
60
122
|
};
|
|
@@ -62,7 +124,8 @@
|
|
|
62
124
|
const keyWordsField: TextField = {
|
|
63
125
|
type: 'text',
|
|
64
126
|
slug: 'keywords',
|
|
65
|
-
label:
|
|
127
|
+
label: labels.keywords.label,
|
|
128
|
+
description: labels.keywords.description,
|
|
66
129
|
required: false,
|
|
67
130
|
multiline: true
|
|
68
131
|
};
|
|
@@ -70,14 +133,16 @@
|
|
|
70
133
|
const ogImageField: ImageField = {
|
|
71
134
|
type: 'image',
|
|
72
135
|
slug: 'ogImage',
|
|
73
|
-
label:
|
|
136
|
+
label: labels.ogImage.label,
|
|
137
|
+
description: labels.ogImage.description,
|
|
74
138
|
required: false
|
|
75
139
|
};
|
|
76
140
|
|
|
77
141
|
const customCodeField: TextField = {
|
|
78
142
|
type: 'text',
|
|
79
143
|
slug: 'customCode',
|
|
80
|
-
label:
|
|
144
|
+
label: labels.customCode.label,
|
|
145
|
+
description: labels.customCode.description,
|
|
81
146
|
required: false,
|
|
82
147
|
multiline: true
|
|
83
148
|
};
|
|
@@ -91,19 +156,134 @@
|
|
|
91
156
|
ogImageField,
|
|
92
157
|
customCodeField
|
|
93
158
|
];
|
|
159
|
+
|
|
160
|
+
// Helper: read a value from formData, handling both localized (object) and plain (string) values
|
|
161
|
+
function readSourceValue(sourcePath: string): string | undefined {
|
|
162
|
+
const raw = ($formData as Record<string, unknown>)[sourcePath];
|
|
163
|
+
if (typeof raw === 'string') return raw;
|
|
164
|
+
if (raw && typeof raw === 'object') {
|
|
165
|
+
return (raw as Record<string, string>)[contentLanguage.current];
|
|
166
|
+
}
|
|
167
|
+
return undefined;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// Helper: read value at a dot-path from formData
|
|
171
|
+
function readPath(dotPath: string): string | undefined {
|
|
172
|
+
const val = getAtPath($formData as Record<string, unknown>, dotPath);
|
|
173
|
+
return typeof val === 'string' ? val : undefined;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// Character count for current language
|
|
177
|
+
let titleLength = $derived.by(() => {
|
|
178
|
+
const val = readPath(joinPath(String(path), 'title', contentLanguage.current));
|
|
179
|
+
return val?.length ?? 0;
|
|
180
|
+
});
|
|
181
|
+
let descLength = $derived.by(() => {
|
|
182
|
+
const val = readPath(joinPath(String(path), 'description', contentLanguage.current));
|
|
183
|
+
return val?.length ?? 0;
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
function charHintClass(len: number, min: number, max: number): string {
|
|
187
|
+
if (len === 0) return 'text-muted-foreground';
|
|
188
|
+
if (len >= min && len <= max) return 'text-success';
|
|
189
|
+
if (len < min) return 'text-warning';
|
|
190
|
+
return 'text-destructive';
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// Auto-gen: track last auto-generated values per language
|
|
194
|
+
let lastAutoSlugs: Record<string, string> = {};
|
|
195
|
+
let lastAutoTitles: Record<string, string> = {};
|
|
196
|
+
|
|
197
|
+
// slugSource → auto-gen seo.slug per language
|
|
198
|
+
$effect(() => {
|
|
199
|
+
if (!field.slugSource) return;
|
|
200
|
+
const sourceRaw = ($formData as Record<string, unknown>)[field.slugSource];
|
|
201
|
+
if (!sourceRaw) return;
|
|
202
|
+
|
|
203
|
+
untrack(() => {
|
|
204
|
+
const pairs: [string, string][] =
|
|
205
|
+
typeof sourceRaw === 'string'
|
|
206
|
+
? [[contentLanguage.current, sourceRaw]]
|
|
207
|
+
: typeof sourceRaw === 'object'
|
|
208
|
+
? Object.entries(sourceRaw as Record<string, string>).filter(([, v]) => typeof v === 'string' && v)
|
|
209
|
+
: [];
|
|
210
|
+
|
|
211
|
+
let changed = false;
|
|
212
|
+
for (const [lang, text] of pairs) {
|
|
213
|
+
const targetPath = joinPath(String(path), 'slug', lang);
|
|
214
|
+
const current = getAtPath($formData as Record<string, unknown>, targetPath) as string | undefined;
|
|
215
|
+
if (!current || current === lastAutoSlugs[lang]) {
|
|
216
|
+
const newSlug = slugify(String(text), { lower: true, strict: true, trim: true });
|
|
217
|
+
if (newSlug !== current) {
|
|
218
|
+
setAtPath($formData as Record<string, unknown>, targetPath, newSlug);
|
|
219
|
+
changed = true;
|
|
220
|
+
}
|
|
221
|
+
lastAutoSlugs[lang] = newSlug;
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
if (changed) $formData = $formData;
|
|
225
|
+
});
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
// titleSource → auto-fill seo.title per language
|
|
229
|
+
$effect(() => {
|
|
230
|
+
if (!field.titleSource) return;
|
|
231
|
+
const sourceRaw = ($formData as Record<string, unknown>)[field.titleSource];
|
|
232
|
+
if (!sourceRaw) return;
|
|
233
|
+
|
|
234
|
+
untrack(() => {
|
|
235
|
+
const pairs: [string, string][] =
|
|
236
|
+
typeof sourceRaw === 'string'
|
|
237
|
+
? [[contentLanguage.current, sourceRaw]]
|
|
238
|
+
: typeof sourceRaw === 'object'
|
|
239
|
+
? Object.entries(sourceRaw as Record<string, string>).filter(([, v]) => typeof v === 'string' && v)
|
|
240
|
+
: [];
|
|
241
|
+
|
|
242
|
+
let changed = false;
|
|
243
|
+
for (const [lang, text] of pairs) {
|
|
244
|
+
const targetPath = joinPath(String(path), 'title', lang);
|
|
245
|
+
const current = getAtPath($formData as Record<string, unknown>, targetPath) as string | undefined;
|
|
246
|
+
if (!current || current === lastAutoTitles[lang]) {
|
|
247
|
+
if (text !== current) {
|
|
248
|
+
setAtPath($formData as Record<string, unknown>, targetPath, text);
|
|
249
|
+
changed = true;
|
|
250
|
+
}
|
|
251
|
+
lastAutoTitles[lang] = text;
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
if (changed) $formData = $formData;
|
|
255
|
+
});
|
|
256
|
+
});
|
|
94
257
|
</script>
|
|
95
258
|
|
|
96
|
-
<
|
|
97
|
-
|
|
98
|
-
<
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
<
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
259
|
+
<div class="space-y-4">
|
|
260
|
+
{#each fields as f}
|
|
261
|
+
<div>
|
|
262
|
+
<FieldRenderer
|
|
263
|
+
field={f}
|
|
264
|
+
form={form as SuperForm<Record<string, unknown>>}
|
|
265
|
+
path={joinPath(path, f.slug)}
|
|
266
|
+
/>
|
|
267
|
+
{#if f.slug === 'title'}
|
|
268
|
+
<p class="mt-1 text-xs {charHintClass(titleLength, 50, 60)}">
|
|
269
|
+
{titleLength}/60
|
|
270
|
+
{#if titleLength > 0 && titleLength < 50}
|
|
271
|
+
— {getLocalizedLabel({ en: 'a bit short', pl: 'trochę za krótko' }, interfaceLanguage.current)}
|
|
272
|
+
{:else if titleLength > 60}
|
|
273
|
+
— {getLocalizedLabel({ en: 'too long', pl: 'za długo' }, interfaceLanguage.current)}
|
|
274
|
+
{/if}
|
|
275
|
+
</p>
|
|
276
|
+
{/if}
|
|
277
|
+
{#if f.slug === 'description'}
|
|
278
|
+
<p class="mt-1 text-xs {charHintClass(descLength, 120, 160)}">
|
|
279
|
+
{descLength}/160
|
|
280
|
+
{#if descLength > 0 && descLength < 120}
|
|
281
|
+
— {getLocalizedLabel({ en: 'a bit short', pl: 'trochę za krótko' }, interfaceLanguage.current)}
|
|
282
|
+
{:else if descLength > 160}
|
|
283
|
+
— {getLocalizedLabel({ en: 'too long', pl: 'za długo' }, interfaceLanguage.current)}
|
|
284
|
+
{/if}
|
|
285
|
+
</p>
|
|
286
|
+
{/if}
|
|
107
287
|
</div>
|
|
108
|
-
|
|
109
|
-
</
|
|
288
|
+
{/each}
|
|
289
|
+
</div>
|