diff --git a/README.md b/README.md index f4e6a98..03d5ee8 100644 --- a/README.md +++ b/README.md @@ -29,14 +29,9 @@ Web News follows a "zero-knowledge" philosophy: - [ ] Reading time - [ ] UI/UX Cleanup -- [ ] Add feed fetching timeout and button to remove if failed 3 times - [ ] Use Go Mobile, remove Java RSS plugin. -- [ ] Dont show loading screen if not initial load (eg. reloading tab) -- [ ] Fix feeds double image (Feed image and article image at top) - [ ] Export article(s) -- [ ] Export/Import OPML on add feed modal -- [ ] Favicons for feeds and caching -- [ ] +- [ ] Favicon fetcher and caching ## Getting Started diff --git a/desktop/app.go b/desktop/app.go index 3c4c146..c3aa8a3 100644 --- a/desktop/app.go +++ b/desktop/app.go @@ -151,12 +151,12 @@ func (a *App) SaveArticles(articles string) error { return a.db.SaveArticles(articles) } -func (a *App) GetArticles(feedId string, offset, limit int) (string, error) { - a.logDebug("GetArticles feedId=%s offset=%d limit=%d", feedId, offset, limit) +func (a *App) GetArticles(feedId string, offset, limit int, categoryId string) (string, error) { + a.logDebug("GetArticles feedId=%s categoryId=%s offset=%d limit=%d", feedId, categoryId, offset, limit) if a.db == nil { return "[]", nil } - return a.db.GetArticles(feedId, offset, limit) + return a.db.GetArticles(feedId, offset, limit, categoryId) } func (a *App) SearchArticles(query string, limit int) (string, error) { diff --git a/eslint.config.js b/eslint.config.js index 76b102a..65f6f25 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -52,6 +52,7 @@ export default [ FileReader: 'readonly', performance: 'readonly', AbortController: 'readonly', + AbortSignal: 'readonly', DOMParser: 'readonly', Element: 'readonly', Node: 'readonly', diff --git a/internal/storage/sqlite.go b/internal/storage/sqlite.go index e1b190e..098609a 100644 --- a/internal/storage/sqlite.go +++ b/internal/storage/sqlite.go @@ -322,11 +322,18 @@ func (s *SQLiteDB) SaveArticles(articlesJSON string) error { return tx.Commit() } -func (s *SQLiteDB) GetArticles(feedId string, offset, limit int) (string, error) { +func (s *SQLiteDB) GetArticles(feedId string, offset, limit int, categoryId string) (string, error) { var rows *sql.Rows var err error if feedId != "" { rows, err = s.db.Query("SELECT id, feedId, title, link, description, content, author, pubDate, read, saved, imageUrl, readAt FROM articles WHERE feedId = ? ORDER BY pubDate DESC LIMIT ? OFFSET ?", feedId, limit, offset) + } else if categoryId != "" { + rows, err = s.db.Query(` + SELECT a.id, a.feedId, a.title, a.link, a.description, a.content, a.author, a.pubDate, a.read, a.saved, a.imageUrl, a.readAt + FROM articles a + JOIN feeds f ON a.feedId = f.id + WHERE f.categoryId = ? + ORDER BY a.pubDate DESC LIMIT ? OFFSET ?`, categoryId, limit, offset) } else { rows, err = s.db.Query("SELECT id, feedId, title, link, description, content, author, pubDate, read, saved, imageUrl, readAt FROM articles ORDER BY pubDate DESC LIMIT ? OFFSET ?", limit, offset) } @@ -488,7 +495,7 @@ func (s *SQLiteDB) ClearAll() error { func (s *SQLiteDB) GetReadingHistory(days int) (string, error) { cutoff := time.Now().AddDate(0, 0, -days).UnixMilli() rows, err := s.db.Query(` - SELECT strftime('%Y-%m-%d', datetime(readAt/1000, 'unixepoch')) as date, COUNT(*) as count + SELECT strftime('%Y-%m-%d', datetime(readAt/1000, 'unixepoch', 'localtime')) as date, COUNT(*) as count FROM articles WHERE read = 1 AND readAt > ? GROUP BY date @@ -505,8 +512,11 @@ func (s *SQLiteDB) GetReadingHistory(days int) (string, error) { if err := rows.Scan(&date, &count); err != nil { continue } - // Convert date string back to timestamp for frontend - t, _ := time.Parse("2006-01-02", date) + // Convert local date string back to local midnight timestamp for frontend + t, err := time.ParseInLocation("2006-01-02", date, time.Local) + if err != nil { + continue + } history = append(history, map[string]any{ "date": t.UnixMilli(), "count": count, diff --git a/src/components/Sidebar.svelte b/src/components/Sidebar.svelte index a33d692..a2fa6db 100644 --- a/src/components/Sidebar.svelte +++ b/src/components/Sidebar.svelte @@ -353,8 +353,16 @@ {:else} + + +

{ if (e.key === 'Enter' && newFilter) { - newsStore.settings.muteFilters = [ - ...newsStore.settings.muteFilters, - newFilter, - ]; + muteFilters = [...muteFilters, newFilter]; newFilter = ''; } }} @@ -743,10 +781,7 @@ class="btn-primary px-4 py-2 rounded-xl whitespace-nowrap" onclick={() => { if (newFilter) { - newsStore.settings.muteFilters = [ - ...newsStore.settings.muteFilters, - newFilter, - ]; + muteFilters = [...muteFilters, newFilter]; newFilter = ''; } }} @@ -757,7 +792,7 @@
- {#each newsStore.settings.muteFilters as filter} + {#each muteFilters as filter} @@ -765,8 +800,7 @@ @@ -835,12 +869,14 @@ {#each Array(30) .fill(0) .map((_, i) => { - const date = new Date(); - date.setDate(date.getDate() - (29 - i)); - const dStr = date.toISOString().split('T')[0]; - const entry = readingHistory.find((h) => new Date(h.date) - .toISOString() - .split('T')[0] === dStr); + const d = new Date(); + d.setDate(d.getDate() - (29 - i)); + const dStr = `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}`; + const entry = readingHistory.find((h) => { + const hd = new Date(h.date); + const hStr = `${hd.getFullYear()}-${String(hd.getMonth() + 1).padStart(2, '0')}-${String(hd.getDate()).padStart(2, '0')}`; + return hStr === dStr; + }); return { date: dStr, count: entry?.count || 0 }; }) as day}
{feed?.id}
+ {:else if newsStore.selectedCategoryId} + {@const cat = newsStore.categories.find( + (c) => c.id === newsStore.selectedCategoryId + )} + {cat?.name} {:else if newsStore.currentView === 'saved'} Saved stories {:else if newsStore.currentView === 'following'}