slidev-theme-tud 0.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.
Files changed (56) hide show
  1. package/.envrc +1 -0
  2. package/.github/workflows/deploy.yml +84 -0
  3. package/.github/workflows/release.yml +89 -0
  4. package/.vscode/extensions.json +3 -0
  5. package/README.md +60 -0
  6. package/assets/TUD-logo-bl.svg +1 -0
  7. package/assets/TUD-logo-no-color.svg +1 -0
  8. package/assets/TUD-logo-text-no-color.svg +1 -0
  9. package/assets/TUD-logo-text-small-no-color.svg +1 -0
  10. package/assets/TUD-logo-tr.svg +1 -0
  11. package/assets/favicons/apple-touch-icon.png +0 -0
  12. package/assets/favicons/dark/apple-touch-icon.png +0 -0
  13. package/assets/favicons/dark/favicon-16x16.png +0 -0
  14. package/assets/favicons/dark/favicon-32x32.png +0 -0
  15. package/assets/favicons/dark/favicon.ico +0 -0
  16. package/assets/favicons/favicon-16x16.png +0 -0
  17. package/assets/favicons/favicon-32x32.png +0 -0
  18. package/assets/favicons/favicon.ico +0 -0
  19. package/assets/fonts/FiraCode-VariableFont_wght.ttf +0 -0
  20. package/assets/fonts/NotoSans-Italic-VariableFont_wdth,wght.ttf +0 -0
  21. package/assets/fonts/NotoSans-VariableFont_wdth,wght.ttf +0 -0
  22. package/assets/fonts/OFL.txt +93 -0
  23. package/components/.gitkeep +0 -0
  24. package/components/Background.vue +130 -0
  25. package/components/Footnotes.vue +164 -0
  26. package/example.mdc +372 -0
  27. package/flake.lock +61 -0
  28. package/flake.nix +22 -0
  29. package/global-bottom.vue +79 -0
  30. package/global-top.vue +72 -0
  31. package/layouts/README.md +2 -0
  32. package/layouts/cols.vue +38 -0
  33. package/layouts/cover-blue.vue +60 -0
  34. package/layouts/cover-white.vue +58 -0
  35. package/layouts/cover.vue +10 -0
  36. package/layouts/default.vue +15 -0
  37. package/layouts/section-blue.vue +32 -0
  38. package/layouts/section-n.vue +171 -0
  39. package/layouts/section-white.vue +25 -0
  40. package/layouts/section.vue +10 -0
  41. package/markdown.ts +196 -0
  42. package/package.json +70 -0
  43. package/pnpm-workspace.yaml +23 -0
  44. package/scripts/background.ts +69 -0
  45. package/scripts/color.ts +81 -0
  46. package/scripts/util.ts +51 -0
  47. package/setup/katex.ts +35 -0
  48. package/setup/shiki.ts +48 -0
  49. package/shims.d.ts +27 -0
  50. package/styles/fade-transition.css +36 -0
  51. package/styles/font.css +28 -0
  52. package/styles/index.ts +5 -0
  53. package/styles/layout.css +184 -0
  54. package/tsconfig.json +30 -0
  55. package/uno.config.ts +35 -0
  56. package/vite.config.ts +29 -0
package/global-top.vue ADDED
@@ -0,0 +1,72 @@
1
+ <script setup lang="ts">
2
+ import { defineComponent, getCurrentInstance } from 'vue'
3
+ import { useHead } from '@unhead/vue'
4
+
5
+ // Favicons are imported as Vite assets (not from public/) so the bundler
6
+ // resolves each to a hashed, base-aware URL. This works regardless of where
7
+ // the theme is installed, unlike hardcoded "/theme/..." paths in index.html.
8
+ import faviconIco from './assets/favicons/favicon.ico?url'
9
+ import favicon32 from './assets/favicons/favicon-32x32.png?url'
10
+ import favicon16 from './assets/favicons/favicon-16x16.png?url'
11
+ import appleTouchIcon from './assets/favicons/apple-touch-icon.png?url'
12
+ import faviconIcoDark from './assets/favicons/dark/favicon.ico?url'
13
+ import favicon32Dark from './assets/favicons/dark/favicon-32x32.png?url'
14
+ import favicon16Dark from './assets/favicons/dark/favicon-16x16.png?url'
15
+ import appleTouchIconDark from './assets/favicons/dark/apple-touch-icon.png?url'
16
+
17
+ useHead({
18
+ link: [
19
+ // Light color scheme
20
+ { rel: 'apple-touch-icon', sizes: '180x180', href: appleTouchIcon, media: '(prefers-color-scheme: light)' },
21
+ { rel: 'icon', type: 'image/png', sizes: '32x32', href: favicon32, media: '(prefers-color-scheme: light)' },
22
+ { rel: 'icon', type: 'image/png', sizes: '16x16', href: favicon16, media: '(prefers-color-scheme: light)' },
23
+ { rel: 'icon', href: faviconIco, sizes: 'any', media: '(prefers-color-scheme: light)' },
24
+ // Dark color scheme
25
+ { rel: 'apple-touch-icon', sizes: '180x180', href: appleTouchIconDark, media: '(prefers-color-scheme: dark)' },
26
+ { rel: 'icon', type: 'image/png', sizes: '32x32', href: favicon32Dark, media: '(prefers-color-scheme: dark)' },
27
+ { rel: 'icon', type: 'image/png', sizes: '16x16', href: favicon16Dark, media: '(prefers-color-scheme: dark)' },
28
+ { rel: 'icon', href: faviconIcoDark, sizes: 'any', media: '(prefers-color-scheme: dark)' },
29
+ ],
30
+ })
31
+
32
+
33
+ // `slidev-component-progress` is optional. When it is installed and
34
+ // enabled (via `addons:`), Slidev auto-imports its <Progress>
35
+ //
36
+ // registering a global no-op fallback
37
+ const app = getCurrentInstance()?.appContext.app
38
+ if (app && !app.component('Progress')) {
39
+ app.component(
40
+ 'Progress',
41
+ defineComponent({ name: 'Progress', inheritAttrs: false, render: () => null }),
42
+ )
43
+ app.component(
44
+ 'MarkersShapes',
45
+ defineComponent({ name: 'MarkersShapes', inheritAttrs: false, render: () => null }),
46
+ )
47
+ }
48
+ // Note: setting opacity to 1 directly in the template causes problems from
49
+ // the unocss attributify generated class
50
+ const progressProps = {
51
+ level: '3',
52
+ height: 15,
53
+ thickness: '15px',
54
+ clicks: true,
55
+ opacity: 1,
56
+ print: true,
57
+ marginY: '-1px',
58
+ fillLast: true,
59
+ emptyFirst: true,
60
+ scale: 'clicks',
61
+ disable: (layout: string) =>
62
+ new Set(['cover', 'cover-blue', 'cover-white', 'section', 'section-blue', 'section-white', 'section-n']).has(layout),
63
+ }
64
+ </script>
65
+
66
+ <template>
67
+ <div class="absolute top-0 left-0 w-full z-10">
68
+ <Progress v-bind="progressProps">
69
+ <template #marker="args"><MarkersShapes v-bind="args" shape="square" visible="hover" activeStyle="filled"/></template>
70
+ </Progress>
71
+ </div>
72
+ </template>
@@ -0,0 +1,2 @@
1
+ Note that `cover.vue` and `section.vue` are only symbolic links
2
+ to the `cover-blue.vue` and `section-blue.vue` layouts, respectively.
@@ -0,0 +1,38 @@
1
+ <template>
2
+ <div class="slidev-layout layout-cols w-full h-full">
3
+ <div class="content px-[64px] py-[60px]">
4
+ <slot></slot>
5
+ <div class="flex justify-between mb-8">
6
+ <div v-for="col in orderedCols" :key="col.num" class="col">
7
+ <component :is="col.fn" />
8
+ <!-- <slot :name="`col-${col.num}`"></slot> -->
9
+ </div>
10
+ </div>
11
+ <slot name="bottom"></slot>
12
+ </div>
13
+ </div>
14
+ </template>
15
+
16
+ <script setup>
17
+ import { computed, useSlots } from "vue";
18
+ import { useLogo } from "../scripts/background";
19
+
20
+ useLogo({ small: 'primary' });
21
+
22
+ const slots = useSlots();
23
+
24
+ const orderedCols = computed(() => {
25
+ return Object.entries(slots)
26
+ .filter(([name]) => name.startsWith("col-"))
27
+ .map(([name, fn]) => {
28
+ const num = parseInt(name.split("-")[1], 10);
29
+ return { num, fn };
30
+ })
31
+ .sort((a, b) => a.num - b.num);
32
+ });
33
+ </script>
34
+ <style lang="stylus">
35
+ .slidev-layout.layout-cols col {
36
+ h1 {}
37
+ }
38
+ </style>
@@ -0,0 +1,60 @@
1
+ <template>
2
+ <div class="h-full">
3
+ <div class="slidev-layout cover text-white">
4
+ <div class="content p-[64px]">
5
+ <!-- <slot></slot> -->
6
+ <div class="title absolute bottom-[340px] w-full">
7
+ <div class="date absolute top-0 -translate-y-full text-md">{{ get_date }}</div>
8
+ <h1 v-if="!slotTags.includes('h1')"> {{ $slidev.configs.title }} </h1>
9
+ <component v-else v-for="node in get_slot('h1')" :is="node" :key="node.key"/>
10
+
11
+ <div class="absolute bottom-0 translate-y-full">
12
+ <h2 v-if="!slotTags.includes('h2')"> {{ $slidev.configs.subtitle }} </h2>
13
+ <component v-else v-for="node in get_slot('h2')" :is="node" :key="node.key"/>
14
+ </div>
15
+ </div>
16
+
17
+ <div class="name absolute bottom-[120px]">
18
+ <div v-if="!slotTags.includes('p')">
19
+ <p class="!text-2xl !m-0 font-bold">{{ $slidev.configs.author }}</p>
20
+ <p class="!m-0 !text-sm">{{ $slidev.configs.group }}</p>
21
+ </div>
22
+ <component v-else v-for="node in get_slot('p')" class="!m-0 !text-sm" :is="node" :key="node.key"/>
23
+ </div>
24
+ </div>
25
+ </div>
26
+ </div>
27
+ </template>
28
+ <script setup lang="ts">
29
+ import { useSlideContext } from '@slidev/client'
30
+ import { expandDateTokens } from '../scripts/util';
31
+ import { useBackground, useLogo } from '../scripts/background'
32
+ import { computed, useSlots } from 'vue'
33
+
34
+ useBackground('primary')
35
+ useLogo({ text: 'white' })
36
+
37
+ const slotTags = computed(() => (useSlots().default?.() || []).map(e => e.type));
38
+ const { $slidev } = useSlideContext()
39
+
40
+ function get_slot(tag) {
41
+ return (useSlots().default?.() || []).filter(n => n.type === tag)
42
+ }
43
+
44
+ const get_date = computed(() => {
45
+ const d = $slidev.configs.date
46
+ return d ? expandDateTokens(String(d)) : d
47
+ })
48
+ </script>
49
+
50
+ <style scoped lang="stylus">
51
+ .content {
52
+ .title :deep(h1) {
53
+ @apply my-1;
54
+ color: white;
55
+ }
56
+ .title :deep(h2), .name :deep(p) {
57
+ color: white;
58
+ }
59
+ }
60
+ </style>
@@ -0,0 +1,58 @@
1
+ <template>
2
+ <div class="h-full">
3
+ <div class="slidev-layout cover-white">
4
+ <div class="content p-[64px]">
5
+
6
+ <div class="title absolute bottom-[340px] w-full">
7
+ <div class="date absolute top-0 -translate-y-full text-gray text-md">{{ get_date }}</div>
8
+ <h1 v-if="!slotTags.includes('h1')"> {{ $slidev.configs.title }} </h1>
9
+ <component v-else v-for="node in get_slot('h1')" :is="node" :key="node.key"/>
10
+
11
+ <div class="absolute bottom-0 translate-y-full">
12
+ <h2 v-if="!slotTags.includes('h2')" class="text-gray"> {{ $slidev.configs.subtitle }} </h2>
13
+ <component v-else v-for="node in get_slot('h2')" class="text-gray" :is="node" :key="node.key"/>
14
+ </div>
15
+ </div>
16
+
17
+ <div class="name absolute bottom-[120px] text-gray">
18
+ <div v-if="!slotTags.includes('p')">
19
+ <p class="!text-2xl !m-0 font-bold">{{ $slidev.configs.author }}</p>
20
+ <p class="!m-0 !text-sm">{{ $slidev.configs.group }}</p>
21
+ </div>
22
+ <component v-else v-for="node in get_slot('p')" class="!m-0 !text-sm" :is="node" :key="node.key"/>
23
+ </div>
24
+ </div>
25
+ </div>
26
+ </div>
27
+ </template>
28
+ <script setup lang="ts">
29
+ import { useSlideContext } from '@slidev/client'
30
+ import { expandDateTokens } from '../scripts/util';
31
+ import { useLogo } from '../scripts/background'
32
+ import { computed, useSlots } from 'vue'
33
+
34
+ useLogo({ text: 'primary' })
35
+
36
+ const slotTags = computed(() => (useSlots().default?.() || []).map(e => e.type));
37
+ const { $slidev } = useSlideContext()
38
+
39
+ function get_slot(tag) {
40
+ return (useSlots().default?.() || []).filter(n => n.type === tag)
41
+ }
42
+
43
+ const get_date = computed(() => {
44
+ const d = $slidev.configs.date
45
+ return d ? expandDateTokens(String(d)) : d
46
+ })
47
+ </script>
48
+
49
+ <style scoped>
50
+ .content {
51
+ .title :deep(h1) {
52
+ @apply m-0;
53
+ }
54
+ .title :deep(h2) {
55
+ @apply text-gray;
56
+ }
57
+ }
58
+ </style>
@@ -0,0 +1,10 @@
1
+ <!-- Alias: for the `cover-blue` layout. -->
2
+ <template>
3
+ <CoverBlue>
4
+ <slot />
5
+ </CoverBlue>
6
+ </template>
7
+
8
+ <script setup lang="ts">
9
+ import CoverBlue from './cover-blue.vue'
10
+ </script>
@@ -0,0 +1,15 @@
1
+ <template>
2
+ <div class="h-full">
3
+ <div class="slidev-layout default">
4
+ <div class="content px-[64px] py-[60px] w-full h-full">
5
+ <slot></slot>
6
+ </div>
7
+ </div>
8
+ </div>
9
+ </template>
10
+
11
+ <script setup lang="ts">
12
+ import { useLogo } from '../scripts/background'
13
+
14
+ useLogo({ small: 'primary' })
15
+ </script>
@@ -0,0 +1,32 @@
1
+ <template>
2
+ <div class="h-full">
3
+ <div class="slidev-layout section-blue text-white">
4
+ <div class="content p-[64px] pb-8 flex flex-col justify-center h-full">
5
+ <slot></slot>
6
+ </div>
7
+ </div>
8
+ </div>
9
+ </template>
10
+
11
+ <script setup lang="ts">
12
+ import { useBackground, useLogo } from '../scripts/background'
13
+ useBackground('primary')
14
+ useLogo({ small: 'white' })
15
+ // TODO generalize over bg color via parameter
16
+ </script>
17
+
18
+ <style>
19
+ .slidev-layout.section-blue {
20
+ h1 {
21
+ @apply mb-4;
22
+ }
23
+
24
+ h1, h2 {
25
+ color: white;
26
+ }
27
+
28
+ code {
29
+ @apply bg-white/10;
30
+ }
31
+ }
32
+ </style>
@@ -0,0 +1,171 @@
1
+ <template>
2
+ <div class="h-full">
3
+ <div class="slidev-layout section-n" :class="`section-${variant}`" :style="{ '--section-text': textCss }">
4
+ <div class="content content-main flex items-center absolute inset-0">
5
+ <div class="main w-full">
6
+ <slot></slot>
7
+ </div>
8
+ </div>
9
+ <div class="content content-detail flex items-center absolute inset-0">
10
+ <div class="detail w-full">
11
+ <slot name="detail"></slot>
12
+ </div>
13
+ </div>
14
+ </div>
15
+
16
+ </div>
17
+ </template>
18
+
19
+ <script setup lang="ts">
20
+ import { computed } from 'vue'
21
+ import { useBackground, useBackgroundLogo, useLogo, type BackgroundLogo, type MarkTransform } from '../scripts/background'
22
+ import { asIndex, resolveColorName, toCssColor } from '../scripts/color'
23
+
24
+ const { variant = 1, colors = {} } = defineProps<{
25
+ variant?: number | string
26
+ colors?: {
27
+ bg?: number | string
28
+ logo?: number | string
29
+ text?: number | string
30
+ }
31
+ }>()
32
+ const { bg, logo, text } = colors
33
+
34
+ const defaultIndex = asIndex(bg) ?? asIndex(logo) ?? Number(variant)
35
+
36
+ const bgColor = computed(() => resolveColorName(bg, 'bg', defaultIndex))
37
+ const logoFill = computed(() => resolveColorName(logo, 'logo', defaultIndex))
38
+ const textColor = computed(() => resolveColorName(text, 'text', defaultIndex))
39
+ // The template consumes --section-text as a CSS colour, so convert here.
40
+ const textCss = computed(() => toCssColor(textColor.value))
41
+
42
+ useBackground(bgColor)
43
+
44
+ // SVG is 100x100; slide is 1280x720, and the transform origin is (50,50).
45
+ // Values feed MarkTransform (see scripts/background.ts): { scale, x, y, rotate? }.
46
+ const HIDDEN: MarkTransform = { scale: 5, x: 640, y: 360 }
47
+ const sectionTransforms = computed<Pick<BackgroundLogo, 'bl' | 'tr'>>(() => {
48
+ switch (String(variant)) {
49
+ case '1':
50
+ return {
51
+ // bl: SVG (69,100) -> slide (530,493)
52
+ bl: { scale: 28.32, x: -8.08, y: -923 },
53
+ // tr: SVG (31,0) -> slide (530,493)
54
+ tr: { scale: 28.32, x: 1068.08, y: 1909 },
55
+ }
56
+ case '2':
57
+ // bl/tr: SVG (31,0) -> slide (1280,0), logo centre on vertical middle (y=360)
58
+ return {
59
+ bl: { rotate: 90, scale: 18.9474, x: 332.63, y: 360 },
60
+ tr: { rotate: 90, scale: 18.9474, x: 332.63, y: 360 },
61
+ }
62
+ case '3':
63
+ return {
64
+ // bl: SVG (0,40.584) -> slide (640,430)
65
+ bl: { scale: 20.63, x: 1671.5, y: 624.252 },
66
+ // tr: SVG (100,59.416) -> slide (640,430)
67
+ tr: { scale: 20.63, x: -391.5, y: 235.748 },
68
+ }
69
+ case '4':
70
+ return {
71
+ // bl: SVG (0,70.71) -> slide (800,360)
72
+ bl: { scale: 23.6, x: 1980, y: -128.756 },
73
+ // tr: SVG (100,29.29) -> slide (800,360)
74
+ tr: { scale: 23.6, x: -380, y: 848.756 },
75
+ }
76
+ case '5':
77
+ return {
78
+ // bl: SVG (0,70.71) -> slide (800,360)
79
+ bl: { scale: 10, x: 640 - 300, y: 360 + 50 },
80
+ // tr: SVG (100,29.29) -> slide (800,360)
81
+ tr: { scale: 10, x: 640 + 300, y: 360 - 50 },
82
+ }
83
+ case '6':
84
+ return {
85
+ // bl: SVG (17.25,37.542) -> slide (640,360), -0.5px along logo +y
86
+ bl: { rotate: -60, scale: 15, x: 1047.026, y: 27.75 },
87
+ // tr: SVG (82.75,62.458) -> slide (640,360), +0.5px along logo +y
88
+ tr: { rotate: -60, scale: 15, x: 232.974, y: 692.25 },
89
+ }
90
+ default:
91
+ return { bl: HIDDEN, tr: HIDDEN }
92
+ }
93
+ })
94
+
95
+ const sectionLogo = computed<BackgroundLogo>(() => ({
96
+ ...sectionTransforms.value,
97
+ fill: logoFill.value,
98
+ }))
99
+ useBackgroundLogo(sectionLogo)
100
+ useLogo(computed(() => {
101
+ switch (String(variant)) {
102
+ case '1':
103
+ case '5':
104
+ case '6':
105
+ return { small: textColor.value }
106
+ case '3':
107
+ return { small: logoFill.value }
108
+ case '4':
109
+ return { small: bgColor.value }
110
+ case '2':
111
+ default:
112
+ return { }
113
+ }
114
+ }))
115
+ </script>
116
+ <style>
117
+ .slidev-layout.section-n {
118
+ code {
119
+ background: none;
120
+ @apply border-2 border-[color-mix(in_srgb,var(--section-text,white)_20%,transparent)];
121
+ }
122
+ color: var(--section-text, white);
123
+ h1, h2, h3, h4, h5, h6, p {
124
+ color: var(--section-text, white);
125
+ }
126
+ h1 {
127
+ @apply mb-18;
128
+ }
129
+ }
130
+
131
+ .slidev-layout.section-1 {
132
+ .content-main {
133
+ @apply pl-[530px] pb-[227px];
134
+ }
135
+ .content-detail {
136
+ @apply pr-[750px] pt-[493px];
137
+ }
138
+ .main { @apply my-[64px] mr-[64px] }
139
+ .detail { @apply pl-[64px] py-[64px] }
140
+
141
+ }
142
+ .slidev-layout.section-2 {
143
+ .content-main {
144
+ @apply pl-[64px] py-[66px];
145
+ }
146
+ }
147
+ .slidev-layout.section-3 {
148
+ .content-main {
149
+ @apply pb-[175px] pr-[640px]; /*pb-[290px]*/
150
+ }
151
+ .content-detail {
152
+ @apply pl-[640px] pt-[320px];
153
+ }
154
+ .main { @apply p-[64px] }
155
+ .detail { @apply p-[64px] }
156
+ h1 {
157
+ @apply mb-18;
158
+ }
159
+ }
160
+ .slidev-layout.section-4 {
161
+ .main { @apply p-[64px] }
162
+ }
163
+
164
+ .slidev-layout.section-5 {
165
+ .main { @apply text-center }
166
+ }
167
+
168
+ .slidev-layout.section-6 {
169
+ .main { @apply text-center }
170
+ }
171
+ </style>
@@ -0,0 +1,25 @@
1
+ <template>
2
+ <div class="h-full">
3
+ <div class="slidev-layout section-white">
4
+ <div class="content p-[64px] pb-8 flex flex-col justify-center h-full">
5
+ <slot></slot>
6
+ </div>
7
+ </div>
8
+ </div>
9
+ </template>
10
+ <script setup lang="ts">
11
+ import { useLogo } from '../scripts/background'
12
+
13
+ useLogo({ small: 'primary' })
14
+ </script>
15
+ <style>
16
+ .slidev-layout.section-white {
17
+ h1 {
18
+ @apply mb-4;
19
+ }
20
+ h2 {
21
+ @apply text-gray;
22
+ }
23
+ /* @apply m-0 absolute bottom-[340px]; */
24
+ }
25
+ </style>
@@ -0,0 +1,10 @@
1
+ <!-- Alias: for the `section-blue` layout. -->
2
+ <template>
3
+ <SectionBlue>
4
+ <slot />
5
+ </SectionBlue>
6
+ </template>
7
+
8
+ <script setup lang="ts">
9
+ import SectionBlue from './section-blue.vue'
10
+ </script>