"use client"; import { Card, Flex, Group, Image, ScrollArea, SimpleGrid, Text } from "@mantine/core"; import { IconClock } from "@tabler/icons-react"; import dayjs from "dayjs"; import type { RouterInputs } from "@homarr/api"; import { clientApi } from "@homarr/api/client"; import { useRequiredBoard } from "@homarr/boards/context"; import type { WidgetComponentProps } from "../definition"; import classes from "./component.module.scss"; const useLiveFeedEntries = (input: RouterInputs["widget"]["rssFeed"]["getFeeds"]) => { const { data: feedEntries = [], error } = clientApi.widget.rssFeed.getFeeds.useQuery(input); if (error) throw error; return feedEntries; }; export default function RssFeed({ options, width, displayMode }: WidgetComponentProps<"rssFeed">) { const feedEntries = useLiveFeedEntries({ urls: options.feedUrls, maximumAmountPosts: typeof options.maximumAmountPosts === "number" ? options.maximumAmountPosts : 100, }); const board = useRequiredBoard(); const languageDir = options.enableRtl ? "RTL" : "LTR"; const isAdvanced = displayMode === "advanced"; const isNarrow = !isAdvanced && width < 128 * 3; const columns = isAdvanced && width >= 720 ? 2 : 1; return ( {feedEntries.map((feedEntry) => ( {feedEntry.enclosure !== undefined && ( backdrop )} {feedEntry.enclosure !== undefined && options.showPosterImage && !isNarrow && ( {feedEntry.title} )} {feedEntry.title} {!options.hideDescription && feedEntry.description && ( {feedDescriptionToText(feedEntry.description)} )} ))} ); } export const feedDescriptionToText = (description: string): string => { if (typeof DOMParser !== "undefined") { return new DOMParser().parseFromString(description, "text/html").body.textContent?.trim() ?? ""; } return description .replace(/<[^>]*>/g, " ") .replace(/\s+/g, " ") .trim(); }; export const getHostname = (url: string): string => { try { return new URL(url).hostname; } catch { return url; } }; export const getSafeExternalUrl = (value: unknown, baseUrl?: string): string | undefined => { if (typeof value !== "string") return undefined; try { const url = new URL(value, baseUrl); return url.protocol === "http:" || url.protocol === "https:" ? url.toString() : undefined; } catch { return undefined; } }; const InfoDisplay = ({ date, source }: { date?: string; source?: string }) => ( {date && } {date && ( {date} )} {date && source && •} {source && ( {source} )} );