feat: add viewer preference for auto-marking articles as read and implement click/scroll-based read detection logic

This commit is contained in:
2026-08-24 21:25:32 -07:00
parent 3742dbdce4
commit 7a51931386
4 changed files with 112 additions and 122 deletions
+61 -2
View File
@@ -19,6 +19,7 @@ import {
X,
Clock,
Timer,
Eye,
} from 'lucide-react';
interface SettingsViewProps {
@@ -38,7 +39,10 @@ export const SettingsView: React.FC<SettingsViewProps> = ({
onRefreshData,
onOpenAddFeed,
}) => {
const [activeTab, setActiveTab] = useState<'feeds' | 'categories' | 'opml' | 'account'>('feeds');
const [activeTab, setActiveTab] = useState<'feeds' | 'categories' | 'viewer' | 'opml' | 'account'>('feeds');
const [autoReadBottom, setAutoReadBottom] = useState<boolean>(() => {
return localStorage.getItem('rsspipe_auto_read_bottom') !== 'false';
});
const [feedSearch, setFeedSearch] = useState('');
const [newCatTitle, setNewCatTitle] = useState('');
const [loading, setLoading] = useState(false);
@@ -191,6 +195,14 @@ export const SettingsView: React.FC<SettingsViewProps> = ({
<span>Categories ({categories.length})</span>
</button>
<button
className={`settings-nav-item ${activeTab === 'viewer' ? 'active' : ''}`}
onClick={() => setActiveTab('viewer')}
>
<Eye size={15} />
<span>Viewer</span>
</button>
<button
className={`settings-nav-item ${activeTab === 'opml' ? 'active' : ''}`}
onClick={() => setActiveTab('opml')}
@@ -463,7 +475,54 @@ export const SettingsView: React.FC<SettingsViewProps> = ({
</div>
)}
{/* 3. OPML Tab */}
{/* 3. Viewer Preferences Tab */}
{activeTab === 'viewer' && (
<div>
<div style={{ marginBottom: '1.25rem' }}>
<h2 style={{ fontSize: '1.2rem', fontWeight: 700, color: 'var(--text-main)' }}>
Viewer & Reading Preferences
</h2>
<p style={{ fontSize: '0.8rem', color: 'var(--text-muted)' }}>
Configure reading behavior, auto-read triggers, and article view options.
</p>
</div>
<div className="settings-card">
<h3 className="settings-card-title">Auto-Mark as Read</h3>
<p className="settings-card-subtitle">
Control how articles are automatically marked as read during your reading session.
</p>
<div style={{ marginTop: '1rem' }}>
<label style={{ display: 'flex', alignItems: 'flex-start', gap: '0.75rem', cursor: 'pointer' }}>
<input
type="checkbox"
checked={autoReadBottom}
onChange={(e) => {
const val = e.target.checked;
setAutoReadBottom(val);
localStorage.setItem('rsspipe_auto_read_bottom', val ? 'true' : 'false');
setMessage(`Updated viewer preferences: auto-read at bottom ${val ? 'enabled' : 'disabled'}.`);
setTimeout(() => setMessage(null), 3000);
}}
style={{ marginTop: '0.2rem', width: 16, height: 16, accentColor: 'var(--accent)' }}
/>
<div>
<div style={{ fontSize: '0.88rem', fontWeight: 600, color: 'var(--text-main)' }}>
Auto mark short articles (&lt; 1 page) as read after 2 seconds
</div>
<div style={{ fontSize: '0.78rem', color: 'var(--text-muted)', marginTop: '0.25rem', lineHeight: 1.4 }}>
• <strong>Short articles (&lt; 1 page)</strong>: Since the content is non-scrollable and fully visible, automatically marks as read after 2 seconds of viewing.<br />
• <strong>Long articles (&ge; 1 page)</strong>: Any active scroll on the content pane immediately marks the post as read.
</div>
</div>
</label>
</div>
</div>
</div>
)}
{/* 4. OPML Migration Tab */}
{activeTab === 'opml' && (
<div>
<div style={{ marginBottom: '1.25rem' }}>