includio-cms 0.5.1 → 0.5.3
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 +35 -12
- package/ROADMAP.md +17 -0
- package/dist/admin/client/entry/entry-form.svelte +1 -0
- package/dist/admin/client/entry/entry.svelte +130 -123
- package/dist/admin/client/entry/hybrid/hybrid-preview.svelte +92 -9
- package/dist/admin/components/dashboard/changelog-dialog.svelte +16 -6
- package/dist/admin/components/fields/blocks-field.svelte +142 -112
- package/dist/admin/components/fields/blocks-field.svelte.d.ts +10 -30
- package/dist/admin/components/fields/boolean-field.svelte +28 -38
- package/dist/admin/components/fields/boolean-field.svelte.d.ts +5 -27
- package/dist/admin/components/fields/checkboxes-field.svelte +12 -24
- package/dist/admin/components/fields/checkboxes-field.svelte.d.ts +5 -27
- package/dist/admin/components/fields/content-field.svelte +4 -17
- package/dist/admin/components/fields/content-field.svelte.d.ts +5 -27
- package/dist/admin/components/fields/date-field.svelte +8 -21
- package/dist/admin/components/fields/date-field.svelte.d.ts +5 -27
- package/dist/admin/components/fields/datetime-field.svelte +8 -21
- package/dist/admin/components/fields/datetime-field.svelte.d.ts +5 -27
- package/dist/admin/components/fields/field-renderer.svelte +32 -19
- package/dist/admin/components/fields/field-renderer.svelte.d.ts +1 -1
- package/dist/admin/components/fields/field-value-bridge.svelte +21 -0
- package/dist/admin/components/fields/field-value-bridge.svelte.d.ts +31 -0
- package/dist/admin/components/fields/fields-form.svelte +13 -10
- package/dist/admin/components/fields/file-field.svelte +12 -27
- package/dist/admin/components/fields/file-field.svelte.d.ts +5 -27
- package/dist/admin/components/fields/image-field.svelte +13 -28
- package/dist/admin/components/fields/image-field.svelte.d.ts +5 -27
- package/dist/admin/components/fields/media-field.svelte +15 -30
- package/dist/admin/components/fields/media-field.svelte.d.ts +5 -27
- package/dist/admin/components/fields/number-field.svelte +6 -20
- package/dist/admin/components/fields/number-field.svelte.d.ts +5 -27
- package/dist/admin/components/fields/object-field.svelte +26 -29
- package/dist/admin/components/fields/object-field.svelte.d.ts +11 -31
- package/dist/admin/components/fields/radio-field.svelte +8 -20
- package/dist/admin/components/fields/radio-field.svelte.d.ts +5 -27
- package/dist/admin/components/fields/relation-field.svelte +15 -30
- package/dist/admin/components/fields/relation-field.svelte.d.ts +5 -27
- package/dist/admin/components/fields/richtext-field.svelte +4 -17
- package/dist/admin/components/fields/richtext-field.svelte.d.ts +5 -27
- package/dist/admin/components/fields/select-field.svelte +14 -28
- package/dist/admin/components/fields/select-field.svelte.d.ts +5 -27
- package/dist/admin/components/fields/seo-field.svelte +5 -12
- package/dist/admin/components/fields/seo-field.svelte.d.ts +8 -28
- package/dist/admin/components/fields/simple-array-field.svelte +29 -42
- package/dist/admin/components/fields/simple-array-field.svelte.d.ts +5 -27
- package/dist/admin/components/fields/slug-field.svelte +6 -11
- package/dist/admin/components/fields/slug-field.svelte.d.ts +6 -26
- package/dist/admin/components/fields/text-field-wrapper.svelte +22 -40
- package/dist/admin/components/fields/text-field.svelte +7 -19
- package/dist/admin/components/fields/text-field.svelte.d.ts +5 -27
- package/dist/admin/components/fields/url-field-wrapper.svelte +8 -3
- package/dist/admin/components/fields/url-field.svelte +294 -128
- package/dist/admin/components/fields/url-field.svelte.d.ts +5 -27
- package/dist/admin/components/layout/layout-renderer.svelte +8 -6
- package/dist/admin/components/tiptap/InlineBlockNodeView.svelte +221 -31
- package/dist/admin/components/tiptap/content-editor.svelte +13 -2
- package/dist/admin/components/tiptap/inline-block-node.d.ts +1 -0
- package/dist/admin/components/tiptap/inline-block-node.js +18 -1
- package/dist/admin/components/tiptap/slash-command.js +2 -3
- package/dist/admin/components/tiptap/standalone-form.d.ts +7 -0
- package/dist/admin/components/tiptap/standalone-form.js +31 -0
- package/dist/admin/components/tiptap/tiptap-editor.svelte +7 -0
- package/dist/admin/remote/entry.remote.js +16 -0
- package/dist/admin/styles/admin.css +10 -0
- package/dist/admin/utils/fieldCondition.d.ts +6 -0
- package/dist/admin/utils/fieldCondition.js +20 -0
- package/dist/components/ui/switch/index.d.ts +2 -0
- package/dist/components/ui/switch/index.js +4 -0
- package/dist/components/ui/switch/switch.svelte +26 -0
- package/dist/components/ui/switch/switch.svelte.d.ts +4 -0
- package/dist/core/fields/fieldSchemaToTs.js +15 -3
- package/dist/core/fields/formFieldSchemaToTs.js +22 -6
- package/dist/core/fields/urlUtils.d.ts +14 -0
- package/dist/core/fields/urlUtils.js +21 -0
- package/dist/core/server/fields/populateEntry.js +43 -0
- package/dist/core/server/fields/resolveImageFields.js +33 -1
- package/dist/core/server/fields/resolveRelationFields.js +46 -0
- package/dist/core/server/fields/resolveRichtextLinks.js +15 -1
- package/dist/core/server/fields/resolveUrlFields.js +65 -0
- package/dist/core/server/generator/formFieldSchemaToString.js +40 -9
- package/dist/core/server/generator/formFields.js +2 -0
- package/dist/core/server/generator/generator.js +25 -1
- package/dist/schemas/field/url.d.ts +2 -0
- package/dist/schemas/field/url.js +4 -2
- package/dist/types/fields.d.ts +9 -0
- package/dist/types/formFields.d.ts +15 -2
- package/dist/types/index.d.ts +1 -0
- package/dist/types/index.js +1 -0
- package/dist/updates/0.0.65/index.js +1 -1
- package/dist/updates/0.0.67/index.js +1 -1
- package/dist/updates/0.1.2/index.js +1 -1
- package/dist/updates/0.1.5/index.js +1 -1
- package/dist/updates/0.2.0/index.js +1 -1
- package/dist/updates/0.2.2/index.js +1 -1
- package/dist/updates/0.5.0/index.js +1 -1
- package/dist/updates/0.5.2/index.d.ts +2 -0
- package/dist/updates/0.5.2/index.js +14 -0
- package/dist/updates/0.5.3/index.d.ts +2 -0
- package/dist/updates/0.5.3/index.js +19 -0
- package/dist/updates/index.d.ts +2 -1
- package/dist/updates/index.js +3 -1
- package/package.json +2 -1
- package/dist/admin/components/fields/standalone-field-renderer.svelte +0 -148
- package/dist/admin/components/fields/standalone-field-renderer.svelte.d.ts +0 -9
- package/dist/updates/0.0.65/migration.sql +0 -55
- package/dist/updates/0.0.67/migration.sql +0 -9
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,37 @@
|
|
|
3
3
|
All notable changes to includio-cms are documented here.
|
|
4
4
|
Generated from `src/lib/updates/` — do not edit manually.
|
|
5
5
|
|
|
6
|
+
## 0.5.3 — 2026-03-04
|
|
7
|
+
|
|
8
|
+
Form fields, inline blocks, hybrid preview, field components refactor
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
- Form fields: select type, minLength/maxLength, errorMessage, remote commands
|
|
12
|
+
- Conditional field visibility (showWhen)
|
|
13
|
+
- Hybrid preview: device frames, container queries
|
|
14
|
+
- TipTap placeholder extension + Notion-style styles
|
|
15
|
+
- Server-side field resolution for inline blocks
|
|
16
|
+
- Inline blocks: standalone form, full field rendering, collapse UI
|
|
17
|
+
- URL field: rel attribute, external auto-detect, UI redesign
|
|
18
|
+
- Switch UI component (bits-ui)
|
|
19
|
+
- Boolean field: Switch toggle zamiast checkbox
|
|
20
|
+
- Storybook stories for all field types
|
|
21
|
+
|
|
22
|
+
### Fixed
|
|
23
|
+
- Hybrid preview layout fix
|
|
24
|
+
|
|
25
|
+
## 0.5.2 — 2026-02-25
|
|
26
|
+
|
|
27
|
+
Update system: split migration into sql + notes
|
|
28
|
+
|
|
29
|
+
### Fixed
|
|
30
|
+
- CmsUpdate.migration split into sql (executable SQL) and notes (manual steps) — fixes CLI crash on text descriptions
|
|
31
|
+
- Changelog dialog: SQL accordion hidden when no SQL, notes shown as inline text
|
|
32
|
+
- Changelog script: SQL in ```sql blocks, notes as plain text
|
|
33
|
+
|
|
34
|
+
### Breaking
|
|
35
|
+
- CmsUpdate interface: migration field replaced by sql + notes fields
|
|
36
|
+
|
|
6
37
|
## 0.5.1 — 2026-02-24
|
|
7
38
|
|
|
8
39
|
Restore archived entries, dashboard redesign, translation fixes
|
|
@@ -28,11 +59,9 @@ Frontend rendering for structured content
|
|
|
28
59
|
- Query helpers: `extractBlocks()`, `extractInlineBlocks()`, `extractText()`, `extractMediaRefs()`
|
|
29
60
|
- Media resolution in population pipeline for `content` field — figure/video nodes enriched with `_media`
|
|
30
61
|
|
|
31
|
-
###
|
|
62
|
+
### Notes
|
|
32
63
|
|
|
33
|
-
```sql
|
|
34
64
|
No migration needed. Import `StructuredContent` from `includio/sveltekit` to render content fields.
|
|
35
|
-
```
|
|
36
65
|
|
|
37
66
|
## 0.2.2 — 2026-02-21
|
|
38
67
|
|
|
@@ -43,11 +72,9 @@ Structured Content field (TipTap JSON)
|
|
|
43
72
|
- Extracted shared editor toolbar component
|
|
44
73
|
- Content field link resolution in resolve pipeline
|
|
45
74
|
|
|
46
|
-
###
|
|
75
|
+
### Notes
|
|
47
76
|
|
|
48
|
-
```sql
|
|
49
77
|
No migration needed. Add type:"content" fields to collection/single configs. Existing richtext fields unchanged.
|
|
50
|
-
```
|
|
51
78
|
|
|
52
79
|
## 0.2.0 — 2026-02-21
|
|
53
80
|
|
|
@@ -59,11 +86,9 @@ Array→Blocks rename, new simple array field
|
|
|
59
86
|
### Breaking
|
|
60
87
|
- type:"array" with objects renamed to type:"blocks". Update collection/single configs.
|
|
61
88
|
|
|
62
|
-
###
|
|
89
|
+
### Notes
|
|
63
90
|
|
|
64
|
-
```sql
|
|
65
91
|
Config-only: rename type:"array" to type:"blocks" in field definitions. Stored data unchanged.
|
|
66
|
-
```
|
|
67
92
|
|
|
68
93
|
## 0.1.5 — 2026-02-21
|
|
69
94
|
|
|
@@ -80,11 +105,9 @@ Simplified entry versioning
|
|
|
80
105
|
- Auto-save no longer creates dozens of empty versions
|
|
81
106
|
- Pruning no longer deletes important versions to make room for empty ones
|
|
82
107
|
|
|
83
|
-
###
|
|
108
|
+
### Notes
|
|
84
109
|
|
|
85
|
-
```sql
|
|
86
110
|
Removes duplicate entry versions where data is identical to the previous version. Preserves published, scheduled, and latest draft versions.
|
|
87
|
-
```
|
|
88
111
|
|
|
89
112
|
## 0.1.4 — 2026-02-19
|
|
90
113
|
|
package/ROADMAP.md
CHANGED
|
@@ -72,6 +72,23 @@
|
|
|
72
72
|
- [x] `[fix]` `[P1]` False "Niezapisane zmiany" on entry load
|
|
73
73
|
- [x] `[fix]` `[P2]` Hide translation dots for non-required empty fields
|
|
74
74
|
|
|
75
|
+
## 0.5.2 — Update system fix
|
|
76
|
+
|
|
77
|
+
- [x] `[fix]` `[P1]` Split `migration` field into `sql` + `notes` — fixes CLI crash on text descriptions
|
|
78
|
+
|
|
79
|
+
## 0.5.3 — Form fields, inline blocks, hybrid preview
|
|
80
|
+
|
|
81
|
+
- [x] `[feature]` `[P1]` Form fields: select type, minLength/maxLength, errorMessage, remote commands
|
|
82
|
+
- [x] `[feature]` `[P1]` Conditional field visibility (showWhen)
|
|
83
|
+
- [x] `[feature]` `[P1]` Hybrid preview: device frames, container queries
|
|
84
|
+
- [x] `[feature]` `[P2]` TipTap placeholder extension + Notion-style styles
|
|
85
|
+
- [x] `[feature]` `[P1]` Server-side field resolution for inline blocks
|
|
86
|
+
- [x] `[feature]` `[P1]` Inline blocks: standalone form, field rendering, collapse UI
|
|
87
|
+
- [x] `[feature]` `[P2]` URL field: rel attribute, external auto-detect, UI redesign
|
|
88
|
+
- [x] `[feature]` `[P2]` Switch UI component + boolean field toggle
|
|
89
|
+
- [x] `[chore]` `[P2]` Storybook stories for all field types
|
|
90
|
+
- [x] `[chore]` `[P1]` Field components refactor: bindable value props
|
|
91
|
+
|
|
75
92
|
## 0.6.0 — Plugin system _(deferred from 0.2.0)_
|
|
76
93
|
|
|
77
94
|
- [ ] `[feature]` `[P0]` Wire plugin hooks into CRUD operations (before/afterCreate, Update, Delete) <!-- files: src/lib/types/plugins.ts, src/lib/core/server/entries/operations/ -->
|
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
import ArchiveIcon from '@tabler/icons-svelte/icons/archive';
|
|
14
14
|
import XIcon from '@tabler/icons-svelte/icons/x';
|
|
15
15
|
import Button from '../../../components/ui/button/button.svelte';
|
|
16
|
+
import { cn } from '../../../utils.js';
|
|
16
17
|
import { ElementSize, useDebounce } from 'runed';
|
|
17
18
|
import { defaults, superForm, type SuperForm } from 'sveltekit-superforms';
|
|
18
19
|
import { zod4, zod4Client } from 'sveltekit-superforms/adapters';
|
|
@@ -326,9 +327,7 @@
|
|
|
326
327
|
validationErrors = errors;
|
|
327
328
|
|
|
328
329
|
// Scroll to first errored field
|
|
329
|
-
const firstErrorKey = Object.keys(validatedForm.errors).find(
|
|
330
|
-
(k) => k !== '_errors'
|
|
331
|
-
);
|
|
330
|
+
const firstErrorKey = Object.keys(validatedForm.errors).find((k) => k !== '_errors');
|
|
332
331
|
if (firstErrorKey) {
|
|
333
332
|
scrollToIssue(firstErrorKey);
|
|
334
333
|
}
|
|
@@ -540,137 +539,145 @@
|
|
|
540
539
|
});
|
|
541
540
|
|
|
542
541
|
const t = $derived(lang[interfaceLanguage.current]);
|
|
542
|
+
const isHybrid = $derived(hybridContext.mode === 'hybrid' && !!collection.previewUrl);
|
|
543
543
|
</script>
|
|
544
544
|
|
|
545
|
-
<
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
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"
|
|
545
|
+
<div class={isHybrid ? 'flex h-full flex-col overflow-hidden' : ''}>
|
|
546
|
+
<EntryHeader
|
|
547
|
+
{entry}
|
|
548
|
+
version={editingEntry}
|
|
549
|
+
{onSave}
|
|
550
|
+
onSaveDraft={performAutosave}
|
|
551
|
+
{onArchive}
|
|
552
|
+
{saveStatus}
|
|
553
|
+
{isArchived}
|
|
554
|
+
fields={getFieldsFromConfig(collection)}
|
|
555
|
+
getFormData={() => get(form.form)}
|
|
556
|
+
onScrollToIssue={scrollToIssue}
|
|
557
|
+
{translationStatus}
|
|
558
|
+
/>
|
|
559
|
+
|
|
560
|
+
{#if validationErrors.length > 0}
|
|
561
|
+
<div
|
|
562
|
+
role="alert"
|
|
563
|
+
aria-live="assertive"
|
|
564
|
+
class="flex shrink-0 items-start gap-3 border-b border-[var(--error)]/20 bg-[#FDF0F0] px-6 py-3 text-sm text-[var(--error)]"
|
|
580
565
|
>
|
|
581
|
-
<
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
{
|
|
566
|
+
<AlertCircle class="mt-0.5 size-4 shrink-0" />
|
|
567
|
+
<div class="min-w-0 flex-1">
|
|
568
|
+
<p class="font-semibold">{t.cannotPublish}</p>
|
|
569
|
+
<p class="text-xs opacity-80">{t.validationHint}</p>
|
|
570
|
+
<ul class="mt-1 text-xs">
|
|
571
|
+
{#each validationErrors.slice(0, 5) as error}
|
|
572
|
+
<li>— {error}</li>
|
|
573
|
+
{/each}
|
|
574
|
+
</ul>
|
|
575
|
+
</div>
|
|
576
|
+
<button
|
|
577
|
+
type="button"
|
|
578
|
+
onclick={() => (validationErrors = [])}
|
|
579
|
+
class="shrink-0 rounded p-0.5 opacity-60 hover:opacity-100"
|
|
580
|
+
aria-label="Zamknij"
|
|
581
|
+
>
|
|
582
|
+
<XIcon class="size-4" />
|
|
583
|
+
</button>
|
|
584
|
+
</div>
|
|
585
|
+
{/if}
|
|
585
586
|
|
|
586
|
-
{#if isArchived}
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
587
|
+
{#if isArchived}
|
|
588
|
+
<div
|
|
589
|
+
role="alert"
|
|
590
|
+
class="flex shrink-0 items-center justify-between gap-3 border-b border-[var(--warning)]/20 bg-[#FDF6EC] px-6 py-3 text-sm"
|
|
591
|
+
>
|
|
592
|
+
<div class="flex items-center gap-2 text-[var(--warning)]">
|
|
593
|
+
<ArchiveIcon class="size-4 shrink-0" />
|
|
594
|
+
<span>{t.archivedBanner}</span>
|
|
595
|
+
</div>
|
|
596
|
+
<Button size="sm" onclick={onRestore}>{t.restore}</Button>
|
|
594
597
|
</div>
|
|
595
|
-
|
|
596
|
-
</div>
|
|
597
|
-
{/if}
|
|
598
|
+
{/if}
|
|
598
599
|
|
|
599
|
-
{#if showDraftBanner}
|
|
600
|
-
|
|
601
|
-
|
|
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}`)}
|
|
600
|
+
{#if showDraftBanner}
|
|
601
|
+
<div
|
|
602
|
+
class="flex shrink-0 items-center justify-between border-b bg-[var(--lavender-lighter)] px-6 py-2 text-sm"
|
|
608
603
|
>
|
|
609
|
-
{lang[interfaceLanguage.current].
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
604
|
+
<span class="text-[var(--text-secondary)]">{lang[interfaceLanguage.current].newerDraft}</span>
|
|
605
|
+
<button
|
|
606
|
+
type="button"
|
|
607
|
+
class="font-semibold text-[var(--primary)] hover:underline"
|
|
608
|
+
onclick={() => goto(`?version=${draftVersionId}`)}
|
|
609
|
+
>
|
|
610
|
+
{lang[interfaceLanguage.current].switchToDraft}
|
|
611
|
+
</button>
|
|
612
|
+
</div>
|
|
613
|
+
{:else if showPublishedBanner}
|
|
614
|
+
<div
|
|
615
|
+
class="flex shrink-0 items-center justify-between border-b bg-[var(--lavender-lighter)] px-6 py-2 text-sm"
|
|
616
|
+
>
|
|
617
|
+
<span class="text-[var(--text-secondary)]"
|
|
618
|
+
>{lang[interfaceLanguage.current].editingDraft}</span
|
|
619
|
+
>
|
|
620
|
+
<button
|
|
621
|
+
type="button"
|
|
622
|
+
class="font-semibold text-[var(--primary)] hover:underline"
|
|
623
|
+
onclick={() => goto(`?version=${entry.publishedVersion!.id}`)}
|
|
624
|
+
>
|
|
625
|
+
{lang[interfaceLanguage.current].switchToPublished}
|
|
626
|
+
</button>
|
|
627
|
+
</div>
|
|
628
|
+
{/if}
|
|
629
|
+
|
|
613
630
|
<div
|
|
614
|
-
class=
|
|
631
|
+
class={cn(
|
|
632
|
+
isArchived && 'pointer-events-none opacity-60',
|
|
633
|
+
isHybrid && 'flex min-h-0 flex-1 overflow-hidden'
|
|
634
|
+
)}
|
|
615
635
|
>
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
{
|
|
638
|
-
<
|
|
639
|
-
{
|
|
640
|
-
{
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
{size}
|
|
644
|
-
bind:el
|
|
636
|
+
{#if isHybrid}
|
|
637
|
+
{#await import('./hybrid/hybrid-layout.svelte')}
|
|
638
|
+
<div class="bg-accent h-full animate-pulse rounded-md"></div>
|
|
639
|
+
{:then { default: HybridLayout }}
|
|
640
|
+
<HybridLayout>
|
|
641
|
+
{#snippet preview()}
|
|
642
|
+
{#await import('./hybrid/hybrid-preview.svelte')}
|
|
643
|
+
<div class="bg-accent h-full animate-pulse rounded-md"></div>
|
|
644
|
+
{:then { default: HybridPreview }}
|
|
645
|
+
<HybridPreview
|
|
646
|
+
{collection}
|
|
647
|
+
{editingEntry}
|
|
648
|
+
bind:previewIframe
|
|
649
|
+
bind:sizePreset
|
|
650
|
+
{size}
|
|
651
|
+
bind:el
|
|
652
|
+
/>
|
|
653
|
+
{:catch}
|
|
654
|
+
<p class="text-destructive p-4 text-sm">Failed to load preview</p>
|
|
655
|
+
{/await}
|
|
656
|
+
{/snippet}
|
|
657
|
+
{#snippet formPanel()}
|
|
658
|
+
<EntryForm
|
|
659
|
+
{form}
|
|
660
|
+
{entry}
|
|
661
|
+
focusedPath={hybridContext.focusedPath}
|
|
662
|
+
onPathSelect={(path) => (hybridContext.focusedPath = path)}
|
|
645
663
|
/>
|
|
646
|
-
{
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
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>
|
|
667
|
-
{:else}
|
|
668
|
-
<div class="flex items-stretch justify-center" style="scroll-padding-top: 48px;">
|
|
669
|
-
<div class="max-w-2xl grow p-4 lg:p-6">
|
|
670
|
-
<div class="bg-card rounded-2xl border p-4 shadow-sm lg:p-6">
|
|
664
|
+
{/snippet}
|
|
665
|
+
</HybridLayout>
|
|
666
|
+
{:catch}
|
|
667
|
+
<p class="text-destructive p-4 text-sm">Failed to load layout</p>
|
|
668
|
+
{/await}
|
|
669
|
+
{:else if hasLayout(collection)}
|
|
670
|
+
<div class="overflow-y-auto" style="scroll-padding-top: 48px;">
|
|
671
671
|
<EntryForm {form} {entry} />
|
|
672
672
|
</div>
|
|
673
|
-
|
|
673
|
+
{:else}
|
|
674
|
+
<div class="flex items-stretch justify-center" style="scroll-padding-top: 48px;">
|
|
675
|
+
<div class="max-w-2xl grow p-4 lg:p-6">
|
|
676
|
+
<div class="bg-card rounded-2xl border p-4 shadow-sm lg:p-6">
|
|
677
|
+
<EntryForm {form} {entry} />
|
|
678
|
+
</div>
|
|
679
|
+
</div>
|
|
680
|
+
</div>
|
|
681
|
+
{/if}
|
|
674
682
|
</div>
|
|
675
|
-
{/if}
|
|
676
683
|
</div>
|
|
@@ -28,6 +28,36 @@
|
|
|
28
28
|
tablet: [768, 1024],
|
|
29
29
|
mobile: [375, 667]
|
|
30
30
|
} as const;
|
|
31
|
+
|
|
32
|
+
const deviceFrames = {
|
|
33
|
+
mobile: { padX: 16, padTop: 40, padBottom: 24, radius: 32, notch: 40 },
|
|
34
|
+
tablet: { padX: 20, padTop: 32, padBottom: 24, radius: 24, notch: 48 }
|
|
35
|
+
} as const;
|
|
36
|
+
|
|
37
|
+
const frameSize = $derived.by(() => {
|
|
38
|
+
if (sizePreset !== 'mobile' && sizePreset !== 'tablet') return null;
|
|
39
|
+
const frame = deviceFrames[sizePreset];
|
|
40
|
+
const [iw, ih] = sizePresets[sizePreset];
|
|
41
|
+
return {
|
|
42
|
+
w: iw + frame.padX * 2 + 16,
|
|
43
|
+
h: ih + frame.padTop + frame.padBottom + 16
|
|
44
|
+
};
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
const scale = $derived.by(() => {
|
|
48
|
+
if (sizePreset === 'responsive') return 1;
|
|
49
|
+
const cw = size.width;
|
|
50
|
+
const ch = size.height;
|
|
51
|
+
if (!cw || !ch) return 1;
|
|
52
|
+
|
|
53
|
+
if (sizePreset === 'desktop') {
|
|
54
|
+
const [iw, ih] = sizePresets.desktop;
|
|
55
|
+
return Math.min(cw / iw, ch / ih, 1);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
if (!frameSize) return 1;
|
|
59
|
+
return Math.min(cw / frameSize.w, ch / frameSize.h, 1) * 0.95;
|
|
60
|
+
});
|
|
31
61
|
</script>
|
|
32
62
|
|
|
33
63
|
<div class="flex h-full flex-col overflow-hidden">
|
|
@@ -56,14 +86,67 @@
|
|
|
56
86
|
</Button>
|
|
57
87
|
</div>
|
|
58
88
|
<div class="relative flex-1 overflow-hidden" bind:this={el}>
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
89
|
+
{#if sizePreset === 'responsive'}
|
|
90
|
+
<iframe
|
|
91
|
+
bind:this={previewIframe}
|
|
92
|
+
class="h-full w-full border-0"
|
|
93
|
+
src="{collection.previewUrl}?preview={editingEntry.id}"
|
|
94
|
+
title="preview"
|
|
95
|
+
></iframe>
|
|
96
|
+
{:else if sizePreset === 'desktop'}
|
|
97
|
+
<div class="flex h-full w-full items-center justify-center">
|
|
98
|
+
<iframe
|
|
99
|
+
bind:this={previewIframe}
|
|
100
|
+
style="transform: scale({scale}); transform-origin: center center;"
|
|
101
|
+
class="shrink-0 border-0"
|
|
102
|
+
width={sizePresets.desktop[0]}
|
|
103
|
+
height={sizePresets.desktop[1]}
|
|
104
|
+
src="{collection.previewUrl}?preview={editingEntry.id}"
|
|
105
|
+
title="preview"
|
|
106
|
+
></iframe>
|
|
107
|
+
</div>
|
|
108
|
+
{:else}
|
|
109
|
+
{@const frame = deviceFrames[sizePreset]}
|
|
110
|
+
{@const [iw, ih] = sizePresets[sizePreset]}
|
|
111
|
+
<div class="flex h-full w-full items-center justify-center">
|
|
112
|
+
<div
|
|
113
|
+
class="relative shrink-0 overflow-hidden"
|
|
114
|
+
style="
|
|
115
|
+
width: {iw + frame.padX * 2 + 16}px;
|
|
116
|
+
height: {ih + frame.padTop + frame.padBottom + 16}px;
|
|
117
|
+
border: 8px solid #1a1a2e;
|
|
118
|
+
border-radius: {frame.radius}px;
|
|
119
|
+
background: #000;
|
|
120
|
+
transform: scale({scale});
|
|
121
|
+
transform-origin: center center;
|
|
122
|
+
"
|
|
123
|
+
>
|
|
124
|
+
<!-- notch -->
|
|
125
|
+
<div
|
|
126
|
+
class="absolute left-1/2 -translate-x-1/2"
|
|
127
|
+
style="
|
|
128
|
+
top: {(frame.padTop - 6) / 2}px;
|
|
129
|
+
width: {frame.notch}px;
|
|
130
|
+
height: 6px;
|
|
131
|
+
background: #333;
|
|
132
|
+
border-radius: 3px;
|
|
133
|
+
"
|
|
134
|
+
></div>
|
|
135
|
+
<!-- iframe -->
|
|
136
|
+
<iframe
|
|
137
|
+
bind:this={previewIframe}
|
|
138
|
+
class="absolute border-0 bg-white"
|
|
139
|
+
style="
|
|
140
|
+
top: {frame.padTop}px;
|
|
141
|
+
left: {frame.padX}px;
|
|
142
|
+
"
|
|
143
|
+
width={iw}
|
|
144
|
+
height={ih}
|
|
145
|
+
src="{collection.previewUrl}?preview={editingEntry.id}"
|
|
146
|
+
title="preview"
|
|
147
|
+
></iframe>
|
|
148
|
+
</div>
|
|
149
|
+
</div>
|
|
150
|
+
{/if}
|
|
68
151
|
</div>
|
|
69
152
|
</div>
|
|
@@ -33,7 +33,8 @@
|
|
|
33
33
|
features: string;
|
|
34
34
|
fixes: string;
|
|
35
35
|
breaking: string;
|
|
36
|
-
|
|
36
|
+
sql: string;
|
|
37
|
+
notes: string;
|
|
37
38
|
empty: string;
|
|
38
39
|
}
|
|
39
40
|
> = {
|
|
@@ -42,7 +43,8 @@
|
|
|
42
43
|
features: 'Nowe funkcje',
|
|
43
44
|
fixes: 'Poprawki',
|
|
44
45
|
breaking: 'Zmiany wymagające uwagi',
|
|
45
|
-
|
|
46
|
+
sql: 'Migracja SQL',
|
|
47
|
+
notes: 'Uwagi do aktualizacji',
|
|
46
48
|
empty: 'Brak zmian w tej wersji.'
|
|
47
49
|
},
|
|
48
50
|
en: {
|
|
@@ -50,7 +52,8 @@
|
|
|
50
52
|
features: 'Features',
|
|
51
53
|
fixes: 'Fixes',
|
|
52
54
|
breaking: 'Breaking changes',
|
|
53
|
-
|
|
55
|
+
sql: 'SQL Migration',
|
|
56
|
+
notes: 'Update notes',
|
|
54
57
|
empty: 'No changes in this version.'
|
|
55
58
|
}
|
|
56
59
|
};
|
|
@@ -138,14 +141,21 @@
|
|
|
138
141
|
</div>
|
|
139
142
|
{/if}
|
|
140
143
|
|
|
141
|
-
{#if update.
|
|
144
|
+
{#if update.sql}
|
|
142
145
|
<details>
|
|
143
146
|
<summary class="cursor-pointer text-xs font-semibold text-foreground/60">
|
|
144
|
-
{t.
|
|
147
|
+
{t.sql}
|
|
145
148
|
</summary>
|
|
146
|
-
<pre class="mt-1 overflow-x-auto rounded-lg bg-muted p-2 text-xs">{update.
|
|
149
|
+
<pre class="mt-1 overflow-x-auto rounded-lg bg-muted p-2 text-xs">{update.sql}</pre>
|
|
147
150
|
</details>
|
|
148
151
|
{/if}
|
|
152
|
+
|
|
153
|
+
{#if update.notes}
|
|
154
|
+
<p class="text-xs text-foreground/60">
|
|
155
|
+
<span class="font-semibold">{t.notes}:</span>
|
|
156
|
+
{update.notes}
|
|
157
|
+
</p>
|
|
158
|
+
{/if}
|
|
149
159
|
</div>
|
|
150
160
|
{:else}
|
|
151
161
|
<p class="mt-1 text-xs text-foreground/50 italic">{t.empty}</p>
|