From 9c1c131603677371eab0e6b6956481a661f14628 Mon Sep 17 00:00:00 2001 From: Adam Mathes Date: Fri, 13 Feb 2026 17:29:12 -0800 Subject: feat(v2/ui): add theme toggle and collapse sidebar by default (NK-gnxc6e, NK-k4y597) --- frontend/src/App.tsx | 17 ++++++++++++----- frontend/src/components/FeedList.css | 35 ++++++++++++++++++++++++++++++++++- frontend/src/components/FeedList.tsx | 11 ++++++++++- frontend/src/index.css | 24 ++++++++++++++++++++++++ 4 files changed, 80 insertions(+), 7 deletions(-) (limited to 'frontend/src') diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 7c6b11f..409878c 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -35,12 +35,12 @@ import FeedList from './components/FeedList'; import FeedItems from './components/FeedItems'; import Settings from './components/Settings'; -function Dashboard() { +function Dashboard({ theme, setTheme }: { theme: string, setTheme: (t: string) => void }) { const navigate = useNavigate(); - const [sidebarVisible, setSidebarVisible] = useState(true); + const [sidebarVisible, setSidebarVisible] = useState(false); return ( -
+

setSidebarVisible(!sidebarVisible)} style={{ cursor: 'pointer' }}>🐱

@@ -72,6 +72,13 @@ function Dashboard() { } function App() { + const [theme, setTheme] = useState(localStorage.getItem('neko-theme') || 'light'); + + const handleSetTheme = (newTheme: string) => { + setTheme(newTheme); + localStorage.setItem('neko-theme', newTheme); + }; + return ( @@ -80,7 +87,7 @@ function App() { path="/*" element={ - + } /> diff --git a/frontend/src/components/FeedList.css b/frontend/src/components/FeedList.css index d91a8ac..d0ee9eb 100644 --- a/frontend/src/components/FeedList.css +++ b/frontend/src/components/FeedList.css @@ -119,6 +119,39 @@ .feed-title.active, .tag-link.active, -.filter-list li a.active { +.filter-list li a.active, +.theme-selector button.active { font-weight: bold !important; +} + +.theme-section { + margin-top: 2rem; + padding-bottom: 2rem; +} + +.theme-selector { + display: flex; + justify-content: space-between; + gap: 5px; +} + +.theme-selector button { + font-size: 0.8rem; + padding: 0.2rem 0.5rem; + width: 30%; + background: whitesmoke; + color: blue; + border: 1px solid #ccc; + border-radius: 4px; + font-variant: small-caps; + text-transform: lowercase; +} + +.theme-selector button:hover { + background: #eee; +} + +.theme-selector button.active { + color: black; + border-color: #000; } \ No newline at end of file diff --git a/frontend/src/components/FeedList.tsx b/frontend/src/components/FeedList.tsx index 8159cac..4af1bbc 100644 --- a/frontend/src/components/FeedList.tsx +++ b/frontend/src/components/FeedList.tsx @@ -3,7 +3,7 @@ import { Link, useNavigate, useSearchParams, useLocation, useParams } from 'reac import type { Feed, Category } from '../types'; import './FeedList.css'; -export default function FeedList() { +export default function FeedList({ theme, setTheme }: { theme: string, setTheme: (t: string) => void }) { const [feeds, setFeeds] = useState([]); const [tags, setTags] = useState([]); const [loading, setLoading] = useState(true); @@ -100,6 +100,15 @@ export default function FeedList() {
)} + +
+

Themes

+
+ + + +
+
); } diff --git a/frontend/src/index.css b/frontend/src/index.css index 43cdff5..821a259 100644 --- a/frontend/src/index.css +++ b/frontend/src/index.css @@ -47,6 +47,30 @@ h5, } } +.theme-dark { + --bg-color: #24292e; + --text-color: #ffffff; + --sidebar-bg: #1b1f23; + --link-color: rgb(90, 200, 250); + background-color: var(--bg-color); + color: var(--text-color); +} + +.theme-black { + --bg-color: #000000; + --text-color: #ffffff; + --sidebar-bg: #111111; + --link-color: rgb(90, 200, 250); + background-color: var(--bg-color); + color: var(--text-color); +} + +.theme-dark button, +.theme-black button { + background-color: #333; + color: #fff; +} + body { margin: 0; min-width: 320px; -- cgit v1.2.3