@lincyaw/viewer 1.0.0-rc.0 → 1.0.0-rc.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -4
- package/package.json +20 -8
- package/src/client/block.ts +70 -0
- package/src/client/code/code-block.ts +54 -0
- package/src/client/code/code-editor.ts +73 -0
- package/src/client/code/code-view.ts +22 -0
- package/src/{highlight.ts → client/code/highlight.ts} +2 -2
- package/src/{outputs.ts → client/code/outputs.ts} +23 -36
- package/src/client/content-marks.ts +15 -0
- package/src/client/element.ts +27 -0
- package/src/client/index.ts +40 -0
- package/src/client/layout.ts +22 -0
- package/src/{markdown.ts → client/markdown/handlers.ts} +22 -116
- package/src/client/markdown/hast.ts +20 -0
- package/src/client/markdown/layout-handlers.ts +57 -0
- package/src/client/markdown/math.ts +10 -0
- package/src/client/markdown/mermaid.ts +75 -0
- package/src/client/markdown/render.ts +79 -0
- package/src/client/markdown/role-mark.ts +9 -0
- package/src/client/markdown/tables.ts +49 -0
- package/src/client/markdown/tabs.ts +52 -0
- package/src/client/markdown/tree-cache.ts +77 -0
- package/src/client/operations.ts +9 -0
- package/src/client/registry.ts +21 -0
- package/src/client/section-context.ts +5 -0
- package/src/client/section.ts +30 -0
- package/src/client/slidev-compat/click-directives.ts +16 -0
- package/src/client/slidev-compat/slide-globals.ts +3 -0
- package/src/{style.css → client/style.css} +306 -81
- package/src/client/viewer-messages.ts +7 -0
- package/src/{plugins.ts → client/viewer-plugins.ts} +3 -2
- package/src/client/viewer-state.ts +47 -0
- package/src/client/views/actions.ts +52 -0
- package/src/client/views/controls.css +44 -0
- package/src/client/views/document.ts +12 -0
- package/src/client/views/outlets.ts +37 -0
- package/src/client/views/overlay.ts +16 -0
- package/src/client/views/present.ts +132 -0
- package/src/client/views/presenter.ts +76 -0
- package/src/client/views/scrolly.ts +4 -0
- package/src/client/views/slide.css +8 -0
- package/src/client/views/slide.ts +57 -0
- package/src/domain/clicks.ts +1 -1
- package/src/domain/code-width.ts +11 -0
- package/src/domain/document-content.ts +6 -0
- package/src/domain/{text.ts → footnotes.ts} +0 -12
- package/src/domain/index.ts +5 -4
- package/src/domain/live.ts +11 -10
- package/src/domain/messages.ts +54 -30
- package/src/domain/origin.ts +17 -32
- package/src/domain/outputs.ts +27 -0
- package/src/domain/steps.ts +2 -1
- package/src/block.ts +0 -122
- package/src/cards.ts +0 -130
- package/src/clicks.ts +0 -124
- package/src/code.ts +0 -235
- package/src/context.ts +0 -16
- package/src/dark.ts +0 -5
- package/src/domain/follow.ts +0 -32
- package/src/globals.ts +0 -66
- package/src/i18n.ts +0 -7
- package/src/index.ts +0 -55
- package/src/operations.ts +0 -28
- package/src/present.ts +0 -327
- package/src/registry.ts +0 -81
- package/src/rich.ts +0 -155
- package/src/section.ts +0 -209
- package/src/viewer.ts +0 -116
- package/src/views.ts +0 -101
- /package/src/{env.d.ts → client/env.d.ts} +0 -0
package/src/code.ts
DELETED
|
@@ -1,235 +0,0 @@
|
|
|
1
|
-
import { currentLocale, OPERATIONS, usePrefersReducedMotion, useService, useStartReport } from '@lincyaw/host'
|
|
2
|
-
import type { Operations } from '@lincyaw/host'
|
|
3
|
-
import { blockState, EXECUTOR, errorMessage, failedRun } from '@lincyaw/kernel'
|
|
4
|
-
import type { CodeNode, IRBlock, RecordedRun, RunRequest, RunResult } from '@lincyaw/kernel'
|
|
5
|
-
import { ShikiMagicMove } from '@shikijs/magic-move/vue'
|
|
6
|
-
import '@shikijs/magic-move/style.css'
|
|
7
|
-
import type { Element, ElementContent, Root } from 'hast'
|
|
8
|
-
import { toHtml } from 'hast-util-to-html'
|
|
9
|
-
import type { PropType, VNode, VNodeChild } from 'vue'
|
|
10
|
-
import { computed, defineComponent, h, inject, onBeforeUnmount, onMounted, ref, shallowRef, watch } from 'vue'
|
|
11
|
-
import { IN_COMPONENT, useSectionContext } from './context.ts'
|
|
12
|
-
import { useDark } from './dark.ts'
|
|
13
|
-
import { codeColumns, originParts } from './domain/index.ts'
|
|
14
|
-
import type { OriginPart } from './domain/index.ts'
|
|
15
|
-
import { highlighterFor, THEMES } from './highlight.ts'
|
|
16
|
-
import { messages } from './i18n.ts'
|
|
17
|
-
import { proseOnly, runOutput } from './outputs.ts'
|
|
18
|
-
|
|
19
|
-
type Loaded = Awaited<ReturnType<typeof highlighterFor>>
|
|
20
|
-
|
|
21
|
-
function useHighlighter(lang: () => string) {
|
|
22
|
-
const shiki = shallowRef<Loaded>()
|
|
23
|
-
const load = async () => {
|
|
24
|
-
const wanted = lang()
|
|
25
|
-
const loaded = await highlighterFor(wanted).catch(() => undefined)
|
|
26
|
-
if (wanted === lang()) shiki.value = loaded
|
|
27
|
-
}
|
|
28
|
-
onMounted(load)
|
|
29
|
-
watch(lang, load)
|
|
30
|
-
return shiki
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
function lineElements(tree: Root): Element[] {
|
|
34
|
-
const pre = tree.children.find((node): node is Element => node.type === 'element')
|
|
35
|
-
const code = pre?.children.find((node): node is Element => node.type === 'element' && node.tagName === 'code')
|
|
36
|
-
return (code?.children ?? []).filter((node: ElementContent): node is Element => node.type === 'element')
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
export const CodeView = defineComponent({
|
|
40
|
-
name: 'PmCodeView',
|
|
41
|
-
props: {
|
|
42
|
-
lang: { type: String, default: '' },
|
|
43
|
-
value: { type: String, required: true },
|
|
44
|
-
highlight: { type: Array as PropType<number[]>, default: undefined },
|
|
45
|
-
},
|
|
46
|
-
setup(props) {
|
|
47
|
-
const shiki = useHighlighter(() => props.lang)
|
|
48
|
-
const code = computed(() => props.value.replace(/\n$/, ''))
|
|
49
|
-
const lines = computed(() => new Set(props.highlight ?? []))
|
|
50
|
-
const tree = computed(() => shiki.value && shiki.value.highlighter.codeToHast(code.value, { lang: shiki.value.lang, themes: THEMES, defaultColor: false }))
|
|
51
|
-
const html = computed(() => {
|
|
52
|
-
if (!tree.value) return undefined
|
|
53
|
-
const marked = lines.value
|
|
54
|
-
lineElements(tree.value).forEach((line, i) => {
|
|
55
|
-
line.properties.class = marked.has(i + 1) ? 'line highlighted' : 'line'
|
|
56
|
-
})
|
|
57
|
-
return toHtml(tree.value)
|
|
58
|
-
})
|
|
59
|
-
const columns = computed(() => codeColumns(code.value))
|
|
60
|
-
return () => {
|
|
61
|
-
const attrs = {
|
|
62
|
-
'class': ['pm-code', { 'pm-code--highlight': lines.value.size > 0 }],
|
|
63
|
-
'style': { '--pm-code-columns': columns.value },
|
|
64
|
-
'data-lang': props.lang || undefined,
|
|
65
|
-
}
|
|
66
|
-
if (html.value) return h('div', { ...attrs, key: 'shiki', innerHTML: html.value })
|
|
67
|
-
const rows = code.value.split('\n').flatMap((text, i) => [h('span', { class: ['line', { highlighted: lines.value.has(i + 1) }] }, text), '\n'])
|
|
68
|
-
return h('div', { ...attrs, key: 'plain' }, [h('pre', { class: 'shiki' }, [h('code', rows.slice(0, -1))])])
|
|
69
|
-
}
|
|
70
|
-
},
|
|
71
|
-
})
|
|
72
|
-
|
|
73
|
-
const VariantView = defineComponent({
|
|
74
|
-
name: 'PmCodeVariant',
|
|
75
|
-
props: {
|
|
76
|
-
lang: { type: String, default: '' },
|
|
77
|
-
value: { type: String, required: true },
|
|
78
|
-
},
|
|
79
|
-
setup(props) {
|
|
80
|
-
const shiki = useHighlighter(() => props.lang)
|
|
81
|
-
const reduced = usePrefersReducedMotion()
|
|
82
|
-
const dark = useDark()
|
|
83
|
-
const code = computed(() => props.value.replace(/\n$/, ''))
|
|
84
|
-
return () => {
|
|
85
|
-
const loaded = shiki.value
|
|
86
|
-
if (!loaded || reduced.value) return h(CodeView, { lang: props.lang, value: props.value })
|
|
87
|
-
return h('div', { 'class': 'pm-code pm-code--magic-move', 'style': { '--pm-code-columns': codeColumns(code.value) }, 'data-lang': props.lang || undefined }, [
|
|
88
|
-
h(ShikiMagicMove, { highlighter: loaded.highlighter, lang: loaded.lang, theme: dark.value ? THEMES.dark : THEMES.light, code: code.value, options: { duration: 500 } }),
|
|
89
|
-
])
|
|
90
|
-
}
|
|
91
|
-
},
|
|
92
|
-
})
|
|
93
|
-
|
|
94
|
-
function link(className: string, href: string | undefined, text: string, attrs: Record<string, unknown> = {}): VNode {
|
|
95
|
-
return href
|
|
96
|
-
? h('a', { ...attrs, class: className, href, target: '_blank', rel: 'noopener' }, text)
|
|
97
|
-
: h('span', { ...attrs, class: className }, text)
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
function originPart(part: OriginPart, k: number): VNode {
|
|
101
|
-
return link(`pm-code-origin__${part.kind}`, part.href, part.text, {
|
|
102
|
-
'key': `${part.kind}:${k}`,
|
|
103
|
-
'title': part.title,
|
|
104
|
-
'data-active': part.active ? '' : undefined,
|
|
105
|
-
'data-status': part.status,
|
|
106
|
-
'data-drift': part.drift,
|
|
107
|
-
})
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
function originBar(node: CodeNode, shown: number | undefined): VNodeChild {
|
|
111
|
-
const bar = originParts(node, shown, currentLocale())
|
|
112
|
-
return bar ? h('div', { 'class': 'pm-code-origin', 'data-anchor': bar.anchor }, bar.parts.map(originPart)) : null
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
const replays = new Set<(data: Record<string, unknown>) => void>()
|
|
116
|
-
const followed = new WeakSet<Operations>()
|
|
117
|
-
|
|
118
|
-
function followRuns(operations: Operations): void {
|
|
119
|
-
if (followed.has(operations)) return
|
|
120
|
-
followed.add(operations)
|
|
121
|
-
operations.onReplay('run', { apply: data => replays.forEach(replay => replay(data)) })
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
export const CodeBlockView = defineComponent({
|
|
125
|
-
name: 'PmCodeBlock',
|
|
126
|
-
props: {
|
|
127
|
-
block: { type: Object as PropType<IRBlock>, required: true },
|
|
128
|
-
step: { type: Number, required: true },
|
|
129
|
-
expanded: Boolean,
|
|
130
|
-
},
|
|
131
|
-
setup(props) {
|
|
132
|
-
const owned = inject(IN_COMPONENT, false)
|
|
133
|
-
const executor = useService(EXECUTOR)
|
|
134
|
-
const operations = useService(OPERATIONS)
|
|
135
|
-
const section = useSectionContext()
|
|
136
|
-
const report = useStartReport()
|
|
137
|
-
const live = shallowRef<RunResult>()
|
|
138
|
-
const fallback = ref<string>()
|
|
139
|
-
const running = ref(false)
|
|
140
|
-
const mounted = ref(false)
|
|
141
|
-
let current: AbortController | undefined
|
|
142
|
-
const stop = () => {
|
|
143
|
-
current?.abort()
|
|
144
|
-
current = undefined
|
|
145
|
-
running.value = false
|
|
146
|
-
}
|
|
147
|
-
onMounted(() => {
|
|
148
|
-
mounted.value = true
|
|
149
|
-
})
|
|
150
|
-
onBeforeUnmount(stop)
|
|
151
|
-
const show = (result: RunResult | undefined) => {
|
|
152
|
-
const node = props.block.node as CodeNode
|
|
153
|
-
const recorded = result && !result.ok && result.exitCode === null && node.outputs?.length
|
|
154
|
-
fallback.value = recorded ? result.stderr.trim() || messages().code.unavailable : undefined
|
|
155
|
-
live.value = recorded ? undefined : result
|
|
156
|
-
}
|
|
157
|
-
const run = async () => {
|
|
158
|
-
const node = props.block.node as CodeNode
|
|
159
|
-
const router = executor.value
|
|
160
|
-
if (!node.run || !router || running.value) return
|
|
161
|
-
stop()
|
|
162
|
-
const controller = new AbortController()
|
|
163
|
-
current = controller
|
|
164
|
-
running.value = true
|
|
165
|
-
const { lang, args, stdin, timeoutMs, executor: named, session } = node.run
|
|
166
|
-
const request: RunRequest = { lang, code: node.value, args, stdin, timeoutMs, executor: named, session }
|
|
167
|
-
const started = Date.now()
|
|
168
|
-
let result: RunResult
|
|
169
|
-
try {
|
|
170
|
-
result = await router.run(request, controller.signal)
|
|
171
|
-
} catch (error) {
|
|
172
|
-
result = failedRun(router.id, messages().code.executorFailed(router.id, errorMessage(error)), Date.now() - started)
|
|
173
|
-
}
|
|
174
|
-
if (controller.signal.aborted) return
|
|
175
|
-
show(result)
|
|
176
|
-
current = undefined
|
|
177
|
-
running.value = false
|
|
178
|
-
const recording = node.outputs?.[0] as RecordedRun | undefined
|
|
179
|
-
operations.value?.report({ type: 'run', data: { section: section?.section.value.id, block: props.block.id, result: fallback.value && recording ? `freeze:${recording.cacheKey}` : 'live' } })
|
|
180
|
-
}
|
|
181
|
-
const reset = async () => {
|
|
182
|
-
const node = props.block.node as CodeNode
|
|
183
|
-
if (!node.run?.session) return
|
|
184
|
-
stop()
|
|
185
|
-
await executor.value?.endSession?.(node.run.session)
|
|
186
|
-
show(undefined)
|
|
187
|
-
}
|
|
188
|
-
const replay = (data: Record<string, unknown>) => {
|
|
189
|
-
if (data.block !== props.block.id || (data.section !== undefined && data.section !== section?.section.value.id)) return
|
|
190
|
-
stop()
|
|
191
|
-
show(undefined)
|
|
192
|
-
}
|
|
193
|
-
watch(operations, (ops) => {
|
|
194
|
-
if (ops) followRuns(ops)
|
|
195
|
-
}, { immediate: true })
|
|
196
|
-
onMounted(() => replays.add(replay))
|
|
197
|
-
onBeforeUnmount(() => replays.delete(replay))
|
|
198
|
-
watch(() => (props.block.node as CodeNode).value, () => {
|
|
199
|
-
stop()
|
|
200
|
-
show(undefined)
|
|
201
|
-
})
|
|
202
|
-
|
|
203
|
-
return () => {
|
|
204
|
-
const node = props.block.node as CodeNode
|
|
205
|
-
const state = blockState(props.block, props.step)
|
|
206
|
-
const variants = node.variants ?? []
|
|
207
|
-
const shown = variants.length && !props.expanded ? Math.min(state, variants.length - 1) : undefined
|
|
208
|
-
const listings = variants.length === 0
|
|
209
|
-
? [h(CodeView, { lang: node.lang, value: node.value, highlight: props.expanded ? undefined : node.highlight?.[state] })]
|
|
210
|
-
: shown === undefined
|
|
211
|
-
? variants.map(v => h('div', { key: v.label, class: 'pm-code-block__variant' }, [h('p', { class: 'pm-code-block__label' }, v.label), h(CodeView, { lang: node.lang, value: v.value })]))
|
|
212
|
-
: [h(VariantView, { key: 'variant', lang: node.lang, value: variants[shown]!.value })]
|
|
213
|
-
const echo = node.echo !== false
|
|
214
|
-
const runnable = !owned && echo && node.run && node.run.when !== 'compile'
|
|
215
|
-
const t = messages().code
|
|
216
|
-
const available = mounted.value && executor.value
|
|
217
|
-
const controls = runnable
|
|
218
|
-
? h('div', { class: 'pm-code-block__run' }, [
|
|
219
|
-
h('button', { type: 'button', disabled: running.value || !available, onClick: run }, running.value ? t.running : live.value ? t.rerun : t.run),
|
|
220
|
-
node.run!.session ? h('button', { 'type': 'button', 'class': 'pm-code-block__reset', 'disabled': !available, 'data-session': node.run!.session, 'onClick': reset }, t.resetSession) : null,
|
|
221
|
-
mounted.value && !executor.value && report.value ? h('span', { class: 'pm-code-block__hint' }, t.unavailable) : null,
|
|
222
|
-
])
|
|
223
|
-
: null
|
|
224
|
-
const runs = owned ? [] : live.value ? [live.value] : node.outputs ?? []
|
|
225
|
-
const prose = !echo && !live.value && runs.length > 0 && runs.every(proseOnly)
|
|
226
|
-
const prefix = section?.section.value.id ?? props.block.id
|
|
227
|
-
const outputs = runs.length
|
|
228
|
-
? h('div', { 'class': ['pm-outputs', { 'pm-outputs--prose': prose }], 'data-source': live.value ? 'live' : 'recorded' }, runs.map((r, i) => runOutput(r, (r as RecordedRun).cacheKey || i, prefix, { prose, note: fallback.value })))
|
|
229
|
-
: null
|
|
230
|
-
return h('div', { 'class': ['pm-code-block', { 'pm-code-block--output-only': !echo }], 'data-state': props.expanded ? undefined : state, 'data-run': runnable ? node.run!.when : undefined, 'data-session': node.run?.session }, echo
|
|
231
|
-
? [originBar(node, shown), ...listings, controls, outputs]
|
|
232
|
-
: [outputs])
|
|
233
|
-
}
|
|
234
|
-
},
|
|
235
|
-
})
|
package/src/context.ts
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import type { IRSection } from '@lincyaw/kernel'
|
|
2
|
-
import type { InjectionKey, Ref } from 'vue'
|
|
3
|
-
import { inject } from 'vue'
|
|
4
|
-
|
|
5
|
-
export interface SectionContext {
|
|
6
|
-
section: Readonly<Ref<IRSection>>
|
|
7
|
-
step: Readonly<Ref<number>>
|
|
8
|
-
view: Readonly<Ref<string>>
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
export const SECTION_CONTEXT: InjectionKey<SectionContext> = Symbol('presmium.viewer.section')
|
|
12
|
-
export const IN_COMPONENT: InjectionKey<boolean> = Symbol('presmium.viewer.inComponent')
|
|
13
|
-
|
|
14
|
-
export function useSectionContext(): SectionContext | undefined {
|
|
15
|
-
return inject(SECTION_CONTEXT, undefined)
|
|
16
|
-
}
|
package/src/dark.ts
DELETED
package/src/domain/follow.ts
DELETED
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
import { stepTrail, trailStep } from '@lincyaw/kernel'
|
|
2
|
-
import type { IRSection, StepKeys } from '@lincyaw/kernel'
|
|
3
|
-
|
|
4
|
-
export { stepKeys, stepTrail, trailStep } from '@lincyaw/kernel'
|
|
5
|
-
export type { StepKeys } from '@lincyaw/kernel'
|
|
6
|
-
|
|
7
|
-
export interface FollowAnchor {
|
|
8
|
-
section?: string
|
|
9
|
-
trail?: string[]
|
|
10
|
-
back?: string
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
const LEARNERS = 'student'
|
|
14
|
-
|
|
15
|
-
export function backSection(sections: readonly Pick<IRSection, 'id' | 'audience'>[], id: string): string | undefined {
|
|
16
|
-
const at = sections.findIndex(section => section.id === id)
|
|
17
|
-
const audience = sections[at]?.audience
|
|
18
|
-
if (!audience?.length) return undefined
|
|
19
|
-
const learners = !audience.includes(LEARNERS)
|
|
20
|
-
return sections.slice(0, at).findLast(section => !section.audience?.length || (learners && section.audience.includes(LEARNERS)))?.id
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
export function followedPlace(position: FollowAnchor & { step: number }, keysOf: (id: string) => StepKeys | undefined): { section: string, step: number } | undefined {
|
|
24
|
-
const { section, trail, back, step } = position
|
|
25
|
-
const keys = section === undefined ? undefined : keysOf(section)
|
|
26
|
-
if (keys) {
|
|
27
|
-
const other = trail !== undefined && stepTrail(keys, step).join('\n') !== trail.join('\n')
|
|
28
|
-
return { section: section!, step: other ? trailStep(keys, trail) : step }
|
|
29
|
-
}
|
|
30
|
-
const before = back === undefined ? undefined : keysOf(back)
|
|
31
|
-
return before && { section: back!, step: before.length - 1 }
|
|
32
|
-
}
|
package/src/globals.ts
DELETED
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
import type { IRSection } from '@lincyaw/kernel'
|
|
2
|
-
import type { App, Component, ComponentOptions } from 'vue'
|
|
3
|
-
import { computed, getCurrentInstance, inject, reactive } from 'vue'
|
|
4
|
-
import { SECTION_CONTEXT } from './context.ts'
|
|
5
|
-
import type { SectionContext } from './context.ts'
|
|
6
|
-
import { VIEWER } from './viewer.ts'
|
|
7
|
-
import type { Viewer } from './viewer.ts'
|
|
8
|
-
|
|
9
|
-
function section() {
|
|
10
|
-
return getCurrentInstance() ? inject(SECTION_CONTEXT, undefined) : undefined
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export function installSlideGlobals(app: App, viewer: Viewer): void {
|
|
14
|
-
const props = app.config.globalProperties as Record<string, unknown>
|
|
15
|
-
const index = computed(() => viewer.section(viewer.position.value.section)?.index ?? 1)
|
|
16
|
-
const go = (n: number) => {
|
|
17
|
-
const target = viewer.doc.value.sections[n - 1]
|
|
18
|
-
if (target) viewer.show({ section: target.id, step: 0 })
|
|
19
|
-
}
|
|
20
|
-
const nav = reactive({
|
|
21
|
-
currentPage: index,
|
|
22
|
-
currentSlideNo: index,
|
|
23
|
-
clicks: computed(() => viewer.position.value.step),
|
|
24
|
-
total: computed(() => viewer.doc.value.sections.length),
|
|
25
|
-
go,
|
|
26
|
-
next: () => viewer.next(),
|
|
27
|
-
prev: () => viewer.prev(),
|
|
28
|
-
nextSlide: () => go(index.value + 1),
|
|
29
|
-
prevSlide: () => go(index.value - 1),
|
|
30
|
-
})
|
|
31
|
-
const configs = computed(() => ({ ...viewer.doc.value.meta, presmium: viewer.doc.value.config.presmium }))
|
|
32
|
-
const define = (name: string, get: () => unknown) => {
|
|
33
|
-
const existing = Object.getOwnPropertyDescriptor(props, name)
|
|
34
|
-
if (existing && !existing.configurable) return
|
|
35
|
-
Object.defineProperty(props, name, { configurable: true, enumerable: true, get })
|
|
36
|
-
}
|
|
37
|
-
define('$page', () => section()?.section.value.index ?? index.value)
|
|
38
|
-
define('$clicks', () => section()?.step.value ?? viewer.position.value.step)
|
|
39
|
-
define('$nav', () => nav)
|
|
40
|
-
define('$slidev', () => ({ configs: configs.value, themeConfigs: {}, nav }))
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
export function sectionFrontmatter(section: IRSection, renderer: string): Record<string, unknown> {
|
|
44
|
-
return { title: section.title, ...section.hints[renderer] }
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
export function withSlideGlobals(component: Component): Component {
|
|
48
|
-
if (typeof component === 'function') return component
|
|
49
|
-
const options = component as ComponentOptions
|
|
50
|
-
const inject = Array.isArray(options.inject) ? Object.fromEntries(options.inject.map(key => [key, key])) : options.inject
|
|
51
|
-
return {
|
|
52
|
-
...options,
|
|
53
|
-
inject: {
|
|
54
|
-
...inject,
|
|
55
|
-
pmSection: { from: SECTION_CONTEXT, default: undefined },
|
|
56
|
-
pmViewer: { from: VIEWER, default: undefined },
|
|
57
|
-
},
|
|
58
|
-
computed: {
|
|
59
|
-
...options.computed,
|
|
60
|
-
$frontmatter(): Record<string, unknown> | undefined {
|
|
61
|
-
const { pmSection, pmViewer } = this as unknown as { pmSection?: SectionContext, pmViewer?: Viewer }
|
|
62
|
-
return pmSection && sectionFrontmatter(pmSection.section.value, pmViewer?.options.renderer ?? 'web')
|
|
63
|
-
},
|
|
64
|
-
},
|
|
65
|
-
} as ComponentOptions
|
|
66
|
-
}
|
package/src/i18n.ts
DELETED
package/src/index.ts
DELETED
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
import type { App } from 'vue'
|
|
2
|
-
import { installClicks } from './clicks.ts'
|
|
3
|
-
import { installSlideGlobals } from './globals.ts'
|
|
4
|
-
import { messages } from './i18n.ts'
|
|
5
|
-
import { BUILTIN_ACTIONS, PresenterView, PresentView } from './present.ts'
|
|
6
|
-
import { registerAction, registerView } from './registry.ts'
|
|
7
|
-
import { provideViewer } from './viewer.ts'
|
|
8
|
-
import type { Viewer } from './viewer.ts'
|
|
9
|
-
import { DocumentView, ScrollyView } from './views.ts'
|
|
10
|
-
import './style.css'
|
|
11
|
-
|
|
12
|
-
registerView({ id: 'document', get label() { return messages().views.document }, kind: 'page', component: DocumentView })
|
|
13
|
-
registerView({ id: 'scrolly', get label() { return messages().views.scrolly }, kind: 'page', component: ScrollyView })
|
|
14
|
-
registerView({ id: 'present', get label() { return messages().views.present }, kind: 'overlay', component: PresentView })
|
|
15
|
-
registerView({ id: 'presenter', get label() { return messages().views.presenter }, kind: 'overlay', component: PresenterView, hidden: true })
|
|
16
|
-
BUILTIN_ACTIONS.forEach(registerAction)
|
|
17
|
-
|
|
18
|
-
export function installViewer(app: App, viewer: Viewer): void {
|
|
19
|
-
provideViewer(app, viewer)
|
|
20
|
-
installClicks(app)
|
|
21
|
-
installSlideGlobals(app, viewer)
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export { BlockView, PmComponentFallback } from './block.ts'
|
|
25
|
-
export { CodeView } from './code.ts'
|
|
26
|
-
export { SECTION_CONTEXT, useSectionContext } from './context.ts'
|
|
27
|
-
export type { SectionContext } from './context.ts'
|
|
28
|
-
export * from './domain/index.ts'
|
|
29
|
-
export { sectionFrontmatter, withSlideGlobals } from './globals.ts'
|
|
30
|
-
export { messages } from './i18n.ts'
|
|
31
|
-
export { MarkdownView } from './markdown.ts'
|
|
32
|
-
export { followOperations } from './operations.ts'
|
|
33
|
-
export { installViewerPlugin } from './plugins.ts'
|
|
34
|
-
export type { ViewerPlugin, ViewerPluginContext } from './plugins.ts'
|
|
35
|
-
export { BUILTIN_ACTIONS, PresenterView, PresentView } from './present.ts'
|
|
36
|
-
export {
|
|
37
|
-
getComponent,
|
|
38
|
-
getNodeRenderer,
|
|
39
|
-
getView,
|
|
40
|
-
listActions,
|
|
41
|
-
listLayers,
|
|
42
|
-
listViews,
|
|
43
|
-
registerAction,
|
|
44
|
-
registerComponent,
|
|
45
|
-
registerLayer,
|
|
46
|
-
registerNodeRenderer,
|
|
47
|
-
registerView,
|
|
48
|
-
} from './registry.ts'
|
|
49
|
-
export type { NodeRenderer, ViewDefinition, ViewerAction, ViewerLayer } from './registry.ts'
|
|
50
|
-
export { PmMath, PmMermaid, PmRoleMark } from './rich.ts'
|
|
51
|
-
export { SectionView, STEP_LINE } from './section.ts'
|
|
52
|
-
export type { SectionLayout } from './section.ts'
|
|
53
|
-
export { createViewer, useViewer, VIEWER } from './viewer.ts'
|
|
54
|
-
export type { Viewer, ViewerOptions } from './viewer.ts'
|
|
55
|
-
export { DocumentView, OverlayHost, ScrollyView, ViewHost } from './views.ts'
|
package/src/operations.ts
DELETED
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import type { Operations } from '@lincyaw/host'
|
|
2
|
-
import { watch } from 'vue'
|
|
3
|
-
import { getView } from './registry.ts'
|
|
4
|
-
import type { Viewer } from './viewer.ts'
|
|
5
|
-
|
|
6
|
-
export function followOperations(viewer: Viewer, operations: Operations): () => void {
|
|
7
|
-
const stop = watch(
|
|
8
|
-
() => ({ section: viewer.position.value.section, step: viewer.position.value.step, view: viewer.view.value }),
|
|
9
|
-
(now, before) => {
|
|
10
|
-
if (before && now.section === before.section && now.step === before.step && now.view === before.view) return
|
|
11
|
-
operations.report({ type: 'go', data: { ...now } })
|
|
12
|
-
},
|
|
13
|
-
{ flush: 'sync' },
|
|
14
|
-
)
|
|
15
|
-
const off = operations.onReplay('go', {
|
|
16
|
-
apply(data) {
|
|
17
|
-
const view = typeof data.view === 'string' ? getView(data.view) : undefined
|
|
18
|
-
if (view && !view.hidden) viewer.setView(view.id)
|
|
19
|
-
if (typeof data.section !== 'string') return
|
|
20
|
-
const step = Number(data.step)
|
|
21
|
-
viewer.show({ section: data.section, step: Number.isFinite(step) && step >= 0 ? step : 0 })
|
|
22
|
-
},
|
|
23
|
-
})
|
|
24
|
-
return () => {
|
|
25
|
-
stop()
|
|
26
|
-
off()
|
|
27
|
-
}
|
|
28
|
-
}
|