import { useEffect, useState } from "react"; import { Rss, ExternalLink } from "lucide-react"; import { registerWidget } from "./WidgetRegistry"; import { homepageApi } from "@/main-axios"; import type { RssFeedConfig, WidgetComponentProps, } from "@/types/homepage-types"; import { GRID_SIZE } from "@/types/homepage-types"; import { WidgetTitle } from "./WidgetTitle"; interface RssItem { title: string; link: string; pubDate: string | null; description: string | null; } function formatDate(dateStr: string | null): string { if (!dateStr) return ""; try { const d = new Date(dateStr); const diffMs = Date.now() - d.getTime(); const diffH = Math.floor(diffMs / 3_600_000); if (diffH < 1) return "just now"; if (diffH < 24) return `${diffH}h ago`; const diffD = Math.floor(diffH / 24); if (diffD < 7) return `${diffD}d ago`; return d.toLocaleDateString(undefined, { month: "short", day: "numeric" }); } catch { return ""; } } function RssFeedWidget({ widget, config, isReadOnly, }: WidgetComponentProps) { const { feedUrl, maxItems, showDescription } = config; const [items, setItems] = useState([]); const [error, setError] = useState(false); const [loading, setLoading] = useState(false); useEffect(() => { if (!feedUrl) return; let cancelled = false; const fetchFeed = async () => { try { setLoading(true); setError(false); const res = await homepageApi.get( `/rss?url=${encodeURIComponent(feedUrl)}&max=${maxItems ?? 10}`, ); if (!cancelled) setItems(res.data); } catch { if (!cancelled) setError(true); } finally { if (!cancelled) setLoading(false); } }; fetchFeed(); return () => { cancelled = true; }; }, [feedUrl, maxItems]); if (!feedUrl) { return (
Configure a feed URL in widget settings
); } if (loading && items.length === 0) { return (
Loading...
); } if (error) { return (
Could not load feed
); } return (
} /> {/* Items */}
{items.length === 0 ? (
No items
) : ( items.map((item, i) => ( )) )}
); } registerWidget({ id: "rss_feed", name: "RSS Feed", description: "Display items from an RSS or Atom feed", category: "links", icon: , defaultConfig: { feedUrl: "", maxItems: 10, showDescription: false }, defaultSize: { w: GRID_SIZE * 10, h: GRID_SIZE * 10 }, minSize: { w: GRID_SIZE * 2, h: GRID_SIZE * 2 }, component: RssFeedWidget, }); export { RssFeedWidget };