This commit is contained in:
Tomáš Dvořák
2025-10-16 13:32:05 +02:00
commit 12cba639b9
663 changed files with 168914 additions and 0 deletions
+103
View File
@@ -0,0 +1,103 @@
import { Box, Heading, SimpleGrid, Image, Text, VStack, HStack, Button, Skeleton, Badge, useColorModeValue } from '@chakra-ui/react';
import { useQuery } from '@tanstack/react-query';
import { getArticles, Article } from '../../services/articles';
import { Link as RouterLink } from 'react-router-dom';
import { assetUrl } from '../../utils/url';
const BlogCard: React.FC<{ article: Article }> = ({ article }) => {
const link = article.slug ? `/news/${article.slug}` : `/articles/${article.id}`;
const cardBg = useColorModeValue('white', 'gray.800');
const border = useColorModeValue('gray.200', 'whiteAlpha.300');
const categoryName = (article as any)?.category?.name || '';
return (
<VStack
as={RouterLink}
to={link}
align="stretch"
spacing={0}
borderWidth="1px"
borderRadius="xl"
bg={cardBg}
overflow="hidden"
boxShadow="lg"
borderColor={border}
_hover={{ boxShadow: '2xl', transform: 'translateY(-4px)' }}
transition="all 0.3s cubic-bezier(0.4, 0, 0.2, 1)"
>
<Box position="relative" overflow="hidden">
<Image
src={assetUrl(article.image_url) || '/logo192.png'}
alt={article.title}
objectFit="cover"
w="100%"
h="200px"
transition="transform 0.3s ease"
_groupHover={{ transform: 'scale(1.05)' }}
/>
{categoryName && (
<Badge
position="absolute"
top={3}
left={3}
colorScheme="blue"
fontSize="xs"
px={3}
py={1}
borderRadius="full"
textTransform="uppercase"
fontWeight="bold"
>
{categoryName}
</Badge>
)}
</Box>
<VStack align="stretch" spacing={3} p={5}>
<Heading size="md" noOfLines={2} lineHeight="1.3">{article.title}</Heading>
<Text noOfLines={3} color="gray.600" fontSize="sm" lineHeight="1.5">
{article.content?.replace(/<[^>]*>/g, '').slice(0, 160)}
</Text>
<HStack spacing={2} pt={2} borderTopWidth="1px" borderColor={border}>
{article.estimated_read_minutes && (
<Text fontSize="xs" color="gray.500">
{article.estimated_read_minutes} min čtení
</Text>
)}
{article.published_at && (
<Text fontSize="xs" color="gray.500">
{new Date(article.published_at).toLocaleDateString('cs-CZ')}
</Text>
)}
</HStack>
</VStack>
</VStack>
);
};
const BlogGrid: React.FC = () => {
const { data, isLoading } = useQuery({
queryKey: ['articles', { page: 1, page_size: 10, published: true }],
queryFn: () => getArticles({ page: 1, page_size: 10, published: true }),
});
const articles = data?.data || [];
return (
<Box>
<HStack justify="space-between" mb={4}>
<Heading size="lg">Aktuality</Heading>
<Button as={RouterLink} to="/blog" size="sm" variant="link">Zobrazit všechny</Button>
</HStack>
<SimpleGrid columns={{ base: 1, sm: 2, md: 3 }} spacing={6}>
{isLoading && Array.from({ length: 6 }).map((_, i) => (
<Skeleton key={i} height="240px" />
))}
{!isLoading && articles.map((a) => (
<BlogCard key={a.id} article={a} />
))}
</SimpleGrid>
</Box>
);
};
export default BlogGrid;