includio-cms 0.5.3 → 0.5.7
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 +71 -0
- package/ROADMAP.md +33 -0
- package/dist/admin/api/rest/handler.d.ts +7 -0
- package/dist/admin/api/rest/handler.js +116 -0
- package/dist/admin/api/rest/middleware/apiKey.d.ts +6 -0
- package/dist/admin/api/rest/middleware/apiKey.js +45 -0
- package/dist/admin/api/rest/routes/collections.d.ts +5 -0
- package/dist/admin/api/rest/routes/collections.js +104 -0
- package/dist/admin/api/rest/routes/entries.d.ts +2 -0
- package/dist/admin/api/rest/routes/entries.js +37 -0
- package/dist/admin/api/rest/routes/languages.d.ts +1 -0
- package/dist/admin/api/rest/routes/languages.js +5 -0
- package/dist/admin/api/rest/routes/schema.d.ts +2 -0
- package/dist/admin/api/rest/routes/schema.js +78 -0
- package/dist/admin/api/rest/routes/singletons.d.ts +3 -0
- package/dist/admin/api/rest/routes/singletons.js +60 -0
- package/dist/admin/auth-client.d.ts +48 -48
- package/dist/admin/client/admin/admin-after-login-layout.svelte +5 -3
- package/dist/admin/client/admin/admin-layout.svelte +0 -2
- package/dist/admin/client/collection/bulk-actions-bar.svelte +3 -1
- package/dist/admin/client/collection/bulk-actions-bar.svelte.d.ts +1 -1
- package/dist/admin/client/collection/collection-entries.svelte +334 -166
- package/dist/admin/client/collection/collection-page.svelte +6 -3
- package/dist/admin/client/collection/data-table.svelte +127 -18
- package/dist/admin/client/collection/data-table.svelte.d.ts +2 -0
- package/dist/admin/client/collection/row-actions.svelte +3 -1
- package/dist/admin/client/collection/row-actions.svelte.d.ts +1 -1
- package/dist/admin/client/entry/entry-page.svelte +5 -4
- package/dist/admin/client/form/form-config-wrapper.svelte +5 -3
- package/dist/admin/client/form/form-page.svelte +5 -5
- package/dist/admin/client/form/form-submission/form-submission-page.svelte +30 -32
- package/dist/admin/components/accessibility/accessibility-overview.svelte +7 -5
- package/dist/admin/components/accessibility/accessibility-overview.svelte.d.ts +2 -17
- package/dist/admin/components/dashboard/a11y-gauge.svelte +7 -4
- package/dist/admin/components/dashboard/a11y-gauge.svelte.d.ts +2 -17
- package/dist/admin/components/dashboard/accessibility-hub.svelte +7 -4
- package/dist/admin/components/dashboard/accessibility-hub.svelte.d.ts +2 -17
- package/dist/admin/components/dashboard/form-submissions-widget.svelte +8 -3
- package/dist/admin/components/dashboard/form-submissions-widget.svelte.d.ts +2 -17
- package/dist/admin/components/dashboard/recent-activity.svelte +8 -3
- package/dist/admin/components/dashboard/recent-activity.svelte.d.ts +2 -17
- package/dist/admin/components/dashboard/recent-entries.svelte +8 -3
- package/dist/admin/components/dashboard/recent-entries.svelte.d.ts +2 -17
- package/dist/admin/components/fields/image-field.svelte +21 -20
- package/dist/admin/components/fields/media-field.svelte +45 -44
- package/dist/admin/components/fields/relation-field.svelte +428 -149
- package/dist/admin/components/fields/relation-picker-dialog.svelte +112 -0
- package/dist/admin/components/fields/relation-picker-dialog.svelte.d.ts +22 -0
- package/dist/admin/components/fields/seo-field.svelte +66 -10
- package/dist/admin/components/icons/icon-map.d.ts +4 -0
- package/dist/admin/components/icons/icon-map.js +143 -0
- package/dist/admin/components/layout/header-actions.svelte +0 -10
- package/dist/admin/components/layout/nav-collections.svelte +55 -57
- package/dist/admin/components/layout/nav-collections.svelte.d.ts +2 -17
- package/dist/admin/components/layout/nav-forms.svelte +49 -49
- package/dist/admin/components/layout/nav-forms.svelte.d.ts +2 -17
- package/dist/admin/components/layout/nav-search.svelte +15 -22
- package/dist/admin/components/layout/nav-singletons.svelte +35 -38
- package/dist/admin/components/layout/nav-singletons.svelte.d.ts +2 -17
- package/dist/admin/components/media/file/file-preview.svelte +92 -91
- package/dist/admin/components/media/file-preview.svelte +17 -18
- package/dist/admin/components/media/media-library.svelte +39 -41
- package/dist/admin/components/media/media-selector.svelte +8 -8
- package/dist/admin/components/tiptap/InlineBlockNodeView.svelte +6 -8
- package/dist/admin/components/tiptap/content-editor.svelte +2 -2
- package/dist/admin/components/tiptap/editor-toolbar.svelte +1 -1
- package/dist/admin/components/tiptap/inline-block-node.d.ts +1 -0
- package/dist/admin/components/tiptap/inline-block-node.js +12 -1
- package/dist/admin/components/tiptap/tiptap-editor.svelte +1 -1
- package/dist/admin/remote/entry.remote.d.ts +20 -1
- package/dist/admin/remote/entry.remote.js +24 -3
- package/dist/admin/remote/invite.d.ts +2 -2
- package/dist/cli/scaffold/admin.js +8 -0
- package/dist/cms/runtime/remote.d.ts +8 -0
- package/dist/cms/runtime/remote.js +7 -0
- package/dist/cms/runtime/types.d.ts +1 -1
- package/dist/components/ui/input/input.svelte.d.ts +1 -1
- package/dist/components/ui/input-group/input-group-input.svelte.d.ts +1 -1
- package/dist/components/ui/sidebar/sidebar-input.svelte.d.ts +1 -1
- package/dist/components/ui/sonner/sonner.svelte +1 -2
- package/dist/core/cms.d.ts +2 -1
- package/dist/core/cms.js +2 -0
- package/dist/core/server/entries/operations/get.d.ts +11 -0
- package/dist/core/server/entries/operations/get.js +63 -1
- package/dist/core/server/entries/operations/update.d.ts +1 -0
- package/dist/core/server/entries/operations/update.js +5 -1
- package/dist/core/server/fields/resolveUrlFields.js +49 -18
- package/dist/db-postgres/schema/entry.d.ts +17 -0
- package/dist/db-postgres/schema/entry.js +4 -2
- package/dist/server/auth.d.ts +4 -4
- package/dist/sveltekit/components/structured-content.svelte +18 -5
- package/dist/sveltekit/server/handle.js +1 -0
- package/dist/types/cms.d.ts +7 -0
- package/dist/types/collections.d.ts +2 -0
- package/dist/types/config.d.ts +2 -2
- package/dist/types/entries.d.ts +7 -1
- package/dist/types/forms.d.ts +2 -0
- package/dist/types/index.d.ts +2 -1
- package/dist/types/index.js +1 -0
- package/dist/updates/0.5.4/index.d.ts +2 -0
- package/dist/updates/0.5.4/index.js +15 -0
- package/dist/updates/0.5.5/index.d.ts +2 -0
- package/dist/updates/0.5.5/index.js +20 -0
- package/dist/updates/0.5.6/index.d.ts +2 -0
- package/dist/updates/0.5.6/index.js +17 -0
- package/dist/updates/0.5.7/index.d.ts +2 -0
- package/dist/updates/0.5.7/index.js +14 -0
- package/dist/updates/index.js +5 -1
- package/package.json +6 -2
|
@@ -149,8 +149,10 @@
|
|
|
149
149
|
async function onTagUpdate(tagIds: string[]) {
|
|
150
150
|
if (currentFile) {
|
|
151
151
|
await remotes.setMediaFileTags({ fileId: currentFile.id, tagIds });
|
|
152
|
-
const tags =
|
|
153
|
-
|
|
152
|
+
const tags = tagsQuery.current as MediaTag[] | undefined;
|
|
153
|
+
if (tags) {
|
|
154
|
+
currentFile = { ...currentFile, tags: tags.filter((t) => tagIds.includes(t.id)) };
|
|
155
|
+
}
|
|
154
156
|
await filesQuery.refresh();
|
|
155
157
|
await allFilesQuery.refresh();
|
|
156
158
|
}
|
|
@@ -216,17 +218,17 @@
|
|
|
216
218
|
<div class="flex h-full overflow-hidden" bind:this={dropZoneRef}>
|
|
217
219
|
<!-- Tag sidebar (192px) -->
|
|
218
220
|
<aside class="w-48 min-w-48 shrink-0 border-r bg-card flex flex-col overflow-hidden" aria-label="Filtry tagów">
|
|
219
|
-
{#
|
|
221
|
+
{#if tagsQuery.ready && allFilesQuery.ready && tagsQuery.current && allFilesQuery.current}
|
|
220
222
|
<TagSidebar
|
|
221
|
-
{
|
|
222
|
-
files={
|
|
223
|
+
tags={tagsQuery.current}
|
|
224
|
+
files={allFilesQuery.current}
|
|
223
225
|
activeFilter={activeTagFilter}
|
|
224
226
|
onFilterChange={(f) => (activeTagFilter = f)}
|
|
225
227
|
onCreateTag={handleCreateTag}
|
|
226
228
|
onUpdateTag={handleUpdateTag}
|
|
227
229
|
onDeleteTag={handleDeleteTag}
|
|
228
230
|
/>
|
|
229
|
-
{/
|
|
231
|
+
{/if}
|
|
230
232
|
</aside>
|
|
231
233
|
|
|
232
234
|
<!-- Main content (flex-1) -->
|
|
@@ -259,20 +261,20 @@
|
|
|
259
261
|
|
|
260
262
|
<!-- File grid -->
|
|
261
263
|
<div class="flex-1 overflow-y-auto px-5 pt-4 pb-24 scrollbar-thin" role="listbox" aria-multiselectable="true" aria-label="Siatka plików">
|
|
262
|
-
<div class="grid grid-cols-[repeat(auto-fill,minmax(9rem,1fr))] gap-3">
|
|
263
|
-
{#
|
|
264
|
+
<div class="grid grid-cols-[repeat(auto-fill,minmax(9rem,1fr))] gap-3" class:opacity-60={filesQuery.loading} style="transition: opacity 200ms">
|
|
265
|
+
{#if !filesQuery.ready}
|
|
264
266
|
{#each Array(8) as _}
|
|
265
267
|
<Skeleton class="block h-[168px] rounded-xl" />
|
|
266
268
|
{/each}
|
|
267
|
-
{:
|
|
269
|
+
{:else if filesQuery.current}
|
|
268
270
|
<FilesList
|
|
269
|
-
{
|
|
271
|
+
files={filesQuery.current}
|
|
270
272
|
selected={selectedFileIds.length > 0 ? selectedFileIds : (selected ?? '')}
|
|
271
273
|
onSelect={handleFileSelect}
|
|
272
274
|
onRangeSelect={handleRangeSelect}
|
|
273
275
|
{selectionMode}
|
|
274
276
|
/>
|
|
275
|
-
{/
|
|
277
|
+
{/if}
|
|
276
278
|
</div>
|
|
277
279
|
</div>
|
|
278
280
|
</section>
|
|
@@ -280,22 +282,20 @@
|
|
|
280
282
|
<!-- Detail panel (384px) -->
|
|
281
283
|
<aside class="w-96 min-w-96 shrink-0 border-l bg-card flex flex-col overflow-hidden" aria-label="Szczegóły pliku">
|
|
282
284
|
{#if selectionMode}
|
|
283
|
-
{#
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
{/await}
|
|
292
|
-
{/await}
|
|
285
|
+
{#if filesQuery.ready && filesQuery.current && tagsQuery.ready && tagsQuery.current}
|
|
286
|
+
<MultiFileSummary
|
|
287
|
+
files={filesQuery.current.filter((f) => selectedFileIds.includes(f.id))}
|
|
288
|
+
allTags={tagsQuery.current}
|
|
289
|
+
onBulkTag={handleBulkTag}
|
|
290
|
+
onBulkDelete={handleBulkDelete}
|
|
291
|
+
/>
|
|
292
|
+
{/if}
|
|
293
293
|
{:else if currentFile}
|
|
294
294
|
{#key currentFile}
|
|
295
|
-
{#
|
|
295
|
+
{#if tagsQuery.ready && tagsQuery.current}
|
|
296
296
|
<FileDetails
|
|
297
297
|
file={currentFile}
|
|
298
|
-
allTags={
|
|
298
|
+
allTags={tagsQuery.current}
|
|
299
299
|
onDelete={deleteFileCommand}
|
|
300
300
|
onReplace={(updated) => {
|
|
301
301
|
currentFile = updated;
|
|
@@ -305,7 +305,7 @@
|
|
|
305
305
|
{onTagUpdate}
|
|
306
306
|
{onNameUpdate}
|
|
307
307
|
/>
|
|
308
|
-
{/
|
|
308
|
+
{/if}
|
|
309
309
|
{/key}
|
|
310
310
|
{:else}
|
|
311
311
|
<!-- Empty state -->
|
|
@@ -323,21 +323,19 @@
|
|
|
323
323
|
</div>
|
|
324
324
|
|
|
325
325
|
<!-- Bulk action bar -->
|
|
326
|
-
{#if selectedFileIds.length > 0}
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
/>
|
|
342
|
-
{/await}
|
|
326
|
+
{#if selectedFileIds.length > 0 && tagsQuery.ready && tagsQuery.current && allFilesQuery.ready && allFilesQuery.current}
|
|
327
|
+
<BulkActionBar
|
|
328
|
+
selectedCount={selectedFileIds.length}
|
|
329
|
+
totalCount={allFilesQuery.current.length}
|
|
330
|
+
tags={tagsQuery.current}
|
|
331
|
+
onBulkTag={handleBulkTag}
|
|
332
|
+
onBulkDelete={handleBulkDelete}
|
|
333
|
+
onClear={exitSelectionMode}
|
|
334
|
+
onSelectAll={() => { selectedFileIds = allFilesQuery.current!.map((f) => f.id); }}
|
|
335
|
+
onCreateTag={handleCreateTag}
|
|
336
|
+
onUpdateTagColor={async (id, color) => {
|
|
337
|
+
const tag = tagsQuery.current?.find((t) => t.id === id);
|
|
338
|
+
if (tag) await handleUpdateTag(id, tag.name, color);
|
|
339
|
+
}}
|
|
340
|
+
/>
|
|
343
341
|
{/if}
|
|
@@ -112,9 +112,9 @@
|
|
|
112
112
|
<div class="flex min-h-0 flex-1 overflow-hidden">
|
|
113
113
|
<!-- Tag sidebar -->
|
|
114
114
|
<div class="w-44 shrink-0 border-r p-3 overflow-y-auto">
|
|
115
|
-
{#
|
|
115
|
+
{#if tagsQuery.ready && tagsQuery.current}
|
|
116
116
|
<TagSidebar
|
|
117
|
-
{
|
|
117
|
+
tags={tagsQuery.current}
|
|
118
118
|
files={[]}
|
|
119
119
|
activeFilter={activeTagFilter}
|
|
120
120
|
onFilterChange={(f) => (activeTagFilter = f)}
|
|
@@ -131,7 +131,7 @@
|
|
|
131
131
|
await tagsQuery.refresh();
|
|
132
132
|
}}
|
|
133
133
|
/>
|
|
134
|
-
{/
|
|
134
|
+
{/if}
|
|
135
135
|
</div>
|
|
136
136
|
|
|
137
137
|
<!-- Main content -->
|
|
@@ -149,14 +149,14 @@
|
|
|
149
149
|
|
|
150
150
|
<!-- Grid z plikami -->
|
|
151
151
|
<div class="flex-1 overflow-y-auto pr-2">
|
|
152
|
-
<div class="grid grid-cols-[repeat(auto-fill,minmax(9rem,1fr))] gap-3 p-4">
|
|
153
|
-
{#
|
|
152
|
+
<div class="grid grid-cols-[repeat(auto-fill,minmax(9rem,1fr))] gap-3 p-4" class:opacity-60={filesQuery.loading} style="transition: opacity 200ms">
|
|
153
|
+
{#if !filesQuery.ready}
|
|
154
154
|
{#each Array(8) as _}
|
|
155
155
|
<Skeleton class="block aspect-square rounded-2xl" />
|
|
156
156
|
{/each}
|
|
157
|
-
{:
|
|
157
|
+
{:else if filesQuery.current}
|
|
158
158
|
<FilesList
|
|
159
|
-
{
|
|
159
|
+
files={filesQuery.current}
|
|
160
160
|
selected={stagedSelection}
|
|
161
161
|
onSelect={(file) => {
|
|
162
162
|
currentFile = file;
|
|
@@ -169,7 +169,7 @@
|
|
|
169
169
|
}
|
|
170
170
|
}}
|
|
171
171
|
/>
|
|
172
|
-
{/
|
|
172
|
+
{/if}
|
|
173
173
|
</div>
|
|
174
174
|
</div>
|
|
175
175
|
</div>
|
|
@@ -14,10 +14,11 @@
|
|
|
14
14
|
import { onMount, onDestroy } from 'svelte';
|
|
15
15
|
import type { FormPathLeaves } from 'sveltekit-superforms';
|
|
16
16
|
import { evaluateCondition } from '../../utils/fieldCondition.js';
|
|
17
|
+
import { isRecentlyInserted } from './inline-block-node.js';
|
|
17
18
|
|
|
18
|
-
let { node, updateAttributes, editor, getPos, deleteNode
|
|
19
|
+
let { node, updateAttributes, editor, getPos, deleteNode }: NodeViewProps = $props();
|
|
19
20
|
|
|
20
|
-
let collapsed = $state(
|
|
21
|
+
let collapsed = $state(!isRecentlyInserted(node.attrs.blockId));
|
|
21
22
|
|
|
22
23
|
const contentLanguage = getContentLanguage();
|
|
23
24
|
|
|
@@ -243,7 +244,7 @@
|
|
|
243
244
|
}
|
|
244
245
|
</script>
|
|
245
246
|
|
|
246
|
-
<NodeViewWrapper class="inline-block-node
|
|
247
|
+
<NodeViewWrapper class="inline-block-node" data-drag-handle>
|
|
247
248
|
<div class="inline-block-wrapper">
|
|
248
249
|
<!-- Header -->
|
|
249
250
|
<div class="inline-block-header">
|
|
@@ -308,17 +309,13 @@
|
|
|
308
309
|
border-radius: 12px;
|
|
309
310
|
overflow: hidden;
|
|
310
311
|
margin: 0.5rem 0;
|
|
311
|
-
background: var(--surface, var(--
|
|
312
|
+
background: var(--surface, var(--muted));
|
|
312
313
|
}
|
|
313
314
|
|
|
314
315
|
.inline-block-wrapper:hover {
|
|
315
316
|
border-color: color-mix(in oklch, var(--primary) 50%, transparent);
|
|
316
317
|
}
|
|
317
318
|
|
|
318
|
-
:global(.selected) .inline-block-wrapper {
|
|
319
|
-
border-color: color-mix(in oklch, var(--primary) 50%, transparent);
|
|
320
|
-
}
|
|
321
|
-
|
|
322
319
|
.inline-block-header {
|
|
323
320
|
display: flex;
|
|
324
321
|
align-items: center;
|
|
@@ -441,4 +438,5 @@
|
|
|
441
438
|
font-size: 0.8125rem;
|
|
442
439
|
font-style: italic;
|
|
443
440
|
}
|
|
441
|
+
|
|
444
442
|
</style>
|
|
@@ -126,7 +126,7 @@
|
|
|
126
126
|
</script>
|
|
127
127
|
|
|
128
128
|
<Tooltip.Provider>
|
|
129
|
-
<div class="border-input bg-
|
|
129
|
+
<div class="border-input bg-card rounded-lg border">
|
|
130
130
|
<!-- Toolbar — no code view for content editor -->
|
|
131
131
|
{#if ed}
|
|
132
132
|
<EditorToolbar
|
|
@@ -267,7 +267,7 @@
|
|
|
267
267
|
<!-- Editor content -->
|
|
268
268
|
<div
|
|
269
269
|
bind:this={element}
|
|
270
|
-
class="prose prose-sm dark:prose-invert max-w-none p-4 focus:outline-none [&_.ProseMirror]:min-h-[200px] [&_.ProseMirror]:outline-none [&_.ProseMirror]:scroll-padding-top-12"
|
|
270
|
+
class="prose prose-sm dark:prose-invert max-w-none p-4 focus:outline-none overflow-y-auto max-h-[70vh] [&_.ProseMirror]:min-h-[200px] [&_.ProseMirror]:outline-none [&_.ProseMirror]:scroll-padding-top-12"
|
|
271
271
|
></div>
|
|
272
272
|
</div>
|
|
273
273
|
</Tooltip.Provider>
|
|
@@ -57,7 +57,7 @@
|
|
|
57
57
|
</script>
|
|
58
58
|
|
|
59
59
|
<Tooltip.Provider>
|
|
60
|
-
<div class="flex flex-wrap items-center gap-0.5 border-b p-1 sticky top-0 z-10 bg-
|
|
60
|
+
<div class="flex flex-wrap items-center gap-0.5 border-b p-1 sticky top-0 z-10 bg-muted/50">
|
|
61
61
|
<!-- Headings -->
|
|
62
62
|
<ToolbarButton
|
|
63
63
|
label="Nagłówek 2"
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Node } from '@tiptap/core';
|
|
2
2
|
import type { ObjectField } from '../../../types/fields.js';
|
|
3
|
+
export declare function isRecentlyInserted(id: string): boolean;
|
|
3
4
|
export interface InlineBlockOptions {
|
|
4
5
|
HTMLAttributes: Record<string, string>;
|
|
5
6
|
inlineBlocks: ObjectField[];
|
|
@@ -1,6 +1,14 @@
|
|
|
1
1
|
import { Node, mergeAttributes } from '@tiptap/core';
|
|
2
2
|
import { SvelteNodeViewRenderer } from 'svelte-tiptap';
|
|
3
3
|
import InlineBlockNodeView from './InlineBlockNodeView.svelte';
|
|
4
|
+
const recentlyInsertedIds = new Set();
|
|
5
|
+
export function isRecentlyInserted(id) {
|
|
6
|
+
if (recentlyInsertedIds.has(id)) {
|
|
7
|
+
recentlyInsertedIds.delete(id);
|
|
8
|
+
return true;
|
|
9
|
+
}
|
|
10
|
+
return false;
|
|
11
|
+
}
|
|
4
12
|
/** Build default data for an inline block from its field definitions. */
|
|
5
13
|
export function buildDefaultData(blockType, inlineBlocks) {
|
|
6
14
|
const def = inlineBlocks.find((b) => b.slug === blockType);
|
|
@@ -50,6 +58,7 @@ export const InlineBlockNode = Node.create({
|
|
|
50
58
|
name: 'inlineBlock',
|
|
51
59
|
group: 'block',
|
|
52
60
|
atom: true,
|
|
61
|
+
selectable: false,
|
|
53
62
|
draggable: true,
|
|
54
63
|
isolating: true,
|
|
55
64
|
addOptions() {
|
|
@@ -96,12 +105,14 @@ export const InlineBlockNode = Node.create({
|
|
|
96
105
|
return {
|
|
97
106
|
insertInlineBlock: ({ blockType, blockData }) => ({ commands }) => {
|
|
98
107
|
const data = blockData ?? buildDefaultData(blockType, this.options.inlineBlocks);
|
|
108
|
+
const blockId = crypto.randomUUID();
|
|
109
|
+
recentlyInsertedIds.add(blockId);
|
|
99
110
|
return commands.insertContent({
|
|
100
111
|
type: this.name,
|
|
101
112
|
attrs: {
|
|
102
113
|
blockType,
|
|
103
114
|
blockData: JSON.stringify(data),
|
|
104
|
-
blockId
|
|
115
|
+
blockId
|
|
105
116
|
}
|
|
106
117
|
});
|
|
107
118
|
}
|
|
@@ -231,7 +231,7 @@
|
|
|
231
231
|
<!-- Editor content -->
|
|
232
232
|
<div
|
|
233
233
|
bind:this={element}
|
|
234
|
-
class="prose prose-sm dark:prose-invert max-w-none p-4 focus:outline-none [&_.ProseMirror]:min-h-[200px] [&_.ProseMirror]:outline-none {isCodeViewActive && 'hidden'}"
|
|
234
|
+
class="prose prose-sm dark:prose-invert max-w-none p-4 focus:outline-none overflow-y-auto max-h-[70vh] [&_.ProseMirror]:min-h-[200px] [&_.ProseMirror]:outline-none {isCodeViewActive && 'hidden'}"
|
|
235
235
|
></div>
|
|
236
236
|
|
|
237
237
|
<!-- HTML textarea -->
|
|
@@ -6,7 +6,7 @@ export declare const getRawEntries: import("@sveltejs/kit").RemoteQueryFunction<
|
|
|
6
6
|
limit?: number | undefined;
|
|
7
7
|
offset?: number | undefined;
|
|
8
8
|
orderBy?: {
|
|
9
|
-
column: "createdAt" | "updatedAt";
|
|
9
|
+
column: "createdAt" | "updatedAt" | "sortOrder";
|
|
10
10
|
direction: "asc" | "desc";
|
|
11
11
|
} | undefined;
|
|
12
12
|
}, {
|
|
@@ -20,7 +20,22 @@ export declare const getEntries: import("@sveltejs/kit").RemoteQueryFunction<{
|
|
|
20
20
|
language?: string | undefined;
|
|
21
21
|
status?: "draft" | "published" | "scheduled" | "archived" | undefined;
|
|
22
22
|
slug?: string | undefined;
|
|
23
|
+
orderBy?: {
|
|
24
|
+
column: "createdAt" | "updatedAt" | "sortOrder";
|
|
25
|
+
direction: "asc" | "desc";
|
|
26
|
+
} | undefined;
|
|
23
27
|
}, import("../../types/entries.js").Entry[]>;
|
|
28
|
+
export declare const getEntryLabels: import("@sveltejs/kit").RemoteQueryFunction<{
|
|
29
|
+
slug: string;
|
|
30
|
+
ids?: string[] | undefined;
|
|
31
|
+
search?: string | undefined;
|
|
32
|
+
limit?: number | undefined;
|
|
33
|
+
status?: "draft" | "published" | "all" | undefined;
|
|
34
|
+
}, {
|
|
35
|
+
id: string;
|
|
36
|
+
label: string;
|
|
37
|
+
total: number;
|
|
38
|
+
}[]>;
|
|
24
39
|
export declare const getEntry: import("@sveltejs/kit").RemoteQueryFunction<{
|
|
25
40
|
id?: string | undefined;
|
|
26
41
|
dataValues?: Record<string, unknown> | undefined;
|
|
@@ -53,11 +68,15 @@ export declare const updateEntryCommand: import("@sveltejs/kit").RemoteCommand<{
|
|
|
53
68
|
publishedAt?: Date | null | undefined;
|
|
54
69
|
publishedVersionId?: string | null | undefined;
|
|
55
70
|
publishedBy?: string | null | undefined;
|
|
71
|
+
sortOrder?: number | null | undefined;
|
|
56
72
|
};
|
|
57
73
|
}, Promise<import("../../types/entries.js").DbEntry>>;
|
|
58
74
|
export declare const archiveEntryCommand: import("@sveltejs/kit").RemoteCommand<string, Promise<import("../../types/entries.js").DbEntry>>;
|
|
59
75
|
export declare const unarchiveEntryCommand: import("@sveltejs/kit").RemoteCommand<string, Promise<import("../../types/entries.js").DbEntry>>;
|
|
60
76
|
export declare const deleteEntryCommand: import("@sveltejs/kit").RemoteCommand<string, Promise<void>>;
|
|
77
|
+
export declare const reorderEntriesCommand: import("@sveltejs/kit").RemoteCommand<{
|
|
78
|
+
orderedIds: string[];
|
|
79
|
+
}, Promise<void>>;
|
|
61
80
|
export declare const getEntryVersion: import("@sveltejs/kit").RemoteQueryFunction<{
|
|
62
81
|
id: string;
|
|
63
82
|
language: string;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { command, query } from '$app/server';
|
|
2
2
|
import { createEntry as createEntryOperation, createEntrySchema, createEntryVersion } from '../../core/server/entries/operations/create.js';
|
|
3
|
-
import { getRawEntries as getRawEntriesOperation, countRawEntries as countRawEntriesOperation, getRawEntry as getRawEntryOperation, getRawEntryOrThrow, getDbEntry, getDbEntryOrThrow, getEntries as getEntriesOperation, getEntry as getEntryOperation, getEntryVersion as getEntryVersionOperation } from '../../core/server/entries/operations/get.js';
|
|
3
|
+
import { getRawEntries as getRawEntriesOperation, countRawEntries as countRawEntriesOperation, getRawEntry as getRawEntryOperation, getRawEntryOrThrow, getDbEntry, getDbEntryOrThrow, getEntries as getEntriesOperation, getEntry as getEntryOperation, getEntryVersion as getEntryVersionOperation, getEntryLabels as getEntryLabelsOperation } from '../../core/server/entries/operations/get.js';
|
|
4
4
|
import { getCMS } from '../../core/cms.js';
|
|
5
5
|
import { pruneOldDraftVersions, unpublishEntry, upsertDraftVersion, updateEntry, updateEntrySchema, updateEntryVersionCommandTypes } from '../../core/server/entries/operations/update.js';
|
|
6
6
|
import z from 'zod';
|
|
@@ -14,7 +14,7 @@ export const getRawEntries = query(z.object({
|
|
|
14
14
|
offset: z.number().int().nonnegative().optional(),
|
|
15
15
|
orderBy: z
|
|
16
16
|
.object({
|
|
17
|
-
column: z.enum(['createdAt', 'updatedAt']),
|
|
17
|
+
column: z.enum(['createdAt', 'updatedAt', 'sortOrder']),
|
|
18
18
|
direction: z.enum(['asc', 'desc'])
|
|
19
19
|
})
|
|
20
20
|
.optional()
|
|
@@ -32,10 +32,25 @@ export const getEntries = query(z.object({
|
|
|
32
32
|
dataLike: z.record(z.string(), z.unknown()).optional(),
|
|
33
33
|
language: z.string().optional(),
|
|
34
34
|
status: z.enum(entryStatuses).optional(),
|
|
35
|
-
slug: z.string().optional()
|
|
35
|
+
slug: z.string().optional(),
|
|
36
|
+
orderBy: z
|
|
37
|
+
.object({
|
|
38
|
+
column: z.enum(['createdAt', 'updatedAt', 'sortOrder']),
|
|
39
|
+
direction: z.enum(['asc', 'desc'])
|
|
40
|
+
})
|
|
41
|
+
.optional()
|
|
36
42
|
}), async (input) => {
|
|
37
43
|
return getEntriesOperation(input);
|
|
38
44
|
});
|
|
45
|
+
export const getEntryLabels = query(z.object({
|
|
46
|
+
slug: z.string(),
|
|
47
|
+
ids: z.array(z.string()).optional(),
|
|
48
|
+
search: z.string().optional(),
|
|
49
|
+
limit: z.number().int().positive().optional(),
|
|
50
|
+
status: z.enum(['published', 'draft', 'all']).optional()
|
|
51
|
+
}), async (input) => {
|
|
52
|
+
return getEntryLabelsOperation(input);
|
|
53
|
+
});
|
|
39
54
|
export const getEntry = query(z.object({
|
|
40
55
|
id: z.string().uuid().optional(),
|
|
41
56
|
dataValues: z.record(z.string(), z.unknown()).optional(),
|
|
@@ -172,6 +187,12 @@ export const deleteEntryCommand = command(z.string().uuid(), async (id) => {
|
|
|
172
187
|
}
|
|
173
188
|
return getCMS().databaseAdapter.deleteEntry({ id });
|
|
174
189
|
});
|
|
190
|
+
export const reorderEntriesCommand = command(z.object({
|
|
191
|
+
orderedIds: z.array(z.string().uuid())
|
|
192
|
+
}), async ({ orderedIds }) => {
|
|
193
|
+
requireAuth();
|
|
194
|
+
await Promise.all(orderedIds.map((id, index) => updateEntry(id, { sortOrder: index })));
|
|
195
|
+
});
|
|
175
196
|
export const getEntryVersion = query(z.object({
|
|
176
197
|
id: z.string().uuid(),
|
|
177
198
|
language: z.string()
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import type { UserRole } from '../../types/roles.js';
|
|
2
2
|
export declare function createInvitation(email: string, role: UserRole, createdBy: string): Promise<{
|
|
3
|
+
id: string;
|
|
4
|
+
role: string;
|
|
3
5
|
createdAt: Date;
|
|
4
6
|
email: string;
|
|
5
|
-
id: string;
|
|
6
7
|
expiresAt: Date;
|
|
7
8
|
token: string;
|
|
8
|
-
role: string;
|
|
9
9
|
createdBy: string;
|
|
10
10
|
usedAt: Date | null;
|
|
11
11
|
}>;
|
|
@@ -156,6 +156,14 @@ export * from 'includio-cms/admin/remote';
|
|
|
156
156
|
import { createAdminApiHandler } from 'includio-cms/admin/api/handler';
|
|
157
157
|
|
|
158
158
|
export const { GET, POST, PATCH, PUT, DELETE } = createAdminApiHandler();
|
|
159
|
+
`
|
|
160
|
+
},
|
|
161
|
+
{
|
|
162
|
+
path: 'admin/api/rest/[...restPath]/+server.ts',
|
|
163
|
+
content: `${GENERATED_COMMENT_TS}
|
|
164
|
+
import { createRestApiHandler } from 'includio-cms/admin/api/rest/handler';
|
|
165
|
+
|
|
166
|
+
export const { GET, POST, PUT, DELETE } = createRestApiHandler();
|
|
159
167
|
`
|
|
160
168
|
}
|
|
161
169
|
];
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
// This file is auto-generated. Do not edit directly.
|
|
2
|
+
import { command } from '$app/server';
|
|
3
|
+
import { submitForm } from './api';
|
|
4
|
+
import { contactFormSchema } from './schemas';
|
|
5
|
+
export const submitContactCommand = command(contactFormSchema, async (data) => {
|
|
6
|
+
await submitForm('contact', data);
|
|
7
|
+
});
|
|
@@ -8,6 +8,6 @@ type Props = WithElementRef<Omit<HTMLInputAttributes, "type"> & ({
|
|
|
8
8
|
type?: InputType;
|
|
9
9
|
files?: undefined;
|
|
10
10
|
})>;
|
|
11
|
-
declare const Input: import("svelte").Component<Props, {}, "
|
|
11
|
+
declare const Input: import("svelte").Component<Props, {}, "files" | "ref" | "value">;
|
|
12
12
|
type Input = ReturnType<typeof Input>;
|
|
13
13
|
export default Input;
|
|
@@ -2,7 +2,7 @@ declare const InputGroupInput: import("svelte").Component<(Omit<import("svelte/e
|
|
|
2
2
|
type: "file";
|
|
3
3
|
files?: FileList;
|
|
4
4
|
} | {
|
|
5
|
-
type?: "number" | "image" | "url" | "text" | "date" | "radio" | "
|
|
5
|
+
type?: "number" | "image" | "url" | "text" | "date" | "radio" | "color" | "button" | "checkbox" | "search" | (string & {}) | "email" | "hidden" | "password" | "reset" | "time" | "submit" | "tel" | "datetime-local" | "month" | "range" | "week";
|
|
6
6
|
files?: undefined;
|
|
7
7
|
})) & {
|
|
8
8
|
ref?: HTMLElement | null | undefined;
|
|
@@ -2,7 +2,7 @@ declare const SidebarInput: import("svelte").Component<(Omit<import("svelte/elem
|
|
|
2
2
|
type: "file";
|
|
3
3
|
files?: FileList;
|
|
4
4
|
} | {
|
|
5
|
-
type?: "number" | "image" | "url" | "text" | "date" | "radio" | "
|
|
5
|
+
type?: "number" | "image" | "url" | "text" | "date" | "radio" | "color" | "button" | "checkbox" | "search" | (string & {}) | "email" | "hidden" | "password" | "reset" | "time" | "submit" | "tel" | "datetime-local" | "month" | "range" | "week";
|
|
6
6
|
files?: undefined;
|
|
7
7
|
})) & {
|
|
8
8
|
ref?: HTMLElement | null | undefined;
|
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import { Toaster as Sonner, type ToasterProps as SonnerProps } from "svelte-sonner";
|
|
3
|
-
import { mode } from "mode-watcher";
|
|
4
3
|
|
|
5
4
|
let { richColors = false, ...restProps }: SonnerProps = $props();
|
|
6
5
|
</script>
|
|
7
6
|
|
|
8
7
|
<Sonner
|
|
9
|
-
theme=
|
|
8
|
+
theme="light"
|
|
10
9
|
class="toaster group"
|
|
11
10
|
{richColors}
|
|
12
11
|
style="
|
package/dist/core/cms.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { DatabaseAdapter } from '../types/adapters/db.js';
|
|
2
2
|
import type { FilesAdapter } from '../types/adapters/files.js';
|
|
3
|
-
import type { CMSConfig, ICMS, MediaConfig } from '../types/cms.js';
|
|
3
|
+
import type { ApiKeyConfig, CMSConfig, ICMS, MediaConfig } from '../types/cms.js';
|
|
4
4
|
import type { CollectionConfigWithType } from '../types/collections.js';
|
|
5
5
|
import type { Language } from '../types/languages.js';
|
|
6
6
|
import type { SingleConfigWithType } from '../types/singles.js';
|
|
@@ -22,6 +22,7 @@ export declare class CMS implements ICMS {
|
|
|
22
22
|
languages: Language[];
|
|
23
23
|
mediaConfig: MediaConfig;
|
|
24
24
|
plugins: PluginConfig[];
|
|
25
|
+
apiKeys: ApiKeyConfig[];
|
|
25
26
|
constructor(config: CMSConfig);
|
|
26
27
|
getBySlug(slug: string): CollectionConfigWithType | SingleConfigWithType;
|
|
27
28
|
getFormBySlug(slug: string): FormConfig;
|
package/dist/core/cms.js
CHANGED
|
@@ -11,6 +11,7 @@ export class CMS {
|
|
|
11
11
|
languages;
|
|
12
12
|
mediaConfig;
|
|
13
13
|
plugins = [];
|
|
14
|
+
apiKeys = [];
|
|
14
15
|
constructor(config) {
|
|
15
16
|
this.config = config;
|
|
16
17
|
this.databaseAdapter = config.db;
|
|
@@ -40,6 +41,7 @@ export class CMS {
|
|
|
40
41
|
};
|
|
41
42
|
});
|
|
42
43
|
this.languages = config.languages || [];
|
|
44
|
+
this.apiKeys = config.apiKeys || [];
|
|
43
45
|
if (config.plugins) {
|
|
44
46
|
this.plugins = config.plugins;
|
|
45
47
|
}
|
|
@@ -10,6 +10,17 @@ export declare const getRawEntryOrThrow: (options: getRawEntryOptions) => Promis
|
|
|
10
10
|
export declare const getEntries: (options?: GetEntriesOptions) => Promise<Entry[]>;
|
|
11
11
|
export declare const getEntry: (options?: GetEntryOptions) => Promise<Entry | null>;
|
|
12
12
|
export declare const getEntryOrThrow: (options?: GetEntryOptions) => Promise<Entry>;
|
|
13
|
+
export declare const getEntryLabels: (options: {
|
|
14
|
+
slug: string;
|
|
15
|
+
ids?: string[];
|
|
16
|
+
search?: string;
|
|
17
|
+
limit?: number;
|
|
18
|
+
status?: "published" | "draft" | "all";
|
|
19
|
+
}) => Promise<{
|
|
20
|
+
id: string;
|
|
21
|
+
label: string;
|
|
22
|
+
total: number;
|
|
23
|
+
}[]>;
|
|
13
24
|
export declare const getDbEntryVersions: (options: GetDbEntryVersionsOptions) => Promise<DbEntryVersion[]>;
|
|
14
25
|
export declare const getDbEntryVersion: (options: GetDbEntryVersionOptions) => Promise<DbEntryVersion | null>;
|
|
15
26
|
export declare const getDbEntryVersionOrThrow: (options: GetDbEntryVersionOptions) => Promise<DbEntryVersion>;
|