@dxos/plugin-presenter 0.9.0 → 0.9.1-staging.ee54ba693a
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/PLUGIN.mdl +12 -12
- package/dist/lib/neutral/{CollectionPresenterArticle-DFREOQTG.mjs → CollectionArticle-7R4KJWDW.mjs} +10 -9
- package/dist/lib/neutral/CollectionArticle-7R4KJWDW.mjs.map +7 -0
- package/dist/lib/neutral/DocumentArticle-YZRKVEN7.mjs +32 -0
- package/dist/lib/neutral/DocumentArticle-YZRKVEN7.mjs.map +7 -0
- package/dist/lib/neutral/PresenterPlugin.mjs +11 -4
- package/dist/lib/neutral/PresenterPlugin.mjs.map +4 -4
- package/dist/lib/neutral/SlideArticle-FE2I6KBO.mjs +20 -0
- package/dist/lib/neutral/SlideArticle-FE2I6KBO.mjs.map +7 -0
- package/dist/lib/neutral/{app-graph-builder-DIEDSRPX.mjs → app-graph-builder-FNDFY5L3.mjs} +8 -24
- package/dist/lib/neutral/app-graph-builder-FNDFY5L3.mjs.map +7 -0
- package/dist/lib/neutral/capabilities/index.mjs +7 -3
- package/dist/lib/neutral/capabilities/index.mjs.map +3 -3
- package/dist/lib/neutral/chunk-63IF7OXT.mjs +19 -0
- package/dist/lib/neutral/chunk-63IF7OXT.mjs.map +7 -0
- package/dist/lib/neutral/chunk-MSQDHOPV.mjs +47 -0
- package/dist/lib/neutral/chunk-MSQDHOPV.mjs.map +7 -0
- package/dist/lib/neutral/{chunk-VVALMI52.mjs → chunk-NDZ6IIAL.mjs} +8 -4
- package/dist/lib/neutral/chunk-NDZ6IIAL.mjs.map +7 -0
- package/dist/lib/neutral/components/index.mjs +90 -29
- package/dist/lib/neutral/components/index.mjs.map +4 -4
- package/dist/lib/neutral/containers/index.mjs +6 -6
- package/dist/lib/neutral/containers/index.mjs.map +3 -3
- package/dist/lib/neutral/index.mjs +2 -2
- package/dist/lib/neutral/markdown-extension-HGLRVZDF.mjs +37 -0
- package/dist/lib/neutral/markdown-extension-HGLRVZDF.mjs.map +7 -0
- package/dist/lib/neutral/meta.json +1 -1
- package/dist/lib/neutral/meta.mjs +1 -1
- package/dist/lib/neutral/operation-handler-3ZESW5AK.mjs +13 -0
- package/dist/lib/neutral/operation-handler-3ZESW5AK.mjs.map +7 -0
- package/dist/lib/neutral/operations/index.mjs +9 -0
- package/dist/lib/neutral/operations/index.mjs.map +7 -0
- package/dist/lib/neutral/plugin.mjs +1 -1
- package/dist/lib/neutral/react-surface-VO4GPCLQ.mjs +42 -0
- package/dist/lib/neutral/react-surface-VO4GPCLQ.mjs.map +7 -0
- package/dist/lib/neutral/{settings-R6LRDAAK.mjs → settings-DBV7N5HT.mjs} +3 -3
- package/dist/lib/neutral/{settings-R6LRDAAK.mjs.map → settings-DBV7N5HT.mjs.map} +3 -3
- package/dist/lib/neutral/toggle-presentation-PH7ZJJDD.mjs +60 -0
- package/dist/lib/neutral/toggle-presentation-PH7ZJJDD.mjs.map +7 -0
- package/dist/lib/neutral/translations.mjs +1 -2
- package/dist/lib/neutral/translations.mjs.map +3 -3
- package/dist/lib/neutral/types/index.mjs +1 -1
- package/dist/types/dx.config.d.ts +28 -0
- package/dist/types/dx.config.d.ts.map +1 -0
- package/dist/types/src/PresenterPlugin.d.ts.map +1 -1
- package/dist/types/src/capabilities/app-graph-builder.d.ts +1 -2
- package/dist/types/src/capabilities/app-graph-builder.d.ts.map +1 -1
- package/dist/types/src/capabilities/index.d.ts +6 -3
- package/dist/types/src/capabilities/index.d.ts.map +1 -1
- package/dist/types/src/capabilities/markdown-extension.d.ts +9 -0
- package/dist/types/src/capabilities/markdown-extension.d.ts.map +1 -0
- package/dist/types/src/capabilities/operation-handler.d.ts +6 -0
- package/dist/types/src/capabilities/operation-handler.d.ts.map +1 -0
- package/dist/types/src/capabilities/react-surface.d.ts +2 -2
- package/dist/types/src/capabilities/react-surface.d.ts.map +1 -1
- package/dist/types/src/capabilities/settings.d.ts +1 -3
- package/dist/types/src/capabilities/settings.d.ts.map +1 -1
- package/dist/types/src/components/Presenter/PresentationShell.d.ts +20 -0
- package/dist/types/src/components/Presenter/PresentationShell.d.ts.map +1 -0
- package/dist/types/src/components/Presenter/index.d.ts +1 -0
- package/dist/types/src/components/Presenter/index.d.ts.map +1 -1
- package/dist/types/src/components/RevealPlayer/RevealPlayer.d.ts.map +1 -1
- package/dist/types/src/components/RevealPlayer/RevealPlayer.stories.d.ts +0 -1
- package/dist/types/src/components/RevealPlayer/RevealPlayer.stories.d.ts.map +1 -1
- package/dist/types/src/components/index.d.ts +0 -2
- package/dist/types/src/components/index.d.ts.map +1 -1
- package/dist/types/src/containers/CollectionArticle/CollectionArticle.d.ts +6 -0
- package/dist/types/src/containers/CollectionArticle/CollectionArticle.d.ts.map +1 -0
- package/dist/types/src/containers/CollectionArticle/index.d.ts +2 -0
- package/dist/types/src/{components/PresenterSettings → containers/CollectionArticle}/index.d.ts.map +1 -1
- package/dist/types/src/containers/DocumentArticle/DocumentArticle.d.ts +6 -0
- package/dist/types/src/containers/DocumentArticle/DocumentArticle.d.ts.map +1 -0
- package/dist/types/src/containers/DocumentArticle/index.d.ts +2 -0
- package/dist/types/src/containers/DocumentArticle/index.d.ts.map +1 -0
- package/dist/types/src/containers/SlideArticle/SlideArticle.d.ts +6 -0
- package/dist/types/src/containers/SlideArticle/SlideArticle.d.ts.map +1 -0
- package/dist/types/src/containers/SlideArticle/index.d.ts +2 -0
- package/dist/types/src/containers/SlideArticle/index.d.ts.map +1 -0
- package/dist/types/src/containers/index.d.ts +3 -3
- package/dist/types/src/containers/index.d.ts.map +1 -1
- package/dist/types/src/meta.d.ts +32 -2
- package/dist/types/src/meta.d.ts.map +1 -1
- package/dist/types/src/operations/index.d.ts +3 -0
- package/dist/types/src/operations/index.d.ts.map +1 -0
- package/dist/types/src/operations/toggle-presentation.d.ts +10 -0
- package/dist/types/src/operations/toggle-presentation.d.ts.map +1 -0
- package/dist/types/src/paths.d.ts +3 -0
- package/dist/types/src/paths.d.ts.map +1 -0
- package/dist/types/src/translations.d.ts +0 -1
- package/dist/types/src/translations.d.ts.map +1 -1
- package/dist/types/src/types/PresenterCapabilities.d.ts.map +1 -1
- package/dist/types/src/types/PresenterOperation.d.ts +5 -13
- package/dist/types/src/types/PresenterOperation.d.ts.map +1 -1
- package/dist/types/src/useExitPresenter.d.ts +6 -1
- package/dist/types/src/useExitPresenter.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/dx.config.ts +37 -0
- package/package.json +39 -31
- package/src/PresenterPlugin.test.ts +1 -1
- package/src/PresenterPlugin.tsx +9 -2
- package/src/capabilities/app-graph-builder.ts +9 -24
- package/src/capabilities/index.ts +6 -0
- package/src/capabilities/markdown-extension.ts +45 -0
- package/src/capabilities/operation-handler.ts +16 -0
- package/src/capabilities/react-surface.tsx +14 -23
- package/src/capabilities/settings.ts +2 -2
- package/src/components/Markdown/Panel.stories.tsx +1 -1
- package/src/components/Presenter/PresentationShell.tsx +99 -0
- package/src/components/Presenter/index.ts +1 -0
- package/src/components/RevealPlayer/RevealPlayer.tsx +11 -12
- package/src/components/index.ts +0 -4
- package/src/containers/CollectionArticle/CollectionArticle.tsx +44 -0
- package/src/containers/CollectionArticle/index.ts +5 -0
- package/src/containers/DocumentArticle/DocumentArticle.tsx +34 -0
- package/src/containers/DocumentArticle/index.ts +5 -0
- package/src/containers/{MarkdownSlide/MarkdownSlide.tsx → SlideArticle/SlideArticle.tsx} +4 -5
- package/src/containers/SlideArticle/index.ts +5 -0
- package/src/containers/index.ts +3 -3
- package/src/meta.ts +2 -30
- package/src/operations/index.ts +7 -0
- package/src/operations/toggle-presentation.ts +59 -0
- package/src/paths.ts +8 -0
- package/src/translations.ts +1 -2
- package/src/types/PresenterCapabilities.ts +3 -1
- package/src/types/PresenterOperation.ts +4 -3
- package/src/useExitPresenter.ts +13 -26
- package/dist/lib/neutral/CollectionPresenterArticle-DFREOQTG.mjs.map +0 -7
- package/dist/lib/neutral/DocumentPresenterContainer-KCDZ2O2C.mjs +0 -24
- package/dist/lib/neutral/DocumentPresenterContainer-KCDZ2O2C.mjs.map +0 -7
- package/dist/lib/neutral/MarkdownSlide-WXILOIBE.mjs +0 -18
- package/dist/lib/neutral/MarkdownSlide-WXILOIBE.mjs.map +0 -7
- package/dist/lib/neutral/PresenterSettings-2G4XD4QY.mjs +0 -25
- package/dist/lib/neutral/PresenterSettings-2G4XD4QY.mjs.map +0 -7
- package/dist/lib/neutral/app-graph-builder-DIEDSRPX.mjs.map +0 -7
- package/dist/lib/neutral/chunk-PPL2FF6R.mjs +0 -38
- package/dist/lib/neutral/chunk-PPL2FF6R.mjs.map +0 -7
- package/dist/lib/neutral/chunk-V323QBC3.mjs +0 -41
- package/dist/lib/neutral/chunk-V323QBC3.mjs.map +0 -7
- package/dist/lib/neutral/chunk-VVALMI52.mjs.map +0 -7
- package/dist/lib/neutral/react-surface-SPJGAJIF.mjs +0 -54
- package/dist/lib/neutral/react-surface-SPJGAJIF.mjs.map +0 -7
- package/dist/types/src/components/PresenterSettings/PresenterSettings.d.ts +0 -6
- package/dist/types/src/components/PresenterSettings/PresenterSettings.d.ts.map +0 -1
- package/dist/types/src/components/PresenterSettings/PresenterSettings.stories.d.ts +0 -23
- package/dist/types/src/components/PresenterSettings/PresenterSettings.stories.d.ts.map +0 -1
- package/dist/types/src/components/PresenterSettings/index.d.ts +0 -2
- package/dist/types/src/containers/CollectionPresenterArticle/CollectionPresenterArticle.d.ts +0 -6
- package/dist/types/src/containers/CollectionPresenterArticle/CollectionPresenterArticle.d.ts.map +0 -1
- package/dist/types/src/containers/CollectionPresenterArticle/index.d.ts +0 -2
- package/dist/types/src/containers/CollectionPresenterArticle/index.d.ts.map +0 -1
- package/dist/types/src/containers/DocumentPresenterContainer/DocumentPresenterContainer.d.ts +0 -6
- package/dist/types/src/containers/DocumentPresenterContainer/DocumentPresenterContainer.d.ts.map +0 -1
- package/dist/types/src/containers/DocumentPresenterContainer/index.d.ts +0 -2
- package/dist/types/src/containers/DocumentPresenterContainer/index.d.ts.map +0 -1
- package/dist/types/src/containers/MarkdownSlide/MarkdownSlide.d.ts +0 -8
- package/dist/types/src/containers/MarkdownSlide/MarkdownSlide.d.ts.map +0 -1
- package/dist/types/src/containers/MarkdownSlide/index.d.ts +0 -2
- package/dist/types/src/containers/MarkdownSlide/index.d.ts.map +0 -1
- package/src/components/PresenterSettings/PresenterSettings.stories.tsx +0 -32
- package/src/components/PresenterSettings/PresenterSettings.tsx +0 -31
- package/src/components/PresenterSettings/index.ts +0 -5
- package/src/containers/CollectionPresenterArticle/CollectionPresenterArticle.tsx +0 -50
- package/src/containers/CollectionPresenterArticle/index.ts +0 -5
- package/src/containers/DocumentPresenterContainer/DocumentPresenterContainer.tsx +0 -24
- package/src/containers/DocumentPresenterContainer/index.ts +0 -5
- package/src/containers/MarkdownSlide/index.ts +0 -5
package/dx.config.ts
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2025 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { Config2 } from '@dxos/app-framework/config';
|
|
6
|
+
import { trim } from '@dxos/util';
|
|
7
|
+
|
|
8
|
+
export default Config2.make({
|
|
9
|
+
plugin: {
|
|
10
|
+
key: 'org.dxos.plugin.presenter',
|
|
11
|
+
name: 'Presenter',
|
|
12
|
+
author: 'DXOS',
|
|
13
|
+
description: trim`
|
|
14
|
+
Transform existing workspace objects into interactive presentation slideshows without
|
|
15
|
+
duplicating content. Markdown documents are split into slides on horizontal \`---\`
|
|
16
|
+
separators and rendered with Reveal.js, giving authors a familiar authoring surface
|
|
17
|
+
with full Markdown syntax. Collections can optionally be presented slide-by-slide,
|
|
18
|
+
with each member object rendered by its own plugin surface.
|
|
19
|
+
|
|
20
|
+
Activate presentation mode for any supported object via the action menu or the
|
|
21
|
+
Shift+Cmd+P (macOS) / Shift+Alt+P (Windows/Linux) keyboard shortcut. The presenter
|
|
22
|
+
opens in a solo fullscreen layout managed by the Deck plugin, keeping the rest of the
|
|
23
|
+
workspace undisturbed.
|
|
24
|
+
|
|
25
|
+
Navigation controls and a page-number indicator are shown during collection
|
|
26
|
+
slideshows. Pressing Escape exits fullscreen and returns to the originating document
|
|
27
|
+
or collection view. All navigation is keyboard-accessible.
|
|
28
|
+
|
|
29
|
+
Collaboration is inherent: because slides are backed by live ECHO objects, edits made
|
|
30
|
+
by any peer in the workspace are immediately reflected in an open presentation without
|
|
31
|
+
any manual refresh.
|
|
32
|
+
`,
|
|
33
|
+
source: 'https://github.com/dxos/dxos/tree/main/packages/plugins/plugin-presenter',
|
|
34
|
+
icon: { key: 'ph--presentation--regular', hue: 'indigo' },
|
|
35
|
+
spec: 'PLUGIN.mdl',
|
|
36
|
+
},
|
|
37
|
+
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dxos/plugin-presenter",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.1-staging.ee54ba693a",
|
|
4
4
|
"description": "Braneframe presenter plugin",
|
|
5
5
|
"homepage": "https://dxos.org",
|
|
6
6
|
"bugs": "https://github.com/dxos/dxos/issues",
|
|
@@ -33,6 +33,11 @@
|
|
|
33
33
|
"types": "./dist/types/src/meta.d.ts",
|
|
34
34
|
"default": "./dist/lib/neutral/meta.mjs"
|
|
35
35
|
},
|
|
36
|
+
"#operations": {
|
|
37
|
+
"source": "./src/operations/index.ts",
|
|
38
|
+
"types": "./dist/types/src/operations/index.d.ts",
|
|
39
|
+
"default": "./dist/lib/neutral/operations/index.mjs"
|
|
40
|
+
},
|
|
36
41
|
"#plugin": {
|
|
37
42
|
"source": {
|
|
38
43
|
"workerd": "./src/PresenterPlugin.workerd.ts",
|
|
@@ -77,10 +82,12 @@
|
|
|
77
82
|
"types": "dist/types/src/index.d.ts",
|
|
78
83
|
"files": [
|
|
79
84
|
"dist",
|
|
85
|
+
"dx.config.ts",
|
|
80
86
|
"src",
|
|
81
87
|
"PLUGIN.mdl"
|
|
82
88
|
],
|
|
83
89
|
"dependencies": {
|
|
90
|
+
"@codemirror/state": "^6.6.0",
|
|
84
91
|
"@effect-atom/atom-react": "^0.5.0",
|
|
85
92
|
"hastscript": "^7.1.0",
|
|
86
93
|
"highlight.js": "^11.9.0",
|
|
@@ -92,45 +99,46 @@
|
|
|
92
99
|
"remark-frontmatter": "^5.0.0",
|
|
93
100
|
"remark-parse-frontmatter": "^1.0.3",
|
|
94
101
|
"reveal.js": "^5.1.0",
|
|
95
|
-
"@dxos/app-framework": "0.9.
|
|
96
|
-
"@dxos/app-toolkit": "0.9.
|
|
97
|
-
"@dxos/
|
|
98
|
-
"@dxos/
|
|
99
|
-
"@dxos/
|
|
100
|
-
"@dxos/plugin-client": "0.9.
|
|
101
|
-
"@dxos/
|
|
102
|
-
"@dxos/plugin-
|
|
103
|
-
"@dxos/
|
|
104
|
-
"@dxos/
|
|
105
|
-
"@dxos/
|
|
106
|
-
"@dxos/
|
|
107
|
-
"@dxos/react-ui-
|
|
108
|
-
"@dxos/
|
|
102
|
+
"@dxos/app-framework": "0.9.1-staging.ee54ba693a",
|
|
103
|
+
"@dxos/app-toolkit": "0.9.1-staging.ee54ba693a",
|
|
104
|
+
"@dxos/keys": "0.9.1-staging.ee54ba693a",
|
|
105
|
+
"@dxos/log": "0.9.1-staging.ee54ba693a",
|
|
106
|
+
"@dxos/echo": "0.9.1-staging.ee54ba693a",
|
|
107
|
+
"@dxos/plugin-client": "0.9.1-staging.ee54ba693a",
|
|
108
|
+
"@dxos/plugin-deck": "0.9.1-staging.ee54ba693a",
|
|
109
|
+
"@dxos/plugin-graph": "0.9.1-staging.ee54ba693a",
|
|
110
|
+
"@dxos/compute": "0.9.1-staging.ee54ba693a",
|
|
111
|
+
"@dxos/plugin-markdown": "0.9.1-staging.ee54ba693a",
|
|
112
|
+
"@dxos/react-ui-attention": "0.9.1-staging.ee54ba693a",
|
|
113
|
+
"@dxos/ui-editor": "0.9.1-staging.ee54ba693a",
|
|
114
|
+
"@dxos/react-ui-form": "0.9.1-staging.ee54ba693a",
|
|
115
|
+
"@dxos/util": "0.9.1-staging.ee54ba693a",
|
|
116
|
+
"@dxos/effect": "0.9.1-staging.ee54ba693a"
|
|
109
117
|
},
|
|
110
118
|
"devDependencies": {
|
|
111
119
|
"@effect-atom/atom-react": "^0.5.0",
|
|
112
|
-
"@effect/platform": "0.96.
|
|
113
|
-
"@types/react": "~19.2.
|
|
120
|
+
"@effect/platform": "0.96.2",
|
|
121
|
+
"@types/react": "~19.2.17",
|
|
114
122
|
"@types/react-dom": "~19.2.3",
|
|
115
123
|
"@types/reveal.js": "^5.0.3",
|
|
116
|
-
"effect": "3.21.
|
|
117
|
-
"react": "~19.2.
|
|
118
|
-
"react-dom": "~19.2.
|
|
124
|
+
"effect": "3.21.4",
|
|
125
|
+
"react": "~19.2.7",
|
|
126
|
+
"react-dom": "~19.2.7",
|
|
119
127
|
"vite": "^8.0.16",
|
|
120
|
-
"@dxos/plugin-testing": "0.9.
|
|
121
|
-
"@dxos/
|
|
122
|
-
"@dxos/
|
|
123
|
-
"@dxos/
|
|
124
|
-
"@dxos/ui-theme": "0.9.
|
|
128
|
+
"@dxos/plugin-testing": "0.9.1-staging.ee54ba693a",
|
|
129
|
+
"@dxos/react-ui": "0.9.1-staging.ee54ba693a",
|
|
130
|
+
"@dxos/storybook-utils": "0.9.1-staging.ee54ba693a",
|
|
131
|
+
"@dxos/random": "0.9.1-staging.ee54ba693a",
|
|
132
|
+
"@dxos/ui-theme": "0.9.1-staging.ee54ba693a"
|
|
125
133
|
},
|
|
126
134
|
"peerDependencies": {
|
|
127
135
|
"@effect-atom/atom-react": "^0.5.0",
|
|
128
|
-
"@effect/platform": "0.96.
|
|
129
|
-
"effect": "3.21.
|
|
130
|
-
"react": "~19.2.
|
|
131
|
-
"react-dom": "~19.2.
|
|
132
|
-
"@dxos/react-ui": "0.9.
|
|
133
|
-
"@dxos/ui-theme": "0.9.
|
|
136
|
+
"@effect/platform": "0.96.2",
|
|
137
|
+
"effect": "3.21.4",
|
|
138
|
+
"react": "~19.2.7",
|
|
139
|
+
"react-dom": "~19.2.7",
|
|
140
|
+
"@dxos/react-ui": "0.9.1-staging.ee54ba693a",
|
|
141
|
+
"@dxos/ui-theme": "0.9.1-staging.ee54ba693a"
|
|
134
142
|
},
|
|
135
143
|
"publishConfig": {
|
|
136
144
|
"access": "public"
|
|
@@ -10,7 +10,7 @@ import { PresenterPlugin } from '#plugin';
|
|
|
10
10
|
|
|
11
11
|
import { meta } from './meta';
|
|
12
12
|
|
|
13
|
-
const moduleId = (name: string) => `${meta.
|
|
13
|
+
const moduleId = (name: string) => `${meta.profile.key}.module.${name}`;
|
|
14
14
|
|
|
15
15
|
describe('PresenterPlugin', () => {
|
|
16
16
|
test('modules activate on the expected events', async ({ expect }) => {
|
package/src/PresenterPlugin.tsx
CHANGED
|
@@ -4,8 +4,9 @@
|
|
|
4
4
|
|
|
5
5
|
import { Plugin } from '@dxos/app-framework';
|
|
6
6
|
import { AppPlugin } from '@dxos/app-toolkit';
|
|
7
|
+
import { MarkdownEvents } from '@dxos/plugin-markdown';
|
|
7
8
|
|
|
8
|
-
import { AppGraphBuilder, PresenterSettings, ReactSurface } from '#capabilities';
|
|
9
|
+
import { AppGraphBuilder, MarkdownExtension, OperationHandler, PresenterSettings, ReactSurface } from '#capabilities';
|
|
9
10
|
import { meta } from '#meta';
|
|
10
11
|
import { translations } from '#translations';
|
|
11
12
|
|
|
@@ -17,11 +18,17 @@ import pluginSpec from '../PLUGIN.mdl?raw';
|
|
|
17
18
|
|
|
18
19
|
export const PresenterPlugin = Plugin.define(meta).pipe(
|
|
19
20
|
AppPlugin.addAppGraphModule({ activate: AppGraphBuilder }),
|
|
21
|
+
AppPlugin.addOperationHandlerModule({ activate: OperationHandler }),
|
|
20
22
|
AppPlugin.addSettingsModule({ activate: PresenterSettings }),
|
|
21
23
|
AppPlugin.addSurfaceModule({ activate: ReactSurface }),
|
|
24
|
+
Plugin.addModule({
|
|
25
|
+
id: `${meta.profile.key}/markdown`,
|
|
26
|
+
activatesOn: MarkdownEvents.SetupExtensions,
|
|
27
|
+
activate: MarkdownExtension,
|
|
28
|
+
}),
|
|
22
29
|
AppPlugin.addTranslationsModule({ translations }),
|
|
23
30
|
AppPlugin.addPluginAssetModule({
|
|
24
|
-
asset: { pluginId: meta.
|
|
31
|
+
asset: { pluginId: meta.profile.key, path: 'PLUGIN.mdl', content: pluginSpec, mimeType: 'application/x-mdl' },
|
|
25
32
|
}),
|
|
26
33
|
Plugin.make,
|
|
27
34
|
);
|
|
@@ -2,14 +2,14 @@
|
|
|
2
2
|
// Copyright 2025 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
+
import { type Atom } from '@effect-atom/atom-react';
|
|
5
6
|
import * as Effect from 'effect/Effect';
|
|
6
7
|
import * as Option from 'effect/Option';
|
|
7
8
|
|
|
8
|
-
import {
|
|
9
|
-
import { AppCapabilities, AppNode
|
|
9
|
+
import { Capability } from '@dxos/app-framework';
|
|
10
|
+
import { AppCapabilities, AppNode } from '@dxos/app-toolkit';
|
|
10
11
|
import { Operation } from '@dxos/compute';
|
|
11
12
|
import { Collection, Obj } from '@dxos/echo';
|
|
12
|
-
import { DeckCapabilities, DeckOperation } from '@dxos/plugin-deck';
|
|
13
13
|
import { GraphBuilder, type Node, NodeMatcher } from '@dxos/plugin-graph';
|
|
14
14
|
import { Markdown } from '@dxos/plugin-markdown';
|
|
15
15
|
import { linkedSegment } from '@dxos/react-ui-attention';
|
|
@@ -19,9 +19,9 @@ import { PresenterOperation } from '#types';
|
|
|
19
19
|
import { PresenterCapabilities } from '#types';
|
|
20
20
|
|
|
21
21
|
/** Match nodes that can be presented (Collection or Document). */
|
|
22
|
-
const whenPresentable = (node: Node.Node) =>
|
|
23
|
-
Option.orElse(NodeMatcher.whenEchoType(Collection.Collection)(node), () =>
|
|
24
|
-
NodeMatcher.whenEchoType(Markdown.Document)(node),
|
|
22
|
+
const whenPresentable = (node: Node.Node, get: Atom.Context) =>
|
|
23
|
+
Option.orElse(NodeMatcher.whenEchoType(Collection.Collection)(node, get), () =>
|
|
24
|
+
NodeMatcher.whenEchoType(Markdown.Document)(node, get),
|
|
25
25
|
);
|
|
26
26
|
|
|
27
27
|
export default Capability.makeModule(
|
|
@@ -47,7 +47,7 @@ export default Capability.makeModule(
|
|
|
47
47
|
id: linkedSegment('presenter'),
|
|
48
48
|
label: 'Presenter',
|
|
49
49
|
icon: 'ph--presentation--regular',
|
|
50
|
-
data: { type: meta.
|
|
50
|
+
data: { type: meta.profile.key, object },
|
|
51
51
|
}),
|
|
52
52
|
]);
|
|
53
53
|
},
|
|
@@ -61,30 +61,15 @@ export default Capability.makeModule(
|
|
|
61
61
|
if (!isPresentable || !db) {
|
|
62
62
|
return Effect.succeed([]);
|
|
63
63
|
}
|
|
64
|
-
const objectPath = getObjectPathFromObject(object);
|
|
65
64
|
|
|
66
65
|
return Effect.succeed([
|
|
67
66
|
{
|
|
68
67
|
id: PresenterOperation.TogglePresentation.meta.key,
|
|
69
|
-
// TODO(burdon): Allow function so can generate state when activated.
|
|
70
|
-
// So can set explicit fullscreen state coordinated with current presenter state.
|
|
71
68
|
data: Effect.fnUntraced(function* () {
|
|
72
|
-
|
|
73
|
-
const deck = deckState.decks[deckState.activeDeck];
|
|
74
|
-
const presenterId = `${objectPath}/${linkedSegment('presenter')}`;
|
|
75
|
-
if (!deck?.fullscreen) {
|
|
76
|
-
yield* Operation.invoke(DeckOperation.Adjust, {
|
|
77
|
-
type: 'solo--fullscreen' as const,
|
|
78
|
-
id: presenterId,
|
|
79
|
-
});
|
|
80
|
-
}
|
|
81
|
-
yield* Operation.invoke(LayoutOperation.Open, {
|
|
82
|
-
subject: [presenterId],
|
|
83
|
-
workspace: getSpacePath(db.spaceId),
|
|
84
|
-
});
|
|
69
|
+
yield* Operation.invoke(PresenterOperation.TogglePresentation, { object });
|
|
85
70
|
}),
|
|
86
71
|
properties: {
|
|
87
|
-
label: ['toggle-presentation.label', { ns: meta.
|
|
72
|
+
label: ['toggle-presentation.label', { ns: meta.profile.key }],
|
|
88
73
|
icon: 'ph--presentation--regular',
|
|
89
74
|
disposition: 'list-item',
|
|
90
75
|
keyBinding: {
|
|
@@ -3,7 +3,13 @@
|
|
|
3
3
|
//
|
|
4
4
|
|
|
5
5
|
import { Capability } from '@dxos/app-framework';
|
|
6
|
+
import type { OperationHandlerSet } from '@dxos/compute';
|
|
6
7
|
|
|
7
8
|
export const AppGraphBuilder = Capability.lazy('AppGraphBuilder', () => import('./app-graph-builder'));
|
|
9
|
+
export const MarkdownExtension = Capability.lazy('MarkdownExtension', () => import('./markdown-extension'));
|
|
10
|
+
export const OperationHandler = Capability.lazy<OperationHandlerSet.OperationHandlerSet>(
|
|
11
|
+
'OperationHandler',
|
|
12
|
+
() => import('./operation-handler'),
|
|
13
|
+
);
|
|
8
14
|
export const ReactSurface = Capability.lazy('ReactSurface', () => import('./react-surface'));
|
|
9
15
|
export const PresenterSettings = Capability.lazy('PresenterSettings', () => import('./settings'));
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2025 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { Prec } from '@codemirror/state';
|
|
6
|
+
import * as Effect from 'effect/Effect';
|
|
7
|
+
|
|
8
|
+
import { Capabilities, Capability } from '@dxos/app-framework';
|
|
9
|
+
import { MarkdownCapabilities } from '@dxos/plugin-markdown/types';
|
|
10
|
+
import { keymap } from '@dxos/ui-editor';
|
|
11
|
+
|
|
12
|
+
import { PresenterOperation } from '#types';
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Contributes the present shortcut (Shift+Cmd+P) to the markdown editor so presentation
|
|
16
|
+
* can be toggled while editing without relying on the global navtree keyboard context.
|
|
17
|
+
*/
|
|
18
|
+
export default Capability.makeModule(
|
|
19
|
+
Effect.fnUntraced(function* () {
|
|
20
|
+
const capabilities = yield* Capability.Service;
|
|
21
|
+
|
|
22
|
+
return Capability.contributes(MarkdownCapabilities.ExtensionProvider, [
|
|
23
|
+
({ document }) => {
|
|
24
|
+
if (!document) {
|
|
25
|
+
return undefined;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const { invokePromise } = capabilities.get(Capabilities.OperationInvoker);
|
|
29
|
+
return Prec.highest(
|
|
30
|
+
keymap.of([
|
|
31
|
+
{
|
|
32
|
+
key: 'Shift-Mod-p',
|
|
33
|
+
preventDefault: true,
|
|
34
|
+
stopPropagation: true,
|
|
35
|
+
run: () => {
|
|
36
|
+
void invokePromise(PresenterOperation.TogglePresentation, { object: document });
|
|
37
|
+
return true;
|
|
38
|
+
},
|
|
39
|
+
},
|
|
40
|
+
]),
|
|
41
|
+
);
|
|
42
|
+
},
|
|
43
|
+
]);
|
|
44
|
+
}),
|
|
45
|
+
);
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2025 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import * as Effect from 'effect/Effect';
|
|
6
|
+
|
|
7
|
+
import { Capabilities, Capability } from '@dxos/app-framework';
|
|
8
|
+
import type { OperationHandlerSet } from '@dxos/compute';
|
|
9
|
+
|
|
10
|
+
import { PresenterOperationHandlerSet } from '#operations';
|
|
11
|
+
|
|
12
|
+
export default Capability.makeModule<OperationHandlerSet.OperationHandlerSet>(
|
|
13
|
+
Effect.fnUntraced(function* () {
|
|
14
|
+
return Capability.contributes(Capabilities.OperationHandler, PresenterOperationHandlerSet);
|
|
15
|
+
}),
|
|
16
|
+
);
|
|
@@ -6,61 +6,52 @@ import * as Effect from 'effect/Effect';
|
|
|
6
6
|
import React from 'react';
|
|
7
7
|
|
|
8
8
|
import { Capabilities, Capability } from '@dxos/app-framework';
|
|
9
|
-
import { Surface
|
|
9
|
+
import { Surface } from '@dxos/app-framework/ui';
|
|
10
10
|
import { AppSurface } from '@dxos/app-toolkit/ui';
|
|
11
11
|
import { Collection, Obj } from '@dxos/echo';
|
|
12
12
|
import { Markdown } from '@dxos/plugin-markdown';
|
|
13
|
+
import { Position } from '@dxos/util';
|
|
13
14
|
|
|
14
|
-
import {
|
|
15
|
-
import { CollectionPresenterArticle, DocumentPresenterContainer, MarkdownSlide } from '#containers';
|
|
15
|
+
import { CollectionArticle, DocumentArticle, SlideArticle } from '#containers';
|
|
16
16
|
import { meta } from '#meta';
|
|
17
|
-
import { type Settings } from '#types';
|
|
18
17
|
|
|
19
18
|
export default Capability.makeModule(() =>
|
|
20
19
|
Effect.succeed(
|
|
21
20
|
Capability.contributes(Capabilities.ReactSurface, [
|
|
22
21
|
Surface.create({
|
|
23
22
|
id: 'document',
|
|
24
|
-
position:
|
|
25
|
-
filter:
|
|
23
|
+
position: Position.first,
|
|
24
|
+
filter: Surface.makeFilter(
|
|
26
25
|
AppSurface.Article,
|
|
27
|
-
(data): data is AppSurface.ArticleData<{ type: typeof meta.
|
|
26
|
+
(data): data is AppSurface.ArticleData<{ type: typeof meta.profile.key; object: Markdown.Document }> =>
|
|
28
27
|
!!data.subject &&
|
|
29
28
|
typeof data.subject === 'object' &&
|
|
30
29
|
'type' in data.subject &&
|
|
31
30
|
'object' in data.subject &&
|
|
32
|
-
data.subject.type === meta.
|
|
31
|
+
data.subject.type === meta.profile.key &&
|
|
33
32
|
Obj.instanceOf(Markdown.Document, data.subject.object),
|
|
34
33
|
),
|
|
35
|
-
component: ({ data }) => <
|
|
34
|
+
component: ({ role, data }) => <DocumentArticle role={role} subject={data.subject.object} />,
|
|
36
35
|
}),
|
|
37
36
|
Surface.create({
|
|
38
37
|
id: 'collection',
|
|
39
|
-
position:
|
|
40
|
-
filter:
|
|
38
|
+
position: Position.first,
|
|
39
|
+
filter: Surface.makeFilter(
|
|
41
40
|
AppSurface.Article,
|
|
42
|
-
(data): data is AppSurface.ArticleData<{ type: typeof meta.
|
|
41
|
+
(data): data is AppSurface.ArticleData<{ type: typeof meta.profile.key; object: Collection.Collection }> =>
|
|
43
42
|
!!data.subject &&
|
|
44
43
|
typeof data.subject === 'object' &&
|
|
45
44
|
'type' in data.subject &&
|
|
46
45
|
'object' in data.subject &&
|
|
47
|
-
data.subject.type === meta.
|
|
46
|
+
data.subject.type === meta.profile.key &&
|
|
48
47
|
Obj.instanceOf(Collection.Collection, data.subject.object),
|
|
49
48
|
),
|
|
50
|
-
component: ({ role, data }) => <
|
|
49
|
+
component: ({ role, data }) => <CollectionArticle role={role} subject={data.subject.object} />,
|
|
51
50
|
}),
|
|
52
51
|
Surface.create({
|
|
53
52
|
id: 'slide',
|
|
54
53
|
filter: AppSurface.object(AppSurface.Slide, Markdown.Document),
|
|
55
|
-
component: ({ data }) => <
|
|
56
|
-
}),
|
|
57
|
-
Surface.create({
|
|
58
|
-
id: 'pluginSettings',
|
|
59
|
-
filter: AppSurface.settings(AppSurface.Article, meta.id),
|
|
60
|
-
component: ({ data: { subject } }) => {
|
|
61
|
-
const { settings, updateSettings } = useSettingsState<Settings.Settings>(subject.atom);
|
|
62
|
-
return <PresenterSettings settings={settings} onSettingsChange={updateSettings} />;
|
|
63
|
-
},
|
|
54
|
+
component: ({ data }) => <SlideArticle {...data} />,
|
|
64
55
|
}),
|
|
65
56
|
]),
|
|
66
57
|
),
|
|
@@ -14,7 +14,7 @@ import { PresenterCapabilities, Settings } from '#types';
|
|
|
14
14
|
export default Capability.makeModule(() =>
|
|
15
15
|
Effect.sync(() => {
|
|
16
16
|
const settingsAtom = createKvsStore({
|
|
17
|
-
key: meta.
|
|
17
|
+
key: meta.profile.key,
|
|
18
18
|
schema: Settings.Settings,
|
|
19
19
|
defaultValue: () => ({}),
|
|
20
20
|
});
|
|
@@ -22,7 +22,7 @@ export default Capability.makeModule(() =>
|
|
|
22
22
|
return [
|
|
23
23
|
Capability.contributes(PresenterCapabilities.Settings, settingsAtom),
|
|
24
24
|
Capability.contributes(AppCapabilities.Settings, {
|
|
25
|
-
prefix: meta.
|
|
25
|
+
prefix: meta.profile.key,
|
|
26
26
|
schema: Settings.Settings,
|
|
27
27
|
atom: settingsAtom,
|
|
28
28
|
}),
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2025 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import React, { type PropsWithChildren, useCallback, useEffect, useRef, useState } from 'react';
|
|
6
|
+
|
|
7
|
+
import { composable, composableProps } from '@dxos/react-ui';
|
|
8
|
+
import { mx } from '@dxos/ui-theme';
|
|
9
|
+
|
|
10
|
+
export type PresentationShellProps = PropsWithChildren<{
|
|
11
|
+
/** Fade-in/out duration (ms). */
|
|
12
|
+
fadeDuration?: number;
|
|
13
|
+
/** Duration the [ESC] hint remains visible (ms). */
|
|
14
|
+
hintDuration?: number;
|
|
15
|
+
/** Whether the presentation is fullscreen. */
|
|
16
|
+
fullscreen?: boolean;
|
|
17
|
+
/** Invoked once the exit fade-out has completed. */
|
|
18
|
+
onExit?: () => void;
|
|
19
|
+
}>;
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Wraps presentation content with a fade-in/out transition, an ESC handler that exits in a
|
|
23
|
+
* single keypress (intercepting before the deck's fullscreen handler), and a transient [ESC]
|
|
24
|
+
* caption shown on enter.
|
|
25
|
+
*/
|
|
26
|
+
export const PresentationShell = composable<HTMLDivElement, PresentationShellProps>(
|
|
27
|
+
({ children, fadeDuration = 300, hintDuration = 3000, fullscreen = true, onExit, ...props }, forwardedRef) => {
|
|
28
|
+
const [visible, setVisible] = useState(false);
|
|
29
|
+
const [exiting, setExiting] = useState(false);
|
|
30
|
+
const [showHint, setShowHint] = useState(true);
|
|
31
|
+
const exitTimeout = useRef<ReturnType<typeof setTimeout>>(undefined);
|
|
32
|
+
// Guards against exiting twice; a state updater can't gate this since React double-invokes
|
|
33
|
+
// updaters in dev, which would schedule the exit (and its side effects) more than once.
|
|
34
|
+
const exitingRef = useRef(false);
|
|
35
|
+
|
|
36
|
+
// Fade in once mounted.
|
|
37
|
+
useEffect(() => {
|
|
38
|
+
const frame = requestAnimationFrame(() => setVisible(true));
|
|
39
|
+
return () => cancelAnimationFrame(frame);
|
|
40
|
+
}, []);
|
|
41
|
+
|
|
42
|
+
// Hide the hint after the configured duration.
|
|
43
|
+
useEffect(() => {
|
|
44
|
+
const timer = setTimeout(() => setShowHint(false), hintDuration);
|
|
45
|
+
return () => clearTimeout(timer);
|
|
46
|
+
}, [hintDuration]);
|
|
47
|
+
|
|
48
|
+
const handleExit = useCallback(() => {
|
|
49
|
+
if (exitingRef.current) {
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
exitingRef.current = true;
|
|
53
|
+
setExiting(true);
|
|
54
|
+
setVisible(false);
|
|
55
|
+
exitTimeout.current = setTimeout(() => onExit?.(), fadeDuration);
|
|
56
|
+
}, [onExit, fadeDuration]);
|
|
57
|
+
|
|
58
|
+
useEffect(() => () => clearTimeout(exitTimeout.current), []);
|
|
59
|
+
|
|
60
|
+
// Capture ESC before the deck/reveal handlers so a single keypress exits directly.
|
|
61
|
+
useEffect(() => {
|
|
62
|
+
const handler = (event: KeyboardEvent) => {
|
|
63
|
+
if (event.key === 'Escape') {
|
|
64
|
+
event.preventDefault();
|
|
65
|
+
event.stopImmediatePropagation();
|
|
66
|
+
handleExit();
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
document.addEventListener('keydown', handler, { capture: true });
|
|
71
|
+
return () => document.removeEventListener('keydown', handler, { capture: true });
|
|
72
|
+
}, [handleExit]);
|
|
73
|
+
|
|
74
|
+
return (
|
|
75
|
+
<div
|
|
76
|
+
{...composableProps(props, {
|
|
77
|
+
classNames: [
|
|
78
|
+
'relative grow overflow-hidden bg-black transition-opacity',
|
|
79
|
+
visible && !exiting ? 'opacity-100' : 'opacity-0',
|
|
80
|
+
],
|
|
81
|
+
style: { transitionDuration: `${fadeDuration}ms` },
|
|
82
|
+
})}
|
|
83
|
+
ref={forwardedRef}
|
|
84
|
+
>
|
|
85
|
+
{children}
|
|
86
|
+
{fullscreen && (
|
|
87
|
+
<div
|
|
88
|
+
className={mx(
|
|
89
|
+
'absolute top-4 left-4 z-[300] transition-opacity duration-500',
|
|
90
|
+
showHint && !exiting ? 'opacity-100' : 'opacity-0',
|
|
91
|
+
)}
|
|
92
|
+
>
|
|
93
|
+
<span className='rounded-sm bg-white/10 px-2 py-1 font-mono text-sm text-white/70'>[ESC]</span>
|
|
94
|
+
</div>
|
|
95
|
+
)}
|
|
96
|
+
</div>
|
|
97
|
+
);
|
|
98
|
+
},
|
|
99
|
+
);
|
|
@@ -17,6 +17,7 @@ import RevealMarkdown from 'reveal.js/plugin/markdown/plugin.js';
|
|
|
17
17
|
|
|
18
18
|
import { useAsyncEffect } from '@dxos/react-ui';
|
|
19
19
|
import { composable, composableProps } from '@dxos/react-ui';
|
|
20
|
+
import { mx } from '@dxos/ui-theme';
|
|
20
21
|
|
|
21
22
|
const styles = `
|
|
22
23
|
<style type="text/css">
|
|
@@ -148,23 +149,21 @@ export const RevealPlayer = composable<HTMLDivElement, RevealProps>(
|
|
|
148
149
|
return (
|
|
149
150
|
<div
|
|
150
151
|
{...composableProps(props, {
|
|
151
|
-
classNames: ['dx-container grid place-items-center bg-
|
|
152
|
+
classNames: ['dx-container grid place-items-center bg-scrim-surface', fullscreen && 'absolute inset-0'],
|
|
152
153
|
})}
|
|
153
154
|
ref={forwardedRef}
|
|
154
155
|
>
|
|
155
156
|
<div className='relative aspect-video h-full w-full h-auto max-h-full overflow-hidden'>
|
|
156
157
|
<div ref={deckDivRef} className='absolute inset-0 reveal'>
|
|
157
|
-
{/*
|
|
158
|
-
<
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
<div className='slides'>
|
|
167
|
-
<div className='text-center!' />
|
|
158
|
+
{/* React hoists these to <head>; they must not be wrapped in <style> (which only renders CSS text). */}
|
|
159
|
+
<link rel='preconnect' href='https://fonts.gstatic.com' {...{ crossOrigin: '' }} />
|
|
160
|
+
<link rel='preconnect' href='https://fonts.googleapis.com' />
|
|
161
|
+
<link
|
|
162
|
+
rel='stylesheet'
|
|
163
|
+
href='https://fonts.googleapis.com/css2?family=Raleway:ital,wght@0,100..900;1,100..900&display=swap'
|
|
164
|
+
/>
|
|
165
|
+
<div className={mx('slides', !fullscreen && 'bg-base-surface p-8')}>
|
|
166
|
+
<div />
|
|
168
167
|
<section {...{ 'data-markdown': [] }}>
|
|
169
168
|
<textarea {...{ 'data-template': true }} defaultValue={[styles, content].join('\n')}></textarea>
|
|
170
169
|
</section>
|
package/src/components/index.ts
CHANGED
|
@@ -2,10 +2,6 @@
|
|
|
2
2
|
// Copyright 2023 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import { type ComponentType, lazy } from 'react';
|
|
6
|
-
|
|
7
5
|
export * from './Markdown';
|
|
8
6
|
export * from './Presenter';
|
|
9
7
|
export * from './RevealPlayer';
|
|
10
|
-
|
|
11
|
-
export const PresenterSettings: ComponentType<any> = lazy(() => import('./PresenterSettings'));
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2023 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import React, { useContext, useState } from 'react';
|
|
6
|
+
|
|
7
|
+
import { Surface } from '@dxos/app-framework/ui';
|
|
8
|
+
import { AppSurface } from '@dxos/app-toolkit/ui';
|
|
9
|
+
import { type Collection, Obj } from '@dxos/echo';
|
|
10
|
+
import { Panel } from '@dxos/react-ui';
|
|
11
|
+
|
|
12
|
+
import { PageNumber, Pager, PresentationShell, Layout as PresenterLayout } from '#components';
|
|
13
|
+
import { PresenterContext } from '#types';
|
|
14
|
+
|
|
15
|
+
import { useExitPresenter } from '../../useExitPresenter';
|
|
16
|
+
|
|
17
|
+
export type CollectionArticleProps = AppSurface.ObjectArticleProps<Collection.Collection>;
|
|
18
|
+
|
|
19
|
+
export const CollectionArticle = ({ role, subject: collection }: CollectionArticleProps) => {
|
|
20
|
+
const [slide, setSlide] = useState(0);
|
|
21
|
+
const { running } = useContext(PresenterContext);
|
|
22
|
+
const handleExit = useExitPresenter(collection);
|
|
23
|
+
|
|
24
|
+
return (
|
|
25
|
+
<Panel.Root role={role} classNames='relative'>
|
|
26
|
+
<Panel.Content asChild>
|
|
27
|
+
<PresentationShell onExit={handleExit}>
|
|
28
|
+
<PresenterLayout
|
|
29
|
+
bottomRight={<PageNumber index={slide} count={collection.objects.length} />}
|
|
30
|
+
bottomLeft={<Pager index={slide} count={collection.objects.length} keys={running} onChange={setSlide} />}
|
|
31
|
+
>
|
|
32
|
+
<Surface.Surface
|
|
33
|
+
type={AppSurface.Slide}
|
|
34
|
+
data={{
|
|
35
|
+
subject: collection.objects[slide],
|
|
36
|
+
attendableId: Obj.getURI(collection),
|
|
37
|
+
}}
|
|
38
|
+
/>
|
|
39
|
+
</PresenterLayout>
|
|
40
|
+
</PresentationShell>
|
|
41
|
+
</Panel.Content>
|
|
42
|
+
</Panel.Root>
|
|
43
|
+
);
|
|
44
|
+
};
|