Add full project source
This commit is contained in:
101
src/pages/cs/index.astro
Normal file
101
src/pages/cs/index.astro
Normal file
@@ -0,0 +1,101 @@
|
||||
---
|
||||
import BaseLayout from '../../layouts/BaseLayout.astro';
|
||||
import ArticleTile from '../../components/ArticleTile.astro';
|
||||
import { getCollection } from 'astro:content';
|
||||
import { useTranslations } from '../../i18n/ui';
|
||||
|
||||
const lang = 'cs';
|
||||
const t = useTranslations(lang);
|
||||
|
||||
const posts = (await getCollection('blog', ({ data }) => !data.draft))
|
||||
.filter(p => p.id.startsWith('cs/'))
|
||||
.sort((a, b) => b.data.date.valueOf() - a.data.date.valueOf());
|
||||
|
||||
const allTags = [...new Set(posts.flatMap(p => p.data.tags))].sort();
|
||||
---
|
||||
|
||||
<BaseLayout title="Vladimír Duša" description="Osobní web Vladimíra Duši" lang={lang} alternateUrl="/en/">
|
||||
{posts.length === 0 ? (
|
||||
<div class="px-8 py-16 text-gray-400 text-sm">{t('empty.articles')}</div>
|
||||
) : (
|
||||
<div class="px-8 pb-12">
|
||||
{allTags.length > 0 && (
|
||||
<div class="tag-filter" id="tag-filter">
|
||||
<button class="tag-filter-btn active" data-tag="all">{t('filter.all')}</button>
|
||||
{allTags.map((tag) => (
|
||||
<>
|
||||
<span class="tag-filter-sep">·</span>
|
||||
<button class="tag-filter-btn" data-tag={tag}>{tag}</button>
|
||||
</>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
<div class="article-grid">
|
||||
{posts.map((post, i) => {
|
||||
const baseSlug = post.id.replace(/^cs\//, '').replace(/\.md$/, '');
|
||||
return (
|
||||
<ArticleTile
|
||||
title={post.data.title}
|
||||
href={`/cs/clanky/${baseSlug}`}
|
||||
image={post.data.image}
|
||||
description={post.data.description}
|
||||
tags={post.data.tags}
|
||||
class={i % 6 === 0 ? 'tile-featured-left' : i % 6 === 5 ? 'tile-featured-right' : 'tile-regular'}
|
||||
eager={i < 3}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</BaseLayout>
|
||||
|
||||
<script>
|
||||
const buttons = document.querySelectorAll<HTMLButtonElement>('.tag-filter-btn');
|
||||
const tiles = document.querySelectorAll<HTMLAnchorElement>('.article-tile');
|
||||
|
||||
function applyFilter(tag: string) {
|
||||
buttons.forEach(btn => btn.classList.toggle('active', btn.dataset.tag === tag));
|
||||
|
||||
tiles.forEach(tile => {
|
||||
const tileTags = (tile.dataset.tags ?? '').split(',').filter(Boolean);
|
||||
const matches = tag === 'all' || tileTags.includes(tag);
|
||||
tile.classList.toggle('is-filtered', !matches);
|
||||
});
|
||||
|
||||
const url = new URL(window.location.href);
|
||||
if (tag === 'all') url.searchParams.delete('tag');
|
||||
else url.searchParams.set('tag', tag);
|
||||
history.replaceState(null, '', url.toString());
|
||||
}
|
||||
|
||||
const initialTag = new URLSearchParams(window.location.search).get('tag') ?? 'all';
|
||||
applyFilter(initialTag);
|
||||
|
||||
buttons.forEach(btn => {
|
||||
btn.addEventListener('click', () => applyFilter(btn.dataset.tag ?? 'all'));
|
||||
});
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.article-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, 1fr);
|
||||
grid-auto-rows: 260px;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.article-grid {
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
grid-auto-rows: 200px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 480px) {
|
||||
.article-grid {
|
||||
grid-template-columns: 1fr;
|
||||
grid-auto-rows: 220px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user