This commit is contained in:
2026-02-10 15:30:53 -05:00
parent f707594d0c
commit 3d5bc84550
18 changed files with 89 additions and 60 deletions

View File

@@ -1,4 +1,5 @@
import type { TabId } from "./Tab" import type { TabId } from "./Tab"
import { useTheme } from "@/context/ThemeContext"
type NavigationProps = { type NavigationProps = {
activeTab: TabId activeTab: TabId
@@ -6,9 +7,10 @@ type NavigationProps = {
} }
export function Navigation(props: NavigationProps) { export function Navigation(props: NavigationProps) {
const { theme } = useTheme();
return ( return (
<box style={{ flexDirection: "row", width: "100%", height: 1 }}> <box style={{ flexDirection: "row", width: "100%", height: 1 }}>
<text> <text fg={theme.text}>
{props.activeTab === "feed" ? "[" : " "}Feed{props.activeTab === "feed" ? "]" : " "} {props.activeTab === "feed" ? "[" : " "}Feed{props.activeTab === "feed" ? "]" : " "}
<span> </span> <span> </span>
{props.activeTab === "shows" ? "[" : " "}My Shows{props.activeTab === "shows" ? "]" : " "} {props.activeTab === "shows" ? "[" : " "}My Shows{props.activeTab === "shows" ? "]" : " "}

View File

@@ -1,24 +1,26 @@
import { shortcuts } from "@/config/shortcuts"; import { shortcuts } from "@/config/shortcuts";
import { useTheme } from "@/context/ThemeContext";
export function ShortcutHelp() { export function ShortcutHelp() {
const { theme } = useTheme();
return ( return (
<box border title="Shortcuts" style={{ padding: 1 }}> <box border title="Shortcuts" style={{ padding: 1 }}>
<box style={{ flexDirection: "column" }}> <box style={{ flexDirection: "column" }}>
<box style={{ flexDirection: "row" }}> <box style={{ flexDirection: "row" }}>
<text>{shortcuts[0]?.keys ?? ""} </text> <text fg={theme.text}>{shortcuts[0]?.keys ?? ""} </text>
<text>{shortcuts[0]?.action ?? ""}</text> <text fg={theme.text}>{shortcuts[0]?.action ?? ""}</text>
</box> </box>
<box style={{ flexDirection: "row" }}> <box style={{ flexDirection: "row" }}>
<text>{shortcuts[1]?.keys ?? ""} </text> <text fg={theme.text}>{shortcuts[1]?.keys ?? ""} </text>
<text>{shortcuts[1]?.action ?? ""}</text> <text fg={theme.text}>{shortcuts[1]?.action ?? ""}</text>
</box> </box>
<box style={{ flexDirection: "row" }}> <box style={{ flexDirection: "row" }}>
<text>{shortcuts[2]?.keys ?? ""} </text> <text fg={theme.text}>{shortcuts[2]?.keys ?? ""} </text>
<text>{shortcuts[2]?.action ?? ""}</text> <text fg={theme.text}>{shortcuts[2]?.action ?? ""}</text>
</box> </box>
<box style={{ flexDirection: "row" }}> <box style={{ flexDirection: "row" }}>
<text>{shortcuts[3]?.keys ?? ""} </text> <text fg={theme.text}>{shortcuts[3]?.keys ?? ""} </text>
<text>{shortcuts[3]?.action ?? ""}</text> <text fg={theme.text}>{shortcuts[3]?.action ?? ""}</text>
</box> </box>
</box> </box>
</box> </box>

View File

@@ -129,10 +129,10 @@ export function FeedDetail(props: FeedDetailProps) {
{/* Episodes header */} {/* Episodes header */}
<box flexDirection="row" justifyContent="space-between"> <box flexDirection="row" justifyContent="space-between">
<text> <text fg={theme.text}>
<strong>Episodes</strong> <strong>Episodes</strong>
</text> </text>
<text fg="gray">({episodes().length} total)</text> <text fg={theme.textMuted}>({episodes().length} total)</text>
</box> </box>
{/* Episode list */} {/* Episode list */}

View File

@@ -29,7 +29,7 @@ export function PlayerPage(props: PageProps) {
return ( return (
<box flexDirection="column" gap={1} width="100%"> <box flexDirection="column" gap={1} width="100%">
<box flexDirection="row" justifyContent="space-between"> <box flexDirection="row" justifyContent="space-between">
<text> <text fg={theme.text}>
<strong>Now Playing</strong> <strong>Now Playing</strong>
</text> </text>
<text fg={theme.muted}> <text fg={theme.muted}>
@@ -40,7 +40,7 @@ export function PlayerPage(props: PageProps) {
{audio.error() && <text fg={theme.error}>{audio.error()}</text>} {audio.error() && <text fg={theme.error}>{audio.error()}</text>}
<box border padding={1} flexDirection="column" gap={1}> <box border borderColor={theme.border} padding={1} flexDirection="column" gap={1}>
<text fg={theme.text}> <text fg={theme.text}>
<strong>{audio.currentEpisode()?.title}</strong> <strong>{audio.currentEpisode()?.title}</strong>
</text> </text>

View File

@@ -15,6 +15,7 @@ import {
} from "@/utils/cavacore"; } from "@/utils/cavacore";
import { AudioStreamReader } from "@/utils/audio-stream-reader"; import { AudioStreamReader } from "@/utils/audio-stream-reader";
import { useAudio } from "@/hooks/useAudio"; import { useAudio } from "@/hooks/useAudio";
import { useTheme } from "@/context/ThemeContext";
// ── Types ──────────────────────────────────────────────────────────── // ── Types ────────────────────────────────────────────────────────────
@@ -44,6 +45,7 @@ const SAMPLES_PER_FRAME = 512;
// ── Component ──────────────────────────────────────────────────────── // ── Component ────────────────────────────────────────────────────────
export function RealtimeWaveform(props: RealtimeWaveformProps) { export function RealtimeWaveform(props: RealtimeWaveformProps) {
const { theme } = useTheme();
const audio = useAudio(); const audio = useAudio();
// Frequency bar values (0.01.0 per bar) // Frequency bar values (0.01.0 per bar)
@@ -247,8 +249,8 @@ export function RealtimeWaveform(props: RealtimeWaveformProps) {
}; };
return ( return (
<box border padding={1} onMouseDown={handleClick}> <box border borderColor={theme.border} padding={1} onMouseDown={handleClick}>
{renderLine()} {renderLine()}
</box> </box>
); );
} }

View File

@@ -62,7 +62,7 @@ export function SearchPage(props: PageProps) {
<box flexDirection="column" height="100%" gap={1} width="100%"> <box flexDirection="column" height="100%" gap={1} width="100%">
{/* Search Header */} {/* Search Header */}
<box flexDirection="column" gap={1}> <box flexDirection="column" gap={1}>
<text> <text fg={theme.text}>
<strong>Search Podcasts</strong> <strong>Search Podcasts</strong>
</text> </text>
@@ -101,7 +101,7 @@ export function SearchPage(props: PageProps) {
{/* Main Content - Results or History */} {/* Main Content - Results or History */}
<box flexDirection="row" height="100%" gap={2}> <box flexDirection="row" height="100%" gap={2}>
{/* Results Panel */} {/* Results Panel */}
<box flexDirection="column" flexGrow={1} border> <box flexDirection="column" flexGrow={1} border borderColor={theme.border}>
<box padding={1}> <box padding={1}>
<text <text
fg={props.depth() === SearchPaneType.RESULTS ? theme.primary : theme.muted} fg={props.depth() === SearchPaneType.RESULTS ? theme.primary : theme.muted}
@@ -134,7 +134,7 @@ export function SearchPage(props: PageProps) {
</box> </box>
{/* History Sidebar */} {/* History Sidebar */}
<box width={30} border> <box width={30} border borderColor={theme.border}>
<box padding={1} flexDirection="column"> <box padding={1} flexDirection="column">
<box paddingBottom={1}> <box paddingBottom={1}>
<text <text

View File

@@ -6,19 +6,21 @@ const createSignal = <T,>(value: T): [() => T, (next: T) => void] => {
} }
import { SyncStatus } from "./SyncStatus" import { SyncStatus } from "./SyncStatus"
import { useTheme } from "@/context/ThemeContext"
export function ExportDialog() { export function ExportDialog() {
const { theme } = useTheme();
const filename = createSignal("podcast-sync.json") const filename = createSignal("podcast-sync.json")
const format = createSignal<"json" | "xml">("json") const format = createSignal<"json" | "xml">("json")
return ( return (
<box border title="Export" style={{ padding: 1, flexDirection: "column", gap: 1 }}> <box border title="Export" style={{ padding: 1, flexDirection: "column", gap: 1 }}>
<box style={{ flexDirection: "row", gap: 1 }}> <box style={{ flexDirection: "row", gap: 1 }}>
<text>File:</text> <text fg={theme.text}>File:</text>
<input value={filename[0]()} onInput={filename[1]} style={{ width: 30 }} /> <input value={filename[0]()} onInput={filename[1]} style={{ width: 30 }} />
</box> </box>
<box style={{ flexDirection: "row", gap: 1 }}> <box style={{ flexDirection: "row", gap: 1 }}>
<text>Format:</text> <text fg={theme.text}>Format:</text>
<tab_select <tab_select
options={[ options={[
{ name: "JSON", description: "Portable" }, { name: "JSON", description: "Portable" },
@@ -27,8 +29,8 @@ export function ExportDialog() {
onSelect={(index) => format[1](index === 0 ? "json" : "xml")} onSelect={(index) => format[1](index === 0 ? "json" : "xml")}
/> />
</box> </box>
<box border> <box border borderColor={theme.border}>
<text>Export {format[0]()} to {filename[0]()}</text> <text fg={theme.text}>Export {format[0]()} to {filename[0]()}</text>
</box> </box>
<SyncStatus /> <SyncStatus />
</box> </box>

View File

@@ -1,4 +1,5 @@
import { detectFormat } from "@/utils/file-detector"; import { detectFormat } from "@/utils/file-detector";
import { useTheme } from "@/context/ThemeContext";
type FilePickerProps = { type FilePickerProps = {
value: string; value: string;
@@ -6,6 +7,7 @@ type FilePickerProps = {
}; };
export function FilePicker(props: FilePickerProps) { export function FilePicker(props: FilePickerProps) {
const { theme } = useTheme();
const format = detectFormat(props.value); const format = detectFormat(props.value);
return ( return (
@@ -16,7 +18,7 @@ export function FilePicker(props: FilePickerProps) {
placeholder="/path/to/sync-file.json" placeholder="/path/to/sync-file.json"
style={{ width: 40 }} style={{ width: 40 }}
/> />
<text>Format: {format}</text> <text fg={theme.text}>Format: {format}</text>
</box> </box>
); );
} }

View File

@@ -6,15 +6,17 @@ const createSignal = <T,>(value: T): [() => T, (next: T) => void] => {
} }
import { FilePicker } from "./FilePicker" import { FilePicker } from "./FilePicker"
import { useTheme } from "@/context/ThemeContext"
export function ImportDialog() { export function ImportDialog() {
const { theme } = useTheme();
const filePath = createSignal("") const filePath = createSignal("")
return ( return (
<box border title="Import" style={{ padding: 1, flexDirection: "column", gap: 1 }}> <box border title="Import" style={{ padding: 1, flexDirection: "column", gap: 1 }}>
<FilePicker value={filePath[0]()} onChange={filePath[1]} /> <FilePicker value={filePath[0]()} onChange={filePath[1]} />
<box border> <box border borderColor={theme.border}>
<text>Import selected file</text> <text fg={theme.text}>Import selected file</text>
</box> </box>
</box> </box>
) )

View File

@@ -83,8 +83,8 @@ export function LoginScreen(props: LoginScreenProps) {
}; };
return ( return (
<box flexDirection="column" border padding={2} gap={1}> <box flexDirection="column" border borderColor={theme.border} padding={2} gap={1}>
<text> <text fg={theme.text}>
<strong>Sign In</strong> <strong>Sign In</strong>
</text> </text>
@@ -92,7 +92,7 @@ export function LoginScreen(props: LoginScreenProps) {
{/* Email field */} {/* Email field */}
<box flexDirection="column" gap={0}> <box flexDirection="column" gap={0}>
<text fg={focusField() === "email" ? theme.primary : undefined}> <text fg={focusField() === "email" ? theme.primary : theme.textMuted}>
Email: Email:
</text> </text>
<input <input
@@ -107,7 +107,7 @@ export function LoginScreen(props: LoginScreenProps) {
{/* Password field */} {/* Password field */}
<box flexDirection="column" gap={0}> <box flexDirection="column" gap={0}>
<text fg={focusField() === "password" ? theme.primary : undefined}> <text fg={focusField() === "password" ? theme.primary : theme.textMuted}>
Password: Password:
</text> </text>
<input <input
@@ -126,6 +126,7 @@ export function LoginScreen(props: LoginScreenProps) {
<box flexDirection="row" gap={2}> <box flexDirection="row" gap={2}>
<box <box
border border
borderColor={theme.border}
padding={1} padding={1}
backgroundColor={ backgroundColor={
focusField() === "submit" ? theme.primary : undefined focusField() === "submit" ? theme.primary : undefined
@@ -148,6 +149,7 @@ export function LoginScreen(props: LoginScreenProps) {
<box flexDirection="row" gap={2}> <box flexDirection="row" gap={2}>
<box <box
border border
borderColor={theme.border}
padding={1} padding={1}
backgroundColor={focusField() === "code" ? theme.primary : undefined} backgroundColor={focusField() === "code" ? theme.primary : undefined}
> >
@@ -158,6 +160,7 @@ export function LoginScreen(props: LoginScreenProps) {
<box <box
border border
borderColor={theme.border}
padding={1} padding={1}
backgroundColor={focusField() === "oauth" ? theme.primary : undefined} backgroundColor={focusField() === "oauth" ? theme.primary : undefined}
> >

View File

@@ -94,7 +94,7 @@ export function PreferencesPanel() {
<text fg={focusField() === "theme" ? theme.primary : theme.textMuted}> <text fg={focusField() === "theme" ? theme.primary : theme.textMuted}>
Theme: Theme:
</text> </text>
<box border padding={0}> <box border borderColor={theme.border} padding={0}>
<text fg={theme.text}> <text fg={theme.text}>
{THEME_LABELS.find((t) => t.value === settings().theme)?.label} {THEME_LABELS.find((t) => t.value === settings().theme)?.label}
</text> </text>
@@ -106,7 +106,7 @@ export function PreferencesPanel() {
<text fg={focusField() === "font" ? theme.primary : theme.textMuted}> <text fg={focusField() === "font" ? theme.primary : theme.textMuted}>
Font Size: Font Size:
</text> </text>
<box border padding={0}> <box border borderColor={theme.border} padding={0}>
<text fg={theme.text}>{settings().fontSize}px</text> <text fg={theme.text}>{settings().fontSize}px</text>
</box> </box>
<text fg={theme.textMuted}>[Left/Right]</text> <text fg={theme.textMuted}>[Left/Right]</text>
@@ -116,7 +116,7 @@ export function PreferencesPanel() {
<text fg={focusField() === "speed" ? theme.primary : theme.textMuted}> <text fg={focusField() === "speed" ? theme.primary : theme.textMuted}>
Playback: Playback:
</text> </text>
<box border padding={0}> <box border borderColor={theme.border} padding={0}>
<text fg={theme.text}>{settings().playbackSpeed}x</text> <text fg={theme.text}>{settings().playbackSpeed}x</text>
</box> </box>
<text fg={theme.textMuted}>[Left/Right]</text> <text fg={theme.textMuted}>[Left/Right]</text>
@@ -128,7 +128,7 @@ export function PreferencesPanel() {
> >
Show Explicit: Show Explicit:
</text> </text>
<box border padding={0}> <box border borderColor={theme.border} padding={0}>
<text <text
fg={preferences().showExplicit ? theme.success : theme.textMuted} fg={preferences().showExplicit ? theme.success : theme.textMuted}
> >
@@ -142,7 +142,7 @@ export function PreferencesPanel() {
<text fg={focusField() === "auto" ? theme.primary : theme.textMuted}> <text fg={focusField() === "auto" ? theme.primary : theme.textMuted}>
Auto Download: Auto Download:
</text> </text>
<box border padding={0}> <box border borderColor={theme.border} padding={0}>
<text <text
fg={preferences().autoDownload ? theme.success : theme.textMuted} fg={preferences().autoDownload ? theme.success : theme.textMuted}
> >

View File

@@ -37,6 +37,7 @@ export function SettingsPage(props: PageProps) {
{(section, index) => ( {(section, index) => (
<box <box
border border
borderColor={theme.border}
padding={0} padding={0}
backgroundColor={ backgroundColor={
activeSection() === section.id ? theme.primary : undefined activeSection() === section.id ? theme.primary : undefined
@@ -55,7 +56,7 @@ export function SettingsPage(props: PageProps) {
</For> </For>
</box> </box>
<box border flexGrow={1} padding={1} flexDirection="column" gap={1}> <box border borderColor={theme.border} flexGrow={1} padding={1} flexDirection="column" gap={1}>
{activeSection() === SettingsPaneType.SYNC && <SyncPanel />} {activeSection() === SettingsPaneType.SYNC && <SyncPanel />}
{activeSection() === SettingsPaneType.SOURCES && ( {activeSection() === SettingsPaneType.SOURCES && (
<SourceManager focused /> <SourceManager focused />

View File

@@ -166,12 +166,12 @@ export function SourceManager(props: SourceManagerProps) {
const sourceLanguage = () => selectedSource()?.language || "en_us"; const sourceLanguage = () => selectedSource()?.language || "en_us";
return ( return (
<box flexDirection="column" border padding={1} gap={1}> <box flexDirection="column" border borderColor={theme.border} padding={1} gap={1}>
<box flexDirection="row" justifyContent="space-between"> <box flexDirection="row" justifyContent="space-between">
<text> <text fg={theme.text}>
<strong>Podcast Sources</strong> <strong>Podcast Sources</strong>
</text> </text>
<box border padding={0} onMouseDown={props.onClose}> <box border borderColor={theme.border} padding={0} onMouseDown={props.onClose}>
<text fg={theme.primary}>[Esc] Close</text> <text fg={theme.primary}>[Esc] Close</text>
</box> </box>
</box> </box>
@@ -179,7 +179,7 @@ export function SourceManager(props: SourceManagerProps) {
<text fg={theme.textMuted}>Manage where to search for podcasts</text> <text fg={theme.textMuted}>Manage where to search for podcasts</text>
{/* Source list */} {/* Source list */}
<box border padding={1} flexDirection="column" gap={1}> <box border borderColor={theme.border} padding={1} flexDirection="column" gap={1}>
<text fg={focusArea() === "list" ? theme.primary : theme.textMuted}> <text fg={focusArea() === "list" ? theme.primary : theme.textMuted}>
Sources: Sources:
</text> </text>
@@ -243,6 +243,7 @@ export function SourceManager(props: SourceManagerProps) {
<box flexDirection="row" gap={2}> <box flexDirection="row" gap={2}>
<box <box
border border
borderColor={theme.border}
padding={0} padding={0}
backgroundColor={ backgroundColor={
focusArea() === "country" ? theme.primary : undefined focusArea() === "country" ? theme.primary : undefined
@@ -256,6 +257,7 @@ export function SourceManager(props: SourceManagerProps) {
</box> </box>
<box <box
border border
borderColor={theme.border}
padding={0} padding={0}
backgroundColor={ backgroundColor={
focusArea() === "language" ? theme.primary : undefined focusArea() === "language" ? theme.primary : undefined
@@ -272,6 +274,7 @@ export function SourceManager(props: SourceManagerProps) {
</box> </box>
<box <box
border border
borderColor={theme.border}
padding={0} padding={0}
backgroundColor={ backgroundColor={
focusArea() === "explicit" ? theme.primary : undefined focusArea() === "explicit" ? theme.primary : undefined
@@ -293,7 +296,7 @@ export function SourceManager(props: SourceManagerProps) {
</box> </box>
{/* Add new source form */} {/* Add new source form */}
<box border padding={1} flexDirection="column" gap={1}> <box border borderColor={theme.border} padding={1} flexDirection="column" gap={1}>
<text <text
fg={ fg={
focusArea() === "add" || focusArea() === "url" focusArea() === "add" || focusArea() === "url"
@@ -329,7 +332,7 @@ export function SourceManager(props: SourceManagerProps) {
/> />
</box> </box>
<box border padding={0} width={15} onMouseDown={handleAddSource}> <box border borderColor={theme.border} padding={0} width={15} onMouseDown={handleAddSource}>
<text fg={theme.success}>[+] Add Source</text> <text fg={theme.success}>[+] Add Source</text>
</box> </box>
</box> </box>

View File

@@ -1,14 +1,17 @@
import { useTheme } from "@/context/ThemeContext"
type SyncErrorProps = { type SyncErrorProps = {
message: string message: string
onRetry: () => void onRetry: () => void
} }
export function SyncError(props: SyncErrorProps) { export function SyncError(props: SyncErrorProps) {
const { theme } = useTheme();
return ( return (
<box border title="Error" style={{ padding: 1, flexDirection: "column", gap: 1 }}> <box border title="Error" style={{ padding: 1, flexDirection: "column", gap: 1 }}>
<text>{props.message}</text> <text fg={theme.text}>{props.message}</text>
<box border onMouseDown={props.onRetry}> <box border borderColor={theme.border} onMouseDown={props.onRetry}>
<text>Retry</text> <text fg={theme.text}>Retry</text>
</box> </box>
</box> </box>
) )

View File

@@ -8,18 +8,20 @@ const createSignal = <T,>(value: T): [() => T, (next: T) => void] => {
import { ImportDialog } from "./ImportDialog" import { ImportDialog } from "./ImportDialog"
import { ExportDialog } from "./ExportDialog" import { ExportDialog } from "./ExportDialog"
import { SyncStatus } from "./SyncStatus" import { SyncStatus } from "./SyncStatus"
import { useTheme } from "@/context/ThemeContext"
export function SyncPanel() { export function SyncPanel() {
const { theme } = useTheme();
const mode = createSignal<"import" | "export" | null>(null) const mode = createSignal<"import" | "export" | null>(null)
return ( return (
<box style={{ flexDirection: "column", gap: 1 }}> <box style={{ flexDirection: "column", gap: 1 }}>
<box style={{ flexDirection: "row", gap: 1 }}> <box style={{ flexDirection: "row", gap: 1 }}>
<box border onMouseDown={() => mode[1]("import")}> <box border borderColor={theme.border} onMouseDown={() => mode[1]("import")}>
<text>Import</text> <text fg={theme.text}>Import</text>
</box> </box>
<box border onMouseDown={() => mode[1]("export")}> <box border borderColor={theme.border} onMouseDown={() => mode[1]("export")}>
<text>Export</text> <text fg={theme.text}>Export</text>
</box> </box>
</box> </box>
<SyncStatus /> <SyncStatus />

View File

@@ -1,8 +1,11 @@
import { useTheme } from "@/context/ThemeContext"
type SyncProgressProps = { type SyncProgressProps = {
value: number value: number
} }
export function SyncProgress(props: SyncProgressProps) { export function SyncProgress(props: SyncProgressProps) {
const { theme } = useTheme();
const width = 30 const width = 30
let filled = (props.value / 100) * width let filled = (props.value / 100) * width
filled = filled >= 0 ? filled : 0 filled = filled >= 0 ? filled : 0
@@ -18,8 +21,8 @@ export function SyncProgress(props: SyncProgressProps) {
return ( return (
<box style={{ flexDirection: "column" }}> <box style={{ flexDirection: "column" }}>
<text>{bar}</text> <text fg={theme.text}>{bar}</text>
<text>{props.value}%</text> <text fg={theme.text}>{props.value}%</text>
</box> </box>
) )
} }

View File

@@ -7,10 +7,12 @@ const createSignal = <T,>(value: T): [() => T, (next: T) => void] => {
import { SyncProgress } from "./SyncProgress" import { SyncProgress } from "./SyncProgress"
import { SyncError } from "./SyncError" import { SyncError } from "./SyncError"
import { useTheme } from "@/context/ThemeContext"
type SyncState = "idle" | "syncing" | "complete" | "error" type SyncState = "idle" | "syncing" | "complete" | "error"
export function SyncStatus() { export function SyncStatus() {
const { theme } = useTheme();
const state = createSignal<SyncState>("idle") const state = createSignal<SyncState>("idle")
const message = createSignal("Idle") const message = createSignal("Idle")
const progress = createSignal(0) const progress = createSignal(0)
@@ -35,15 +37,15 @@ export function SyncStatus() {
} }
return ( return (
<box border title="Sync Status" style={{ padding: 1, flexDirection: "column", gap: 1 }}> <box border title="Sync Status" borderColor={theme.border} style={{ padding: 1, flexDirection: "column", gap: 1 }}>
<box style={{ flexDirection: "row", gap: 1 }}> <box style={{ flexDirection: "row", gap: 1 }}>
<text>Status:</text> <text fg={theme.text}>Status:</text>
<text>{message[0]()}</text> <text fg={theme.text}>{message[0]()}</text>
</box> </box>
<SyncProgress value={progress[0]()} /> <SyncProgress value={progress[0]()} />
{state[0]() === "error" ? <SyncError message={message[0]()} onRetry={() => toggle()} /> : null} {state[0]() === "error" ? <SyncError message={message[0]()} onRetry={() => toggle()} /> : null}
<box border onMouseDown={toggle}> <box border borderColor={theme.border} onMouseDown={toggle}>
<text>Cycle Status</text> <text fg={theme.text}>Cycle Status</text>
</box> </box>
</box> </box>
) )

View File

@@ -99,7 +99,7 @@ export function VisualizerSettings() {
<text fg={focusField() === "bars" ? theme.primary : theme.textMuted}> <text fg={focusField() === "bars" ? theme.primary : theme.textMuted}>
Bars: Bars:
</text> </text>
<box border padding={0}> <box border borderColor={theme.border} padding={0}>
<text fg={theme.text}>{viz().bars}</text> <text fg={theme.text}>{viz().bars}</text>
</box> </box>
<text fg={theme.textMuted}>[Left/Right +/-8]</text> <text fg={theme.textMuted}>[Left/Right +/-8]</text>
@@ -113,7 +113,7 @@ export function VisualizerSettings() {
> >
Auto Sensitivity: Auto Sensitivity:
</text> </text>
<box border padding={0}> <box border borderColor={theme.border} padding={0}>
<text <text
fg={viz().sensitivity === 1 ? theme.success : theme.textMuted} fg={viz().sensitivity === 1 ? theme.success : theme.textMuted}
> >
@@ -127,7 +127,7 @@ export function VisualizerSettings() {
<text fg={focusField() === "noise" ? theme.primary : theme.textMuted}> <text fg={focusField() === "noise" ? theme.primary : theme.textMuted}>
Noise Reduction: Noise Reduction:
</text> </text>
<box border padding={0}> <box border borderColor={theme.border} padding={0}>
<text fg={theme.text}>{viz().noiseReduction.toFixed(2)}</text> <text fg={theme.text}>{viz().noiseReduction.toFixed(2)}</text>
</box> </box>
<text fg={theme.textMuted}>[Left/Right +/-0.05]</text> <text fg={theme.textMuted}>[Left/Right +/-0.05]</text>
@@ -139,7 +139,7 @@ export function VisualizerSettings() {
> >
Low Cutoff: Low Cutoff:
</text> </text>
<box border padding={0}> <box border borderColor={theme.border} padding={0}>
<text fg={theme.text}>{viz().lowCutOff} Hz</text> <text fg={theme.text}>{viz().lowCutOff} Hz</text>
</box> </box>
<text fg={theme.textMuted}>[Left/Right +/-10]</text> <text fg={theme.textMuted}>[Left/Right +/-10]</text>
@@ -151,7 +151,7 @@ export function VisualizerSettings() {
> >
High Cutoff: High Cutoff:
</text> </text>
<box border padding={0}> <box border borderColor={theme.border} padding={0}>
<text fg={theme.text}>{viz().highCutOff} Hz</text> <text fg={theme.text}>{viz().highCutOff} Hz</text>
</box> </box>
<text fg={theme.textMuted}>[Left/Right +/-500]</text> <text fg={theme.textMuted}>[Left/Right +/-500]</text>