feat(news): improve news listing with tags filter, badges and url params
- Add new vertical layout with thumbnail, excerpt, tags and read more button - Add tags filter navbar with click-to-filter functionality - Add tags as checkered badges (beige/green pattern) - Add URL parameter ?tag=[tag] for sharing filtered views - Add tags display to individual news page - Fix TypeScript errors in news pages - Update tina config for proper content schema
This commit is contained in:
parent
627ea56417
commit
b65e070620
|
|
@ -7,24 +7,71 @@ import utc from "dayjs/plugin/utc";
|
||||||
const regionNames = new Intl.DisplayNames(['es'], { type: 'region' });
|
const regionNames = new Intl.DisplayNames(['es'], { type: 'region' });
|
||||||
|
|
||||||
const locale = Astro.currentLocale;
|
const locale = Astro.currentLocale;
|
||||||
|
import { createTranslator } from '@/i18n';
|
||||||
|
const tl = createTranslator(Astro.currentLocale);
|
||||||
dayjs.extend(utc);
|
dayjs.extend(utc);
|
||||||
dayjs.locale(locale);
|
dayjs.locale(locale);
|
||||||
|
|
||||||
const { data } = Astro.props;
|
const { data, content } = Astro.props;
|
||||||
const nicedate = dayjs.utc(data.data.date).format("D MMMM YYYY");
|
const nicedate = dayjs.utc(data.data.date).format("D MMMM YYYY");
|
||||||
const countryName = data?.data?.country ? regionNames.of(data.data.country) : "";
|
const countryName = data?.data?.country ? regionNames.of(data.data.country) : "";
|
||||||
|
|
||||||
const locationArray = [data.data.city,countryName]
|
const locationArray = [data.data.city,countryName]
|
||||||
locationArray.filter(Boolean).join(', ');
|
const location = locationArray.filter(Boolean).join(', ');
|
||||||
|
|
||||||
|
const newsUrl = `/${locale}/news/${data.id}`;
|
||||||
|
|
||||||
|
const rawContent = content?.body || "";
|
||||||
|
const plainText = rawContent.replace(/^#.*$/gm, '').replace(/^###.*$/gm, '').trim();
|
||||||
|
const words = plainText.split(/\s+/).slice(0, 40);
|
||||||
|
const excerpt = words.join(' ') + (words.length === 40 ? '...' : '');
|
||||||
---
|
---
|
||||||
|
|
||||||
<div>
|
<a href={newsUrl} class="block group">
|
||||||
<h3 class="text-2xl font-bold mb-1 font-secondary text-tertiary"><a href={`/${locale}/news/${data.id}`}>{data.data.title}</a></h3>
|
<article class="flex flex-col md:flex-row gap-6 md:gap-8 p-4 md:p-6 border-b border-tertiary/20 hover:bg-tertiary/5 transition-colors">
|
||||||
|
<div class="md:w-1/3 flex-shrink-0 overflow-hidden">
|
||||||
{
|
<Image
|
||||||
data.data.city && <span class="font-normal font-primary text-lg text-tertiary/70">
|
src={data.data.thumbnail}
|
||||||
{locationArray.filter(Boolean).join(', ')} | </span>
|
alt={data.data.title}
|
||||||
}
|
width={400}
|
||||||
<span class="font-normal font-primary text-lg text-tertiary/70">{nicedate}</span>
|
height={300}
|
||||||
|
class="w-full h-48 md:h-full object-cover transform group-hover:scale-105 transition-transform duration-300"
|
||||||
</div>
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="md:w-2/3 flex flex-col">
|
||||||
|
<div class="flex items-center gap-2 mb-2">
|
||||||
|
<span class="font-normal font-primary text-sm text-tertiary/70">{nicedate}</span>
|
||||||
|
{location && (
|
||||||
|
<>
|
||||||
|
<span class="text-tertiary/40">|</span>
|
||||||
|
<span class="font-normal font-primary text-sm text-tertiary/70">{location}</span>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h3 class="text-xl md:text-2xl font-bold font-secondary text-tertiary group-hover:text-tertiary/80 transition-colors mb-2">
|
||||||
|
{data.data.title}
|
||||||
|
</h3>
|
||||||
|
|
||||||
|
<p class="font-primary text-base text-tertiary/80 mb-4 line-clamp-3">
|
||||||
|
{excerpt}
|
||||||
|
</p>
|
||||||
|
|
||||||
|
{data.data.tags && data.data.tags.length > 0 && (
|
||||||
|
<div class="flex flex-wrap gap-2 mb-4">
|
||||||
|
{data.data.tags.map((tag: string) => (
|
||||||
|
<span class="badge rounded-none bg-[#EBE6D2] border-none text-[#003421]">{tag}</span>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<div class="mt-auto">
|
||||||
|
<span class="inline-flex items-center gap-1 text-sm font-primary text-tertiary font-semibold group-hover:underline">
|
||||||
|
{tl("news.seemore")}
|
||||||
|
<Icon name="ph:arrow-right" class="transform group-hover:translate-x-1 transition-transform" />
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</article>
|
||||||
|
</a>
|
||||||
|
|
@ -16,6 +16,7 @@ const news = defineCollection({
|
||||||
country: z.string().optional(),
|
country: z.string().optional(),
|
||||||
thumbnail: image().optional().describe("Main news thumbnail image"),
|
thumbnail: image().optional().describe("Main news thumbnail image"),
|
||||||
youtube: z.string().optional(),
|
youtube: z.string().optional(),
|
||||||
|
tags: z.array(z.string()).optional().describe("News tags"),
|
||||||
gallery: z.array(z.object({
|
gallery: z.array(z.object({
|
||||||
image: image().optional(),
|
image: image().optional(),
|
||||||
text: z.string().optional()
|
text: z.string().optional()
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ place: 'Cámara de Representantes'
|
||||||
city: 'Bogotá'
|
city: 'Bogotá'
|
||||||
state: 'Distrito Capital'
|
state: 'Distrito Capital'
|
||||||
country: 'CO'
|
country: 'CO'
|
||||||
|
tags: [Colombia]
|
||||||
thumbnail: https://ik.imagekit.io/crpy/tr:w-900/JBP-CONDECORACION-25.webp
|
thumbnail: https://ik.imagekit.io/crpy/tr:w-900/JBP-CONDECORACION-25.webp
|
||||||
gallery: [
|
gallery: [
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ slug: 2025-08-29-un-nuevo-hijo-para-jacarei
|
||||||
place: ''
|
place: ''
|
||||||
city: Jacareí
|
city: Jacareí
|
||||||
country: BR
|
country: BR
|
||||||
|
tags: [Brasil]
|
||||||
thumbnail: https://ik.imagekit.io/crpy/tr:w-900/2025-09-04-19.53.04.jpg
|
thumbnail: https://ik.imagekit.io/crpy/tr:w-900/2025-09-04-19.53.04.jpg
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ slug: 2025-09-18-la-democracia-se-vistio-de-gala
|
||||||
place: Congreso de Colombia
|
place: Congreso de Colombia
|
||||||
city: Bogotá
|
city: Bogotá
|
||||||
country: CO
|
country: CO
|
||||||
|
tags: [Colombia]
|
||||||
thumbnail: https://ik.imagekit.io/crpy/tr:w-900/Condecoracion-JBP-congreso-18-sep-2025_-15-scaled.jpg
|
thumbnail: https://ik.imagekit.io/crpy/tr:w-900/Condecoracion-JBP-congreso-18-sep-2025_-15-scaled.jpg
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ date: 2026-02-13
|
||||||
slug: 2026-02-13-congreso-internacional-de-rabinos-en-puerto-rico
|
slug: 2026-02-13-congreso-internacional-de-rabinos-en-puerto-rico
|
||||||
city: San Juan
|
city: San Juan
|
||||||
country: PR
|
country: PR
|
||||||
|
tags: [Puerto Rico]
|
||||||
thumbnail: ' https://ik.imagekit.io/crpy/tr:w-900/Viernes-3.webp'
|
thumbnail: ' https://ik.imagekit.io/crpy/tr:w-900/Viernes-3.webp'
|
||||||
gallery: [
|
gallery: [
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ date: 2026-02-15
|
||||||
slug: 2026-02-15-apertura-oficial-del-iii-congreso-internacional-rabinos-en-puerto-rico
|
slug: 2026-02-15-apertura-oficial-del-iii-congreso-internacional-rabinos-en-puerto-rico
|
||||||
city: San Juan
|
city: San Juan
|
||||||
country: PR
|
country: PR
|
||||||
|
tags: [Puerto Rico]
|
||||||
thumbnail: https://ik.imagekit.io/crpy/tr:w-900/2026_02_15_congreso8.webp
|
thumbnail: https://ik.imagekit.io/crpy/tr:w-900/2026_02_15_congreso8.webp
|
||||||
gallery: [
|
gallery: [
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -182,6 +182,8 @@
|
||||||
"news.text2": "This section brings together the main events, awards, and undertakings of the Kingdom of Peace and Justice Center and its founder.",
|
"news.text2": "This section brings together the main events, awards, and undertakings of the Kingdom of Peace and Justice Center and its founder.",
|
||||||
"news.text3": "This page brings together the main events, awards, and undertakings of the Kingdom of Peace and Justice Center and its founder.",
|
"news.text3": "This page brings together the main events, awards, and undertakings of the Kingdom of Peace and Justice Center and its founder.",
|
||||||
"news.buttonLable": "See More News",
|
"news.buttonLable": "See More News",
|
||||||
|
"news.seemore": "See More",
|
||||||
|
"news.all": "All",
|
||||||
|
|
||||||
|
|
||||||
"participate.title": "Participate | Collaborate",
|
"participate.title": "Participate | Collaborate",
|
||||||
|
|
|
||||||
|
|
@ -188,6 +188,8 @@
|
||||||
"news.text2": "Esta sección reúne las principales actividades, reconocimientos y acciones del Centro del Reino de Paz y Justicia y de su fundador.",
|
"news.text2": "Esta sección reúne las principales actividades, reconocimientos y acciones del Centro del Reino de Paz y Justicia y de su fundador.",
|
||||||
"news.text3": "Esta página reúne las principales actividades, reconocimientos y acciones del Centro del Reino de Paz y Justicia y de su fundador.",
|
"news.text3": "Esta página reúne las principales actividades, reconocimientos y acciones del Centro del Reino de Paz y Justicia y de su fundador.",
|
||||||
"news.buttonLable": "Ver Más Noticias",
|
"news.buttonLable": "Ver Más Noticias",
|
||||||
|
"news.seemore": "Ver Más",
|
||||||
|
"news.all": "Todas",
|
||||||
|
|
||||||
"participate.title": "Participa | Colabora",
|
"participate.title": "Participa | Colabora",
|
||||||
"participate.text": "Sumarse es asumir un compromiso con propósito",
|
"participate.text": "Sumarse es asumir un compromiso con propósito",
|
||||||
|
|
@ -206,6 +208,4 @@
|
||||||
"footer.form.mesagge": "Escriba su mensaje",
|
"footer.form.mesagge": "Escriba su mensaje",
|
||||||
"footer.form.button": "Enviar",
|
"footer.form.button": "Enviar",
|
||||||
"footer.reserved": "©2026. Todos los Derechos Reservados. Centro del Reino de Paz y Justicia"
|
"footer.reserved": "©2026. Todos los Derechos Reservados. Centro del Reino de Paz y Justicia"
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -35,12 +35,16 @@ const routeTranslations = {
|
||||||
|
|
||||||
const baseSlug = routeTranslations.news[locale] || routeTranslations.news.en;
|
const baseSlug = routeTranslations.news[locale] || routeTranslations.news.en;
|
||||||
|
|
||||||
|
const rawContent = post.body || "";
|
||||||
|
const plainText = rawContent.replace(/^#.*$/gm, '').replace(/^###.*$/gm, '').trim();
|
||||||
|
const words = plainText.split(/\s+/).slice(0, 35);
|
||||||
|
const excerpt = words.join(' ') + (words.length === 35 ? '...' : '');
|
||||||
|
|
||||||
---
|
---
|
||||||
</style>
|
|
||||||
|
|
||||||
<MainLayout
|
<MainLayout
|
||||||
title={post.data.title}
|
title={post.data.title}
|
||||||
description={`${post.data.title} - ${post.data.city ?? ""} ${post.data.country ?? ""}`}
|
description={excerpt}
|
||||||
image={post.data.thumbnail}
|
image={post.data.thumbnail}
|
||||||
url={new URL(`/${locale}/${"news"}/${post.id}`, Astro.site)}
|
url={new URL(`/${locale}/${"news"}/${post.id}`, Astro.site)}
|
||||||
>
|
>
|
||||||
|
|
@ -48,27 +52,44 @@ const baseSlug = routeTranslations.news[locale] || routeTranslations.news.en;
|
||||||
<Header />
|
<Header />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<TitleSection title={post.data.title} />
|
<a href={`/${locale}/news/${post.id}`} class="block">
|
||||||
|
<TitleSection title={post.data.title} />
|
||||||
|
</a>
|
||||||
|
|
||||||
<div class="container mx-auto">
|
<div class="container mx-auto">
|
||||||
{post.data.gallery?.length ? ( <CarouselSection images={post.data.gallery} />) : post.data.thumbnail ? (<Image src={post.data.thumbnail} alt="" /> ) : null}
|
<a href={`/${locale}/news/${post.id}`} class="block">
|
||||||
<div class="grid md:grid-cols-10">
|
{post.data.gallery?.length ? ( <CarouselSection images={post.data.gallery} />) : post.data.thumbnail ? (<Image src={post.data.thumbnail} alt={post.data.title} class="hover:opacity-90 transition-opacity" /> ) : null}
|
||||||
<div class="md:col-span-7 content bg-white p-8 md:p-20 prose-p:mb-4 text-[#003421] text-justify">
|
</a>
|
||||||
<Content />
|
|
||||||
</div>
|
|
||||||
<div class="md:col-span-3 bg-tertiary md:sticky top-0 h-fit">
|
|
||||||
{ post.data.youtube && (
|
|
||||||
<YouTube id={post.data.youtube} />
|
|
||||||
|
|
||||||
)}
|
{post.data.tags && post.data.tags.length > 0 && (
|
||||||
|
<div class="container mx-auto lg:max-w-4xl px-4 mb-6">
|
||||||
|
<div class="flex flex-wrap gap-2">
|
||||||
|
{post.data.tags.map((tag: string) => (
|
||||||
|
<span class="px-2 py-1 text-xs font-bold font-primary text-[#003421] rounded-sm relative overflow-hidden" style="background: repeating-conic-gradient(#003421 0% 25%, #EBE5D0 0% 50%) 50% / 8px 8px;">
|
||||||
|
<span class="block px-1">{tag}</span>
|
||||||
|
</span>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
{post.data.gallery && (
|
<div class="grid md:grid-cols-10">
|
||||||
post.data.gallery.map(galleryImage => (
|
<div class="md:col-span-7 content bg-white p-8 md:p-20 prose-p:mb-4 text-[#003421] text-justify">
|
||||||
<Image src={galleryImage.image} alt={galleryImage.text} />
|
<!-- <p class="text-lg font-semibold text-tertiary mb-8 pb-6 border-b border-tertiary/20 italic">
|
||||||
))
|
{excerpt}
|
||||||
)}
|
</p> -->
|
||||||
|
<Content />
|
||||||
|
</div>
|
||||||
|
<div class="md:col-span-3 bg-tertiary md:sticky top-0 h-fit">
|
||||||
|
{ post.data.youtube && (
|
||||||
|
<YouTube id={post.data.youtube} />
|
||||||
|
)}
|
||||||
|
|
||||||
</div>
|
{post.data.gallery && (
|
||||||
|
post.data.gallery.map(galleryImage => (
|
||||||
|
<Image src={galleryImage.image} alt={galleryImage.text} />
|
||||||
|
))
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</MainLayout>
|
</MainLayout>
|
||||||
|
|
|
||||||
|
|
@ -1,20 +1,32 @@
|
||||||
---
|
---
|
||||||
import MainLayout from "@/layouts/MainLayout.astro"
|
import MainLayout from "@/layouts/MainLayout.astro"
|
||||||
import NewsSection from "@/components/section/NewsSection.astro"
|
|
||||||
import Header from "@/components/Header.astro"
|
import Header from "@/components/Header.astro"
|
||||||
import NewsCard from "@/components/cards/NewsCard.astro";
|
import NewsList from "@/components/cards/NewsList.astro";
|
||||||
import { getCollection, getEntry } from "astro:content";
|
import { getCollection, getEntry } from "astro:content";
|
||||||
import FooterSection from "@/components/section/FooterSection.astro";
|
import FooterSection from "@/components/section/FooterSection.astro";
|
||||||
import NewsList from "@/components/cards/NewsList.astro";
|
|
||||||
|
|
||||||
|
|
||||||
import { createTranslator, t } from '@/i18n';
|
import { createTranslator } from '@/i18n';
|
||||||
const tl = createTranslator(Astro.currentLocale);
|
const tl = createTranslator(Astro.currentLocale);
|
||||||
|
|
||||||
const newsItems = await getCollection("news", (post)=>{
|
const newsItems = await getCollection("news", (post)=>{
|
||||||
const currentLocale = Astro.currentLocale;
|
const currentLocale = Astro.currentLocale;
|
||||||
return post.data.locale == currentLocale
|
return post.data.locale == currentLocale
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const sortedPosts = [...newsItems]
|
||||||
|
.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 = [...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();
|
||||||
---
|
---
|
||||||
|
|
||||||
<MainLayout >
|
<MainLayout >
|
||||||
|
|
@ -25,27 +37,95 @@ const newsItems = await getCollection("news", (post)=>{
|
||||||
<div class="flex flex-col lg:w-1/2 items-center mx-auto py-8">
|
<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("news.title")}</h1>
|
<h1 class="text-white text-2xl uppercase font-bold text-center mb-4 font-primary md:mt-20 mt-10">{tl("news.title")}</h1>
|
||||||
<h2 class="text-white text-3xl lg:text-5xl font-bold text-center font-secondary mb-4">{tl("news.text")}</h2>
|
<h2 class="text-white text-3xl lg:text-5xl font-bold text-center font-secondary mb-4">{tl("news.text")}</h2>
|
||||||
<!-- <p class="text-white text-xl text-center">{tl("news.text3")}</p> -->
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{allTags.length > 0 && (
|
||||||
<div class="flex flex-col md:gap-8 gap-2 lg:max-w-4xl mx-auto bg-white p-8">
|
<div class="container mx-auto mb-8">
|
||||||
{
|
<div class="flex flex-wrap gap-2 justify-center">
|
||||||
[...newsItems]
|
<button class="filter-btn px-4 py-2 font-primary text-sm cursor-pointer transition-colors" data-tag="all">
|
||||||
.sort((a, b) => {
|
{tl("news.all")}
|
||||||
const dateDiff =
|
</button>
|
||||||
new Date(b.data.date).getTime() - new Date(a.data.date).getTime()
|
{allTags.map((tag) => (
|
||||||
|
<button class="filter-btn px-4 py-2 font-primary text-sm cursor-pointer transition-colors" data-tag={tag!}>
|
||||||
if (dateDiff !== 0) return dateDiff
|
{tag}
|
||||||
|
</button>
|
||||||
return (a.data.order ?? 0) - (b.data.order ?? 0)
|
))}
|
||||||
})
|
</div>
|
||||||
.map((item) => (
|
|
||||||
<NewsList data={item} />
|
|
||||||
))
|
|
||||||
}
|
|
||||||
</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">
|
||||||
|
{
|
||||||
|
sortedPosts.map((item) => (
|
||||||
|
<div class="news-item" data-tags={JSON.stringify(item.data.tags || [])}>
|
||||||
|
<NewsList data={item} content={{ body: item.body }} />
|
||||||
|
</div>
|
||||||
|
))
|
||||||
|
}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<FooterSection />
|
<FooterSection />
|
||||||
|
|
||||||
</MainLayout>
|
</MainLayout>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
const activeClasses = "bg-[#003421] text-[#EBE5D0]";
|
||||||
|
const inactiveClasses = "bg-[#003421]/20 text-[#EBE5D0] hover:bg-[#003421]/30";
|
||||||
|
|
||||||
|
function activateTag(tag: string | null) {
|
||||||
|
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(" "));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
document.querySelectorAll('.news-item').forEach(item => {
|
||||||
|
const itemTags = JSON.parse(item.getAttribute('data-tags') || '[]');
|
||||||
|
if (tag === 'all' || tag === null || itemTags.includes(tag)) {
|
||||||
|
(item as HTMLElement).style.display = 'block';
|
||||||
|
} else {
|
||||||
|
(item as HTMLElement).style.display = 'none';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
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());
|
||||||
|
}
|
||||||
|
|
||||||
|
document.querySelectorAll('.filter-btn').forEach(btn => {
|
||||||
|
btn.classList.add(...inactiveClasses.split(" "));
|
||||||
|
});
|
||||||
|
|
||||||
|
const urlParams = new URLSearchParams(window.location.search);
|
||||||
|
const initialTag = urlParams.get('tag');
|
||||||
|
if (initialTag) {
|
||||||
|
const matchingBtn = document.querySelector(`.filter-btn[data-tag="${initialTag}"]`);
|
||||||
|
if (matchingBtn) {
|
||||||
|
matchingBtn.classList.remove(...inactiveClasses.split(" "));
|
||||||
|
matchingBtn.classList.add(...activeClasses.split(" "));
|
||||||
|
}
|
||||||
|
activateTag(initialTag);
|
||||||
|
} else {
|
||||||
|
document.querySelector('.filter-btn[data-tag="all"]')?.classList.add(...activeClasses.split(" "));
|
||||||
|
document.querySelector('.filter-btn[data-tag="all"]')?.classList.remove(...inactiveClasses.split(" "));
|
||||||
|
}
|
||||||
|
|
||||||
|
document.querySelectorAll('.filter-btn').forEach(btn => {
|
||||||
|
btn.addEventListener('click', () => {
|
||||||
|
const tag = btn.getAttribute('data-tag');
|
||||||
|
activateTag(tag);
|
||||||
|
updateUrl(tag);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
File diff suppressed because one or more lines are too long
|
|
@ -1 +1 @@
|
||||||
{"version":{"fullVersion":"2.2.3","major":"2","minor":"2","patch":"3"},"meta":{"flags":["experimentalData"]},"collections":[{"name":"news","label":"News","path":"src/content/news","format":"md","fields":[{"type":"string","name":"locale","label":"Language","options":[{"label":"Español","value":"es"},{"label":"English","value":"en"}],"namespace":["news","locale"],"searchable":true,"uid":false},{"type":"string","name":"title","label":"Title","isTitle":true,"required":true,"namespace":["news","title"],"searchable":true,"uid":false},{"type":"datetime","name":"date","label":"Date","required":true,"namespace":["news","date"],"searchable":true,"uid":false},{"type":"string","name":"slug","label":"Slug","namespace":["news","slug"],"searchable":true,"uid":false},{"type":"string","name":"place","label":"Place","namespace":["news","place"],"searchable":true,"uid":false},{"type":"string","name":"thumbnail","label":"Thumbnail URL","namespace":["news","thumbnail"],"searchable":true,"uid":false},{"type":"string","name":"youtube","label":"YouTube ID","namespace":["news","youtube"],"searchable":true,"uid":false},{"type":"boolean","name":"draft","label":"Draft","namespace":["news","draft"],"searchable":true,"uid":false},{"type":"rich-text","name":"body","label":"Content","isBody":true,"namespace":["news","body"],"searchable":true,"parser":{"type":"markdown"},"uid":false}],"namespace":["news"]},{"name":"documentaries","label":"Documentaries","path":"src/content/documentaries","format":"md","fields":[{"type":"string","name":"locale","label":"Language","options":[{"label":"Español","value":"es"}],"namespace":["documentaries","locale"],"searchable":true,"uid":false},{"type":"string","name":"title","label":"Title","isTitle":true,"required":true,"namespace":["documentaries","title"],"searchable":true,"uid":false},{"type":"string","name":"video_yt","label":"YouTube ID","namespace":["documentaries","video_yt"],"searchable":true,"uid":false},{"type":"datetime","name":"date","label":"Date","required":true,"namespace":["documentaries","date"],"searchable":true,"uid":false}],"namespace":["documentaries"]}],"config":{"media":{"tina":{"publicFolder":"public","mediaRoot":"public/images"}}}}
|
{"version":{"fullVersion":"2.2.3","major":"2","minor":"2","patch":"3"},"meta":{"flags":["experimentalData"]},"collections":[{"name":"news","label":"News","path":"src/content/news","format":"md","fields":[{"type":"string","name":"locale","label":"Language","options":[{"label":"Español","value":"es"},{"label":"English","value":"en"}],"namespace":["news","locale"],"searchable":true,"uid":false},{"type":"string","name":"title","label":"Title","isTitle":true,"required":true,"namespace":["news","title"],"searchable":true,"uid":false},{"type":"datetime","name":"date","label":"Date","required":true,"namespace":["news","date"],"searchable":true,"uid":false},{"type":"string","name":"slug","label":"Slug","namespace":["news","slug"],"searchable":true,"uid":false},{"type":"string","name":"place","label":"Place","namespace":["news","place"],"searchable":true,"uid":false},{"type":"string","name":"thumbnail","label":"Thumbnail URL","namespace":["news","thumbnail"],"searchable":true,"uid":false},{"type":"string","name":"youtube","label":"YouTube ID","namespace":["news","youtube"],"searchable":true,"uid":false},{"type":"string","name":"tags","label":"Tags (comma separated)","namespace":["news","tags"],"searchable":true,"uid":false},{"type":"boolean","name":"draft","label":"Draft","namespace":["news","draft"],"searchable":true,"uid":false},{"type":"rich-text","name":"body","label":"Content","isBody":true,"namespace":["news","body"],"searchable":true,"parser":{"type":"markdown"},"uid":false}],"namespace":["news"]},{"name":"documentaries","label":"Documentaries","path":"src/content/documentaries","format":"md","fields":[{"type":"string","name":"locale","label":"Language","options":[{"label":"Español","value":"es"}],"namespace":["documentaries","locale"],"searchable":true,"uid":false},{"type":"string","name":"title","label":"Title","isTitle":true,"required":true,"namespace":["documentaries","title"],"searchable":true,"uid":false},{"type":"string","name":"video_yt","label":"YouTube ID","namespace":["documentaries","video_yt"],"searchable":true,"uid":false},{"type":"datetime","name":"date","label":"Date","required":true,"namespace":["documentaries","date"],"searchable":true,"uid":false}],"namespace":["documentaries"]}],"config":{"media":{"tina":{"publicFolder":"public","mediaRoot":"public/images"}}}}
|
||||||
|
|
@ -65,6 +65,11 @@ var config_default = defineConfig({
|
||||||
name: "youtube",
|
name: "youtube",
|
||||||
label: "YouTube ID"
|
label: "YouTube ID"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
type: "string",
|
||||||
|
name: "tags",
|
||||||
|
label: "Tags (comma separated)"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
type: "boolean",
|
type: "boolean",
|
||||||
name: "draft",
|
name: "draft",
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ fragment NewsParts on News {
|
||||||
place
|
place
|
||||||
thumbnail
|
thumbnail
|
||||||
youtube
|
youtube
|
||||||
|
tags
|
||||||
draft
|
draft
|
||||||
body
|
body
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -98,6 +98,7 @@ type News implements Node & Document {
|
||||||
place: String
|
place: String
|
||||||
thumbnail: String
|
thumbnail: String
|
||||||
youtube: String
|
youtube: String
|
||||||
|
tags: String
|
||||||
draft: Boolean
|
draft: Boolean
|
||||||
body: JSON
|
body: JSON
|
||||||
id: ID!
|
id: ID!
|
||||||
|
|
@ -139,6 +140,7 @@ input NewsFilter {
|
||||||
place: StringFilter
|
place: StringFilter
|
||||||
thumbnail: StringFilter
|
thumbnail: StringFilter
|
||||||
youtube: StringFilter
|
youtube: StringFilter
|
||||||
|
tags: StringFilter
|
||||||
draft: BooleanFilter
|
draft: BooleanFilter
|
||||||
body: RichTextFilter
|
body: RichTextFilter
|
||||||
}
|
}
|
||||||
|
|
@ -213,6 +215,7 @@ input NewsMutation {
|
||||||
place: String
|
place: String
|
||||||
thumbnail: String
|
thumbnail: String
|
||||||
youtube: String
|
youtube: String
|
||||||
|
tags: String
|
||||||
draft: Boolean
|
draft: Boolean
|
||||||
body: JSON
|
body: JSON
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -192,6 +192,7 @@ export type News = Node & Document & {
|
||||||
place?: Maybe<Scalars['String']['output']>;
|
place?: Maybe<Scalars['String']['output']>;
|
||||||
thumbnail?: Maybe<Scalars['String']['output']>;
|
thumbnail?: Maybe<Scalars['String']['output']>;
|
||||||
youtube?: Maybe<Scalars['String']['output']>;
|
youtube?: Maybe<Scalars['String']['output']>;
|
||||||
|
tags?: Maybe<Scalars['String']['output']>;
|
||||||
draft?: Maybe<Scalars['Boolean']['output']>;
|
draft?: Maybe<Scalars['Boolean']['output']>;
|
||||||
body?: Maybe<Scalars['JSON']['output']>;
|
body?: Maybe<Scalars['JSON']['output']>;
|
||||||
id: Scalars['ID']['output'];
|
id: Scalars['ID']['output'];
|
||||||
|
|
@ -233,6 +234,7 @@ export type NewsFilter = {
|
||||||
place?: InputMaybe<StringFilter>;
|
place?: InputMaybe<StringFilter>;
|
||||||
thumbnail?: InputMaybe<StringFilter>;
|
thumbnail?: InputMaybe<StringFilter>;
|
||||||
youtube?: InputMaybe<StringFilter>;
|
youtube?: InputMaybe<StringFilter>;
|
||||||
|
tags?: InputMaybe<StringFilter>;
|
||||||
draft?: InputMaybe<BooleanFilter>;
|
draft?: InputMaybe<BooleanFilter>;
|
||||||
body?: InputMaybe<RichTextFilter>;
|
body?: InputMaybe<RichTextFilter>;
|
||||||
};
|
};
|
||||||
|
|
@ -370,6 +372,7 @@ export type NewsMutation = {
|
||||||
place?: InputMaybe<Scalars['String']['input']>;
|
place?: InputMaybe<Scalars['String']['input']>;
|
||||||
thumbnail?: InputMaybe<Scalars['String']['input']>;
|
thumbnail?: InputMaybe<Scalars['String']['input']>;
|
||||||
youtube?: InputMaybe<Scalars['String']['input']>;
|
youtube?: InputMaybe<Scalars['String']['input']>;
|
||||||
|
tags?: InputMaybe<Scalars['String']['input']>;
|
||||||
draft?: InputMaybe<Scalars['Boolean']['input']>;
|
draft?: InputMaybe<Scalars['Boolean']['input']>;
|
||||||
body?: InputMaybe<Scalars['JSON']['input']>;
|
body?: InputMaybe<Scalars['JSON']['input']>;
|
||||||
};
|
};
|
||||||
|
|
@ -381,7 +384,7 @@ export type DocumentariesMutation = {
|
||||||
date?: InputMaybe<Scalars['String']['input']>;
|
date?: InputMaybe<Scalars['String']['input']>;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type NewsPartsFragment = { __typename: 'News', locale?: string | null, title: string, date: string, slug?: string | null, place?: string | null, thumbnail?: string | null, youtube?: string | null, draft?: boolean | null, body?: any | null };
|
export type NewsPartsFragment = { __typename: 'News', locale?: string | null, title: string, date: string, slug?: string | null, place?: string | null, thumbnail?: string | null, youtube?: string | null, tags?: string | null, draft?: boolean | null, body?: any | null };
|
||||||
|
|
||||||
export type DocumentariesPartsFragment = { __typename: 'Documentaries', locale?: string | null, title: string, video_yt?: string | null, date: string };
|
export type DocumentariesPartsFragment = { __typename: 'Documentaries', locale?: string | null, title: string, video_yt?: string | null, date: string };
|
||||||
|
|
||||||
|
|
@ -390,7 +393,7 @@ export type NewsQueryVariables = Exact<{
|
||||||
}>;
|
}>;
|
||||||
|
|
||||||
|
|
||||||
export type NewsQuery = { __typename?: 'Query', news: { __typename: 'News', id: string, locale?: string | null, title: string, date: string, slug?: string | null, place?: string | null, thumbnail?: string | null, youtube?: string | null, draft?: boolean | null, body?: any | null, _sys: { __typename?: 'SystemInfo', filename: string, basename: string, hasReferences?: boolean | null, breadcrumbs: Array<string>, path: string, relativePath: string, extension: string } } };
|
export type NewsQuery = { __typename?: 'Query', news: { __typename: 'News', id: string, locale?: string | null, title: string, date: string, slug?: string | null, place?: string | null, thumbnail?: string | null, youtube?: string | null, tags?: string | null, draft?: boolean | null, body?: any | null, _sys: { __typename?: 'SystemInfo', filename: string, basename: string, hasReferences?: boolean | null, breadcrumbs: Array<string>, path: string, relativePath: string, extension: string } } };
|
||||||
|
|
||||||
export type NewsConnectionQueryVariables = Exact<{
|
export type NewsConnectionQueryVariables = Exact<{
|
||||||
before?: InputMaybe<Scalars['String']['input']>;
|
before?: InputMaybe<Scalars['String']['input']>;
|
||||||
|
|
@ -402,7 +405,7 @@ export type NewsConnectionQueryVariables = Exact<{
|
||||||
}>;
|
}>;
|
||||||
|
|
||||||
|
|
||||||
export type NewsConnectionQuery = { __typename?: 'Query', newsConnection: { __typename?: 'NewsConnection', totalCount: number, pageInfo: { __typename?: 'PageInfo', hasPreviousPage: boolean, hasNextPage: boolean, startCursor: string, endCursor: string }, edges?: Array<{ __typename?: 'NewsConnectionEdges', cursor: string, node?: { __typename: 'News', id: string, locale?: string | null, title: string, date: string, slug?: string | null, place?: string | null, thumbnail?: string | null, youtube?: string | null, draft?: boolean | null, body?: any | null, _sys: { __typename?: 'SystemInfo', filename: string, basename: string, hasReferences?: boolean | null, breadcrumbs: Array<string>, path: string, relativePath: string, extension: string } } | null } | null> | null } };
|
export type NewsConnectionQuery = { __typename?: 'Query', newsConnection: { __typename?: 'NewsConnection', totalCount: number, pageInfo: { __typename?: 'PageInfo', hasPreviousPage: boolean, hasNextPage: boolean, startCursor: string, endCursor: string }, edges?: Array<{ __typename?: 'NewsConnectionEdges', cursor: string, node?: { __typename: 'News', id: string, locale?: string | null, title: string, date: string, slug?: string | null, place?: string | null, thumbnail?: string | null, youtube?: string | null, tags?: string | null, draft?: boolean | null, body?: any | null, _sys: { __typename?: 'SystemInfo', filename: string, basename: string, hasReferences?: boolean | null, breadcrumbs: Array<string>, path: string, relativePath: string, extension: string } } | null } | null> | null } };
|
||||||
|
|
||||||
export type DocumentariesQueryVariables = Exact<{
|
export type DocumentariesQueryVariables = Exact<{
|
||||||
relativePath: Scalars['String']['input'];
|
relativePath: Scalars['String']['input'];
|
||||||
|
|
@ -433,6 +436,7 @@ export const NewsPartsFragmentDoc = gql`
|
||||||
place
|
place
|
||||||
thumbnail
|
thumbnail
|
||||||
youtube
|
youtube
|
||||||
|
tags
|
||||||
draft
|
draft
|
||||||
body
|
body
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -66,6 +66,11 @@ export default defineConfig({
|
||||||
name: "youtube",
|
name: "youtube",
|
||||||
label: "YouTube ID",
|
label: "YouTube ID",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
type: "string",
|
||||||
|
name: "tags",
|
||||||
|
label: "Tags (comma separated)",
|
||||||
|
},
|
||||||
{
|
{
|
||||||
type: "boolean",
|
type: "boolean",
|
||||||
name: "draft",
|
name: "draft",
|
||||||
|
|
|
||||||
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue