better themeing
This commit is contained in:
@@ -13,6 +13,7 @@ import { format } from "date-fns";
|
|||||||
import type { Episode } from "@/types/episode";
|
import type { Episode } from "@/types/episode";
|
||||||
import type { Feed } from "@/types/feed";
|
import type { Feed } from "@/types/feed";
|
||||||
import { PageProps } from "@/App";
|
import { PageProps } from "@/App";
|
||||||
|
import { useTheme } from "@/context/ThemeContext";
|
||||||
|
|
||||||
enum MyShowsPaneType {
|
enum MyShowsPaneType {
|
||||||
SHOWS = 1,
|
SHOWS = 1,
|
||||||
@@ -27,6 +28,8 @@ export function MyShowsPage(props: PageProps) {
|
|||||||
const [showIndex, setShowIndex] = createSignal(0);
|
const [showIndex, setShowIndex] = createSignal(0);
|
||||||
const [episodeIndex, setEpisodeIndex] = createSignal(0);
|
const [episodeIndex, setEpisodeIndex] = createSignal(0);
|
||||||
const [isRefreshing, setIsRefreshing] = createSignal(false);
|
const [isRefreshing, setIsRefreshing] = createSignal(false);
|
||||||
|
const { theme } = useTheme();
|
||||||
|
const mutedColor = () => theme.muted || theme.text;
|
||||||
|
|
||||||
/** Threshold: load more when within this many items of the end */
|
/** Threshold: load more when within this many items of the end */
|
||||||
const LOAD_MORE_THRESHOLD = 5;
|
const LOAD_MORE_THRESHOLD = 5;
|
||||||
@@ -94,23 +97,6 @@ export function MyShowsPage(props: PageProps) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Get download status color */
|
|
||||||
const downloadColor = (episodeId: string): string => {
|
|
||||||
const status = downloadStore.getDownloadStatus(episodeId);
|
|
||||||
switch (status) {
|
|
||||||
case DownloadStatus.QUEUED:
|
|
||||||
return "yellow";
|
|
||||||
case DownloadStatus.DOWNLOADING:
|
|
||||||
return "cyan";
|
|
||||||
case DownloadStatus.COMPLETED:
|
|
||||||
return "green";
|
|
||||||
case DownloadStatus.FAILED:
|
|
||||||
return "red";
|
|
||||||
default:
|
|
||||||
return "gray";
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleRefresh = async () => {
|
const handleRefresh = async () => {
|
||||||
const show = selectedShow();
|
const show = selectedShow();
|
||||||
if (!show) return;
|
if (!show) return;
|
||||||
@@ -127,17 +113,34 @@ export function MyShowsPage(props: PageProps) {
|
|||||||
setEpisodeIndex(0);
|
setEpisodeIndex(0);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** Get download status color */
|
||||||
|
const downloadColor = (episodeId: string): string => {
|
||||||
|
const status = downloadStore.getDownloadStatus(episodeId);
|
||||||
|
switch (status) {
|
||||||
|
case DownloadStatus.QUEUED:
|
||||||
|
return theme.warning.toString();
|
||||||
|
case DownloadStatus.DOWNLOADING:
|
||||||
|
return theme.primary.toString();
|
||||||
|
case DownloadStatus.COMPLETED:
|
||||||
|
return theme.success.toString();
|
||||||
|
case DownloadStatus.FAILED:
|
||||||
|
return theme.error.toString();
|
||||||
|
default:
|
||||||
|
return mutedColor().toString();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<box flexDirection="row" flexGrow={1} width="100%">
|
<box flexDirection="row" flexGrow={1} width="100%">
|
||||||
<box flexDirection="column" height="100%">
|
<box flexDirection="column" height="100%">
|
||||||
<Show when={isRefreshing()}>
|
<Show when={isRefreshing()}>
|
||||||
<text fg="yellow">Refreshing...</text>
|
<text fg={theme.warning}>Refreshing...</text>
|
||||||
</Show>
|
</Show>
|
||||||
<Show
|
<Show
|
||||||
when={shows().length > 0}
|
when={shows().length > 0}
|
||||||
fallback={
|
fallback={
|
||||||
<box padding={1}>
|
<box padding={1}>
|
||||||
<text fg="gray">
|
<text fg={theme.muted}>
|
||||||
No shows yet. Subscribe from Discover or Search.
|
No shows yet. Subscribe from Discover or Search.
|
||||||
</text>
|
</text>
|
||||||
</box>
|
</box>
|
||||||
@@ -154,19 +157,19 @@ export function MyShowsPage(props: PageProps) {
|
|||||||
gap={1}
|
gap={1}
|
||||||
paddingLeft={1}
|
paddingLeft={1}
|
||||||
paddingRight={1}
|
paddingRight={1}
|
||||||
backgroundColor={index() === showIndex() ? "#333" : undefined}
|
backgroundColor={index() === showIndex() ? theme.primary : undefined}
|
||||||
onMouseDown={() => {
|
onMouseDown={() => {
|
||||||
setShowIndex(index());
|
setShowIndex(index());
|
||||||
setEpisodeIndex(0);
|
setEpisodeIndex(0);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<text fg={index() === showIndex() ? "cyan" : "gray"}>
|
<text fg={index() === showIndex() ? theme.primary : theme.muted}>
|
||||||
{index() === showIndex() ? ">" : " "}
|
{index() === showIndex() ? ">" : " "}
|
||||||
</text>
|
</text>
|
||||||
<text fg={index() === showIndex() ? "white" : undefined}>
|
<text fg={index() === showIndex() ? theme.text : undefined}>
|
||||||
{feed.customName || feed.podcast.title}
|
{feed.customName || feed.podcast.title}
|
||||||
</text>
|
</text>
|
||||||
<text fg="gray">({feed.episodes.length})</text>
|
<text fg={theme.muted}>({feed.episodes.length})</text>
|
||||||
</box>
|
</box>
|
||||||
)}
|
)}
|
||||||
</For>
|
</For>
|
||||||
@@ -178,7 +181,7 @@ export function MyShowsPage(props: PageProps) {
|
|||||||
when={selectedShow()}
|
when={selectedShow()}
|
||||||
fallback={
|
fallback={
|
||||||
<box padding={1}>
|
<box padding={1}>
|
||||||
<text fg="gray">Select a show</text>
|
<text fg={theme.muted}>Select a show</text>
|
||||||
</box>
|
</box>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
@@ -186,7 +189,7 @@ export function MyShowsPage(props: PageProps) {
|
|||||||
when={episodes().length > 0}
|
when={episodes().length > 0}
|
||||||
fallback={
|
fallback={
|
||||||
<box padding={1}>
|
<box padding={1}>
|
||||||
<text fg="gray">No episodes. Press [r] to refresh.</text>
|
<text fg={theme.muted}>No episodes. Press [r] to refresh.</text>
|
||||||
</box>
|
</box>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
@@ -202,16 +205,16 @@ export function MyShowsPage(props: PageProps) {
|
|||||||
paddingLeft={1}
|
paddingLeft={1}
|
||||||
paddingRight={1}
|
paddingRight={1}
|
||||||
backgroundColor={
|
backgroundColor={
|
||||||
index() === episodeIndex() ? "#333" : undefined
|
index() === episodeIndex() ? theme.primary : undefined
|
||||||
}
|
}
|
||||||
onMouseDown={() => setEpisodeIndex(index())}
|
onMouseDown={() => setEpisodeIndex(index())}
|
||||||
>
|
>
|
||||||
<box flexDirection="row" gap={1}>
|
<box flexDirection="row" gap={1}>
|
||||||
<text fg={index() === episodeIndex() ? "cyan" : "gray"}>
|
<text fg={index() === episodeIndex() ? theme.primary : theme.muted}>
|
||||||
{index() === episodeIndex() ? ">" : " "}
|
{index() === episodeIndex() ? ">" : " "}
|
||||||
</text>
|
</text>
|
||||||
<text
|
<text
|
||||||
fg={index() === episodeIndex() ? "white" : undefined}
|
fg={index() === episodeIndex() ? theme.text : undefined}
|
||||||
>
|
>
|
||||||
{episode.episodeNumber
|
{episode.episodeNumber
|
||||||
? `#${episode.episodeNumber} `
|
? `#${episode.episodeNumber} `
|
||||||
@@ -220,8 +223,8 @@ export function MyShowsPage(props: PageProps) {
|
|||||||
</text>
|
</text>
|
||||||
</box>
|
</box>
|
||||||
<box flexDirection="row" gap={2} paddingLeft={2}>
|
<box flexDirection="row" gap={2} paddingLeft={2}>
|
||||||
<text fg="gray">{formatDate(episode.pubDate)}</text>
|
<text fg={theme.muted}>{formatDate(episode.pubDate)}</text>
|
||||||
<text fg="gray">{formatDuration(episode.duration)}</text>
|
<text fg={theme.muted}>{formatDuration(episode.duration)}</text>
|
||||||
<Show when={downloadLabel(episode.id)}>
|
<Show when={downloadLabel(episode.id)}>
|
||||||
<text fg={downloadColor(episode.id)}>
|
<text fg={downloadColor(episode.id)}>
|
||||||
{downloadLabel(episode.id)}
|
{downloadLabel(episode.id)}
|
||||||
@@ -233,7 +236,7 @@ export function MyShowsPage(props: PageProps) {
|
|||||||
</For>
|
</For>
|
||||||
<Show when={feedStore.isLoadingMore()}>
|
<Show when={feedStore.isLoadingMore()}>
|
||||||
<box paddingLeft={2} paddingTop={1}>
|
<box paddingLeft={2} paddingTop={1}>
|
||||||
<text fg="yellow">Loading more episodes...</text>
|
<text fg={theme.warning}>Loading more episodes...</text>
|
||||||
</box>
|
</box>
|
||||||
</Show>
|
</Show>
|
||||||
<Show
|
<Show
|
||||||
@@ -244,7 +247,7 @@ export function MyShowsPage(props: PageProps) {
|
|||||||
}
|
}
|
||||||
>
|
>
|
||||||
<box paddingLeft={2} paddingTop={1}>
|
<box paddingLeft={2} paddingTop={1}>
|
||||||
<text fg="gray">Scroll down for more episodes</text>
|
<text fg={theme.muted}>Scroll down for more episodes</text>
|
||||||
</box>
|
</box>
|
||||||
</Show>
|
</Show>
|
||||||
</scrollbox>
|
</scrollbox>
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { PlaybackControls } from "./PlaybackControls";
|
|||||||
import { RealtimeWaveform } from "./RealtimeWaveform";
|
import { RealtimeWaveform } from "./RealtimeWaveform";
|
||||||
import { useAudio } from "@/hooks/useAudio";
|
import { useAudio } from "@/hooks/useAudio";
|
||||||
import { useAppStore } from "@/stores/app";
|
import { useAppStore } from "@/stores/app";
|
||||||
|
import { useTheme } from "@/context/ThemeContext";
|
||||||
|
|
||||||
enum PlayerPaneType {
|
enum PlayerPaneType {
|
||||||
PLAYER = 1,
|
PLAYER = 1,
|
||||||
@@ -11,6 +12,7 @@ export const PlayerPaneCount = 1;
|
|||||||
|
|
||||||
export function PlayerPage(props: PageProps) {
|
export function PlayerPage(props: PageProps) {
|
||||||
const audio = useAudio();
|
const audio = useAudio();
|
||||||
|
const { theme } = useTheme();
|
||||||
|
|
||||||
const progressPercent = () => {
|
const progressPercent = () => {
|
||||||
const d = audio.duration();
|
const d = audio.duration();
|
||||||
@@ -30,19 +32,19 @@ export function PlayerPage(props: PageProps) {
|
|||||||
<text>
|
<text>
|
||||||
<strong>Now Playing</strong>
|
<strong>Now Playing</strong>
|
||||||
</text>
|
</text>
|
||||||
<text fg="gray">
|
<text fg={theme.muted}>
|
||||||
{formatTime(audio.position())} / {formatTime(audio.duration())} (
|
{formatTime(audio.position())} / {formatTime(audio.duration())} (
|
||||||
{progressPercent()}%)
|
{progressPercent()}%)
|
||||||
</text>
|
</text>
|
||||||
</box>
|
</box>
|
||||||
|
|
||||||
{audio.error() && <text fg="red">{audio.error()}</text>}
|
{audio.error() && <text fg={theme.error}>{audio.error()}</text>}
|
||||||
|
|
||||||
<box border padding={1} flexDirection="column" gap={1}>
|
<box border padding={1} flexDirection="column" gap={1}>
|
||||||
<text fg="white">
|
<text fg={theme.text}>
|
||||||
<strong>{audio.currentEpisode()?.title}</strong>
|
<strong>{audio.currentEpisode()?.title}</strong>
|
||||||
</text>
|
</text>
|
||||||
<text fg="gray">{audio.currentEpisode()?.description}</text>
|
<text fg={theme.muted}>{audio.currentEpisode()?.description}</text>
|
||||||
|
|
||||||
<RealtimeWaveform
|
<RealtimeWaveform
|
||||||
visualizerConfig={(() => {
|
visualizerConfig={(() => {
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import { SearchHistory } from "./SearchHistory";
|
|||||||
import type { SearchResult } from "@/types/source";
|
import type { SearchResult } from "@/types/source";
|
||||||
import { PageProps } from "@/App";
|
import { PageProps } from "@/App";
|
||||||
import { MyShowsPage } from "../MyShows/MyShowsPage";
|
import { MyShowsPage } from "../MyShows/MyShowsPage";
|
||||||
|
import { useTheme } from "@/context/ThemeContext";
|
||||||
|
|
||||||
enum SearchPaneType {
|
enum SearchPaneType {
|
||||||
INPUT = 1,
|
INPUT = 1,
|
||||||
@@ -23,6 +24,7 @@ export function SearchPage(props: PageProps) {
|
|||||||
const [inputValue, setInputValue] = createSignal("");
|
const [inputValue, setInputValue] = createSignal("");
|
||||||
const [resultIndex, setResultIndex] = createSignal(0);
|
const [resultIndex, setResultIndex] = createSignal(0);
|
||||||
const [historyIndex, setHistoryIndex] = createSignal(0);
|
const [historyIndex, setHistoryIndex] = createSignal(0);
|
||||||
|
const { theme } = useTheme();
|
||||||
|
|
||||||
// Keep parent informed about input focus state
|
// Keep parent informed about input focus state
|
||||||
// TODO: have a global input focused prop in useKeyboard hook
|
// TODO: have a global input focused prop in useKeyboard hook
|
||||||
@@ -83,16 +85,16 @@ export function SearchPage(props: PageProps) {
|
|||||||
paddingRight={1}
|
paddingRight={1}
|
||||||
onMouseDown={handleSearch}
|
onMouseDown={handleSearch}
|
||||||
>
|
>
|
||||||
<text fg="cyan">[Enter] Search</text>
|
<text fg={theme.primary}>[Enter] Search</text>
|
||||||
</box>
|
</box>
|
||||||
</box>
|
</box>
|
||||||
|
|
||||||
{/* Status */}
|
{/* Status */}
|
||||||
<Show when={searchStore.isSearching()}>
|
<Show when={searchStore.isSearching()}>
|
||||||
<text fg="yellow">Searching...</text>
|
<text fg={theme.warning}>Searching...</text>
|
||||||
</Show>
|
</Show>
|
||||||
<Show when={searchStore.error()}>
|
<Show when={searchStore.error()}>
|
||||||
<text fg="red">{searchStore.error()}</text>
|
<text fg={theme.error}>{searchStore.error()}</text>
|
||||||
</Show>
|
</Show>
|
||||||
</box>
|
</box>
|
||||||
|
|
||||||
@@ -102,7 +104,7 @@ export function SearchPage(props: PageProps) {
|
|||||||
<box flexDirection="column" flexGrow={1} border>
|
<box flexDirection="column" flexGrow={1} border>
|
||||||
<box padding={1}>
|
<box padding={1}>
|
||||||
<text
|
<text
|
||||||
fg={props.depth() === SearchPaneType.RESULTS ? "cyan" : "gray"}
|
fg={props.depth() === SearchPaneType.RESULTS ? theme.primary : theme.muted}
|
||||||
>
|
>
|
||||||
Results ({searchStore.results().length})
|
Results ({searchStore.results().length})
|
||||||
</text>
|
</text>
|
||||||
@@ -111,7 +113,7 @@ export function SearchPage(props: PageProps) {
|
|||||||
when={searchStore.results().length > 0}
|
when={searchStore.results().length > 0}
|
||||||
fallback={
|
fallback={
|
||||||
<box padding={2}>
|
<box padding={2}>
|
||||||
<text fg="gray">
|
<text fg={theme.muted}>
|
||||||
{searchStore.query()
|
{searchStore.query()
|
||||||
? "No results found"
|
? "No results found"
|
||||||
: "Enter a search term to find podcasts"}
|
: "Enter a search term to find podcasts"}
|
||||||
@@ -136,7 +138,7 @@ export function SearchPage(props: PageProps) {
|
|||||||
<box padding={1} flexDirection="column">
|
<box padding={1} flexDirection="column">
|
||||||
<box paddingBottom={1}>
|
<box paddingBottom={1}>
|
||||||
<text
|
<text
|
||||||
fg={props.depth() === SearchPaneType.HISTORY ? "cyan" : "gray"}
|
fg={props.depth() === SearchPaneType.HISTORY ? theme.primary : theme.muted}
|
||||||
>
|
>
|
||||||
History
|
History
|
||||||
</text>
|
</text>
|
||||||
|
|||||||
Reference in New Issue
Block a user