@startnext/chrome 0.3.4 → 0.3.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +38 -397
- package/dist/components/base/BaseComponent.d.ts +0 -2
- package/dist/components/base/BaseComponent.d.ts.map +1 -1
- package/dist/components/footer/StartnextFooter.d.ts +0 -3
- package/dist/components/footer/StartnextFooter.d.ts.map +1 -1
- package/dist/components/header/StartnextHeader.d.ts +0 -3
- package/dist/components/header/StartnextHeader.d.ts.map +1 -1
- package/dist/components/header/header.css.d.ts +1 -1
- package/dist/components/header/header.css.d.ts.map +1 -1
- package/dist/components/header/header.template.d.ts +4 -0
- package/dist/components/header/header.template.d.ts.map +1 -1
- package/dist/index.d.ts +0 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.umd.js +2 -2
- package/dist/render.js +1 -1
- package/package.json +9 -18
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
> Startnext Header/Footer Web Components
|
|
4
4
|
|
|
5
|
-
Wiederverwendbare Header- und Footer-Components
|
|
5
|
+
Wiederverwendbare Header- und Footer-Components für alle Startnext Microservices.
|
|
6
6
|
|
|
7
7
|
## Installation
|
|
8
8
|
|
|
@@ -14,41 +14,24 @@ pnpm add @startnext/chrome
|
|
|
14
14
|
|
|
15
15
|
## Quick Start
|
|
16
16
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
1. **Client-Side Rendering** — Web Component fetcht Daten selbst (einfach, kein Server noetig)
|
|
20
|
-
2. **Server-Side Rendering (SSR)** — Server holt fertig gerendertes HTML von der API (sofort sichtbar ohne JS, bessere Performance + SEO)
|
|
21
|
-
|
|
22
|
-
### Client-Side: Via CDN (PHP, Vanilla HTML)
|
|
23
|
-
```html
|
|
24
|
-
<script type="module" src="https://unpkg.com/@startnext/chrome@latest/dist/index.js"></script>
|
|
25
|
-
|
|
26
|
-
<startnext-header api-url="https://scs-api.vercel.app"></startnext-header>
|
|
27
|
-
<startnext-footer api-url="https://scs-api.vercel.app"></startnext-footer>
|
|
28
|
-
```
|
|
29
|
-
|
|
30
|
-
### Client-Side: Modern JavaScript (React, Vue, etc.)
|
|
17
|
+
### Modern JavaScript (React, Vue, etc.)
|
|
31
18
|
```javascript
|
|
32
19
|
import '@startnext/chrome';
|
|
33
20
|
```
|
|
34
21
|
|
|
35
22
|
```html
|
|
36
|
-
<startnext-header
|
|
37
|
-
<startnext-footer
|
|
23
|
+
<startnext-header></startnext-header>
|
|
24
|
+
<startnext-footer></startnext-footer>
|
|
38
25
|
```
|
|
39
26
|
|
|
40
|
-
###
|
|
41
|
-
|
|
42
|
-
|
|
27
|
+
### Via CDN (PHP, Vanilla HTML)
|
|
28
|
+
```html
|
|
29
|
+
<script type="module" src="https://unpkg.com/@startnext/chrome@latest/dist/index.js"></script>
|
|
43
30
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
curl "https://scs-api.vercel.app/api/header/render?lang=de&large-animation"
|
|
47
|
-
curl "https://scs-api.vercel.app/api/footer/render?lang=de"
|
|
31
|
+
<startnext-header></startnext-header>
|
|
32
|
+
<startnext-footer></startnext-footer>
|
|
48
33
|
```
|
|
49
34
|
|
|
50
|
-
Siehe Framework-spezifische Beispiele: [React / Next.js](#react--nextjs-app-router), [Vue / Nuxt](#vue--nuxt-3), [PHP / Vanilla](#php--vanilla-html)
|
|
51
|
-
|
|
52
35
|
## API
|
|
53
36
|
|
|
54
37
|
### `<startnext-header>`
|
|
@@ -58,46 +41,41 @@ Siehe Framework-spezifische Beispiele: [React / Next.js](#react--nextjs-app-rout
|
|
|
58
41
|
| Attribute | Type | Default | Description |
|
|
59
42
|
|---|---|---|---|
|
|
60
43
|
| `lang` | `string` | `'de'` | Sprache (`'de'`, `'en'`) |
|
|
61
|
-
| `light` | `boolean` | `false` | Heller Header (
|
|
62
|
-
| `large-animation` | `boolean` | `false` |
|
|
44
|
+
| `light` | `boolean` | `false` | Heller Header (weiße Schrift/Icons über dunklem Hero, wechselt automatisch zu dunkel beim Scrollen). Standard ohne Attribut: dunkler Header |
|
|
45
|
+
| `large-animation` | `boolean` | `false` | Große Lottie-Logo-Animation mit Claim und horizontaler Navigation |
|
|
63
46
|
| `authenticated` | `boolean` | `false` | Zeigt User-Avatar statt "Anmelden" Button |
|
|
64
47
|
| `user-name` | `string` | - | Name des eingeloggten Users |
|
|
65
48
|
| `user-avatar` | `string` | - | Avatar-URL des Users |
|
|
66
49
|
| `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 |
|
|
67
50
|
| `hide-color-mode` | `boolean` | `false` | Versteckt den Color-Mode Toggle-Button |
|
|
68
51
|
| `hide-lang` | `boolean` | `false` | Versteckt den Language-Switcher |
|
|
69
|
-
| `hide-login` | `boolean` | `false` | Versteckt den Login/Avatar-Button |
|
|
70
|
-
| `show-back-link` | `boolean` | `false` | Zeigt einen "Zurueck zu Startnext"-Link (Text kommt von der API) |
|
|
71
|
-
| `back-url` | `string` | - | Ueberschreibt die Back-Link-URL |
|
|
72
|
-
| `back-label` | `string` | - | Ueberschreibt den Back-Link-Text |
|
|
73
|
-
| `api-url` | `string` | - | API-Endpoint-URL fuer Live-Daten aus Notion (nicht noetig bei SSR) |
|
|
74
52
|
|
|
75
53
|
**Events:**
|
|
76
54
|
|
|
77
55
|
| Event | Detail | Description |
|
|
78
56
|
|---|---|---|
|
|
79
|
-
| `burger-menu-toggle` | `{ open: boolean }` | Burger-
|
|
80
|
-
| `user-menu-toggle` | `{ open: boolean }` | User-
|
|
57
|
+
| `burger-menu-toggle` | `{ open: boolean }` | Burger-Menü geöffnet/geschlossen |
|
|
58
|
+
| `user-menu-toggle` | `{ open: boolean }` | User-Menü geöffnet/geschlossen |
|
|
81
59
|
| `navigation-click` | `{ item: NavigationItem }` | Navigation-Link geklickt |
|
|
82
60
|
| `cta-click` | `{ url: string }` | "Projekt starten" Button geklickt |
|
|
83
61
|
| `logout` | `{}` | Abmelden geklickt |
|
|
84
62
|
| `language-change` | `{ language: string }` | Sprache gewechselt |
|
|
85
|
-
| `scroll-state-change` | `{ scrolled: boolean, slideUp: boolean }` | Scroll-Zustand
|
|
63
|
+
| `scroll-state-change` | `{ scrolled: boolean, slideUp: boolean }` | Scroll-Zustand geändert |
|
|
86
64
|
| `color-mode-change` | `{ mode: 'light' \| 'dark' }` | Farbmodus gewechselt (per Toggle-Button) |
|
|
87
65
|
|
|
88
66
|
**Usage Examples:**
|
|
89
67
|
|
|
90
68
|
```html
|
|
91
|
-
<!-- Default: dunkler Header (dunkle Schrift
|
|
69
|
+
<!-- Default: dunkler Header (dunkle Schrift für helle Seiten) -->
|
|
92
70
|
<startnext-header></startnext-header>
|
|
93
71
|
|
|
94
|
-
<!-- Heller Header (
|
|
72
|
+
<!-- Heller Header (weiße Schrift über dunklem Hero) -->
|
|
95
73
|
<startnext-header light></startnext-header>
|
|
96
74
|
|
|
97
|
-
<!-- Heller Header +
|
|
75
|
+
<!-- Heller Header + große Animation (z.B. Startseite) -->
|
|
98
76
|
<startnext-header light large-animation></startnext-header>
|
|
99
77
|
|
|
100
|
-
<!-- Heller Header +
|
|
78
|
+
<!-- Heller Header + groß + eingeloggt -->
|
|
101
79
|
<startnext-header
|
|
102
80
|
light
|
|
103
81
|
large-animation
|
|
@@ -116,17 +94,6 @@ Siehe Framework-spezifische Beispiele: [React / Next.js](#react--nextjs-app-rout
|
|
|
116
94
|
</html>
|
|
117
95
|
```
|
|
118
96
|
|
|
119
|
-
```html
|
|
120
|
-
<!-- Embedded / Microservice-Modus: Login ausblenden, Back-Link anzeigen -->
|
|
121
|
-
<startnext-header
|
|
122
|
-
hide-login
|
|
123
|
-
show-back-link
|
|
124
|
-
back-url="https://www.startnext.com"
|
|
125
|
-
back-label="Zurueck zu Startnext"
|
|
126
|
-
api-url="https://scs-api.vercel.app"
|
|
127
|
-
></startnext-header>
|
|
128
|
-
```
|
|
129
|
-
|
|
130
97
|
```javascript
|
|
131
98
|
const header = document.querySelector('startnext-header');
|
|
132
99
|
|
|
@@ -136,9 +103,8 @@ header.addEventListener('navigation-click', (e) => {
|
|
|
136
103
|
});
|
|
137
104
|
|
|
138
105
|
header.addEventListener('language-change', (e) => {
|
|
139
|
-
//
|
|
140
|
-
|
|
141
|
-
// document.querySelector('startnext-footer').setAttribute('lang', e.detail.language);
|
|
106
|
+
// Sprache auch im Footer synchronisieren
|
|
107
|
+
document.querySelector('startnext-footer').setAttribute('lang', e.detail.language);
|
|
142
108
|
});
|
|
143
109
|
|
|
144
110
|
header.addEventListener('logout', () => {
|
|
@@ -158,8 +124,6 @@ header.addEventListener('color-mode-change', (e) => {
|
|
|
158
124
|
| Attribute | Type | Default | Description |
|
|
159
125
|
|---|---|---|---|
|
|
160
126
|
| `lang` | `string` | `'de'` | Sprache (`'de'`, `'en'`) |
|
|
161
|
-
| `api-url` | `string` | - | API-Endpoint-URL fuer Live-Daten (nicht noetig bei SSR) |
|
|
162
|
-
| `lang-sync` | `boolean` | `true` | Synchronisiert Sprache automatisch wenn der Header ein `language-change` Event emittiert. Mit `lang-sync="false"` deaktivieren |
|
|
163
127
|
|
|
164
128
|
**Events:**
|
|
165
129
|
|
|
@@ -186,7 +150,7 @@ startnext-footer {
|
|
|
186
150
|
|
|
187
151
|
## Fonts
|
|
188
152
|
|
|
189
|
-
|
|
153
|
+
Standardmäßig nutzen die Components System-Fonts als Fallback. Für eigene Schriftarten `@font-face` im eigenen CSS deklarieren und `--font-family` setzen:
|
|
190
154
|
|
|
191
155
|
```css
|
|
192
156
|
@font-face {
|
|
@@ -202,329 +166,11 @@ startnext-header, startnext-footer {
|
|
|
202
166
|
}
|
|
203
167
|
```
|
|
204
168
|
|
|
205
|
-
## Server-Side Rendering (SSR)
|
|
206
|
-
|
|
207
|
-
Die API liefert fertig gerendertes HTML mit **Declarative Shadow DOM** (`<template shadowrootmode="open">`) und eingebetteten **API-Daten als JSON** (`<script data-ssr-props>`). Der Browser zeigt den Content sofort an — ohne JavaScript. Die Web Component JS hydriert anschliessend (Events anbinden, kein Re-Render noetig).
|
|
208
|
-
|
|
209
|
-
### Wie es funktioniert
|
|
210
|
-
|
|
211
|
-
1. Server fetcht SSR-HTML von `/api/header/render` bzw. `/api/footer/render`
|
|
212
|
-
2. HTML wird direkt in die Seite eingebunden
|
|
213
|
-
3. Browser parst DSD → Shadow DOM existiert sofort, Content ist sichtbar
|
|
214
|
-
4. Web Component JS laedt → erkennt bestehenden `shadowRoot`, setzt `isHydrating = true`
|
|
215
|
-
5. `render()` ueberspringt `innerHTML`, ruft nur `attachEvents()` auf
|
|
216
|
-
6. `parseSsrProps()` liest eingebettetes JSON → populiert API-Cache mit echten Daten
|
|
217
|
-
7. Attribut-Aenderungen (z.B. `color-mode`, `large-animation`) funktionieren sofort — kein Client-Fetch noetig
|
|
218
|
-
|
|
219
|
-
```html
|
|
220
|
-
<!-- Server liefert fertiges HTML (vereinfacht) -->
|
|
221
|
-
<startnext-header lang="de" light large-animation>
|
|
222
|
-
<template shadowrootmode="open">
|
|
223
|
-
<style>/* headerCSS */</style>
|
|
224
|
-
<div><!-- Shadow DOM HTML --></div>
|
|
225
|
-
</template>
|
|
226
|
-
<script type="application/json" data-ssr-props>{"mainNavigation":[...],...}</script>
|
|
227
|
-
</startnext-header>
|
|
228
|
-
|
|
229
|
-
<!-- JS hydriert automatisch -->
|
|
230
|
-
<script type="module" src="@startnext/chrome"></script>
|
|
231
|
-
```
|
|
232
|
-
|
|
233
|
-
### Render-Endpoints (Query-Parameter)
|
|
234
|
-
|
|
235
|
-
**Header:** `GET /api/header/render`
|
|
236
|
-
|
|
237
|
-
| Parameter | Typ | Beschreibung |
|
|
238
|
-
|-----------|-----|-------------|
|
|
239
|
-
| `lang` | `de` \| `en` | Sprache |
|
|
240
|
-
| `light` | flag | Heller Header |
|
|
241
|
-
| `large-animation` | flag | Grosse Logo-Animation |
|
|
242
|
-
| `authenticated` | flag | Eingeloggt |
|
|
243
|
-
| `user-name` | string | User-Name |
|
|
244
|
-
| `user-avatar` | string | Avatar-URL |
|
|
245
|
-
| `hide-color-mode` | flag | Color-Mode Toggle verstecken |
|
|
246
|
-
| `hide-lang` | flag | Language-Switcher verstecken |
|
|
247
|
-
| `hide-login` | flag | Login-Button verstecken |
|
|
248
|
-
| `show-back-link` | flag | Back-Link anzeigen |
|
|
249
|
-
| `back-url` | string | Back-Link URL |
|
|
250
|
-
| `back-label` | string | Back-Link Text |
|
|
251
|
-
|
|
252
|
-
**Footer:** `GET /api/footer/render`
|
|
253
|
-
|
|
254
|
-
| Parameter | Typ | Beschreibung |
|
|
255
|
-
|-----------|-----|-------------|
|
|
256
|
-
| `lang` | `de` \| `en` | Sprache |
|
|
257
|
-
|
|
258
|
-
Beispiel: `GET /api/header/render?lang=de&large-animation&hide-login&show-back-link`
|
|
259
|
-
|
|
260
|
-
### `api-url` bei SSR nicht noetig
|
|
261
|
-
|
|
262
|
-
Bei SSR werden die API-Daten als JSON im HTML eingebettet (`<script data-ssr-props>`). Der Component liest das beim Hydrating und hat sofort echte Daten im Cache. `api-url` ist daher **nicht noetig** — der Component rendert und reagiert auf Attribut-Aenderungen ohne zusaetzlichen Fetch.
|
|
263
|
-
|
|
264
|
-
`api-url` ist nur fuer **Client-Side-Only** Rendering relevant, wenn kein SSR-HTML verfuegbar ist.
|
|
265
|
-
|
|
266
|
-
---
|
|
267
|
-
|
|
268
|
-
## Framework-Integration (SSR)
|
|
269
|
-
|
|
270
|
-
### React / Next.js (App Router)
|
|
271
|
-
|
|
272
|
-
React's `dangerouslySetInnerHTML` nutzt `innerHTML`, das DSD nicht parsed. Nach der Hydration wird `setHTMLUnsafe()` als Fallback aufgerufen.
|
|
273
|
-
|
|
274
|
-
**Layout (Server Component):**
|
|
275
|
-
|
|
276
|
-
```tsx
|
|
277
|
-
// app/[locale]/layout.tsx
|
|
278
|
-
async function fetchChromeHtml(path: string): Promise<string> {
|
|
279
|
-
try {
|
|
280
|
-
const res = await fetch(`${process.env.NEXT_PUBLIC_SCS_API_URL}${path}`, {
|
|
281
|
-
next: { revalidate: 60 },
|
|
282
|
-
});
|
|
283
|
-
if (!res.ok) return "";
|
|
284
|
-
return await res.text();
|
|
285
|
-
} catch {
|
|
286
|
-
return "";
|
|
287
|
-
}
|
|
288
|
-
}
|
|
289
|
-
|
|
290
|
-
export default async function Layout({ children, params }) {
|
|
291
|
-
const { locale } = await params;
|
|
292
|
-
const [headerHtml, footerHtml] = await Promise.all([
|
|
293
|
-
fetchChromeHtml(`/api/header/render?lang=${locale}&large-animation`),
|
|
294
|
-
fetchChromeHtml(`/api/footer/render?lang=${locale}`),
|
|
295
|
-
]);
|
|
296
|
-
|
|
297
|
-
return (
|
|
298
|
-
<html lang={locale}>
|
|
299
|
-
<body>
|
|
300
|
-
<ChromeHeader ssrHtml={headerHtml} />
|
|
301
|
-
<main>{children}</main>
|
|
302
|
-
<ChromeFooter ssrHtml={footerHtml} />
|
|
303
|
-
</body>
|
|
304
|
-
</html>
|
|
305
|
-
);
|
|
306
|
-
}
|
|
307
|
-
```
|
|
308
|
-
|
|
309
|
-
**Header (Client Component):**
|
|
310
|
-
|
|
311
|
-
```tsx
|
|
312
|
-
// components/ChromeHeader.tsx
|
|
313
|
-
"use client";
|
|
314
|
-
import { useEffect, useRef, useState } from "react";
|
|
315
|
-
|
|
316
|
-
export function ChromeHeader({ ssrHtml }: { ssrHtml?: string }) {
|
|
317
|
-
const containerRef = useRef<HTMLDivElement>(null);
|
|
318
|
-
const [mounted, setMounted] = useState(false);
|
|
319
|
-
|
|
320
|
-
useEffect(() => {
|
|
321
|
-
const container = containerRef.current;
|
|
322
|
-
if (container && ssrHtml) {
|
|
323
|
-
const header = container.querySelector("startnext-header");
|
|
324
|
-
if (!header?.shadowRoot && "setHTMLUnsafe" in Element.prototype) {
|
|
325
|
-
container.setHTMLUnsafe(ssrHtml);
|
|
326
|
-
}
|
|
327
|
-
}
|
|
328
|
-
import("@startnext/chrome");
|
|
329
|
-
setMounted(true);
|
|
330
|
-
}, [ssrHtml]);
|
|
331
|
-
|
|
332
|
-
// Attribut-Sync nach Mount (z.B. color-mode, large-animation)
|
|
333
|
-
useEffect(() => {
|
|
334
|
-
const el = containerRef.current?.querySelector("startnext-header");
|
|
335
|
-
if (!el || !mounted) return;
|
|
336
|
-
// Beispiel: el.setAttribute("color-mode", resolvedTheme);
|
|
337
|
-
}, [mounted]);
|
|
338
|
-
|
|
339
|
-
if (ssrHtml) {
|
|
340
|
-
return (
|
|
341
|
-
<div ref={containerRef} style={{ display: "contents" }}
|
|
342
|
-
suppressHydrationWarning
|
|
343
|
-
dangerouslySetInnerHTML={{ __html: ssrHtml }}
|
|
344
|
-
/>
|
|
345
|
-
);
|
|
346
|
-
}
|
|
347
|
-
|
|
348
|
-
// Fallback ohne SSR
|
|
349
|
-
return <startnext-header api-url={process.env.NEXT_PUBLIC_SCS_API_URL} />;
|
|
350
|
-
}
|
|
351
|
-
```
|
|
352
|
-
|
|
353
|
-
**Footer (Client Component):**
|
|
354
|
-
|
|
355
|
-
```tsx
|
|
356
|
-
// components/ChromeFooter.tsx
|
|
357
|
-
"use client";
|
|
358
|
-
import { useEffect, useRef } from "react";
|
|
359
|
-
|
|
360
|
-
export function ChromeFooter({ ssrHtml }: { ssrHtml?: string }) {
|
|
361
|
-
const containerRef = useRef<HTMLDivElement>(null);
|
|
362
|
-
|
|
363
|
-
useEffect(() => {
|
|
364
|
-
const container = containerRef.current;
|
|
365
|
-
if (container && ssrHtml) {
|
|
366
|
-
const footer = container.querySelector("startnext-footer");
|
|
367
|
-
if (!footer?.shadowRoot && "setHTMLUnsafe" in Element.prototype) {
|
|
368
|
-
container.setHTMLUnsafe(ssrHtml);
|
|
369
|
-
}
|
|
370
|
-
}
|
|
371
|
-
import("@startnext/chrome");
|
|
372
|
-
}, [ssrHtml]);
|
|
373
|
-
|
|
374
|
-
if (ssrHtml) {
|
|
375
|
-
return (
|
|
376
|
-
<div ref={containerRef} style={{ display: "contents" }}
|
|
377
|
-
suppressHydrationWarning
|
|
378
|
-
dangerouslySetInnerHTML={{ __html: ssrHtml }}
|
|
379
|
-
/>
|
|
380
|
-
);
|
|
381
|
-
}
|
|
382
|
-
|
|
383
|
-
return <startnext-footer api-url={process.env.NEXT_PUBLIC_SCS_API_URL} />;
|
|
384
|
-
}
|
|
385
|
-
```
|
|
386
|
-
|
|
387
|
-
### Vue / Nuxt 3
|
|
388
|
-
|
|
389
|
-
Vue parsed DSD korrekt via `v-html` — kein `setHTMLUnsafe()` Workaround noetig.
|
|
390
|
-
|
|
391
|
-
**Server Plugin (SSR-HTML fetchen):**
|
|
392
|
-
|
|
393
|
-
```ts
|
|
394
|
-
// server/plugins/chrome.ts
|
|
395
|
-
export default defineEventHandler(async (event) => {
|
|
396
|
-
// Wird automatisch von useAsyncData / useFetch aufgerufen
|
|
397
|
-
});
|
|
398
|
-
```
|
|
399
|
-
|
|
400
|
-
**Layout:**
|
|
401
|
-
|
|
402
|
-
```vue
|
|
403
|
-
<!-- layouts/default.vue -->
|
|
404
|
-
<script setup lang="ts">
|
|
405
|
-
const { locale } = useI18n();
|
|
406
|
-
const config = useRuntimeConfig();
|
|
407
|
-
|
|
408
|
-
const { data: headerHtml } = await useFetch(
|
|
409
|
-
() => `${config.public.scsApiUrl}/api/header/render?lang=${locale.value}&large-animation`,
|
|
410
|
-
{ key: `chrome-header-${locale.value}` }
|
|
411
|
-
);
|
|
412
|
-
|
|
413
|
-
const { data: footerHtml } = await useFetch(
|
|
414
|
-
() => `${config.public.scsApiUrl}/api/footer/render?lang=${locale.value}`,
|
|
415
|
-
{ key: `chrome-footer-${locale.value}` }
|
|
416
|
-
);
|
|
417
|
-
|
|
418
|
-
onMounted(() => {
|
|
419
|
-
import('@startnext/chrome');
|
|
420
|
-
});
|
|
421
|
-
</script>
|
|
422
|
-
|
|
423
|
-
<template>
|
|
424
|
-
<div v-if="headerHtml" v-html="headerHtml" style="display: contents" />
|
|
425
|
-
<startnext-header v-else :lang="locale" :api-url="config.public.scsApiUrl" />
|
|
426
|
-
|
|
427
|
-
<main>
|
|
428
|
-
<slot />
|
|
429
|
-
</main>
|
|
430
|
-
|
|
431
|
-
<div v-if="footerHtml" v-html="footerHtml" style="display: contents" />
|
|
432
|
-
<startnext-footer v-else :lang="locale" :api-url="config.public.scsApiUrl" />
|
|
433
|
-
</template>
|
|
434
|
-
```
|
|
435
|
-
|
|
436
|
-
**Nuxt Config (Custom Elements registrieren):**
|
|
437
|
-
|
|
438
|
-
```ts
|
|
439
|
-
// nuxt.config.ts
|
|
440
|
-
export default defineNuxtConfig({
|
|
441
|
-
vue: {
|
|
442
|
-
compilerOptions: {
|
|
443
|
-
isCustomElement: (tag) => tag.startsWith('startnext-'),
|
|
444
|
-
},
|
|
445
|
-
},
|
|
446
|
-
runtimeConfig: {
|
|
447
|
-
public: {
|
|
448
|
-
scsApiUrl: process.env.SCS_API_URL || 'https://scs-api.vercel.app',
|
|
449
|
-
},
|
|
450
|
-
},
|
|
451
|
-
});
|
|
452
|
-
```
|
|
453
|
-
|
|
454
|
-
### PHP / Vanilla HTML
|
|
455
|
-
|
|
456
|
-
```php
|
|
457
|
-
<?php
|
|
458
|
-
$apiUrl = 'https://scs-api.vercel.app';
|
|
459
|
-
$lang = 'de';
|
|
460
|
-
|
|
461
|
-
$headerHtml = @file_get_contents("$apiUrl/api/header/render?lang=$lang&large-animation");
|
|
462
|
-
$footerHtml = @file_get_contents("$apiUrl/api/footer/render?lang=$lang");
|
|
463
|
-
?>
|
|
464
|
-
<!DOCTYPE html>
|
|
465
|
-
<html lang="<?= $lang ?>">
|
|
466
|
-
<head>
|
|
467
|
-
<script type="module" src="https://unpkg.com/@startnext/chrome@latest/dist/index.js"></script>
|
|
468
|
-
</head>
|
|
469
|
-
<body>
|
|
470
|
-
<?= $headerHtml ?: '<startnext-header api-url="' . $apiUrl . '"></startnext-header>' ?>
|
|
471
|
-
|
|
472
|
-
<main><!-- Content --></main>
|
|
473
|
-
|
|
474
|
-
<?= $footerHtml ?: '<startnext-footer api-url="' . $apiUrl . '"></startnext-footer>' ?>
|
|
475
|
-
</body>
|
|
476
|
-
</html>
|
|
477
|
-
```
|
|
478
|
-
|
|
479
|
-
### Edge Side Includes (ESI)
|
|
480
|
-
|
|
481
|
-
```html
|
|
482
|
-
<!-- Varnish / CDN ESI -->
|
|
483
|
-
<esi:try>
|
|
484
|
-
<esi:attempt>
|
|
485
|
-
<esi:include src="/api/header/render?lang=de&large-animation" />
|
|
486
|
-
</esi:attempt>
|
|
487
|
-
<esi:except>
|
|
488
|
-
<startnext-header api-url="https://scs-api.vercel.app"></startnext-header>
|
|
489
|
-
</esi:except>
|
|
490
|
-
</esi:try>
|
|
491
|
-
```
|
|
492
|
-
|
|
493
|
-
---
|
|
494
|
-
|
|
495
|
-
## Render Entry Point (Server-seitig)
|
|
496
|
-
|
|
497
|
-
Das Paket exportiert einen server-sicheren Subpath `@startnext/chrome/render` mit reinen String-Funktionen (keine Browser-Abhaengigkeiten):
|
|
498
|
-
|
|
499
|
-
```javascript
|
|
500
|
-
import {
|
|
501
|
-
renderHeader, renderBurgerItems, renderUserItems,
|
|
502
|
-
renderFooter,
|
|
503
|
-
headerCSS, footerCSS,
|
|
504
|
-
toHeaderRenderData, toFooterRenderData,
|
|
505
|
-
getUiString, getIcon,
|
|
506
|
-
} from '@startnext/chrome/render';
|
|
507
|
-
```
|
|
508
|
-
|
|
509
|
-
| Export | Beschreibung |
|
|
510
|
-
|--------|-------------|
|
|
511
|
-
| `renderHeader(props)` | Header Shadow DOM HTML |
|
|
512
|
-
| `renderBurgerItems(data, expandedSections)` | Burger-Menue Items HTML |
|
|
513
|
-
| `renderUserItems(data, expandedSections)` | User-Menue Items HTML |
|
|
514
|
-
| `renderFooter(data)` | Footer Shadow DOM HTML |
|
|
515
|
-
| `headerCSS`, `footerCSS`, `resetCSS` | CSS als Strings |
|
|
516
|
-
| `getIcon(name, size?)` | SVG-Icon als String |
|
|
517
|
-
| `getUiString(key, lang)` | UI-String (ARIA Labels etc.) |
|
|
518
|
-
| `toHeaderRenderData(apiData)` | API-Daten -> HeaderData (fuegt stub `theme` hinzu) |
|
|
519
|
-
| `toFooterRenderData(apiData)` | API-Daten -> FooterData (fuegt stub `theme` hinzu) |
|
|
520
|
-
| `renderHeaderCrawlerNav(data)` | Crawler-`<nav>` fuer Header (optional, fuer Client-Side Rendering) |
|
|
521
|
-
| `renderFooterCrawlerNav(data)` | Crawler-`<nav>` fuer Footer (optional, fuer Client-Side Rendering) |
|
|
522
|
-
|
|
523
169
|
## Browser Support
|
|
524
170
|
|
|
525
|
-
- Chrome/Edge 90+
|
|
526
|
-
- Firefox 88+
|
|
527
|
-
- Safari 14+
|
|
171
|
+
- Chrome/Edge 90+
|
|
172
|
+
- Firefox 88+
|
|
173
|
+
- Safari 14+
|
|
528
174
|
|
|
529
175
|
## Development
|
|
530
176
|
|
|
@@ -542,7 +188,7 @@ pnpm --filter @startnext/chrome build
|
|
|
542
188
|
pnpm --filter @startnext/chrome lint
|
|
543
189
|
```
|
|
544
190
|
|
|
545
|
-
Demo-Seite
|
|
191
|
+
Demo-Seite öffnen: `packages/sn-chrome-web-component/examples/vanilla/index.html`
|
|
546
192
|
|
|
547
193
|
## Architecture
|
|
548
194
|
|
|
@@ -552,41 +198,36 @@ Jede Component ist modular in drei Dateien aufgeteilt:
|
|
|
552
198
|
src/
|
|
553
199
|
├── components/
|
|
554
200
|
│ ├── base/
|
|
555
|
-
│ │ ├── BaseComponent.ts # Abstrakte Basis (Shadow DOM,
|
|
201
|
+
│ │ ├── BaseComponent.ts # Abstrakte Basis (Shadow DOM, Events, Theming)
|
|
556
202
|
│ │ ├── icons.ts # SVG-Icon-Registry
|
|
557
203
|
│ │ └── styles.ts # Shared Reset-CSS
|
|
558
204
|
│ ├── header/
|
|
559
|
-
│ │ ├── StartnextHeader.ts # Logik (Scroll, Drawers, Lottie, Events
|
|
205
|
+
│ │ ├── StartnextHeader.ts # Logik (Scroll, Drawers, Lottie, Events)
|
|
560
206
|
│ │ ├── header.css.ts # CSS als Template-Literal-Export
|
|
561
207
|
│ │ └── header.template.ts # Render-Funktionen (HTML-Strings)
|
|
562
208
|
│ └── footer/
|
|
563
|
-
│ ├── StartnextFooter.ts # Logik (Render, Events
|
|
209
|
+
│ ├── StartnextFooter.ts # Logik (Render, Events)
|
|
564
210
|
│ ├── footer.css.ts # CSS als Template-Literal-Export
|
|
565
211
|
│ └── footer.template.ts # Render-Funktion (HTML-String)
|
|
566
212
|
├── data/
|
|
567
|
-
│
|
|
568
|
-
│ └── uiStrings.ts # UI-Strings (ARIA Labels, de/en)
|
|
213
|
+
│ └── mockData.ts # Mock-Daten
|
|
569
214
|
├── types/
|
|
570
215
|
│ └── index.ts # Alle TypeScript-Interfaces
|
|
571
|
-
|
|
572
|
-
└── render.ts # Server-Entry (reine String-Funktionen, kein Browser)
|
|
216
|
+
└── index.ts # Barrel-Export
|
|
573
217
|
```
|
|
574
218
|
|
|
575
219
|
**Konventionen:**
|
|
576
|
-
- CSS in `*.css.ts` als exportierter Template-Literal-String (kein extra Build-Plugin
|
|
577
|
-
- Templates in `*.template.ts` als reine Funktionen die HTML-Strings
|
|
578
|
-
- Logik in der Hauptdatei: Event-Handling, State, Lifecycle
|
|
579
|
-
- BEM-Naming
|
|
580
|
-
- Shadow DOM (open mode), kein Virtual DOM
|
|
581
|
-
|
|
582
|
-
**Zwei Entry Points:**
|
|
583
|
-
- `src/index.ts` -> `dist/index.js` (ESM) + `dist/index.umd.js` (UMD) — Browser, registriert Custom Elements
|
|
584
|
-
- `src/render.ts` -> `dist/render.js` (ESM) — Server, reine String-Funktionen ohne Browser-Abhaengigkeiten
|
|
220
|
+
- CSS in `*.css.ts` als exportierter Template-Literal-String (kein extra Build-Plugin nötig)
|
|
221
|
+
- Templates in `*.template.ts` als reine Funktionen die HTML-Strings zurückgeben
|
|
222
|
+
- Logik in der Hauptdatei: Event-Handling, State, Lifecycle
|
|
223
|
+
- BEM-Naming für CSS-Klassen (`headbar__left`, `drawer__item--highlighted`)
|
|
224
|
+
- Shadow DOM (open mode), kein Virtual DOM
|
|
585
225
|
|
|
586
226
|
## Monorepo Structure
|
|
587
227
|
|
|
588
228
|
```
|
|
589
229
|
packages/
|
|
590
|
-
scs-web-component/
|
|
591
|
-
scs-api/
|
|
230
|
+
scs-web-component/ ← this package
|
|
231
|
+
scs-api/ ← Express API service
|
|
592
232
|
```
|
|
233
|
+
|
|
@@ -5,8 +5,6 @@ import type { ThemeVariables } from '../../types/index.js';
|
|
|
5
5
|
*/
|
|
6
6
|
export declare abstract class BaseComponent extends HTMLElement {
|
|
7
7
|
protected shadow: ShadowRoot;
|
|
8
|
-
/** True when Declarative Shadow DOM was present — first render should hydrate, not replace. */
|
|
9
|
-
protected isHydrating: boolean;
|
|
10
8
|
constructor();
|
|
11
9
|
/** Emit a typed CustomEvent that bubbles and is composed (crosses shadow DOM). */
|
|
12
10
|
protected emit<T>(name: string, detail: T): boolean;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BaseComponent.d.ts","sourceRoot":"","sources":["../../../src/components/base/BaseComponent.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAE3D;;;GAGG;AACH,8BAAsB,aAAc,SAAQ,WAAW;IACrD,SAAS,CAAC,MAAM,EAAE,UAAU,CAAC
|
|
1
|
+
{"version":3,"file":"BaseComponent.d.ts","sourceRoot":"","sources":["../../../src/components/base/BaseComponent.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAE3D;;;GAGG;AACH,8BAAsB,aAAc,SAAQ,WAAW;IACrD,SAAS,CAAC,MAAM,EAAE,UAAU,CAAC;;IAO7B,kFAAkF;IAClF,SAAS,CAAC,IAAI,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,GAAG,OAAO;IAWnD,mEAAmE;IACnE,SAAS,CAAC,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,UAAQ,GAAG,OAAO;IAM9D,6DAA6D;IAC7D,SAAS,CAAC,UAAU,CAAC,KAAK,EAAE,cAAc,GAAG,IAAI;IAMjD,kDAAkD;IAClD,SAAS,CAAC,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,gBAAgB;CAKrD"}
|
|
@@ -15,9 +15,6 @@ export declare class StartnextFooter extends BaseComponent {
|
|
|
15
15
|
private teardownLangSync;
|
|
16
16
|
/** Return cached API data if available, otherwise defaults (theme only). */
|
|
17
17
|
private getFooterData;
|
|
18
|
-
/** Parse SSR-embedded data to populate the API cache during hydration.
|
|
19
|
-
* Eliminates the need for a client-side fetch when SSR HTML is used. */
|
|
20
|
-
private parseSsrProps;
|
|
21
18
|
/** If api-url is set, fetch footer data from API and re-render. */
|
|
22
19
|
private loadApiData;
|
|
23
20
|
private renderLightDomNav;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"StartnextFooter.d.ts","sourceRoot":"","sources":["../../../src/components/footer/StartnextFooter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAMzD,qBAAa,eAAgB,SAAQ,aAAa;IAChD,MAAM,CAAC,kBAAkB,WAAoC;IAE7D,OAAO,CAAC,IAAI,CAAc;IAC1B,oCAAoC;IACpC,OAAO,CAAC,QAAQ,CAAiC;IACjD,+DAA+D;IAC/D,OAAO,CAAC,gBAAgB,CAAqC;IAE7D,OAAO,KAAK,WAAW,GAEtB;IAED,OAAO,KAAK,eAAe,GAE1B;IAED,iBAAiB,IAAI,IAAI;
|
|
1
|
+
{"version":3,"file":"StartnextFooter.d.ts","sourceRoot":"","sources":["../../../src/components/footer/StartnextFooter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAMzD,qBAAa,eAAgB,SAAQ,aAAa;IAChD,MAAM,CAAC,kBAAkB,WAAoC;IAE7D,OAAO,CAAC,IAAI,CAAc;IAC1B,oCAAoC;IACpC,OAAO,CAAC,QAAQ,CAAiC;IACjD,+DAA+D;IAC/D,OAAO,CAAC,gBAAgB,CAAqC;IAE7D,OAAO,KAAK,WAAW,GAEtB;IAED,OAAO,KAAK,eAAe,GAE1B;IAED,iBAAiB,IAAI,IAAI;IASzB,oBAAoB,IAAI,IAAI;IAK5B,wBAAwB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAe5C,OAAO,CAAC,aAAa;IAQrB,OAAO,CAAC,gBAAgB;IAOxB,4EAA4E;IAC5E,OAAO,CAAC,aAAa;IAMrB,mEAAmE;YACrD,WAAW;IAuBzB,OAAO,CAAC,iBAAiB;IAiCzB,OAAO,CAAC,MAAM;IAWd,OAAO,CAAC,YAAY;CAUrB"}
|
|
@@ -25,9 +25,6 @@ export declare class StartnextHeader extends BaseComponent {
|
|
|
25
25
|
connectedCallback(): void;
|
|
26
26
|
/** Return cached API data if available, otherwise defaults (theme only). */
|
|
27
27
|
private getHeaderData;
|
|
28
|
-
/** Parse SSR-embedded data to populate the API cache during hydration.
|
|
29
|
-
* Eliminates the need for a client-side fetch when SSR HTML is used. */
|
|
30
|
-
private parseSsrProps;
|
|
31
28
|
/** If api-url is set, fetch header data from API and re-render. */
|
|
32
29
|
private loadApiData;
|
|
33
30
|
disconnectedCallback(): void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"StartnextHeader.d.ts","sourceRoot":"","sources":["../../../src/components/header/StartnextHeader.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAWzD,qBAAa,eAAgB,SAAQ,aAAa;IAChD,OAAO,CAAC,IAAI,CAAc;IAC1B,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,WAAW,CAAK;IACxB,OAAO,CAAC,gBAAgB,CAAqB;IAC7C,OAAO,CAAC,UAAU,CAA8B;IAChD,OAAO,CAAC,UAAU,CAAuB;IACzC,6EAA6E;IAC7E,OAAO,CAAC,QAAQ,CAAiC;IAEjD,OAAO,CAAC,iBAAiB,CAAgC;IACzD,OAAO,CAAC,kBAAkB,CAAiC;IAC3D,OAAO,CAAC,iBAAiB,CAAgC;IACzD,OAAO,CAAC,mBAAmB,CAAkC;IAE7D,MAAM,KAAK,kBAAkB,IAAI,MAAM,EAAE,CAExC;IAED,OAAO,CAAC,aAAa,CAAS;IAE9B,OAAO,KAAK,WAAW,GAEtB;IAED,6EAA6E;IAC7E,OAAO,KAAK,aAAa,GAGxB;IAED,OAAO,CAAC,EAAE;IAIV,iBAAiB,IAAI,IAAI;
|
|
1
|
+
{"version":3,"file":"StartnextHeader.d.ts","sourceRoot":"","sources":["../../../src/components/header/StartnextHeader.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAWzD,qBAAa,eAAgB,SAAQ,aAAa;IAChD,OAAO,CAAC,IAAI,CAAc;IAC1B,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,WAAW,CAAK;IACxB,OAAO,CAAC,gBAAgB,CAAqB;IAC7C,OAAO,CAAC,UAAU,CAA8B;IAChD,OAAO,CAAC,UAAU,CAAuB;IACzC,6EAA6E;IAC7E,OAAO,CAAC,QAAQ,CAAiC;IAEjD,OAAO,CAAC,iBAAiB,CAAgC;IACzD,OAAO,CAAC,kBAAkB,CAAiC;IAC3D,OAAO,CAAC,iBAAiB,CAAgC;IACzD,OAAO,CAAC,mBAAmB,CAAkC;IAE7D,MAAM,KAAK,kBAAkB,IAAI,MAAM,EAAE,CAExC;IAED,OAAO,CAAC,aAAa,CAAS;IAE9B,OAAO,KAAK,WAAW,GAEtB;IAED,6EAA6E;IAC7E,OAAO,KAAK,aAAa,GAGxB;IAED,OAAO,CAAC,EAAE;IAIV,iBAAiB,IAAI,IAAI;IAgBzB,4EAA4E;IAC5E,OAAO,CAAC,aAAa;IAMrB,mEAAmE;YACrD,WAAW;IA6BzB,oBAAoB,IAAI,IAAI;IAU5B,wBAAwB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAa5C,gEAAgE;IAChE,OAAO,CAAC,kBAAkB;IAS1B,OAAO,CAAC,kBAAkB;IAU1B,OAAO,CAAC,UAAU;IA0BlB,OAAO,CAAC,YAAY;IAgDpB,OAAO,CAAC,mBAAmB;IAoC3B,OAAO,CAAC,YAAY;IAKpB,OAAO,CAAC,aAAa;IAQrB,OAAO,CAAC,cAAc;IAQtB,OAAO,CAAC,YAAY;IAOpB,OAAO,CAAC,cAAc;IAOtB,OAAO,CAAC,kBAAkB;IAO1B,OAAO,CAAC,SAAS;IAMjB,OAAO,CAAC,cAAc;IAItB,OAAO,CAAC,cAAc;IAItB,OAAO,CAAC,YAAY;IAKpB,OAAO,CAAC,oBAAoB;IAI5B,OAAO,CAAC,cAAc;IAUtB,OAAO,CAAC,YAAY;IAMpB,OAAO,CAAC,kBAAkB;IAW1B,OAAO,CAAC,aAAa;IAmBrB,OAAO,CAAC,eAAe;IAOvB,OAAO,CAAC,cAAc;IA0BtB,OAAO,CAAC,iBAAiB;IAsDzB,OAAO,CAAC,MAAM;IAgCd,OAAO,CAAC,YAAY;CAkErB"}
|