feat(search): live YouTube search UI
Surface live YouTube search in the existing feed, triggered explicitly so the expensive API call is never per-keystroke. - Header: the search box still filters the local catalog as you type; Enter or a YouTube button escalates the term to a live search (hidden for the demo account). - Feed: a dedicated infinite query renders results in the same VirtualFeed cards + in-app player, under a banner with a back button and a quota note. No auto-paginate (each page spends 100 units) — an explicit 'Load more (uses quota)' button instead; quota/limit errors (incl. 429) shown inline. The empty local feed offers a 'Search YouTube for <q>' CTA. - Library: a 'Search-discovered' toggle reveals search-ingested videos (hidden by default); sent as exclude_search_discovered. - Admin: search_daily_limit_per_user config field; new videos_search quota label. - All new strings translated in HU/EN/DE.
This commit is contained in:
parent
9b1bdb6b42
commit
546be57963
16 changed files with 240 additions and 15 deletions
|
|
@ -122,6 +122,9 @@ export default function App() {
|
|||
const saveMsgTimer = useRef<number | undefined>(undefined);
|
||||
const [sidebarLayout, setSidebarLayoutState] = useState<SidebarLayout>(loadLayout);
|
||||
const [page, setPageState] = useState<Page>(loadInitialPage);
|
||||
// Live YouTube search term (null = normal feed). Ephemeral: not persisted and not in the URL,
|
||||
// so a reload returns to the normal feed (a search spends quota, so we never auto-replay it).
|
||||
const [ytSearch, setYtSearch] = useState<string | null>(null);
|
||||
const [wizardOpen, setWizardOpen] = useState(false);
|
||||
// Channel status chip, persisted so a reload (F5) keeps it; clamp a stale value at render.
|
||||
const [channelFilterRaw, setChannelFilter] = usePersistedState(LS.channelFilter, "all");
|
||||
|
|
@ -153,6 +156,8 @@ export default function App() {
|
|||
};
|
||||
useEffect(() => {
|
||||
if (page !== "channels") setFocusChannelName(null);
|
||||
// Leaving the feed ends any live YouTube search, so coming back shows the normal feed.
|
||||
if (page !== "feed") setYtSearch(null);
|
||||
}, [page]);
|
||||
|
||||
function openReleaseNotes(highlight?: string) {
|
||||
|
|
@ -500,6 +505,7 @@ export default function App() {
|
|||
filters={filters}
|
||||
setFilters={setFilters}
|
||||
page={page}
|
||||
onYtSearch={setYtSearch}
|
||||
onGoToFullHistory={() => {
|
||||
setChannelFilter("needs_full");
|
||||
setChannelsView("subscribed"); // the status filter applies to the subscriptions tab
|
||||
|
|
@ -572,6 +578,8 @@ export default function App() {
|
|||
canRead={meQuery.data!.can_read}
|
||||
isDemo={meQuery.data!.is_demo}
|
||||
onOpenWizard={() => setWizardOpen(true)}
|
||||
ytSearch={ytSearch}
|
||||
setYtSearch={setYtSearch}
|
||||
/>
|
||||
)}
|
||||
</main>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue