Initial commit: Van's DIY & Bastelbedarf Astro shop
This commit is contained in:
@@ -0,0 +1,313 @@
|
||||
---
|
||||
import "../styles/global.css";
|
||||
import { categories } from "../data/categories";
|
||||
import { defaultLocale, localeMeta, localePrefix, type Locale } from "../i18n/config";
|
||||
import { useTranslations } from "../i18n/ui";
|
||||
import LanguageSwitcher from "../components/LanguageSwitcher.astro";
|
||||
|
||||
interface Props {
|
||||
title: string;
|
||||
description?: string;
|
||||
lang?: Locale;
|
||||
/** Sprachneutraler Pfad der aktuellen Seite (ohne Sprach-Prefix), z.B. "/shop/". Für den Sprachumschalter. */
|
||||
path?: string;
|
||||
/** Seite existiert nur auf Deutsch (Rechtstexte) — siehe LanguageSwitcher. */
|
||||
legalOnly?: boolean;
|
||||
}
|
||||
const {
|
||||
title,
|
||||
description = "Van's DIY & Bastelbedarf – handgemachte Häkelwerke, Plushies, Schmuck und Bastelzubehör mit Liebe gefertigt.",
|
||||
lang = defaultLocale,
|
||||
path = "/",
|
||||
legalOnly = false,
|
||||
} = Astro.props;
|
||||
|
||||
const t = useTranslations(lang);
|
||||
const p = (href: string) => `${localePrefix(lang)}${href}`;
|
||||
---
|
||||
<!doctype html>
|
||||
<html lang={localeMeta[lang].htmlLang}>
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
||||
<title>{title} · Van's DIY & Bastelbedarf</title>
|
||||
<meta name="description" content={description} />
|
||||
<link rel="canonical" href={new URL(Astro.url.pathname, Astro.site ?? "https://vans-diy-bastelbedarf.de").toString()} />
|
||||
<meta property="og:type" content="website" />
|
||||
<meta property="og:site_name" content="Van's DIY & Bastelbedarf" />
|
||||
<meta property="og:title" content={title} />
|
||||
<meta property="og:description" content={description} />
|
||||
<meta name="theme-color" content="#0a0910" />
|
||||
<!-- TODO Phase 2: Fonts self-hosten statt Google-Fonts-CDN (Performance/DSGVO) -->
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||||
<link href="https://fonts.googleapis.com/css2?family=Fraunces:opsz,[email protected],300..700&family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet" />
|
||||
<style>
|
||||
:root { --font-head-override: "Fraunces", serif; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="topbar">🩵 {t.topbar}</div>
|
||||
|
||||
<header class="site-header">
|
||||
<div class="container header-inner">
|
||||
<a href={p("/")} class="brand">
|
||||
<img src="/logo.png" alt="Van's DIY & Bastelbedarf Logo" width="42" height="42" />
|
||||
<span>Van's DIY & Bastelbedarf</span>
|
||||
</a>
|
||||
|
||||
<nav class="main-nav" aria-label="Hauptnavigation">
|
||||
<a href={p("/shop/")}>{t.nav.shop}</a>
|
||||
<a href={p("/sale/")}>{t.nav.sale}</a>
|
||||
<a href={p("/ueber-die-kreative/")}>{t.nav.creative}</a>
|
||||
<a href={p("/faq/")}>{t.nav.faq}</a>
|
||||
<a href={p("/kontakt/")}>{t.nav.contact}</a>
|
||||
</nav>
|
||||
|
||||
<div class="header-actions">
|
||||
<LanguageSwitcher lang={lang} path={path} legalOnly={legalOnly} />
|
||||
<a href={p("/konto/")} class="account-btn">
|
||||
<span class="account-icon" aria-hidden="true">
|
||||
<svg viewBox="0 0 24 24" width="14" height="14" fill="currentColor"><path d="M12 12a5 5 0 1 0-5-5 5 5 0 0 0 5 5Zm0 2c-4.4 0-9 2.2-9 5v2h18v-2c0-2.8-4.6-5-9-5Z"/></svg>
|
||||
</span>
|
||||
<span class="account-label">{t.nav.login}</span>
|
||||
</a>
|
||||
<a href={p("/warenkorb/")} class="icon-link cart-link" aria-label={t.nav.account}>
|
||||
🧺 <span class="cart-count" id="cart-count">0</span>
|
||||
</a>
|
||||
<button class="hamburger" id="hamburger" aria-label="Menü" aria-expanded="false">☰</button>
|
||||
</div>
|
||||
</div>
|
||||
<nav class="mobile-nav" id="mobile-nav" aria-label="Mobile Navigation">
|
||||
<a href={p("/shop/")}>{t.nav.shop}</a>
|
||||
<a href={p("/sale/")}>{t.nav.sale}</a>
|
||||
<a href={p("/ueber-die-kreative/")}>{t.nav.creative}</a>
|
||||
<a href={p("/faq/")}>{t.nav.faq}</a>
|
||||
<a href={p("/kontakt/")}>{t.nav.contact}</a>
|
||||
<a href={p("/konto/")}>{t.nav.account}</a>
|
||||
<span class="mobile-nav-divider">{t.shop.categoryLabel}</span>
|
||||
{categories.map((c) => <a href={p(`/shop/${c.slug}/`)}>{c.icon} {c.name[lang]}</a>)}
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
<nav class="sub-nav" aria-label="Kategorien-Schnellzugriff">
|
||||
<div class="container sub-nav-inner">
|
||||
{categories.map((c) => (
|
||||
<a href={p(`/shop/${c.slug}/`)}>{c.name[lang]}</a>
|
||||
))}
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<main>
|
||||
<slot />
|
||||
</main>
|
||||
|
||||
<footer class="site-footer">
|
||||
<div class="container footer-grid">
|
||||
<div>
|
||||
<a href={p("/")} class="brand">
|
||||
<img src="/logo.png" alt="Van's DIY & Bastelbedarf Logo" width="36" height="36" />
|
||||
<span>Van's DIY & Bastelbedarf</span>
|
||||
</a>
|
||||
<p class="small">{t.footer.tagline}</p>
|
||||
</div>
|
||||
<div>
|
||||
<h3>{t.footer.shopHeading}</h3>
|
||||
<ul class="footer-list">
|
||||
{categories.map((c) => <li><a href={p(`/shop/${c.slug}/`)}>{c.name[lang]}</a></li>)}
|
||||
</ul>
|
||||
</div>
|
||||
<div>
|
||||
<h3>{t.footer.serviceHeading}</h3>
|
||||
<ul class="footer-list">
|
||||
<li><a href={p("/versand-zahlung/")}>{t.footer.shipping}</a></li>
|
||||
<li><a href={p("/faq/")}>{t.nav.faq}</a></li>
|
||||
<li><a href={p("/kontakt/")}>{t.nav.contact}</a></li>
|
||||
<li><a href={p("/konto/")}>{t.footer.account}</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div>
|
||||
<h3>{t.footer.legalHeading}</h3>
|
||||
<ul class="footer-list">
|
||||
<li><a href="/impressum/">Impressum</a></li>
|
||||
<li><a href="/datenschutz/">Datenschutz</a></li>
|
||||
<li><a href="/agb/">AGB</a></li>
|
||||
<li><a href="/widerruf/">Widerrufsbelehrung</a></li>
|
||||
<li><a href="/muster-widerrufsformular/">Muster-Widerrufsformular</a></li>
|
||||
</ul>
|
||||
{lang !== "de" && <p class="small legal-note-footer" title={t.footer.legalNoteTitle}>{t.footer.legalNote}</p>}
|
||||
</div>
|
||||
</div>
|
||||
<div class="container">
|
||||
<hr class="divider" />
|
||||
<p class="small">© {new Date().getFullYear()} Van's DIY & Bastelbedarf · {t.footer.copyright}</p>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<script>
|
||||
import { cartCount } from "../scripts/cart";
|
||||
function updateCount() {
|
||||
const el = document.getElementById("cart-count");
|
||||
if (el) el.textContent = String(cartCount());
|
||||
}
|
||||
updateCount();
|
||||
window.addEventListener("cart:changed", updateCount);
|
||||
window.addEventListener("storage", updateCount);
|
||||
|
||||
const hamburger = document.getElementById("hamburger");
|
||||
const mobileNav = document.getElementById("mobile-nav");
|
||||
hamburger?.addEventListener("click", () => {
|
||||
const open = mobileNav?.classList.toggle("open");
|
||||
hamburger.setAttribute("aria-expanded", String(!!open));
|
||||
});
|
||||
</script>
|
||||
|
||||
<style is:global>
|
||||
body { font-family: var(--font-body); }
|
||||
h1, h2, h3, h4 { font-family: var(--font-head-override, var(--font-head)); }
|
||||
|
||||
.topbar {
|
||||
background: linear-gradient(90deg, var(--c-purple), var(--c-purple-deep));
|
||||
color: var(--c-text);
|
||||
text-align: center;
|
||||
font-size: 0.82rem;
|
||||
padding: 0.5rem 1rem;
|
||||
letter-spacing: 0.01em;
|
||||
}
|
||||
|
||||
.site-header {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 40;
|
||||
background: rgba(10, 9, 16, 0.85);
|
||||
backdrop-filter: blur(10px);
|
||||
border-bottom: 1px solid rgba(244, 241, 247, 0.06);
|
||||
}
|
||||
.header-inner {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 1rem;
|
||||
padding-block: 0.8rem;
|
||||
}
|
||||
.brand {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.6rem;
|
||||
font-family: var(--font-head);
|
||||
font-weight: 600;
|
||||
font-size: 1.05rem;
|
||||
}
|
||||
.brand img { border-radius: 50%; }
|
||||
|
||||
.main-nav { display: flex; gap: 1.6rem; }
|
||||
.main-nav a {
|
||||
font-size: 0.92rem;
|
||||
color: var(--c-text-muted);
|
||||
transition: color 0.2s var(--ease);
|
||||
}
|
||||
.main-nav a:hover { color: var(--c-accent); }
|
||||
|
||||
.header-actions { display: flex; align-items: center; gap: 0.8rem; }
|
||||
.icon-link { font-size: 1.1rem; position: relative; display: inline-flex; align-items: center; gap: 0.3rem; }
|
||||
.cart-count {
|
||||
background: var(--c-accent);
|
||||
color: #08181c;
|
||||
font-size: 0.7rem;
|
||||
font-weight: 700;
|
||||
border-radius: 999px;
|
||||
min-width: 1.2em;
|
||||
padding: 0 0.35em;
|
||||
text-align: center;
|
||||
}
|
||||
.hamburger {
|
||||
display: none;
|
||||
background: none;
|
||||
border: none;
|
||||
color: var(--c-text);
|
||||
font-size: 1.4rem;
|
||||
cursor: pointer;
|
||||
}
|
||||
.mobile-nav {
|
||||
display: none;
|
||||
flex-direction: column;
|
||||
padding: 0.5rem 1.5rem 1.2rem;
|
||||
gap: 0.9rem;
|
||||
border-top: 1px solid rgba(244,241,247,0.06);
|
||||
}
|
||||
.mobile-nav.open { display: flex; }
|
||||
.mobile-nav-divider {
|
||||
margin-top: 0.4rem;
|
||||
padding-top: 0.9rem;
|
||||
border-top: 1px solid rgba(244, 241, 247, 0.08);
|
||||
font-size: 0.72rem;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.08em;
|
||||
color: var(--c-accent);
|
||||
}
|
||||
|
||||
@media (max-width: 860px) {
|
||||
.main-nav { display: none; }
|
||||
.hamburger { display: inline-block; }
|
||||
}
|
||||
|
||||
/* Zweite Navigationsleiste: Schnellzugriff auf die 5 Hauptkategorien, direkt unter der
|
||||
Hauptnav — gleicher Designstil (dunkler Anthrazit-Streifen, Akzent-Unterstrich bei Hover). */
|
||||
.sub-nav {
|
||||
background: var(--c-anthracite);
|
||||
border-bottom: 1px solid rgba(244, 241, 247, 0.06);
|
||||
}
|
||||
.sub-nav-inner {
|
||||
display: flex;
|
||||
gap: clamp(1.1rem, 3vw, 2rem);
|
||||
overflow-x: auto;
|
||||
padding-block: 0.6rem;
|
||||
scrollbar-width: none;
|
||||
}
|
||||
.sub-nav-inner::-webkit-scrollbar { display: none; }
|
||||
.sub-nav-inner a {
|
||||
position: relative;
|
||||
font-size: 0.83rem;
|
||||
font-weight: 600;
|
||||
color: var(--c-text-muted);
|
||||
white-space: nowrap;
|
||||
padding-bottom: 3px;
|
||||
transition: color 0.2s var(--ease);
|
||||
}
|
||||
.sub-nav-inner a::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: -1px;
|
||||
height: 2px;
|
||||
background: var(--c-accent);
|
||||
transform: scaleX(0);
|
||||
transform-origin: left;
|
||||
transition: transform 0.2s var(--ease);
|
||||
}
|
||||
.sub-nav-inner a:hover { color: var(--c-accent); }
|
||||
.sub-nav-inner a:hover::after { transform: scaleX(1); }
|
||||
@media (max-width: 860px) { .sub-nav { display: none; } }
|
||||
|
||||
.site-footer {
|
||||
background: var(--c-anthracite);
|
||||
margin-top: 4rem;
|
||||
padding-top: 3rem;
|
||||
padding-bottom: 2rem;
|
||||
}
|
||||
.footer-grid {
|
||||
display: grid;
|
||||
grid-template-columns: 1.4fr 1fr 1fr 1fr;
|
||||
gap: 2rem;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
.footer-list { list-style: none; padding: 0; margin: 0; display: grid; gap: 0.55rem; }
|
||||
.footer-list a { color: var(--c-text-muted); font-size: 0.9rem; }
|
||||
.footer-list a:hover { color: var(--c-accent); }
|
||||
.legal-note-footer { margin-top: 0.8rem; font-size: 0.78rem; line-height: 1.5; }
|
||||
@media (max-width: 760px) { .footer-grid { grid-template-columns: 1fr 1fr; } }
|
||||
@media (max-width: 480px) { .footer-grid { grid-template-columns: 1fr; } }
|
||||
</style>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user