feat(feed): saved views as a header popover + Personal Views modal + a view chip
Retire the standalone 'Saved views' sidebar panel. The saved-views feature now
lives in three lighter surfaces, coordinated by a new SavedViewsProvider (query +
CRUD + the active/sticky view + modal state):
- the filter panel's header ICON opens a quick-pick popover (apply a view, active
one checked, plus 'Manage views…');
- the header TITLE ('Filters') opens a new Personal Views modal — a master/detail
manager: left = the reorderable list + a save-current-filters input, right = the
selected view's name, its captured filters (shown as the same chips the toolbar
row uses), default toggle, apply, and delete;
- a SelectedViewChip leads the applied-filter row, naming the active view with a
warn-coloured 'modified' dot once the live filters diverge from it; clicking it
reopens the picker.
SidePanel/FilterRail gain optional iconExpanded + onTitleClick slots (feed-only,
hidden for the demo account); the collapsed tab keeps its plain pin behaviour.
SavedViewsWidget is deleted and dropped from the panel layout.
Verified live: icon popover lists HH + Manage; applying HH surfaces the chip and
switches scope; removing a filter lights the dirty dot; the title opens the
master/detail modal with the captured-filters summary. 374 vitest, tsc, eslint
(0 err).
This commit is contained in:
@@ -20,6 +20,8 @@ export default function SidePanel({
|
||||
onReset,
|
||||
editHint,
|
||||
actions,
|
||||
iconExpanded,
|
||||
onTitleClick,
|
||||
children,
|
||||
}: {
|
||||
title: string;
|
||||
@@ -34,6 +36,11 @@ export default function SidePanel({
|
||||
editHint?: string;
|
||||
// Extra header controls shown when NOT editing (e.g. the feed's Clear all + Share view).
|
||||
actions?: ReactNode;
|
||||
// Optional override for the icon in the EXPANDED header only (the collapsed tab keeps the plain
|
||||
// `icon`) — the feed passes its saved-views popover trigger here so the header icon opens the picker.
|
||||
iconExpanded?: ReactNode;
|
||||
// When set, the expanded-header title becomes a button (the feed opens its Personal Views modal).
|
||||
onTitleClick?: () => void;
|
||||
children: ReactNode;
|
||||
}) {
|
||||
const { t } = useTranslation();
|
||||
@@ -99,10 +106,19 @@ export default function SidePanel({
|
||||
>
|
||||
{pinned ? <PinOff className="w-4 h-4" /> : <Pin className="w-4 h-4" />}
|
||||
</button>
|
||||
<span className="shrink-0 flex text-accent">{icon}</span>
|
||||
<span className="flex-1 min-w-0 truncate text-sm font-bold uppercase tracking-[0.12em]">
|
||||
{title}
|
||||
</span>
|
||||
{iconExpanded ?? <span className="shrink-0 flex text-accent">{icon}</span>}
|
||||
{onTitleClick ? (
|
||||
<button
|
||||
onClick={onTitleClick}
|
||||
className="flex-1 min-w-0 truncate text-left text-sm font-bold uppercase tracking-[0.12em] transition hover:text-accent"
|
||||
>
|
||||
{title}
|
||||
</button>
|
||||
) : (
|
||||
<span className="flex-1 min-w-0 truncate text-sm font-bold uppercase tracking-[0.12em]">
|
||||
{title}
|
||||
</span>
|
||||
)}
|
||||
{count > 0 && (
|
||||
<span
|
||||
title={t("sidebar.activeCount", { count })}
|
||||
|
||||
Reference in New Issue
Block a user