slidev-theme-tud-db 0.0.2 → 0.0.4
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/components/Takeaway.vue +48 -0
- package/global-bottom.vue +29 -7
- package/layouts/cover.vue +4 -21
- package/layouts/default.vue +4 -0
- package/layouts/section-num.vue +3 -15
- package/layouts/section.vue +4 -9
- package/layouts/two-cols-grid.vue +4 -0
- package/layouts/two-cols-header.vue +4 -0
- package/package.json +2 -1
- package/scripts/logo.ts +29 -0
- package/styles/db-theme.css +60 -2
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { computed } from 'vue'
|
|
3
|
+
|
|
4
|
+
// F1-style callout: a coloured left rule + a small uppercase eyebrow label, no
|
|
5
|
+
// fill, no symbol, upright (non-italic) body text. Knobs:
|
|
6
|
+
// label the eyebrow text ("Key Takeaway", "Question", "Problem"…); label=""
|
|
7
|
+
// hides it and leaves a bare ruled aside.
|
|
8
|
+
// color the rule + label colour: a brand keyword (below) or any CSS colour,
|
|
9
|
+
// so e.g. problems read red while takeaways stay blue.
|
|
10
|
+
// size optional overall scale — body text matches the slide's default text
|
|
11
|
+
// size by default; set e.g. size="1.1em" (or a bare number "1.1") to
|
|
12
|
+
// enlarge the whole callout. All spacing is em-based, so it stays
|
|
13
|
+
// vertically balanced at any size.
|
|
14
|
+
// Authoring (MDC block, needs `mdc: true`):
|
|
15
|
+
// ::takeaway{label="Problem" color="red"}
|
|
16
|
+
// A question can hide the fact that nothing was proven.
|
|
17
|
+
// ::
|
|
18
|
+
const props = defineProps({
|
|
19
|
+
label: { type: String, default: 'Key Takeaway' },
|
|
20
|
+
color: { type: String, default: 'blue' },
|
|
21
|
+
size: { type: String, default: '' },
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
// Brand-colour keywords -> theme tokens; anything else is used as a raw CSS colour.
|
|
25
|
+
const TOKENS: Record<string, string> = {
|
|
26
|
+
blue: 'var(--db-heading-blue)',
|
|
27
|
+
navy: 'var(--db-navy)',
|
|
28
|
+
teal: 'var(--db-accent3)',
|
|
29
|
+
green: 'var(--db-accent1)',
|
|
30
|
+
yellow: 'var(--db-accent4)',
|
|
31
|
+
red: 'var(--db-accent5)',
|
|
32
|
+
orange: 'var(--db-accent5)',
|
|
33
|
+
purple: 'var(--db-accent6)',
|
|
34
|
+
}
|
|
35
|
+
const accent = computed(() => TOKENS[props.color?.toLowerCase()] ?? props.color)
|
|
36
|
+
|
|
37
|
+
// A bare number ("1.1") is treated as an em multiplier; otherwise used verbatim.
|
|
38
|
+
const fontSize = computed(() =>
|
|
39
|
+
!props.size ? undefined : /^[\d.]+$/.test(props.size) ? `${props.size}em` : props.size,
|
|
40
|
+
)
|
|
41
|
+
</script>
|
|
42
|
+
|
|
43
|
+
<template>
|
|
44
|
+
<div class="db-takeaway" :style="{ '--tk-accent': accent, fontSize }">
|
|
45
|
+
<div v-if="label" class="db-takeaway__label">{{ label }}</div>
|
|
46
|
+
<div class="db-takeaway__body"><slot /></div>
|
|
47
|
+
</div>
|
|
48
|
+
</template>
|
package/global-bottom.vue
CHANGED
|
@@ -1,23 +1,45 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import { useSlideContext } from '@slidev/client'
|
|
3
3
|
import { computed } from 'vue'
|
|
4
|
+
import { slideLogos } from './scripts/logo'
|
|
4
5
|
|
|
5
6
|
import ddrgColor from './assets/ddrg-color.svg'
|
|
7
|
+
import ddrgWhite from './assets/ddrg-white.svg'
|
|
8
|
+
import tudWhite from './assets/tud-white.svg'
|
|
6
9
|
import tudBlack from './assets/tud-black.svg'
|
|
7
10
|
|
|
8
11
|
const { $nav } = useSlideContext()
|
|
9
|
-
const
|
|
12
|
+
const logos = computed(() => slideLogos[$nav.value.currentPage] ?? {})
|
|
10
13
|
</script>
|
|
11
14
|
|
|
12
15
|
<template>
|
|
13
|
-
<div
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
16
|
+
<div class="absolute inset-0 z-100 pointer-events-none">
|
|
17
|
+
<div class="absolute flex flex-row-reverse items-start gap-[45px] top-[25px] right-[35px]">
|
|
18
|
+
<div class="relative h-[45px]">
|
|
19
|
+
<img
|
|
20
|
+
:class="{ 'opacity-0': logos.ddrg !== 'color' }"
|
|
21
|
+
class="h-full transition-opacity duration-500"
|
|
22
|
+
:src="ddrgColor"
|
|
23
|
+
alt="Dresden Database Research Group"
|
|
24
|
+
/>
|
|
25
|
+
<img
|
|
26
|
+
:class="{ 'opacity-0': logos.ddrg !== 'white' }"
|
|
27
|
+
class="absolute inset-0 h-full transition-opacity duration-500"
|
|
28
|
+
:src="ddrgWhite"
|
|
29
|
+
alt="Dresden Database Research Group"
|
|
30
|
+
/>
|
|
31
|
+
</div>
|
|
32
|
+
<img
|
|
33
|
+
:class="{ 'opacity-0': !logos.tud }"
|
|
34
|
+
class="h-[45px] transition-opacity duration-500"
|
|
35
|
+
:src="tudWhite"
|
|
36
|
+
alt="TU Dresden"
|
|
37
|
+
/>
|
|
38
|
+
</div>
|
|
18
39
|
|
|
19
40
|
<footer
|
|
20
|
-
class="
|
|
41
|
+
:class="{ 'opacity-0': !logos.footer }"
|
|
42
|
+
class="db-footer absolute inset-x-0 bottom-0 h-[40px] px-[30px] flex items-center justify-between bg-[var(--db-footer-bg)] pointer-events-auto transition-opacity duration-500"
|
|
21
43
|
>
|
|
22
44
|
<img class="h-[25px]" :src="tudBlack" alt="TU Dresden" />
|
|
23
45
|
<span class="text-[12px] text-[var(--db-text)]">
|
package/layouts/cover.vue
CHANGED
|
@@ -1,32 +1,15 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
|
|
3
|
-
// title area below. Reconstructed as pure vector: the navy is a CSS fill, the
|
|
4
|
-
// corner mosaic is `cover-mosaic.svg` (rebuilt from the original DB_template.potx
|
|
5
|
-
// title-slide tiles), and the logos are the theme's own white SVGs. No raster.
|
|
6
|
-
// Geometry (positions/sizes in pt == px on the 720-wide canvas) is taken from
|
|
7
|
-
// slideLayout1.xml ("Titelfolie") so it matches the source template.
|
|
2
|
+
import { useLogo } from '../scripts/logo'
|
|
8
3
|
import mosaic from '../assets/mosaic.svg'
|
|
9
|
-
|
|
10
|
-
|
|
4
|
+
|
|
5
|
+
useLogo({ ddrg: 'white', tud: true })
|
|
11
6
|
</script>
|
|
12
7
|
|
|
13
8
|
<template>
|
|
14
9
|
<div class="slidev-layout db-cover p-0">
|
|
15
|
-
<!-- navy band: solid fill + vector mosaic
|
|
10
|
+
<!-- navy band: solid fill + vector mosaic, logos handled by global-bottom -->
|
|
16
11
|
<div class="relative w-full h-[345px] bg-[var(--db-navy)] overflow-hidden">
|
|
17
12
|
<img class="absolute h-full scale-[1.01]" :src="mosaic" alt="" />
|
|
18
|
-
<div class="absolute flex gap-[45px] top-[25px] right-[35px]">
|
|
19
|
-
<img
|
|
20
|
-
class="h-[45px]"
|
|
21
|
-
:src="tudWhite"
|
|
22
|
-
alt="TU Dresden"
|
|
23
|
-
/>
|
|
24
|
-
<img
|
|
25
|
-
class="h-[45px]"
|
|
26
|
-
:src="ddrgWhite"
|
|
27
|
-
alt="Dresden Database Research Group"
|
|
28
|
-
/>
|
|
29
|
-
</div>
|
|
30
13
|
</div>
|
|
31
14
|
|
|
32
15
|
<!-- white area: title (#) + subtitle (following text) -->
|
package/layouts/default.vue
CHANGED
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
+
import { useLogo } from '../scripts/logo'
|
|
3
|
+
|
|
2
4
|
// "Titel und Inhalt": title + single content column. Chrome via DbFrame.
|
|
3
5
|
// `codeSize` frontmatter (optional) overrides the code font size for the slide.
|
|
4
6
|
const props = defineProps({
|
|
5
7
|
codeSize: { type: String, default: '' },
|
|
6
8
|
})
|
|
9
|
+
|
|
10
|
+
useLogo({ ddrg: 'color', footer: true })
|
|
7
11
|
</script>
|
|
8
12
|
|
|
9
13
|
<template>
|
package/layouts/section-num.vue
CHANGED
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
import { useSlideContext } from '@slidev/client'
|
|
3
3
|
import { computed } from 'vue'
|
|
4
4
|
|
|
5
|
-
import
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
import { useLogo } from '../scripts/logo'
|
|
6
|
+
|
|
7
|
+
useLogo({ ddrg: 'white', tud: true })
|
|
8
8
|
|
|
9
9
|
// The large glyph in the blue area can be overridden per slide via the `num`
|
|
10
10
|
// frontmatter, e.g.
|
|
@@ -49,18 +49,6 @@ const num = computed(() => {
|
|
|
49
49
|
v-if="num !== ''"
|
|
50
50
|
class="absolute font-700 text-[24rem]/[24rem] pt-8 px-4 bg-white bg-clip-text text-transparent"
|
|
51
51
|
>{{ num }}</div>
|
|
52
|
-
<div class="absolute flex gap-[45px] top-[25px] right-[35px]">
|
|
53
|
-
<img
|
|
54
|
-
class="h-[45px]"
|
|
55
|
-
:src="tudWhite"
|
|
56
|
-
alt="TU Dresden"
|
|
57
|
-
/>
|
|
58
|
-
<img
|
|
59
|
-
class="h-[45px]"
|
|
60
|
-
:src="ddrgWhite"
|
|
61
|
-
alt="Dresden Database Research Group"
|
|
62
|
-
/>
|
|
63
|
-
</div>
|
|
64
52
|
</div>
|
|
65
53
|
|
|
66
54
|
<!-- white area: title (#) + subtitle (following text) -->
|
package/layouts/section.vue
CHANGED
|
@@ -1,18 +1,13 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
|
|
3
|
-
// title area below. Reconstructed as pure vector: the navy is a CSS fill, the
|
|
4
|
-
// corner mosaic is `cover-mosaic.svg` (rebuilt from the original DB_template.potx
|
|
5
|
-
// title-slide tiles), and the logos are the theme's own white SVGs. No raster.
|
|
6
|
-
// Geometry (positions/sizes in pt == px on the 720-wide canvas) is taken from
|
|
7
|
-
// slideLayout1.xml ("Titelfolie") so it matches the source template.
|
|
2
|
+
import { useLogo } from '../scripts/logo'
|
|
8
3
|
import mosaic from '../assets/section-mosaic.svg'
|
|
9
|
-
|
|
10
|
-
|
|
4
|
+
|
|
5
|
+
useLogo({ ddrg: 'color', footer: true })
|
|
11
6
|
</script>
|
|
12
7
|
|
|
13
8
|
<template>
|
|
14
9
|
<div class="slidev-layout db-cover p-0">
|
|
15
|
-
<!--
|
|
10
|
+
<!-- blue band: solid fill + vector mosaic -->
|
|
16
11
|
<div class="relative w-full mt-[95px] h-[250px] bg-[#97c6ff] overflow-hidden">
|
|
17
12
|
<img class="absolute h-full scale-[1.01]" :src="mosaic" alt="" />
|
|
18
13
|
</div>
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
+
import { useLogo } from '../scripts/logo'
|
|
3
|
+
|
|
2
4
|
// Like two-cols-header, but the two columns are laid out as a ROW GRID: every
|
|
3
5
|
// top-level <div> in the `::grid::` slot becomes a cell, filling left, right,
|
|
4
6
|
// left, right… Because CSS grid rows align across columns, paired items (e.g. a
|
|
@@ -19,6 +21,8 @@ const props = defineProps({
|
|
|
19
21
|
columns: { type: String, default: '1fr 1fr' },
|
|
20
22
|
codeSize: { type: String, default: '' },
|
|
21
23
|
})
|
|
24
|
+
|
|
25
|
+
useLogo({ ddrg: 'color', footer: true })
|
|
22
26
|
</script>
|
|
23
27
|
|
|
24
28
|
<template>
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
+
import { useLogo } from '../scripts/logo'
|
|
3
|
+
|
|
2
4
|
// "Zwei Inhalte": full-width title (default slot) + two columns. Chrome via DbFrame.
|
|
3
5
|
// Column ratio is configurable per slide via the `columns` frontmatter, e.g.
|
|
4
6
|
// layout: two-cols-header
|
|
@@ -7,6 +9,8 @@ const props = defineProps({
|
|
|
7
9
|
columns: { type: String, default: '1fr 1fr' },
|
|
8
10
|
codeSize: { type: String, default: '' },
|
|
9
11
|
})
|
|
12
|
+
|
|
13
|
+
useLogo({ ddrg: 'color', footer: true })
|
|
10
14
|
</script>
|
|
11
15
|
|
|
12
16
|
<template>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "slidev-theme-tud-db",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.4",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Slidev theme cloning the TU Dresden / Dresden Database Research Group PowerPoint template",
|
|
6
6
|
"license": "GPL-3.0-or-later",
|
|
@@ -24,6 +24,7 @@
|
|
|
24
24
|
"components",
|
|
25
25
|
"global-bottom.vue",
|
|
26
26
|
"layouts",
|
|
27
|
+
"scripts",
|
|
27
28
|
"markdown.ts",
|
|
28
29
|
"setup",
|
|
29
30
|
"styles",
|
package/scripts/logo.ts
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { reactive, toValue, watchEffect } from 'vue'
|
|
2
|
+
import type { MaybeRefOrGetter } from 'vue'
|
|
3
|
+
import { useSlideContext } from '@slidev/client'
|
|
4
|
+
|
|
5
|
+
function createRegistry<T>() {
|
|
6
|
+
const store = reactive<Record<number, T>>({})
|
|
7
|
+
|
|
8
|
+
function publish(value: MaybeRefOrGetter<T>) {
|
|
9
|
+
const page = toValue(useSlideContext().$page)
|
|
10
|
+
watchEffect(() => {
|
|
11
|
+
store[page] = toValue(value)
|
|
12
|
+
})
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
return { store, publish }
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface SlideLogos {
|
|
19
|
+
ddrg?: 'color' | 'white'
|
|
20
|
+
tud?: boolean
|
|
21
|
+
footer?: boolean
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const slideLogosReg = createRegistry<SlideLogos>()
|
|
25
|
+
export const slideLogos = slideLogosReg.store
|
|
26
|
+
|
|
27
|
+
export function useLogo(logos: MaybeRefOrGetter<SlideLogos>) {
|
|
28
|
+
slideLogosReg.publish(logos)
|
|
29
|
+
}
|
package/styles/db-theme.css
CHANGED
|
@@ -160,6 +160,35 @@
|
|
|
160
160
|
font-style: normal; /* keep inline code upright inside the italic aside */
|
|
161
161
|
}
|
|
162
162
|
|
|
163
|
+
/* Rhetorical-question / one-sentence-takeaway callout (<Takeaway> via ::takeaway).
|
|
164
|
+
"F1" style: a coloured left rule fitted to the text height + a small uppercase
|
|
165
|
+
eyebrow label, no fill, no symbol. The accent colour is driven by --tk-accent
|
|
166
|
+
(set inline by the component from its `color` prop), defaulting to brand blue. */
|
|
167
|
+
.slidev-layout.db-default .db-takeaway {
|
|
168
|
+
margin: 0.6em 0;
|
|
169
|
+
/* em-based so the rule stays vertically balanced at any `size`. The tiny
|
|
170
|
+
top/bottom difference offsets the label cap-height vs body baseline insets. */
|
|
171
|
+
padding: 0.28em 0 0.11em 0.85em;
|
|
172
|
+
border-left: 3px solid var(--tk-accent, var(--db-heading-blue));
|
|
173
|
+
}
|
|
174
|
+
.slidev-layout.db-default .db-takeaway__label {
|
|
175
|
+
margin-bottom: 0.3em;
|
|
176
|
+
font-size: 0.72em;
|
|
177
|
+
font-weight: 700;
|
|
178
|
+
letter-spacing: 0.09em;
|
|
179
|
+
line-height: 1.1;
|
|
180
|
+
text-transform: uppercase;
|
|
181
|
+
color: var(--tk-accent, var(--db-heading-blue));
|
|
182
|
+
}
|
|
183
|
+
.slidev-layout.db-default .db-takeaway__body {
|
|
184
|
+
font-size: 1em;
|
|
185
|
+
line-height: 1.2;
|
|
186
|
+
color: var(--db-text-soft);
|
|
187
|
+
}
|
|
188
|
+
.slidev-layout.db-default .db-takeaway__body p { margin: 0; }
|
|
189
|
+
.slidev-layout.db-default .db-takeaway__body strong { font-weight: 700; }
|
|
190
|
+
.slidev-layout.db-default .db-takeaway__body code { font-weight: 500; }
|
|
191
|
+
|
|
163
192
|
/* Fenced code blocks: box only as wide as its content, not full slide width.
|
|
164
193
|
fit-content on the WRAPPER so an optional caption + the code share one width.
|
|
165
194
|
max-width keeps long lines from overflowing the slide. */
|
|
@@ -187,9 +216,12 @@
|
|
|
187
216
|
are a wide 24px gap between the number and the code, plus the block's 10px
|
|
188
217
|
left padding before the number. Both are scoped to line-numbered blocks so
|
|
189
218
|
plain code blocks keep their normal padding. */
|
|
190
|
-
.slidev-layout.db-default .slidev-code-line-numbers .slidev-code
|
|
219
|
+
.slidev-layout.db-default .slidev-code-line-numbers .slidev-code,
|
|
220
|
+
.slidev-layout.db-default .shiki-magic-move-container.slidev-code {
|
|
191
221
|
/* override the padding *variable* (Slidev applies padding via it, which beats
|
|
192
|
-
a plain padding-left here). top right bottom left — only the left shrinks.
|
|
222
|
+
a plain padding-left here). top right bottom left — only the left shrinks.
|
|
223
|
+
The Magic Move container isn't wrapped in .slidev-code-line-numbers, so it
|
|
224
|
+
needs the same override to keep its gutter rule aligned with plain blocks. */
|
|
193
225
|
--slidev-code-padding: 4px 10px 4px 6px; /* less space left of the numbers (was 10px) */
|
|
194
226
|
}
|
|
195
227
|
.slidev-layout.db-default .slidev-code-line-numbers .slidev-code code .line::before {
|
|
@@ -202,6 +234,32 @@
|
|
|
202
234
|
margin-right: 7px; /* separator → code (was a plain 8px gap) */
|
|
203
235
|
}
|
|
204
236
|
|
|
237
|
+
/* Magic Move (```md magic-move```) renders line numbers as real
|
|
238
|
+
.shiki-magic-move-line-number elements (each with opacity:0.3), not the
|
|
239
|
+
::before pseudo the plain blocks use — so the gutter rule above never reaches
|
|
240
|
+
them and the separator was missing. Re-create the same gutter: recolour the
|
|
241
|
+
numbers to match plain line-numbered blocks (gray-400, gray-600 in dark) so
|
|
242
|
+
the border can sit at full opacity instead of the dimmed 0.3. */
|
|
243
|
+
.slidev-layout.db-default .shiki-magic-move-line-number {
|
|
244
|
+
opacity: 1;
|
|
245
|
+
color: rgb(156 163 175);
|
|
246
|
+
/* Mirror the plain block's ::before geometry exactly: a fixed 1ch column,
|
|
247
|
+
right-aligned, so the digit is pinned against the padding instead of
|
|
248
|
+
shrink-wrapped and left-aligned. white-space:normal drops the literal
|
|
249
|
+
trailing spaces Magic Move pads numbers with (e.g. "1 "). */
|
|
250
|
+
box-sizing: border-box;
|
|
251
|
+
width: 1ch;
|
|
252
|
+
text-align: right;
|
|
253
|
+
overflow: visible;
|
|
254
|
+
white-space: normal;
|
|
255
|
+
padding-right: 10px; /* number → separator */
|
|
256
|
+
border-right: 1px solid var(--db-table-rule);
|
|
257
|
+
margin-right: 7px; /* separator → code */
|
|
258
|
+
}
|
|
259
|
+
.dark .slidev-layout.db-default .shiki-magic-move-line-number {
|
|
260
|
+
color: rgb(75 85 99);
|
|
261
|
+
}
|
|
262
|
+
|
|
205
263
|
/* Optional caption above a code block.
|
|
206
264
|
Authoring: ```python [What this snippet does] */
|
|
207
265
|
.slidev-layout.db-default .slidev-code-block-title {
|