diff --git a/scripts/generate-news-indexes/constants.ts b/scripts/generate-news-indexes/constants.ts index 990e914e0a1..113a62575ac 100644 --- a/scripts/generate-news-indexes/constants.ts +++ b/scripts/generate-news-indexes/constants.ts @@ -28,7 +28,7 @@ export const LANGUAGES: Record = { sort: 'Sort:', newest: 'Newest First', oldest: 'Oldest First', titleSort: 'Title' }, noResults: 'No articles matched the filters', - i18n: { noArticles: 'No articles available', search: 'Search:', searchPlaceholder: 'Search articles...', loadMore: 'Load more articles', showing: 'Showing {shown} of {total} articles' }, + i18n: { noArticles: 'No articles available', search: 'Search:', searchPlaceholder: 'Search articles...', loadMore: 'Load more articles', showing: 'Showing {shown} of {total} articles', totalArticles: 'Total articles: {total}' }, aiNewsroomTitle: 'AI-Disrupted News Generation', aiNewsroomText: 'Riksdagsmonitor\'s agentic news generation pipeline is the world\'s first fully AI-driven political intelligence newsroom for parliamentary monitoring. Powered by Claude Opus via GitHub Copilot Coding Agent, our 10 specialized workflows (9 scheduled + 1 on-demand) autonomously produce deep political analysis \u2014 not shallow summaries, but structured intelligence products with source verification, multi-party balance, and GDPR-compliant OSINT methodology.', disclaimer: 'Ongoing improvements \u2014 please', @@ -48,7 +48,7 @@ export const LANGUAGES: Record = { sort: 'Sortera:', newest: 'Nyast först', oldest: 'Äldst först', titleSort: 'Titel' }, noResults: 'Inga artiklar matchade filtren', - i18n: { noArticles: 'Inga artiklar tillgängliga', search: 'Sök:', searchPlaceholder: 'Sök artiklar...', loadMore: 'Ladda fler artiklar', showing: 'Visar {shown} av {total} artiklar' }, + i18n: { noArticles: 'Inga artiklar tillgängliga', search: 'Sök:', searchPlaceholder: 'Sök artiklar...', loadMore: 'Ladda fler artiklar', showing: 'Visar {shown} av {total} artiklar', totalArticles: 'Totalt antal artiklar: {total}' }, aiNewsroomTitle: 'AI-styrd nyhetsproduktion', aiNewsroomText: 'Riksdagsmonitors agentbaserade nyhetsproduktionskedja \u00e4r v\u00e4rldens f\u00f6rsta helt AI-drivna politiska underr\u00e4ttelseredaktion f\u00f6r parlaments\u00f6vervakning. Med kraft fr\u00e5n Claude Opus via GitHub Copilot Coding Agent producerar v\u00e5ra 10 specialiserade arbetsfl\u00f6den (9 schemalagda + 1 vid behov) sj\u00e4lvst\u00e4ndigt djupg\u00e5ende politiska analyser \u2014 inte ytliga sammanfattningar, utan strukturerade underr\u00e4ttelseprodukter med k\u00e4llverifiering, flerpartibalans och GDPR-kompatibel OSINT-metodik.', disclaimer: 'P\u00e5g\u00e5ende f\u00f6rb\u00e4ttringar \u2014 v\u00e4nligen', @@ -68,7 +68,7 @@ export const LANGUAGES: Record = { sort: 'Sorter:', newest: 'Nyeste først', oldest: 'Ældste først', titleSort: 'Titel' }, noResults: 'Ingen artikler matchede filtrene', - i18n: { noArticles: 'Ingen artikler tilgængelige', search: 'Søg:', searchPlaceholder: 'Søg artikler...', loadMore: 'Indlæs flere artikler', showing: 'Viser {shown} af {total} artikler' }, + i18n: { noArticles: 'Ingen artikler tilgængelige', search: 'Søg:', searchPlaceholder: 'Søg artikler...', loadMore: 'Indlæs flere artikler', showing: 'Viser {shown} af {total} artikler', totalArticles: 'Samlet antal artikler: {total}' }, aiNewsroomTitle: 'AI-disrupteret nyhedsgenerering', aiNewsroomText: 'Riksdagsmonitors agentbaserede nyhedsgenereringspipeline er verdens f\u00f8rste fuldt AI-drevne politiske efterretningsnyhedsredaktion til parlamentarisk overv\u00e5gning. Drevet af Claude Opus via GitHub Copilot Coding Agent producerer vores 10 specialiserede arbejdsgange (9 planlagte + 1 on-demand) autonomt dybdeg\u00e5ende politiske analyser \u2014 ikke overfladiske resum\u00e9er, men strukturerede efterretningsprodukter med kildeverificering, flerpartisk balance og GDPR-kompatibel OSINT-metodologi.', disclaimer: 'L\u00f8bende forbedringer \u2014 venligst', @@ -88,7 +88,7 @@ export const LANGUAGES: Record = { sort: 'Sorter:', newest: 'Nyeste først', oldest: 'Eldste først', titleSort: 'Tittel' }, noResults: 'Ingen artikler matchet filtrene', - i18n: { noArticles: 'Ingen artikler tilgjengelige', search: 'Søk:', searchPlaceholder: 'Søk artikler...', loadMore: 'Last flere artikler', showing: 'Viser {shown} av {total} artikler' }, + i18n: { noArticles: 'Ingen artikler tilgjengelige', search: 'Søk:', searchPlaceholder: 'Søk artikler...', loadMore: 'Last flere artikler', showing: 'Viser {shown} av {total} artikler', totalArticles: 'Totalt antall artikler: {total}' }, aiNewsroomTitle: 'AI-drevet nyhetsproduksjon', aiNewsroomText: 'Riksdagsmonitors agentbaserte nyhetsproduksjonslinje er verdens f\u00f8rste fullt AI-drevne politiske etterretningsredaksjon for parlamentarisk overv\u00e5king. Drevet av Claude Opus via GitHub Copilot Coding Agent produserer v\u00e5re 10 spesialiserte arbeidsflyter (9 planlagte + 1 ved behov) autonomt dyptg\u00e5ende politiske analyser \u2014 ikke overfladiske sammendrag, men strukturerte etterretningsprodukter med kildeverifisering, flerpartisk balanse og GDPR-kompatibel OSINT-metodikk.', disclaimer: 'P\u00e5g\u00e5ende forbedringer \u2014 vennligst', @@ -108,7 +108,7 @@ export const LANGUAGES: Record = { sort: 'Järjestä:', newest: 'Uusimmat ensin', oldest: 'Vanhimmat ensin', titleSort: 'Otsikko' }, noResults: 'Mikään artikkeli ei vastannut suodattimia', - i18n: { noArticles: 'Ei artikkeleita saatavilla', search: 'Haku:', searchPlaceholder: 'Hae artikkeleita...', loadMore: 'Lataa lisää artikkeleita', showing: 'Näytetään {shown} / {total} artikkelia' }, + i18n: { noArticles: 'Ei artikkeleita saatavilla', search: 'Haku:', searchPlaceholder: 'Hae artikkeleita...', loadMore: 'Lataa lisää artikkeleita', showing: 'Näytetään {shown} / {total} artikkelia', totalArticles: 'Artikkeleita yhteensä: {total}' }, aiNewsroomTitle: 'AI-ohjattu uutistuotanto', aiNewsroomText: 'Riksdagsmonitorin agenttipohjainen uutistuotantoputki on maailman ensimm\u00e4inen t\u00e4ysin teko\u00e4lyll\u00e4 toimiva poliittisen tiedustelun uutistoimitus parlamenttiseurantaa varten. Claude Opus -mallin ja GitHub Copilot Coding Agent -agentin voimin 10 erikoistunutta ty\u00f6nkulkua (9 ajastettua + 1 tarvittaessa k\u00e4ynnistett\u00e4v\u00e4) tuottaa itsen\u00e4isesti syv\u00e4llist\u00e4 poliittista analyysi\u00e4 \u2014 ei pinnallisia yhteenvetoja, vaan rakenteistettuja tiedustelutuotteita, joissa on l\u00e4hteiden varmistus, monipuolueinen tasapaino ja GDPR-yhteensopiva OSINT-menetelm\u00e4.', disclaimer: 'Jatkuvia parannuksia \u2014 ole hyv\u00e4 ja', @@ -128,7 +128,7 @@ export const LANGUAGES: Record = { sort: 'Sortieren:', newest: 'Neueste zuerst', oldest: 'Älteste zuerst', titleSort: 'Titel' }, noResults: 'Keine Artikel entsprachen den Filtern', - i18n: { noArticles: 'Keine Artikel verfügbar', search: 'Suche:', searchPlaceholder: 'Artikel suchen...', loadMore: 'Mehr Artikel laden', showing: 'Zeige {shown} von {total} Artikeln' }, + i18n: { noArticles: 'Keine Artikel verfügbar', search: 'Suche:', searchPlaceholder: 'Artikel suchen...', loadMore: 'Mehr Artikel laden', showing: 'Zeige {shown} von {total} Artikeln', totalArticles: 'Artikel insgesamt: {total}' }, aiNewsroomTitle: 'KI-gest\u00fctzte Nachrichtenproduktion', aiNewsroomText: 'Die agentenbasierte Nachrichtenpipeline von Riksdagsmonitor ist der weltweit erste vollst\u00e4ndig KI-gesteuerte Newsroom f\u00fcr politische Intelligence im Parlamentsmonitoring. Angetrieben von Claude Opus \u00fcber den GitHub Copilot Coding Agent erzeugen unsere 10 spezialisierten Workflows (9 geplante + 1 On-Demand) autonom tiefgehende politische Analysen \u2014 keine oberfl\u00e4chlichen Zusammenfassungen, sondern strukturierte Intelligence-Produkte mit Quellenpr\u00fcfung, multiperspektivischer Parteibalance und DSGVO-konformer OSINT-Methodik.', disclaimer: 'Laufende Verbesserungen \u2014 bitte', @@ -148,7 +148,7 @@ export const LANGUAGES: Record = { sort: 'Trier :', newest: 'Plus récent', oldest: 'Plus ancien', titleSort: 'Titre' }, noResults: 'Aucun article ne correspond aux filtres', - i18n: { noArticles: 'Aucun article disponible', search: 'Recherche :', searchPlaceholder: 'Rechercher des articles...', loadMore: 'Charger plus d\'articles', showing: 'Affichage de {shown} sur {total} articles' }, + i18n: { noArticles: 'Aucun article disponible', search: 'Recherche :', searchPlaceholder: 'Rechercher des articles...', loadMore: 'Charger plus d\'articles', showing: 'Affichage de {shown} sur {total} articles', totalArticles: 'Total des articles : {total}' }, aiNewsroomTitle: 'R\u00e9daction d\'actualit\u00e9s pilot\u00e9e par l\'IA', aiNewsroomText: 'Le pipeline de g\u00e9n\u00e9ration d\'actualit\u00e9s agentique de Riksdagsmonitor est la premi\u00e8re r\u00e9daction d\'intelligence politique enti\u00e8rement pilot\u00e9e par l\'IA d\u00e9di\u00e9e au suivi parlementaire. Propuls\u00e9s par Claude Opus via GitHub Copilot Coding Agent, nos 10 flux de travail sp\u00e9cialis\u00e9s (9 planifi\u00e9s + 1 \u00e0 la demande) produisent de mani\u00e8re autonome des analyses politiques approfondies \u2014 non pas de simples r\u00e9sum\u00e9s, mais de v\u00e9ritables produits d\'intelligence structur\u00e9s avec v\u00e9rification des sources, \u00e9quilibre multipartite et m\u00e9thodologie OSINT conforme au RGPD.', disclaimer: 'Am\u00e9liorations en cours \u2014 veuillez', @@ -168,7 +168,7 @@ export const LANGUAGES: Record = { sort: 'Ordenar:', newest: 'Más reciente', oldest: 'Más antiguo', titleSort: 'Título' }, noResults: 'Ningún artículo coincidió con los filtros', - i18n: { noArticles: 'No hay artículos disponibles', search: 'Buscar:', searchPlaceholder: 'Buscar artículos...', loadMore: 'Cargar más artículos', showing: 'Mostrando {shown} de {total} artículos' }, + i18n: { noArticles: 'No hay artículos disponibles', search: 'Buscar:', searchPlaceholder: 'Buscar artículos...', loadMore: 'Cargar más artículos', showing: 'Mostrando {shown} de {total} artículos', totalArticles: 'Total de artículos: {total}' }, aiNewsroomTitle: 'Redacci\u00f3n de noticias impulsada por IA', aiNewsroomText: 'La cadena agente de generaci\u00f3n de noticias de Riksdagsmonitor es la primera redacci\u00f3n de inteligencia pol\u00edtica del mundo totalmente impulsada por IA para el monitoreo parlamentario. Impulsada por Claude Opus a trav\u00e9s de GitHub Copilot Coding Agent, nuestras 10 canalizaciones especializadas (9 programadas y 1 bajo demanda) producen de forma aut\u00f3noma an\u00e1lisis pol\u00edticos profundos \u2014 no simples res\u00famenes, sino productos de inteligencia estructurados con verificaci\u00f3n de fuentes, equilibrio multipartidista y una metodolog\u00eda OSINT compatible con el RGPD.', disclaimer: 'Mejoras en curso \u2014 por favor', @@ -188,7 +188,7 @@ export const LANGUAGES: Record = { sort: 'Sorteren:', newest: 'Nieuwste eerst', oldest: 'Oudste eerst', titleSort: 'Titel' }, noResults: 'Geen artikelen voldeden aan de filters', - i18n: { noArticles: 'Geen artikelen beschikbaar', search: 'Zoeken:', searchPlaceholder: 'Artikelen zoeken...', loadMore: 'Meer artikelen laden', showing: 'Toon {shown} van {total} artikelen' }, + i18n: { noArticles: 'Geen artikelen beschikbaar', search: 'Zoeken:', searchPlaceholder: 'Artikelen zoeken...', loadMore: 'Meer artikelen laden', showing: 'Toon {shown} van {total} artikelen', totalArticles: 'Totaal aantal artikelen: {total}' }, aiNewsroomTitle: 'AI-gestuurde nieuwsproductie', aiNewsroomText: 'De agentische nieuwsproductiepijplijn van Riksdagsmonitor is \'s werelds eerste volledig AI-gestuurde politieke-intelligentie-nieuwsredactie voor parlementaire monitoring. Aangedreven door Claude Opus via de GitHub Copilot Coding Agent produceren onze 10 gespecialiseerde workflows (9 gepland + 1 on-demand) autonoom diepgaande politieke analyses \u2014 geen oppervlakkige samenvattingen, maar gestructureerde inlichtingenproducten met bronverificatie, meerpartijenbalans en een AVG-conforme OSINT-methodologie.', disclaimer: 'Doorlopende verbeteringen \u2014 gelieve', @@ -208,7 +208,7 @@ export const LANGUAGES: Record = { sort: 'الترتيب:', newest: 'الأحدث أولاً', oldest: 'الأقدم أولاً', titleSort: 'العنوان' }, noResults: 'لا توجد مقالات تطابق الفلاتر', - i18n: { noArticles: 'لا توجد مقالات متاحة', search: 'بحث:', searchPlaceholder: 'ابحث في المقالات...', loadMore: 'تحميل المزيد من المقالات', showing: 'عرض {shown} من {total} مقالات' }, + i18n: { noArticles: 'لا توجد مقالات متاحة', search: 'بحث:', searchPlaceholder: 'ابحث في المقالات...', loadMore: 'تحميل المزيد من المقالات', showing: 'عرض {shown} من {total} مقالات', totalArticles: 'إجمالي المقالات: {total}' }, aiNewsroomTitle: '\u0625\u0646\u062a\u0627\u062c \u0627\u0644\u0623\u062e\u0628\u0627\u0631 \u0627\u0644\u0645\u0639\u0637\u064e\u0651\u0644 \u0628\u0627\u0644\u0630\u0643\u0627\u0621 \u0627\u0644\u0627\u0635\u0637\u0646\u0627\u0639\u064a', aiNewsroomText: '\u062e\u0637 \u0625\u0646\u062a\u0627\u062c \u0627\u0644\u0623\u062e\u0628\u0627\u0631 \u0627\u0644\u0630\u0643\u064a \u0641\u064a Riksdagsmonitor \u0647\u0648 \u0623\u0648\u0644 \u063a\u0631\u0641\u0629 \u0623\u062e\u0628\u0627\u0631 \u0627\u0633\u062a\u062e\u0628\u0627\u0631\u0627\u062a \u0633\u064a\u0627\u0633\u064a\u0629 \u0641\u064a \u0627\u0644\u0639\u0627\u0644\u0645 \u062a\u0639\u0645\u0644 \u0628\u0627\u0644\u0643\u0627\u0645\u0644 \u0628\u0627\u0644\u0630\u0643\u0627\u0621 \u0627\u0644\u0627\u0635\u0637\u0646\u0627\u0639\u064a \u0644\u0645\u0631\u0627\u0642\u0628\u0629 \u0627\u0644\u0628\u0631\u0644\u0645\u0627\u0646\u0627\u062a. \u0645\u062f\u0639\u0648\u0645 \u0628\u0646\u0645\u0648\u0630\u062c Claude Opus \u0639\u0628\u0631 GitHub Copilot Coding Agent\u060c \u062a\u0642\u0648\u0645 10 \u0645\u0633\u0627\u0631\u0627\u062a \u0639\u0645\u0644 \u0645\u062a\u062e\u0635\u0635\u0629 (9 \u0645\u062c\u062f\u0648\u0644\u0629 + 1 \u062d\u0633\u0628 \u0627\u0644\u0637\u0644\u0628) \u0628\u0625\u0646\u062a\u0627\u062c \u062a\u062d\u0644\u064a\u0644\u0627\u062a \u0633\u064a\u0627\u0633\u064a\u0629 \u0645\u0639\u0645\u0651\u0642\u0629 \u0628\u0634\u0643\u0644 \u0630\u0627\u062a\u064a \u2014 \u0644\u064a\u0633\u062a \u0645\u0644\u062e\u0635\u0627\u062a \u0633\u0637\u062d\u064a\u0629\u060c \u0628\u0644 \u0645\u0646\u062a\u062c\u0627\u062a \u0627\u0633\u062a\u062e\u0628\u0627\u0631\u0627\u062a\u064a\u0629 \u0645\u0646\u0638\u0645\u0629 \u0645\u0639 \u062a\u062d\u0642\u0642 \u0645\u0646 \u0627\u0644\u0645\u0635\u0627\u062f\u0631\u060c \u0648\u062a\u0648\u0627\u0632\u0646 \u0628\u064a\u0646 \u062c\u0645\u064a\u0639 \u0627\u0644\u0623\u062d\u0632\u0627\u0628\u060c \u0648\u0645\u0646\u0647\u062c\u064a\u0629 OSINT \u0645\u062a\u0648\u0627\u0641\u0642\u0629 \u0645\u0639 \u0627\u0644\u0644\u0627\u0626\u062d\u0629 \u0627\u0644\u0639\u0627\u0645\u0629 \u0644\u062d\u0645\u0627\u064a\u0629 \u0627\u0644\u0628\u064a\u0627\u0646\u0627\u062a (GDPR).', disclaimer: '\u062a\u062d\u0633\u064a\u0646\u0627\u062a \u0645\u0633\u062a\u0645\u0631\u0629 \u2014 \u064a\u0631\u062c\u0649', @@ -228,7 +228,7 @@ export const LANGUAGES: Record = { sort: 'מיון:', newest: 'החדש ביותר', oldest: 'הישן ביותר', titleSort: 'כותרת' }, noResults: 'אין מאמרים שתואמים את הסינון', - i18n: { noArticles: 'אין מאמרים זמינים', search: 'חיפוש:', searchPlaceholder: 'חפש מאמרים...', loadMore: 'טען עוד מאמרים', showing: 'מציג {shown} מתוך {total} מאמרים' }, + i18n: { noArticles: 'אין מאמרים זמינים', search: 'חיפוש:', searchPlaceholder: 'חפש מאמרים...', loadMore: 'טען עוד מאמרים', showing: 'מציג {shown} מתוך {total} מאמרים', totalArticles: 'סך כל המאמרים: {total}' }, aiNewsroomTitle: '\u05d7\u05d3\u05e8 \u05d7\u05d3\u05e9\u05d5\u05ea \u05e4\u05d5\u05dc\u05d9\u05d8\u05d9\u05d5\u05ea \u05de\u05d5\u05e0\u05e2 \u05d1\u05d9\u05e0\u05d4 \u05de\u05dc\u05d0\u05db\u05d5\u05ea\u05d9\u05ea', aiNewsroomText: '\u05e6\u05d9\u05e0\u05d5\u05e8 \u05d9\u05e6\u05d9\u05e8\u05ea \u05d4\u05d7\u05d3\u05e9\u05d5\u05ea \u05d4\u05d0\u05d5\u05d8\u05d5\u05e0\u05d5\u05de\u05d9 \u05e9\u05dc Riksdagsmonitor \u05d4\u05d5\u05d0 \u05d7\u05d3\u05e8 \u05d4\u05d7\u05d3\u05e9\u05d5\u05ea \u05d4\u05e8\u05d0\u05e9\u05d5\u05df \u05d1\u05e2\u05d5\u05dc\u05dd \u05dc\u05e0\u05d9\u05d8\u05d5\u05e8 \u05e4\u05e8\u05dc\u05de\u05e0\u05d8\u05e8\u05d9 \u05e9\u05de\u05d5\u05e4\u05e2\u05dc \u05db\u05d5\u05dc\u05d5 \u05d1\u05d1\u05d9\u05e0\u05d4 \u05de\u05dc\u05d0\u05db\u05d5\u05ea\u05d9\u05ea. \u05d1\u05e2\u05d6\u05e8\u05ea Claude Opus \u05d3\u05e8\u05da GitHub Copilot Coding Agent, \u05e2\u05e9\u05e8\u05d4 \u05ea\u05d6\u05e8\u05d9\u05de\u05d9 \u05e2\u05d1\u05d5\u05d3\u05d4 \u05de\u05ea\u05de\u05d7\u05d9\u05dd (9 \u05de\u05ea\u05d5\u05d6\u05de\u05e0\u05d9\u05dd + 1 \u05dc\u05e4\u05d9 \u05d3\u05e8\u05d9\u05e9\u05d4) \u05de\u05d9\u05d9\u05e6\u05e8\u05d9\u05dd \u05d1\u05d0\u05d5\u05e4\u05df \u05e2\u05e6\u05de\u05d0\u05d9 \u05e0\u05d9\u05ea\u05d5\u05d7 \u05e4\u05d5\u05dc\u05d9\u05d8\u05d9 \u05e2\u05de\u05d5\u05e7 \u2014 \u05dc\u05d0 \u05ea\u05e7\u05e6\u05d9\u05e8\u05d9\u05dd \u05e9\u05d8\u05d7\u05d9\u05d9\u05dd, \u05d0\u05dc\u05d0 \u05de\u05d5\u05e6\u05e8\u05d9 \u05de\u05d5\u05d3\u05d9\u05e2\u05d9\u05df \u05de\u05d5\u05d1\u05e0\u05d9\u05dd \u05e2\u05dd \u05d0\u05d9\u05de\u05d5\u05ea \u05de\u05e7\u05d5\u05e8\u05d5\u05ea, \u05d0\u05d9\u05d6\u05d5\u05df \u05d1\u05d9\u05df \u05de\u05e4\u05dc\u05d2\u05d5\u05ea \u05d5\u05de\u05ea\u05d5\u05d3\u05d5\u05dc\u05d5\u05d2\u05d9\u05d9\u05ea OSINT \u05d4\u05ea\u05d5\u05d0\u05de\u05ea \u05dc-GDPR.', disclaimer: '\u05e9\u05d9\u05e4\u05d5\u05e8\u05d9\u05dd \u05de\u05ea\u05de\u05e9\u05db\u05d9\u05dd \u2014 \u05e0\u05d0', @@ -248,7 +248,7 @@ export const LANGUAGES: Record = { sort: '並び替え:', newest: '最新順', oldest: '古い順', titleSort: 'タイトル' }, noResults: 'フィルターに一致する記事がありません', - i18n: { noArticles: '記事がありません', search: '検索:', searchPlaceholder: '記事を検索...', loadMore: 'さらに記事を読み込む', showing: '{shown} / {total} 件の記事' }, + i18n: { noArticles: '記事がありません', search: '検索:', searchPlaceholder: '記事を検索...', loadMore: 'さらに記事を読み込む', showing: '{shown} / {total} 件の記事', totalArticles: '記事総数:{total}' }, aiNewsroomTitle: 'AI\u306b\u3088\u308b\u30cb\u30e5\u30fc\u30b9\u751f\u6210\u9769\u547d', aiNewsroomText: 'Riksdagsmonitor \u306e\u30a8\u30fc\u30b8\u30a7\u30f3\u30c8\u578b\u30cb\u30e5\u30fc\u30b9\u751f\u6210\u30d1\u30a4\u30d7\u30e9\u30a4\u30f3\u306f\u3001\u8b70\u4f1a\u30e2\u30cb\u30bf\u30ea\u30f3\u30b0\u306e\u305f\u3081\u306e\u4e16\u754c\u521d\u306e\u30d5\u30ebAI\u99c6\u52d5\u578b\u300c\u653f\u6cbb\u30a4\u30f3\u30c6\u30ea\u30b8\u30a7\u30f3\u30b9\u30fb\u30cb\u30e5\u30fc\u30b9\u30eb\u30fc\u30e0\u300d\u3067\u3059\u3002GitHub Copilot Coding Agent \u7d4c\u7531\u3067\u52d5\u4f5c\u3059\u308b Claude Opus \u3092\u4e2d\u6838\u306b\u300110\u500b\u306e\u5c02\u9580\u30ef\u30fc\u30af\u30d5\u30ed\u30fc\uff08\u5b9a\u671f\u5b9f\u884c9\u672c\uff0b\u30aa\u30f3\u30c7\u30de\u30f3\u30c91\u672c\uff09\u304c\u3001\u81ea\u5f8b\u7684\u306b\u9ad8\u5ea6\u306a\u653f\u6cbb\u5206\u6790\u3092\u751f\u6210\u3057\u307e\u3059\u3002\u5358\u306a\u308b\u8981\u7d04\u3067\u306f\u306a\u304f\u3001\u60c5\u5831\u6e90\u691c\u8a3c\u3001\u8907\u6570\u653f\u515a\u3078\u306e\u516c\u5e73\u6027\u3001GDPR\u306b\u6e96\u62e0\u3057\u305fOSINT\u624b\u6cd5\u306b\u57fa\u3065\u304f\u69cb\u9020\u5316\u30a4\u30f3\u30c6\u30ea\u30b8\u30a7\u30f3\u30b9\u3068\u3057\u3066\u63d0\u4f9b\u3057\u307e\u3059\u3002', disclaimer: '\u7d99\u7d9a\u7684\u306a\u6539\u5584\u3092\u884c\u3063\u3066\u3044\u307e\u3059 \u2014', @@ -268,7 +268,7 @@ export const LANGUAGES: Record = { sort: '정렬:', newest: '최신순', oldest: '오래된 순', titleSort: '제목' }, noResults: '필터와 일치하는 기사가 없습니다', - i18n: { noArticles: '기사가 없습니다', search: '검색:', searchPlaceholder: '기사 검색...', loadMore: '더 많은 기사 불러오기', showing: '{shown} / {total} 개 기사' }, + i18n: { noArticles: '기사가 없습니다', search: '검색:', searchPlaceholder: '기사 검색...', loadMore: '더 많은 기사 불러오기', showing: '{shown} / {total} 개 기사', totalArticles: '전체 기사 수: {total}' }, aiNewsroomTitle: 'AI \ud601\uc2e0 \ub274\uc2a4 \uc0dd\uc131', aiNewsroomText: 'Riksdagsmonitor\uc758 \uc5d0\uc774\uc804\ud2b8\ud615 \ub274\uc2a4 \uc0dd\uc131 \ud30c\uc774\ud504\ub77c\uc778\uc740 \uc758\ud68c \ubaa8\ub2c8\ud130\ub9c1\uc744 \uc704\ud55c \uc138\uacc4 \ucd5c\ucd08\uc758 \uc644\uc804 AI \uae30\ubc18 \uc815\uce58 \uc778\ud154\ub9ac\uc804\uc2a4 \ub274\uc2a4\ub8f8\uc785\ub2c8\ub2e4. GitHub Copilot Coding Agent\ub97c \ud1b5\ud574 Claude Opus\ub85c \uad6c\ub3d9\ub418\uba70, 10\uac1c\uc758 \uc804\ubb38 \uc6cc\ud06c\ud50c\ub85c(\uc608\uc57d 9\uac1c + \uc8fc\ubb38\ud615 1\uac1c)\uac00 \uc790\uc728\uc801\uc73c\ub85c \uc2ec\uce35 \uc815\uce58 \ubd84\uc11d\uc744 \uc0dd\uc131\ud569\ub2c8\ub2e4. \uc774\ub294 \ub2e8\uc21c \uc694\uc57d\uc774 \uc544\ub2c8\ub77c \ucd9c\ucc98 \uac80\uc99d, \ub2e4\ub2f9\uc81c \uade0\ud615, GDPR\uc744 \uc900\uc218\ud558\ub294 OSINT \ubc29\ubc95\ub860\uc744 \uac16\ucd98 \uad6c\uc870\ud654\ub41c \uc778\ud154\ub9ac\uc804\uc2a4 \ub9ac\ud3ec\ud2b8\uc785\ub2c8\ub2e4.', disclaimer: '\uc9c0\uc18d\uc801\uc73c\ub85c \uac1c\uc120 \uc911\uc785\ub2c8\ub2e4 \u2014', @@ -288,7 +288,7 @@ export const LANGUAGES: Record = { sort: '排序:', newest: '最新优先', oldest: '最旧优先', titleSort: '标题' }, noResults: '没有与过滤器匹配的文章', - i18n: { noArticles: '没有可用的文章', search: '搜索:', searchPlaceholder: '搜索文章...', loadMore: '加载更多文章', showing: '显示 {shown} / {total} 篇文章' }, + i18n: { noArticles: '没有可用的文章', search: '搜索:', searchPlaceholder: '搜索文章...', loadMore: '加载更多文章', showing: '显示 {shown} / {total} 篇文章', totalArticles: '文章总数:{total}' }, aiNewsroomTitle: 'AI \u9a71\u52a8\u7684\u65b0\u95fb\u60c5\u62a5\u751f\u4ea7', aiNewsroomText: 'Riksdagsmonitor \u7684\u4ee3\u7406\u5f0f\u65b0\u95fb\u751f\u6210\u6d41\u6c34\u7ebf\uff0c\u662f\u5168\u7403\u9996\u4e2a\u4e13\u6ce8\u8bae\u4f1a\u76d1\u6d4b\u7684\u5168\u81ea\u52a8 AI \u653f\u6cbb\u60c5\u62a5\u65b0\u95fb\u5ba4\u3002\u4f9d\u6258\u901a\u8fc7 GitHub Copilot Coding Agent \u8c03\u7528\u7684 Claude Opus\uff0c\u6211\u4eec\u7684 10 \u6761\u4e13\u4e1a\u5de5\u4f5c\u6d41\uff089 \u6761\u5b9a\u65f6\u4efb\u52a1 + 1 \u6761\u6309\u9700\u89e6\u53d1\uff09\u53ef\u4ee5\u81ea\u4e3b\u751f\u6210\u6df1\u5ea6\u653f\u6cbb\u5206\u6790\u2014\u2014\u4e0d\u662f\u6d45\u5c42\u6458\u8981\uff0c\u800c\u662f\u5305\u542b\u6765\u6e90\u6838\u67e5\u3001\u591a\u515a\u6d3e\u89c6\u89d2\u5e73\u8861\uff0c\u5e76\u9075\u5faa GDPR \u7684 OSINT \u65b9\u6cd5\u8bba\u7684\u7ed3\u6784\u5316\u60c5\u62a5\u4ea7\u54c1\u3002', disclaimer: '\u6301\u7eed\u6539\u8fdb\u4e2d\u2014\u2014\u8bf7', diff --git a/scripts/generate-news-indexes/template.ts b/scripts/generate-news-indexes/template.ts index 739d01128ee..57d29d5b522 100644 --- a/scripts/generate-news-indexes/template.ts +++ b/scripts/generate-news-indexes/template.ts @@ -23,6 +23,26 @@ import { } from './helpers.js'; import { PKG_VERSION } from '../shared/version.js'; +function formatDisplayDate(date: string, locale: string): string { + const [yearStr, monthStr, dayStr] = date.split('-'); + const year: number = Number(yearStr); + const month: number = Number(monthStr); + const day: number = Number(dayStr); + + if (!Number.isFinite(year) || !Number.isFinite(month) || !Number.isFinite(day)) { + return date; + } + + const utcDate: Date = new Date(Date.UTC(year, month - 1, day)); + + return new Intl.DateTimeFormat(locale, { + year: 'numeric', + month: 'long', + day: 'numeric', + timeZone: 'UTC', + }).format(utcDate); +} + export function generateIndexHTML( langKey: string, languageArticles: NewsArticleMetadata[], @@ -51,6 +71,9 @@ export function generateIndexHTML( topics: a.topics, tags: a.tags, })); + const latestDate: string | null = displayArticles[0]?.date ?? null; + const totalArticlesSummary: string = lang.i18n.totalArticles.replace('{total}', String(displayArticles.length)); + const allLanguagesSummary: string = generateAvailableLanguages(Object.keys(LANGUAGES), langKey); const html = ` @@ -214,6 +237,13 @@ ${generateHreflangTags()}

${escapeHtml(lang.title)}

${lang.subtitle}

\u2190 ${escapeHtml(lang.backLink)} +
+

${escapeHtml(totalArticlesSummary)}

+ ${latestDate ? `

` : ''} +
+
+ ${allLanguagesSummary} +
${generateLanguageSwitcherNav(langKey)} @@ -263,6 +293,8 @@ ${needsLanguageNotice ? generateLanguageNotice(langKey) : ''} +

+
@@ -276,7 +308,6 @@ ${needsLanguageNotice ? generateLanguageNotice(langKey) : ''} diff --git a/scripts/generate-news-indexes/types.ts b/scripts/generate-news-indexes/types.ts index 1b959b9144b..412dd429f0e 100644 --- a/scripts/generate-news-indexes/types.ts +++ b/scripts/generate-news-indexes/types.ts @@ -33,6 +33,7 @@ export interface I18nStrings { searchPlaceholder: string; loadMore: string; showing: string | { one: string; other: string }; + totalArticles: string; } export interface BreadcrumbLabels { diff --git a/styles.css b/styles.css index 40921229c4d..35f923911fd 100644 --- a/styles.css +++ b/styles.css @@ -1296,7 +1296,7 @@ header { position: relative; text-align: center; margin-bottom: var(--spacing-lg); - padding: 0 0 var(--spacing-md) 0; + padding: 0 0 var(--spacing-xl) 0; border-bottom: 2px solid var(--section-border); display: flex; flex-direction: column; @@ -1310,10 +1310,20 @@ header { .hero-banner { position: relative; width: 100%; - height: clamp(260px, 40vw, 380px); + height: clamp(300px, 44vw, 430px); overflow: hidden; } +.hero-banner::after { + content: ""; + position: absolute; + inset: 0; + background: + radial-gradient(circle at top center, rgba(0, 217, 255, 0.18), transparent 45%), + linear-gradient(180deg, rgba(10, 14, 39, 0.08) 0%, rgba(10, 14, 39, 0.5) 100%); + z-index: 0; +} + .hero-banner-bg { position: absolute; top: 0; @@ -1334,7 +1344,7 @@ header { align-items: center; justify-content: center; padding: var(--spacing-sm) var(--spacing-lg); - gap: var(--spacing-xs); + gap: var(--spacing-sm); background: linear-gradient( to bottom, rgba(255, 255, 255, 0.3) 0%, @@ -1345,6 +1355,27 @@ header { -webkit-backdrop-filter: blur(1px); } +.hero-banner-overlay::before { + content: ""; + position: absolute; + left: 50%; + bottom: 2rem; + transform: translateX(-50%); + width: min(92%, 760px); + min-height: clamp(190px, 42%, 270px); + border-radius: var(--border-radius-lg); + background: linear-gradient(180deg, rgba(4, 18, 34, 0.66) 0%, rgba(10, 14, 39, 0.82) 100%); + border: 1px solid rgba(0, 217, 255, 0.35); + box-shadow: 0 18px 48px rgba(0, 0, 0, 0.28), 0 0 24px rgba(0, 217, 255, 0.12); + backdrop-filter: blur(14px); + -webkit-backdrop-filter: blur(14px); +} + +.hero-banner-overlay > * { + position: relative; + z-index: 1; +} + @media (prefers-color-scheme: dark) { .hero-banner-overlay { background: linear-gradient( @@ -1374,13 +1405,18 @@ html[data-theme="dark"] .hero-banner-overlay { .hero-banner-overlay h1 { margin: 0; - font-size: clamp(1.4rem, 4vw, 2.2rem); - line-height: 1.2; - text-shadow: 0 1px 4px rgba(255,255,255,0.5); + max-width: 14ch; + font-size: clamp(1.7rem, 4.6vw, 3rem); + line-height: 1.1; + color: #fff; + text-shadow: 0 1px 10px rgba(0, 0, 0, 0.55); } .hero-banner-overlay .h1-subtitle { - font-size: clamp(0.85rem, 2vw, 1.1rem); + display: block; + margin-top: 0.45rem; + font-size: clamp(0.95rem, 2vw, 1.25rem); + color: rgba(255, 255, 255, 0.88); } @media (prefers-color-scheme: dark) { @@ -1395,8 +1431,10 @@ html[data-theme="dark"] .hero-banner-overlay h1 { .hero-banner-overlay .tagline { margin: 0; - font-size: clamp(0.75rem, 1.8vw, 0.95rem); - text-shadow: 0 1px 3px rgba(255,255,255,0.4); + max-width: 58ch; + font-size: clamp(0.9rem, 1.8vw, 1.05rem); + color: rgba(255, 255, 255, 0.92); + text-shadow: 0 1px 8px rgba(0, 0, 0, 0.45); } @media (prefers-color-scheme: dark) { @@ -1411,16 +1449,32 @@ html[data-theme="dark"] .hero-banner-overlay .tagline { @media (max-width: 768px) { .hero-banner { - height: clamp(200px, 50vw, 300px); + height: clamp(250px, 56vw, 340px); } .hero-banner-overlay { padding: var(--spacing-sm); } + + .hero-banner-overlay::before { + left: 50%; + bottom: 1rem; + transform: translateX(-50%); + width: min(94%, 680px); + min-height: clamp(170px, 62%, 240px); + } } @media (max-width: 480px) { .hero-banner { - height: clamp(180px, 55vw, 260px); + height: clamp(220px, 65vw, 300px); + } + + .hero-banner-overlay h1 { + font-size: clamp(1.5rem, 8vw, 2.1rem); + } + + .hero-banner-overlay .tagline { + font-size: 0.9rem; } } @@ -3375,6 +3429,14 @@ footer { border-radius: var(--border-radius); font-size: 0.9rem; list-style: none; + width: min(100%, 1100px); + box-sizing: border-box; +} + +body > nav[aria-label="Breadcrumb"] { + display: flex; + justify-content: center; + padding: 0 var(--spacing-md); } @media (prefers-color-scheme: dark) { @@ -4141,18 +4203,29 @@ footer { /* Election Countdown */ .election-countdown { - margin: var(--spacing-md) 0; - padding: var(--spacing-md); + position: relative; + z-index: 2; + width: min(calc(100% - (var(--spacing-lg) * 2)), 880px); + margin: calc(var(--spacing-lg) * -0.5) auto 0; + padding: clamp(1rem, 2.5vw, 1.5rem); background: var(--card-bg); border: 2px solid var(--primary-color); border-radius: var(--border-radius-lg); text-align: center; + box-shadow: 0 18px 40px rgba(0, 0, 0, 0.16); } .election-countdown h2 { - font-size: 1.5rem; + display: flex; + flex-wrap: wrap; + align-items: center; + justify-content: center; + gap: 0.35rem 0.6rem; + font-size: clamp(1.35rem, 3vw, 2rem); color: var(--primary-color); margin-bottom: var(--spacing-xs); + text-transform: uppercase; + letter-spacing: 0.05em; } .election-countdown #countdown { @@ -4161,23 +4234,49 @@ footer { font-family: var(--font-mono); } +.election-countdown p { + margin: 0; + color: var(--text-secondary); + font-size: var(--font-size-base); +} + /* Hero Stats Grid */ .hero-stats { display: grid; - grid-template-columns: repeat(auto-fit, minmax(130px, 1fr)); + grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: var(--spacing-md); - margin: var(--spacing-md) 0; + margin: var(--spacing-lg) 0 0; width: 100%; - padding: 0 var(--spacing-lg); + padding: 0 var(--spacing-lg) var(--spacing-lg); box-sizing: border-box; } .hero-stats .stat { + position: relative; + overflow: hidden; text-align: center; padding: var(--spacing-md); background: var(--card-bg); border: 1px solid var(--border-color); border-radius: var(--border-radius); + box-shadow: 0 10px 24px rgba(0, 0, 0, 0.08); + transition: transform 0.25s ease, border-color 0.25s ease, box-shadow 0.25s ease; +} + +.hero-stats .stat::before { + content: ""; + position: absolute; + inset: 0 0 auto 0; + height: 3px; + background: linear-gradient(90deg, var(--primary-color), var(--accent-color), var(--primary-light)); + opacity: 0.9; +} + +.hero-stats .stat:hover, +.hero-stats .stat:focus-within { + transform: translateY(-3px); + border-color: rgba(0, 217, 255, 0.45); + box-shadow: 0 16px 32px rgba(0, 0, 0, 0.14); } .hero-stats .stat .number { @@ -4195,6 +4294,7 @@ footer { font-size: 0.9rem; color: var(--text-secondary); font-weight: 500; + line-height: 1.45; } /* Coalition Stability */ @@ -4489,6 +4589,11 @@ footer { /* Responsive Design for Election Pages */ @media (max-width: 768px) { + .election-countdown { + width: min(calc(100% - (var(--spacing-md) * 2)), 880px); + margin-top: calc(var(--spacing-md) * -0.35); + } + .hero-stats { grid-template-columns: repeat(2, 1fr); gap: var(--spacing-md); @@ -9077,9 +9182,13 @@ body.news-page { /* News header section */ .news-page .header-section { position: relative; - background: var(--card-bg, rgba(26, 30, 61, 0.9)); - border-bottom: 2px solid var(--primary-cyan, #00d9ff); - padding: 2rem 1rem; + overflow: hidden; + background: + radial-gradient(circle at top right, rgba(255, 0, 110, 0.18), transparent 32%), + radial-gradient(circle at left center, rgba(0, 217, 255, 0.12), transparent 38%), + var(--card-bg, rgba(26, 30, 61, 0.9)); + border-bottom: 1px solid rgba(0, 217, 255, 0.35); + padding: clamp(2rem, 5vw, 3.5rem) 1rem 2rem; margin-bottom: 0; } @@ -9087,6 +9196,18 @@ body.news-page { max-width: 1400px; margin: 0 auto; position: relative; + display: grid; + gap: 1rem; +} + +.news-page .header-content::before { + content: ""; + position: absolute; + inset: -1rem auto auto 0; + width: clamp(140px, 18vw, 220px); + height: 3px; + background: linear-gradient(90deg, var(--primary-cyan, #00d9ff), var(--primary-magenta, #ff006e)); + border-radius: 999px; } .news-page h1 { @@ -9101,7 +9222,8 @@ body.news-page { } .news-page .subtitle { - font-size: 1.1rem; + max-width: 72ch; + font-size: clamp(1rem, 1.7vw, 1.15rem); color: var(--text-secondary, #b0b0b0); margin: 0 0 0.75rem 0; } @@ -9110,12 +9232,61 @@ body.news-page { display: inline-block; color: var(--primary-cyan, #00d9ff); text-decoration: none; - padding: 0.5rem 0; - transition: transform 0.2s; + width: fit-content; + padding: 0.6rem 1rem; + border-radius: 999px; + border: 1px solid rgba(0, 217, 255, 0.3); + background: rgba(0, 217, 255, 0.08); + transition: transform 0.2s ease, background 0.2s ease, border-color 0.2s ease; } .news-page .back-link:hover { - transform: translateX(-5px); + transform: translateX(-4px); + background: rgba(0, 217, 255, 0.14); + border-color: rgba(0, 217, 255, 0.45); +} + +.news-page .news-hero-meta { + display: flex; + flex-wrap: wrap; + gap: 0.75rem; + align-items: center; +} + +.news-page .news-hero-stat { + display: inline-flex; + align-items: center; + gap: 0.45rem; + margin: 0; + padding: 0.55rem 0.9rem; + border-radius: 999px; + border: 1px solid rgba(0, 217, 255, 0.25); + background: rgba(10, 14, 39, 0.28); + color: var(--text-color, #e0e0e0); + font-size: 0.95rem; +} + +.news-page .news-hero-languages { + max-width: 1000px; +} + +.news-page .news-hero-languages .available-languages { + display: flex; + flex-wrap: wrap; + gap: 0.5rem; + align-items: center; + margin: 0; + color: var(--text-secondary, #b0b0b0); +} + +.news-page .news-hero-languages .available-languages strong { + color: var(--text-color, #e0e0e0); +} + +.news-page .news-hero-languages .language-badge { + margin-left: 0; + background: rgba(0, 217, 255, 0.08); + border: 1px solid rgba(0, 217, 255, 0.2); } .news-page .container { @@ -9156,11 +9327,18 @@ body.news-page { display: flex; flex-wrap: wrap; gap: 1rem; - margin-bottom: 1.5rem; + position: sticky; + /* Keep filters above flowing cards but below overlays like modals/tooltips. */ + top: 1rem; + z-index: 15; + margin-bottom: 1rem; padding: 1rem; background: var(--card-bg, rgba(26, 30, 61, 0.6)); border-radius: 8px; border: 1px solid var(--border-color, rgba(0, 217, 255, 0.3)); + box-shadow: 0 14px 28px rgba(0, 0, 0, 0.12); + backdrop-filter: blur(14px); + -webkit-backdrop-filter: blur(14px); } .news-page .filter-group { @@ -9217,9 +9395,10 @@ body.news-page { } .news-page .article-counter { - color: #888; + color: var(--text-secondary, #888); font-size: 0.9rem; - margin-bottom: 1rem; + margin: 0 0 1rem; + padding-inline: 0.2rem; } .news-page .load-more-btn { @@ -9247,30 +9426,48 @@ body.news-page { /* Articles grid */ .news-page .articles-grid { display: grid; - grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); - gap: 2rem; - margin-top: 2rem; + grid-template-columns: repeat(auto-fill, minmax(min(100%, 320px), 1fr)); + gap: 1.5rem; + margin-top: 0; } /* Article card */ .news-page .article-card { + position: relative; + overflow: hidden; background: var(--card-bg, rgba(26, 30, 61, 0.8)); border: 1px solid var(--border-color, rgba(0, 217, 255, 0.3)); - border-radius: 8px; + border-radius: 14px; padding: 1.5rem; transition: all 0.3s ease; display: flex; flex-direction: column; + min-height: 100%; + box-shadow: 0 10px 24px rgba(0, 0, 0, 0.1); +} + +.news-page .article-card::before { + content: ""; + position: absolute; + inset: 0 0 auto; + height: 3px; + background: linear-gradient(90deg, var(--primary-cyan, #00d9ff), var(--primary-magenta, #ff006e)); } .news-page .article-card:hover { border-color: var(--primary-cyan, #00d9ff); - box-shadow: 0 4px 20px rgba(0, 217, 255, 0.2); - transform: translateY(-2px); + box-shadow: 0 18px 36px rgba(0, 217, 255, 0.15); + transform: translateY(-4px); +} + +.news-page .article-card:focus-within { + border-color: var(--primary-cyan, #00d9ff); + box-shadow: 0 0 0 3px rgba(0, 217, 255, 0.18), 0 18px 36px rgba(0, 217, 255, 0.15); } .news-page .article-meta { display: flex; + flex-wrap: wrap; gap: 1rem; margin-bottom: 1rem; font-size: 0.85rem; @@ -9308,16 +9505,30 @@ body.news-page { color: var(--primary-cyan, #00d9ff); } +.news-page .article-title a:focus-visible { + outline: 2px solid var(--primary-cyan, #00d9ff); + outline-offset: 4px; + border-radius: 4px; +} + .news-page .article-excerpt { color: var(--text-secondary, #b0b0b0); margin-bottom: 1rem; flex-grow: 1; + line-height: 1.7; + display: -webkit-box; + -webkit-line-clamp: 4; + -webkit-box-orient: vertical; + overflow: hidden; } .news-page .article-tags { display: flex; flex-wrap: wrap; gap: 0.5rem; + margin-top: auto; + padding-top: 1rem; + border-top: 1px solid rgba(0, 217, 255, 0.14); } .news-page .tag { @@ -9357,6 +9568,15 @@ body.news-page { .news-page .header-section { padding: 1.5rem 0.75rem; } + + .news-page .news-hero-meta { + gap: 0.5rem; + } + + .news-page .news-hero-stat { + width: fit-content; + max-width: 100%; + } } /* ======================================== @@ -11229,6 +11449,23 @@ html[data-theme="light"] .news-page .header-section { border-bottom-color: var(--primary-color); } +html[data-theme="light"] .news-page .back-link { + background: rgba(0, 102, 51, 0.08); + border-color: rgba(0, 102, 51, 0.18); +} + +html[data-theme="light"] .news-page .news-hero-stat { + background: rgba(255, 255, 255, 0.72); + border-color: rgba(0, 102, 51, 0.15); + color: var(--text-color); +} + +html[data-theme="light"] .news-page .news-hero-languages .language-badge { + background: rgba(0, 102, 51, 0.06); + border-color: rgba(0, 102, 51, 0.16); + color: var(--text-color); +} + html[data-theme="light"] .news-page h1 { background: linear-gradient(135deg, var(--primary-color), var(--primary-light)); -webkit-background-clip: text; @@ -11322,6 +11559,11 @@ html[data-theme="dark"] .news-page .header-section { border-bottom-color: var(--primary-cyan); } +html[data-theme="dark"] .news-page .back-link { + background: rgba(0, 217, 255, 0.08); + border-color: rgba(0, 217, 255, 0.22); +} + html[data-theme="dark"] .news-page .article-card { background: rgba(0, 28, 37, 0.8); border-color: rgba(0, 204, 102, 0.2); @@ -11499,5 +11741,3 @@ html[data-theme="dark"] .language-switcher { .news-footer a:hover { color: var(--link-hover, #ff006e); } - - diff --git a/tests/generate-news-indexes.test.ts b/tests/generate-news-indexes.test.ts index 6aeada97e33..9e53fc7da29 100644 --- a/tests/generate-news-indexes.test.ts +++ b/tests/generate-news-indexes.test.ts @@ -364,6 +364,17 @@ describe('Generate News Indexes', () => { expect(enContent).toMatch(/addEventListener\s*\(\s*['"]click['"]\s*,\s*loadMore\s*\)/); }); + it('should include hero metadata and language coverage summary in generated indexes', () => { + module.generateAllIndexes(); + + const enContent = fs.readFileSync(path.join(NEWS_DIR, 'index.html'), 'utf-8'); + expect(enContent).toContain('class="news-hero-meta"'); + expect(enContent).toContain('class="news-hero-languages"'); + expect(enContent).toContain('class="news-hero-stat"'); + expect(enContent).toMatch(/class="news-hero-meta"[\s\S]*?]+datetime="/); + expect(enContent).toMatch(/class="news-hero-languages"[\s\S]*?class="language-badge"/); + }); + it('should include PAGE_SIZE and pagination logic', () => { module.generateAllIndexes();