includio-cms 0.0.69 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +24 -0
- package/ROADMAP.md +24 -5
- package/dist/admin/client/account/lang.d.ts +0 -5
- package/dist/admin/client/account/lang.js +2 -12
- package/dist/admin/client/account/preferences-section.svelte +27 -24
- package/dist/admin/client/account/profile-section.svelte +11 -15
- package/dist/admin/client/account/security-section.svelte +0 -11
- package/dist/admin/client/account/sessions-section.svelte +2 -1
- package/dist/admin/client/collection/collection-entries.svelte +168 -43
- package/dist/admin/client/collection/collection-view.svelte.d.ts +5 -0
- package/dist/admin/client/collection/collection-view.svelte.js +22 -5
- package/dist/admin/client/collection/collection.svelte +2 -2
- package/dist/admin/client/collection/data-table.svelte +15 -3
- package/dist/admin/client/collection/data-table.svelte.d.ts +3 -0
- package/dist/admin/client/entry/entry.svelte +11 -7
- package/dist/admin/client/entry/header/status-badge.svelte +6 -3
- package/dist/admin/client/entry/header/version-history-sheet.svelte +6 -3
- package/dist/admin/client/form/form-submissions.svelte +3 -26
- package/dist/admin/components/dashboard/form-submissions-widget.svelte +2 -12
- package/dist/admin/components/dashboard/recent-activity.svelte +2 -12
- package/dist/admin/components/layout/header-actions.svelte +4 -3
- package/dist/admin/components/media/media-library.svelte +17 -6
- package/dist/admin/remote/entry.remote.d.ts +10 -1
- package/dist/admin/remote/entry.remote.js +16 -4
- package/dist/admin/state/interface-language.svelte.d.ts +4 -7
- package/dist/admin/state/interface-language.svelte.js +19 -18
- package/dist/admin/utils/formatDate.d.ts +1 -0
- package/dist/admin/utils/formatDate.js +5 -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/core/server/entries/operations/get.d.ts +2 -0
- package/dist/core/server/entries/operations/get.js +6 -0
- package/dist/db-postgres/index.js +26 -1
- package/dist/sveltekit/components/hybrid-context.d.ts +4 -0
- package/dist/sveltekit/components/hybrid-context.js +9 -0
- package/dist/sveltekit/components/hybrid-target.svelte +4 -1
- package/dist/sveltekit/components/image.svelte +5 -2
- package/dist/sveltekit/components/preview.svelte +3 -0
- package/dist/sveltekit/components/video.svelte +4 -1
- package/dist/sveltekit/index.d.ts +1 -0
- package/dist/sveltekit/index.js +1 -0
- package/dist/types/adapters/db.d.ts +3 -1
- package/dist/types/entries.d.ts +10 -2
- package/dist/types/languages.d.ts +2 -1
- package/dist/updates/0.1.0/index.d.ts +2 -0
- package/dist/updates/0.1.0/index.js +25 -0
- package/dist/updates/index.js +2 -1
- package/package.json +1 -1
- package/dist/core/server/utils/sanitizeRichText.d.ts +0 -1
- package/dist/core/server/utils/sanitizeRichText.js +0 -67
|
@@ -2,7 +2,9 @@ const DEFAULT_STATE = {
|
|
|
2
2
|
viewMode: 'list',
|
|
3
3
|
dateFormat: 'relative',
|
|
4
4
|
pageSize: 10,
|
|
5
|
-
sorting: []
|
|
5
|
+
sorting: [],
|
|
6
|
+
pageIndex: 0,
|
|
7
|
+
activeTab: 'active'
|
|
6
8
|
};
|
|
7
9
|
function getStorageKey(collectionSlug) {
|
|
8
10
|
return `includio-collection-${collectionSlug}-view`;
|
|
@@ -42,25 +44,40 @@ export function createCollectionViewState(collectionSlug) {
|
|
|
42
44
|
return state.viewMode;
|
|
43
45
|
},
|
|
44
46
|
set viewMode(value) {
|
|
45
|
-
state =
|
|
47
|
+
state.viewMode = value;
|
|
46
48
|
},
|
|
47
49
|
get dateFormat() {
|
|
48
50
|
return state.dateFormat;
|
|
49
51
|
},
|
|
50
52
|
set dateFormat(value) {
|
|
51
|
-
state =
|
|
53
|
+
state.dateFormat = value;
|
|
52
54
|
},
|
|
53
55
|
get pageSize() {
|
|
54
56
|
return state.pageSize;
|
|
55
57
|
},
|
|
56
58
|
set pageSize(value) {
|
|
57
|
-
state =
|
|
59
|
+
state.pageSize = value;
|
|
60
|
+
state.pageIndex = 0;
|
|
58
61
|
},
|
|
59
62
|
get sorting() {
|
|
60
63
|
return state.sorting;
|
|
61
64
|
},
|
|
62
65
|
set sorting(value) {
|
|
63
|
-
state =
|
|
66
|
+
state.sorting = value;
|
|
67
|
+
state.pageIndex = 0;
|
|
68
|
+
},
|
|
69
|
+
get pageIndex() {
|
|
70
|
+
return state.pageIndex;
|
|
71
|
+
},
|
|
72
|
+
set pageIndex(value) {
|
|
73
|
+
state.pageIndex = value;
|
|
74
|
+
},
|
|
75
|
+
get activeTab() {
|
|
76
|
+
return state.activeTab;
|
|
77
|
+
},
|
|
78
|
+
set activeTab(value) {
|
|
79
|
+
state.activeTab = value;
|
|
80
|
+
state.pageIndex = 0;
|
|
64
81
|
}
|
|
65
82
|
};
|
|
66
83
|
}
|
|
@@ -45,8 +45,8 @@
|
|
|
45
45
|
});
|
|
46
46
|
|
|
47
47
|
$effect(() => {
|
|
48
|
-
remotes.getRawEntries({ slug: collection.slug }).then((
|
|
49
|
-
entryCount =
|
|
48
|
+
remotes.getRawEntries({ slug: collection.slug }).then(({ total }) => {
|
|
49
|
+
entryCount = total;
|
|
50
50
|
});
|
|
51
51
|
});
|
|
52
52
|
</script>
|
|
@@ -29,6 +29,9 @@
|
|
|
29
29
|
pagination?: PaginationState;
|
|
30
30
|
onPaginationChange?: (pagination: PaginationState) => void;
|
|
31
31
|
tableRef?: (table: TableType<TData>) => void;
|
|
32
|
+
manualPagination?: boolean;
|
|
33
|
+
pageCount?: number;
|
|
34
|
+
rowCount?: number;
|
|
32
35
|
};
|
|
33
36
|
|
|
34
37
|
let {
|
|
@@ -45,7 +48,10 @@
|
|
|
45
48
|
onRowSelectionChange,
|
|
46
49
|
pagination = { pageIndex: 0, pageSize: 10 },
|
|
47
50
|
onPaginationChange,
|
|
48
|
-
tableRef
|
|
51
|
+
tableRef,
|
|
52
|
+
manualPagination: manualPaginationProp = false,
|
|
53
|
+
pageCount: pageCountProp,
|
|
54
|
+
rowCount: rowCountProp
|
|
49
55
|
}: DataTableProps<TData, TValue> = $props();
|
|
50
56
|
|
|
51
57
|
const table = createSvelteTable({
|
|
@@ -81,8 +87,14 @@
|
|
|
81
87
|
onPaginationChange?.(newPagination);
|
|
82
88
|
},
|
|
83
89
|
globalFilterFn: 'includesString',
|
|
84
|
-
manualPagination:
|
|
85
|
-
manualSorting: true
|
|
90
|
+
manualPagination: manualPaginationProp,
|
|
91
|
+
manualSorting: true,
|
|
92
|
+
get pageCount() {
|
|
93
|
+
return pageCountProp;
|
|
94
|
+
},
|
|
95
|
+
get rowCount() {
|
|
96
|
+
return rowCountProp;
|
|
97
|
+
}
|
|
86
98
|
});
|
|
87
99
|
|
|
88
100
|
$effect(() => {
|
|
@@ -14,6 +14,9 @@ type DataTableProps<TData, TValue> = {
|
|
|
14
14
|
pagination?: PaginationState;
|
|
15
15
|
onPaginationChange?: (pagination: PaginationState) => void;
|
|
16
16
|
tableRef?: (table: TableType<TData>) => void;
|
|
17
|
+
manualPagination?: boolean;
|
|
18
|
+
pageCount?: number;
|
|
19
|
+
rowCount?: number;
|
|
17
20
|
};
|
|
18
21
|
declare function $$render<TData, TValue>(): {
|
|
19
22
|
props: DataTableProps<TData, TValue>;
|
|
@@ -74,6 +74,8 @@
|
|
|
74
74
|
saveDraftToast: string;
|
|
75
75
|
publishToast: string;
|
|
76
76
|
scheduledToast: string;
|
|
77
|
+
saveFailed: string;
|
|
78
|
+
cannotPublish: string;
|
|
77
79
|
}
|
|
78
80
|
> = {
|
|
79
81
|
en: {
|
|
@@ -81,14 +83,18 @@
|
|
|
81
83
|
saveToast: 'Entry saved successfully',
|
|
82
84
|
saveDraftToast: 'Draft saved successfully',
|
|
83
85
|
publishToast: 'Entry published successfully',
|
|
84
|
-
scheduledToast: 'Entry scheduled successfully'
|
|
86
|
+
scheduledToast: 'Entry scheduled successfully',
|
|
87
|
+
saveFailed: 'Save failed',
|
|
88
|
+
cannotPublish: 'Cannot publish'
|
|
85
89
|
},
|
|
86
90
|
pl: {
|
|
87
91
|
entryArchived: 'Wpis został zarchiwizowany pomyślnie',
|
|
88
92
|
saveToast: 'Wpis został pomyślnie zapisany',
|
|
89
93
|
saveDraftToast: 'Wersja robocza została pomyślnie zapisana',
|
|
90
94
|
publishToast: 'Wpis został pomyślnie opublikowany',
|
|
91
|
-
scheduledToast: 'Wpis został zaplanowany pomyślnie'
|
|
95
|
+
scheduledToast: 'Wpis został zaplanowany pomyślnie',
|
|
96
|
+
saveFailed: 'Błąd zapisu',
|
|
97
|
+
cannotPublish: 'Nie można opublikować'
|
|
92
98
|
}
|
|
93
99
|
};
|
|
94
100
|
|
|
@@ -199,7 +205,7 @@
|
|
|
199
205
|
} catch (e) {
|
|
200
206
|
console.error('Save error:', e);
|
|
201
207
|
saveStatus = 'error';
|
|
202
|
-
toast.error(interfaceLanguage.current
|
|
208
|
+
toast.error(lang[interfaceLanguage.current].saveFailed, {
|
|
203
209
|
description: e instanceof Error ? e.message : undefined
|
|
204
210
|
});
|
|
205
211
|
}
|
|
@@ -234,16 +240,14 @@
|
|
|
234
240
|
} catch (e) {
|
|
235
241
|
console.error('Publish error:', e);
|
|
236
242
|
saveStatus = 'error';
|
|
237
|
-
toast.error(interfaceLanguage.current
|
|
243
|
+
toast.error(lang[interfaceLanguage.current].saveFailed, {
|
|
238
244
|
description: e instanceof Error ? e.message : undefined
|
|
239
245
|
});
|
|
240
246
|
}
|
|
241
247
|
} else {
|
|
242
248
|
const errors = flattenErrors(validatedForm.errors, collection.fields);
|
|
243
249
|
toast.error(
|
|
244
|
-
interfaceLanguage.current
|
|
245
|
-
? 'Nie można opublikować'
|
|
246
|
-
: 'Cannot publish',
|
|
250
|
+
lang[interfaceLanguage.current].cannotPublish,
|
|
247
251
|
{
|
|
248
252
|
description: errors.slice(0, 3).join('\n') + (errors.length > 3 ? '\n...' : ''),
|
|
249
253
|
duration: 5000
|
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
publishedBy: string;
|
|
18
18
|
createdAt: string;
|
|
19
19
|
scheduledFor: string;
|
|
20
|
+
publishedVersion: string;
|
|
20
21
|
}
|
|
21
22
|
> = {
|
|
22
23
|
en: {
|
|
@@ -29,7 +30,8 @@
|
|
|
29
30
|
publishedAt: 'Published at',
|
|
30
31
|
publishedBy: 'Published by',
|
|
31
32
|
createdAt: 'Created at',
|
|
32
|
-
scheduledFor: 'Scheduled for'
|
|
33
|
+
scheduledFor: 'Scheduled for',
|
|
34
|
+
publishedVersion: 'Published version'
|
|
33
35
|
},
|
|
34
36
|
pl: {
|
|
35
37
|
status: {
|
|
@@ -41,7 +43,8 @@
|
|
|
41
43
|
publishedAt: 'Opublikowano',
|
|
42
44
|
publishedBy: 'Opublikował',
|
|
43
45
|
createdAt: 'Utworzono',
|
|
44
|
-
scheduledFor: 'Zaplanowano na'
|
|
46
|
+
scheduledFor: 'Zaplanowano na',
|
|
47
|
+
publishedVersion: 'Opublikowana wersja'
|
|
45
48
|
}
|
|
46
49
|
};
|
|
47
50
|
|
|
@@ -152,7 +155,7 @@
|
|
|
152
155
|
{#if entry.publishedVersion && entry.publishedVersion.id !== version.id}
|
|
153
156
|
<div class="border-t pt-2 mt-2">
|
|
154
157
|
<div class="text-muted-foreground text-xs">
|
|
155
|
-
{interfaceLanguage.current
|
|
158
|
+
{lang[interfaceLanguage.current].publishedVersion}: v{entry.publishedVersion.versionNumber}
|
|
156
159
|
</div>
|
|
157
160
|
</div>
|
|
158
161
|
{/if}
|
|
@@ -22,6 +22,7 @@
|
|
|
22
22
|
draft: string;
|
|
23
23
|
changedFields: string;
|
|
24
24
|
noChanges: string;
|
|
25
|
+
versionsCount: string;
|
|
25
26
|
}
|
|
26
27
|
> = {
|
|
27
28
|
en: {
|
|
@@ -33,7 +34,8 @@
|
|
|
33
34
|
scheduled: 'Scheduled',
|
|
34
35
|
draft: 'Draft',
|
|
35
36
|
changedFields: 'Changed fields',
|
|
36
|
-
noChanges: 'No changes'
|
|
37
|
+
noChanges: 'No changes',
|
|
38
|
+
versionsCount: 'versions'
|
|
37
39
|
},
|
|
38
40
|
pl: {
|
|
39
41
|
history: 'Historia wersji',
|
|
@@ -44,7 +46,8 @@
|
|
|
44
46
|
scheduled: 'Zaplanowana',
|
|
45
47
|
draft: 'Szkic',
|
|
46
48
|
changedFields: 'Zmienione pola',
|
|
47
|
-
noChanges: 'Brak zmian'
|
|
49
|
+
noChanges: 'Brak zmian',
|
|
50
|
+
versionsCount: 'wersji'
|
|
48
51
|
}
|
|
49
52
|
};
|
|
50
53
|
|
|
@@ -153,7 +156,7 @@
|
|
|
153
156
|
<Sheet.Header>
|
|
154
157
|
<Sheet.Title>{lang[interfaceLanguage.current].history}</Sheet.Title>
|
|
155
158
|
<Sheet.Description>
|
|
156
|
-
{sortedVersions.length} {interfaceLanguage.current
|
|
159
|
+
{sortedVersions.length} {lang[interfaceLanguage.current].versionsCount}
|
|
157
160
|
</Sheet.Description>
|
|
158
161
|
</Sheet.Header>
|
|
159
162
|
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
import { getLocalizedLabel } from '../../utils/collectionLabel.js';
|
|
11
11
|
import { useInterfaceLanguage } from '../../state/interface-language.svelte.js';
|
|
12
12
|
import type { InterfaceLanguage } from '../../../types/languages.js';
|
|
13
|
+
import { formatRelativeDate as formatRelativeDateUtil, formatAbsoluteDate as formatAbsoluteDateUtil } from '../../utils/formatDate.js';
|
|
13
14
|
import type { DateFormat } from '../collection/collection-view.svelte.js';
|
|
14
15
|
import Checkbox from '../../../components/ui/checkbox/checkbox.svelte';
|
|
15
16
|
import { getRemotes } from '../../context/remotes.js';
|
|
@@ -188,35 +189,11 @@
|
|
|
188
189
|
});
|
|
189
190
|
|
|
190
191
|
function formatRelativeDate(date: Date): string {
|
|
191
|
-
|
|
192
|
-
const diff = now.getTime() - date.getTime();
|
|
193
|
-
const minutes = Math.floor(diff / 60000);
|
|
194
|
-
const hours = Math.floor(diff / 3600000);
|
|
195
|
-
const days = Math.floor(diff / 86400000);
|
|
196
|
-
const weeks = Math.floor(days / 7);
|
|
197
|
-
const months = Math.floor(days / 30);
|
|
198
|
-
|
|
199
|
-
if (minutes < 1) return interfaceLanguage.current === 'pl' ? 'teraz' : 'now';
|
|
200
|
-
if (minutes < 60)
|
|
201
|
-
return interfaceLanguage.current === 'pl' ? `${minutes} min temu` : `${minutes} min ago`;
|
|
202
|
-
if (hours < 24)
|
|
203
|
-
return interfaceLanguage.current === 'pl' ? `${hours} godz. temu` : `${hours}h ago`;
|
|
204
|
-
if (days < 7) return interfaceLanguage.current === 'pl' ? `${days} dni temu` : `${days}d ago`;
|
|
205
|
-
if (weeks < 5)
|
|
206
|
-
return interfaceLanguage.current === 'pl' ? `${weeks} tyg. temu` : `${weeks}w ago`;
|
|
207
|
-
if (months < 12)
|
|
208
|
-
return interfaceLanguage.current === 'pl' ? `${months} mies. temu` : `${months}mo ago`;
|
|
209
|
-
return formatAbsoluteDate(date);
|
|
192
|
+
return formatRelativeDateUtil(date, interfaceLanguage.current);
|
|
210
193
|
}
|
|
211
194
|
|
|
212
195
|
function formatAbsoluteDate(date: Date): string {
|
|
213
|
-
return date
|
|
214
|
-
year: 'numeric',
|
|
215
|
-
month: '2-digit',
|
|
216
|
-
day: '2-digit',
|
|
217
|
-
hour: '2-digit',
|
|
218
|
-
minute: '2-digit'
|
|
219
|
-
});
|
|
196
|
+
return formatAbsoluteDateUtil(date, interfaceLanguage.current);
|
|
220
197
|
}
|
|
221
198
|
|
|
222
199
|
async function handleBulkDelete() {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import { useInterfaceLanguage } from '../../state/interface-language.svelte.js';
|
|
3
|
+
import { formatRelativeDate as formatRelativeDateUtil } from '../../utils/formatDate.js';
|
|
3
4
|
import * as Card from '../../../components/ui/card/index.js';
|
|
4
5
|
import { Badge } from '../../../components/ui/badge/index.js';
|
|
5
6
|
import { Button } from '../../../components/ui/button/index.js';
|
|
@@ -45,18 +46,7 @@
|
|
|
45
46
|
};
|
|
46
47
|
|
|
47
48
|
function formatRelativeDate(date: Date): string {
|
|
48
|
-
|
|
49
|
-
const diff = now.getTime() - date.getTime();
|
|
50
|
-
const minutes = Math.floor(diff / 60000);
|
|
51
|
-
const hours = Math.floor(diff / 3600000);
|
|
52
|
-
const days = Math.floor(diff / 86400000);
|
|
53
|
-
|
|
54
|
-
if (minutes < 1) return interfaceLanguage.current === 'pl' ? 'teraz' : 'now';
|
|
55
|
-
if (minutes < 60)
|
|
56
|
-
return interfaceLanguage.current === 'pl' ? `${minutes} min` : `${minutes}m`;
|
|
57
|
-
if (hours < 24)
|
|
58
|
-
return interfaceLanguage.current === 'pl' ? `${hours} godz.` : `${hours}h`;
|
|
59
|
-
return interfaceLanguage.current === 'pl' ? `${days} dni` : `${days}d`;
|
|
49
|
+
return formatRelativeDateUtil(date, interfaceLanguage.current);
|
|
60
50
|
}
|
|
61
51
|
</script>
|
|
62
52
|
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import { useInterfaceLanguage } from '../../state/interface-language.svelte.js';
|
|
3
|
+
import { formatRelativeDate as formatRelativeDateUtil } from '../../utils/formatDate.js';
|
|
3
4
|
import * as Card from '../../../components/ui/card/index.js';
|
|
4
5
|
import Skeleton from '../../../components/ui/skeleton/skeleton.svelte';
|
|
5
6
|
import { getRemotes } from '../../../sveltekit/index.js';
|
|
@@ -34,18 +35,7 @@
|
|
|
34
35
|
};
|
|
35
36
|
|
|
36
37
|
function formatRelativeDate(date: Date): string {
|
|
37
|
-
|
|
38
|
-
const diff = now.getTime() - date.getTime();
|
|
39
|
-
const minutes = Math.floor(diff / 60000);
|
|
40
|
-
const hours = Math.floor(diff / 3600000);
|
|
41
|
-
const days = Math.floor(diff / 86400000);
|
|
42
|
-
|
|
43
|
-
if (minutes < 1) return interfaceLanguage.current === 'pl' ? 'teraz' : 'now';
|
|
44
|
-
if (minutes < 60)
|
|
45
|
-
return interfaceLanguage.current === 'pl' ? `${minutes} min temu` : `${minutes}m ago`;
|
|
46
|
-
if (hours < 24)
|
|
47
|
-
return interfaceLanguage.current === 'pl' ? `${hours} godz. temu` : `${hours}h ago`;
|
|
48
|
-
return interfaceLanguage.current === 'pl' ? `${days} dni temu` : `${days}d ago`;
|
|
38
|
+
return formatRelativeDateUtil(date, interfaceLanguage.current);
|
|
49
39
|
}
|
|
50
40
|
</script>
|
|
51
41
|
|
|
@@ -2,12 +2,13 @@
|
|
|
2
2
|
import { toggleMode } from 'mode-watcher';
|
|
3
3
|
import Sun from '@tabler/icons-svelte/icons/sun';
|
|
4
4
|
import Moon from '@tabler/icons-svelte/icons/moon';
|
|
5
|
-
import { useInterfaceLanguage } from '../../state/interface-language.svelte.js';
|
|
5
|
+
import { useInterfaceLanguage, locales } from '../../state/interface-language.svelte.js';
|
|
6
6
|
|
|
7
7
|
const interfaceLanguage = useInterfaceLanguage();
|
|
8
8
|
|
|
9
9
|
function toggleLanguage() {
|
|
10
|
-
|
|
10
|
+
const idx = locales.indexOf(interfaceLanguage.current);
|
|
11
|
+
interfaceLanguage.current = locales[(idx + 1) % locales.length];
|
|
11
12
|
}
|
|
12
13
|
</script>
|
|
13
14
|
|
|
@@ -23,6 +24,6 @@
|
|
|
23
24
|
onclick={toggleLanguage}
|
|
24
25
|
class="text-foreground/70 hover:text-foreground flex size-8 items-center justify-center rounded-md border border-black/10 text-xs font-semibold transition-colors hover:bg-black/5 dark:border-white/10 dark:hover:bg-white/10"
|
|
25
26
|
>
|
|
26
|
-
{interfaceLanguage.current
|
|
27
|
+
{interfaceLanguage.current.toUpperCase()}
|
|
27
28
|
</button>
|
|
28
29
|
</div>
|
|
@@ -65,6 +65,10 @@
|
|
|
65
65
|
})
|
|
66
66
|
);
|
|
67
67
|
|
|
68
|
+
const allFilesQuery = $derived(
|
|
69
|
+
remotes.getMediaFiles({ data: { mimeTypes: accept?.split(',') } })
|
|
70
|
+
);
|
|
71
|
+
|
|
68
72
|
let tagsQuery = $derived(remotes.getMediaTags());
|
|
69
73
|
|
|
70
74
|
// Multi-select with shift/ctrl
|
|
@@ -99,6 +103,7 @@
|
|
|
99
103
|
await remotes.deleteMediaFile(currentFile.id);
|
|
100
104
|
toast.success(lang[interfaceLanguage.current].fileDeletedToast);
|
|
101
105
|
filesQuery.refresh();
|
|
106
|
+
allFilesQuery.refresh();
|
|
102
107
|
currentFile = null;
|
|
103
108
|
}
|
|
104
109
|
}
|
|
@@ -109,6 +114,7 @@
|
|
|
109
114
|
const tags = (await tagsQuery) as MediaTag[];
|
|
110
115
|
currentFile = { ...currentFile, tags: tags.filter((t) => tagIds.includes(t.id)) };
|
|
111
116
|
await filesQuery.refresh();
|
|
117
|
+
await allFilesQuery.refresh();
|
|
112
118
|
}
|
|
113
119
|
}
|
|
114
120
|
|
|
@@ -133,12 +139,14 @@
|
|
|
133
139
|
await remotes.updateMediaTag({ id, name, color });
|
|
134
140
|
await tagsQuery.refresh();
|
|
135
141
|
await filesQuery.refresh();
|
|
142
|
+
await allFilesQuery.refresh();
|
|
136
143
|
}
|
|
137
144
|
|
|
138
145
|
async function handleDeleteTag(id: string) {
|
|
139
146
|
await remotes.deleteMediaTag(id);
|
|
140
147
|
await tagsQuery.refresh();
|
|
141
148
|
await filesQuery.refresh();
|
|
149
|
+
await allFilesQuery.refresh();
|
|
142
150
|
}
|
|
143
151
|
|
|
144
152
|
// Bulk operations
|
|
@@ -146,6 +154,7 @@
|
|
|
146
154
|
const fileIds = selectedFileIds;
|
|
147
155
|
await remotes.bulkSetMediaFileTags({ fileIds, tagIds });
|
|
148
156
|
await filesQuery.refresh();
|
|
157
|
+
await allFilesQuery.refresh();
|
|
149
158
|
}
|
|
150
159
|
|
|
151
160
|
async function handleBulkDelete() {
|
|
@@ -154,6 +163,7 @@
|
|
|
154
163
|
selectedFileIds = [];
|
|
155
164
|
currentFile = null;
|
|
156
165
|
await filesQuery.refresh();
|
|
166
|
+
await allFilesQuery.refresh();
|
|
157
167
|
}
|
|
158
168
|
|
|
159
169
|
onMount(() => {
|
|
@@ -168,10 +178,10 @@
|
|
|
168
178
|
<div class="flex h-full" bind:this={dropZoneRef}>
|
|
169
179
|
<!-- Tag sidebar -->
|
|
170
180
|
<div class="w-48 shrink-0 border-r p-3">
|
|
171
|
-
{#await tagsQuery then tags}
|
|
181
|
+
{#await Promise.all([tagsQuery, allFilesQuery]) then [tags, allFiles]}
|
|
172
182
|
<TagSidebar
|
|
173
183
|
{tags}
|
|
174
|
-
files={
|
|
184
|
+
files={allFiles}
|
|
175
185
|
activeFilter={activeTagFilter}
|
|
176
186
|
onFilterChange={(f) => (activeTagFilter = f)}
|
|
177
187
|
onCreateTag={handleCreateTag}
|
|
@@ -187,7 +197,7 @@
|
|
|
187
197
|
<MediaSearch bind:value={searchQuery} />
|
|
188
198
|
<MediaSort />
|
|
189
199
|
<FileUpload
|
|
190
|
-
onUpload={() => filesQuery.refresh()}
|
|
200
|
+
onUpload={() => { filesQuery.refresh(); allFilesQuery.refresh(); }}
|
|
191
201
|
{accept}
|
|
192
202
|
bind:dropZoneRef
|
|
193
203
|
/>
|
|
@@ -234,6 +244,7 @@
|
|
|
234
244
|
onReplace={(updated) => {
|
|
235
245
|
currentFile = updated;
|
|
236
246
|
filesQuery.refresh();
|
|
247
|
+
allFilesQuery.refresh();
|
|
237
248
|
}}
|
|
238
249
|
{onTagUpdate}
|
|
239
250
|
{onNameUpdate}
|
|
@@ -256,15 +267,15 @@
|
|
|
256
267
|
|
|
257
268
|
<!-- Bulk action bar -->
|
|
258
269
|
{#if selectedFileIds.length > 0}
|
|
259
|
-
{#await tagsQuery then tags}
|
|
270
|
+
{#await Promise.all([tagsQuery, allFilesQuery]) then [tags, allFiles]}
|
|
260
271
|
<BulkActionBar
|
|
261
272
|
selectedCount={selectedFileIds.length}
|
|
262
|
-
totalCount={
|
|
273
|
+
totalCount={allFiles.length}
|
|
263
274
|
{tags}
|
|
264
275
|
onBulkTag={handleBulkTag}
|
|
265
276
|
onBulkDelete={handleBulkDelete}
|
|
266
277
|
onClear={() => (selectedFileIds = [])}
|
|
267
|
-
onSelectAll={() => {}}
|
|
278
|
+
onSelectAll={() => { selectedFileIds = allFiles.map((f) => f.id); }}
|
|
268
279
|
onCreateTag={handleCreateTag}
|
|
269
280
|
onUpdateTagColor={async (id, color) => {
|
|
270
281
|
const tag = tags.find((t) => t.id === id);
|
|
@@ -3,7 +3,16 @@ export declare const getRawEntries: import("@sveltejs/kit").RemoteQueryFunction<
|
|
|
3
3
|
ids?: string[] | undefined;
|
|
4
4
|
slug?: string | undefined;
|
|
5
5
|
onlyArchived?: boolean | undefined;
|
|
6
|
-
|
|
6
|
+
limit?: number | undefined;
|
|
7
|
+
offset?: number | undefined;
|
|
8
|
+
orderBy?: {
|
|
9
|
+
column: "createdAt" | "updatedAt";
|
|
10
|
+
direction: "asc" | "desc";
|
|
11
|
+
} | undefined;
|
|
12
|
+
}, {
|
|
13
|
+
entries: RawEntry[];
|
|
14
|
+
total: number;
|
|
15
|
+
}>;
|
|
7
16
|
export declare const getEntries: import("@sveltejs/kit").RemoteQueryFunction<{
|
|
8
17
|
ids?: string[] | undefined;
|
|
9
18
|
dataValues?: Record<string, unknown> | undefined;
|
|
@@ -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, 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 } from '../../core/server/entries/operations/get.js';
|
|
4
4
|
import { getCMS } from '../../core/cms.js';
|
|
5
5
|
import { pruneOldDraftVersions, unpublishEntry, updateEntry, updateEntrySchema, updateEntryVersionCommandTypes } from '../../core/server/entries/operations/update.js';
|
|
6
6
|
import z from 'zod';
|
|
@@ -9,10 +9,22 @@ import { entryStatuses } from '../../types/entries.js';
|
|
|
9
9
|
export const getRawEntries = query(z.object({
|
|
10
10
|
ids: z.array(z.string().uuid()).optional(),
|
|
11
11
|
slug: z.string().optional(),
|
|
12
|
-
onlyArchived: z.boolean().optional()
|
|
12
|
+
onlyArchived: z.boolean().optional(),
|
|
13
|
+
limit: z.number().int().positive().optional(),
|
|
14
|
+
offset: z.number().int().nonnegative().optional(),
|
|
15
|
+
orderBy: z
|
|
16
|
+
.object({
|
|
17
|
+
column: z.enum(['createdAt', 'updatedAt']),
|
|
18
|
+
direction: z.enum(['asc', 'desc'])
|
|
19
|
+
})
|
|
20
|
+
.optional()
|
|
13
21
|
}), async (input) => {
|
|
14
|
-
|
|
15
|
-
|
|
22
|
+
const { limit, offset, orderBy, ...filterOptions } = input;
|
|
23
|
+
const [entries, total] = await Promise.all([
|
|
24
|
+
getRawEntriesOperation(input),
|
|
25
|
+
countRawEntriesOperation(filterOptions)
|
|
26
|
+
]);
|
|
27
|
+
return { entries, total };
|
|
16
28
|
});
|
|
17
29
|
export const getEntries = query(z.object({
|
|
18
30
|
ids: z.array(z.string().uuid()).optional(),
|
|
@@ -1,8 +1,5 @@
|
|
|
1
1
|
import type { InterfaceLanguage as InterfaceLanguageType } from '../../types/languages.js';
|
|
2
|
-
export declare
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
set current(value: InterfaceLanguageType);
|
|
7
|
-
}
|
|
8
|
-
export declare function useInterfaceLanguage(): InterfaceLanguage;
|
|
2
|
+
export declare function useInterfaceLanguage(): {
|
|
3
|
+
current: InterfaceLanguageType;
|
|
4
|
+
};
|
|
5
|
+
export { locales } from '../../paraglide/runtime.js';
|
|
@@ -1,25 +1,26 @@
|
|
|
1
1
|
import { PersistedState } from 'runed';
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
2
|
+
import { locales, baseLocale } from '../../paraglide/runtime.js';
|
|
3
|
+
function detectDefaultLocale() {
|
|
4
|
+
if (typeof navigator === 'undefined')
|
|
5
|
+
return baseLocale;
|
|
6
|
+
const langs = navigator.languages ?? [navigator.language];
|
|
7
|
+
for (const lang of langs) {
|
|
8
|
+
const base = lang.split('-')[0].toLowerCase();
|
|
9
|
+
if (locales.includes(base))
|
|
10
|
+
return base;
|
|
9
11
|
}
|
|
12
|
+
return baseLocale;
|
|
13
|
+
}
|
|
14
|
+
const state = new PersistedState('interface-language', detectDefaultLocale());
|
|
15
|
+
const interfaceLanguage = {
|
|
10
16
|
get current() {
|
|
11
|
-
return
|
|
12
|
-
}
|
|
17
|
+
return state.current;
|
|
18
|
+
},
|
|
13
19
|
set current(value) {
|
|
14
|
-
|
|
20
|
+
state.current = value;
|
|
15
21
|
}
|
|
16
|
-
}
|
|
22
|
+
};
|
|
17
23
|
export function useInterfaceLanguage() {
|
|
18
|
-
|
|
19
|
-
return getInterfaceLanguage();
|
|
20
|
-
}
|
|
21
|
-
catch {
|
|
22
|
-
setInterfaceLanguage(new InterfaceLanguage());
|
|
23
|
-
return getInterfaceLanguage();
|
|
24
|
-
}
|
|
24
|
+
return interfaceLanguage;
|
|
25
25
|
}
|
|
26
|
+
export { locales } from '../../paraglide/runtime.js';
|
|
@@ -1,3 +1,4 @@
|
|
|
1
1
|
import type { InterfaceLanguage } from '../../types/languages.js';
|
|
2
|
+
export declare function toLocaleCode(lang: string): string;
|
|
2
3
|
export declare function formatRelativeDate(date: Date | string, lang?: InterfaceLanguage): string;
|
|
3
4
|
export declare function formatAbsoluteDate(date: Date | string, lang?: InterfaceLanguage): string;
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
export function toLocaleCode(lang) {
|
|
2
|
+
const map = { pl: 'pl-PL', en: 'en-US' };
|
|
3
|
+
return map[lang] ?? lang;
|
|
4
|
+
}
|
|
1
5
|
const units = [
|
|
2
6
|
{ unit: 'year', ms: 365 * 24 * 60 * 60 * 1000 },
|
|
3
7
|
{ unit: 'month', ms: 30 * 24 * 60 * 60 * 1000 },
|
|
@@ -84,7 +88,7 @@ export function formatRelativeDate(date, lang = 'en') {
|
|
|
84
88
|
}
|
|
85
89
|
export function formatAbsoluteDate(date, lang = 'en') {
|
|
86
90
|
const d = typeof date === 'string' ? new Date(date) : date;
|
|
87
|
-
return d.toLocaleString(lang
|
|
91
|
+
return d.toLocaleString(toLocaleCode(lang), {
|
|
88
92
|
year: 'numeric',
|
|
89
93
|
month: 'short',
|
|
90
94
|
day: 'numeric',
|
|
@@ -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" | "
|
|
5
|
+
type?: "number" | "image" | "url" | "text" | "date" | "radio" | "email" | "checkbox" | "hidden" | (string & {}) | "password" | "reset" | "search" | "time" | "color" | "button" | "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" | "
|
|
5
|
+
type?: "number" | "image" | "url" | "text" | "date" | "radio" | "email" | "checkbox" | "hidden" | (string & {}) | "password" | "reset" | "search" | "time" | "color" | "button" | "submit" | "tel" | "datetime-local" | "month" | "range" | "week";
|
|
6
6
|
files?: undefined;
|
|
7
7
|
})) & {
|
|
8
8
|
ref?: HTMLElement | null | undefined;
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import type { DbEntry, DbEntryVersion, Entry, GetDbEntriesOptions, GetDbEntryOptions, GetDbEntryVersionOptions, GetDbEntryVersionsOptions, GetEntriesOptions, GetEntryOptions, GetRawEntriesOptions, getRawEntryOptions, RawEntry } from '../../../../types/entries.js';
|
|
2
2
|
export declare const getDbEntries: (options: GetDbEntriesOptions) => Promise<DbEntry[]>;
|
|
3
|
+
export declare const countDbEntries: (options: Omit<GetDbEntriesOptions, "limit" | "offset" | "orderBy">) => Promise<number>;
|
|
3
4
|
export declare const getDbEntry: (options: GetDbEntryOptions) => Promise<DbEntry | null>;
|
|
4
5
|
export declare const getDbEntryOrThrow: (options: GetDbEntryOptions) => Promise<DbEntry>;
|
|
6
|
+
export declare const countRawEntries: (options: Omit<GetRawEntriesOptions, "limit" | "offset" | "orderBy">) => Promise<number>;
|
|
5
7
|
export declare const getRawEntries: (options: GetRawEntriesOptions) => Promise<RawEntry[]>;
|
|
6
8
|
export declare const getRawEntry: (options: getRawEntryOptions) => Promise<RawEntry | null>;
|
|
7
9
|
export declare const getRawEntryOrThrow: (options: getRawEntryOptions) => Promise<RawEntry>;
|