@sp-days-framework/slidev-theme-sykehuspartner 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/README.md +622 -0
- package/layouts/about-me.vue +410 -0
- package/layouts/center.vue +38 -0
- package/layouts/cover.vue +88 -0
- package/layouts/default.vue +96 -0
- package/layouts/end.vue +54 -0
- package/layouts/fact.vue +39 -0
- package/layouts/full.vue +34 -0
- package/layouts/image-left.vue +222 -0
- package/layouts/image-right.vue +218 -0
- package/layouts/image.vue +143 -0
- package/layouts/intro.vue +315 -0
- package/layouts/quote.vue +72 -0
- package/layouts/section.vue +140 -0
- package/layouts/statement.vue +60 -0
- package/layouts/three-cols-header.vue +103 -0
- package/layouts/three-cols.vue +77 -0
- package/layouts/two-cols-header.vue +95 -0
- package/layouts/two-cols.vue +69 -0
- package/package.json +59 -0
- package/public/sp-banner-dark.svg +37 -0
- package/public/sp-banner-light.svg +37 -0
- package/public/sp-logo-dark.svg +24 -0
- package/public/sp-logo-light.svg +24 -0
- package/setup/index.ts +38 -0
- package/setup/shiki.ts +56 -0
- package/styles/code.css +30 -0
- package/styles/index.ts +4 -0
- package/styles/layout.css +161 -0
- package/uno.config.ts +47 -0
- package/utils/headerContentSplitter.ts +48 -0
- package/utils/layoutHelper.ts +172 -0
|
@@ -0,0 +1,315 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="slidev-layout intro">
|
|
3
|
+
<!-- Standard layout when no image is provided -->
|
|
4
|
+
<div v-if="!hasImage" class="content-wrapper-no-image">
|
|
5
|
+
<div class="text-content-full">
|
|
6
|
+
<div v-if="showBanner" class="banner-container">
|
|
7
|
+
<div class="banner-image banner"></div>
|
|
8
|
+
</div>
|
|
9
|
+
<div class="content-container">
|
|
10
|
+
<slot />
|
|
11
|
+
</div>
|
|
12
|
+
</div>
|
|
13
|
+
</div>
|
|
14
|
+
|
|
15
|
+
<!-- Split layout with image -->
|
|
16
|
+
<div v-else class="content-wrapper" :class="layoutClass">
|
|
17
|
+
<!-- Text content section -->
|
|
18
|
+
<div class="text-content" :style="textContentStyle">
|
|
19
|
+
<div v-if="showBanner" class="banner-container">
|
|
20
|
+
<div class="banner-image banner"></div>
|
|
21
|
+
</div>
|
|
22
|
+
<div class="content-container">
|
|
23
|
+
<slot />
|
|
24
|
+
</div>
|
|
25
|
+
</div>
|
|
26
|
+
|
|
27
|
+
<!-- Image content section -->
|
|
28
|
+
<div class="image-content" :style="imageContentStyle">
|
|
29
|
+
<div class="image-container" :class="imageAlignClass">
|
|
30
|
+
<img
|
|
31
|
+
:src="getImageUrl(props.imageSrc)"
|
|
32
|
+
:style="imageStyle"
|
|
33
|
+
alt="Slide Image"
|
|
34
|
+
>
|
|
35
|
+
</div>
|
|
36
|
+
</div>
|
|
37
|
+
</div>
|
|
38
|
+
</div>
|
|
39
|
+
</template>
|
|
40
|
+
|
|
41
|
+
<script setup>
|
|
42
|
+
import { computed } from 'vue'
|
|
43
|
+
import { getImageUrl } from '../utils/layoutHelper'
|
|
44
|
+
|
|
45
|
+
const props = defineProps({
|
|
46
|
+
bannerEnabled: {
|
|
47
|
+
type: Boolean,
|
|
48
|
+
default: true
|
|
49
|
+
},
|
|
50
|
+
// Image options
|
|
51
|
+
imageSrc: String,
|
|
52
|
+
imageSize: {
|
|
53
|
+
type: String,
|
|
54
|
+
default: '100%'
|
|
55
|
+
},
|
|
56
|
+
imagePosition: {
|
|
57
|
+
type: String,
|
|
58
|
+
default: 'right',
|
|
59
|
+
validator: (value) => ['left', 'right'].includes(value)
|
|
60
|
+
},
|
|
61
|
+
imageRatio: {
|
|
62
|
+
type: String,
|
|
63
|
+
default: '33%'
|
|
64
|
+
},
|
|
65
|
+
// Logo/banner option
|
|
66
|
+
enableLogo: {
|
|
67
|
+
type: Boolean,
|
|
68
|
+
default: true
|
|
69
|
+
}
|
|
70
|
+
})
|
|
71
|
+
|
|
72
|
+
// Check if image is provided in frontmatter or props
|
|
73
|
+
const hasImage = computed(() => {
|
|
74
|
+
// First check frontmatter (for backward compatibility)
|
|
75
|
+
if ($slidev?.configs?.frontmatter?.imageSrc) {
|
|
76
|
+
props.imageSrc = $slidev.configs.frontmatter.imageSrc
|
|
77
|
+
return true
|
|
78
|
+
}
|
|
79
|
+
// Then check props
|
|
80
|
+
return Boolean(props.imageSrc)
|
|
81
|
+
})
|
|
82
|
+
|
|
83
|
+
// Determine if banner should be shown
|
|
84
|
+
const showBanner = computed(() => {
|
|
85
|
+
// First check frontmatter (for backward compatibility)
|
|
86
|
+
if ($slidev?.configs?.frontmatter?.enableLogo !== undefined) {
|
|
87
|
+
return $slidev.configs.frontmatter.enableLogo
|
|
88
|
+
}
|
|
89
|
+
// Then check props
|
|
90
|
+
return props.enableLogo !== undefined ? props.enableLogo : props.bannerEnabled
|
|
91
|
+
})
|
|
92
|
+
|
|
93
|
+
// Calculate layout class based on image position
|
|
94
|
+
const layoutClass = computed(() => {
|
|
95
|
+
// First check frontmatter (for backward compatibility)
|
|
96
|
+
const position = $slidev?.configs?.frontmatter?.imagePosition || props.imagePosition
|
|
97
|
+
return position === 'right' ? 'image-right' : 'image-left'
|
|
98
|
+
})
|
|
99
|
+
|
|
100
|
+
// Calculate image alignment class based on image position
|
|
101
|
+
const imageAlignClass = computed(() => {
|
|
102
|
+
// First check frontmatter (for backward compatibility)
|
|
103
|
+
const position = $slidev?.configs?.frontmatter?.imagePosition || props.imagePosition
|
|
104
|
+
return position === 'right' ? 'align-left' : 'align-right'
|
|
105
|
+
})
|
|
106
|
+
|
|
107
|
+
// Parse image ratio from frontmatter or props
|
|
108
|
+
const imageRatio = computed(() => {
|
|
109
|
+
// First check frontmatter (for backward compatibility)
|
|
110
|
+
const ratio = $slidev?.configs?.frontmatter?.imageRatio || props.imageRatio || '33%'
|
|
111
|
+
// Remove % sign and parse as number
|
|
112
|
+
return parseFloat(ratio.toString().replace('%', ''))
|
|
113
|
+
})
|
|
114
|
+
|
|
115
|
+
// Calculate text content width style
|
|
116
|
+
const textContentStyle = computed(() => {
|
|
117
|
+
const textWidth = 100 - imageRatio.value
|
|
118
|
+
return {
|
|
119
|
+
width: `${textWidth}%`,
|
|
120
|
+
}
|
|
121
|
+
})
|
|
122
|
+
|
|
123
|
+
// Calculate image content width style
|
|
124
|
+
const imageContentStyle = computed(() => {
|
|
125
|
+
return {
|
|
126
|
+
width: `${imageRatio.value}%`,
|
|
127
|
+
}
|
|
128
|
+
})
|
|
129
|
+
|
|
130
|
+
// Calculate image size and scaling
|
|
131
|
+
const imageSize = computed(() => {
|
|
132
|
+
return $slidev?.configs?.frontmatter?.imageSize || props.imageSize || '100%'
|
|
133
|
+
})
|
|
134
|
+
|
|
135
|
+
// Calculate image style
|
|
136
|
+
const imageStyle = computed(() => {
|
|
137
|
+
const size = imageSize.value
|
|
138
|
+
const style = {
|
|
139
|
+
maxWidth: '100%',
|
|
140
|
+
maxHeight: '100%',
|
|
141
|
+
objectFit: 'contain',
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
if (size) {
|
|
145
|
+
if (size.toString().endsWith('%')) {
|
|
146
|
+
const sizeValue = parseFloat(size.toString().replace('%', '')) / 100
|
|
147
|
+
style.maxWidth = `${sizeValue * 100}%`
|
|
148
|
+
style.maxHeight = `${sizeValue * 100}%`
|
|
149
|
+
} else if (!isNaN(Number(size))) {
|
|
150
|
+
style.maxWidth = `${parseFloat(size) * 100}%`
|
|
151
|
+
style.maxHeight = `${parseFloat(size) * 100}%`
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
return style
|
|
156
|
+
})
|
|
157
|
+
|
|
158
|
+
// Using onMounted to handle font sizing after DOM is ready
|
|
159
|
+
import { onMounted, nextTick } from 'vue'
|
|
160
|
+
|
|
161
|
+
// Dynamic font sizing logic
|
|
162
|
+
onMounted(async () => {
|
|
163
|
+
// Wait for content to be rendered
|
|
164
|
+
await nextTick()
|
|
165
|
+
|
|
166
|
+
// Find the h1 element
|
|
167
|
+
const h1 = document.querySelector('.slidev-layout.intro h1')
|
|
168
|
+
if (!h1) return
|
|
169
|
+
|
|
170
|
+
const textLength = h1.textContent?.length || 0
|
|
171
|
+
|
|
172
|
+
// Apply font sizing based on text length
|
|
173
|
+
if (textLength > 30) {
|
|
174
|
+
h1.style.fontSize = '2.5rem'
|
|
175
|
+
} else if (textLength > 20) {
|
|
176
|
+
h1.style.fontSize = '3rem'
|
|
177
|
+
} else {
|
|
178
|
+
h1.style.fontSize = '3.5rem'
|
|
179
|
+
}
|
|
180
|
+
})
|
|
181
|
+
</script>
|
|
182
|
+
|
|
183
|
+
<style scoped>
|
|
184
|
+
.intro {
|
|
185
|
+
height: 100%;
|
|
186
|
+
width: 100%;
|
|
187
|
+
padding: 0;
|
|
188
|
+
display: flex;
|
|
189
|
+
align-items: center;
|
|
190
|
+
justify-content: center;
|
|
191
|
+
overflow: hidden;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/* Layout when no image */
|
|
195
|
+
.content-wrapper-no-image {
|
|
196
|
+
display: flex;
|
|
197
|
+
width: 100%;
|
|
198
|
+
height: 100%;
|
|
199
|
+
overflow: hidden;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
.text-content-full {
|
|
203
|
+
flex: 1;
|
|
204
|
+
position: relative;
|
|
205
|
+
display: flex;
|
|
206
|
+
flex-direction: column;
|
|
207
|
+
justify-content: center;
|
|
208
|
+
padding: 0 2rem;
|
|
209
|
+
min-width: 0;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/* Split layout with image */
|
|
213
|
+
.content-wrapper {
|
|
214
|
+
display: flex;
|
|
215
|
+
width: 100%;
|
|
216
|
+
height: 100%;
|
|
217
|
+
align-items: center;
|
|
218
|
+
overflow: hidden;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
.image-left {
|
|
222
|
+
flex-direction: row-reverse; /* Image on left, text on right */
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
.image-right {
|
|
226
|
+
flex-direction: row; /* Text on left, image on right */
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/* Text content styling */
|
|
230
|
+
.text-content {
|
|
231
|
+
height: 100%;
|
|
232
|
+
position: relative;
|
|
233
|
+
display: flex;
|
|
234
|
+
flex-direction: column;
|
|
235
|
+
justify-content: center;
|
|
236
|
+
padding: 2rem;
|
|
237
|
+
overflow: hidden;
|
|
238
|
+
text-align: left;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/* Image content styling */
|
|
242
|
+
.image-content {
|
|
243
|
+
height: 100%;
|
|
244
|
+
display: flex;
|
|
245
|
+
align-items: center;
|
|
246
|
+
justify-content: center;
|
|
247
|
+
padding: 1rem;
|
|
248
|
+
overflow: hidden;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
.image-container {
|
|
252
|
+
display: flex;
|
|
253
|
+
height: 100%;
|
|
254
|
+
align-items: center;
|
|
255
|
+
max-width: 100%;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
.align-left {
|
|
259
|
+
justify-content: flex-start;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
.align-right {
|
|
263
|
+
justify-content: flex-end;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
/* Banner styles */
|
|
267
|
+
.banner-container {
|
|
268
|
+
width: 100%;
|
|
269
|
+
margin-bottom: 0.5rem;
|
|
270
|
+
display: flex; /* Using flexbox for better control */
|
|
271
|
+
justify-content: flex-start; /* Always align content to the left for intro */
|
|
272
|
+
margin-left: -0rem;
|
|
273
|
+
max-width: 200px;
|
|
274
|
+
height: 3rem;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
.banner {
|
|
278
|
+
width: 100%;
|
|
279
|
+
height: 100%;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
/* Banner styling handled by global CSS */
|
|
283
|
+
|
|
284
|
+
.content-container {
|
|
285
|
+
position: relative;
|
|
286
|
+
z-index: 5;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
/* Typography adjustments for headers */
|
|
290
|
+
:deep(h1) {
|
|
291
|
+
color: inherit;
|
|
292
|
+
font-size: 4rem; /* Default size that will be overridden by JS */
|
|
293
|
+
line-height: 1.25;
|
|
294
|
+
margin-top: 0;
|
|
295
|
+
word-wrap: break-word;
|
|
296
|
+
overflow-wrap: break-word;
|
|
297
|
+
hyphens: auto;
|
|
298
|
+
max-width: 100%;
|
|
299
|
+
transition: font-size 0.3s ease;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
:deep(h1)::after {
|
|
303
|
+
content: '';
|
|
304
|
+
display: block;
|
|
305
|
+
width: 20%;
|
|
306
|
+
margin-top: 0.5rem;
|
|
307
|
+
margin-bottom: 1.5rem;
|
|
308
|
+
height: 4px;
|
|
309
|
+
background-color: var(--sp-primary);
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
:deep(h2) {
|
|
313
|
+
color: var(--sp-primary-darkest);
|
|
314
|
+
}
|
|
315
|
+
</style>
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="slidev-layout quote">
|
|
3
|
+
<div v-if="showLogo" class="logo-container">
|
|
4
|
+
<div class="logo-image logo"></div>
|
|
5
|
+
</div>
|
|
6
|
+
<div class="my-auto quote-container">
|
|
7
|
+
<slot />
|
|
8
|
+
</div>
|
|
9
|
+
</div>
|
|
10
|
+
</template>
|
|
11
|
+
|
|
12
|
+
<script setup>
|
|
13
|
+
import { computed } from 'vue'
|
|
14
|
+
|
|
15
|
+
const props = defineProps({
|
|
16
|
+
logo: {
|
|
17
|
+
type: Boolean,
|
|
18
|
+
default: false
|
|
19
|
+
}
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
const showLogo = computed(() => {
|
|
23
|
+
if ($slidev?.configs?.frontmatter?.logo !== undefined) {
|
|
24
|
+
return $slidev.configs.frontmatter.logo
|
|
25
|
+
}
|
|
26
|
+
return props.logo
|
|
27
|
+
})
|
|
28
|
+
</script>
|
|
29
|
+
|
|
30
|
+
<style scoped>
|
|
31
|
+
.quote {
|
|
32
|
+
height: 100%;
|
|
33
|
+
display: flex;
|
|
34
|
+
align-items: center;
|
|
35
|
+
justify-content: center;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
.quote-container {
|
|
39
|
+
max-width: 80%;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
:deep(h1) {
|
|
43
|
+
font-size: 2rem;
|
|
44
|
+
color: inherit;
|
|
45
|
+
text-align: center;
|
|
46
|
+
margin-bottom: 2rem;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
:deep(h2) {
|
|
50
|
+
color: var(--sp-primary);
|
|
51
|
+
font-weight: 600;
|
|
52
|
+
text-align: right;
|
|
53
|
+
max-width: 100%;
|
|
54
|
+
margin-top: 0.5rem;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
:deep(h3) {
|
|
58
|
+
color: var(--sp-primary-lightest);
|
|
59
|
+
text-align: right;
|
|
60
|
+
max-width: 100%;
|
|
61
|
+
margin-top: 0.25rem;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
.logo-container {
|
|
65
|
+
position: absolute;
|
|
66
|
+
top: 1rem;
|
|
67
|
+
right: 1rem;
|
|
68
|
+
z-index: 10;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/* Logo styling moved to global layout.css */
|
|
72
|
+
</style>
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="slidev-layout section">
|
|
3
|
+
<div v-if="showLogo" class="logo-container">
|
|
4
|
+
<div class="logo-image logo"></div>
|
|
5
|
+
</div>
|
|
6
|
+
<div class="content-wrapper">
|
|
7
|
+
<div class="text-content">
|
|
8
|
+
<div class="content-container" :class="{ 'with-title-line': showTitleLine }">
|
|
9
|
+
<slot />
|
|
10
|
+
</div>
|
|
11
|
+
</div>
|
|
12
|
+
<div v-if="hasImage" class="image-content">
|
|
13
|
+
<img :src="imageUrl" alt="Slide Image">
|
|
14
|
+
</div>
|
|
15
|
+
</div>
|
|
16
|
+
</div>
|
|
17
|
+
</template>
|
|
18
|
+
|
|
19
|
+
<script setup>
|
|
20
|
+
import { computed } from 'vue'
|
|
21
|
+
import { getImageUrl } from '../utils/layoutHelper'
|
|
22
|
+
|
|
23
|
+
const props = defineProps({
|
|
24
|
+
logo: {
|
|
25
|
+
type: Boolean,
|
|
26
|
+
default: true
|
|
27
|
+
}
|
|
28
|
+
})
|
|
29
|
+
|
|
30
|
+
const hasImage = computed(() => {
|
|
31
|
+
return Boolean($slidev?.configs?.frontmatter?.image)
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
const imageUrl = computed(() => {
|
|
35
|
+
const image = $slidev?.configs?.frontmatter?.image
|
|
36
|
+
if (!image) return ''
|
|
37
|
+
return getImageUrl(image)
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
const showLogo = computed(() => {
|
|
41
|
+
if ($slidev?.configs?.frontmatter?.logo !== undefined) {
|
|
42
|
+
return $slidev.configs.frontmatter.logo
|
|
43
|
+
}
|
|
44
|
+
return props.logo
|
|
45
|
+
})
|
|
46
|
+
|
|
47
|
+
const showTitleLine = computed(() => {
|
|
48
|
+
if ($slidev?.configs?.frontmatter?.titleLine !== undefined) {
|
|
49
|
+
return $slidev.configs.frontmatter.titleLine
|
|
50
|
+
}
|
|
51
|
+
return true // Default to showing the line if not specified
|
|
52
|
+
})
|
|
53
|
+
</script>
|
|
54
|
+
|
|
55
|
+
<style scoped>
|
|
56
|
+
.section {
|
|
57
|
+
height: 100%;
|
|
58
|
+
display: flex;
|
|
59
|
+
align-items: center;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
.content-wrapper {
|
|
63
|
+
display: flex;
|
|
64
|
+
width: 100%;
|
|
65
|
+
height: 100%;
|
|
66
|
+
overflow: hidden; /* Ensure no overflow */
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
.text-content {
|
|
70
|
+
flex: 1;
|
|
71
|
+
position: relative;
|
|
72
|
+
display: flex;
|
|
73
|
+
flex-direction: column;
|
|
74
|
+
justify-content: center;
|
|
75
|
+
align-items: center;
|
|
76
|
+
text-align: center;
|
|
77
|
+
padding: 0 2rem;
|
|
78
|
+
min-width: 0; /* Ensure flexbox can shrink if needed */
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
.content-container {
|
|
82
|
+
position: relative;
|
|
83
|
+
z-index: 5;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
.image-content {
|
|
87
|
+
flex: 1;
|
|
88
|
+
display: flex;
|
|
89
|
+
align-items: center;
|
|
90
|
+
justify-content: center;
|
|
91
|
+
padding: 1rem;
|
|
92
|
+
max-width: 50%; /* Limit to half the width */
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
.image-content img {
|
|
96
|
+
max-width: 100%;
|
|
97
|
+
max-height: 100%;
|
|
98
|
+
object-fit: contain;
|
|
99
|
+
border-radius: 4px; /* Optional: slightly round the corners */
|
|
100
|
+
box-shadow: 0 4px 8px rgba(0,0,0,0.1); /* Optional: add a subtle shadow */
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
:deep(h1) {
|
|
105
|
+
color: inherit;
|
|
106
|
+
font-size: 2.75rem;
|
|
107
|
+
line-height: 3rem;
|
|
108
|
+
margin-top: 0;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
:deep(h1) {
|
|
113
|
+
position: relative;
|
|
114
|
+
display: inline-block;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
:deep(.with-title-line h1)::after {
|
|
118
|
+
content: '';
|
|
119
|
+
position: absolute;
|
|
120
|
+
left: 0;
|
|
121
|
+
bottom: -2rem;
|
|
122
|
+
width: 4rem;
|
|
123
|
+
height: 3px;
|
|
124
|
+
margin-bottom: 1.5rem;
|
|
125
|
+
background-color: var(--sp-primary);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
:deep(h2) {
|
|
129
|
+
color: var(--sp-primary);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
.logo-container {
|
|
133
|
+
position: absolute;
|
|
134
|
+
top: 1rem;
|
|
135
|
+
right: 1rem;
|
|
136
|
+
z-index: 10;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/* Logo styling moved to global layout.css */
|
|
140
|
+
</style>
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="slidev-layout statement">
|
|
3
|
+
<div v-if="showLogo" class="logo-container">
|
|
4
|
+
<div class="logo-image logo"></div>
|
|
5
|
+
</div>
|
|
6
|
+
<div class="content">
|
|
7
|
+
<slot />
|
|
8
|
+
</div>
|
|
9
|
+
</div>
|
|
10
|
+
</template>
|
|
11
|
+
|
|
12
|
+
<script setup>
|
|
13
|
+
import { computed } from 'vue'
|
|
14
|
+
|
|
15
|
+
const props = defineProps({
|
|
16
|
+
logo: {
|
|
17
|
+
type: Boolean,
|
|
18
|
+
default: true
|
|
19
|
+
}
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
const showLogo = computed(() => {
|
|
23
|
+
if ($slidev?.configs?.frontmatter?.logo !== undefined) {
|
|
24
|
+
return $slidev.configs.frontmatter.logo
|
|
25
|
+
}
|
|
26
|
+
return props.logo
|
|
27
|
+
})
|
|
28
|
+
</script>
|
|
29
|
+
|
|
30
|
+
<style scoped>
|
|
31
|
+
.statement {
|
|
32
|
+
height: 100%;
|
|
33
|
+
display: flex;
|
|
34
|
+
flex-direction: column;
|
|
35
|
+
justify-content: center;
|
|
36
|
+
align-items: center;
|
|
37
|
+
text-align: center;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
.content {
|
|
41
|
+
max-width: 80%;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
.statement h1 {
|
|
45
|
+
font-size: 3rem;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
.statement h2 {
|
|
49
|
+
font-size: 2rem;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
.logo-container {
|
|
53
|
+
position: absolute;
|
|
54
|
+
top: 1rem;
|
|
55
|
+
right: 1rem;
|
|
56
|
+
z-index: 10;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/* Logo styling moved to global layout.css */
|
|
60
|
+
</style>
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="slidev-layout three-cols-header">
|
|
3
|
+
<div v-if="showLogo" class="logo-container">
|
|
4
|
+
<div class="logo-image logo"></div>
|
|
5
|
+
</div>
|
|
6
|
+
<div class="header">
|
|
7
|
+
<slot />
|
|
8
|
+
</div>
|
|
9
|
+
<div class="cols-container">
|
|
10
|
+
<div class="col left">
|
|
11
|
+
<slot name="left" />
|
|
12
|
+
</div>
|
|
13
|
+
<div class="col middle">
|
|
14
|
+
<slot name="middle" />
|
|
15
|
+
</div>
|
|
16
|
+
<div class="col right">
|
|
17
|
+
<slot name="right" />
|
|
18
|
+
</div>
|
|
19
|
+
</div>
|
|
20
|
+
</div>
|
|
21
|
+
</template>
|
|
22
|
+
|
|
23
|
+
<script setup>
|
|
24
|
+
import { computed } from 'vue'
|
|
25
|
+
|
|
26
|
+
const props = defineProps({
|
|
27
|
+
logo: {
|
|
28
|
+
type: Boolean,
|
|
29
|
+
default: true
|
|
30
|
+
},
|
|
31
|
+
textAlignment: {
|
|
32
|
+
type: String,
|
|
33
|
+
default: 'center',
|
|
34
|
+
validator: (value) => ['top', 'center', 'bottom'].includes(value)
|
|
35
|
+
}
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
const showLogo = computed(() => {
|
|
39
|
+
if ($slidev?.configs?.frontmatter?.logo !== undefined) {
|
|
40
|
+
return $slidev.configs.frontmatter.logo
|
|
41
|
+
}
|
|
42
|
+
return props.logo
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
// Compute content alignment style based on textAlignment prop
|
|
46
|
+
const contentAlignmentStyle = computed(() => {
|
|
47
|
+
switch (props.textAlignment) {
|
|
48
|
+
case 'top':
|
|
49
|
+
return 'flex-start'
|
|
50
|
+
case 'bottom':
|
|
51
|
+
return 'flex-end'
|
|
52
|
+
case 'center':
|
|
53
|
+
default:
|
|
54
|
+
return 'center'
|
|
55
|
+
}
|
|
56
|
+
})
|
|
57
|
+
</script>
|
|
58
|
+
|
|
59
|
+
<style scoped>
|
|
60
|
+
.three-cols-header {
|
|
61
|
+
display: flex;
|
|
62
|
+
flex-direction: column;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
.header {
|
|
66
|
+
margin-bottom: 1rem;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
.cols-container {
|
|
70
|
+
display: flex;
|
|
71
|
+
flex-grow: 1;
|
|
72
|
+
column-gap: 2rem;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
.col {
|
|
76
|
+
display: flex;
|
|
77
|
+
flex-direction: column;
|
|
78
|
+
width: 33.33%;
|
|
79
|
+
justify-content: v-bind(contentAlignmentStyle);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
.left {
|
|
83
|
+
padding-right: 0.5rem;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
.middle {
|
|
87
|
+
padding-left: 0.5rem;
|
|
88
|
+
padding-right: 0.5rem;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
.right {
|
|
92
|
+
padding-left: 0.5rem;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
.logo-container {
|
|
96
|
+
position: absolute;
|
|
97
|
+
top: 1rem;
|
|
98
|
+
right: 1rem;
|
|
99
|
+
z-index: 10;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/* Logo styling moved to global layout.css */
|
|
103
|
+
</style>
|