From 92c797d7d90b0cec9c5cb7edbafe52fcb0870d80 Mon Sep 17 00:00:00 2001 From: Greg Shuflin Date: Tue, 4 Feb 2025 02:33:26 -0800 Subject: [PATCH] Uncategorized feeds --- src/demo.rs | 21 ++++++++++++++------- static/css/style.css | 13 +++++++++++++ static/js/app.js | 38 +++++++++++++++++++++++++++++++++++++- 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/demo.rs b/src/demo.rs index 795f4a3..c8a3b9d 100644 --- a/src/demo.rs +++ b/src/demo.rs @@ -4,30 +4,35 @@ use crate::user::User; struct DemoFeed { name: &'static str, url: &'static str, - category: &'static str, + category: Option<&'static str>, } -const DEMO_FEEDS: [DemoFeed; 4] = [ +const DEMO_FEEDS: [DemoFeed; 5] = [ DemoFeed { name: "XKCD", url: "https://xkcd.com/atom.xml", - category: "Webcomic", + category: Some("Webcomic"), }, DemoFeed { name: "Isidore & Friends", url: "https://isidore.webcomic.ws/rss/", - category: "Webcomic", + category: Some("Webcomic"), }, DemoFeed { name: "Astral Codex Ten", url: "https://www.astralcodexten.com/feed", - category: "Substack", + category: Some("Substack"), }, DemoFeed { name: "BBC News", url: "https://feeds.bbci.co.uk/news/world/us_and_canada/rss.xml", - category: "News", + category: Some("News"), }, + DemoFeed { + name: "Astronomy Picture of the Day (APOD)", + url: "https://apod.nasa.gov/apod.rss", + category: None, + } ]; pub async fn setup_demo_data(pool: &sqlx::SqlitePool) { @@ -61,7 +66,9 @@ pub async fn setup_demo_data(pool: &sqlx::SqlitePool) { demo_feed.url.parse().unwrap(), demo.id, ); - feed.categorization = vec![demo_feed.category.to_string()]; + if let Some(category) = demo_feed.category { + feed.categorization = vec![category.to_string()]; + } feed.write_to_database(pool) .await diff --git a/static/css/style.css b/static/css/style.css index 54b7a21..b15d3a4 100644 --- a/static/css/style.css +++ b/static/css/style.css @@ -617,4 +617,17 @@ button:disabled { .user-menu-item#logoutButton:hover { background-color: rgba(244, 63, 63, 0.1); +} + +.feed-category { + margin-bottom: 1rem; +} + +.feed-category-header { + color: var(--primary-red); + font-size: 0.9rem; + text-transform: uppercase; + letter-spacing: 0.05em; + margin: 0; + border-bottom: 1px solid var(--border-color); } diff --git a/static/js/app.js b/static/js/app.js index 6e3f98e..36f9aa8 100644 --- a/static/js/app.js +++ b/static/js/app.js @@ -150,6 +150,7 @@ async function handleFeeds() { const feedList = document.getElementById('feedList'); if (feeds) { + console.log('Loaded feeds:', feeds); feedList.innerHTML = ''; if (feeds.length === 0) { @@ -158,8 +159,43 @@ async function handleFeeds() { emptyMessage.textContent = 'No feeds added yet'; feedList.appendChild(emptyMessage); } else { + // Group feeds by category + const feedsByCategory = {}; + const uncategorizedFeeds = []; + feeds.forEach(feed => { - feedList.appendChild(openFeed(feed)); + const category = feed.categorization.length > 0 ? feed.categorization[0] : null; + if (category) { + if (!feedsByCategory[category]) { + feedsByCategory[category] = []; + } + feedsByCategory[category].push(feed); + } else { + uncategorizedFeeds.push(feed); + } + }); + + // Sort categories alphabetically, but keep "Uncategorized" at the end + const sortedCategories = Object.keys(feedsByCategory).sort((a, b) => a.localeCompare(b)); + sortedCategories.push(""); + feedsByCategory[""] = uncategorizedFeeds; + + // Create category sections + sortedCategories.forEach(category => { + const categorySection = document.createElement('div'); + categorySection.className = 'feed-category'; + + const categoryHeader = document.createElement('h3'); + categoryHeader.className = 'feed-category-header'; + categoryHeader.textContent = category; + categorySection.appendChild(categoryHeader); + + // Add feeds for this category + feedsByCategory[category].forEach(feed => { + categorySection.appendChild(openFeed(feed)); + }); + + feedList.appendChild(categorySection); }); } } else {