personal-dash-cl/claudash/src/components/widgets/NewsWidget.jsx
2026-02-12 03:26:10 -05:00

199 lines
No EOL
7.2 KiB
JavaScript

import { Typography, Box, Link, Chip, List, ListItem, ListItemText } from '@mui/material';
import { OpenInNew, Comment, TrendingUp } from '@mui/icons-material';
import GenericWidget from './GenericWidget';
function NewsWidget({ data, sx }) {
if (!data || data.error) {
return (
<GenericWidget title="News" sx={{ opacity: 0.5, ...sx }}>
<Typography color="text.secondary">
{data?.message || 'News data unavailable'}
</Typography>
</GenericWidget>
);
}
// Handle Reddit data
if (data.type === 'reddit' && data.posts) {
const subreddit = data.url?.match(/\/r\/([^\/\.]+)/)?.[1] || 'Reddit';
return (
<GenericWidget title={`r/${subreddit}`} sx={{ ...sx }}>
<List dense>
{data.posts.slice(0, 5).map((post, index) => (
<ListItem key={index} disablePadding sx={{ mb: 1 }}>
<ListItemText
primary={
<Box sx={{ display: 'flex', alignItems: 'start', gap: 1 }}>
{post.thumbnail && post.thumbnail.startsWith('http') && (
<Link
href={post.url}
target="_blank"
rel="noopener noreferrer"
>
<Box
component="img"
src={post.thumbnail}
alt={post.title}
sx={{
width: 70,
height: 70,
objectFit: 'cover',
borderRadius: 1,
flexShrink: 0
}}
/>
</Link>
)}
<Link
href={post.url}
target="_blank"
rel="noopener noreferrer"
sx={{
textDecoration: 'none',
color: 'text.primary',
'&:hover': { textDecoration: 'underline' }
}}
>
<Typography variant="body2" sx={{ display: 'flex', alignItems: 'center', gap: 0.5 }}>
{post.title}
<OpenInNew sx={{ fontSize: 14 }} />
</Typography>
</Link>
</Box>
}
secondaryTypographyProps={{ component: 'div' }}
secondary={
<Box sx={{ display: 'flex', gap: 1, mt: 0.5 }}>
<Chip
icon={<TrendingUp />}
label={post.score}
size="small"
variant="outlined"
/>
<Chip
icon={<Comment />}
label={post.comments}
size="small"
variant="outlined"
/>
<Typography variant="caption" color="text.secondary" sx={{ ml: 1, alignSelf: 'center' }}>
by {post.author}
</Typography>
</Box>
}
/>
</ListItem>
))}
</List>
</GenericWidget>
);
}
// Handle RSS feed data
if (data.type === 'rss' && data.items) {
return (
<GenericWidget title={data.feedTitle || 'RSS Feed'} sx={{ ...sx }}>
<List dense>
{data.items.slice(0, 5).map((item, index) => (
<ListItem key={index} disablePadding sx={{ mb: 1 }}>
<ListItemText
primary={
<Box sx={{ display: 'flex', alignItems: 'start', gap: 1 }}>
{(item.thumbnail || item.enclosure?.url || item['media:thumbnail']?.url) && (
<Link
href={item.link}
target="_blank"
rel="noopener noreferrer"
>
<Box
component="img"
src={item.thumbnail || item.enclosure?.url || item['media:thumbnail']?.url}
alt={item.title}
sx={{
width: 70,
height: 70,
objectFit: 'cover',
borderRadius: 1,
flexShrink: 0
}}
/>
</Link>
)}
<Link
href={item.link}
target="_blank"
rel="noopener noreferrer"
sx={{
textDecoration: 'none',
color: 'text.primary',
'&:hover': { textDecoration: 'underline' }
}}
>
<Typography variant="body2" sx={{ display: 'flex', alignItems: 'center', gap: 0.5 }}>
{item.title}
<OpenInNew sx={{ fontSize: 14 }} />
</Typography>
</Link>
</Box>
}
secondaryTypographyProps={{ component: 'div' }}
secondary={
<Box>
<Typography variant="caption" color="text.secondary">
{item.pubDate && new Date(item.pubDate).toLocaleDateString()}
</Typography>
{item.description && (
<Typography
variant="caption"
color="text.secondary"
sx={{
display: '-webkit-box',
mt: 0.5,
overflow: 'hidden',
textOverflow: 'ellipsis',
WebkitLineClamp: 2,
WebkitBoxOrient: 'vertical',
}}
>
{item.description.replace(/<[^>]*>?/gm, '')}
</Typography>
)}
</Box>
}
/>
</ListItem>
))}
</List>
</GenericWidget>
);
}
// Handle Hacker News data
if (data.type === 'hackernews' && data.storyIds) {
return (
<GenericWidget title="Hacker News" sx={{ ...sx }}>
<Typography variant="body2" color="text.secondary">
{data.storyIds.length} top stories loaded
</Typography>
<Typography variant="caption" color="text.secondary">
(Story details will load when API is configured)
</Typography>
</GenericWidget>
);
}
// Default fallback for unknown data types
return (
<GenericWidget title="News" sx={{ ...sx }}>
<Typography variant="body2" color="text.secondary">
Data format not recognized
</Typography>
<Typography variant="caption" color="text.secondary">
{JSON.stringify(data).substring(0, 100)}...
</Typography>
</GenericWidget>
);
}
export default NewsWidget;