feat(documents): add a "Nur undatierte" filter toggle wired to the URL

SearchFilterBar gains an aria-pressed "Nur undatierte" toggle in the
advanced row (min-h-[44px] touch target, labels the state not the colour).
The documents page threads `undated` through the filter snapshot so it is a
shareable URL param picked up by both filter-change nav and pagination, and
flows into the bulk-edit "select all" /ids request. Toggling resets to page
0 via the existing implicit page-drop.

Refs #668
This commit is contained in:
Marcel
2026-05-27 18:53:44 +02:00
parent 5d8bb70255
commit 098c2c9def
3 changed files with 81 additions and 3 deletions

View File

@@ -32,10 +32,16 @@ let sort = $state(untrack(() => data.sort || 'DATE'));
let dir = $state(untrack(() => data.dir || 'desc'));
let tagQ = $state(untrack(() => data.tagQ || ''));
let tagOperator = $state<'AND' | 'OR'>(untrack(() => (data.tagOp as 'AND' | 'OR') || 'AND'));
let undated = $state(untrack(() => data.undated ?? false));
function hasAdvancedFilters() {
return (
(data.tags?.length ?? 0) > 0 || !!data.senderId || !!data.receiverId || !!data.from || !!data.to
(data.tags?.length ?? 0) > 0 ||
!!data.senderId ||
!!data.receiverId ||
!!data.from ||
!!data.to ||
!!data.undated
);
}
@@ -54,6 +60,7 @@ type FilterSnapshot = {
dir: string;
tagQ: string;
tagOp: 'AND' | 'OR';
undated: boolean;
zoomFrom?: string | null;
zoomTo?: string | null;
};
@@ -77,6 +84,7 @@ function buildSearchParams(filters: FilterSnapshot, targetPage?: number): Svelte
if (filters.dir) params.set('dir', filters.dir);
if (filters.tagQ) params.set('tagQ', filters.tagQ);
if (filters.tagOp === 'OR') params.set('tagOp', 'OR');
if (filters.undated) params.set('undated', 'true');
if (filters.zoomFrom) params.set('zoomFrom', filters.zoomFrom);
if (filters.zoomTo) params.set('zoomTo', filters.zoomTo);
if (targetPage !== undefined && targetPage > 0) params.set('page', String(targetPage));
@@ -112,6 +120,7 @@ function navigateWithZoom(zoomFrom: string | null, zoomTo: string | null) {
dir,
tagQ,
tagOp: tagOperator,
undated,
zoomFrom,
zoomTo
});
@@ -136,7 +145,8 @@ function buildPageHref(targetPage: number): string {
sort: data.sort || '',
dir: data.dir || '',
tagQ: data.tagQ || '',
tagOp: (data.tagOp as 'AND' | 'OR') || 'AND'
tagOp: (data.tagOp as 'AND' | 'OR') || 'AND',
undated: data.undated ?? false
},
targetPage
);
@@ -188,7 +198,8 @@ async function editAllMatching() {
sort: '',
dir: '',
tagQ: data.tagQ || '',
tagOp: (data.tagOp as 'AND' | 'OR') || 'AND'
tagOp: (data.tagOp as 'AND' | 'OR') || 'AND',
undated: data.undated ?? false
});
params.delete('sort');
params.delete('dir');
@@ -226,6 +237,7 @@ $effect(() => {
dir = data.dir || 'desc';
tagQ = data.tagQ || '';
tagOperator = (data.tagOp as 'AND' | 'OR') || 'AND';
undated = data.undated ?? false;
if (hasAdvancedFilters()) showAdvanced = true;
});
</script>
@@ -255,6 +267,7 @@ $effect(() => {
bind:dir={dir}
bind:tagQ={tagQ}
bind:tagOperator={tagOperator}
bind:undated={undated}
initialSenderName={initialSenderName}
initialReceiverName={initialReceiverName}
navKey={navKey}