feat: feedback round 3 — content-type toggles, channel filter, card polish
- Content type is now three independent toggles (Normal / Shorts / Live·Upcoming); the feed is the union of enabled types (backend show_normal + include_shorts + include_live) - Per-channel filter: a button on each card scopes the feed to that channel, shown as a removable chip in the sidebar - Hide now refetches the feed once the change is persisted, so a hidden video shows up in the Hidden view immediately (no refresh needed); optimistic updates respect the current view - Grid cards are now distinct panels (card background, border, shadow) that lift on hover; clickable channel name in list view too
This commit is contained in:
parent
e07a37622d
commit
ecbecbb9f4
6 changed files with 115 additions and 30 deletions
|
|
@ -1,4 +1,5 @@
|
|||
import { useQuery } from "@tanstack/react-query";
|
||||
import { X } from "lucide-react";
|
||||
import { api, type FeedFilters, type Tag } from "../lib/api";
|
||||
|
||||
const SORTS = [
|
||||
|
|
@ -64,13 +65,27 @@ export default function Sidebar({
|
|||
|
||||
const active =
|
||||
filters.tags.length > 0 ||
|
||||
!filters.includeNormal ||
|
||||
filters.includeShorts ||
|
||||
filters.includeLive ||
|
||||
filters.show !== "unwatched" ||
|
||||
filters.sort !== "newest";
|
||||
filters.sort !== "newest" ||
|
||||
!!filters.channelId;
|
||||
|
||||
return (
|
||||
<aside className="w-64 shrink-0 border-r border-border bg-surface/40 overflow-y-auto p-4 space-y-5 hidden md:block">
|
||||
{filters.channelId && (
|
||||
<Section title="Channel">
|
||||
<button
|
||||
onClick={() => setFilters({ ...filters, channelId: undefined, channelName: undefined })}
|
||||
className="w-full flex items-center justify-between gap-2 text-sm px-3 py-2 rounded-lg bg-accent text-accent-fg shadow-sm hover:opacity-90 transition"
|
||||
>
|
||||
<span className="truncate">{filters.channelName ?? "This channel"}</span>
|
||||
<X className="w-4 h-4 shrink-0" />
|
||||
</button>
|
||||
</Section>
|
||||
)}
|
||||
|
||||
<Section title="Show">
|
||||
<div className="grid grid-cols-2 gap-1.5">
|
||||
{SHOWS.map((s) => (
|
||||
|
|
@ -103,14 +118,19 @@ export default function Sidebar({
|
|||
</select>
|
||||
</Section>
|
||||
|
||||
<Section title="Content">
|
||||
<Section title="Content type">
|
||||
<Toggle
|
||||
label="Include Shorts"
|
||||
label="Normal"
|
||||
checked={filters.includeNormal}
|
||||
onChange={(v) => setFilters({ ...filters, includeNormal: v })}
|
||||
/>
|
||||
<Toggle
|
||||
label="Shorts"
|
||||
checked={filters.includeShorts}
|
||||
onChange={(v) => setFilters({ ...filters, includeShorts: v })}
|
||||
/>
|
||||
<Toggle
|
||||
label="Include live / upcoming"
|
||||
label="Live / Upcoming"
|
||||
checked={filters.includeLive}
|
||||
onChange={(v) => setFilters({ ...filters, includeLive: v })}
|
||||
/>
|
||||
|
|
@ -167,6 +187,7 @@ export default function Sidebar({
|
|||
tagMode: "or",
|
||||
q: filters.q,
|
||||
sort: "newest",
|
||||
includeNormal: true,
|
||||
includeShorts: false,
|
||||
includeLive: false,
|
||||
show: "unwatched",
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue