Add time filter pills to RSS feed widget

Adds since query param (1h/24h/7d/30d) to the RSS API route and
a matching TimeFilterPills row in the NewsFeed UI so users can
narrow the feed to recent items.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Shivam Patel
2026-02-09 17:25:39 -05:00
parent b9568c69a7
commit 717d52bd9a
2 changed files with 69 additions and 1 deletions

View File

@@ -150,6 +150,51 @@ function FeedFilterPills({
);
}
type TimeFilter = '1h' | '24h' | '7d' | '30d';
const TIME_FILTER_OPTIONS: { value: TimeFilter; label: string }[] = [
{ value: '1h', label: '1h' },
{ value: '24h', label: '24h' },
{ value: '7d', label: '7d' },
{ value: '30d', label: '30d' },
];
function TimeFilterPills({
active,
onSelect,
}: {
active: TimeFilter | null;
onSelect: (v: TimeFilter | null) => void;
}) {
return (
<div className="flex gap-1.5 overflow-x-auto pb-1 scrollbar-none">
<button
onClick={() => onSelect(null)}
className={`shrink-0 px-2.5 py-1 rounded-full text-[11px] font-medium transition-colors ${
active === null
? 'bg-neutral-700 text-white'
: 'bg-neutral-800/60 text-neutral-400 hover:text-neutral-200'
}`}
>
Any time
</button>
{TIME_FILTER_OPTIONS.map((opt) => (
<button
key={opt.value}
onClick={() => onSelect(opt.value)}
className={`shrink-0 px-2.5 py-1 rounded-full text-[11px] font-medium transition-colors ${
active === opt.value
? 'bg-neutral-700 text-white'
: 'bg-neutral-800/60 text-neutral-400 hover:text-neutral-200'
}`}
>
{opt.label}
</button>
))}
</div>
);
}
function AddFeedForm({ onAdded }: { onAdded: () => void }) {
const [url, setUrl] = useState('');
const [submitting, setSubmitting] = useState(false);
@@ -332,6 +377,7 @@ export function NewsFeed() {
const [feeds, setFeeds] = useState<Feed[]>([]);
const [searchQuery, setSearchQuery] = useState('');
const [activeFeedId, setActiveFeedId] = useState<number | null>(null);
const [timeFilter, setTimeFilter] = useState<TimeFilter | null>(null);
const [showBookmarked, setShowBookmarked] = useState(false);
const [showFeedManager, setShowFeedManager] = useState(false);
const [loading, setLoading] = useState(true);
@@ -354,6 +400,7 @@ export function NewsFeed() {
if (searchQuery) params.set('q', searchQuery);
if (!opts?.resetFeedFilter && activeFeedId !== null) params.set('feed_id', String(activeFeedId));
if (showBookmarked) params.set('bookmarked', '1');
if (timeFilter) params.set('since', timeFilter);
params.set('limit', '50');
const res = await fetch(`/api/rss?${params}`);
@@ -373,7 +420,7 @@ export function NewsFeed() {
} finally {
setLoading(false);
}
}, [searchQuery, activeFeedId, showBookmarked]);
}, [searchQuery, activeFeedId, showBookmarked, timeFilter]);
// Initial load + refresh
useEffect(() => {
@@ -469,6 +516,13 @@ export function NewsFeed() {
</div>
)}
{/* Time filter pills */}
{hasFeeds && (
<div className="shrink-0 mb-2">
<TimeFilterPills active={timeFilter} onSelect={setTimeFilter} />
</div>
)}
{/* Feed manager (collapsible) */}
{showFeedManager && (
<div className="shrink-0 mb-3">