easy-web-content-blocks
Installation
Section titled “Installation”pnpm add @easy-web/content-blocksOverview
Section titled “Overview”@easy-web/content-blocks ships twenty-two pure-Astro components covering every standard page section: four header variants with responsive mobile menus, a footer, a theme toggle, a language switcher, hero/CTA/contact sections, structural helpers (Section, CardGrid, Card), a CMS-driven gallery system with six rendering variants, blog post cards, legal prose layouts, and notice banners. All components use the --ew-* design tokens from @easy-web/theme-core and carry no styling system of their own.
Components are not exported from a JavaScript barrel. Import each one from its component path using the ./components/* exports map:
---import Header from '@easy-web/content-blocks/components/Header';import Footer from '@easy-web/content-blocks/components/Footer';---Peer dependencies
Section titled “Peer dependencies”astro >= 6.0.0@easy-web/theme-core— provides the--ew-*token CSS
Quick start
Section titled “Quick start”---import '@easy-web/theme-core/tokens.css';import { noFlashScript } from '@easy-web/theme-core';import Header from '@easy-web/content-blocks/components/Header';import Footer from '@easy-web/content-blocks/components/Footer';---<html lang="de"> <head> <script is:inline set:html={noFlashScript}></script> </head> <body> <Header siteName="My Site" navItems={navItems} currentLang="de" pathname={pathname} /> <slot /> <Footer siteName="My Site" legalLinks={legalLinks} /> </body></html>Site chrome
Section titled “Site chrome”Header
Section titled “Header”Sticky responsive header with an actions slot. Mobile hamburger menu via scoped vanilla JS. Default slot fallback renders ThemeToggle + LanguageSwitch automatically.
Import: import Header from '@easy-web/content-blocks/components/Header'
| Prop | Type | Required | Default |
| :--- | :--- | :---: | :--- |
| siteName | string | ✓ | — |
| navItems | NavItem[] | ✓ | — |
| currentLang | string | ✓ | — |
| pathname | string | ✓ | — |
| alternateHref | string | | — |
| menuLabel | string | | — |
Variants: HeaderCentered, HeaderHideOnScroll, HeaderFlyout — same props, different layout behaviours. HeaderFlyout additionally supports children[] on nav items for dropdown panels.
---import Header from '@easy-web/content-blocks/components/Header';import HeaderFlyout from '@easy-web/content-blocks/components/HeaderFlyout';---
<!-- Standard header --><Header siteName="My Site" navItems={navItems} currentLang="de" pathname={pathname} />
<!-- Header with custom actions slot (replaces ThemeToggle + LanguageSwitch) --><Header siteName="My Site" navItems={navItems} currentLang="de" pathname={pathname}> <fragment slot="actions"> <MyLoginButton /> </fragment></Header>
<!-- Flyout header with nested nav items --><HeaderFlyout siteName="My Site" navItems={navItemsWithChildren} currentLang="de" pathname={pathname} />Footer
Section titled “Footer”Simple copyright footer with legal-link navigation.
Import: import Footer from '@easy-web/content-blocks/components/Footer'
| Prop | Type | Required |
| :--- | :--- | :---: |
| siteName | string | ✓ |
| legalLinks | Array<{ label: string; href: string }> | ✓ |
ThemeToggle
Section titled “ThemeToggle”Light / dark / system three-way toggle button. Reads and writes theme state via @easy-web/theme-core.
Import: import ThemeToggle from '@easy-web/content-blocks/components/ThemeToggle'
No props. Renders a trio of buttons; the active state is reflected via data-theme on <html>.
LanguageSwitch
Section titled “LanguageSwitch”DE ↔ EN switcher. If alternateHref is provided, links there directly; otherwise infers the alternate path from pathname.
Import: import LanguageSwitch from '@easy-web/content-blocks/components/LanguageSwitch'
| Prop | Type | Required |
| :--- | :--- | :---: |
| currentLang | string | ✓ |
| pathname | string | ✓ |
| alternateHref | string | |
Hero / CTA / Contact
Section titled “Hero / CTA / Contact”Full-width page banner with optional CTA button.
Import: import Hero from '@easy-web/content-blocks/components/Hero'
| Prop | Type | Required | Notes |
| :--- | :--- | :---: | :--- |
| title | string | ✓ | — |
| subtitle | string | | — |
| ctaLabel | string | | Both ctaLabel and ctaHref must be present for the button to render |
| ctaHref | string | | — |
| variant | 'centered' \| 'left-aligned' | | — |
---import Hero from '@easy-web/content-blocks/components/Hero';---<Hero title="Willkommen" subtitle="Der beste Ort für Harley-Davidson Vermietung in Florida" ctaLabel="Jetzt buchen" ctaHref="#booking" variant="centered"/>CtaSection
Section titled “CtaSection”Standalone call-to-action banner with optional body text.
Import: import CtaSection from '@easy-web/content-blocks/components/CtaSection'
| Prop | Type | Required | Notes |
| :--- | :--- | :---: | :--- |
| heading | string | ✓ | — |
| buttonLabel | string | ✓ | — |
| buttonHref | string | ✓ | — |
| body | string | | — |
| variant | 'default' \| 'muted' \| 'primary' | | primary inverts to brand colour |
ContactSection
Section titled “ContactSection”Centered mailto-based contact CTA. Button href is mailto:${email}.
Import: import ContactSection from '@easy-web/content-blocks/components/ContactSection'
| Prop | Type | Required |
| :--- | :--- | :---: |
| heading | string | ✓ |
| email | string | ✓ |
| buttonLabel | string | ✓ |
| body | string | |
Structural
Section titled “Structural”Section
Section titled “Section”Generic slot-based content wrapper. id enables anchor-link targets.
Import: import Section from '@easy-web/content-blocks/components/Section'
CardGrid
Section titled “CardGrid”Responsive CSS grid (3 → 2 → 1 columns by breakpoint). Slot in Card children.
Import: import CardGrid from '@easy-web/content-blocks/components/CardGrid'
Content card. Renders as <a> when href is provided, plain <div> otherwise. Image is loading="lazy".
Import: import Card from '@easy-web/content-blocks/components/Card'
| Prop | Type | Required |
| :--- | :--- | :---: |
| title | string | ✓ |
| description | string | |
| href | string | |
| image | string | |
| imageAlt | string | |
---import Section from '@easy-web/content-blocks/components/Section';import CardGrid from '@easy-web/content-blocks/components/CardGrid';import Card from '@easy-web/content-blocks/components/Card';---<Section id="services"> <h2>Unsere Leistungen</h2> <CardGrid> <Card title="Tagestouren" description="Entdecken Sie Florida auf zwei Rädern." href="/touren" /> <Card title="Wochenend-Pakete" description="Drei Tage, ein Abenteuer." href="/pakete" /> <Card title="Gruppen-Buchungen" description="Für Gruppen ab 4 Personen." href="/gruppen" /> </CardGrid></Section>Gallery system
Section titled “Gallery system”The gallery system is CMS-driven. Content authors create gallery entries in src/content/galleries/; pages load the entry and pass it to GallerySection, which dispatches to the correct variant based on entry.data.kind.
Setting up the content collection
Section titled “Setting up the content collection”import { defineCollection } from 'astro:content';import { glob } from 'astro/loaders';import { gallerySchema } from '@easy-web/content-blocks/schemas/galleries';
const galleries = defineCollection({ loader: glob({ pattern: '**/*.{yml,yaml}', base: './src/content/galleries' }), schema: gallerySchema,});
export const collections = { galleries };GallerySection
Section titled “GallerySection”Dispatcher component. Renders the correct variant based on entry.data.kind. Renders nothing when entry is null or undefined.
Import: import GallerySection from '@easy-web/content-blocks/components/GallerySection'
---import GallerySection from '@easy-web/content-blocks/components/GallerySection';import { getEntry } from 'astro:content';
const heroEntry = await getEntry('galleries', 'home-hero-de');---<GallerySection entry={heroEntry} />Gallery kind values
Section titled “Gallery kind values”| kind | Component | Use case |
| :--- | :--- | :--- |
| image-grid | GalleryImageGrid | Static N-column uniform grid |
| hero-slider | GalleryHeroSlider | Full-bleed editorial carousel |
| carousel | GalleryCarousel | Constrained-width image slider |
| masonry-grid | GalleryMasonryGrid | Pinterest-style variable-height grid |
| feature-highlight | GalleryFeatureHighlight | Alternating image+text rows |
| lightbox-grid | GalleryLightboxGrid | Grid with click-to-expand modal |
All gallery components are also importable directly if you want to bypass the CMS entry abstraction.
BlogPostCard
Section titled “BlogPostCard”Linked card for blog index pages. Date is formatted with Intl.DateTimeFormat using the provided locale.
Import: import BlogPostCard from '@easy-web/content-blocks/components/BlogPostCard'
| Prop | Type | Required |
| :--- | :--- | :---: |
| title | string | ✓ |
| description | string | ✓ |
| href | string | ✓ |
| pubDate | Date | ✓ |
| heroImage | string | |
| heroImageAlt | string | |
| locale | string | |
Legal & long-form
Section titled “Legal & long-form”LegalLayout
Section titled “LegalLayout”Narrow content wrapper for impressum / datenschutz / AGB pages. Constrains line-length for legal prose.
Import: import LegalLayout from '@easy-web/content-blocks/components/LegalLayout'
Slot-based — place your Markdown content or <Prose> inside.
Styled wrapper that applies --ew-* typography tokens to raw HTML elements (<h1>–<h6>, <p>, <ul>, <a>, <blockquote>, <code>, etc.).
Import: import Prose from '@easy-web/content-blocks/components/Prose'
---import LegalLayout from '@easy-web/content-blocks/components/LegalLayout';import Prose from '@easy-web/content-blocks/components/Prose';import { Content } from '../content/impressum.md';---<LegalLayout> <Prose> <Content /> </Prose></LegalLayout>Banners / notices
Section titled “Banners / notices”DraftBanner
Section titled “DraftBanner”Banner notice for draft content. Slot-based; pass a short status message.
Import: import DraftBanner from '@easy-web/content-blocks/components/DraftBanner'
LanguageNotice
Section titled “LanguageNotice”Banner notice shown when a page is displayed in the non-current locale or has a partial translation.
Import: import LanguageNotice from '@easy-web/content-blocks/components/LanguageNotice'
Styling
Section titled “Styling”All components reference @easy-web/theme-core CSS custom properties exclusively. To re-skin, override --ew-* variables on :root (or a scoped ancestor) — do not edit the component files. Class names follow BEM with an ew- prefix (e.g. .ew-hero, .ew-hero__title, .ew-hero--centered).