feat(views): saved-views UI — sidebar widget, apply/rename/default/reorder/share
A new "Saved views" filter-sidebar widget (SavedViewsWidget): save the current filters under a name, apply one with a click (active-highlighted when it matches), rename, delete (confirm), drag-reorder, share by link (reuses shareUrl), and star one as the default. The default view's filters are mirrored to localStorage so loadInitialFilters applies it synchronously on load/F5 (an api/url share link still wins; no default → last-session filters as before). Hidden for the demo account. EN/HU/DE.
This commit is contained in:
parent
3056734231
commit
0a358fa82e
12 changed files with 429 additions and 3 deletions
|
|
@ -188,6 +188,15 @@ export interface FeedFilters {
|
|||
dateTo?: string;
|
||||
}
|
||||
|
||||
// A saved "smart view": a per-user named snapshot of FeedFilters (see SavedViewsWidget).
|
||||
export interface SavedView {
|
||||
id: number;
|
||||
name: string;
|
||||
filters: FeedFilters;
|
||||
position: number;
|
||||
is_default: boolean;
|
||||
}
|
||||
|
||||
export interface VersionInfo {
|
||||
app_version: string;
|
||||
git_sha: string;
|
||||
|
|
@ -831,6 +840,20 @@ export const api = {
|
|||
req(`/api/me/notifications/${id}/dismiss`, { method: "POST" }),
|
||||
clearNotifications: () => req("/api/me/notifications/clear", { method: "POST" }),
|
||||
|
||||
// --- saved smart views (named FeedFilters snapshots) ---
|
||||
savedViews: (): Promise<SavedView[]> => req("/api/saved-views"),
|
||||
createView: (name: string, filters: FeedFilters): Promise<SavedView> =>
|
||||
req("/api/saved-views", { method: "POST", body: JSON.stringify({ name, filters }) }),
|
||||
updateView: (
|
||||
id: number,
|
||||
patch: Partial<{ name: string; filters: FeedFilters; is_default: boolean }>,
|
||||
): Promise<SavedView> =>
|
||||
req(`/api/saved-views/${id}`, { method: "PATCH", body: JSON.stringify(patch) }),
|
||||
deleteView: (id: number): Promise<{ deleted: number }> =>
|
||||
req(`/api/saved-views/${id}`, { method: "DELETE" }),
|
||||
reorderViews: (ids: number[]): Promise<{ ok: boolean }> =>
|
||||
req("/api/saved-views/reorder", { method: "POST", body: JSON.stringify({ ids }) }),
|
||||
|
||||
// --- direct messages (end-to-end encrypted) ---
|
||||
messageMyKey: (): Promise<MyKeyBundle> => req("/api/messages/keys/me"),
|
||||
setupMessageKey: (k: KeySetup): Promise<{ configured: boolean }> =>
|
||||
|
|
|
|||
|
|
@ -6,11 +6,12 @@
|
|||
// longer sidebar widgets. normalizeLayout drops them from any persisted layout automatically.
|
||||
import { LS, readJSON, writeJSON } from "./storage";
|
||||
|
||||
export type WidgetId = "date" | "language" | "topic" | "tags";
|
||||
export type WidgetId = "savedviews" | "date" | "language" | "topic" | "tags";
|
||||
|
||||
export const ALL_WIDGETS: WidgetId[] = ["date", "language", "topic", "tags"];
|
||||
export const ALL_WIDGETS: WidgetId[] = ["savedviews", "date", "language", "topic", "tags"];
|
||||
|
||||
export const WIDGET_TITLES: Record<WidgetId, string> = {
|
||||
savedviews: "Saved views",
|
||||
date: "Upload date",
|
||||
language: "Language",
|
||||
topic: "Topic",
|
||||
|
|
|
|||
|
|
@ -9,6 +9,9 @@ export const LS = {
|
|||
hints: "siftlode.hints",
|
||||
lang: "siftlode.lang",
|
||||
filters: "siftlode.filters",
|
||||
// Mirror of the default saved view's filters, so it can be applied synchronously on load
|
||||
// (before the async saved-views query resolves). Kept in sync by SavedViewsWidget.
|
||||
defaultViewFilters: "siftlode.defaultViewFilters",
|
||||
page: "siftlode.page",
|
||||
perfMode: "siftlode.perfMode",
|
||||
channelFilter: "siftlode.channelFilter",
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue