Files
siftlode/frontend/src/components/filesContext.ts
T
peter 85aa917b38 feat(files): the Files page — the library in one aligned list, its folders in a rail
Files is the one library: every done file, the ones shared with me, or one
folder's, picked in a side rail (sources, own folders, the storage meter) and
mirrored to ?folder=. One table with every kind of value in its own column;
Copy link, Share and Save in sight, every action on a right click: play,
cut, rename in the row, move to an own folder or back home, keep, details,
re-download, delete.

The Downloads page keeps only the queue until the tray replaces it. The old
/api/downloads library routes are gone: list shared, upload, the details
PATCH, delete, the file and the usage now live under /api/files, and a
listed file says which source it came from. The job's "expired" flag is gone
with the state it described.
2026-10-11 05:34:25 +02:00

48 lines
1.7 KiB
TypeScript

import { createContext, useContext } from "react";
// The Files module's contexts + hooks, split out of FilesProvider so that file exports only
// components (Fast Refresh).
/** What the Files page lists: every file of mine, the ones shared with me, or one folder's. */
export type FilesView = { kind: "all" } | { kind: "shared" } | { kind: "folder"; id: number };
export const ALL_FILES: FilesView = { kind: "all" };
/** The view as one string — the `?folder=` bookmark and the remembered view share it. */
export function viewParam(view: FilesView): string {
return view.kind === "folder" ? String(view.id) : view.kind;
}
/** The view a stored or bookmarked string names; anything else is the whole library. */
export function parseView(raw: string | null | undefined): FilesView | null {
if (raw === "all") return ALL_FILES;
if (raw === "shared") return { kind: "shared" };
const id = raw && /^[1-9]\d*$/.test(raw) ? Number(raw) : null;
return id !== null && Number.isSafeInteger(id) ? { kind: "folder", id } : null;
}
export const sameView = (a: FilesView, b: FilesView): boolean => viewParam(a) === viewParam(b);
export type FilesState = {
search: string;
view: FilesView;
};
export interface FilesActions {
setSearch: (q: string) => void;
setView: (view: FilesView) => void;
}
export const FilesStateContext = createContext<FilesState>({ search: "", view: ALL_FILES });
export const FilesActionsContext = createContext<FilesActions>({
setSearch: () => {},
setView: () => {},
});
export function useFiles(): FilesState {
return useContext(FilesStateContext);
}
export function useFilesActions(): FilesActions {
return useContext(FilesActionsContext);
}