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
|
@@ -15,6 +15,8 @@
|
|
|
15
15
|
import * as Table from '../../../components/ui/table/index.js';
|
|
16
16
|
import { useInterfaceLanguage } from '../../state/interface-language.svelte.js';
|
|
17
17
|
import type { InterfaceLanguage } from '../../../types/languages.js';
|
|
18
|
+
import { droppable, draggable, dndState } from '@thisux/sveltednd';
|
|
19
|
+
import { flip } from 'svelte/animate';
|
|
18
20
|
|
|
19
21
|
type DataTableProps<TData, TValue> = {
|
|
20
22
|
columns: ColumnDef<TData, TValue>[];
|
|
@@ -35,6 +37,8 @@
|
|
|
35
37
|
pageCount?: number;
|
|
36
38
|
rowCount?: number;
|
|
37
39
|
emptyMessage?: string;
|
|
40
|
+
orderable?: boolean;
|
|
41
|
+
onReorder?: (fromIndex: number, toIndex: number) => void;
|
|
38
42
|
};
|
|
39
43
|
|
|
40
44
|
let {
|
|
@@ -55,9 +59,18 @@
|
|
|
55
59
|
manualPagination: manualPaginationProp = false,
|
|
56
60
|
pageCount: pageCountProp,
|
|
57
61
|
rowCount: rowCountProp,
|
|
58
|
-
emptyMessage
|
|
62
|
+
emptyMessage,
|
|
63
|
+
orderable = false,
|
|
64
|
+
onReorder
|
|
59
65
|
}: DataTableProps<TData, TValue> = $props();
|
|
60
66
|
|
|
67
|
+
let liveRegionMessage = $state('');
|
|
68
|
+
let dropProcessing = false;
|
|
69
|
+
|
|
70
|
+
const matchesReducedMotion = typeof window !== 'undefined'
|
|
71
|
+
? window.matchMedia('(prefers-reduced-motion: reduce)').matches
|
|
72
|
+
: false;
|
|
73
|
+
|
|
61
74
|
const interfaceLanguage = useInterfaceLanguage();
|
|
62
75
|
|
|
63
76
|
const defaultEmptyMessages: Record<InterfaceLanguage, string> = {
|
|
@@ -113,10 +126,17 @@
|
|
|
113
126
|
});
|
|
114
127
|
</script>
|
|
115
128
|
|
|
116
|
-
|
|
129
|
+
{#if orderable}
|
|
130
|
+
<div aria-live="polite" aria-atomic="true" class="sr-only">{liveRegionMessage}</div>
|
|
131
|
+
{/if}
|
|
132
|
+
|
|
133
|
+
<Table.Root aria-roledescription={orderable ? 'sortable list' : undefined}>
|
|
117
134
|
<Table.Header class="bg-muted sticky top-0 z-10">
|
|
118
135
|
{#each table.getHeaderGroups() as headerGroup (headerGroup.id)}
|
|
119
136
|
<Table.Row class="border-b-0 hover:bg-transparent">
|
|
137
|
+
{#if orderable}
|
|
138
|
+
<Table.Head class="text-[11px] font-bold uppercase tracking-[0.04em] text-muted-foreground h-10 w-10"></Table.Head>
|
|
139
|
+
{/if}
|
|
120
140
|
{#each headerGroup.headers as header (header.id)}
|
|
121
141
|
<Table.Head class="text-[11px] font-bold uppercase tracking-[0.04em] text-muted-foreground h-10">
|
|
122
142
|
{#if !header.isPlaceholder}
|
|
@@ -131,23 +151,112 @@
|
|
|
131
151
|
{/each}
|
|
132
152
|
</Table.Header>
|
|
133
153
|
<Table.Body>
|
|
134
|
-
{#
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
154
|
+
{#if orderable}
|
|
155
|
+
{#each table.getRowModel().rows as row, i (row.id)}
|
|
156
|
+
{@const totalRows = table.getRowModel().rows.length}
|
|
157
|
+
<tr
|
|
158
|
+
use:droppable={{
|
|
159
|
+
container: i.toString(),
|
|
160
|
+
callbacks: {
|
|
161
|
+
onDrop: (state) => {
|
|
162
|
+
if (dropProcessing) return;
|
|
163
|
+
dropProcessing = true;
|
|
164
|
+
const fromIndex = parseInt(state.sourceContainer ?? '');
|
|
165
|
+
const toIndex = parseInt(state.targetContainer ?? '');
|
|
166
|
+
if (!isNaN(fromIndex) && !isNaN(toIndex)) {
|
|
167
|
+
onReorder?.(fromIndex, toIndex);
|
|
168
|
+
}
|
|
169
|
+
dndState.isDragging = false;
|
|
170
|
+
dndState.draggedItem = null;
|
|
171
|
+
dndState.sourceContainer = '';
|
|
172
|
+
dndState.targetContainer = null;
|
|
173
|
+
dndState.targetElement = null;
|
|
174
|
+
setTimeout(() => { dropProcessing = false; }, 50);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
}}
|
|
178
|
+
animate:flip={{ duration: matchesReducedMotion ? 0 : 200 }}
|
|
179
|
+
data-slot="table-row"
|
|
180
|
+
data-state={row.getIsSelected() ? 'selected' : undefined}
|
|
181
|
+
class="hover:bg-muted/50 data-[state=selected]:bg-muted border-b transition-colors hover:bg-lavender-lighter/50 data-[state=selected]:bg-lavender-lighter/30 {i === totalRows - 1 ? 'border-b-0' : ''}"
|
|
182
|
+
>
|
|
183
|
+
<Table.Cell class="py-3 w-10">
|
|
184
|
+
<div class="flex items-center gap-1">
|
|
185
|
+
<div
|
|
186
|
+
use:draggable={{
|
|
187
|
+
container: i.toString(),
|
|
188
|
+
dragData: { index: i }
|
|
189
|
+
}}
|
|
190
|
+
class="text-muted-foreground hover:text-foreground cursor-grab"
|
|
191
|
+
role="button"
|
|
192
|
+
tabindex="0"
|
|
193
|
+
aria-label={`Drag to reorder, row ${i + 1} of ${totalRows}`}
|
|
194
|
+
aria-roledescription="draggable"
|
|
195
|
+
>
|
|
196
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="9" cy="12" r="1"/><circle cx="9" cy="5" r="1"/><circle cx="9" cy="19" r="1"/><circle cx="15" cy="12" r="1"/><circle cx="15" cy="5" r="1"/><circle cx="15" cy="19" r="1"/></svg>
|
|
197
|
+
</div>
|
|
198
|
+
<div class="flex flex-col">
|
|
199
|
+
{#if i > 0}
|
|
200
|
+
<button
|
|
201
|
+
type="button"
|
|
202
|
+
class="p-0.5 rounded text-muted-foreground hover:text-foreground"
|
|
203
|
+
aria-label={`Move up, row ${i + 1} of ${totalRows}`}
|
|
204
|
+
onclick={() => {
|
|
205
|
+
onReorder?.(i, i - 1);
|
|
206
|
+
liveRegionMessage = `Moved to position ${i} of ${totalRows}`;
|
|
207
|
+
}}
|
|
208
|
+
>
|
|
209
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="m18 15-6-6-6 6"/></svg>
|
|
210
|
+
</button>
|
|
211
|
+
{/if}
|
|
212
|
+
{#if i < totalRows - 1}
|
|
213
|
+
<button
|
|
214
|
+
type="button"
|
|
215
|
+
class="p-0.5 rounded text-muted-foreground hover:text-foreground"
|
|
216
|
+
aria-label={`Move down, row ${i + 1} of ${totalRows}`}
|
|
217
|
+
onclick={() => {
|
|
218
|
+
onReorder?.(i, i + 1);
|
|
219
|
+
liveRegionMessage = `Moved to position ${i + 2} of ${totalRows}`;
|
|
220
|
+
}}
|
|
221
|
+
>
|
|
222
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="m6 9 6 6 6-6"/></svg>
|
|
223
|
+
</button>
|
|
224
|
+
{/if}
|
|
225
|
+
</div>
|
|
226
|
+
</div>
|
|
142
227
|
</Table.Cell>
|
|
143
|
-
|
|
144
|
-
|
|
228
|
+
{#each row.getVisibleCells() as cell (cell.id)}
|
|
229
|
+
<Table.Cell class="py-3">
|
|
230
|
+
<FlexRender content={cell.column.columnDef.cell} context={cell.getContext()} />
|
|
231
|
+
</Table.Cell>
|
|
232
|
+
{/each}
|
|
233
|
+
</tr>
|
|
234
|
+
{:else}
|
|
235
|
+
<Table.Row>
|
|
236
|
+
<Table.Cell colspan={columns.length + 1} class="h-24 text-center text-muted-foreground">
|
|
237
|
+
{emptyMessage ?? defaultEmptyMessages[interfaceLanguage.current]}
|
|
238
|
+
</Table.Cell>
|
|
239
|
+
</Table.Row>
|
|
240
|
+
{/each}
|
|
145
241
|
{:else}
|
|
146
|
-
|
|
147
|
-
<Table.
|
|
148
|
-
{
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
242
|
+
{#each table.getRowModel().rows as row, i (row.id)}
|
|
243
|
+
<Table.Row
|
|
244
|
+
data-state={row.getIsSelected() && 'selected'}
|
|
245
|
+
class="hover:bg-lavender-lighter/50 data-[state=selected]:bg-lavender-lighter/30 {i === table.getRowModel().rows.length - 1 ? 'border-b-0' : ''}"
|
|
246
|
+
>
|
|
247
|
+
{#each row.getVisibleCells() as cell (cell.id)}
|
|
248
|
+
<Table.Cell class="py-3">
|
|
249
|
+
<FlexRender content={cell.column.columnDef.cell} context={cell.getContext()} />
|
|
250
|
+
</Table.Cell>
|
|
251
|
+
{/each}
|
|
252
|
+
</Table.Row>
|
|
253
|
+
{:else}
|
|
254
|
+
<Table.Row>
|
|
255
|
+
<Table.Cell colspan={columns.length} class="h-24 text-center text-muted-foreground">
|
|
256
|
+
{emptyMessage ?? defaultEmptyMessages[interfaceLanguage.current]}
|
|
257
|
+
</Table.Cell>
|
|
258
|
+
</Table.Row>
|
|
259
|
+
{/each}
|
|
260
|
+
{/if}
|
|
152
261
|
</Table.Body>
|
|
153
262
|
</Table.Root>
|
|
@@ -18,6 +18,8 @@ type DataTableProps<TData, TValue> = {
|
|
|
18
18
|
pageCount?: number;
|
|
19
19
|
rowCount?: number;
|
|
20
20
|
emptyMessage?: string;
|
|
21
|
+
orderable?: boolean;
|
|
22
|
+
onReorder?: (fromIndex: number, toIndex: number) => void;
|
|
21
23
|
};
|
|
22
24
|
declare function $$render<TData, TValue>(): {
|
|
23
25
|
props: DataTableProps<TData, TValue>;
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
entryUrl: string;
|
|
14
14
|
entryName: string;
|
|
15
15
|
onArchive: () => void;
|
|
16
|
-
onDelete
|
|
16
|
+
onDelete?: () => void;
|
|
17
17
|
onRestore?: () => void;
|
|
18
18
|
};
|
|
19
19
|
|
|
@@ -61,9 +61,11 @@
|
|
|
61
61
|
{t.archive}
|
|
62
62
|
</DropdownMenu.Item>
|
|
63
63
|
{/if}
|
|
64
|
+
{#if onDelete}
|
|
64
65
|
<DropdownMenu.Item class="text-destructive focus:text-destructive" onclick={onDelete}>
|
|
65
66
|
<Trash class="mr-2 size-4" />
|
|
66
67
|
{t.delete}
|
|
67
68
|
</DropdownMenu.Item>
|
|
69
|
+
{/if}
|
|
68
70
|
</DropdownMenu.Content>
|
|
69
71
|
</DropdownMenu.Root>
|
|
@@ -10,10 +10,11 @@
|
|
|
10
10
|
let { data }: Props = $props();
|
|
11
11
|
|
|
12
12
|
const entryId = $derived(data?.entryId || page.params.entryId || '');
|
|
13
|
+
const query = $derived(remotes.getEntryForEntryPage(entryId));
|
|
13
14
|
</script>
|
|
14
15
|
|
|
15
|
-
{#
|
|
16
|
+
{#if !query.ready}
|
|
16
17
|
<EntryPageSkeleton />
|
|
17
|
-
{:
|
|
18
|
-
<EntryVersion {
|
|
19
|
-
{/
|
|
18
|
+
{:else if query.current}
|
|
19
|
+
<EntryVersion entry={query.current} />
|
|
20
|
+
{/if}
|
|
@@ -27,6 +27,8 @@
|
|
|
27
27
|
});
|
|
28
28
|
</script>
|
|
29
29
|
|
|
30
|
-
{#
|
|
31
|
-
<
|
|
32
|
-
{
|
|
30
|
+
{#if formSubmissionsQuery.ready && formSubmissionsQuery.current}
|
|
31
|
+
<div class:opacity-60={formSubmissionsQuery.loading} class="transition-opacity duration-200">
|
|
32
|
+
<FormSubmissions submissions={formSubmissionsQuery.current} {formConfig} />
|
|
33
|
+
</div>
|
|
34
|
+
{/if}
|
|
@@ -9,9 +9,9 @@
|
|
|
9
9
|
</script>
|
|
10
10
|
|
|
11
11
|
<div class="p-4 md:p-6">
|
|
12
|
-
{#
|
|
13
|
-
{
|
|
14
|
-
<FormConfigWrapper {
|
|
15
|
-
|
|
16
|
-
{/
|
|
12
|
+
{#if formConfigQuery.ready && formConfigQuery.current}
|
|
13
|
+
<div class:opacity-60={formConfigQuery.loading} class="transition-opacity duration-200">
|
|
14
|
+
<FormConfigWrapper formConfig={formConfigQuery.current} />
|
|
15
|
+
</div>
|
|
16
|
+
{/if}
|
|
17
17
|
</div>
|
|
@@ -44,47 +44,45 @@
|
|
|
44
44
|
data?.submissionId || (page.params as Record<string, string>).submissionId || (page.params as Record<string, string>).id || ''
|
|
45
45
|
);
|
|
46
46
|
|
|
47
|
-
|
|
47
|
+
const formSubmissionQuery = $derived(submissionId ? remotes.getFormSubmission(submissionId) : null);
|
|
48
48
|
|
|
49
49
|
$effect(() => {
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
];
|
|
65
|
-
|
|
66
|
-
if (!submission.read) {
|
|
67
|
-
await remotes.updateFormSubmission({ id: submission.id, read: true });
|
|
50
|
+
const submission = formSubmissionQuery?.current;
|
|
51
|
+
if (submission) {
|
|
52
|
+
// Update breadcrumbs
|
|
53
|
+
const formQuery = remotes.getForm(submission.formSlug);
|
|
54
|
+
if (formQuery.ready && formQuery.current) {
|
|
55
|
+
const form = formQuery.current;
|
|
56
|
+
const formLabel = getLocalizedLabel(form.label, interfaceLanguage.current) || form.slug;
|
|
57
|
+
breadcrumbs.state = [
|
|
58
|
+
{
|
|
59
|
+
label: formLabel,
|
|
60
|
+
href: `/admin/forms/${form.slug}`
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
label: lang[interfaceLanguage.current].submission
|
|
68
64
|
}
|
|
69
|
-
|
|
70
|
-
}
|
|
65
|
+
];
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if (!submission.read) {
|
|
69
|
+
remotes.updateFormSubmission({ id: submission.id, read: true });
|
|
70
|
+
}
|
|
71
71
|
}
|
|
72
72
|
});
|
|
73
73
|
</script>
|
|
74
74
|
|
|
75
75
|
<div class="p-4 md:p-6">
|
|
76
76
|
{#if formSubmissionQuery}
|
|
77
|
-
{#
|
|
78
|
-
{
|
|
79
|
-
|
|
80
|
-
{
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
{
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
{/await}
|
|
87
|
-
{/key}
|
|
77
|
+
{#if !formSubmissionQuery.ready}
|
|
78
|
+
<p class="text-muted-foreground">{lang[interfaceLanguage.current].loading}</p>
|
|
79
|
+
{:else if formSubmissionQuery.current === null}
|
|
80
|
+
<p class="text-muted-foreground">{lang[interfaceLanguage.current].notFound}</p>
|
|
81
|
+
{:else if formSubmissionQuery.current}
|
|
82
|
+
<div class:opacity-60={formSubmissionQuery.loading} class="transition-opacity duration-200">
|
|
83
|
+
<FormSubmission submission={formSubmissionQuery.current} />
|
|
84
|
+
</div>
|
|
85
|
+
{/if}
|
|
88
86
|
{:else}
|
|
89
87
|
<p class="text-muted-foreground">{lang[interfaceLanguage.current].notFound}</p>
|
|
90
88
|
{/if}
|
|
@@ -20,6 +20,8 @@
|
|
|
20
20
|
altInfo: 'Total images without alt text:'
|
|
21
21
|
}
|
|
22
22
|
};
|
|
23
|
+
|
|
24
|
+
const query = $derived(remotes.getAltOverview());
|
|
23
25
|
</script>
|
|
24
26
|
|
|
25
27
|
<Card.Root>
|
|
@@ -28,18 +30,18 @@
|
|
|
28
30
|
<Card.Description>{lang[interfaceLanguage.current].description}</Card.Description>
|
|
29
31
|
</Card.Header>
|
|
30
32
|
<Card.Content>
|
|
31
|
-
{#
|
|
33
|
+
{#if !query.ready}
|
|
32
34
|
<div class="space-y-2">
|
|
33
35
|
<Skeleton class="h-4 w-[250px]" />
|
|
34
36
|
<Skeleton class="h-4 w-[200px]" />
|
|
35
37
|
</div>
|
|
36
|
-
{:
|
|
37
|
-
<div class="space-y-4">
|
|
38
|
+
{:else if query.current}
|
|
39
|
+
<div class="space-y-4" class:opacity-60={query.loading} style="transition: opacity 200ms">
|
|
38
40
|
<p>
|
|
39
41
|
{lang[interfaceLanguage.current].altInfo}
|
|
40
|
-
<span class="text-2xl font-bold text-primary">{
|
|
42
|
+
<span class="text-2xl font-bold text-primary">{query.current.filesWithoutAlt}</span>
|
|
41
43
|
</p>
|
|
42
44
|
</div>
|
|
43
|
-
{/
|
|
45
|
+
{/if}
|
|
44
46
|
</Card.Content>
|
|
45
47
|
</Card.Root>
|
|
@@ -1,18 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
$$bindings?: Bindings;
|
|
4
|
-
} & Exports;
|
|
5
|
-
(internal: unknown, props: {
|
|
6
|
-
$$events?: Events;
|
|
7
|
-
$$slots?: Slots;
|
|
8
|
-
}): Exports & {
|
|
9
|
-
$set?: any;
|
|
10
|
-
$on?: any;
|
|
11
|
-
};
|
|
12
|
-
z_$$bindings?: Bindings;
|
|
13
|
-
}
|
|
14
|
-
declare const AccessibilityOverview: $$__sveltets_2_IsomorphicComponent<Record<string, never>, {
|
|
15
|
-
[evt: string]: CustomEvent<any>;
|
|
16
|
-
}, {}, {}, string>;
|
|
17
|
-
type AccessibilityOverview = InstanceType<typeof AccessibilityOverview>;
|
|
1
|
+
declare const AccessibilityOverview: import("svelte").Component<Record<string, never>, {}, "">;
|
|
2
|
+
type AccessibilityOverview = ReturnType<typeof AccessibilityOverview>;
|
|
18
3
|
export default AccessibilityOverview;
|
|
@@ -31,6 +31,8 @@
|
|
|
31
31
|
hint: (n) => `${n} image${n === 1 ? ' needs' : 's need'} a description. Go to the media library to add them.`
|
|
32
32
|
}
|
|
33
33
|
};
|
|
34
|
+
|
|
35
|
+
const query = $derived(remotes.getAltOverview());
|
|
34
36
|
</script>
|
|
35
37
|
|
|
36
38
|
<section class="dash-card dash-card--a11y" aria-labelledby="a11y-heading">
|
|
@@ -38,7 +40,7 @@
|
|
|
38
40
|
<h2 class="dash-card-title" id="a11y-heading">{lang[interfaceLanguage.current].title}</h2>
|
|
39
41
|
</div>
|
|
40
42
|
|
|
41
|
-
{#
|
|
43
|
+
{#if !query.ready}
|
|
42
44
|
<div class="a11y-card-body">
|
|
43
45
|
<div class="gauge-wrap">
|
|
44
46
|
<Skeleton class="rounded-full" style="width:140px;height:140px" />
|
|
@@ -46,12 +48,13 @@
|
|
|
46
48
|
<Skeleton class="h-4 w-32 mb-2" />
|
|
47
49
|
<Skeleton class="h-12 w-full" />
|
|
48
50
|
</div>
|
|
49
|
-
{:
|
|
51
|
+
{:else if query.current}
|
|
52
|
+
{@const overview = query.current}
|
|
50
53
|
{@const compliancePercent = overview.totalFiles > 0 ? Math.round((overview.filesWithAlt / overview.totalFiles) * 100) : 100}
|
|
51
54
|
{@const fillLength = (compliancePercent / 100) * CIRCUMFERENCE}
|
|
52
55
|
{@const hasIssues = overview.filesWithoutAlt > 0}
|
|
53
56
|
|
|
54
|
-
<div class="a11y-card-body">
|
|
57
|
+
<div class="a11y-card-body" class:opacity-60={query.loading} style="transition: opacity 200ms">
|
|
55
58
|
<div class="gauge-wrap">
|
|
56
59
|
<svg class="gauge-svg" viewBox="0 0 140 140" role="img" aria-label="{interfaceLanguage.current === 'pl' ? 'Ocena dostępności' : 'Accessibility score'}: {compliancePercent}%">
|
|
57
60
|
<circle class="gauge-bg" cx="70" cy="70" r="54" />
|
|
@@ -86,5 +89,5 @@
|
|
|
86
89
|
{/if}
|
|
87
90
|
</div>
|
|
88
91
|
</div>
|
|
89
|
-
{/
|
|
92
|
+
{/if}
|
|
90
93
|
</section>
|
|
@@ -1,18 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
$$bindings?: Bindings;
|
|
4
|
-
} & Exports;
|
|
5
|
-
(internal: unknown, props: {
|
|
6
|
-
$$events?: Events;
|
|
7
|
-
$$slots?: Slots;
|
|
8
|
-
}): Exports & {
|
|
9
|
-
$set?: any;
|
|
10
|
-
$on?: any;
|
|
11
|
-
};
|
|
12
|
-
z_$$bindings?: Bindings;
|
|
13
|
-
}
|
|
14
|
-
declare const A11yGauge: $$__sveltets_2_IsomorphicComponent<Record<string, never>, {
|
|
15
|
-
[evt: string]: CustomEvent<any>;
|
|
16
|
-
}, {}, {}, string>;
|
|
17
|
-
type A11yGauge = InstanceType<typeof A11yGauge>;
|
|
1
|
+
declare const A11yGauge: import("svelte").Component<Record<string, never>, {}, "">;
|
|
2
|
+
type A11yGauge = ReturnType<typeof A11yGauge>;
|
|
18
3
|
export default A11yGauge;
|
|
@@ -52,6 +52,8 @@
|
|
|
52
52
|
issuesFound: 'images need alt text'
|
|
53
53
|
}
|
|
54
54
|
};
|
|
55
|
+
|
|
56
|
+
const query = $derived(remotes.getAltOverview());
|
|
55
57
|
</script>
|
|
56
58
|
|
|
57
59
|
<Card.Root class="rounded-2xl border bg-card shadow-sm">
|
|
@@ -67,7 +69,7 @@
|
|
|
67
69
|
</div>
|
|
68
70
|
</Card.Header>
|
|
69
71
|
<Card.Content>
|
|
70
|
-
{#
|
|
72
|
+
{#if !query.ready}
|
|
71
73
|
<div class="grid gap-4 sm:grid-cols-2 lg:grid-cols-4">
|
|
72
74
|
{#each Array(4) as _}
|
|
73
75
|
<div class="space-y-2">
|
|
@@ -76,14 +78,15 @@
|
|
|
76
78
|
</div>
|
|
77
79
|
{/each}
|
|
78
80
|
</div>
|
|
79
|
-
{:
|
|
81
|
+
{:else if query.current}
|
|
82
|
+
{@const overview = query.current}
|
|
80
83
|
{@const compliancePercent =
|
|
81
84
|
overview.totalFiles > 0
|
|
82
85
|
? Math.round((overview.filesWithAlt / overview.totalFiles) * 100)
|
|
83
86
|
: 100}
|
|
84
87
|
{@const hasIssues = overview.filesWithoutAlt > 0}
|
|
85
88
|
|
|
86
|
-
<div class="space-y-4">
|
|
89
|
+
<div class="space-y-4" class:opacity-60={query.loading} style="transition: opacity 200ms">
|
|
87
90
|
<div class="grid gap-4 sm:grid-cols-2 lg:grid-cols-4">
|
|
88
91
|
<StatCard
|
|
89
92
|
label={lang[interfaceLanguage.current].compliance}
|
|
@@ -142,6 +145,6 @@
|
|
|
142
145
|
</Alert.Root>
|
|
143
146
|
{/if}
|
|
144
147
|
</div>
|
|
145
|
-
{/
|
|
148
|
+
{/if}
|
|
146
149
|
</Card.Content>
|
|
147
150
|
</Card.Root>
|
|
@@ -1,18 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
$$bindings?: Bindings;
|
|
4
|
-
} & Exports;
|
|
5
|
-
(internal: unknown, props: {
|
|
6
|
-
$$events?: Events;
|
|
7
|
-
$$slots?: Slots;
|
|
8
|
-
}): Exports & {
|
|
9
|
-
$set?: any;
|
|
10
|
-
$on?: any;
|
|
11
|
-
};
|
|
12
|
-
z_$$bindings?: Bindings;
|
|
13
|
-
}
|
|
14
|
-
declare const AccessibilityHub: $$__sveltets_2_IsomorphicComponent<Record<string, never>, {
|
|
15
|
-
[evt: string]: CustomEvent<any>;
|
|
16
|
-
}, {}, {}, string>;
|
|
17
|
-
type AccessibilityHub = InstanceType<typeof AccessibilityHub>;
|
|
1
|
+
declare const AccessibilityHub: import("svelte").Component<Record<string, never>, {}, "">;
|
|
2
|
+
type AccessibilityHub = ReturnType<typeof AccessibilityHub>;
|
|
18
3
|
export default AccessibilityHub;
|
|
@@ -29,6 +29,8 @@
|
|
|
29
29
|
function formatRelativeDate(date: Date): string {
|
|
30
30
|
return formatRelativeDateUtil(date, interfaceLanguage.current);
|
|
31
31
|
}
|
|
32
|
+
|
|
33
|
+
const query = $derived(remotes.getSubmissionsOverview());
|
|
32
34
|
</script>
|
|
33
35
|
|
|
34
36
|
<section class="dash-card dash-card--forms" aria-labelledby="forms-heading">
|
|
@@ -37,7 +39,7 @@
|
|
|
37
39
|
<a href="/admin/forms" class="dash-card-link">{lang[interfaceLanguage.current].viewAll}</a>
|
|
38
40
|
</div>
|
|
39
41
|
|
|
40
|
-
{#
|
|
42
|
+
{#if !query.ready}
|
|
41
43
|
<div class="forms-card-body">
|
|
42
44
|
{#each Array(2) as _}
|
|
43
45
|
<div class="form-group">
|
|
@@ -47,7 +49,9 @@
|
|
|
47
49
|
</div>
|
|
48
50
|
{/each}
|
|
49
51
|
</div>
|
|
50
|
-
{:
|
|
52
|
+
{:else if query.current}
|
|
53
|
+
{@const overview = query.current}
|
|
54
|
+
<div class:opacity-60={query.loading} class="transition-opacity duration-200">
|
|
51
55
|
{#if overview.length === 0}
|
|
52
56
|
<p class="text-center text-sm py-6" style="color:var(--text-light)">
|
|
53
57
|
{lang[interfaceLanguage.current].noSubmissions}
|
|
@@ -96,5 +100,6 @@
|
|
|
96
100
|
{/each}
|
|
97
101
|
</div>
|
|
98
102
|
{/if}
|
|
99
|
-
|
|
103
|
+
</div>
|
|
104
|
+
{/if}
|
|
100
105
|
</section>
|
|
@@ -1,18 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
$$bindings?: Bindings;
|
|
4
|
-
} & Exports;
|
|
5
|
-
(internal: unknown, props: {
|
|
6
|
-
$$events?: Events;
|
|
7
|
-
$$slots?: Slots;
|
|
8
|
-
}): Exports & {
|
|
9
|
-
$set?: any;
|
|
10
|
-
$on?: any;
|
|
11
|
-
};
|
|
12
|
-
z_$$bindings?: Bindings;
|
|
13
|
-
}
|
|
14
|
-
declare const FormSubmissionsWidget: $$__sveltets_2_IsomorphicComponent<Record<string, never>, {
|
|
15
|
-
[evt: string]: CustomEvent<any>;
|
|
16
|
-
}, {}, {}, string>;
|
|
17
|
-
type FormSubmissionsWidget = InstanceType<typeof FormSubmissionsWidget>;
|
|
1
|
+
declare const FormSubmissionsWidget: import("svelte").Component<Record<string, never>, {}, "">;
|
|
2
|
+
type FormSubmissionsWidget = ReturnType<typeof FormSubmissionsWidget>;
|
|
18
3
|
export default FormSubmissionsWidget;
|
|
@@ -28,6 +28,8 @@
|
|
|
28
28
|
function formatRelativeDate(date: Date): string {
|
|
29
29
|
return formatRelativeDateUtil(date, interfaceLanguage.current);
|
|
30
30
|
}
|
|
31
|
+
|
|
32
|
+
const query = $derived(remotes.getRecentActivity(10));
|
|
31
33
|
</script>
|
|
32
34
|
|
|
33
35
|
<section class="dash-card dash-card--activity" aria-labelledby="activity-heading">
|
|
@@ -35,7 +37,7 @@
|
|
|
35
37
|
<h2 class="dash-card-title" id="activity-heading">{lang[interfaceLanguage.current].title}</h2>
|
|
36
38
|
</div>
|
|
37
39
|
|
|
38
|
-
{#
|
|
40
|
+
{#if !query.ready}
|
|
39
41
|
<ul class="activity-list">
|
|
40
42
|
{#each Array(4) as _}
|
|
41
43
|
<li class="activity-item">
|
|
@@ -49,7 +51,9 @@
|
|
|
49
51
|
</li>
|
|
50
52
|
{/each}
|
|
51
53
|
</ul>
|
|
52
|
-
{:
|
|
54
|
+
{:else if query.current}
|
|
55
|
+
{@const activity = query.current}
|
|
56
|
+
<div class:opacity-60={query.loading} class="transition-opacity duration-200">
|
|
53
57
|
{#if activity.length === 0}
|
|
54
58
|
<p class="text-center text-sm py-6" style="color:var(--text-light)">
|
|
55
59
|
{lang[interfaceLanguage.current].noActivity}
|
|
@@ -76,5 +80,6 @@
|
|
|
76
80
|
{/each}
|
|
77
81
|
</ul>
|
|
78
82
|
{/if}
|
|
79
|
-
|
|
83
|
+
</div>
|
|
84
|
+
{/if}
|
|
80
85
|
</section>
|
|
@@ -1,18 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
$$bindings?: Bindings;
|
|
4
|
-
} & Exports;
|
|
5
|
-
(internal: unknown, props: {
|
|
6
|
-
$$events?: Events;
|
|
7
|
-
$$slots?: Slots;
|
|
8
|
-
}): Exports & {
|
|
9
|
-
$set?: any;
|
|
10
|
-
$on?: any;
|
|
11
|
-
};
|
|
12
|
-
z_$$bindings?: Bindings;
|
|
13
|
-
}
|
|
14
|
-
declare const RecentActivity: $$__sveltets_2_IsomorphicComponent<Record<string, never>, {
|
|
15
|
-
[evt: string]: CustomEvent<any>;
|
|
16
|
-
}, {}, {}, string>;
|
|
17
|
-
type RecentActivity = InstanceType<typeof RecentActivity>;
|
|
1
|
+
declare const RecentActivity: import("svelte").Component<Record<string, never>, {}, "">;
|
|
2
|
+
type RecentActivity = ReturnType<typeof RecentActivity>;
|
|
18
3
|
export default RecentActivity;
|