From cedf099910472eed41fbdbb1cd5f9e097bcfaa11 Mon Sep 17 00:00:00 2001 From: Michael Freno Date: Thu, 19 Feb 2026 20:40:01 -0500 Subject: [PATCH] working indicator (simpler) --- src/App.tsx | 73 ++++++++-------- src/components/LoadingIndicator.tsx | 40 ++++----- src/pages/Feed/FeedPage.tsx | 124 ++++++++++++---------------- src/pages/MyShows/MyShowsPage.tsx | 3 +- 4 files changed, 104 insertions(+), 136 deletions(-) diff --git a/src/App.tsx b/src/App.tsx index 629a5f2..a5a24d9 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -113,47 +113,48 @@ export function App() { )} > - - {DEBUG && ( - - - - - - - - - - - - - - - - - - - - - - - - - - - )} - - - {LayerGraph[nav.activeTab]()} + + {DEBUG && ( + + + + + + + + + + + + + + + + + + + + + + + + + + + )} + + + {LayerGraph[nav.activeTab]()} + ); diff --git a/src/components/LoadingIndicator.tsx b/src/components/LoadingIndicator.tsx index 85a0a8d..ad4a4a4 100644 --- a/src/components/LoadingIndicator.tsx +++ b/src/components/LoadingIndicator.tsx @@ -1,36 +1,24 @@ -/** - * Loading indicator component - * Displays an animated sliding bar at the top of the screen - */ - -import { For } from "solid-js"; +import { createSignal, createMemo, onCleanup } from "solid-js"; import { useTheme } from "@/context/ThemeContext"; -interface LoadingIndicatorProps { - isLoading: boolean; -} +const spinnerChars = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"]; -export function LoadingIndicator(props: LoadingIndicatorProps) { +//TODO: Watch for actual loading state (fetching feeds) +export function LoadingIndicator() { const { theme } = useTheme(); + const [index, setIndex] = createSignal(0); - if (!props.isLoading) return null; + const interval = setInterval(() => { + setIndex((i) => (i + 1) % spinnerChars.length); + }, 65); + + onCleanup(() => clearInterval(interval)); + + const currentChar = createMemo(() => spinnerChars[index()]); return ( - - - {(_, index) => ( - - )} - + + ); } diff --git a/src/pages/Feed/FeedPage.tsx b/src/pages/Feed/FeedPage.tsx index f27203d..4f1520d 100644 --- a/src/pages/Feed/FeedPage.tsx +++ b/src/pages/Feed/FeedPage.tsx @@ -1,18 +1,17 @@ /** * FeedPage - Shows latest episodes across all subscribed shows - * Reverse chronological order, like an inbox/timeline + * Reverse chronological order, grouped by date */ import { createSignal, For, Show } from "solid-js"; import { useFeedStore } from "@/stores/feed"; -import { useKeyboard } from "@opentui/solid"; import { format } from "date-fns"; import type { Episode } from "@/types/episode"; import type { Feed } from "@/types/feed"; import { useTheme } from "@/context/ThemeContext"; import { SelectableBox, SelectableText } from "@/components/Selectable"; -import { se } from "date-fns/locale"; import { useNavigation } from "@/context/NavigationContext"; +import { LoadingIndicator } from "@/components/LoadingIndicator"; enum FeedPaneType { FEED = 1, @@ -31,22 +30,25 @@ export function FeedPage() { const allEpisodes = () => feedStore.getAllEpisodesChronological(); - const formatDate = (date: Date): string => { - return format(date, "MMM d, yyyy"); - }; - const paginatedEpisodes = () => { const episodes = allEpisodes(); return episodes.slice(0, loadedEpisodesCount()); }; - const episodesByDate = () => { - const groups: Record = {}; - const sortedEpisodes = paginatedEpisodes(); + const formatDate = (date: Date): string => { + return format(date, "MMM d, yyyy"); + }; - for (const episode of sortedEpisodes) { - const dateKey = formatDate(new Date(episode.episode.pubDate)); - groups[dateKey] = episode; + const groupEpisodesByDate = () => { + const groups: Record> = {}; + const episodes = paginatedEpisodes(); + + for (const item of episodes) { + const dateKey = formatDate(new Date(item.episode.pubDate)); + if (!groups[dateKey]) { + groups[dateKey] = []; + } + groups[dateKey].push(item); } return groups; @@ -59,12 +61,6 @@ export function FeedPage() { return `${mins}m`; }; - const handleRefresh = async () => { - setIsRefreshing(true); - await feedStore.refreshAllFeeds(); - setIsRefreshing(false); - }; - const { theme } = useTheme(); return ( - - b.localeCompare(a), + b.localeCompare(a))}> + {([date, episodes]) => ( + + false} primary> + {date} + + + {(item) => ( + false} + flexDirection="column" + gap={0} + paddingLeft={1} + paddingRight={1} + paddingTop={0} + paddingBottom={0} + onMouseDown={() => { + // Selection is handled by App's keyboard navigation + }} + > + false} primary> + {item.episode.title} + + + false} primary> + {item.feed.podcast.title} + + false} tertiary> + {formatDuration(item.episode.duration)} + + + + )} + + )} - > - {([date, episode], groupIndex) => { - const selected = () => groupIndex() === 1; // TODO: Manage selections locally - return ( - <> - - false} primary> - {date} - - - { - // Selection is handled by App's keyboard navigation - }} - > - - {selected() ? ">" : " "} - - - {episode.episode.title} - - - - {episode.feed.podcast.title} - - - {formatDate(episode.episode.pubDate)} - - - {formatDuration(episode.episode.duration)} - - - - - ); - }} {/* Loading indicator */} - Loading more episodes... + diff --git a/src/pages/MyShows/MyShowsPage.tsx b/src/pages/MyShows/MyShowsPage.tsx index 5bed1d3..032055b 100644 --- a/src/pages/MyShows/MyShowsPage.tsx +++ b/src/pages/MyShows/MyShowsPage.tsx @@ -12,6 +12,7 @@ import { format } from "date-fns"; import { useTheme } from "@/context/ThemeContext"; import { useAudioNavStore, AudioSource } from "@/stores/audio-nav"; import { useNavigation } from "@/context/NavigationContext"; +import { LoadingIndicator } from "@/components/LoadingIndicator"; enum MyShowsPaneType { SHOWS = 1, @@ -245,7 +246,7 @@ export function MyShowsPage() { - Loading more episodes... +