import Link from 'next/link'; import { ActionIcon, Badge, Card, Center, Flex, Group, Image, Loader, LoadingOverlay, MediaQuery, ScrollArea, Stack, Text, Title, createStyles, } from '@mantine/core'; import { IconClock, IconRefresh, IconRss } from '@tabler/icons'; import { useQuery } from '@tanstack/react-query'; import dayjs from 'dayjs'; import { useTranslation } from 'next-i18next'; import { defineWidget } from '../helper'; import { IWidget } from '../widgets'; const definition = defineWidget({ id: 'rss', icon: IconRss, options: { rssFeedUrl: { type: 'multiple-text', defaultValue: ['https://github.com/ajnart/homarr/tags.atom'], }, }, gridstack: { minWidth: 2, minHeight: 2, maxWidth: 12, maxHeight: 12, }, component: RssTile, }); export type IRssWidget = IWidget<(typeof definition)['id'], typeof definition>; interface RssTileProps { widget: IRssWidget; } export const useGetRssFeeds = (feedUrls: string[], widgetId: string) => useQuery({ queryKey: ['rss-feeds', feedUrls], // Cache the results for 24 hours cacheTime: 1000 * 60 * 60 * 24, queryFn: async () => { const responses = await Promise.all( feedUrls.map((feedUrl) => fetch( `/api/modules/rss?widgetId=${widgetId}&feedUrl=${encodeURIComponent(feedUrl)}` ).then((response) => response.json()) ) ); return responses; }, }); function RssTile({ widget }: RssTileProps) { const { t } = useTranslation('modules/rss'); const { data, isLoading, isFetching, isError, refetch } = useGetRssFeeds( widget.properties.rssFeedUrl, widget.id ); const { classes } = useStyles(); function formatDate(input: string): string { // Parse the input date as a local date try { const inputDate = dayjs(new Date(input)); const now = dayjs(); // Current date and time // The difference between the input date and now const difference = now.diff(inputDate, 'ms'); const duration = dayjs.duration(difference, 'ms'); const humanizedDuration = duration.humanize(); return `${humanizedDuration} ago`; } catch (e) { return 'Error'; } } if (!data || isLoading) { return (