slidev-theme-tud-db 0.0.5 → 0.0.7

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 CHANGED
@@ -29,7 +29,7 @@ pnpm dev
29
29
 
30
30
  No `addons:` line needed — the theme enables `slidev-addon-gsap` via its
31
31
  defaults, so `import { useTl } from 'slidev-addon-gsap'` works in any slide. The
32
- theme also sets `canvasWidth: 960` (1px == 1pt), Noto Sans, light scheme, and
32
+ theme also sets `canvasWidth: 960` (the 720pt PowerPoint slide, so 1pt == 4/3 px), Noto Sans, light scheme, and
33
33
  Comark on; override any in your own headmatter.
34
34
 
35
35
  ## Example
@@ -55,5 +55,7 @@ cp -r node_modules/slidev-theme-db/skills/slidev-theme-db .claude/skills/
55
55
  - `styles/db-theme.css` — tokens, typography, lists, tables (keyed on `.db-default`).
56
56
  - `setup/shiki.ts` (fenced) and the `THEME` in `vite.config.ts` (inline `{lang}`) —
57
57
  the **two** highlighters; keep them in sync (both `catppuccin-latte`).
58
+ `setup/shiki.ts` also holds the transformer behind `⟦name:text⟧` code marks
59
+ (spans a slide's timeline can recolour).
58
60
  - Link the theme with `link:` (not `file:`), and **restart** the dev server after
59
61
  editing theme files (Vite doesn't hot-reload `node_modules`).
@@ -11,7 +11,8 @@ const props = defineProps({
11
11
  class="slidev-layout default db-default relative"
12
12
  :style="props.codeSize ? { '--slidev-code-font-size': props.codeSize } : undefined"
13
13
  >
14
- <div class="db-default__body px-[30px] py-[33.5px]">
14
+ <!-- top padding puts the title's baseline at 41.9pt, as in the template -->
15
+ <div class="db-default__body px-[30px] pt-[26.5px] pb-[33.5px]">
15
16
  <slot />
16
17
  </div>
17
18
  </div>
package/global-bottom.vue CHANGED
@@ -42,7 +42,7 @@ const logos = computed(() => slideLogos[$nav.value.currentPage] ?? {})
42
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"
43
43
  >
44
44
  <img class="h-[25px]" :src="tudBlack" alt="TU Dresden" />
45
- <span class="text-[12px] text-[var(--db-text)]">
45
+ <span class="db-footer__page">
46
46
  <span class="font-bold">{{ $nav.currentPage }}</span>
47
47
  <template v-if="$nav.clicksTotal > 0">
48
48
  <span class="text-[0.7em]">.{{ $nav.clicks + 1 }}</span>
package/layouts/cover.vue CHANGED
@@ -21,12 +21,12 @@ useLogo({ ddrg: 'white', tud: true })
21
21
 
22
22
  <style scoped>
23
23
  .db-cover__title :deep(h1) {
24
- @apply text-4xl! font-700;
24
+ @apply font-700 leading-10;
25
+ font-size: var(--db-fs-cover-title) !important;
25
26
  }
26
27
  .db-cover__title :deep(p) {
27
- @apply absolute top-[95px] m-0 text-md;
28
- /* margin: 16px 0 0; */
29
- /* font-size: 15px; */
28
+ @apply absolute top-[95px] m-0;
29
+ font-size: var(--db-fs-subtitle);
30
30
  color: var(--db-text-soft);
31
31
  }
32
32
  </style>
@@ -60,10 +60,12 @@ const num = computed(() => {
60
60
 
61
61
  <style scoped>
62
62
  .db-cover__title :deep(h1) {
63
- @apply text-4xl! font-700 text-[var(--db-heading-blue)];
63
+ @apply font-700 leading-10 text-[var(--db-heading-blue)];
64
+ font-size: var(--db-fs-cover-title) !important;
64
65
  }
65
66
  .db-cover__title :deep(p) {
66
- @apply absolute top-[95px] m-0 text-md;
67
+ @apply absolute top-[95px] m-0;
68
+ font-size: var(--db-fs-subtitle);
67
69
  color: var(--db-text-soft);
68
70
  }
69
71
  </style>
@@ -21,12 +21,12 @@ useLogo({ ddrg: 'color', footer: true })
21
21
 
22
22
  <style scoped>
23
23
  .db-cover__title :deep(h1) {
24
- @apply text-4xl! font-700 text-[var(--db-heading-blue)];
24
+ @apply font-700 leading-10 text-[var(--db-heading-blue)];
25
+ font-size: var(--db-fs-section-title) !important;
25
26
  }
26
27
  .db-cover__title :deep(p) {
27
- @apply absolute top-[95px] m-0 text-md;
28
- /* margin: 16px 0 0; */
29
- /* font-size: 15px; */
28
+ @apply absolute top-[95px] m-0;
29
+ font-size: var(--db-fs-subtitle);
30
30
  color: var(--db-text-soft);
31
31
  }
32
32
  </style>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "slidev-theme-tud-db",
3
- "version": "0.0.5",
3
+ "version": "0.0.7",
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",
package/setup/shiki.ts CHANGED
@@ -5,9 +5,51 @@
5
5
  // NB: no `import { defineShikiSetup } from '@slidev/types'` on purpose — it's
6
6
  // only a type helper, and Slidev calls this default export as `setup(ctx)`.
7
7
  // catppuccin-latte / -mocha are bundled with Shiki, so no extra deps needed.
8
+
9
+ // Code marks: wrap exact character ranges of a fenced block so a slide can
10
+ // recolour that text, e.g. at a click. Inside the code, write ⟦name:text⟧: the
11
+ // markers are removed and `text` is wrapped in <span class="code-mark mark-name">.
12
+ //
13
+ // WHERE salary > ⟦paren:(⟧
14
+ //
15
+ // A mark looks like the code around it until something recolours it, typically
16
+ // a gsap timeline at a click. A mark can span several syntax-coloured tokens,
17
+ // so recolour the tokens inside it too:
18
+ //
19
+ // tl.to('.mark-paren, .mark-paren span', { color: '#f9c611' })
20
+ //
21
+ // A mark must stay within one line. Magic-move blocks don't run Shiki
22
+ // transformers, so marks only work in plain fenced blocks.
23
+ const MARK = /⟦([\w-]+):([^⟧\n]*)⟧/g
24
+
25
+ interface Decoration { start: number, end: number, properties: Record<string, string> }
26
+
27
+ const codeMarks = {
28
+ name: 'tud-db:code-marks',
29
+ preprocess(code: string, options: { decorations?: Decoration[] }) {
30
+ if (!code.includes('⟦'))
31
+ return
32
+ const marks: Decoration[] = []
33
+ let out = ''
34
+ let last = 0
35
+ for (const m of code.matchAll(MARK)) {
36
+ out += code.slice(last, m.index)
37
+ const start = out.length
38
+ out += m[2]
39
+ marks.push({ start, end: out.length, properties: { class: `code-mark mark-${m[1]}` } })
40
+ last = m.index! + m[0].length
41
+ }
42
+ out += code.slice(last)
43
+ // Shiki reads the decorations from these options when it renders
44
+ options.decorations = [...(options.decorations ?? []), ...marks]
45
+ return out
46
+ },
47
+ }
48
+
8
49
  export default () => ({
9
50
  themes: {
10
51
  light: 'catppuccin-latte',
11
52
  dark: 'catppuccin-mocha',
12
53
  },
54
+ transformers: [codeMarks],
13
55
  })
@@ -20,6 +20,21 @@
20
20
  --db-table-stripe: #dbdbdb; /* zebra-striped table rows */
21
21
  --db-table-rule: #b9b9b9; /* table header/footer rule lines */
22
22
 
23
+ /* Type scale, in PowerPoint points. The template slide is 720×405pt but the
24
+ theme renders it on Slidev's 960×540px canvas, so 1pt == 4/3 px — never
25
+ write a pt value as px. Sizes measured from resource/template.pdf. */
26
+ --db-pt: calc(4px / 3);
27
+ --db-fs-cover-title: calc(28 * var(--db-pt)); /* cover / section-num title */
28
+ --db-fs-section-title: calc(24 * var(--db-pt)); /* section title */
29
+ --db-fs-subtitle: calc(14 * var(--db-pt)); /* cover / section subtitle */
30
+ --db-fs-title: calc(22 * var(--db-pt)); /* content slide title (h1) */
31
+ --db-fs-heading: calc(15 * var(--db-pt)); /* blue sub-header (h2/h3) */
32
+ --db-fs-body: calc(13 * var(--db-pt)); /* body text, 1st-level bullets */
33
+ --db-fs-small: calc(12 * var(--db-pt)); /* 2nd-level bullets, page number */
34
+ --db-fs-code: calc(11 * var(--db-pt)); /* code blocks */
35
+ --db-fs-caption: calc(11 * var(--db-pt)); /* table / code captions */
36
+ --db-fs-table: calc(10 * var(--db-pt)); /* table cells */
37
+
23
38
  /* Slidev theme variables */
24
39
  --slidev-theme-primary: var(--db-accent3);
25
40
  }
@@ -29,8 +44,7 @@
29
44
  * height:100% fills the slide (theme provides this; not inherited from
30
45
  * @slidev/theme-default anymore). */
31
46
  .slidev-layout {
32
- height: 100%;
33
- background: #ffffff;
47
+ /* background: #ffffff; */
34
48
  color: var(--db-text-soft);
35
49
  font-family: 'NotoSans', ui-sans-serif, system-ui, sans-serif;
36
50
  }
@@ -60,33 +74,36 @@
60
74
  color: var(--db-accent3);
61
75
  }
62
76
 
63
- /* Content slides ("Titel und Inhalt").
64
- * Canvas is 720px wide (== 720pt real slide), so px values below equal PowerPoint pt. */
77
+ /* Content slides ("Titel und Inhalt"). Font sizes come from the pt type scale
78
+ * on :root; spacing below is in canvas px, chosen so the baselines land where
79
+ * resource/template.pdf has them: title 41.9pt, first sub-header 92.5pt, then
80
+ * bullets every 18pt, and 27.9pt from a bullet to the next sub-header. (Noto
81
+ * Sans puts the baseline 0.388em below the middle of its line box.) */
65
82
  .slidev-layout.db-default {
66
- font-size: 13px; /* bullet / body text = 13pt */
67
- line-height: 1.15; /* tight line spacing */
68
- padding: 0; /* we control spacing via the body wrapper + footer */
83
+ font-size: var(--db-fs-body);
84
+ padding: 0;
69
85
  }
70
86
  .slidev-layout.db-default h1 {
71
87
  color: var(--db-text-soft); /* black/gray page heading */
72
- font-size: 22px; /* 22pt */
73
- line-height: 1.2;
74
- margin-bottom: 36px; /* gap to first sub-header (~36pt in template) */
88
+ font-size: var(--db-fs-title);
89
+ line-height: 2.25rem;
90
+ margin-bottom: 39px; /* gap to first sub-header (baseline at 92.5pt) */
75
91
  }
76
92
  .slidev-layout.db-default h2,
77
93
  .slidev-layout.db-default h3 {
78
94
  color: var(--db-heading-blue); /* blue sub-headers */
79
- font-size: 15px; /* 15pt */
80
- line-height: 1.25;
81
- margin-top: 24px; /* space ABOVE a sub-header, whatever precedes it
82
- (bullet list, code block, paragraph, …) */
95
+ font-size: var(--db-fs-heading);
96
+ line-height: 1.75rem;
97
+ margin-top: 11px; /* space ABOVE a sub-header, whatever precedes it
98
+ (bullet list, code block, paragraph, …);
99
+ 27.9pt baseline-to-baseline after a bullet */
83
100
  }
84
101
  /* …except a sub-header that is the FIRST content of its area (right under the
85
102
  page title, or the top of a column / grid cell) — the title's margin-bottom
86
103
  or the grid gap already provides that separation.
87
104
  This is wrap-proof: a section wrapped in a <div> (e.g. a GSAP animation
88
105
  anchor) is still treated as "top" when its wrapper is the first child, but a
89
- wrapped section that FOLLOWS other content keeps the 24px gap. So adding a
106
+ wrapped section that FOLLOWS other content keeps its top gap. So adding a
90
107
  wrapper div later does NOT collapse the spacing. (default layout: h1 is a
91
108
  sibling of the content; two-cols-header: .db-grid__col; two-cols-grid:
92
109
  .db-rowgrid cells.) */
@@ -112,7 +129,7 @@
112
129
  .slidev-layout.db-default ul ul,
113
130
  .slidev-layout.db-default ol ol {
114
131
  margin-left: 0; /* 2nd-level marker aligns with 1st-level text (no extra indent) */
115
- font-size: 12px; /* 2nd-level text a touch smaller (12pt vs 13pt) */
132
+ font-size: var(--db-fs-small); /* 2nd-level text a touch smaller (12pt vs 13pt) */
116
133
  }
117
134
  .slidev-layout.db-default ul ul { list-style-type: square; }
118
135
  /* Tight vertical rhythm (theme defaults to ~1.8 line-height) */
@@ -135,11 +152,6 @@
135
152
  .slidev-layout.db-default li::marker {
136
153
  color: var(--db-text-soft);
137
154
  }
138
- /* Shrink only the bullet glyphs (• ▪); ordered-list numbers keep text size. */
139
- .slidev-layout.db-default ul li::marker {
140
- font-size: 0.8em;
141
- }
142
-
143
155
  /* Blockquotes -> a muted italic aside with a leading en-dash
144
156
  (the "– …" secondary-note style). */
145
157
  .slidev-layout.db-default blockquote {
@@ -204,24 +216,39 @@
204
216
  .slidev-layout.db-default .with-bg pre.slidev-code {
205
217
  background: rgba(0, 0, 0, 0.03) !important;
206
218
  }
207
- /* Code sizing (Slidev defaults: 12px / 18px / 8px). Slightly smaller font and
208
- tighter vertical padding so the box hugs the code top and bottom. */
219
+ /* Code sizing (Slidev defaults: 12px / 18px / 8px). 11pt like the template's
220
+ listings, with tighter vertical padding so the box hugs the code top and bottom.
221
+ No left padding: without a background box, the code text lines up with the
222
+ text, captions and tables around it, as in the template. A .with-bg box gets
223
+ its inset back. */
209
224
  .slidev-layout.db-default {
210
- --slidev-code-font-size: 11px;
225
+ --slidev-code-font-size: var(--db-fs-code);
211
226
  --slidev-code-line-height: 1.3;
227
+ --slidev-code-padding: 4px 10px 4px 0;
228
+ }
229
+ .slidev-layout.db-default .with-bg {
212
230
  --slidev-code-padding: 4px 10px;
213
231
  }
232
+ /* No programming ligatures: Fira Code would draw <> as a diamond and <=, >=,
233
+ != as ≤, ≥, ≠, which readers then can't type. Code shows the characters
234
+ as written. (The theme's --> arrows in prose are a text replacement, not a
235
+ ligature, so they are unaffected.) */
236
+ .slidev-layout code,
237
+ .slidev-layout pre {
238
+ font-variant-ligatures: none;
239
+ }
214
240
 
215
241
  /* Line numbers (```lang {lines:true}```): tighten the gutter. Slidev's defaults
216
242
  are a wide 24px gap between the number and the code, plus the block's 10px
217
243
  left padding before the number. Both are scoped to line-numbered blocks so
218
244
  plain code blocks keep their normal padding. */
219
245
  .slidev-layout.db-default .slidev-code-line-numbers .slidev-code,
220
- .slidev-layout.db-default .shiki-magic-move-container.slidev-code {
246
+ .slidev-layout.db-default .shiki-magic-move-container.slidev-code:has(.shiki-magic-move-line-number) {
221
247
  /* override the padding *variable* (Slidev applies padding via it, which beats
222
248
  a plain padding-left here). top right bottom left — only the left shrinks.
223
249
  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. */
250
+ needs the same override to keep its gutter rule aligned with plain blocks;
251
+ one without line numbers keeps the plain blocks' zero inset. */
225
252
  --slidev-code-padding: 4px 10px 4px 6px; /* less space left of the numbers (was 10px) */
226
253
  }
227
254
  .slidev-layout.db-default .slidev-code-line-numbers .slidev-code code .line::before {
@@ -263,13 +290,16 @@
263
290
  /* Optional caption above a code block.
264
291
  Authoring: ```python [What this snippet does] */
265
292
  .slidev-layout.db-default .slidev-code-block-title {
266
- padding: 3px 10px;
293
+ padding: 3px 0; /* flush with the code text below (see above) */
267
294
  background: transparent; /* drop Slidev's heavy gray title bar */
268
- font-size: 11px;
295
+ font-size: var(--db-fs-caption);
269
296
  font-style: italic;
270
297
  color: var(--db-text);
271
298
  opacity: 0.85;
272
299
  }
300
+ .slidev-layout.db-default .with-bg .slidev-code-block-title {
301
+ padding-inline: 10px; /* match the boxed code's inset */
302
+ }
273
303
 
274
304
  /* Optional table captions (need Comark, enabled by this theme).
275
305
  ABOVE the table: [Title]{.table-caption} -> black, non-italic
@@ -282,7 +312,7 @@
282
312
  .slidev-layout.db-default p:has(.table-caption),
283
313
  .slidev-layout.db-default .table-footer,
284
314
  .slidev-layout.db-default p:has(.table-footer) {
285
- font-size: 11px;
315
+ font-size: var(--db-fs-caption);
286
316
  background: transparent !important;
287
317
  }
288
318
  .slidev-layout.db-default .table-caption,
@@ -322,7 +352,7 @@
322
352
  .slidev-layout.db-default table {
323
353
  border-collapse: collapse;
324
354
  width: auto; /* default: hug content */
325
- font-size: 10px; /* 10pt (canvas 720 => px == pt) */
355
+ font-size: var(--db-fs-table); /* 10pt */
326
356
  }
327
357
  /* Width control: tables hug content by default. To pin a width, wrap in
328
358
  <div class="table-w" style="width: …"> — the table then fills that box, so
@@ -361,6 +391,7 @@
361
391
  border: none; /* no vertical/cell borders */
362
392
  padding: 2px 8px 4px; /* tight padding; bottom>top optically centers
363
393
  single-line text (nudges it up) */
394
+ line-height: 1.4; /* rows every 19.2pt (25.6px), as in the template */
364
395
  vertical-align: middle; /* center cell text vertically */
365
396
  text-align: center; /* center by default; :--/--: in markdown override */
366
397
  }
@@ -384,6 +415,12 @@
384
415
  .slidev-layout.db-default tbody tr:last-child td {
385
416
  border-bottom: 1px solid var(--db-table-rule);
386
417
  }
418
+ /* Footer page number (global-bottom.vue): 12pt like the template. */
419
+ .db-footer__page {
420
+ font-size: var(--db-fs-small);
421
+ color: var(--db-text);
422
+ }
423
+
387
424
  /* Inline code inside tables AND headings: keep the syntax colors but drop the
388
425
  gray "pill" background/padding so it reads like plain text. */
389
426
  .slidev-layout.db-default th code,
@@ -394,3 +431,20 @@
394
431
  background: transparent;
395
432
  padding: 0;
396
433
  }
434
+ /* In a heading, code takes the heading's size and weight (the template's
435
+ "1.1 DISTINCT" is bold mono), not the light, smaller inline-code style. */
436
+ .slidev-layout.db-default :is(h1, h2, h3) code {
437
+ font-size: 1em;
438
+ font-weight: inherit;
439
+ }
440
+
441
+ /* Inline math: KaTeX's default 1.21em makes capitals 15% taller than Noto
442
+ Sans ones, and its 1.2 line height stretches the bullet it sits in. At 1.05em
443
+ the capitals match; line-height 1 keeps a formula's bullet within 0.5px of its
444
+ neighbours. (Not 0: that misplaces overlays such as the slash of \notin.) */
445
+ .slidev-layout.db-default .katex {
446
+ font-size: 1.05em;
447
+ }
448
+ .slidev-layout.db-default :not(.katex-display) > .katex {
449
+ line-height: 1;
450
+ }