Strony artykułów, sitemap, GA4, polityka prywatności

- Klikalne kafelki i slideshow → /blog/[slug]
- Strona artykułu: cover fullwidth z parallax, tytuł nad obrazkiem
- Schema.org BlogPosting na stronach postów
- Dynamiczny sitemap.xml (artykuły + produkty z Directus, revalidate=0)
- Google Analytics GA4 (G-7067BL7TDN)
- Polityka prywatności /polityka-prywatnosci
- CookieBanner z linkiem do polityki
- Footer: działający link do polityki prywatności

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Paweł Domański
2026-07-05 19:49:19 +02:00
parent eb09da9e4d
commit 8d4dc8a6f1
12 changed files with 382 additions and 18 deletions
+12 -4
View File
@@ -1,11 +1,12 @@
import React from 'react';
import Link from 'next/link';
const BentoCard = ({ type, badge, title, category, readTime, bgImage, hero = false, style = {} }) => {
return (
const BentoCard = ({ type, badge, title, category, readTime, bgImage, hero = false, style = {}, href }) => {
const inner = (
<article
className={`bento-card${hero ? ' hero-article' : ''}`}
style={style}
tabIndex={0}
style={href ? {} : style}
tabIndex={href ? -1 : 0}
aria-label={`${category}: ${title}`}
>
<div
@@ -32,6 +33,13 @@ const BentoCard = ({ type, badge, title, category, readTime, bgImage, hero = fal
</div>
</article>
);
if (href) return (
<Link href={href} style={style} className="bento-card-link">
{inner}
</Link>
);
return inner;
};
export default BentoCard;
+10 -2
View File
@@ -1,4 +1,6 @@
import React, { useEffect, useState } from 'react';
'use client'
import { useEffect, useState } from 'react';
import Link from 'next/link';
const BentoSlideshow = ({ slides, style = {} }) => {
const [current, setCurrent] = useState(0);
@@ -40,7 +42,13 @@ const BentoSlideshow = ({ slides, style = {} }) => {
aria-hidden={index !== current}
>
<div className={`bento-badge badge-${slide.type}`}>{slide.badge}</div>
<h2 className="article-title slideshow-title">{slide.title}</h2>
{slide.slug ? (
<Link href={`/blog/${slide.slug}`} className="slideshow-title-link">
<h2 className="article-title slideshow-title">{slide.title}</h2>
</Link>
) : (
<h2 className="article-title slideshow-title">{slide.title}</h2>
)}
<div className="article-meta">
<span>{slide.category}</span>
<span className="dot" aria-hidden="true" />
+6 -3
View File
@@ -1,9 +1,12 @@
import React, { useState } from 'react';
'use client'
import { useState, useEffect } from 'react';
import Link from 'next/link';
const STORAGE_KEY = 'dexos-cookie-consent';
const CookieBanner = () => {
const [visible, setVisible] = useState(() => !localStorage.getItem(STORAGE_KEY));
const [visible, setVisible] = useState(false);
useEffect(() => { setVisible(!localStorage.getItem(STORAGE_KEY)); }, []);
const handleConsent = (accepted) => {
localStorage.setItem(STORAGE_KEY, accepted ? 'accepted' : 'rejected');
@@ -16,7 +19,7 @@ const CookieBanner = () => {
<div className="cookie-banner" role="dialog" aria-modal="true" aria-label="Zgoda na pliki cookie">
<div className="cookie-content">
<h4>Ciasteczka</h4>
<p>Używamy plików cookie, aby dostarczać spersonalizowane treści i analizować ruch na stronie.</p>
<p>Używamy plików cookie do analizy ruchu i personalizacji treści. <Link href="/polityka-prywatnosci" style={{ color: 'var(--primary)' }}>Polityka prywatności</Link></p>
<div className="cookie-actions">
<button className="button-secondary" onClick={() => handleConsent(false)}>
Odrzuć
+48
View File
@@ -0,0 +1,48 @@
const Footer = () => (
<footer className="main-footer">
<div className="footer-container">
<div className="footer-brand">
<div className="nav-logo">
<span className="pulse-dot" aria-hidden="true"></span>
DEX_OS
</div>
<p>Zbudowane przez deweloperów sztucznej inteligencji, dla agentów przyszłości.</p>
<div className="footer-social" aria-label="Social media">
<a href="https://linkedin.com/company/dexterlab" rel="me noopener" target="_blank" aria-label="LinkedIn" className="footer-social__link">
<svg width="18" height="18" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M20.447 20.452h-3.554v-5.569c0-1.328-.027-3.037-1.852-3.037-1.853 0-2.136 1.445-2.136 2.939v5.667H9.351V9h3.414v1.561h.046c.477-.9 1.637-1.85 3.37-1.85 3.601 0 4.267 2.37 4.267 5.455v6.286zM5.337 7.433a2.062 2.062 0 0 1-2.063-2.065 2.064 2.064 0 1 1 2.063 2.065zm1.782 13.019H3.555V9h3.564v11.452zM22.225 0H1.771C.792 0 0 .774 0 1.729v20.542C0 23.227.792 24 1.771 24h20.451C23.2 24 24 23.227 24 22.271V1.729C24 .774 23.2 0 22.222 0h.003z"/></svg>
</a>
<a href="https://x.com/dexterlab_pl" rel="me noopener" target="_blank" aria-label="X (Twitter)" className="footer-social__link">
<svg width="18" height="18" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-4.714-6.231-5.401 6.231H2.748l7.73-8.835L1.254 2.25H8.08l4.261 5.636 5.903-5.636zm-1.161 17.52h1.833L7.084 4.126H5.117z"/></svg>
</a>
<a href="https://facebook.com/dexterlab" rel="me noopener" target="_blank" aria-label="Facebook" className="footer-social__link">
<svg width="18" height="18" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M24 12.073c0-6.627-5.373-12-12-12s-12 5.373-12 12c0 5.99 4.388 10.954 10.125 11.854v-8.385H7.078v-3.47h3.047V9.43c0-3.007 1.792-4.669 4.533-4.669 1.312 0 2.686.235 2.686.235v2.953H15.83c-1.491 0-1.956.925-1.956 1.874v2.25h3.328l-.532 3.47h-2.796v8.385C19.612 23.027 24 18.062 24 12.073z"/></svg>
</a>
</div>
</div>
<div className="footer-links">
<div className="footer-col">
<h4>Platforma</h4>
<a href="#">Architektura</a>
<a href="#">Agent Swarms</a>
<a href="#">Bezpieczeństwo</a>
</div>
<div className="footer-col">
<h4>Firma</h4>
<a href="#">O nas</a>
<a href="#">Kariera</a>
<a href="/kontakt">Kontakt</a>
</div>
<div className="footer-col">
<h4>Zasady</h4>
<a href="#">Regulamin</a>
<a href="/polityka-prywatnosci">Polityka Prywatności</a>
</div>
</div>
</div>
<div className="footer-bottom">
<p>&copy; {new Date().getFullYear()} DEX Operating System. Wszelkie prawa zastrzeżone.</p>
</div>
</footer>
)
export default Footer