finished hygenie
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -21,20 +21,6 @@ export type MediaKeyAction =
|
||||
| "media.seekBackward"
|
||||
| "media.speedCycle";
|
||||
|
||||
/** Key-to-action mappings for multimedia controls */
|
||||
const MEDIA_KEY_MAP: Record<string, MediaKeyAction> = {
|
||||
// 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;
|
||||
|
||||
@@ -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 <Show> gate (not a ternary root swap) so the parent list
|
||||
// mounts/unmounts cleanly on depth change.
|
||||
const parentContent = () => (
|
||||
|
||||
@@ -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 <Show> gate (not a ternary root swap) so the parent list
|
||||
// mounts/unmounts cleanly on depth change.
|
||||
const parentContent = () => (
|
||||
|
||||
@@ -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 (
|
||||
|
||||
@@ -385,8 +385,7 @@ function SearchPage() {
|
||||
</Show>
|
||||
<Show when={result().podcast.description}>
|
||||
<text fg={theme.textSecondary}>
|
||||
{result().podcast.description!.slice(0, 400) ??
|
||||
"No description available."}
|
||||
{result().podcast.description!.slice(0, 400)}
|
||||
{(result().podcast.description?.length ?? 0) > 400 ? "…" : ""}
|
||||
</text>
|
||||
</Show>
|
||||
|
||||
@@ -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 <SyncStatus />;
|
||||
}
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user