JSPM

  • Created
  • Published
  • Downloads 12
  • Score
    100M100P100Q112370F
  • License MIT

Startnext Chrome Web Components

Package Exports

  • @startnext/chrome
  • @startnext/chrome/render

Readme

@startnext/chrome

Startnext Header/Footer Web Components

Wiederverwendbare Header- und Footer-Components für alle Startnext Microservices.

Installation

npm install @startnext/chrome
# or
pnpm add @startnext/chrome

Quick Start

Modern JavaScript (React, Vue, etc.)

import '@startnext/chrome';
<startnext-header></startnext-header>
<startnext-footer></startnext-footer>

Via CDN (PHP, Vanilla HTML)

<script type="module" src="https://unpkg.com/@startnext/chrome@latest/dist/index.js"></script>

<startnext-header></startnext-header>
<startnext-footer></startnext-footer>

API

<startnext-header>

Attributes:

Attribute Type Default Description
lang string 'de' Sprache ('de', 'en')
light boolean false Heller Header (weiße Schrift/Icons über dunklem Hero, wechselt automatisch zu dunkel beim Scrollen). Standard ohne Attribut: dunkler Header
large-animation boolean false Große Lottie-Logo-Animation mit Claim und horizontaler Navigation
authenticated boolean false Zeigt User-Avatar statt "Anmelden" Button
user-name string - Name des eingeloggten Users
user-avatar string - Avatar-URL des Users
color-mode 'light' | 'dark' auto Farbmodus. Ohne Attribut: Header scannt <html> nach Klasse dark/light. Ohne Klasse: Default dark (dunkle Seite, heller Header). Toggle-Button wechselt <html>-Klasse und Header-Darstellung
hide-color-mode boolean false Versteckt den Color-Mode Toggle-Button
hide-lang boolean false Versteckt den Language-Switcher
hide-login boolean false Versteckt den Login/Avatar-Button
show-back-link boolean false Zeigt einen "Zurueck zu Startnext"-Link (Text kommt von der API)
back-url string - Ueberschreibt die Back-Link-URL
back-label string - Ueberschreibt den Back-Link-Text
api-url string - API-Endpoint-URL fuer Live-Daten aus Notion

Events:

Event Detail Description
burger-menu-toggle { open: boolean } Burger-Menü geöffnet/geschlossen
user-menu-toggle { open: boolean } User-Menü geöffnet/geschlossen
navigation-click { item: NavigationItem } Navigation-Link geklickt
cta-click { url: string } "Projekt starten" Button geklickt
logout {} Abmelden geklickt
language-change { language: string } Sprache gewechselt
scroll-state-change { scrolled: boolean, slideUp: boolean } Scroll-Zustand geändert
color-mode-change { mode: 'light' | 'dark' } Farbmodus gewechselt (per Toggle-Button)

Usage Examples:

<!-- Default: dunkler Header (dunkle Schrift für helle Seiten) -->
<startnext-header></startnext-header>

<!-- Heller Header (weiße Schrift über dunklem Hero) -->
<startnext-header light></startnext-header>

<!-- Heller Header + große Animation (z.B. Startseite) -->
<startnext-header light large-animation></startnext-header>

<!-- Heller Header + groß + eingeloggt -->
<startnext-header
  light
  large-animation
  authenticated
  user-name="Elias Groesel"
  user-avatar="https://..."
></startnext-header>
<!-- Color Mode: Header scannt <html> automatisch -->
<!-- html.dark → heller Header, html.light → dunkler Header -->
<!-- Toggle-Button (Sun/Moon) im Header wechselt den Modus -->
<html class="dark">
  <startnext-header light large-animation></startnext-header>
</html>
<!-- Embedded / Microservice-Modus: Login ausblenden, Back-Link anzeigen -->
<startnext-header
  hide-login
  show-back-link
  back-url="https://www.startnext.com"
  back-label="Zurueck zu Startnext"
  api-url="https://scs-api.vercel.app"
></startnext-header>
const header = document.querySelector('startnext-header');

header.addEventListener('navigation-click', (e) => {
  console.log(e.detail.item);
  // e.preventDefault() to handle navigation yourself
});

header.addEventListener('language-change', (e) => {
  // Footer synchronisiert Sprache automatisch (lang-sync ist default true).
  // Manuelle Synchronisation nur noetig wenn lang-sync="false" gesetzt ist:
  // document.querySelector('startnext-footer').setAttribute('lang', e.detail.language);
});

header.addEventListener('logout', () => {
  // Handle logout
});

header.addEventListener('color-mode-change', (e) => {
  console.log(`Color mode: ${e.detail.mode}`); // 'light' | 'dark'
  // <html>-Klasse wird automatisch vom Header gesetzt
});

Attributes:

Attribute Type Default Description
lang string 'de' Sprache ('de', 'en')
api-url string - API-Endpoint-URL fuer Live-Daten
lang-sync boolean true Synchronisiert Sprache automatisch wenn der Header ein language-change Event emittiert. Mit lang-sync="false" deaktivieren

Events:

Event Detail Description
navigation-click { item: { url, label } } Footer-Link geklickt

Theming

Override CSS Custom Properties:

startnext-header {
  --primary-color: #0066FF;
  --btn-primary-bg: #0066FF;
  --header-bg-scrolled: #FAFAFA;
}

startnext-footer {
  --footer-bg: #111111;
  --footer-link-hover: #0066FF;
}

Fonts

Standardmäßig nutzen die Components System-Fonts als Fallback. Für eigene Schriftarten @font-face im eigenen CSS deklarieren und --font-family setzen:

@font-face {
  font-family: "PFDin";
  font-weight: 400;
  font-style: normal;
  font-display: swap;
  src: url("/fonts/PFDin-subset.woff2") format("woff2");
}

startnext-header, startnext-footer {
  --font-family: "PFDin", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
}

Server-Side Rendering (SSR)

Das Paket exportiert einen server-sicheren Subpath @startnext/chrome/render mit reinen String-Funktionen (keine Browser-Abhaengigkeiten). Damit kann der API-Server fertig gerendertes HTML per Declarative Shadow DOM erzeugen.

Render Entry Point

import {
  renderHeader, renderBurgerItems, renderUserItems,
  renderFooter,
  headerCSS, footerCSS,
  renderHeaderCrawlerNav, renderFooterCrawlerNav,
  toHeaderRenderData, toFooterRenderData,
  getUiString, getIcon,
} from '@startnext/chrome/render';

Exports

Export Beschreibung
renderHeader(props) Header Shadow DOM HTML
renderBurgerItems(data, expandedSections) Burger-Menue Items HTML
renderUserItems(data, expandedSections) User-Menue Items HTML
renderFooter(data) Footer Shadow DOM HTML
headerCSS, footerCSS, resetCSS CSS als Strings
getIcon(name, size?) SVG-Icon als String
getUiString(key, lang) UI-String (ARIA Labels etc.)
toHeaderRenderData(apiData) API-Daten → HeaderData (fuegt stub theme hinzu)
toFooterRenderData(apiData) API-Daten → FooterData (fuegt stub theme hinzu)
renderHeaderCrawlerNav(data) Crawler-<nav> fuer Header (Light DOM, SEO)
renderFooterCrawlerNav(data) Crawler-<nav> fuer Footer (Light DOM, SEO)

Hydration

Wenn der Server HTML mit Declarative Shadow DOM (<template shadowrootmode="open">) liefert, erkennt die Web Component den bestehenden shadowRoot und hydriert statt neu zu rendern:

  1. Browser parst DSD → shadowRoot existiert vor dem Custom-Element-Constructor
  2. BaseComponent erkennt bestehenden shadowRoot, setzt isHydrating = true
  3. render() ueberspringt innerHTML, ruft nur attachEvents() auf
  4. connectedCallback() erkennt bestehenden [data-crawler-nav], ueberspringt renderLightDomNav()
  5. loadApiData() holt frische Daten → loest danach ein vollstaendiges Re-Render aus
<!-- Server liefert fertiges HTML -->
<startnext-header lang="de" light large-animation>
  <template shadowrootmode="open">
    <style>/* headerCSS */</style>
    <div><!-- Shadow DOM HTML --></div>
  </template>
  <nav data-crawler-nav aria-hidden="true" style="display:none">
    <!-- SEO-Links -->
  </nav>
</startnext-header>

<!-- JS hydriert automatisch -->
<script type="module" src="@startnext/chrome"></script>

Browser Support

  • Chrome/Edge 90+ (Declarative Shadow DOM: Chrome 90+, Firefox 123+, Safari 16.4+)
  • Firefox 88+ (123+ fuer SSR/Hydration)
  • Safari 14+ (16.4+ fuer SSR/Hydration)

Development

# Install deps (from monorepo root)
pnpm install

# Dev mode (watch)
pnpm --filter @startnext/chrome dev

# Build
pnpm --filter @startnext/chrome build

# Lint
pnpm --filter @startnext/chrome lint

Demo-Seite oeffnen: demo/index.html

Architecture

Jede Component ist modular in drei Dateien aufgeteilt:

src/
├── components/
│   ├── base/
│   │   ├── BaseComponent.ts    # Abstrakte Basis (Shadow DOM, DSD-Hydration, Events, Theming)
│   │   ├── icons.ts            # SVG-Icon-Registry
│   │   └── styles.ts           # Shared Reset-CSS
│   ├── header/
│   │   ├── StartnextHeader.ts  # Logik (Scroll, Drawers, Lottie, Events, Hydration)
│   │   ├── header.css.ts       # CSS als Template-Literal-Export
│   │   └── header.template.ts  # Render-Funktionen (HTML-Strings)
│   └── footer/
│       ├── StartnextFooter.ts  # Logik (Render, Events, Hydration)
│       ├── footer.css.ts       # CSS als Template-Literal-Export
│       └── footer.template.ts  # Render-Funktion (HTML-String)
├── data/
│   ├── mockData.ts             # Mock-Daten
│   └── uiStrings.ts            # UI-Strings (ARIA Labels, de/en)
├── types/
│   └── index.ts                # Alle TypeScript-Interfaces
├── index.ts                    # Browser-Entry (Custom Elements registrieren)
└── render.ts                   # Server-Entry (reine String-Funktionen, kein Browser)

Konventionen:

  • CSS in *.css.ts als exportierter Template-Literal-String (kein extra Build-Plugin noetig)
  • Templates in *.template.ts als reine Funktionen die HTML-Strings zurueckgeben (server-safe)
  • Logik in der Hauptdatei: Event-Handling, State, Lifecycle, Hydration
  • BEM-Naming fuer CSS-Klassen (headbar__left, drawer__item--highlighted)
  • Shadow DOM (open mode), kein Virtual DOM, Declarative Shadow DOM fuer SSR

Zwei Entry Points:

  • src/index.tsdist/index.js (ESM) + dist/index.umd.js (UMD) — Browser, registriert Custom Elements
  • src/render.tsdist/render.js (ESM) — Server, reine String-Funktionen ohne Browser-Abhaengigkeiten

Monorepo Structure

packages/
  scs-web-component/   ← dieses Paket
  scs-api/             ← Express API Service (nutzt @startnext/chrome/render fuer SSR)