@slidev/client 0.48.0-beta.2 → 0.48.0-beta.21

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 (91) hide show
  1. package/App.vue +7 -0
  2. package/builtin/Arrow.vue +2 -4
  3. package/builtin/CodeBlockWrapper.vue +14 -6
  4. package/builtin/KaTexBlockWrapper.vue +5 -4
  5. package/builtin/Mermaid.vue +4 -3
  6. package/builtin/Monaco.vue +109 -92
  7. package/builtin/RenderWhen.vue +3 -3
  8. package/builtin/ShikiMagicMove.vue +50 -0
  9. package/builtin/SlideCurrentNo.vue +2 -3
  10. package/builtin/SlidesTotal.vue +3 -4
  11. package/builtin/SlidevVideo.vue +9 -7
  12. package/builtin/Toc.vue +4 -4
  13. package/builtin/TocList.vue +4 -3
  14. package/builtin/Tweet.vue +3 -22
  15. package/builtin/VClick.ts +2 -1
  16. package/builtin/VClickGap.vue +3 -5
  17. package/builtin/VClicks.ts +1 -1
  18. package/composables/useClicks.ts +39 -20
  19. package/composables/useContext.ts +4 -9
  20. package/composables/useNav.ts +182 -44
  21. package/composables/useSwipeControls.ts +40 -0
  22. package/composables/useTocTree.ts +63 -0
  23. package/constants.ts +59 -10
  24. package/context.ts +73 -0
  25. package/env.ts +3 -12
  26. package/internals/ClicksSlider.vue +93 -0
  27. package/internals/Controls.vue +2 -2
  28. package/internals/DrawingControls.vue +39 -9
  29. package/internals/DrawingLayer.vue +3 -3
  30. package/internals/Goto.vue +7 -6
  31. package/internals/IconButton.vue +7 -3
  32. package/internals/InfoDialog.vue +1 -1
  33. package/internals/Modal.vue +1 -1
  34. package/internals/NavControls.vue +11 -10
  35. package/internals/NoteDisplay.vue +131 -8
  36. package/internals/NoteEditable.vue +128 -0
  37. package/internals/NoteStatic.vue +8 -6
  38. package/internals/PrintContainer.vue +8 -6
  39. package/internals/PrintSlide.vue +10 -11
  40. package/internals/PrintSlideClick.vue +14 -18
  41. package/internals/{SlidesOverview.vue → QuickOverview.vue} +31 -20
  42. package/internals/RecordingControls.vue +1 -1
  43. package/internals/RecordingDialog.vue +5 -6
  44. package/internals/{Editor.vue → SideEditor.vue} +9 -5
  45. package/internals/SlideContainer.vue +12 -9
  46. package/internals/SlideLoading.vue +19 -0
  47. package/internals/SlideWrapper.ts +32 -16
  48. package/internals/SlidesShow.vue +20 -18
  49. package/layouts/error.vue +5 -0
  50. package/layouts/two-cols-header.vue +9 -3
  51. package/logic/drawings.ts +13 -10
  52. package/logic/nav-state.ts +20 -0
  53. package/logic/nav.ts +51 -258
  54. package/logic/note.ts +9 -9
  55. package/logic/overview.ts +2 -2
  56. package/logic/route.ts +10 -1
  57. package/logic/slides.ts +19 -0
  58. package/logic/transition.ts +50 -0
  59. package/main.ts +8 -4
  60. package/modules/context.ts +7 -13
  61. package/modules/mermaid.ts +6 -7
  62. package/modules/{directives.ts → v-click.ts} +15 -15
  63. package/modules/v-mark.ts +159 -0
  64. package/package.json +27 -16
  65. package/{internals/EntrySelect.vue → pages/entry.vue} +7 -0
  66. package/{internals/NotesView.vue → pages/notes.vue} +7 -6
  67. package/pages/overview.vue +227 -0
  68. package/{internals/Play.vue → pages/play.vue} +17 -13
  69. package/{internals/PresenterPrint.vue → pages/presenter/print.vue} +13 -8
  70. package/{internals/Presenter.vue → pages/presenter.vue} +114 -105
  71. package/{internals/Print.vue → pages/print.vue} +3 -4
  72. package/routes.ts +28 -60
  73. package/setup/codemirror.ts +8 -3
  74. package/setup/monaco.ts +108 -44
  75. package/setup/root.ts +8 -9
  76. package/setup/shortcuts.ts +2 -1
  77. package/shim-vue.d.ts +38 -0
  78. package/shim.d.ts +1 -13
  79. package/state/index.ts +10 -10
  80. package/styles/code.css +7 -3
  81. package/styles/index.css +68 -7
  82. package/styles/katex.css +1 -1
  83. package/styles/layouts-base.css +17 -12
  84. package/styles/monaco.css +27 -0
  85. package/styles/vars.css +1 -0
  86. package/uno.config.ts +14 -2
  87. package/utils.ts +15 -2
  88. package/iframes/monaco/index.css +0 -28
  89. package/iframes/monaco/index.html +0 -7
  90. package/iframes/monaco/index.ts +0 -260
  91. package/internals/NoteEditor.vue +0 -88
package/setup/monaco.ts CHANGED
@@ -1,52 +1,114 @@
1
- import { getCurrentInstance, onMounted } from 'vue'
2
- import * as monaco from 'monaco-editor'
3
1
  import { createSingletonPromise } from '@antfu/utils'
4
2
  import type { MonacoSetupReturn } from '@slidev/types'
3
+ import * as monaco from 'monaco-editor'
4
+ import { watchEffect } from 'vue'
5
+ import { setupTypeAcquisition } from '@typescript/ata'
6
+ import ts from 'typescript'
7
+
8
+ import EditorWorker from 'monaco-editor/esm/vs/editor/editor.worker?worker'
9
+ import CssWorker from 'monaco-editor/esm/vs/language/css/css.worker?worker'
10
+ import HtmlWorker from 'monaco-editor/esm/vs/language/html/html.worker?worker'
11
+ import JsonWorker from 'monaco-editor/esm/vs/language/json/json.worker?worker'
12
+ import TsWorker from 'monaco-editor/esm/vs/language/typescript/ts.worker?worker'
13
+
14
+ // @ts-expect-error missing types
15
+ import { ContextViewService } from 'monaco-editor/esm/vs/platform/contextview/browser/contextViewService'
16
+
17
+ // @ts-expect-error missing types
18
+ import { SyncDescriptor } from 'monaco-editor/esm/vs/platform/instantiation/common/descriptors'
19
+
20
+ // @ts-expect-error missing types
21
+ import { StandaloneServices } from 'monaco-editor/esm/vs/editor/standalone/browser/standaloneServices'
22
+
23
+ import { isDark } from '../logic/dark'
24
+ import configs from '#slidev/configs'
5
25
 
6
26
  /* __imports__ */
27
+ window.MonacoEnvironment = {
28
+ getWorker(_, label) {
29
+ if (label === 'json')
30
+ return new JsonWorker()
31
+ if (label === 'css' || label === 'scss' || label === 'less')
32
+ return new CssWorker()
33
+ if (label === 'html' || label === 'handlebars' || label === 'razor')
34
+ return new HtmlWorker()
35
+ if (label === 'typescript' || label === 'javascript')
36
+ return new TsWorker()
37
+ return new EditorWorker()
38
+ },
39
+ }
40
+
41
+ class ContextViewService2 extends ContextViewService {
42
+ showContextView(...args: any) {
43
+ super.showContextView(...args)
44
+ // @ts-expect-error missing types
45
+ const contextView = this.contextView.view as HTMLElement
46
+ contextView.style.left = `calc(${contextView.style.left} / var(--slidev-slide-scale))`
47
+ contextView.style.top = `calc(${contextView.style.top} / var(--slidev-slide-scale))`
48
+ // Reset the scale to 1. Otherwise, the sub-menu will be in the wrong position.
49
+ contextView.style.transform = `scale(calc(1 / var(--slidev-slide-scale)))`
50
+ contextView.style.transformOrigin = '0 0'
51
+ }
52
+ }
7
53
 
8
54
  const setup = createSingletonPromise(async () => {
9
- monaco.languages.typescript.typescriptDefaults.setCompilerOptions({
10
- ...monaco.languages.typescript.typescriptDefaults.getCompilerOptions(),
11
- noUnusedLocals: false,
12
- noUnusedParameters: false,
13
- allowUnreachableCode: true,
14
- allowUnusedLabels: true,
55
+ // Initialize services first, otherwise we can't override them.
56
+ StandaloneServices.initialize({
57
+ contextViewService: new SyncDescriptor(ContextViewService2, [], true),
58
+ })
59
+
60
+ const defaults = monaco.languages.typescript.typescriptDefaults
61
+
62
+ defaults.setCompilerOptions({
63
+ ...defaults.getCompilerOptions(),
15
64
  strict: true,
65
+ moduleResolution: monaco.languages.typescript.ModuleResolutionKind.NodeJs,
66
+ module: monaco.languages.typescript.ModuleKind.ESNext,
16
67
  })
17
68
 
18
- await Promise.all([
19
- // load workers
20
- (async () => {
21
- const [
22
- { default: EditorWorker },
23
- { default: JsonWorker },
24
- { default: CssWorker },
25
- { default: HtmlWorker },
26
- { default: TsWorker },
27
- ] = await Promise.all([
28
- import('monaco-editor/esm/vs/editor/editor.worker?worker'),
29
- import('monaco-editor/esm/vs/language/json/json.worker?worker'),
30
- import('monaco-editor/esm/vs/language/css/css.worker?worker'),
31
- import('monaco-editor/esm/vs/language/html/html.worker?worker'),
32
- import('monaco-editor/esm/vs/language/typescript/ts.worker?worker'),
33
- ])
34
-
35
- window.MonacoEnvironment = {
36
- getWorker(_: any, label: string) {
37
- if (label === 'json')
38
- return new JsonWorker()
39
- if (label === 'css' || label === 'scss' || label === 'less')
40
- return new CssWorker()
41
- if (label === 'html' || label === 'handlebars' || label === 'razor')
42
- return new HtmlWorker()
43
- if (label === 'typescript' || label === 'javascript')
44
- return new TsWorker()
45
- return new EditorWorker()
69
+ // Load types from server
70
+ import('#slidev/monaco-types')
71
+
72
+ const ata = configs.monacoTypesSource === 'cdn'
73
+ ? setupTypeAcquisition({
74
+ projectName: 'TypeScript Playground',
75
+ typescript: ts as any, // Version mismatch. No problem found so far.
76
+ logger: console,
77
+ delegate: {
78
+ receivedFile: (code: string, path: string) => {
79
+ defaults.addExtraLib(code, `file://${path}`)
80
+ const uri = monaco.Uri.file(path)
81
+ if (monaco.editor.getModel(uri) === null)
82
+ monaco.editor.createModel(code, 'javascript', uri)
83
+ },
84
+ progress: (downloaded: number, total: number) => {
85
+ // eslint-disable-next-line no-console
86
+ console.debug(`[Typescript ATA] ${downloaded} / ${total}`)
46
87
  },
47
- }
48
- })(),
49
- ])
88
+ },
89
+ })
90
+ : () => { }
91
+
92
+ // monaco.languages.register({ id: 'vue' })
93
+ monaco.languages.register({ id: 'typescript' })
94
+ monaco.languages.register({ id: 'javascript' })
95
+
96
+ const { shiki, themes, shikiToMonaco } = await import('#slidev/shiki')
97
+ const highlighter = await shiki
98
+
99
+ // Use Shiki to highlight Monaco
100
+ shikiToMonaco(highlighter, monaco)
101
+
102
+ if (typeof themes === 'string') {
103
+ monaco.editor.setTheme(themes)
104
+ }
105
+ else {
106
+ watchEffect(() => {
107
+ monaco.editor.setTheme(isDark.value
108
+ ? themes.dark || 'vitesse-dark'
109
+ : themes.light || 'vitesse-light')
110
+ })
111
+ }
50
112
 
51
113
  // @ts-expect-error injected in runtime
52
114
  // eslint-disable-next-line unused-imports/no-unused-vars
@@ -56,15 +118,17 @@ const setup = createSingletonPromise(async () => {
56
118
 
57
119
  /* __async_injections__ */
58
120
 
59
- if (getCurrentInstance())
60
- await new Promise<void>(resolve => onMounted(resolve))
61
-
62
121
  return {
63
122
  monaco,
123
+ ata,
64
124
  ...injection_return,
65
125
  }
66
126
  })
67
127
 
68
- export default setup
128
+ export async function addFile(raw: Promise<{ default: string }>, path: string) {
129
+ const code = (await raw).default
130
+ monaco.languages.typescript.typescriptDefaults.addExtraLib(code, `file:///${path}`)
131
+ monaco.editor.createModel(code, 'javascript', monaco.Uri.file(path))
132
+ }
69
133
 
70
- setup()
134
+ export default setup
package/setup/root.ts CHANGED
@@ -1,14 +1,14 @@
1
1
  /* __imports__ */
2
2
  import { watch } from 'vue'
3
3
  import { useHead } from '@unhead/vue'
4
- import { nanoid } from 'nanoid'
5
4
  import { configs } from '../env'
6
5
  import { initSharedState, onPatch, patch } from '../state/shared'
7
6
  import { initDrawingState } from '../state/drawings'
8
- import { clicksContext, currentPage, getPath, isNotesViewer, isPresenter } from '../logic/nav'
7
+ import { clicksContext, currentSlideNo, getSlidePath, hasPrimarySlide, isNotesViewer, isPresenter } from '../logic/nav'
9
8
  import { router } from '../routes'
10
9
  import { TRUST_ORIGINS } from '../constants'
11
10
  import { skipTransition } from '../composables/hmr'
11
+ import { makeId } from '../logic/utils'
12
12
 
13
13
  export default function setupRoot() {
14
14
  // @ts-expect-error injected in runtime
@@ -25,7 +25,7 @@ export default function setupRoot() {
25
25
  initSharedState(`${title} - shared`)
26
26
  initDrawingState(`${title} - drawings`)
27
27
 
28
- const id = `${location.origin}_${nanoid()}`
28
+ const id = `${location.origin}_${makeId()}`
29
29
 
30
30
  // update shared state
31
31
  function updateSharedState() {
@@ -37,11 +37,11 @@ export default function setupRoot() {
37
37
  return
38
38
 
39
39
  if (isPresenter.value) {
40
- patch('page', +currentPage.value)
40
+ patch('page', +currentSlideNo.value)
41
41
  patch('clicks', clicksContext.value.current)
42
42
  }
43
43
  else {
44
- patch('viewerPage', +currentPage.value)
44
+ patch('viewerPage', +currentSlideNo.value)
45
45
  patch('viewerClicks', clicksContext.value.current)
46
46
  }
47
47
 
@@ -55,13 +55,12 @@ export default function setupRoot() {
55
55
  watch(clicksContext, updateSharedState)
56
56
 
57
57
  onPatch((state) => {
58
- const routePath = router.currentRoute.value.path
59
- if (!routePath.match(/^\/(\d+|presenter)\/?/))
58
+ if (!hasPrimarySlide.value)
60
59
  return
61
- if (state.lastUpdate?.type === 'presenter' && (+state.page !== +currentPage.value || +clicksContext.value.current !== +state.clicks)) {
60
+ if (state.lastUpdate?.type === 'presenter' && (+state.page !== +currentSlideNo.value || +clicksContext.value.current !== +state.clicks)) {
62
61
  skipTransition.value = false
63
62
  router.replace({
64
- path: getPath(state.page),
63
+ path: getSlidePath(state.page),
65
64
  query: {
66
65
  ...router.currentRoute.value.query,
67
66
  clicks: state.clicks || 0,
@@ -1,7 +1,8 @@
1
1
  /* __imports__ */
2
2
  import { and, not, or } from '@vueuse/math'
3
3
  import type { NavOperations, ShortcutOptions } from '@slidev/types'
4
- import { downloadPDF, go, goFirst, goLast, next, nextSlide, prev, prevSlide } from '../logic/nav'
4
+ import { downloadPDF } from '../utils'
5
+ import { go, goFirst, goLast, next, nextSlide, prev, prevSlide } from '../logic/nav'
5
6
  import { toggleDark } from '../logic/dark'
6
7
  import { magicKeys, showGotoDialog, showOverview, toggleOverview } from '../state'
7
8
  import { drawingEnabled } from '../logic/drawings'
package/shim-vue.d.ts ADDED
@@ -0,0 +1,38 @@
1
+ declare module 'vue' {
2
+ import type { UnwrapNestedRefs } from 'vue'
3
+ import type { SlidevContext } from './modules/context'
4
+
5
+ interface ComponentCustomProperties {
6
+ $slidev: UnwrapNestedRefs<SlidevContext>
7
+ }
8
+ }
9
+
10
+ declare module 'vue-router' {
11
+ import type { TransitionGroupProps } from 'vue'
12
+ import type { ClicksContext, SlideInfo } from '@slidev/types'
13
+
14
+ interface RouteMeta {
15
+ // inherited from frontmatter
16
+ layout: string
17
+ name?: string
18
+ class?: string
19
+ clicks?: number
20
+ transition?: string | TransitionGroupProps | undefined
21
+ preload?: boolean
22
+
23
+ // slide info
24
+ slide?: Omit<SlideInfo, 'source'> & {
25
+ noteHTML: string
26
+ filepath: string
27
+ start: number
28
+ id: number
29
+ no: number
30
+ }
31
+
32
+ // private fields
33
+ __clicksContext: null | ClicksContext
34
+ __preloaded?: boolean
35
+ }
36
+ }
37
+
38
+ export {}
package/shim.d.ts CHANGED
@@ -1,23 +1,11 @@
1
- declare interface Window {
2
- // extend the window
3
- }
4
-
5
- declare module '*.vue';
6
-
7
- // with unplugin-vue-markdown, markdowns can be treat as Vue components
8
1
  declare module '*.md' {
2
+ // with unplugin-vue-markdown, markdowns can be treat as Vue components
9
3
  import type { ComponentOptions } from 'vue'
10
4
 
11
5
  const component: ComponentOptions
12
6
  export default component
13
7
  }
14
8
 
15
- declare module '/@slidev/configs' {
16
- import { SlidevConfig } from '@slidev/types'
17
-
18
- export default SlidevConfig
19
- }
20
-
21
9
  declare module 'mermaid/dist/mermaid.esm.mjs' {
22
10
  import Mermaid from 'mermaid/dist/mermaid.d.ts'
23
11
 
package/state/index.ts CHANGED
@@ -5,6 +5,7 @@ import { slideAspect } from '../env'
5
5
  export const showRecordingDialog = ref(false)
6
6
  export const showInfoDialog = ref(false)
7
7
  export const showGotoDialog = ref(false)
8
+ export const showOverview = ref(false)
8
9
 
9
10
  export const shortcutsEnabled = ref(true)
10
11
  export const breakpoints = useBreakpoints({
@@ -20,19 +21,18 @@ export const activeElement = useActiveElement()
20
21
  export const isInputting = computed(() => ['INPUT', 'TEXTAREA'].includes(activeElement.value?.tagName || '') || activeElement.value?.classList.contains('CodeMirror-code'))
21
22
  export const isOnFocus = computed(() => ['BUTTON', 'A'].includes(activeElement.value?.tagName || ''))
22
23
 
23
- export const currentCamera = useLocalStorage<string>('slidev-camera', 'default')
24
- export const currentMic = useLocalStorage<string>('slidev-mic', 'default')
24
+ export const currentCamera = useLocalStorage<string>('slidev-camera', 'default', { listenToStorageChanges: false })
25
+ export const currentMic = useLocalStorage<string>('slidev-mic', 'default', { listenToStorageChanges: false })
25
26
  export const slideScale = useLocalStorage<number>('slidev-scale', 0)
26
27
 
27
- export const showOverview = useLocalStorage('slidev-show-overview', false)
28
- export const showPresenterCursor = useLocalStorage('slidev-presenter-cursor', true)
29
- export const showEditor = useLocalStorage('slidev-show-editor', false)
30
- export const isEditorVertical = useLocalStorage('slidev-editor-vertical', false)
31
- export const editorWidth = useLocalStorage('slidev-editor-width', isClient ? window.innerWidth * 0.4 : 318)
32
- export const editorHeight = useLocalStorage('slidev-editor-height', isClient ? window.innerHeight * 0.4 : 300)
28
+ export const showPresenterCursor = useLocalStorage('slidev-presenter-cursor', true, { listenToStorageChanges: false })
29
+ export const showEditor = useLocalStorage('slidev-show-editor', false, { listenToStorageChanges: false })
30
+ export const isEditorVertical = useLocalStorage('slidev-editor-vertical', false, { listenToStorageChanges: false })
31
+ export const editorWidth = useLocalStorage('slidev-editor-width', isClient ? window.innerWidth * 0.4 : 318, { listenToStorageChanges: false })
32
+ export const editorHeight = useLocalStorage('slidev-editor-height', isClient ? window.innerHeight * 0.4 : 300, { listenToStorageChanges: false })
33
33
 
34
- export const presenterNotesFontSize = useLocalStorage('slidev-presenter-font-size', 1)
35
- export const presenterLayout = useLocalStorage('slidev-presenter-layout', 1)
34
+ export const presenterNotesFontSize = useLocalStorage('slidev-presenter-font-size', 1, { listenToStorageChanges: false })
35
+ export const presenterLayout = useLocalStorage('slidev-presenter-layout', 1, { listenToStorageChanges: false })
36
36
 
37
37
  export function togglePresenterLayout() {
38
38
  presenterLayout.value = presenterLayout.value + 1
package/styles/code.css CHANGED
@@ -59,7 +59,9 @@ html:not(.dark) .shiki span {
59
59
  .slidev-code-line-numbers .slidev-code code .line::before {
60
60
  content: counter(step);
61
61
  counter-increment: step;
62
- @apply w-4 mr-6 inline-block text-right text-gray-400 dark:text-gray-600;
62
+ display: inline-block;
63
+ text-align: right;
64
+ --uno: w-4 mr-6 text-gray-400 dark-text-gray-600;
63
65
  }
64
66
 
65
67
  /* Inline Code */
@@ -67,7 +69,7 @@ html:not(.dark) .shiki span {
67
69
  font-size: 0.9em;
68
70
  background: var(--slidev-code-background);
69
71
  border-radius: var(--slidev-code-radius);
70
- @apply font-light py-0.5 px-1.5;
72
+ --uno: font-light py-0.5 px-1.5;
71
73
  }
72
74
 
73
75
  .slidev-layout :not(pre) > code:before {
@@ -82,4 +84,6 @@ html:not(.dark) .shiki span {
82
84
  }
83
85
 
84
86
  /* CodeMirror */
85
- .CodeMirror pre.CodeMirror-placeholder { opacity: 0.4; }
87
+ .CodeMirror pre.CodeMirror-placeholder {
88
+ opacity: 0.4;
89
+ }
package/styles/index.css CHANGED
@@ -16,22 +16,27 @@ html {
16
16
  }
17
17
 
18
18
  .slidev-icon-btn {
19
- @apply inline-block cursor-pointer select-none !outline-none;
19
+ aspect-ratio: 1;
20
+ display: inline-block;
21
+ user-select: none;
22
+ outline: none;
23
+ cursor: pointer;
20
24
  @apply opacity-75 transition duration-200 ease-in-out align-middle rounded p-1;
21
25
  @apply hover:(opacity-100 bg-gray-400 bg-opacity-10);
22
26
  @apply md:p-2;
23
27
  }
24
28
 
25
29
  .slidev-icon-btn.shallow {
26
- @apply opacity-30
30
+ opacity: 0.3;
27
31
  }
28
32
 
29
33
  .slidev-icon-btn.active {
30
- @apply opacity-100
34
+ opacity: 1;
31
35
  }
32
36
 
33
37
  .slidev-icon-btn.disabled {
34
- @apply opacity-25 pointer-events-none;
38
+ opacity: 0.25;
39
+ pointer-events: none;
35
40
  }
36
41
 
37
42
  .slidev-vclick-target {
@@ -39,11 +44,13 @@ html {
39
44
  }
40
45
 
41
46
  .slidev-vclick-hidden {
42
- @apply !opacity-0 !pointer-events-none;
47
+ opacity: 0 !important;
48
+ pointer-events: none !important;
49
+ user-select: none !important;
43
50
  }
44
51
 
45
52
  .slidev-vclick-fade {
46
- @apply opacity-50;
53
+ opacity: 0.5;
47
54
  }
48
55
 
49
56
  .slidev-icon {
@@ -53,5 +60,59 @@ html {
53
60
  }
54
61
 
55
62
  .slidev-page {
56
- @apply absolute top-0 left-0 right-0 w-full relative;
63
+ position: relative;
64
+ top: 0;
65
+ left: 0;
66
+ right: 0;
67
+ width: 100%;
68
+ }
69
+
70
+ /* Note Clicks */
71
+
72
+ .slidev-note-with-clicks .slidev-note-fade {
73
+ color: #888888ab;
74
+ }
75
+
76
+ .slidev-note-click-mark {
77
+ user-select: none;
78
+ font-size: 0.7em;
79
+ display: inline-flex;
80
+ --uno: text-violet bg-violet/10 px1 font-mono rounded items-center border
81
+ border-transparent;
82
+ }
83
+ .slidev-note-click-mark.slidev-note-click-mark-active {
84
+ --uno: border border-violet;
85
+ }
86
+ .slidev-note-click-mark.slidev-note-click-mark-past {
87
+ filter: saturate(0);
88
+ opacity: 0.5;
89
+ }
90
+ .slidev-note-click-mark.slidev-note-click-mark-future {
91
+ opacity: 0.5;
92
+ }
93
+
94
+ .slidev-note-click-mark::before {
95
+ content: '';
96
+ display: inline-block;
97
+ --un-icon: url("data:image/svg+xml;utf8,%3Csvg viewBox='0 0 32 32' width='1.2em' height='1.2em' xmlns='http://www.w3.org/2000/svg' %3E%3Cpath fill='currentColor' d='M23 28a1 1 0 0 1-.71-.29l-6.13-6.14l-3.33 5a1 1 0 0 1-1 .44a1 1 0 0 1-.81-.7l-6-20A1 1 0 0 1 6.29 5l20 6a1 1 0 0 1 .7.81a1 1 0 0 1-.44 1l-5 3.33l6.14 6.13a1 1 0 0 1 0 1.42l-4 4A1 1 0 0 1 23 28m0-2.41L25.59 23l-7.16-7.15l5.25-3.5L7.49 7.49l4.86 16.19l3.5-5.25Z'/%3E%3C/svg%3E");
98
+ -webkit-mask: var(--un-icon) no-repeat;
99
+ mask: var(--un-icon) no-repeat;
100
+ -webkit-mask-size: 100% 100%;
101
+ mask-size: 100% 100%;
102
+ background-color: currentColor;
103
+ color: inherit;
104
+ width: 1.2em;
105
+ height: 1.2em;
106
+ opacity: 0.8;
107
+ }
108
+
109
+ .slidev-note-click-mark::after {
110
+ content: attr(data-clicks);
111
+ display: inline-block;
112
+ transform: translateY(0.1em);
113
+ }
114
+
115
+ /* Transform the position back for Rough Notation (v-mark) */
116
+ .rough-annotation {
117
+ transform: scale(calc(1 / var(--slidev-slide-scale)));
57
118
  }
package/styles/katex.css CHANGED
@@ -2,4 +2,4 @@
2
2
  }
3
3
  .slidev-katex-wrapper .mord.dishonored {
4
4
  opacity: 0.3;
5
- }
5
+ }
@@ -1,7 +1,8 @@
1
1
  .slidev-layout {
2
2
  @apply px-14 py-10 text-[1.1rem] h-full;
3
3
 
4
- pre, code {
4
+ pre,
5
+ code {
5
6
  @apply select-text;
6
7
  }
7
8
 
@@ -54,7 +55,9 @@
54
55
  }
55
56
 
56
57
  blockquote {
57
- @apply text-sm px-2 py-1 bg-$prism-background text-$prism-foreground border-$slidev-theme-primary border-l rounded;
58
+ background: var(--slidev-code-background);
59
+ color: var(--slidev-code-foreground);
60
+ @apply text-sm px-2 py-1 border-primary border-l rounded;
58
61
  }
59
62
 
60
63
  blockquote > * {
@@ -66,7 +69,7 @@
66
69
  }
67
70
 
68
71
  tr {
69
- @apply border-b border-gray-400 border-opacity-20;
72
+ @apply border-b border-main;
70
73
  }
71
74
 
72
75
  th {
@@ -74,26 +77,28 @@
74
77
  }
75
78
 
76
79
  a {
77
- @apply border-current border-b border-dashed hover:text-$slidev-theme-primary hover:border-solid;
80
+ @apply border-current border-b border-dashed hover:text-primary hover:border-solid;
78
81
  }
79
82
 
80
- td, th {
83
+ td,
84
+ th {
81
85
  @apply p-2 py-3;
82
86
  }
83
87
 
84
- b, strong {
88
+ b,
89
+ strong {
85
90
  @apply font-600;
86
91
  }
87
92
 
88
93
  kbd {
89
- @apply border border-gray-400 border-b-2 border-opacity-20 rounded;
94
+ @apply border border-main border-b-2 rounded;
90
95
  @apply bg-gray-400 bg-opacity-5 py-0.5 px-1 text-xs font-mono;
91
96
  }
92
97
  }
93
98
 
94
99
  .slidev-layout,
95
- [dir=ltr],
96
- .slidev-layout [dir=ltr] {
100
+ [dir='ltr'],
101
+ .slidev-layout [dir='ltr'] {
97
102
  h1 {
98
103
  @apply -ml-[0.05em] mr-0;
99
104
  }
@@ -107,10 +112,10 @@
107
112
  }
108
113
  }
109
114
 
110
- [dir=rtl],
111
- .slidev-layout [dir=rtl] {
115
+ [dir='rtl'],
116
+ .slidev-layout [dir='rtl'] {
112
117
  h1 {
113
- @apply -mr-[0.05em] ml-0;
118
+ @apply -mr-[0.05em] ml-0;
114
119
  }
115
120
 
116
121
  h6 {
@@ -0,0 +1,27 @@
1
+ div[widgetid='messageoverlay'] {
2
+ transform: translateY(calc(100% * (var(--slidev-slide-scale) - 1)));
3
+ }
4
+
5
+ .slidev-monaco-container {
6
+ position: relative;
7
+ margin: var(--slidev-code-margin);
8
+ padding: var(--slidev-code-padding);
9
+ line-height: var(--slidev-code-line-height);
10
+ border-radius: var(--slidev-code-radius);
11
+ background: var(--slidev-code-background);
12
+ }
13
+
14
+ .slidev-monaco-container .monaco-editor {
15
+ --monaco-monospace-font: var(--slidev-code-font-family);
16
+ --vscode-editor-background: var(--slidev-code-background);
17
+ --vscode-editorGutter-background: var(--slidev-code-background);
18
+ }
19
+
20
+ /** Revert styles */
21
+ .slidev-monaco-container .monaco-editor a {
22
+ border-bottom: none;
23
+ }
24
+
25
+ .slidev-monaco-container .monaco-editor a:hover {
26
+ border-bottom: none;
27
+ }
package/styles/vars.css CHANGED
@@ -7,6 +7,7 @@
7
7
  --slidev-code-line-height: 18px;
8
8
  --slidev-code-radius: 4px;
9
9
  --slidev-code-margin: 4px 0;
10
+ --slidev-theme-primary: #3ab9d5;
10
11
 
11
12
  --slidev-transition-duration: 0.5s;
12
13
  --slidev-slide-container-background: black;
package/uno.config.ts CHANGED
@@ -8,6 +8,7 @@ import {
8
8
  transformerDirectives,
9
9
  transformerVariantGroup,
10
10
  } from 'unocss'
11
+ import { variantMatcher } from '@unocss/preset-mini/utils'
11
12
 
12
13
  export default defineConfig({
13
14
  safelist: [
@@ -15,15 +16,26 @@ export default defineConfig({
15
16
  'prose',
16
17
  ],
17
18
  shortcuts: {
18
- 'bg-main': 'bg-white text-[#181818] dark:(bg-[#121212] text-[#ddd])',
19
+ 'bg-main': 'bg-white dark:bg-[#121212]',
19
20
  'bg-active': 'bg-gray-400/10',
20
- 'border-main': 'border-gray-400/20',
21
+ 'border-main': 'border-gray/20',
22
+ 'text-main': 'text-[#181818] dark:text-[#ddd]',
23
+ 'text-primary': 'color-$slidev-theme-primary',
24
+ 'bg-primary': 'bg-$slidev-theme-primary',
25
+ 'border-primary': 'border-$slidev-theme-primary',
21
26
  'abs-tl': 'absolute top-0 left-0',
22
27
  'abs-tr': 'absolute top-0 right-0',
23
28
  'abs-b': 'absolute bottom-0 left-0 right-0',
24
29
  'abs-bl': 'absolute bottom-0 left-0',
25
30
  'abs-br': 'absolute bottom-0 right-0',
26
31
  },
32
+ // Slidev Specific Variants, probably extrat to a preset later
33
+ variants: [
34
+ // `forward:` and `backward:` variant to selectively apply styles based on the direction of the slide
35
+ // For example, `forward:text-red` will only apply to the slides that are navigated forward
36
+ variantMatcher('forward', input => ({ prefix: `.slidev-nav-go-forward ${input.prefix}` })),
37
+ variantMatcher('backward', input => ({ prefix: `.slidev-nav-go-backward ${input.prefix}` })),
38
+ ],
27
39
  presets: [
28
40
  presetUno(),
29
41
  presetAttributify(),
package/utils.ts CHANGED
@@ -1,6 +1,7 @@
1
- import type { RouteRecordRaw } from 'vue-router'
1
+ import type { SlideRoute } from '@slidev/types'
2
+ import { configs } from './env'
2
3
 
3
- export function getSlideClass(route?: RouteRecordRaw, extra = '') {
4
+ export function getSlideClass(route?: SlideRoute, extra = '') {
4
5
  const classes = ['slidev-page', extra]
5
6
 
6
7
  const no = route?.meta?.slide?.no
@@ -9,3 +10,15 @@ export function getSlideClass(route?: RouteRecordRaw, extra = '') {
9
10
 
10
11
  return classes.filter(Boolean).join(' ')
11
12
  }
13
+
14
+ export async function downloadPDF() {
15
+ const { saveAs } = await import('file-saver')
16
+ saveAs(
17
+ typeof configs.download === 'string'
18
+ ? configs.download
19
+ : configs.exportFilename
20
+ ? `${configs.exportFilename}.pdf`
21
+ : `${import.meta.env.BASE_URL}slidev-exported.pdf`,
22
+ `${configs.title}.pdf`,
23
+ )
24
+ }