feat(frontend): implement file selection with long-press, shift+click, and touch drag
- selection.ts: store with select/deselect/toggle/enter/exit, derived count and active - FileCard: long-press (400ms) enters selection mode, shows check overlay, blocks context menu - Header: Select/Cancel button toggles selection mode - SelectionBar: floating bar above navbar with count, Edit tags, Add to pool, Delete - Shift+click range-selects between last and current index (desktop) - Touch drag-to-select/deselect after long-press; non-passive touchmove blocks scroll only during drag Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,65 @@
|
||||
import { writable, derived } from 'svelte/store';
|
||||
|
||||
interface SelectionState {
|
||||
active: boolean;
|
||||
ids: Set<string>;
|
||||
}
|
||||
|
||||
function createSelectionStore() {
|
||||
const { subscribe, update, set } = writable<SelectionState>({
|
||||
active: false,
|
||||
ids: new Set(),
|
||||
});
|
||||
|
||||
return {
|
||||
subscribe,
|
||||
|
||||
enter() {
|
||||
update((s) => ({ ...s, active: true }));
|
||||
},
|
||||
|
||||
exit() {
|
||||
set({ active: false, ids: new Set() });
|
||||
},
|
||||
|
||||
toggle(id: string) {
|
||||
update((s) => {
|
||||
const ids = new Set(s.ids);
|
||||
if (ids.has(id)) {
|
||||
ids.delete(id);
|
||||
} else {
|
||||
ids.add(id);
|
||||
}
|
||||
// Exit selection mode automatically when last item is deselected
|
||||
const active = ids.size > 0;
|
||||
return { active, ids };
|
||||
});
|
||||
},
|
||||
|
||||
select(id: string) {
|
||||
update((s) => {
|
||||
const ids = new Set(s.ids);
|
||||
ids.add(id);
|
||||
return { active: true, ids };
|
||||
});
|
||||
},
|
||||
|
||||
deselect(id: string) {
|
||||
update((s) => {
|
||||
const ids = new Set(s.ids);
|
||||
ids.delete(id);
|
||||
const active = ids.size > 0;
|
||||
return { active, ids };
|
||||
});
|
||||
},
|
||||
|
||||
clear() {
|
||||
set({ active: false, ids: new Set() });
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export const selectionStore = createSelectionStore();
|
||||
|
||||
export const selectionCount = derived(selectionStore, ($s) => $s.ids.size);
|
||||
export const selectionActive = derived(selectionStore, ($s) => $s.active);
|
||||
Reference in New Issue
Block a user