@miragon/slidev-toolkit 1.0.0
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/LICENSE +21 -0
- package/assets/fonts/Geist-Variable.woff2 +0 -0
- package/assets/fonts/GeistMono-Variable.woff2 +0 -0
- package/assets/fonts/LICENSE.txt +92 -0
- package/assets/komet.svg +1 -0
- package/assets/logo.svg +1 -0
- package/components/Agenda.vue +517 -0
- package/components/BrandMeshBackground.vue +159 -0
- package/components/Card.vue +72 -0
- package/components/CardGrid.vue +46 -0
- package/components/Figure.vue +101 -0
- package/components/SplitView.vue +71 -0
- package/components/Step.vue +19 -0
- package/components/StepList.vue +28 -0
- package/layouts/bpmn.vue +162 -0
- package/layouts/closing.vue +127 -0
- package/layouts/compare.vue +214 -0
- package/layouts/content-image.vue +182 -0
- package/layouts/content.vue +186 -0
- package/layouts/cover.vue +114 -0
- package/layouts/goodbad.vue +308 -0
- package/layouts/hero.vue +168 -0
- package/layouts/person.vue +287 -0
- package/layouts/section.vue +127 -0
- package/layouts/showcase.vue +244 -0
- package/package.json +38 -0
- package/styles/fonts.css +23 -0
- package/styles/index.css +25 -0
- package/styles/theme.css +80 -0
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
/**
|
|
3
|
+
* cover — animierte Titelseite.
|
|
4
|
+
* Mesh-Shader als Vollbild-Hintergrund (z0), Content darüber (z2).
|
|
5
|
+
* Slots: default = Titel/Subtitle (aus Markdown). Frontmatter-Props:
|
|
6
|
+
* eyebrow — kleine Überzeile (z. B. "Q2 Review")
|
|
7
|
+
* footer — Footer-Text rechts (z. B. Name · Datum)
|
|
8
|
+
*/
|
|
9
|
+
defineProps<{
|
|
10
|
+
eyebrow?: string
|
|
11
|
+
footer?: string
|
|
12
|
+
}>()
|
|
13
|
+
|
|
14
|
+
// Brand-Asset reist mit dem Theme: statischer Import, von Vite gebundlet und
|
|
15
|
+
// base-aware. Das Deck erbt das Logo aus dem Theme, ohne es selbst zu duplizieren.
|
|
16
|
+
import logoSrc from '../assets/logo.svg'
|
|
17
|
+
function onLogoError(e: Event) {
|
|
18
|
+
(e.target as HTMLImageElement).style.display = 'none'
|
|
19
|
+
}
|
|
20
|
+
</script>
|
|
21
|
+
|
|
22
|
+
<template>
|
|
23
|
+
<div class="cover-layout">
|
|
24
|
+
<BrandMeshBackground />
|
|
25
|
+
|
|
26
|
+
<div class="cover-content">
|
|
27
|
+
<div v-if="eyebrow" class="cover-eyebrow">{{ eyebrow }}</div>
|
|
28
|
+
<div class="cover-body">
|
|
29
|
+
<slot />
|
|
30
|
+
</div>
|
|
31
|
+
</div>
|
|
32
|
+
|
|
33
|
+
<div class="cover-footer">
|
|
34
|
+
<img :src="logoSrc" alt="Miragon" class="cover-logo" @error="onLogoError" />
|
|
35
|
+
<span v-if="footer" class="cover-footer-text">{{ footer }}</span>
|
|
36
|
+
</div>
|
|
37
|
+
</div>
|
|
38
|
+
</template>
|
|
39
|
+
|
|
40
|
+
<style scoped>
|
|
41
|
+
.cover-layout {
|
|
42
|
+
position: relative;
|
|
43
|
+
width: 100%;
|
|
44
|
+
height: 100%;
|
|
45
|
+
overflow: hidden;
|
|
46
|
+
color: var(--miragon-white);
|
|
47
|
+
/* Brand-Gradient als unterste Ebene: greift, falls BrandMeshBackground (WebGL) gar nicht
|
|
48
|
+
mountet (PDF/headless ohne GPU) — so nie Weiß, immer der Miragon-Verlauf.
|
|
49
|
+
BrandMeshBackground liegt mit position:absolute darüber und verdeckt ihn live. */
|
|
50
|
+
background: linear-gradient(125deg, #335DE5 0%, #1a1a4e 35%, #0d0d2b 55%, #00C853 100%);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
.cover-content {
|
|
54
|
+
position: relative;
|
|
55
|
+
z-index: 2;
|
|
56
|
+
height: 100%;
|
|
57
|
+
display: flex;
|
|
58
|
+
flex-direction: column;
|
|
59
|
+
justify-content: center;
|
|
60
|
+
padding: 0 4rem;
|
|
61
|
+
max-width: 56rem;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
.cover-eyebrow {
|
|
65
|
+
font-size: 0.95rem;
|
|
66
|
+
font-weight: 600;
|
|
67
|
+
letter-spacing: 0.18em;
|
|
68
|
+
text-transform: uppercase;
|
|
69
|
+
color: var(--miragon-green);
|
|
70
|
+
margin-bottom: 1.25rem;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/* Titel: weiß, kursiv, sehr fett — Miragon-Charakter */
|
|
74
|
+
.cover-body :deep(h1) {
|
|
75
|
+
font-size: 3.6rem;
|
|
76
|
+
line-height: 1.05;
|
|
77
|
+
font-weight: 900;
|
|
78
|
+
font-style: italic;
|
|
79
|
+
color: var(--miragon-white);
|
|
80
|
+
margin: 0;
|
|
81
|
+
text-shadow: 0 2px 24px rgba(13, 13, 43, 0.35);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
.cover-body :deep(p) {
|
|
85
|
+
font-size: 1.4rem;
|
|
86
|
+
font-weight: 400;
|
|
87
|
+
color: rgba(255, 255, 255, 0.88);
|
|
88
|
+
margin-top: 1.25rem;
|
|
89
|
+
max-width: 42rem;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
.cover-body :deep(a) {
|
|
93
|
+
color: var(--miragon-green);
|
|
94
|
+
text-decoration: none;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
.cover-footer {
|
|
98
|
+
position: absolute;
|
|
99
|
+
z-index: 2;
|
|
100
|
+
bottom: 2rem;
|
|
101
|
+
left: 4rem;
|
|
102
|
+
right: 4rem;
|
|
103
|
+
display: flex;
|
|
104
|
+
align-items: center;
|
|
105
|
+
justify-content: space-between;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
.cover-logo { height: 1.75rem; opacity: 0.95; }
|
|
109
|
+
|
|
110
|
+
.cover-footer-text {
|
|
111
|
+
font-size: 0.85rem;
|
|
112
|
+
color: rgba(255, 255, 255, 0.7);
|
|
113
|
+
}
|
|
114
|
+
</style>
|
|
@@ -0,0 +1,308 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
/**
|
|
3
|
+
* goodbad — "Which one is right, and why?" (STATISCHE Welt, kein Mesh-Shader).
|
|
4
|
+
*
|
|
5
|
+
* Zwei neutrale weiße Panels nebeneinander, beschriftet "Model A" / "Model B".
|
|
6
|
+
* Beim ersten Klick erscheinen Verdict-Badges (Recommended / Avoid) UND eine
|
|
7
|
+
* kurze Regel-Legende — der Saal kann vorher selbst überlegen, welches Modell
|
|
8
|
+
* besser ist, bevor die Auflösung kommt.
|
|
9
|
+
*
|
|
10
|
+
* Bewusst WEISSE Panels (anders als `compare`, das links/rechts semantisch
|
|
11
|
+
* blau/grün einfärbt): das Modell-Verdict soll erst beim Reveal sichtbar
|
|
12
|
+
* werden, eine Farbe würde es vorab verraten.
|
|
13
|
+
*
|
|
14
|
+
* Folgt der hero/content/compare-Bildsprache: heller Grund, klarer Akzent-Balken,
|
|
15
|
+
* großzügige Typografie, ein einziger sparsamer Gradient-Akzent.
|
|
16
|
+
*
|
|
17
|
+
* Named Slots (in Markdown mit `::left::` / `::right::` / `::legend::`):
|
|
18
|
+
* left — Inhalt von Model A (Text, kleines Code-Snippet, inline-SVG)
|
|
19
|
+
* right — Inhalt von Model B
|
|
20
|
+
* legend — kurze Regel, beim Klick mit den Verdicts zusammen sichtbar
|
|
21
|
+
*
|
|
22
|
+
* Frontmatter-Props:
|
|
23
|
+
* title — Slide-Titel (optional)
|
|
24
|
+
* eyebrow — kleine Überzeile (optional)
|
|
25
|
+
* prompt — kursive Leitfrage als Subtitle (optional)
|
|
26
|
+
* leftIsGood — true → A ist "Recommended", B ist "Avoid"
|
|
27
|
+
* false → A ist "Avoid", B ist "Recommended" (default)
|
|
28
|
+
* Bewusst pro Slide variieren, sodass "Recommended" nicht
|
|
29
|
+
* immer auf derselben Seite landet.
|
|
30
|
+
* accent — "blue" | "green" | "mixed" — Balken-/Eyebrow-Akzent (default blue)
|
|
31
|
+
*/
|
|
32
|
+
import { computed } from 'vue'
|
|
33
|
+
|
|
34
|
+
const props = withDefaults(
|
|
35
|
+
defineProps<{
|
|
36
|
+
eyebrow?: string
|
|
37
|
+
prompt?: string
|
|
38
|
+
leftIsGood?: boolean
|
|
39
|
+
accent?: 'blue' | 'green' | 'mixed'
|
|
40
|
+
// Slidev reicht das volle Frontmatter-Objekt als `frontmatter`-Prop durch.
|
|
41
|
+
frontmatter?: Record<string, unknown>
|
|
42
|
+
}>(),
|
|
43
|
+
{ accent: 'blue', leftIsGood: false },
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
// `title` ist ein RESERVIERTES Slidev-Frontmatter-Feld (TOC/Nav) und wird NICHT
|
|
47
|
+
// als eigener Prop durchgereicht (FRONTMATTER_FIELDS). Daher aus dem
|
|
48
|
+
// mitgelieferten `frontmatter`-Objekt lesen, damit `title:` in slides.md wie
|
|
49
|
+
// dokumentiert funktioniert.
|
|
50
|
+
const title = computed(() => props.frontmatter?.title as string | undefined)
|
|
51
|
+
|
|
52
|
+
// Token reaktiv (siehe hero.vue) — alle Werte aus theme.css, keine Hex.
|
|
53
|
+
const gradientVar = computed(() => `var(--miragon-gradient-${props.accent})`)
|
|
54
|
+
const accentVar = computed(() =>
|
|
55
|
+
props.accent === 'green' ? 'var(--miragon-green-deep)' : 'var(--miragon-blue)',
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
// Verdict-Logik: leftIsGood entscheidet, welche Seite das grüne Recommended
|
|
59
|
+
// und welche das graue Avoid bekommt.
|
|
60
|
+
const leftVerdictLabel = computed(() => (props.leftIsGood ? 'Recommended' : 'Avoid'))
|
|
61
|
+
const rightVerdictLabel = computed(() => (props.leftIsGood ? 'Avoid' : 'Recommended'))
|
|
62
|
+
const leftVerdictClass = computed(() => (props.leftIsGood ? 'verdict-good' : 'verdict-bad'))
|
|
63
|
+
const rightVerdictClass = computed(() => (props.leftIsGood ? 'verdict-bad' : 'verdict-good'))
|
|
64
|
+
</script>
|
|
65
|
+
|
|
66
|
+
<template>
|
|
67
|
+
<div
|
|
68
|
+
class="goodbad-layout"
|
|
69
|
+
:style="{ '--gb-grad': gradientVar, '--gb-accent': accentVar }"
|
|
70
|
+
>
|
|
71
|
+
<div class="goodbad-inner">
|
|
72
|
+
<header v-if="title || eyebrow || prompt" class="goodbad-head">
|
|
73
|
+
<span class="goodbad-bar" aria-hidden="true"></span>
|
|
74
|
+
<div v-if="eyebrow" class="goodbad-eyebrow">{{ eyebrow }}</div>
|
|
75
|
+
<h2 v-if="title" class="goodbad-title">{{ title }}</h2>
|
|
76
|
+
<p v-if="prompt" class="goodbad-prompt">{{ prompt }}</p>
|
|
77
|
+
</header>
|
|
78
|
+
|
|
79
|
+
<div class="goodbad-grid">
|
|
80
|
+
<section class="goodbad-panel">
|
|
81
|
+
<div class="panel-head">
|
|
82
|
+
<span class="model-label">Model A</span>
|
|
83
|
+
<v-click at="1">
|
|
84
|
+
<span class="verdict" :class="leftVerdictClass">
|
|
85
|
+
<span class="verdict-dot" aria-hidden="true"></span>
|
|
86
|
+
<span class="verdict-label">{{ leftVerdictLabel }}</span>
|
|
87
|
+
</span>
|
|
88
|
+
</v-click>
|
|
89
|
+
</div>
|
|
90
|
+
<div class="panel-body"><slot name="left" /></div>
|
|
91
|
+
</section>
|
|
92
|
+
|
|
93
|
+
<section class="goodbad-panel">
|
|
94
|
+
<div class="panel-head">
|
|
95
|
+
<span class="model-label">Model B</span>
|
|
96
|
+
<v-click at="1">
|
|
97
|
+
<span class="verdict" :class="rightVerdictClass">
|
|
98
|
+
<span class="verdict-dot" aria-hidden="true"></span>
|
|
99
|
+
<span class="verdict-label">{{ rightVerdictLabel }}</span>
|
|
100
|
+
</span>
|
|
101
|
+
</v-click>
|
|
102
|
+
</div>
|
|
103
|
+
<div class="panel-body"><slot name="right" /></div>
|
|
104
|
+
</section>
|
|
105
|
+
</div>
|
|
106
|
+
|
|
107
|
+
<v-click at="1">
|
|
108
|
+
<div class="goodbad-legend"><slot name="legend" /></div>
|
|
109
|
+
</v-click>
|
|
110
|
+
</div>
|
|
111
|
+
</div>
|
|
112
|
+
</template>
|
|
113
|
+
|
|
114
|
+
<style scoped>
|
|
115
|
+
.goodbad-layout {
|
|
116
|
+
position: relative;
|
|
117
|
+
width: 100%;
|
|
118
|
+
height: 100%;
|
|
119
|
+
overflow: hidden;
|
|
120
|
+
background: var(--miragon-gray-bg);
|
|
121
|
+
color: var(--miragon-text-primary);
|
|
122
|
+
display: flex;
|
|
123
|
+
align-items: stretch;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
.goodbad-inner {
|
|
127
|
+
position: relative;
|
|
128
|
+
z-index: 1;
|
|
129
|
+
width: 100%;
|
|
130
|
+
max-width: 70rem;
|
|
131
|
+
margin: 0 auto;
|
|
132
|
+
padding: 3rem 5rem;
|
|
133
|
+
display: flex;
|
|
134
|
+
flex-direction: column;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/* --- Kopf: Balken + Eyebrow + Titel + kursive Leitfrage ------------------ */
|
|
138
|
+
.goodbad-head {
|
|
139
|
+
flex: 0 0 auto;
|
|
140
|
+
margin-bottom: 1.5rem;
|
|
141
|
+
}
|
|
142
|
+
.goodbad-bar {
|
|
143
|
+
display: block;
|
|
144
|
+
width: 3.5rem;
|
|
145
|
+
height: 0.35rem;
|
|
146
|
+
border-radius: 999px;
|
|
147
|
+
background: var(--gb-grad);
|
|
148
|
+
margin-bottom: 1.1rem;
|
|
149
|
+
}
|
|
150
|
+
.goodbad-eyebrow {
|
|
151
|
+
font-size: 0.9rem;
|
|
152
|
+
font-weight: 600;
|
|
153
|
+
letter-spacing: 0.18em;
|
|
154
|
+
text-transform: uppercase;
|
|
155
|
+
color: var(--gb-accent);
|
|
156
|
+
margin-bottom: 0.6rem;
|
|
157
|
+
}
|
|
158
|
+
.goodbad-title {
|
|
159
|
+
font-size: clamp(1.7rem, 2.8vw, 2.2rem);
|
|
160
|
+
line-height: 1.15;
|
|
161
|
+
font-weight: 800;
|
|
162
|
+
letter-spacing: -0.02em;
|
|
163
|
+
color: var(--miragon-text-primary);
|
|
164
|
+
margin: 0;
|
|
165
|
+
}
|
|
166
|
+
.goodbad-prompt {
|
|
167
|
+
font-size: 1.05rem;
|
|
168
|
+
font-style: italic;
|
|
169
|
+
color: var(--miragon-text-muted);
|
|
170
|
+
margin: 0.85rem 0 0;
|
|
171
|
+
max-width: 46rem;
|
|
172
|
+
line-height: 1.5;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/* --- Zwei weiße Panels (neutral; Verdict erscheint erst beim Klick) ------ */
|
|
176
|
+
.goodbad-grid {
|
|
177
|
+
flex: 1 1 auto;
|
|
178
|
+
min-height: 0;
|
|
179
|
+
display: grid;
|
|
180
|
+
grid-template-columns: 1fr 1fr;
|
|
181
|
+
gap: 2rem;
|
|
182
|
+
}
|
|
183
|
+
.goodbad-panel {
|
|
184
|
+
background: var(--miragon-white);
|
|
185
|
+
border: 1px solid #E5E7EB;
|
|
186
|
+
border-radius: 1.1rem;
|
|
187
|
+
padding: 1.25rem 1.5rem 1.5rem;
|
|
188
|
+
box-shadow: 0 8px 20px rgba(51, 93, 229, 0.08);
|
|
189
|
+
display: flex;
|
|
190
|
+
flex-direction: column;
|
|
191
|
+
min-height: 0;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
.panel-head {
|
|
195
|
+
display: flex;
|
|
196
|
+
align-items: center;
|
|
197
|
+
gap: 0.8rem;
|
|
198
|
+
min-height: 1.4rem;
|
|
199
|
+
margin-bottom: 1rem;
|
|
200
|
+
}
|
|
201
|
+
.model-label {
|
|
202
|
+
font-size: 0.72rem;
|
|
203
|
+
font-weight: 700;
|
|
204
|
+
letter-spacing: 0.14em;
|
|
205
|
+
text-transform: uppercase;
|
|
206
|
+
color: var(--miragon-text-muted);
|
|
207
|
+
}
|
|
208
|
+
.verdict {
|
|
209
|
+
display: inline-flex;
|
|
210
|
+
align-items: center;
|
|
211
|
+
gap: 0.45rem;
|
|
212
|
+
}
|
|
213
|
+
.verdict-dot {
|
|
214
|
+
width: 0.6rem;
|
|
215
|
+
height: 0.6rem;
|
|
216
|
+
border-radius: 999px;
|
|
217
|
+
display: inline-block;
|
|
218
|
+
}
|
|
219
|
+
.verdict-label {
|
|
220
|
+
font-size: 0.72rem;
|
|
221
|
+
font-weight: 700;
|
|
222
|
+
letter-spacing: 0.14em;
|
|
223
|
+
text-transform: uppercase;
|
|
224
|
+
}
|
|
225
|
+
.verdict-good .verdict-dot { background: var(--miragon-green-dark); }
|
|
226
|
+
.verdict-good .verdict-label { color: var(--miragon-green-deep); }
|
|
227
|
+
.verdict-bad .verdict-dot { background: var(--miragon-text-muted); }
|
|
228
|
+
.verdict-bad .verdict-label { color: var(--miragon-text-muted); }
|
|
229
|
+
|
|
230
|
+
/* --- Panel-Body: Markdown-Inhalt (Text, Code, kleines inline-SVG) -------- */
|
|
231
|
+
.panel-body {
|
|
232
|
+
flex: 1 1 auto;
|
|
233
|
+
min-height: 0;
|
|
234
|
+
}
|
|
235
|
+
.panel-body :deep(p) {
|
|
236
|
+
font-size: 1.05rem;
|
|
237
|
+
line-height: 1.5;
|
|
238
|
+
color: var(--miragon-text-secondary);
|
|
239
|
+
margin: 0 0 0.85rem;
|
|
240
|
+
}
|
|
241
|
+
.panel-body :deep(strong) {
|
|
242
|
+
font-weight: 700;
|
|
243
|
+
color: var(--miragon-text-primary);
|
|
244
|
+
}
|
|
245
|
+
.panel-body :deep(ul) {
|
|
246
|
+
list-style: none;
|
|
247
|
+
padding: 0;
|
|
248
|
+
margin: 0;
|
|
249
|
+
}
|
|
250
|
+
.panel-body :deep(li) {
|
|
251
|
+
position: relative;
|
|
252
|
+
font-size: 1.02rem;
|
|
253
|
+
line-height: 1.45;
|
|
254
|
+
color: var(--miragon-text-secondary);
|
|
255
|
+
padding-left: 1.5rem;
|
|
256
|
+
margin: 0 0 0.65rem;
|
|
257
|
+
}
|
|
258
|
+
.panel-body :deep(li)::before {
|
|
259
|
+
content: '';
|
|
260
|
+
position: absolute;
|
|
261
|
+
left: 0;
|
|
262
|
+
top: 0.55em;
|
|
263
|
+
width: 0.55rem;
|
|
264
|
+
height: 0.55rem;
|
|
265
|
+
border-radius: 0.18rem;
|
|
266
|
+
background: var(--gb-grad);
|
|
267
|
+
}
|
|
268
|
+
.panel-body :deep(code) {
|
|
269
|
+
font-family: var(--miragon-font-mono);
|
|
270
|
+
font-size: 0.9em;
|
|
271
|
+
background: var(--miragon-blue-light);
|
|
272
|
+
color: var(--miragon-blue-darker);
|
|
273
|
+
padding: 0.1em 0.4em;
|
|
274
|
+
border-radius: 0.35rem;
|
|
275
|
+
}
|
|
276
|
+
.panel-body :deep(pre) {
|
|
277
|
+
font-family: var(--miragon-font-mono);
|
|
278
|
+
font-size: 0.9rem;
|
|
279
|
+
background: var(--miragon-blue-light);
|
|
280
|
+
color: var(--miragon-text-primary);
|
|
281
|
+
padding: 0.8rem 1rem;
|
|
282
|
+
border-radius: 0.5rem;
|
|
283
|
+
margin: 0.4rem 0 0;
|
|
284
|
+
overflow-x: auto;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
/* --- Legende: kurze Regel unter den Panels, beim Klick mit eingeblendet -- */
|
|
288
|
+
.goodbad-legend {
|
|
289
|
+
flex: 0 0 auto;
|
|
290
|
+
margin-top: 1.5rem;
|
|
291
|
+
padding: 0.9rem 1.2rem;
|
|
292
|
+
background: var(--miragon-white);
|
|
293
|
+
border: 1px solid #E5E7EB;
|
|
294
|
+
border-radius: 0.8rem;
|
|
295
|
+
box-shadow: 0 4px 12px rgba(51, 93, 229, 0.05);
|
|
296
|
+
}
|
|
297
|
+
.goodbad-legend :deep(p) {
|
|
298
|
+
font-size: 1.02rem;
|
|
299
|
+
line-height: 1.5;
|
|
300
|
+
color: var(--miragon-text-secondary);
|
|
301
|
+
margin: 0;
|
|
302
|
+
text-align: center;
|
|
303
|
+
}
|
|
304
|
+
.goodbad-legend :deep(strong) {
|
|
305
|
+
font-weight: 700;
|
|
306
|
+
color: var(--miragon-text-primary);
|
|
307
|
+
}
|
|
308
|
+
</style>
|
package/layouts/hero.vue
ADDED
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
/**
|
|
3
|
+
* hero — Hero-Statement (STATISCHE Welt, KEIN Mesh-Shader).
|
|
4
|
+
*
|
|
5
|
+
* Hebt EINE große Aussage hervor: einen Leitsatz, eine Kernthese, einen
|
|
6
|
+
* Schlüsselmoment. Anders als `cover` (animierte Titelseite) lebt `hero` von
|
|
7
|
+
* Ruhe: heller Grund, viel Weißraum, sehr große Typografie. Der einzige
|
|
8
|
+
* bewegte Brand-Akzent ist ein statischer Gradient-Balken (sparsam).
|
|
9
|
+
*
|
|
10
|
+
* Diese Slide definiert die visuelle Sprache der statischen Welt, an der sich
|
|
11
|
+
* person/content/compare später orientieren.
|
|
12
|
+
*
|
|
13
|
+
* Slots: default = Aussage (h1) + optionale Attribution/Quelle (p) aus Markdown.
|
|
14
|
+
* Frontmatter-Props:
|
|
15
|
+
* eyebrow — kleine Überzeile (optional)
|
|
16
|
+
* accent — "blue" | "green" | "mixed" — wählt den Gradient-Akzent (default blue)
|
|
17
|
+
* align — "left" | "center" — Ausrichtung (default left)
|
|
18
|
+
*/
|
|
19
|
+
import { computed } from 'vue'
|
|
20
|
+
|
|
21
|
+
const props = withDefaults(
|
|
22
|
+
defineProps<{
|
|
23
|
+
eyebrow?: string
|
|
24
|
+
accent?: 'blue' | 'green' | 'mixed'
|
|
25
|
+
align?: 'left' | 'center'
|
|
26
|
+
}>(),
|
|
27
|
+
{ accent: 'blue', align: 'left' },
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
// Abgeleitete Token reaktiv halten (computed), falls Slidev die Layout-Instanz
|
|
31
|
+
// über Slides hinweg wiederverwendet. Alle Werte zeigen auf theme.css-Variablen
|
|
32
|
+
// — keine hardcoded Hex.
|
|
33
|
+
//
|
|
34
|
+
// Gradient (Balken + Attributions-Strich) je nach Akzent.
|
|
35
|
+
const gradientVar = computed(() => `var(--miragon-gradient-${props.accent})`)
|
|
36
|
+
// Eyebrow-Solidfarbe: Grün nur beim grünen Akzent (CI: Grün sparsam).
|
|
37
|
+
const eyebrowVar = computed(() =>
|
|
38
|
+
props.accent === 'green' ? 'var(--miragon-green-deep)' : 'var(--miragon-blue)',
|
|
39
|
+
)
|
|
40
|
+
// Solidfarbe für das hervorgehobene Wort (**bold**). BEWUSST kein
|
|
41
|
+
// background-clip:text-Gradient: headless Chromium (PDF-Export via `npm run
|
|
42
|
+
// export`) kann die clip-Schrift unsichtbar rendern. Solide Akzentfarbe ist
|
|
43
|
+
// immer sichtbar und exportsicher; der Gradient lebt im Balken/Strich.
|
|
44
|
+
const emphasisVar = computed(() =>
|
|
45
|
+
props.accent === 'green' ? 'var(--miragon-green-deep)' : 'var(--miragon-blue)',
|
|
46
|
+
)
|
|
47
|
+
</script>
|
|
48
|
+
|
|
49
|
+
<template>
|
|
50
|
+
<div
|
|
51
|
+
class="hero-layout"
|
|
52
|
+
:class="[`is-${align}`]"
|
|
53
|
+
:style="{
|
|
54
|
+
'--hero-grad': gradientVar,
|
|
55
|
+
'--hero-eyebrow': eyebrowVar,
|
|
56
|
+
'--hero-emphasis': emphasisVar,
|
|
57
|
+
}"
|
|
58
|
+
>
|
|
59
|
+
<div class="hero-content">
|
|
60
|
+
<span class="hero-bar" aria-hidden="true"></span>
|
|
61
|
+
<div v-if="eyebrow" class="hero-eyebrow">{{ eyebrow }}</div>
|
|
62
|
+
<div class="hero-body">
|
|
63
|
+
<slot />
|
|
64
|
+
</div>
|
|
65
|
+
</div>
|
|
66
|
+
</div>
|
|
67
|
+
</template>
|
|
68
|
+
|
|
69
|
+
<style scoped>
|
|
70
|
+
.hero-layout {
|
|
71
|
+
position: relative;
|
|
72
|
+
width: 100%;
|
|
73
|
+
height: 100%;
|
|
74
|
+
overflow: hidden;
|
|
75
|
+
background: var(--miragon-gray-bg);
|
|
76
|
+
color: var(--miragon-text-primary);
|
|
77
|
+
display: flex;
|
|
78
|
+
align-items: center;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
.hero-content {
|
|
82
|
+
position: relative;
|
|
83
|
+
z-index: 1;
|
|
84
|
+
width: 100%;
|
|
85
|
+
max-width: 64rem;
|
|
86
|
+
padding: 0 5rem;
|
|
87
|
+
display: flex;
|
|
88
|
+
flex-direction: column;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/* Gradient-Akzent: kurzer Balken über der Aussage (der einzige Brand-„Bewegungs"-Punkt). */
|
|
92
|
+
.hero-bar {
|
|
93
|
+
width: 4.5rem;
|
|
94
|
+
height: 0.4rem;
|
|
95
|
+
border-radius: 999px;
|
|
96
|
+
background: var(--hero-grad);
|
|
97
|
+
margin-bottom: 2rem;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
.hero-eyebrow {
|
|
101
|
+
font-size: 0.95rem;
|
|
102
|
+
font-weight: 600;
|
|
103
|
+
letter-spacing: 0.18em;
|
|
104
|
+
text-transform: uppercase;
|
|
105
|
+
color: var(--hero-eyebrow);
|
|
106
|
+
margin-bottom: 1.5rem;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/* Aussage dominiert die Slide: sehr groß, dunkel, fett. */
|
|
110
|
+
.hero-body :deep(h1) {
|
|
111
|
+
font-size: clamp(3rem, 5.4vw, 4.6rem);
|
|
112
|
+
line-height: 1.08;
|
|
113
|
+
font-weight: 800;
|
|
114
|
+
letter-spacing: -0.02em;
|
|
115
|
+
color: var(--miragon-text-primary);
|
|
116
|
+
margin: 0;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/* Attribution / Quelle: dezent, mit Gradient-Strich davor. */
|
|
120
|
+
.hero-body :deep(p) {
|
|
121
|
+
position: relative;
|
|
122
|
+
font-size: 1.15rem;
|
|
123
|
+
font-weight: 500;
|
|
124
|
+
color: var(--miragon-text-muted);
|
|
125
|
+
margin: 2.25rem 0 0;
|
|
126
|
+
padding-left: 3rem;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
.hero-body :deep(p)::before {
|
|
130
|
+
content: '';
|
|
131
|
+
position: absolute;
|
|
132
|
+
left: 0;
|
|
133
|
+
top: 0.7em;
|
|
134
|
+
width: 2rem;
|
|
135
|
+
height: 2px;
|
|
136
|
+
background: var(--hero-grad);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/* Optionaler Brand-Akzent auf einzelnen Wörtern: **bold** im Statement bekommt
|
|
140
|
+
die solide Akzentfarbe. Sparsam einsetzen (ein Schlüsselwort, nicht mehr). */
|
|
141
|
+
.hero-body :deep(h1 strong) {
|
|
142
|
+
font-weight: 800;
|
|
143
|
+
color: var(--hero-emphasis);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/* --- Ausrichtung ---------------------------------------------------------- */
|
|
147
|
+
.is-center {
|
|
148
|
+
justify-content: center;
|
|
149
|
+
}
|
|
150
|
+
.is-center .hero-content {
|
|
151
|
+
align-items: center;
|
|
152
|
+
text-align: center;
|
|
153
|
+
max-width: 56rem;
|
|
154
|
+
}
|
|
155
|
+
.is-center .hero-eyebrow {
|
|
156
|
+
margin-bottom: 1.75rem;
|
|
157
|
+
}
|
|
158
|
+
.is-center .hero-body :deep(p) {
|
|
159
|
+
padding-left: 0;
|
|
160
|
+
padding-top: 2rem;
|
|
161
|
+
}
|
|
162
|
+
.is-center .hero-body :deep(p)::before {
|
|
163
|
+
left: 50%;
|
|
164
|
+
top: 0;
|
|
165
|
+
transform: translateX(-50%);
|
|
166
|
+
width: 2.5rem;
|
|
167
|
+
}
|
|
168
|
+
</style>
|