feat: add viewer preference for auto-marking articles as read and implement click/scroll-based read detection logic
This commit is contained in:
@@ -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 (< 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 (< 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 (≥ 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' }}>
|
||||
|
||||
Reference in New Issue
Block a user