slidev-theme-tud-db 0.0.6 → 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.6",
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
  }
@@ -59,27 +74,36 @@
59
74
  color: var(--db-accent3);
60
75
  }
61
76
 
62
- /* Content slides ("Titel und Inhalt").
63
- * 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.) */
64
82
  .slidev-layout.db-default {
65
- @apply text-md p-0;
83
+ font-size: var(--db-fs-body);
84
+ padding: 0;
66
85
  }
67
86
  .slidev-layout.db-default h1 {
68
87
  color: var(--db-text-soft); /* black/gray page heading */
69
- @apply text-3xl mb-[46px]; /* gap to first sub-header (~46pt 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) */
70
91
  }
71
92
  .slidev-layout.db-default h2,
72
93
  .slidev-layout.db-default h3 {
73
94
  color: var(--db-heading-blue); /* blue sub-headers */
74
- @apply text-xl mt-[45px]; /* space ABOVE a sub-header, whatever precedes it
75
- (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 */
76
100
  }
77
101
  /* …except a sub-header that is the FIRST content of its area (right under the
78
102
  page title, or the top of a column / grid cell) — the title's margin-bottom
79
103
  or the grid gap already provides that separation.
80
104
  This is wrap-proof: a section wrapped in a <div> (e.g. a GSAP animation
81
105
  anchor) is still treated as "top" when its wrapper is the first child, but a
82
- 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
83
107
  wrapper div later does NOT collapse the spacing. (default layout: h1 is a
84
108
  sibling of the content; two-cols-header: .db-grid__col; two-cols-grid:
85
109
  .db-rowgrid cells.) */
@@ -105,7 +129,7 @@
105
129
  .slidev-layout.db-default ul ul,
106
130
  .slidev-layout.db-default ol ol {
107
131
  margin-left: 0; /* 2nd-level marker aligns with 1st-level text (no extra indent) */
108
- 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) */
109
133
  }
110
134
  .slidev-layout.db-default ul ul { list-style-type: square; }
111
135
  /* Tight vertical rhythm (theme defaults to ~1.8 line-height) */
@@ -192,24 +216,39 @@
192
216
  .slidev-layout.db-default .with-bg pre.slidev-code {
193
217
  background: rgba(0, 0, 0, 0.03) !important;
194
218
  }
195
- /* Code sizing (Slidev defaults: 12px / 18px / 8px). Slightly smaller font and
196
- 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. */
197
224
  .slidev-layout.db-default {
198
- --slidev-code-font-size: 11px;
225
+ --slidev-code-font-size: var(--db-fs-code);
199
226
  --slidev-code-line-height: 1.3;
227
+ --slidev-code-padding: 4px 10px 4px 0;
228
+ }
229
+ .slidev-layout.db-default .with-bg {
200
230
  --slidev-code-padding: 4px 10px;
201
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
+ }
202
240
 
203
241
  /* Line numbers (```lang {lines:true}```): tighten the gutter. Slidev's defaults
204
242
  are a wide 24px gap between the number and the code, plus the block's 10px
205
243
  left padding before the number. Both are scoped to line-numbered blocks so
206
244
  plain code blocks keep their normal padding. */
207
245
  .slidev-layout.db-default .slidev-code-line-numbers .slidev-code,
208
- .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) {
209
247
  /* override the padding *variable* (Slidev applies padding via it, which beats
210
248
  a plain padding-left here). top right bottom left — only the left shrinks.
211
249
  The Magic Move container isn't wrapped in .slidev-code-line-numbers, so it
212
- 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. */
213
252
  --slidev-code-padding: 4px 10px 4px 6px; /* less space left of the numbers (was 10px) */
214
253
  }
215
254
  .slidev-layout.db-default .slidev-code-line-numbers .slidev-code code .line::before {
@@ -251,13 +290,16 @@
251
290
  /* Optional caption above a code block.
252
291
  Authoring: ```python [What this snippet does] */
253
292
  .slidev-layout.db-default .slidev-code-block-title {
254
- padding: 3px 10px;
293
+ padding: 3px 0; /* flush with the code text below (see above) */
255
294
  background: transparent; /* drop Slidev's heavy gray title bar */
256
- font-size: 11px;
295
+ font-size: var(--db-fs-caption);
257
296
  font-style: italic;
258
297
  color: var(--db-text);
259
298
  opacity: 0.85;
260
299
  }
300
+ .slidev-layout.db-default .with-bg .slidev-code-block-title {
301
+ padding-inline: 10px; /* match the boxed code's inset */
302
+ }
261
303
 
262
304
  /* Optional table captions (need Comark, enabled by this theme).
263
305
  ABOVE the table: [Title]{.table-caption} -> black, non-italic
@@ -270,7 +312,7 @@
270
312
  .slidev-layout.db-default p:has(.table-caption),
271
313
  .slidev-layout.db-default .table-footer,
272
314
  .slidev-layout.db-default p:has(.table-footer) {
273
- font-size: 11px;
315
+ font-size: var(--db-fs-caption);
274
316
  background: transparent !important;
275
317
  }
276
318
  .slidev-layout.db-default .table-caption,
@@ -310,7 +352,7 @@
310
352
  .slidev-layout.db-default table {
311
353
  border-collapse: collapse;
312
354
  width: auto; /* default: hug content */
313
- font-size: 10px; /* 10pt (canvas 720 => px == pt) */
355
+ font-size: var(--db-fs-table); /* 10pt */
314
356
  }
315
357
  /* Width control: tables hug content by default. To pin a width, wrap in
316
358
  <div class="table-w" style="width: …"> — the table then fills that box, so
@@ -349,6 +391,7 @@
349
391
  border: none; /* no vertical/cell borders */
350
392
  padding: 2px 8px 4px; /* tight padding; bottom>top optically centers
351
393
  single-line text (nudges it up) */
394
+ line-height: 1.4; /* rows every 19.2pt (25.6px), as in the template */
352
395
  vertical-align: middle; /* center cell text vertically */
353
396
  text-align: center; /* center by default; :--/--: in markdown override */
354
397
  }
@@ -372,6 +415,12 @@
372
415
  .slidev-layout.db-default tbody tr:last-child td {
373
416
  border-bottom: 1px solid var(--db-table-rule);
374
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
+
375
424
  /* Inline code inside tables AND headings: keep the syntax colors but drop the
376
425
  gray "pill" background/padding so it reads like plain text. */
377
426
  .slidev-layout.db-default th code,
@@ -382,3 +431,20 @@
382
431
  background: transparent;
383
432
  padding: 0;
384
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
+ }