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

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 (78) 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 +8 -6
  12. package/builtin/Toc.vue +3 -3
  13. package/builtin/TocList.vue +3 -2
  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 +34 -16
  19. package/constants.ts +58 -8
  20. package/context.ts +73 -0
  21. package/env.ts +3 -12
  22. package/internals/ClicksSlider.vue +93 -0
  23. package/internals/Controls.vue +2 -2
  24. package/internals/DrawingControls.vue +39 -9
  25. package/internals/DrawingLayer.vue +3 -3
  26. package/internals/Goto.vue +5 -4
  27. package/internals/IconButton.vue +7 -3
  28. package/internals/InfoDialog.vue +1 -1
  29. package/internals/Modal.vue +1 -1
  30. package/internals/NavControls.vue +4 -5
  31. package/internals/NoteDisplay.vue +131 -8
  32. package/internals/NoteEditable.vue +128 -0
  33. package/internals/NoteStatic.vue +8 -6
  34. package/internals/PrintContainer.vue +4 -3
  35. package/internals/PrintSlide.vue +8 -2
  36. package/internals/PrintSlideClick.vue +5 -7
  37. package/internals/{SlidesOverview.vue → QuickOverview.vue} +21 -10
  38. package/internals/RecordingControls.vue +1 -1
  39. package/internals/RecordingDialog.vue +5 -6
  40. package/internals/{Editor.vue → SideEditor.vue} +7 -3
  41. package/internals/SlideContainer.vue +12 -9
  42. package/internals/SlideWrapper.ts +28 -12
  43. package/internals/SlidesShow.vue +7 -8
  44. package/layouts/two-cols-header.vue +9 -3
  45. package/logic/drawings.ts +6 -3
  46. package/logic/nav.ts +11 -8
  47. package/logic/note.ts +7 -7
  48. package/main.ts +8 -4
  49. package/modules/context.ts +4 -3
  50. package/modules/mermaid.ts +6 -7
  51. package/modules/{directives.ts → v-click.ts} +15 -15
  52. package/modules/v-mark.ts +159 -0
  53. package/package.json +26 -16
  54. package/{internals/EntrySelect.vue → pages/entry.vue} +7 -0
  55. package/{internals/NotesView.vue → pages/notes.vue} +5 -3
  56. package/pages/overview.vue +229 -0
  57. package/{internals/Play.vue → pages/play.vue} +15 -12
  58. package/{internals/PresenterPrint.vue → pages/presenter/print.vue} +12 -7
  59. package/{internals/Presenter.vue → pages/presenter.vue} +108 -100
  60. package/{internals/Print.vue → pages/print.vue} +3 -4
  61. package/routes.ts +27 -51
  62. package/setup/codemirror.ts +8 -3
  63. package/setup/monaco.ts +108 -44
  64. package/setup/root.ts +2 -2
  65. package/shim-vue.d.ts +35 -0
  66. package/shim.d.ts +1 -13
  67. package/state/index.ts +10 -10
  68. package/styles/code.css +7 -3
  69. package/styles/index.css +68 -7
  70. package/styles/katex.css +1 -1
  71. package/styles/layouts-base.css +17 -12
  72. package/styles/monaco.css +27 -0
  73. package/styles/vars.css +1 -0
  74. package/uno.config.ts +14 -2
  75. package/iframes/monaco/index.css +0 -28
  76. package/iframes/monaco/index.html +0 -7
  77. package/iframes/monaco/index.ts +0 -260
  78. package/internals/NoteEditor.vue +0 -88
@@ -2,9 +2,8 @@
2
2
  import { watchEffect } from 'vue'
3
3
  import { windowSize } from '../state'
4
4
  import { isPrintMode } from '../logic/nav'
5
- import { themeVars } from '../env'
6
- import PrintContainer from './PrintContainer.vue'
7
- import PrintStyle from './PrintStyle.vue'
5
+ import PrintContainer from '../internals/PrintContainer.vue'
6
+ import PrintStyle from '../internals/PrintStyle.vue'
8
7
 
9
8
  watchEffect(() => {
10
9
  if (isPrintMode)
@@ -16,7 +15,7 @@ watchEffect(() => {
16
15
 
17
16
  <template>
18
17
  <PrintStyle v-if="isPrintMode" />
19
- <div id="page-root" class="grid grid-cols-[1fr_max-content]" :style="themeVars">
18
+ <div id="page-root" class="grid grid-cols-[1fr_max-content]">
20
19
  <PrintContainer
21
20
  class="w-full h-full"
22
21
  :style="{ background: 'var(--slidev-slide-container-background, black)' }"
package/routes.ts CHANGED
@@ -1,65 +1,73 @@
1
1
  import type { RouteLocationNormalized, RouteRecordRaw } from 'vue-router'
2
2
  import { createRouter, createWebHashHistory, createWebHistory } from 'vue-router'
3
- import type { TransitionGroupProps } from 'vue'
4
- import type { ClicksContext } from '@slidev/types'
5
- import Play from './internals/Play.vue'
6
- import Print from './internals/Print.vue'
7
3
 
8
- // @ts-expect-error missing types
9
- import _rawRoutes, { redirects } from '/@slidev/routes'
4
+ import { rawRoutes, redirects } from '#slidev/routes'
5
+ import configs from '#slidev/configs'
10
6
 
11
- // @ts-expect-error missing types
12
- import _configs from '/@slidev/configs'
13
-
14
- export const rawRoutes = _rawRoutes as RouteRecordRaw[]
7
+ export { rawRoutes }
15
8
 
16
9
  export const routes: RouteRecordRaw[] = [
17
10
  {
18
11
  name: 'play',
19
12
  path: '/',
20
- component: Play,
13
+ component: () => import('./pages/play.vue'),
21
14
  children: [
22
15
  ...rawRoutes,
23
16
  ...redirects,
24
17
  ],
25
18
  },
26
- { name: 'print', path: '/print', component: Print },
19
+ {
20
+ name: 'print',
21
+ path: '/print',
22
+ component: () => import('./pages/print.vue'),
23
+ },
24
+
25
+ // Redirects
27
26
  { path: '', redirect: { path: '/1' } },
28
27
  { path: '/:pathMatch(.*)', redirect: { path: '/1' } },
29
28
  ]
30
29
 
31
30
  if (__SLIDEV_FEATURE_PRESENTER__) {
32
31
  function passwordGuard(to: RouteLocationNormalized) {
33
- if (!_configs.remote || _configs.remote === to.query.password)
32
+ if (!configs.remote || configs.remote === to.query.password)
34
33
  return true
35
- if (_configs.remote && to.query.password === undefined) {
34
+ if (configs.remote && to.query.password === undefined) {
36
35
  // eslint-disable-next-line no-alert
37
36
  const password = prompt('Enter password')
38
- if (_configs.remote === password)
37
+ if (configs.remote === password)
39
38
  return true
40
39
  }
41
40
  if (to.params.no)
42
41
  return { path: `/${to.params.no}` }
43
42
  return { path: '' }
44
43
  }
45
- routes.push({ path: '/presenter/print', component: () => import('./internals/PresenterPrint.vue') })
44
+
45
+ routes.push({
46
+ path: '/presenter/print',
47
+ component: () => import('./pages/presenter/print.vue'),
48
+ })
46
49
  if (__SLIDEV_HAS_SERVER__) {
47
50
  routes.push({
48
51
  name: 'entry',
49
52
  path: '/entry',
50
- component: () => import('./internals/EntrySelect.vue'),
53
+ component: () => import('./pages/entry.vue'),
54
+ })
55
+ routes.push({
56
+ name: 'overview',
57
+ path: '/overview',
58
+ component: () => import('./pages/overview.vue'),
51
59
  })
52
60
  routes.push({
53
61
  name: 'notes',
54
62
  path: '/notes',
55
- component: () => import('./internals/NotesView.vue'),
63
+ component: () => import('./pages/notes.vue'),
56
64
  beforeEnter: passwordGuard,
57
65
  })
58
66
  }
59
67
  routes.push({
60
68
  name: 'presenter',
61
69
  path: '/presenter/:no',
62
- component: () => import('./internals/Presenter.vue'),
70
+ component: () => import('./pages/presenter.vue'),
63
71
  beforeEnter: passwordGuard,
64
72
  })
65
73
  routes.push({
@@ -74,35 +82,3 @@ export const router = createRouter({
74
82
  : createWebHistory(import.meta.env.BASE_URL),
75
83
  routes,
76
84
  })
77
-
78
- declare module 'vue-router' {
79
- interface RouteMeta {
80
- // inherited from frontmatter
81
- layout: string
82
- name?: string
83
- class?: string
84
- clicks?: number
85
- transition?: string | TransitionGroupProps | undefined
86
- preload?: boolean
87
-
88
- // slide info
89
- slide?: {
90
- start: number
91
- end: number
92
- note?: string
93
- noteHTML?: string
94
- id: number
95
- no: number
96
- filepath: string
97
- title?: string
98
- level?: number
99
- raw: string
100
- content: string
101
- frontmatter: Record<string, any>
102
- }
103
-
104
- // private fields
105
- __clicksContext: null | ClicksContext
106
- __preloaded?: boolean
107
- }
108
- }
@@ -1,6 +1,7 @@
1
1
  import type { Ref, WritableComputedRef } from 'vue'
2
+ import { onClickOutside } from '@vueuse/core'
2
3
  import { watch } from 'vue'
3
- import * as _CodeMirror from 'codemirror'
4
+ import CodeMirror from 'codemirror'
4
5
  import 'codemirror/mode/javascript/javascript'
5
6
  import 'codemirror/mode/css/css'
6
7
  import 'codemirror/mode/markdown/markdown'
@@ -9,8 +10,6 @@ import 'codemirror/mode/htmlmixed/htmlmixed'
9
10
  import 'codemirror/addon/display/placeholder'
10
11
  import 'codemirror/lib/codemirror.css'
11
12
 
12
- const CodeMirror = _CodeMirror.default ?? ('fromTextArea' in _CodeMirror ? _CodeMirror : globalThis.CodeMirror)
13
-
14
13
  export async function useCodeMirror(
15
14
  textarea: Ref<HTMLTextAreaElement | null | undefined>,
16
15
  input: Ref<string> | WritableComputedRef<string>,
@@ -47,5 +46,11 @@ export async function useCodeMirror(
47
46
  { immediate: true },
48
47
  )
49
48
 
49
+ onClickOutside(cm.getWrapperElement(), () => {
50
+ const el = cm.getInputField()
51
+ if (document.activeElement === el)
52
+ el.blur()
53
+ })
54
+
50
55
  return cm
51
56
  }
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,7 +1,6 @@
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'
@@ -9,6 +8,7 @@ import { clicksContext, currentPage, getPath, isNotesViewer, isPresenter } from
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() {
package/shim-vue.d.ts ADDED
@@ -0,0 +1,35 @@
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
+ interface RouteMeta {
12
+ // inherited from frontmatter
13
+ layout: string
14
+ name?: string
15
+ class?: string
16
+ clicks?: number
17
+ transition?: string | TransitionGroupProps | undefined
18
+ preload?: boolean
19
+
20
+ // slide info
21
+ slide?: Omit<SlideInfo, 'source'> & {
22
+ noteHTML: string
23
+ filepath: string
24
+ start: number
25
+ id: number
26
+ no: number
27
+ }
28
+
29
+ // private fields
30
+ __clicksContext: null | ClicksContext
31
+ __preloaded?: boolean
32
+ }
33
+ }
34
+
35
+ 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
+ }