@troshab/slidev-theme-troshab 0.1.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 (168) hide show
  1. package/CLAUDE.md +537 -0
  2. package/LICENSE +134 -0
  3. package/README.md +168 -0
  4. package/SKILL.md +414 -0
  5. package/components/AnimatedCounter.vue +35 -0
  6. package/components/Background.vue +204 -0
  7. package/components/Callout.vue +135 -0
  8. package/components/Card.vue +75 -0
  9. package/components/CardGrid.vue +67 -0
  10. package/components/CaseStudy.vue +66 -0
  11. package/components/CodeDiff.vue +229 -0
  12. package/components/CodeHighlight.vue +337 -0
  13. package/components/ColorSwatch.vue +114 -0
  14. package/components/Confetti.vue +292 -0
  15. package/components/Conversation.vue +405 -0
  16. package/components/Countdown.vue +476 -0
  17. package/components/Definition.vue +59 -0
  18. package/components/DeviceMockup.vue +392 -0
  19. package/components/Funnel.vue +87 -0
  20. package/components/Icon.vue +73 -0
  21. package/components/Iframe.vue +38 -0
  22. package/components/Image.vue +69 -0
  23. package/components/ImageCompare.vue +436 -0
  24. package/components/MatrixGrid.vue +85 -0
  25. package/components/MermaidChart.vue +299 -0
  26. package/components/Metric.vue +161 -0
  27. package/components/PersonCard.vue +165 -0
  28. package/components/PricingTable.vue +144 -0
  29. package/components/Progress.vue +100 -0
  30. package/components/Pyramid.vue +81 -0
  31. package/components/QRCode.vue +137 -0
  32. package/components/QuoteBlock.vue +101 -0
  33. package/components/SpeechBubble.vue +169 -0
  34. package/components/Stepper.vue +542 -0
  35. package/components/StyledList.vue +156 -0
  36. package/components/StyledText.vue +275 -0
  37. package/components/SwotGrid.vue +99 -0
  38. package/components/Tags.vue +20 -0
  39. package/components/Testimonial.vue +243 -0
  40. package/components/Typewriter.vue +181 -0
  41. package/components_base/AnimatedCounter.vue +208 -0
  42. package/components_base/CodeHighlight.vue +364 -0
  43. package/composables/useColors.ts +101 -0
  44. package/composables/useShiki.ts +81 -0
  45. package/example_content.md +371 -0
  46. package/example_dark.md +10 -0
  47. package/example_slides/001-cover.md +15 -0
  48. package/example_slides/002-agenda.md +25 -0
  49. package/example_slides/003-section-layouts.md +14 -0
  50. package/example_slides/004-fullscreen-centered.md +7 -0
  51. package/example_slides/005-fullscreen-align-bottom.md +14 -0
  52. package/example_slides/006-fullscreen-no-padding.md +14 -0
  53. package/example_slides/007-fullscreen-bg-image-dark.md +13 -0
  54. package/example_slides/008-fullscreen-bg-image-light.md +13 -0
  55. package/example_slides/009-fullscreen-bg-gradient.md +15 -0
  56. package/example_slides/010-fullscreen-bg-color.md +13 -0
  57. package/example_slides/011-split-basic.md +17 -0
  58. package/example_slides/012-split-image-text.md +18 -0
  59. package/example_slides/013-split-contrast.md +22 -0
  60. package/example_slides/014-columns-basic.md +13 -0
  61. package/example_slides/015-columns-two.md +26 -0
  62. package/example_slides/016-columns-ratios.md +22 -0
  63. package/example_slides/017-columns-three.md +31 -0
  64. package/example_slides/018-columns-four.md +22 -0
  65. package/example_slides/019-columns-alignment.md +23 -0
  66. package/example_slides/020-columns-styled.md +21 -0
  67. package/example_slides/021-footnote-prop.md +16 -0
  68. package/example_slides/022-iframe-fullscreen.md +8 -0
  69. package/example_slides/023-iframe-split.md +18 -0
  70. package/example_slides/024-section-components.md +14 -0
  71. package/example_slides/025-styled-text.md +9 -0
  72. package/example_slides/026-styled-text.md +15 -0
  73. package/example_slides/027-text-formatting.md +28 -0
  74. package/example_slides/028-text-spoiler.md +15 -0
  75. package/example_slides/029-icon-component.md +47 -0
  76. package/example_slides/030-metric-component.md +29 -0
  77. package/example_slides/031-person-card.md +33 -0
  78. package/example_slides/032-styled-list.md +50 -0
  79. package/example_slides/033-color-swatch.md +35 -0
  80. package/example_slides/034-code-highlight.md +9 -0
  81. package/example_slides/035-iframe-component.md +9 -0
  82. package/example_slides/036-callout.md +15 -0
  83. package/example_slides/037-card-grid.md +27 -0
  84. package/example_slides/038-stepper-variants.md +18 -0
  85. package/example_slides/039-stepper-clicks.md +49 -0
  86. package/example_slides/040-stepper-interactive.md +28 -0
  87. package/example_slides/041-tags-progress.md +21 -0
  88. package/example_slides/042-speech-bubble.md +30 -0
  89. package/example_slides/043-conversation.md +13 -0
  90. package/example_slides/044-device-iphone.md +26 -0
  91. package/example_slides/045-device-browser.md +7 -0
  92. package/example_slides/046-qrcode.md +26 -0
  93. package/example_slides/047-countdown.md +14 -0
  94. package/example_slides/048-typewriter.md +8 -0
  95. package/example_slides/049-confetti.md +16 -0
  96. package/example_slides/050-image-compare.md +13 -0
  97. package/example_slides/051-code-diff.md +24 -0
  98. package/example_slides/052-quote-block.md +8 -0
  99. package/example_slides/053-testimonial.md +26 -0
  100. package/example_slides/054-testimonial-featured.md +16 -0
  101. package/example_slides/055-funnel.md +12 -0
  102. package/example_slides/056-pyramid.md +13 -0
  103. package/example_slides/057-pricing-table.md +9 -0
  104. package/example_slides/058-swot-grid.md +12 -0
  105. package/example_slides/059-matrix-grid.md +12 -0
  106. package/example_slides/060-case-study.md +11 -0
  107. package/example_slides/061-definition.md +15 -0
  108. package/example_slides/062-mermaid-intro.md +34 -0
  109. package/example_slides/063-mermaid-flowchart.md +19 -0
  110. package/example_slides/064-mermaid-sequence.md +17 -0
  111. package/example_slides/065-mermaid-xy-chart.md +16 -0
  112. package/example_slides/066-mermaid-pie.md +17 -0
  113. package/example_slides/067-mermaid-class.md +19 -0
  114. package/example_slides/068-mermaid-state.md +19 -0
  115. package/example_slides/069-mermaid-er.md +22 -0
  116. package/example_slides/070-mermaid-gantt.md +24 -0
  117. package/example_slides/071-mermaid-timeline.md +17 -0
  118. package/example_slides/072-mermaid-mindmap.md +21 -0
  119. package/example_slides/073-mermaid-gitgraph.md +20 -0
  120. package/example_slides/074-mermaid-split.md +30 -0
  121. package/example_slides/075-mermaid-columns.md +32 -0
  122. package/example_slides/076-section-addons.md +14 -0
  123. package/example_slides/077-asciinema.md +27 -0
  124. package/example_slides/078-fancyarrow.md +31 -0
  125. package/example_slides/079-fancyarrow-demo.md +23 -0
  126. package/example_slides/080-section-theme.md +14 -0
  127. package/example_slides/081-color-architecture.md +22 -0
  128. package/example_slides/082-semantic-text-colors.md +25 -0
  129. package/example_slides/083-typography.md +16 -0
  130. package/example_slides/084-typography-rationale.md +22 -0
  131. package/example_slides/085-icons.md +24 -0
  132. package/example_slides/086-tables.md +14 -0
  133. package/example_slides/087-code-blocks.md +18 -0
  134. package/example_slides/088-motion-modes.md +35 -0
  135. package/example_slides/089-slide-transitions.md +31 -0
  136. package/example_slides/090-v-click-reveals.md +40 -0
  137. package/example_slides/091-accessibility.md +27 -0
  138. package/example_slides/092-safe-zone.md +17 -0
  139. package/example_slides/093-questions.md +8 -0
  140. package/example_white.md +10 -0
  141. package/fonts/IBMPlexMono-Medium.woff2 +1449 -0
  142. package/fonts/IBMPlexMono-Regular.woff2 +1449 -0
  143. package/fonts/IBMPlexSans-Bold.woff2 +1449 -0
  144. package/fonts/IBMPlexSans-Medium.woff2 +1449 -0
  145. package/fonts/IBMPlexSans-Regular.woff2 +1449 -0
  146. package/fonts/IBMPlexSans-SemiBold.woff2 +1449 -0
  147. package/fonts/LICENSE.txt +93 -0
  148. package/layouts/slide.vue +251 -0
  149. package/package.json +62 -0
  150. package/public/avatars/alice.png +0 -0
  151. package/public/avatars/bob.png +0 -0
  152. package/public/avatars/carol.png +0 -0
  153. package/scripts/chart-audit.mjs +216 -0
  154. package/scripts/contrast-audit.mjs +299 -0
  155. package/scripts/generate-palette.mjs +395 -0
  156. package/scripts/integrity-audit.mjs +357 -0
  157. package/scripts/shared/css-utils.mjs +216 -0
  158. package/scripts/shiki-audit.mjs +300 -0
  159. package/scripts/typography-audit.mjs +300 -0
  160. package/setup/main.ts +107 -0
  161. package/setup/mermaid.ts +237 -0
  162. package/setup/shiki.ts +40 -0
  163. package/snippets/demo.ts +26 -0
  164. package/styles/base.css +1053 -0
  165. package/styles/colors.css +422 -0
  166. package/styles/index.css +12 -0
  167. package/styles/motion.css +486 -0
  168. package/uno.config.ts +67 -0
package/setup/main.ts ADDED
@@ -0,0 +1,107 @@
1
+ /**
2
+ * slidev-theme-troshab — Main Setup
3
+ *
4
+ * Smart automatic image preloading for smoother transitions.
5
+ *
6
+ * Strategy:
7
+ * 1. Startup: immediately preload current + ahead slides (parallel)
8
+ * 2. Background: sequentially preload remaining slides
9
+ * 3. Navigation: ensure upcoming slides are ready
10
+ */
11
+
12
+ import { defineAppSetup } from '@slidev/types'
13
+ import { watch } from 'vue'
14
+
15
+ const loaded = new Set<string>()
16
+ const loading = new Set<string>()
17
+
18
+ function extractImages(content: string): string[] {
19
+ if (!content) return []
20
+ const urls: string[] = []
21
+ const imgExt = /\.(png|jpe?g|gif|webp|svg|avif|bmp|ico)$/i
22
+ let m
23
+
24
+ const md = /!\[[^\]]*\]\(([^)\s"']+)/g
25
+ while ((m = md.exec(content))) urls.push(m[1])
26
+
27
+ const html = /<img[^>]+:?src=["']([^"']+)/gi
28
+ while ((m = html.exec(content))) urls.push(m[1])
29
+
30
+ const css = /url\(["']?([^"')]+)/g
31
+ while ((m = css.exec(content))) if (imgExt.test(m[1])) urls.push(m[1])
32
+
33
+ return urls.filter(u => u && !u.startsWith('data:'))
34
+ }
35
+
36
+ function getSlideImages(slide: any): string[] {
37
+ const urls: string[] = []
38
+ if (slide?.content) urls.push(...extractImages(slide.content))
39
+ if (slide?.source?.raw) urls.push(...extractImages(slide.source.raw))
40
+
41
+ const fm = slide?.frontmatter || slide?.meta || {}
42
+ for (const key of ['image', 'background', 'backgroundImage', 'src', 'cover']) {
43
+ if (typeof fm[key] === 'string') urls.push(fm[key])
44
+ }
45
+ return [...new Set(urls)]
46
+ }
47
+
48
+ function preload(url: string): Promise<void> {
49
+ if (loaded.has(url) || loading.has(url)) return Promise.resolve()
50
+ loading.add(url)
51
+ return new Promise(resolve => {
52
+ const img = new Image()
53
+ img.onload = () => { loading.delete(url); loaded.add(url); resolve() }
54
+ img.onerror = () => { loading.delete(url); resolve() }
55
+ img.src = url
56
+ })
57
+ }
58
+
59
+ async function preloadSlide(images: string[]): Promise<void> {
60
+ await Promise.all(images.filter(u => !loaded.has(u)).map(preload))
61
+ }
62
+
63
+ async function preloadSequentially(slideImages: string[][]): Promise<void> {
64
+ for (const images of slideImages) {
65
+ if (images.length > 0) await preloadSlide(images)
66
+ await new Promise(r => setTimeout(r, 50))
67
+ }
68
+ }
69
+
70
+ export default defineAppSetup(({ router }) => {
71
+ router.isReady().then(async () => {
72
+ const slidev = (window as any).__slidev__
73
+ if (!slidev?.nav) return
74
+
75
+ const config = slidev.configs?.preloadImages ?? {}
76
+ if (config.enabled === false) return
77
+
78
+ const ahead = config.ahead ?? 3
79
+ const slides: any[] = slidev.nav.slides || []
80
+ const current = (slidev.nav.currentSlideNo ?? 1) - 1
81
+ const slideImages: string[][] = slides.map(getSlideImages)
82
+
83
+ if (import.meta.env?.DEV) {
84
+ console.log(`[theme] Preloading images from ${slides.length} slides`)
85
+ }
86
+
87
+ // Phase 1: Priority slides (parallel)
88
+ const priorityEnd = Math.min(current + ahead + 1, slides.length)
89
+ await Promise.all(slideImages.slice(current, priorityEnd).map(preloadSlide))
90
+
91
+ // Phase 2: Remaining slides (sequential)
92
+ preloadSequentially(slideImages.slice(priorityEnd))
93
+
94
+ // Phase 3: On navigation - preload upcoming slides
95
+ watch(
96
+ () => slidev.nav.currentSlideNo,
97
+ async (newSlide: number) => {
98
+ for (let i = 0; i <= ahead; i++) {
99
+ const idx = newSlide - 1 + i
100
+ if (idx < slideImages.length) {
101
+ await preloadSlide(slideImages[idx].filter(u => !loaded.has(u)))
102
+ }
103
+ }
104
+ }
105
+ )
106
+ })
107
+ })
@@ -0,0 +1,237 @@
1
+ import { defineMermaidSetup } from '@slidev/types'
2
+
3
+ /**
4
+ * Mermaid theme configuration for slidev-theme-troshab
5
+ *
6
+ * Reads colors from CSS custom properties at runtime for consistency
7
+ * with the Tailwind palette system defined in styles/colors.css.
8
+ * No fallback hex values - colors.css is the single source of truth.
9
+ *
10
+ * Note: Theme detection happens at page load. If you toggle theme
11
+ * mid-presentation (T key), diagrams won't update — reload the page.
12
+ */
13
+ export default defineMermaidSetup(() => {
14
+ // SSR guard — no DOM available during server-side rendering
15
+ if (typeof document === 'undefined') return {}
16
+
17
+ // Runtime check for dark mode
18
+ const isDark = document.documentElement.classList.contains('dark')
19
+
20
+ /**
21
+ * Get CSS custom property value from :root.
22
+ * Throws if variable is not found (no fallbacks - colors.css is the source of truth).
23
+ */
24
+ const getCssVar = (name: string): string => {
25
+ const value = getComputedStyle(document.documentElement)
26
+ .getPropertyValue(name)
27
+ .trim()
28
+ if (!value) {
29
+ throw new Error(`CSS variable ${name} is empty - check styles/colors.css`)
30
+ }
31
+ return value
32
+ }
33
+
34
+ // Read colors from CSS custom properties (no fallbacks)
35
+ const colors = {
36
+ bg: getCssVar('--color-bg'),
37
+ bgSoft: getCssVar('--color-bg-soft'),
38
+ bgMuted: getCssVar('--color-bg-muted'),
39
+ text: getCssVar('--color-text'),
40
+ textSecondary: getCssVar('--color-text-secondary'),
41
+ textTertiary: getCssVar('--color-text-tertiary'),
42
+ border: getCssVar('--color-border'),
43
+ borderStrong: getCssVar('--color-border-strong'),
44
+ primary: getCssVar('--color-primary'),
45
+ primarySoft: getCssVar('--color-primary-soft'),
46
+ success: getCssVar('--color-success'),
47
+ warning: getCssVar('--color-warning'),
48
+ danger: getCssVar('--color-danger'),
49
+ info: getCssVar('--color-info'),
50
+ chart1: getCssVar('--chart-1'),
51
+ chart2: getCssVar('--chart-2'),
52
+ chart3: getCssVar('--chart-3'),
53
+ chart4: getCssVar('--chart-4'),
54
+ chart5: getCssVar('--chart-5'),
55
+ chart6: getCssVar('--chart-6'),
56
+ chart7: getCssVar('--chart-7'),
57
+ chart8: getCssVar('--chart-8'),
58
+ }
59
+
60
+ return {
61
+ theme: 'base',
62
+ darkMode: isDark,
63
+ themeVariables: {
64
+ // Background
65
+ background: colors.bg,
66
+
67
+ // Primary colors
68
+ primaryColor: colors.primarySoft,
69
+ primaryTextColor: colors.text,
70
+ primaryBorderColor: colors.primary,
71
+
72
+ // Secondary
73
+ secondaryColor: colors.bgSoft,
74
+ secondaryTextColor: colors.textSecondary,
75
+ secondaryBorderColor: colors.border,
76
+
77
+ // Tertiary (explicit — prevents hue-shift derivation from secondaryColor)
78
+ tertiaryColor: colors.bgMuted,
79
+ tertiaryTextColor: colors.textTertiary,
80
+ tertiaryBorderColor: colors.borderStrong,
81
+
82
+ // Lines & arrows
83
+ lineColor: colors.textSecondary,
84
+ arrowheadColor: colors.textSecondary,
85
+
86
+ // Text
87
+ textColor: colors.text,
88
+
89
+ // Nodes (flowchart)
90
+ nodeBkg: colors.bgSoft,
91
+ nodeBorder: colors.primary,
92
+ nodeTextColor: colors.text,
93
+
94
+ // Cluster (flowchart subgraphs)
95
+ mainBkg: colors.bgSoft,
96
+ clusterBkg: colors.bgMuted,
97
+ clusterBorder: colors.borderStrong,
98
+ titleColor: colors.textTertiary,
99
+
100
+ // Edge labels (flowchart, ER, class)
101
+ edgeLabelBackground: colors.bgMuted,
102
+
103
+ // Notes (sequence)
104
+ noteBkgColor: colors.bgSoft,
105
+ noteTextColor: colors.text,
106
+ noteBorderColor: colors.border,
107
+
108
+ // Sequence diagram
109
+ actorBkg: colors.bgSoft,
110
+ actorBorder: colors.primary,
111
+ actorTextColor: colors.text,
112
+ actorLineColor: colors.textSecondary,
113
+ signalColor: colors.textSecondary,
114
+ signalTextColor: colors.text,
115
+ labelBoxBkgColor: colors.bgMuted,
116
+ labelBoxBorderColor: colors.border,
117
+ labelTextColor: colors.text,
118
+ loopTextColor: colors.textSecondary,
119
+ activationBkgColor: colors.primarySoft,
120
+ activationBorderColor: colors.primary,
121
+ sequenceNumberColor: colors.bg,
122
+
123
+ // State diagram
124
+ labelColor: colors.text,
125
+ labelBackgroundColor: colors.bgMuted,
126
+ stateLabelColor: colors.text,
127
+
128
+ // ER diagram
129
+ attributeBackgroundColorOdd: colors.bgSoft,
130
+ attributeBackgroundColorEven: colors.bgMuted,
131
+ // ER styling handled by CSS overrides in base.css
132
+
133
+ // Pie chart — 8 colors (segments beyond 8 use Mermaid defaults)
134
+ pie1: colors.chart1,
135
+ pie2: colors.chart2,
136
+ pie3: colors.chart3,
137
+ pie4: colors.chart4,
138
+ pie5: colors.chart5,
139
+ pie6: colors.chart6,
140
+ pie7: colors.chart7,
141
+ pie8: colors.chart8,
142
+ pieStrokeColor: colors.bg,
143
+ pieStrokeWidth: '2px',
144
+ pieTitleTextColor: colors.text,
145
+ pieSectionTextColor: colors.bg,
146
+ pieLegendTextColor: colors.text,
147
+ pieOuterStrokeWidth: '2px',
148
+ pieOuterStrokeColor: colors.borderStrong,
149
+ pieOpacity: '1',
150
+
151
+ // XY Chart
152
+ xyChart: {
153
+ backgroundColor: 'transparent',
154
+ titleColor: colors.text,
155
+ xAxisTitleColor: colors.textSecondary,
156
+ yAxisTitleColor: colors.textSecondary,
157
+ xAxisLabelColor: colors.textSecondary,
158
+ yAxisLabelColor: colors.textSecondary,
159
+ xAxisTickColor: colors.borderStrong,
160
+ yAxisTickColor: colors.borderStrong,
161
+ xAxisLineColor: colors.borderStrong,
162
+ yAxisLineColor: colors.borderStrong,
163
+ plotColorPalette: `${colors.chart3},${colors.chart5},${colors.chart4},${colors.chart6},${colors.chart1},${colors.chart2}`,
164
+ },
165
+
166
+ // Git Graph — branch labels are TEXT on colored circles (git0-7)
167
+ // Light: chart colors are dark shades → light text (colors.bg = white)
168
+ // Dark: chart colors are light shades → dark text (colors.bg = dark)
169
+ git0: colors.chart1,
170
+ git1: colors.chart2,
171
+ git2: colors.chart3,
172
+ git3: colors.chart4,
173
+ git4: colors.chart5,
174
+ git5: colors.chart6,
175
+ git6: colors.chart7,
176
+ git7: colors.chart8,
177
+ gitBranchLabel0: colors.bg,
178
+ gitBranchLabel1: colors.bg,
179
+ gitBranchLabel2: colors.bg,
180
+ gitBranchLabel3: colors.bg,
181
+ gitBranchLabel4: colors.bg,
182
+ gitBranchLabel5: colors.bg,
183
+ gitBranchLabel6: colors.bg,
184
+ gitBranchLabel7: colors.bg,
185
+ commitLabelColor: colors.text,
186
+ commitLabelBackground: colors.bgMuted,
187
+ commitLabelFontSize: '12px',
188
+ tagLabelColor: colors.text,
189
+ tagLabelBackground: colors.bgSoft,
190
+ tagLabelBorder: colors.borderStrong,
191
+ tagLabelFontSize: '12px',
192
+
193
+ // Timeline & Mindmap — both use cScale/cScaleLabel (not mindmap* vars)
194
+ // Text on colored blocks: colors.bg contrasts in both themes
195
+ cScale0: colors.chart1,
196
+ cScale1: colors.chart2,
197
+ cScale2: colors.chart3,
198
+ cScale3: colors.chart4,
199
+ cScale4: colors.chart5,
200
+ cScale5: colors.chart6,
201
+ cScale6: colors.chart7,
202
+ cScale7: colors.chart8,
203
+ cScaleLabel0: colors.bg,
204
+ cScaleLabel1: colors.bg,
205
+ cScaleLabel2: colors.bg,
206
+ cScaleLabel3: colors.bg,
207
+ cScaleLabel4: colors.bg,
208
+ cScaleLabel5: colors.bg,
209
+ cScaleLabel6: colors.bg,
210
+ cScaleLabel7: colors.bg,
211
+
212
+ // Gantt
213
+ sectionBkgColor: 'transparent',
214
+ sectionBkgColor2: 'transparent',
215
+ altSectionBkgColor: 'transparent',
216
+ gridColor: colors.borderStrong,
217
+ doneTaskBkgColor: colors.success,
218
+ doneTaskBorderColor: colors.success,
219
+ activeTaskBkgColor: colors.primary,
220
+ activeTaskBorderColor: colors.primary,
221
+ critBkgColor: colors.danger,
222
+ critBorderColor: colors.danger,
223
+ taskBkgColor: colors.bgSoft,
224
+ taskBorderColor: colors.borderStrong,
225
+ taskTextColor: colors.text,
226
+ taskTextDarkColor: colors.bg,
227
+ taskTextLightColor: colors.text,
228
+ taskTextOutsideColor: colors.text,
229
+ taskTextClickableColor: colors.primary,
230
+ todayLineColor: colors.danger,
231
+ excludeBkgColor: colors.bgMuted,
232
+
233
+ // Fonts
234
+ fontFamily: 'IBM Plex Sans, Arial, sans-serif',
235
+ },
236
+ }
237
+ })
package/setup/shiki.ts ADDED
@@ -0,0 +1,40 @@
1
+ import { defineShikiSetup } from '@slidev/types'
2
+ import { createCssVariablesTheme } from 'shiki'
3
+ import type { ShikiTransformer } from 'shiki'
4
+
5
+ /**
6
+ * Shiki theme using CSS variables from colors.css.
7
+ * Token colors auto-adapt to light/dark via our semantic CSS vars.
8
+ * No hardcoded colors - fully customizable through the theme's color system.
9
+ */
10
+ const theme = createCssVariablesTheme({
11
+ name: 'troshab',
12
+ variablePrefix: '--shiki-',
13
+ variableDefaults: {},
14
+ fontStyle: true,
15
+ })
16
+
17
+ /**
18
+ * Transformer that adds `data-lang` attribute to <pre> elements.
19
+ * CSS in base.css uses `::before { content: attr(data-lang) }` to render
20
+ * a language label bar above every code block.
21
+ */
22
+ const langLabelTransformer: ShikiTransformer = {
23
+ name: 'lang-label',
24
+ pre(node) {
25
+ const lang = this.options.lang
26
+ if (lang && lang !== 'text') {
27
+ node.properties['data-lang'] = lang
28
+ }
29
+ },
30
+ }
31
+
32
+ export default defineShikiSetup(() => {
33
+ return {
34
+ themes: {
35
+ light: theme,
36
+ dark: theme,
37
+ },
38
+ transformers: [langLabelTransformer],
39
+ }
40
+ })
@@ -0,0 +1,26 @@
1
+ // Example TypeScript snippet for import demo
2
+ // This file demonstrates the <<< import syntax
3
+
4
+ interface ApiResponse<T> {
5
+ data: T
6
+ status: number
7
+ message: string
8
+ }
9
+
10
+ export async function fetchData<T>(
11
+ endpoint: string
12
+ ): Promise<ApiResponse<T>> {
13
+ const response = await fetch(endpoint)
14
+ const data = await response.json()
15
+ return {
16
+ data,
17
+ status: response.status,
18
+ message: response.ok ? 'Success' : 'Error'
19
+ }
20
+ }
21
+
22
+ // #region example
23
+ export const greeting = (name: string) => {
24
+ return `Hello, ${name}!`
25
+ }
26
+ // #endregion example