feat: Move "Small websites" filter to settings dialog
Co-authored-by: aider (gemini/gemini-2.5-pro) <aider@aider.chat>
This commit is contained in:
@@ -25,6 +25,7 @@ function App() {
|
|||||||
const [bodyFontSize, setBodyFontSize] = useState(Number(localStorage.getItem('bodyFontSize')) || defaultBodyFontSize);
|
const [bodyFontSize, setBodyFontSize] = useState(Number(localStorage.getItem('bodyFontSize')) || defaultBodyFontSize);
|
||||||
const [bodyFont, setBodyFont] = useState(localStorage.getItem('bodyFont') || 'Sans Serif');
|
const [bodyFont, setBodyFont] = useState(localStorage.getItem('bodyFont') || 'Sans Serif');
|
||||||
const [articleFont, setArticleFont] = useState(localStorage.getItem('articleFont') || 'Apparatus SIL');
|
const [articleFont, setArticleFont] = useState(localStorage.getItem('articleFont') || 'Apparatus SIL');
|
||||||
|
const [filterSmallweb, setFilterSmallweb] = useState(() => localStorage.getItem('filterSmallweb') === 'true');
|
||||||
|
|
||||||
const updateCache = useCallback((key, value) => {
|
const updateCache = useCallback((key, value) => {
|
||||||
cache.current[key] = value;
|
cache.current[key] = value;
|
||||||
@@ -50,6 +51,12 @@ function App() {
|
|||||||
localStorage.setItem('theme', 'red');
|
localStorage.setItem('theme', 'red');
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleFilterChange = e => {
|
||||||
|
const isChecked = e.target.checked;
|
||||||
|
setFilterSmallweb(isChecked);
|
||||||
|
localStorage.setItem('filterSmallweb', isChecked);
|
||||||
|
};
|
||||||
|
|
||||||
const changeBodyFont = (font) => {
|
const changeBodyFont = (font) => {
|
||||||
setBodyFont(font);
|
setBodyFont(font);
|
||||||
localStorage.setItem('bodyFont', font);
|
localStorage.setItem('bodyFont', font);
|
||||||
@@ -164,6 +171,13 @@ function App() {
|
|||||||
<button className={theme === 'black' ? 'active' : ''} onClick={() => { black() }}>Black</button>
|
<button className={theme === 'black' ? 'active' : ''} onClick={() => { black() }}>Black</button>
|
||||||
<button className={theme === 'red' ? 'active' : ''} onClick={() => { red() }}>Red</button>
|
<button className={theme === 'red' ? 'active' : ''} onClick={() => { red() }}>Red</button>
|
||||||
</div>
|
</div>
|
||||||
|
<div className="setting-group">
|
||||||
|
<h4>Feed</h4>
|
||||||
|
<div className="font-option">
|
||||||
|
<input className="checkbox" type="checkbox" id="filter-smallweb" checked={filterSmallweb} onChange={handleFilterChange} />
|
||||||
|
<label htmlFor="filter-smallweb">Small websites</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div className="setting-group">
|
<div className="setting-group">
|
||||||
<h4>Font Size</h4>
|
<h4>Font Size</h4>
|
||||||
<button onClick={() => changeBodyFontSize(-0.05)}>-</button>
|
<button onClick={() => changeBodyFontSize(-0.05)}>-</button>
|
||||||
@@ -237,7 +251,7 @@ function App() {
|
|||||||
<Route path='/(|search)' component={Submit} />
|
<Route path='/(|search)' component={Submit} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Route path='/' exact render={(props) => <Feed {...props} updateCache={updateCache} />} />
|
<Route path='/' exact render={(props) => <Feed {...props} updateCache={updateCache} filterSmallweb={filterSmallweb} />} />
|
||||||
<Switch>
|
<Switch>
|
||||||
<Route path='/search' component={Results} />
|
<Route path='/search' component={Results} />
|
||||||
<Route path='/:id' exact render={(props) => <Article {...props} cache={cache.current} />} />
|
<Route path='/:id' exact render={(props) => <Article {...props} cache={cache.current} />} />
|
||||||
|
|||||||
@@ -1,21 +1,22 @@
|
|||||||
import React, { useState, useEffect } from 'react';
|
import React, { useState, useEffect, useRef } from 'react';
|
||||||
import { Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
import { Helmet } from 'react-helmet';
|
import { Helmet } from 'react-helmet';
|
||||||
import localForage from 'localforage';
|
import localForage from 'localforage';
|
||||||
import { sourceLink, infoLine, logos } from './utils.js';
|
import { sourceLink, infoLine, logos } from './utils.js';
|
||||||
|
|
||||||
function Feed({ updateCache }) {
|
function Feed({ updateCache, filterSmallweb }) {
|
||||||
const [stories, setStories] = useState(() => JSON.parse(localStorage.getItem('stories')) || false);
|
const [stories, setStories] = useState(() => JSON.parse(localStorage.getItem('stories')) || false);
|
||||||
const [error, setError] = useState('');
|
const [error, setError] = useState('');
|
||||||
const [loadingStatus, setLoadingStatus] = useState(null);
|
const [loadingStatus, setLoadingStatus] = useState(null);
|
||||||
const [filterSmallweb, setFilterSmallweb] = useState(() => localStorage.getItem('filterSmallweb') === 'true');
|
const isInitialMount = useRef(true);
|
||||||
|
|
||||||
const handleFilterChange = e => {
|
useEffect(() => {
|
||||||
const isChecked = e.target.checked;
|
if (isInitialMount.current) {
|
||||||
setStories(false);
|
isInitialMount.current = false;
|
||||||
setFilterSmallweb(isChecked);
|
} else {
|
||||||
localStorage.setItem('filterSmallweb', isChecked);
|
setStories(false);
|
||||||
};
|
}
|
||||||
|
}, [filterSmallweb]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const controller = new AbortController();
|
const controller = new AbortController();
|
||||||
@@ -125,11 +126,6 @@ function Feed({ updateCache }) {
|
|||||||
<meta name="robots" content="index" />
|
<meta name="robots" content="index" />
|
||||||
</Helmet>
|
</Helmet>
|
||||||
|
|
||||||
<div style={{marginBottom: '1rem'}}>
|
|
||||||
<input type="checkbox" id="filter-smallweb" className="checkbox" checked={filterSmallweb} onChange={handleFilterChange} />
|
|
||||||
<label htmlFor="filter-smallweb">Small websites</label>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{error &&
|
{error &&
|
||||||
<details style={{marginBottom: '1rem'}}>
|
<details style={{marginBottom: '1rem'}}>
|
||||||
<summary>Connection error? Click to expand.</summary>
|
<summary>Connection error? Click to expand.</summary>
|
||||||
|
|||||||
Reference in New Issue
Block a user