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).
35 lines
1.5 KiB
TypeScript
35 lines
1.5 KiB
TypeScript
import { useTranslation } from "react-i18next";
|
|
import { Bookmark, ChevronDown } from "lucide-react";
|
|
import SavedViewsPopover from "./SavedViewsPopover";
|
|
import { useSavedViews } from "./SavedViewsProvider";
|
|
|
|
// The active personal view, shown as the leading pill before the active-filter chip row. Styled like
|
|
// the toolbar's FilterSelect pills; a warn-coloured dot appears when the live filters have diverged
|
|
// from the saved view. Clicking it opens the saved-views picker to switch views. Renders nothing when
|
|
// no view is active (nothing applied and the filters match no saved view).
|
|
export default function SelectedViewChip() {
|
|
const { t } = useTranslation();
|
|
const { displayView, isDirty } = useSavedViews();
|
|
if (!displayView) return null;
|
|
return (
|
|
<SavedViewsPopover
|
|
ariaLabel={t("views.saved")}
|
|
className="glass-card glass-hover inline-flex items-center gap-1.5 rounded-full border border-border px-3 py-1 text-sm text-fg transition hover:border-accent/60"
|
|
trigger={
|
|
<>
|
|
<Bookmark className="h-3.5 w-3.5 shrink-0 text-accent" aria-hidden="true" />
|
|
<span className="max-w-40 truncate">{displayView.name}</span>
|
|
{isDirty && (
|
|
<span
|
|
className="h-1.5 w-1.5 shrink-0 rounded-full bg-warn"
|
|
title={t("views.modified")}
|
|
aria-label={t("views.modified")}
|
|
/>
|
|
)}
|
|
<ChevronDown className="h-3.5 w-3.5 shrink-0 text-muted" aria-hidden="true" />
|
|
</>
|
|
}
|
|
/>
|
|
);
|
|
}
|