From e1cdd6b2a56c9b423f923e35727943117cfca0db Mon Sep 17 00:00:00 2001 From: Michael Freno Date: Sun, 9 Aug 2026 14:38:33 -0400 Subject: [PATCH] finished hygenie --- src/components/LoadingIndicator.tsx | 1 - src/context/navigation-store.ts | 4 ---- src/hooks/useMultimediaKeys.ts | 14 ------------ src/pages/Discover/DiscoverPage.tsx | 1 - src/pages/MyShows/MyShowsPage.tsx | 1 - src/pages/Player/RealtimeWaveform.tsx | 5 ----- src/pages/Search/SearchPage.tsx | 3 +-- src/pages/Settings/SyncPanel.tsx | 20 +++-------------- src/types/feed.ts | 8 ------- src/ui/command.tsx | 2 -- src/ui/dialog.tsx | 2 +- tests/audio-dispose.test.ts | 4 ++-- tests/nav-model.test.ts | 2 +- tests/yazi-pages-depth.test.ts | 32 +++++++++++++-------------- 14 files changed, 24 insertions(+), 75 deletions(-) diff --git a/src/components/LoadingIndicator.tsx b/src/components/LoadingIndicator.tsx index ad4a4a4..bc5b1b3 100644 --- a/src/components/LoadingIndicator.tsx +++ b/src/components/LoadingIndicator.tsx @@ -3,7 +3,6 @@ import { useTheme } from "@/context/ThemeContext"; const spinnerChars = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"]; -//TODO: Watch for actual loading state (fetching feeds) export function LoadingIndicator() { const { theme } = useTheme(); const [index, setIndex] = createSignal(0); diff --git a/src/context/navigation-store.ts b/src/context/navigation-store.ts index 1e2a4b2..2ad7c16 100644 --- a/src/context/navigation-store.ts +++ b/src/context/navigation-store.ts @@ -488,11 +488,7 @@ export function createNavigation() { exitVisual, // modes setActiveTabSignal: setActiveTab, - setActiveDepth: setPane, // legacy alias - activeDepth: activePane, // legacy alias setInputFocused, - nextPane: () => {}, // legacy noop; swipe() replaces this - prevPane: () => {}, setMode, enterCommand, enterInput, diff --git a/src/hooks/useMultimediaKeys.ts b/src/hooks/useMultimediaKeys.ts index 034f7fa..3cc2ecb 100644 --- a/src/hooks/useMultimediaKeys.ts +++ b/src/hooks/useMultimediaKeys.ts @@ -21,20 +21,6 @@ export type MediaKeyAction = | "media.seekBackward" | "media.speedCycle"; -/** Key-to-action mappings for multimedia controls */ -const MEDIA_KEY_MAP: Record = { - // Common terminal media keys — these overlap with Player.tsx local - // bindings, but Player guards on `props.focused` so the global - // handler fires independently when the player tab is *not* active. - // - // When Player IS focused both handlers fire, but since the audio - // actions are idempotent (toggle = toggle, seek = additive) having - // them called twice for the same keypress is avoided by the event - // bus approach — the audio hook only processes event-bus events, and - // Player.tsx calls audio methods directly. We therefore guard with - // a "playerFocused" flag passed via options. -}; - export interface MultimediaKeysOptions { /** When true, skip handling (Player.tsx handles keys locally) */ playerFocused?: () => boolean; diff --git a/src/pages/Discover/DiscoverPage.tsx b/src/pages/Discover/DiscoverPage.tsx index dc5f5dc..a25f81f 100644 --- a/src/pages/Discover/DiscoverPage.tsx +++ b/src/pages/Discover/DiscoverPage.tsx @@ -154,7 +154,6 @@ function DiscoverPage() { : `${focusedCategory()?.name ?? "Discover"} · ${podcasts().length}`; // ── parent pane: previous-depth list (muted/blank at depth 0) ───────────── - // ── parent pane: previous-depth list (muted/blank at depth 0) ────────── // Stable gate (not a ternary root swap) so the parent list // mounts/unmounts cleanly on depth change. const parentContent = () => ( diff --git a/src/pages/MyShows/MyShowsPage.tsx b/src/pages/MyShows/MyShowsPage.tsx index 61889a6..4a19050 100644 --- a/src/pages/MyShows/MyShowsPage.tsx +++ b/src/pages/MyShows/MyShowsPage.tsx @@ -208,7 +208,6 @@ export function MyShowsPage() { : `${selectedShow() ? showTitle(selectedShow()!) : "Episodes"} · ${episodes().length}`; // ── parent pane: previous-depth list (muted/blank at depth 0) ───────────── - // ── parent pane: previous-depth list (muted/blank at depth 0) ────────── // Stable gate (not a ternary root swap) so the parent list // mounts/unmounts cleanly on depth change. const parentContent = () => ( diff --git a/src/pages/Player/RealtimeWaveform.tsx b/src/pages/Player/RealtimeWaveform.tsx index d3e8031..36f8b23 100644 --- a/src/pages/Player/RealtimeWaveform.tsx +++ b/src/pages/Player/RealtimeWaveform.tsx @@ -116,7 +116,6 @@ export function RealtimeWaveform(props: RealtimeWaveformProps) { } reader.start(position, speed); - // Start render loop frameTimer = setInterval(renderFrame, FRAME_INTERVAL); }; @@ -140,11 +139,9 @@ export function RealtimeWaveform(props: RealtimeWaveformProps) { const renderFrame = () => { if (!cava?.isReady || !reader?.running || !sampleBuffer) return; - // Read available PCM samples from the stream const count = reader.read(sampleBuffer); if (count === 0) return; - // Feed samples to cavacore → get frequency bars const input = count < sampleBuffer.length ? sampleBuffer.subarray(0, count) @@ -198,7 +195,6 @@ export function RealtimeWaveform(props: RealtimeWaveformProps) { }), ); - // Cleanup on unmount onCleanup(() => { stopVisualization(); if (reader) { @@ -222,7 +218,6 @@ export function RealtimeWaveform(props: RealtimeWaveformProps) { const bars = barData(); const count = numBars(); - // If no data yet, show empty placeholder if (bars.length === 0) { const placeholder = ".".repeat(count); return ( diff --git a/src/pages/Search/SearchPage.tsx b/src/pages/Search/SearchPage.tsx index c7dd2e1..104a6f4 100644 --- a/src/pages/Search/SearchPage.tsx +++ b/src/pages/Search/SearchPage.tsx @@ -385,8 +385,7 @@ function SearchPage() { - {result().podcast.description!.slice(0, 400) ?? - "No description available."} + {result().podcast.description!.slice(0, 400)} {(result().podcast.description?.length ?? 0) > 400 ? "…" : ""} diff --git a/src/pages/Settings/SyncPanel.tsx b/src/pages/Settings/SyncPanel.tsx index 9c0355a..08718e0 100644 --- a/src/pages/Settings/SyncPanel.tsx +++ b/src/pages/Settings/SyncPanel.tsx @@ -3,21 +3,13 @@ * Export dialogs render as depth-2 editors. No own useKeyboard. */ -import { createSignal } from "solid-js"; import { ImportDialog } from "./ImportDialog"; import { ExportDialog } from "./ExportDialog"; -import { SyncStatus } from "./SyncStatus"; import type { SettingItem } from "./types"; -// Module-level state so the action items can open their dialogs as depth-2 -// editors. The SettingsPage reads `syncEditor()` to decide which dialog to show. -const [syncEditor, setSyncEditor] = createSignal<"import" | "export" | null>( - null, -); -export { syncEditor }; -export function closeSyncEditor() { - setSyncEditor(null); -} +// closeSyncEditor kept for SettingsPage's cleanup hook; its backing state +// (the syncEditor signal) was removed as dead — nothing ever read it. +export function closeSyncEditor() {} export function useSyncItems(): SettingItem[] { return [ @@ -49,9 +41,3 @@ export function useSyncItems(): SettingItem[] { }, ]; } - -/** Renders the live sync status block (used by the Settings page header for the - * Sync section, when relevant). */ -export function SyncStatusBlock() { - return ; -} diff --git a/src/types/feed.ts b/src/types/feed.ts index d99698c..f28adce 100644 --- a/src/types/feed.ts +++ b/src/types/feed.ts @@ -97,14 +97,6 @@ export interface FeedListOptions { compact: boolean } -/** Default feed list options */ -export const DEFAULT_FEED_LIST_OPTIONS: FeedListOptions = { - showEpisodeCount: true, - showLastUpdated: true, - showSource: false, - compact: false, -} - /** Feed statistics */ export interface FeedStats { /** Total feed count */ diff --git a/src/ui/command.tsx b/src/ui/command.tsx index fe963a9..9c6c347 100644 --- a/src/ui/command.tsx +++ b/src/ui/command.tsx @@ -85,7 +85,6 @@ function init() { ); const suspended = () => suspendCount() > 0; - // Handle keybind shortcuts useKeyboard((evt) => { if (suspended()) return; if (dialog.isOpen) return; @@ -258,7 +257,6 @@ function CommandDialog(props: { return; } - // Handle text input if (evt.name && evt.name.length === 1 && !evt.ctrl && !evt.meta) { setFilter((f) => f + evt.name); return; diff --git a/src/ui/dialog.tsx b/src/ui/dialog.tsx index e86754f..ac31dac 100644 --- a/src/ui/dialog.tsx +++ b/src/ui/dialog.tsx @@ -12,7 +12,7 @@ export type DialogSize = "medium" | "large" /** * Dialog component that renders a modal overlay with content. */ -export function Dialog( +function Dialog( props: ParentProps<{ size?: DialogSize onClose: () => void diff --git a/tests/audio-dispose.test.ts b/tests/audio-dispose.test.ts index 81f5fa5..fc339ea 100644 --- a/tests/audio-dispose.test.ts +++ b/tests/audio-dispose.test.ts @@ -11,8 +11,8 @@ * * Uses a real `Bun.spawn(["sleep", "60"])` subprocess as a stand-in for the * player process, injected into the (private) `proc` slot of an MpvBackend — - * mpv is the only real backend, and it uses the kill-on-dispose - * exercising one is enough to guard the family. + * mpv is the only real backend; its kill-on-dispose path exercises the + * whole family, so one test suffices to guard it. */ import { test, expect } from "bun:test"; import { MpvBackend } from "../src/utils/audio-player"; diff --git a/tests/nav-model.test.ts b/tests/nav-model.test.ts index da4f8a4..9b74366 100644 --- a/tests/nav-model.test.ts +++ b/tests/nav-model.test.ts @@ -47,7 +47,7 @@ test("createNavigation starts on the tab root (atRootTab true)", () => { // ── depth-tab focus: reads/writes the top frame's focus ─────────────────────── test("depth-tab focusedIndex(DEPTH_CENTER_PANE) returns top frame's focus", () => { withNav((nav) => { - // FeeD is a depth-tab; its root frame is a the top frame on the stack. + // FEED is a depth-tab; its root frame is the top frame on the stack. nav.setActiveTab(TABS.FEED); expect(nav.isDepthTab()).toBe(true); expect(nav.focusedIndex(DEPTH_CENTER_PANE)).toBe(0); diff --git a/tests/yazi-pages-depth.test.ts b/tests/yazi-pages-depth.test.ts index 8ddf808..bd4b373 100644 --- a/tests/yazi-pages-depth.test.ts +++ b/tests/yazi-pages-depth.test.ts @@ -2,23 +2,23 @@ * yazi-pages-depth.test.ts — task 03 page contract tests. * * Every depth-stack tab (Feed / MyShows / Discover / Search / Player / - * Settings) renders through `` with the parent pane reading the - * previous-depth frame's list (blank placeholder at depth 0). Their `open()` - * action calls `nav.pushDepth(frame)` to drill and the Shell calls + * Settings) renders through `` with the parent pane reading the + * previous-depth frame's list (muted tab-list placeholder at depth 0). Their + * `open()` action calls `nav.pushDepth(frame)` to drill and the Shell calls * `nav.popDepth()` on `h`. This file exercises the nav-store contract those * pages depend on for every depth-tab, asserting the parent-slot data model: * - * • depth 0 → stack has exactly the root frame (parent pane is blank) - * • drill(l)→ push a child frame; stack length 2, parent = previous list - * • drill(l)→ push again; stack length 3 (Settings sections→items→editor) + * • depth 0 → stack has exactly the root frame (parent pane is the muted tab list) + * • drill(l) → push a child frame; stack length 2, parent = previous list + * • drill(l) → push again; stack length 3 (Settings sections→items→editor) * • pop(h) → stack shrinks; parent returns to the previous list - * • pop(h) → back at root; parent is blank again + * • pop(h) → back at root; parent is the muted tab list again * - * The visual "blank → list → list → blank" transition is the union of this - * data model (which list each depth renders) with ``'s null - * placeholder (covered by yazi-pane-row.test.tsx). Tested at the store level - * because the page `open()` closures are not exported and the nav store is - * the shared contract all four pages route through. + * The visual "muted → list → list → muted" transition is the union of this + * data model (which list each depth renders) with ``'s parent slot + * (covered by yazi-pane-row.test.tsx). Tested at the store level because the + * page `open()` closures are not exported and the nav store is the shared + * contract all six depth-tabs route through. */ import { test, expect } from "bun:test"; @@ -37,7 +37,7 @@ function withNav(fn: (nav: ReturnType) => void) { }); } -/** The depth-tabs that render via (task 03 conversion). */ +/** The depth-tabs that render via (task 03 conversion). */ const CONVERTED_TABS = [ TABS.FEED, TABS.MYSHOWS, @@ -55,7 +55,7 @@ for (const tab of CONVERTED_TABS) { nav.setActiveTab(tab); expect(nav.isDepthTab()).toBe(true); - // depth 0: exactly the root frame → parent pane renders blank. + // depth 0: exactly the root frame → parent pane is the muted tab list. expect(nav.currentDepth()).toBe(0); expect(nav.depthStack()).toHaveLength(1); @@ -92,7 +92,7 @@ for (const tab of CONVERTED_TABS) { expect(nav.depthStack()).toHaveLength(2); expect(nav.topFrame()).toEqual(child); - // pop (h): back to depth 0 — parent pane is blank again. + // pop (h): back to depth 0 — parent pane is the muted tab list again. expect(nav.popDepth()).toBe(true); expect(nav.currentDepth()).toBe(0); expect(nav.depthStack()).toHaveLength(1); @@ -105,7 +105,7 @@ for (const tab of CONVERTED_TABS) { expect(nav.currentDepth()).toBe(0); expect(nav.popDepth()).toBe(false); expect(nav.currentDepth()).toBe(0); - // the root frame is preserved (parent stays blank, not undefined). + // the root frame is preserved (parent stays the muted tab list, not undefined). expect(nav.depthStack()).toHaveLength(1); expect(nav.topFrame()).toBeDefined(); });