cdrdpyj/src/pages/[locale]/[section]/index.astro

180 lines
6.9 KiB
Plaintext

---
import MainLayout from "@/layouts/MainLayout.astro"
import Header from "@/components/Header.astro"
import NewsList from "@/components/cards/NewsList.astro";
import { getCollection } from "astro:content";
import FooterSection from "@/components/section/FooterSection.astro";
import { createTranslator, getRouteKeyFromSlug } from '@/i18n';
const tl = createTranslator(Astro.currentLocale);
const { locale, section } = Astro.params;
const routeKey = getRouteKeyFromSlug(section);
const items = await getCollection(routeKey, (post)=>{
const currentLocale = Astro.currentLocale;
return post.data.locale == currentLocale
});
const sortedPosts = [...items]
.sort((a, b) => {
const dateDiff = new Date(b.data.date).getTime() - new Date(a.data.date).getTime()
if (dateDiff !== 0) return dateDiff
return (a.data.order ?? 0) - (b.data.order ?? 0)
});
const allTags = routeKey === "news" ? [...new Set(
sortedPosts
.filter(p => p.data.tags && p.data.tags.length > 0)
.flatMap(p => p.data.tags)
.filter((tag): tag is string => tag !== undefined)
)].sort() : [];
const allYears = routeKey === "news" ? [...new Set(
sortedPosts.map(p => new Date(p.data.date).getFullYear())
)].sort((a, b) => b - a) : [];
---
<MainLayout >
<div class="top-16 relative mb container mx-auto">
<Header />
</div>
<div class="container mx-auto mt-4">
<div class="flex flex-col lg:w-1/2 items-center mx-auto py-8">
<h1 class="text-white text-2xl uppercase font-bold text-center mb-4 font-primary md:mt-20 mt-10">{tl(routeKey + ".title")}</h1>
<h2 class="text-white text-3xl lg:text-5xl font-bold text-center font-secondary mb-4 md:p-0 px-2">{tl(routeKey + ".text")}</h2>
</div>
{routeKey === "news" && allTags.length > 0 && (
<div class="container mx-auto mb-8 px-4 md:px-0">
<div class="flex flex-nowrap md:flex-wrap gap-2 md:justify-center overflow-x-auto md:overflow-visible pb-2 md:pb-0">
<button class="filter-btn px-4 py-2 font-primary text-sm cursor-pointer transition-colors whitespace-nowrap" data-tag="all">
{tl("news.all")}
</button>
{allTags.map((tag) => (
<button class="filter-btn px-4 py-2 font-primary text-sm cursor-pointer transition-colors whitespace-nowrap" data-tag={tag!}>
{tag}
</button>
))}
</div>
</div>
)}
<div class="flex flex-col md:gap-0 gap-2 lg:max-w-4xl mx-auto bg-white p-4 md:p-8">
{routeKey === "news" && allYears.length > 0 && (
<div class="container mb-4">
<div class="flex justify-start md:justify-end">
<select id="year-filter" class="bg-[#003421] text-[#EBE5D0] px-4 py-2 font-primary text-sm cursor-pointer border-none outline-none">
<option value="all">{tl("news.allYears")}</option>
{allYears.map((year) => (
<option value={year}>{year}</option>
))}
</select>
</div>
</div>
)}
{
sortedPosts.map((item) => (
<div class="news-item" data-tags={routeKey === "news" ? JSON.stringify(item.data.tags || []) : "[]"} data-year={routeKey === "news" ? new Date(item.data.date).getFullYear() : ""}>
<NewsList data={item} content={{ body: item.body }} routeKey={routeKey} />
</div>
))
}
</div>
</div>
<FooterSection />
</MainLayout>
<script>
const activeClasses = "bg-[#003421] text-[#EBE5D0]";
const inactiveClasses = "bg-[#003421]/20 text-[#EBE5D0] hover:bg-[#003421]/30";
let currentTag: string | null = 'all';
let currentYear: string = 'all';
function filterItems() {
document.querySelectorAll('.news-item').forEach(item => {
const itemTags = JSON.parse(item.getAttribute('data-tags') || '[]');
const itemYear = item.getAttribute('data-year');
const tagMatch = currentTag === 'all' || currentTag === null || itemTags.includes(currentTag);
const yearMatch = currentYear === 'all' || itemYear === currentYear;
if (tagMatch && yearMatch) {
(item as HTMLElement).style.display = 'block';
} else {
(item as HTMLElement).style.display = 'none';
}
});
}
function activateTag(tag: string | null) {
currentTag = tag;
document.querySelectorAll('.filter-btn').forEach(b => {
if (b.getAttribute('data-tag') === tag) {
b.classList.remove(...inactiveClasses.split(" "));
b.classList.add(...activeClasses.split(" "));
} else {
b.classList.remove(...activeClasses.split(" "));
b.classList.add(...inactiveClasses.split(" "));
}
});
filterItems();
}
function updateUrl(tag: string | null) {
const url = new URL(window.location.href);
if (tag && tag !== 'all') {
url.searchParams.set('tag', tag);
} else {
url.searchParams.delete('tag');
}
window.history.replaceState({}, '', url.toString());
}
function initTags() {
document.querySelectorAll('.filter-btn').forEach(btn => {
btn.classList.add(...inactiveClasses.split(" "));
});
const urlParams = new URLSearchParams(window.location.search);
if (urlParams.has('tag')) {
urlParams.delete('tag');
window.history.replaceState({}, '', window.location.pathname + window.location.search);
}
document.querySelector('.filter-btn[data-tag="all"]')?.classList.add(...activeClasses.split(" "));
document.querySelector('.filter-btn[data-tag="all"]')?.classList.remove(...inactiveClasses.split(" "));
activateTag('all');
document.querySelectorAll('.filter-btn').forEach(btn => {
btn.addEventListener('click', () => {
const tag = btn.getAttribute('data-tag');
activateTag(tag);
updateUrl(tag);
});
});
}
function initYearFilter() {
const yearSelect = document.querySelector('#year-filter') as HTMLSelectElement;
if (yearSelect) {
yearSelect.addEventListener('change', () => {
currentYear = yearSelect.value;
filterItems();
});
}
}
document.addEventListener('astro:page-load', () => {
initTags();
initYearFilter();
});
if (document.readyState === 'complete') {
initTags();
initYearFilter();
}
</script>