aboutsummaryrefslogtreecommitdiffstats
path: root/frontend/src
diff options
context:
space:
mode:
authorAdam Mathes <adam@adammathes.com>2026-02-14 10:12:22 -0800
committerAdam Mathes <adam@adammathes.com>2026-02-14 10:12:22 -0800
commit9d3b2a90316a1a5f735845f61abbd8a875529060 (patch)
treeb51c86306a75c4ea57a0e733eeda67a099f15d58 /frontend/src
parent90fa99359fafea4b0e10a88716675de9de4593ed (diff)
downloadneko-9d3b2a90316a1a5f735845f61abbd8a875529060.tar.gz
neko-9d3b2a90316a1a5f735845f61abbd8a875529060.tar.bz2
neko-9d3b2a90316a1a5f735845f61abbd8a875529060.zip
feat: add font theme support (fixing NK-rn4nzp)
Diffstat (limited to 'frontend/src')
-rw-r--r--frontend/src/App.tsx26
-rw-r--r--frontend/src/components/FeedItem.css4
-rw-r--r--frontend/src/components/FeedList.css7
-rw-r--r--frontend/src/components/Settings.css21
-rw-r--r--frontend/src/components/Settings.tsx29
-rw-r--r--frontend/src/index.css31
6 files changed, 102 insertions, 16 deletions
diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx
index 74ae89e..1812451 100644
--- a/frontend/src/App.tsx
+++ b/frontend/src/App.tsx
@@ -36,12 +36,19 @@ import FeedList from './components/FeedList';
import FeedItems from './components/FeedItems';
import Settings from './components/Settings';
-function Dashboard({ theme, setTheme }: { theme: string; setTheme: (t: string) => void }) {
+interface DashboardProps {
+ theme: string;
+ setTheme: (t: string) => void;
+ fontTheme: string;
+ setFontTheme: (t: string) => void;
+}
+
+function Dashboard({ theme, setTheme, fontTheme, setFontTheme }: DashboardProps) {
const [sidebarVisible, setSidebarVisible] = useState(true);
return (
<div
- className={`dashboard ${sidebarVisible ? 'sidebar-visible' : 'sidebar-hidden'} theme-${theme}`}
+ className={`dashboard ${sidebarVisible ? 'sidebar-visible' : 'sidebar-hidden'} theme-${theme} font-${fontTheme}`}
>
<div className="dashboard-content">
{!sidebarVisible && (
@@ -60,7 +67,7 @@ function Dashboard({ theme, setTheme }: { theme: string; setTheme: (t: string) =
<Routes>
<Route path="/feed/:feedId" element={<FeedItems />} />
<Route path="/tag/:tagName" element={<FeedItems />} />
- <Route path="/settings" element={<Settings />} />
+ <Route path="/settings" element={<Settings fontTheme={fontTheme} setFontTheme={setFontTheme} />} />
<Route path="/" element={<FeedItems />} />
</Routes>
</main>
@@ -71,12 +78,18 @@ function Dashboard({ theme, setTheme }: { theme: string; setTheme: (t: string) =
function App() {
const [theme, setTheme] = useState(localStorage.getItem('neko-theme') || 'light');
+ const [fontTheme, setFontTheme] = useState(localStorage.getItem('neko-font-theme') || 'default');
const handleSetTheme = (newTheme: string) => {
setTheme(newTheme);
localStorage.setItem('neko-theme', newTheme);
};
+ const handleSetFontTheme = (newFontTheme: string) => {
+ setFontTheme(newFontTheme);
+ localStorage.setItem('neko-font-theme', newFontTheme);
+ };
+
const basename = window.location.pathname.startsWith('/v2') ? '/v2' : '/';
return (
@@ -87,7 +100,12 @@ function App() {
path="/*"
element={
<RequireAuth>
- <Dashboard theme={theme} setTheme={handleSetTheme} />
+ <Dashboard
+ theme={theme}
+ setTheme={handleSetTheme}
+ fontTheme={fontTheme}
+ setFontTheme={handleSetFontTheme}
+ />
</RequireAuth>
}
/>
diff --git a/frontend/src/components/FeedItem.css b/frontend/src/components/FeedItem.css
index 3becb20..4eca2b1 100644
--- a/frontend/src/components/FeedItem.css
+++ b/frontend/src/components/FeedItem.css
@@ -15,7 +15,7 @@
}
.item-title {
- font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
+ font-family: var(--font-heading);
font-size: 1.8rem;
font-weight: bold;
text-decoration: none;
@@ -114,7 +114,7 @@
border: 1px solid var(--border-color, #ccc);
color: blue;
cursor: pointer;
- font-family: 'Helvetica Neue';
+ font-family: var(--font-heading);
font-weight: bold;
font-size: 0.8rem;
padding: 2px 6px;
diff --git a/frontend/src/components/FeedList.css b/frontend/src/components/FeedList.css
index 7bb0f4c..7c39901 100644
--- a/frontend/src/components/FeedList.css
+++ b/frontend/src/components/FeedList.css
@@ -1,6 +1,6 @@
.feed-list {
padding: 1rem;
- font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
+ font-family: var(--font-heading);
color: #777;
/* specific v1 color */
font-size: 0.8rem;
@@ -18,9 +18,6 @@
z-index: 10;
padding-bottom: 0.5rem;
color: var(--text-color);
- /* Usually dark/white depending on theme, v1 was white on blue? No, white on fixed header? No, v1 logo class says color: white. But sidebar is #ccc. */
- /* In v1 logo was fixed top left (blue header bar?). In v2 sidebar is #ccc.
- Let's use theme text color but maybe bolder? */
}
/* Override logo color if necessary for themes */
@@ -55,7 +52,7 @@
margin: 1rem 0 0.25rem 0;
cursor: pointer;
user-select: none;
- font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
+ font-family: var(--font-heading);
color: #333;
/* Darker than list items */
text-transform: lowercase;
diff --git a/frontend/src/components/Settings.css b/frontend/src/components/Settings.css
index ec6fc83..c8784a0 100644
--- a/frontend/src/components/Settings.css
+++ b/frontend/src/components/Settings.css
@@ -4,7 +4,8 @@
margin: 0 auto;
}
-.add-feed-section {
+.add-feed-section,
+.appearance-section {
background: var(--sidebar-bg);
padding: 1.5rem;
border-radius: 8px;
@@ -12,6 +13,22 @@
border: 1px solid var(--border-color);
}
+.font-selector {
+ display: flex;
+ align-items: center;
+ gap: 1rem;
+}
+
+.font-select {
+ padding: 0.5rem;
+ border: 1px solid var(--border-color);
+ background: var(--bg-color);
+ color: var(--text-color);
+ border-radius: 4px;
+ font-size: 1rem;
+ min-width: 200px;
+}
+
.add-feed-form {
display: flex;
gap: 1rem;
@@ -57,7 +74,7 @@
}
.feed-title {
- font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
+ font-family: var(--font-heading);
font-weight: bold;
font-size: 1.1rem;
}
diff --git a/frontend/src/components/Settings.tsx b/frontend/src/components/Settings.tsx
index 16cf6a3..80e3068 100644
--- a/frontend/src/components/Settings.tsx
+++ b/frontend/src/components/Settings.tsx
@@ -3,14 +3,21 @@ import type { Feed } from '../types';
import './Settings.css';
import { apiFetch } from '../utils';
-export default function Settings() {
+interface SettingsProps {
+ fontTheme?: string;
+ setFontTheme?: (t: string) => void;
+}
+
+export default function Settings({ fontTheme, setFontTheme }: SettingsProps) {
const [feeds, setFeeds] = useState<Feed[]>([]);
+ /* ... existing state ... */
const [newFeedUrl, setNewFeedUrl] = useState('');
const [loading, setLoading] = useState(false);
const [error, setError] = useState<string | null>(null);
const [importFile, setImportFile] = useState<File | null>(null);
+ /* ... existing fetchFeeds ... */
const fetchFeeds = () => {
setLoading(true);
apiFetch('/api/feed/')
@@ -32,6 +39,7 @@ export default function Settings() {
fetchFeeds();
}, []);
+ /* ... existing handlers ... */
const handleAddFeed = (e: React.FormEvent) => {
e.preventDefault();
if (!newFeedUrl) return;
@@ -106,6 +114,25 @@ export default function Settings() {
<div className="settings-page">
<h2>Settings</h2>
+ {setFontTheme && (
+ <div className="appearance-section">
+ <h3>Appearance</h3>
+ <div className="font-selector">
+ <label>Font Theme:</label>
+ <select
+ value={fontTheme || 'default'}
+ onChange={(e) => setFontTheme(e.target.value)}
+ className="font-select"
+ >
+ <option value="default">Default</option>
+ <option value="serif">Serif</option>
+ <option value="sans">Sans-Serif</option>
+ <option value="mono">Monospace</option>
+ </select>
+ </div>
+ </div>
+ )}
+
<div className="add-feed-section">
<h3>Add New Feed</h3>
<form onSubmit={handleAddFeed} className="add-feed-form">
diff --git a/frontend/src/index.css b/frontend/src/index.css
index 3365d34..6396633 100644
--- a/frontend/src/index.css
+++ b/frontend/src/index.css
@@ -1,5 +1,11 @@
+:root {
+ /* Font Variables */
+ --font-body: Palatino, 'Palatino Linotype', 'Palatino LT STD', 'Book Antiqua', Georgia, serif;
+ --font-heading: 'Helvetica Neue', Helvetica, Arial, sans-serif;
+}
+
body {
- font-family: Palatino, 'Palatino Linotype', 'Palatino LT STD', 'Book Antiqua', Georgia, serif;
+ font-family: var(--font-body);
}
h1,
@@ -10,10 +16,31 @@ h5,
.logo,
.nav-link,
.logout-btn {
- font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
+ font-family: var(--font-heading);
font-weight: bold;
}
+/* Font Themes */
+.font-default {
+ --font-body: Palatino, 'Palatino Linotype', 'Palatino LT STD', 'Book Antiqua', Georgia, serif;
+ --font-heading: 'Helvetica Neue', Helvetica, Arial, sans-serif;
+}
+
+.font-serif {
+ --font-body: Georgia, 'Times New Roman', Times, serif;
+ --font-heading: Georgia, 'Times New Roman', Times, serif;
+}
+
+.font-sans {
+ --font-body: Inter, system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
+ --font-heading: Inter, system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
+}
+
+.font-mono {
+ --font-body: Menlo, Monaco, Consolas, 'Courier New', monospace;
+ --font-heading: Menlo, Monaco, Consolas, 'Courier New', monospace;
+}
+
:root {
line-height: 1.5;
font-size: 18px;