@dxos/plugin-presenter 0.8.4-main.28f8d3d → 0.8.4-main.2c6827d

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 (90) hide show
  1. package/dist/lib/browser/{CollectionPresenterContainer-OUCNLVND.mjs → CollectionPresenterContainer-4JFW3EKV.mjs} +33 -25
  2. package/dist/lib/browser/CollectionPresenterContainer-4JFW3EKV.mjs.map +7 -0
  3. package/dist/lib/browser/{DocumentPresenterContainer-THZU5S4O.mjs → DocumentPresenterContainer-SX32NAEH.mjs} +51 -53
  4. package/dist/lib/browser/DocumentPresenterContainer-SX32NAEH.mjs.map +7 -0
  5. package/dist/lib/browser/{MarkdownSlide-KG7ESCSU.mjs → MarkdownSlide-MEXR54L5.mjs} +18 -131
  6. package/dist/lib/browser/MarkdownSlide-MEXR54L5.mjs.map +7 -0
  7. package/dist/lib/browser/app-graph-builder-UJEKUKAP.mjs +106 -0
  8. package/dist/lib/browser/app-graph-builder-UJEKUKAP.mjs.map +7 -0
  9. package/dist/lib/browser/{chunk-UVGTHJUO.mjs → chunk-BJWK5GQV.mjs} +6 -4
  10. package/dist/lib/browser/chunk-BJWK5GQV.mjs.map +7 -0
  11. package/dist/lib/browser/{chunk-RDCZJT62.mjs → chunk-Q3H4KEFB.mjs} +15 -11
  12. package/dist/lib/browser/chunk-Q3H4KEFB.mjs.map +7 -0
  13. package/dist/lib/browser/chunk-TMTUZQCK.mjs +18 -0
  14. package/dist/lib/browser/chunk-TMTUZQCK.mjs.map +7 -0
  15. package/dist/lib/browser/{chunk-W4IR3DJE.mjs → chunk-VRRPVTKA.mjs} +7 -7
  16. package/dist/lib/browser/chunk-VRRPVTKA.mjs.map +7 -0
  17. package/dist/lib/browser/index.mjs +7 -8
  18. package/dist/lib/browser/index.mjs.map +2 -2
  19. package/dist/lib/browser/meta.json +1 -1
  20. package/dist/lib/browser/{react-surface-H3L7Y3ED.mjs → react-surface-S4T6X72R.mjs} +16 -16
  21. package/dist/lib/browser/react-surface-S4T6X72R.mjs.map +7 -0
  22. package/dist/lib/browser/{settings-VQVVDAGY.mjs → settings-57TUVRW3.mjs} +5 -5
  23. package/dist/lib/browser/{settings-VQVVDAGY.mjs.map → settings-57TUVRW3.mjs.map} +1 -1
  24. package/dist/types/src/PresenterPlugin.d.ts +1 -1
  25. package/dist/types/src/PresenterPlugin.d.ts.map +1 -1
  26. package/dist/types/src/capabilities/app-graph-builder.d.ts +1 -1
  27. package/dist/types/src/capabilities/app-graph-builder.d.ts.map +1 -1
  28. package/dist/types/src/capabilities/index.d.ts +3 -3
  29. package/dist/types/src/capabilities/index.d.ts.map +1 -1
  30. package/dist/types/src/capabilities/react-surface.d.ts +1 -1
  31. package/dist/types/src/capabilities/react-surface.d.ts.map +1 -1
  32. package/dist/types/src/capabilities/settings.d.ts +1 -1
  33. package/dist/types/src/components/CollectionPresenterContainer.d.ts +2 -2
  34. package/dist/types/src/components/CollectionPresenterContainer.d.ts.map +1 -1
  35. package/dist/types/src/components/Markdown/Container.stories.d.ts +14 -22
  36. package/dist/types/src/components/Markdown/Container.stories.d.ts.map +1 -1
  37. package/dist/types/src/components/Markdown/Slide.d.ts +1 -3
  38. package/dist/types/src/components/Markdown/Slide.d.ts.map +1 -1
  39. package/dist/types/src/components/Markdown/Slide.stories.d.ts +11 -12
  40. package/dist/types/src/components/Markdown/Slide.stories.d.ts.map +1 -1
  41. package/dist/types/src/components/Presenter/Pager.d.ts +1 -1
  42. package/dist/types/src/components/Presenter/Pager.d.ts.map +1 -1
  43. package/dist/types/src/components/Presenter/Pager.stories.d.ts +12 -4
  44. package/dist/types/src/components/Presenter/Pager.stories.d.ts.map +1 -1
  45. package/dist/types/src/components/PresenterSettings.d.ts.map +1 -1
  46. package/dist/types/src/components/RevealPlayer/RevealPlayer.d.ts.map +1 -1
  47. package/dist/types/src/components/RevealPlayer/RevealPlayer.stories.d.ts +18 -2
  48. package/dist/types/src/components/RevealPlayer/RevealPlayer.stories.d.ts.map +1 -1
  49. package/dist/types/src/components/index.d.ts +20 -3
  50. package/dist/types/src/components/index.d.ts.map +1 -1
  51. package/dist/types/src/meta.d.ts +0 -1
  52. package/dist/types/src/meta.d.ts.map +1 -1
  53. package/dist/types/src/translations.d.ts +1 -0
  54. package/dist/types/src/translations.d.ts.map +1 -1
  55. package/dist/types/src/types.d.ts +7 -6
  56. package/dist/types/src/types.d.ts.map +1 -1
  57. package/dist/types/src/useExitPresenter.d.ts.map +1 -1
  58. package/dist/types/tsconfig.tsbuildinfo +1 -1
  59. package/package.json +37 -36
  60. package/src/PresenterPlugin.tsx +22 -23
  61. package/src/capabilities/app-graph-builder.ts +48 -13
  62. package/src/capabilities/react-surface.tsx +23 -13
  63. package/src/components/CollectionPresenterContainer.tsx +3 -3
  64. package/src/components/Markdown/Container.stories.tsx +19 -19
  65. package/src/components/Markdown/Container.tsx +1 -1
  66. package/src/components/Markdown/Slide.stories.tsx +9 -6
  67. package/src/components/Markdown/Slide.tsx +12 -128
  68. package/src/components/Markdown/styles.css +104 -0
  69. package/src/components/Markdown/theme.ts +2 -2
  70. package/src/components/Markdown/typings.d.ts +8 -0
  71. package/src/components/Presenter/Pager.stories.tsx +8 -8
  72. package/src/components/Presenter/Pager.tsx +53 -18
  73. package/src/components/PresenterSettings.tsx +15 -11
  74. package/src/components/RevealPlayer/RevealPlayer.stories.tsx +5 -4
  75. package/src/components/RevealPlayer/RevealPlayer.tsx +61 -57
  76. package/src/meta.ts +7 -4
  77. package/src/translations.ts +1 -0
  78. package/src/types.ts +5 -5
  79. package/src/useExitPresenter.ts +5 -3
  80. package/dist/lib/browser/CollectionPresenterContainer-OUCNLVND.mjs.map +0 -7
  81. package/dist/lib/browser/DocumentPresenterContainer-THZU5S4O.mjs.map +0 -7
  82. package/dist/lib/browser/MarkdownSlide-KG7ESCSU.mjs.map +0 -7
  83. package/dist/lib/browser/app-graph-builder-GXESSA7Q.mjs +0 -77
  84. package/dist/lib/browser/app-graph-builder-GXESSA7Q.mjs.map +0 -7
  85. package/dist/lib/browser/chunk-RDCZJT62.mjs.map +0 -7
  86. package/dist/lib/browser/chunk-UVGTHJUO.mjs.map +0 -7
  87. package/dist/lib/browser/chunk-VSD5LSE5.mjs +0 -15
  88. package/dist/lib/browser/chunk-VSD5LSE5.mjs.map +0 -7
  89. package/dist/lib/browser/chunk-W4IR3DJE.mjs.map +0 -7
  90. package/dist/lib/browser/react-surface-H3L7Y3ED.mjs.map +0 -7
@@ -0,0 +1,104 @@
1
+ /*!
2
+ Theme: GitHub Dark
3
+ Description: Dark theme as seen on github.com
4
+ Author: github.com
5
+ Maintainer: @Hirse
6
+ Updated: 2021-05-15
7
+ Outdated base version: https://github.com/primer/github-syntax-dark
8
+ Current colors taken from GitHub's CSS
9
+ */
10
+ /* TODO(burdon): Use tokens. */
11
+ .dark pre code.hljs {
12
+ display: block;
13
+ overflow-x: auto;
14
+ padding: 1em;
15
+ }
16
+ .dark code.hljs {
17
+ padding: 3px 5px;
18
+ }
19
+ .dark .hljs {
20
+ color: #c9d1d9;
21
+ background: #0d1117;
22
+ }
23
+ .dark .hljs-doctag,
24
+ .dark .hljs-keyword,
25
+ .dark .hljs-meta .hljs-keyword,
26
+ .dark .hljs-template-tag,
27
+ .dark .hljs-template-variable,
28
+ .dark .hljs-type,
29
+ .dark .hljs-variable.language_ {
30
+ color: #ff7b72;
31
+ }
32
+ .dark .hljs-title,
33
+ .dark .hljs-title.class_,
34
+ .dark .hljs-title.class_.inherited__,
35
+ .dark .hljs-title.function_ {
36
+ color: #d2a8ff;
37
+ }
38
+ .dark .hljs-attr,
39
+ .dark .hljs-attribute,
40
+ .dark .hljs-literal,
41
+ .dark .hljs-meta,
42
+ .dark .hljs-number,
43
+ .dark .hljs-operator,
44
+ .dark .hljs-variable,
45
+ .dark .hljs-selector-attr,
46
+ .dark .hljs-selector-class,
47
+ .dark .hljs-selector-id {
48
+ color: #79c0ff;
49
+ }
50
+ .dark .hljs-regexp,
51
+ .dark .hljs-string,
52
+ .dark .hljs-meta .hljs-string {
53
+ color: #a5d6ff;
54
+ }
55
+ .dark .hljs-built_in,
56
+ .dark .hljs-symbol {
57
+ color: #ffa657;
58
+ }
59
+ .dark .hljs-comment,
60
+ .dark .hljs-code,
61
+ .dark .hljs-formula {
62
+ color: #8b949e;
63
+ }
64
+ .dark .hljs-name,
65
+ .dark .hljs-quote,
66
+ .dark .hljs-selector-tag,
67
+ .dark .hljs-selector-pseudo {
68
+ color: #7ee787;
69
+ }
70
+ .dark .hljs-subst {
71
+ color: #c9d1d9;
72
+ }
73
+ .dark .hljs-section {
74
+ color: #1f6feb;
75
+ font-weight: bold;
76
+ }
77
+ .dark .hljs-bullet {
78
+ color: #f2cc60;
79
+ }
80
+ .dark .hljs-emphasis {
81
+ color: #c9d1d9;
82
+ font-style: italic;
83
+ }
84
+ .dark .hljs-strong {
85
+ color: #c9d1d9;
86
+ font-weight: bold;
87
+ }
88
+ .dark .hljs-addition {
89
+ color: #aff5b4;
90
+ background-color: #033a16;
91
+ }
92
+ .dark .hljs-deletion {
93
+ color: #ffdcd7;
94
+ background-color: #67060c;
95
+ }
96
+ .dark .hljs-char.escape_,
97
+ .dark .hljs-link,
98
+ .dark .hljs-params,
99
+ .dark .hljs-property,
100
+ .dark .hljs-punctuation,
101
+ .dark .hljs-tag {
102
+ /* purposely ignored */
103
+ all: unset;
104
+ }
@@ -7,7 +7,7 @@
7
7
  export const theme = {
8
8
  root: 'bg-attention leading-relaxed font-mono',
9
9
 
10
- padding: 'px-40 py-16 gap-8',
10
+ padding: 'pli-40 plb-16 gap-8',
11
11
 
12
12
  nodes: {
13
13
  h1: 'text-[80px] text-accentText',
@@ -20,7 +20,7 @@ export const theme = {
20
20
  ol: 'my-[16px] ml-24 leading-relaxed list-decimal',
21
21
  li: 'pl-6 text-[48px]',
22
22
 
23
- pre: 'w-full mx-0 my-[32px] p-0 __border-l-[16px] bg-inputSurface p-4 __whitespace-pre-line',
23
+ pre: 'is-full mx-0 my-[32px] p-0 __border-l-[16px] bg-inputSurface p-4 __whitespace-pre-line',
24
24
  code: 'p-0 text-[40px]',
25
25
  },
26
26
  };
@@ -0,0 +1,8 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ declare module '*.css?raw' {
6
+ const content: string;
7
+ export default content;
8
+ }
@@ -2,12 +2,10 @@
2
2
  // Copyright 2023 DXOS.org
3
3
  //
4
4
 
5
- import '@dxos-theme';
6
-
7
- import { type Meta } from '@storybook/react-vite';
5
+ import { type Meta, type StoryObj } from '@storybook/react-vite';
8
6
  import React, { useState } from 'react';
9
7
 
10
- import { withTheme } from '@dxos/storybook-utils';
8
+ import { withTheme } from '@dxos/react-ui/testing';
11
9
 
12
10
  import { PageNumber, Pager, type PagerProps, StartButton } from './Pager';
13
11
 
@@ -24,15 +22,17 @@ const DefaultStory = ({ count = 20 }: PagerProps) => {
24
22
  );
25
23
  };
26
24
 
27
- export const Default = {};
28
-
29
- const meta: Meta<PagerProps> = {
25
+ const meta = {
30
26
  title: 'plugins/plugin-presenter/Pager',
31
27
  render: DefaultStory,
32
28
  decorators: [withTheme],
33
29
  parameters: {
34
30
  layout: 'centered',
35
31
  },
36
- };
32
+ } satisfies Meta<typeof DefaultStory>;
37
33
 
38
34
  export default meta;
35
+
36
+ type Story = StoryObj<typeof meta>;
37
+
38
+ export const Default: Story = {};
@@ -4,7 +4,7 @@
4
4
 
5
5
  import React, { useEffect } from 'react';
6
6
 
7
- import { Button, Icon, useControlledState } from '@dxos/react-ui';
7
+ import { IconButton, useControlledState } from '@dxos/react-ui';
8
8
 
9
9
  export type PagerProps = {
10
10
  index?: number;
@@ -14,8 +14,8 @@ export type PagerProps = {
14
14
  onExit?: () => void;
15
15
  };
16
16
 
17
- export const Pager = ({ index: controlledIndex = 0, count = 0, keys, onChange, onExit }: PagerProps) => {
18
- const [index, setIndex] = useControlledState(controlledIndex);
17
+ export const Pager = ({ index: indexParam = 0, count = 0, keys, onChange, onExit }: PagerProps) => {
18
+ const [index, setIndex] = useControlledState(indexParam);
19
19
  useEffect(() => {
20
20
  onChange?.(index);
21
21
  }, [index]);
@@ -76,18 +76,46 @@ export const Pager = ({ index: controlledIndex = 0, count = 0, keys, onChange, o
76
76
 
77
77
  return (
78
78
  <div className='flex items-center text-neutral-500'>
79
- <Button variant='ghost' classNames='p-0' onClick={() => onChange?.(0)}>
80
- <Icon icon='ph--caret-double-left--regular' size={6} />
81
- </Button>
82
- <Button variant='ghost' classNames='p-0' onClick={() => handleChangeIndex(-1)}>
83
- <Icon icon='ph--caret-left--regular' size={6} />
84
- </Button>
85
- <Button variant='ghost' classNames='p-0' onClick={() => handleChangeIndex(1)}>
86
- <Icon icon='ph--caret-right--regular' size={6} />
87
- </Button>
88
- <Button variant='ghost' classNames='p-0' onClick={() => onChange?.(count - 1)}>
89
- <Icon icon='ph--caret-double-right--regular' size={6} />
90
- </Button>
79
+ <IconButton
80
+ icon='ph--caret-double-left--regular'
81
+ size={6}
82
+ label='Jump to first'
83
+ iconOnly
84
+ noTooltip
85
+ variant='ghost'
86
+ classNames='p-0'
87
+ onClick={() => onChange?.(0)}
88
+ />
89
+ <IconButton
90
+ icon='ph--caret-left--regular'
91
+ size={6}
92
+ label='Previous'
93
+ iconOnly
94
+ noTooltip
95
+ variant='ghost'
96
+ classNames='p-0'
97
+ onClick={() => handleChangeIndex(-1)}
98
+ />
99
+ <IconButton
100
+ icon='ph--caret-right--regular'
101
+ size={6}
102
+ label='Next'
103
+ iconOnly
104
+ noTooltip
105
+ variant='ghost'
106
+ classNames='p-0'
107
+ onClick={() => handleChangeIndex(1)}
108
+ />
109
+ <IconButton
110
+ icon='ph--caret-double-right--regular'
111
+ size={6}
112
+ label='Jump to last'
113
+ iconOnly
114
+ noTooltip
115
+ variant='ghost'
116
+ classNames='p-0'
117
+ onClick={() => onChange?.(count - 1)}
118
+ />
91
119
  </div>
92
120
  );
93
121
  };
@@ -113,8 +141,15 @@ export const PageNumber = ({ index = 0, count = 1 }: PageNumberProps) => {
113
141
 
114
142
  export const StartButton = ({ running, onClick }: { running?: boolean; onClick?: (start: boolean) => void }) => {
115
143
  return (
116
- <Button variant='ghost' classNames='p-0' onClick={() => onClick?.(!running)}>
117
- {(running && <Icon icon='ph--x--regular' size={6} />) || <Icon icon='ph--play--regular' size={6} />}
118
- </Button>
144
+ <IconButton
145
+ icon={running ? 'ph--x--regular' : 'ph--play--regular'}
146
+ size={6}
147
+ label={running ? 'Stop' : 'Play'}
148
+ iconOnly
149
+ noTooltip
150
+ variant='ghost'
151
+ classNames='p-0'
152
+ onClick={() => onClick?.(!running)}
153
+ />
119
154
  );
120
155
  };
@@ -5,22 +5,26 @@
5
5
  import React from 'react';
6
6
 
7
7
  import { Input, useTranslation } from '@dxos/react-ui';
8
- import { DeprecatedFormContainer, DeprecatedFormInput } from '@dxos/react-ui-form';
8
+ import { ControlGroup, ControlItemInput, ControlPage, ControlSection } from '@dxos/react-ui-form';
9
9
 
10
- import { PRESENTER_PLUGIN } from '../meta';
10
+ import { meta } from '../meta';
11
11
  import { type PresenterSettingsProps } from '../types';
12
12
 
13
13
  export const PresenterSettings = ({ settings }: { settings: PresenterSettingsProps }) => {
14
- const { t } = useTranslation(PRESENTER_PLUGIN);
14
+ const { t } = useTranslation(meta.id);
15
15
 
16
16
  return (
17
- <DeprecatedFormContainer>
18
- <DeprecatedFormInput label={t('present collections label')}>
19
- <Input.Switch
20
- checked={settings.presentCollections}
21
- onCheckedChange={(checked) => (settings.presentCollections = !!checked)}
22
- />
23
- </DeprecatedFormInput>
24
- </DeprecatedFormContainer>
17
+ <ControlPage>
18
+ <ControlSection title={t('settings title', { ns: meta.id })}>
19
+ <ControlGroup>
20
+ <ControlItemInput title={t('present collections label')}>
21
+ <Input.Switch
22
+ checked={settings.presentCollections}
23
+ onCheckedChange={(checked) => (settings.presentCollections = !!checked)}
24
+ />
25
+ </ControlItemInput>
26
+ </ControlGroup>
27
+ </ControlSection>
28
+ </ControlPage>
25
29
  );
26
30
  };
@@ -2,10 +2,10 @@
2
2
  // Copyright 2023 DXOS.org
3
3
  //
4
4
 
5
- import '@dxos-theme';
6
-
7
5
  import { type Meta } from '@storybook/react-vite';
8
6
 
7
+ import { withTheme } from '@dxos/react-ui/testing';
8
+
9
9
  import CONTENT from '../../../testing/deck.md?raw';
10
10
  import { translations } from '../../translations';
11
11
 
@@ -19,14 +19,15 @@ import { RevealPlayer } from './RevealPlayer';
19
19
  // https://fontsource.org/fonts
20
20
  // https://fonts.google.com
21
21
 
22
- const meta: Meta<typeof RevealPlayer> = {
22
+ const meta = {
23
23
  title: 'plugins/plugin-presenter/RevealPlayer',
24
24
  component: RevealPlayer,
25
+ decorators: [withTheme],
25
26
  parameters: {
26
27
  layout: 'fullscreen',
27
28
  translations,
28
29
  },
29
- };
30
+ } satisfies Meta<typeof RevealPlayer>;
30
31
 
31
32
  export default meta;
32
33
 
@@ -2,9 +2,8 @@
2
2
  // Copyright 2024 DXOS.org
3
3
  //
4
4
 
5
- // eslint-disable-next-line no-restricted-imports
6
5
  import 'reveal.js/dist/reveal.css';
7
- // eslint-disable-next-line no-restricted-imports
6
+
8
7
  import 'reveal.js/dist/theme/black.css';
9
8
 
10
9
  // https://github.com/highlightjs/highlight.js/tree/main/src/styles
@@ -13,12 +12,12 @@ import 'highlight.js/styles/tokyo-night-dark.css';
13
12
 
14
13
  import hljs from 'highlight.js';
15
14
  import typescript from 'highlight.js/lib/languages/typescript';
16
- import React, { useEffect, useRef } from 'react';
15
+ import React, { useRef } from 'react';
17
16
  import Reveal from 'reveal.js';
18
17
  import RevealHighlight from 'reveal.js/plugin/highlight/highlight';
19
18
  import RevealMarkdown from 'reveal.js/plugin/markdown/plugin.js';
20
19
 
21
- import { type ThemedClassName } from '@dxos/react-ui';
20
+ import { type ThemedClassName, useAsyncEffect } from '@dxos/react-ui';
22
21
  import { mx } from '@dxos/react-ui-theme';
23
22
 
24
23
  const styles = `
@@ -72,7 +71,8 @@ export type RevealProps = ThemedClassName<{
72
71
  export const RevealPlayer = ({ classNames, content, slide, fullscreen = true, onExit }: RevealProps) => {
73
72
  const deckDivRef = useRef<HTMLDivElement>(null);
74
73
  const deckRef = useRef<Reveal.Api | null>(null);
75
- useEffect(() => {
74
+
75
+ useAsyncEffect(async () => {
76
76
  if (deckRef.current) {
77
77
  return;
78
78
  }
@@ -80,76 +80,80 @@ export const RevealPlayer = ({ classNames, content, slide, fullscreen = true, on
80
80
  // Required for syntax highlighting.
81
81
  hljs.registerLanguage('typescript', typescript);
82
82
 
83
- const t = setTimeout(async () => {
84
- // https://revealjs.com/react
85
- // https://revealjs.com/config
86
- // https://github.com/hakimel/reveal.js
87
- // TODO(burdon): Fragments and scroll view steps 2 at a time (safe mode?)
88
- deckRef.current = new Reveal(deckDivRef.current!, {
89
- // view: 'scroll',
90
- progress: false,
91
- transition: 'none',
92
- slideNumber: false,
93
- embedded: true,
94
-
95
- // TODO(burdon): Speaker view requires server to serve popout window.
96
- // https://revealjs.com/speaker-view
97
- showNotes: false,
98
-
99
- // width: 1600,
100
- // height: 900,
101
- margin: 0.1,
102
- // center: false,
103
- // minScale: 0.1,
104
- // maxScale: 1.4,
105
-
106
- // https://revealjs.com/markdown
107
- // TODO(burdon): Requires server to serve popout window.
108
- plugins: [RevealMarkdown, RevealHighlight],
109
-
110
- // See https://marked.js.org/using_advanced#options
111
- markdown: {
112
- gfm: true,
113
- smartypants: true,
114
- highlight: (code, language) => {
115
- if (language) {
116
- return hljs.highlight(code, { language }).value;
117
- }
118
-
119
- return hljs.highlightAuto(code).value;
120
- },
83
+ // https://revealjs.com/react
84
+ // https://revealjs.com/config
85
+ // https://github.com/hakimel/reveal.js
86
+ // TODO(burdon): Fragments and scroll view steps 2 at a time (safe mode?)
87
+ deckRef.current = new Reveal(deckDivRef.current!, {
88
+ // view: 'scroll',
89
+ progress: false,
90
+ transition: 'none',
91
+ slideNumber: false,
92
+ embedded: true,
93
+
94
+ // TODO(burdon): Speaker view requires server to serve popout window.
95
+ // https://revealjs.com/speaker-view
96
+ showNotes: false,
97
+
98
+ // width: 1600,
99
+ // height: 900,
100
+ margin: 0.1,
101
+ // center: false,
102
+ // minScale: 0.1,
103
+ // maxScale: 1.4,
104
+
105
+ // https://revealjs.com/markdown
106
+ // TODO(burdon): Requires server to serve popout window.
107
+ plugins: [RevealMarkdown, RevealHighlight],
108
+
109
+ // See https://marked.js.org/using_advanced#options
110
+ markdown: {
111
+ gfm: true,
112
+ smartypants: true,
113
+ highlight: (code, language) => {
114
+ if (language) {
115
+ return hljs.highlight(code, { language }).value;
116
+ }
117
+
118
+ return hljs.highlightAuto(code).value;
121
119
  },
122
- });
120
+ },
121
+ });
123
122
 
124
- await deckRef.current.initialize();
123
+ await deckRef.current.initialize();
125
124
 
126
- if (slide !== undefined) {
127
- deckRef.current.slide(slide < 0 ? deckRef.current?.getTotalSlides() + slide : slide - 1);
128
- }
125
+ if (slide !== undefined) {
126
+ deckRef.current.slide(slide < 0 ? deckRef.current?.getTotalSlides() + slide : slide - 1);
127
+ }
129
128
 
130
- deckRef.current.addKeyBinding({ keyCode: 27, key: 'Escape', description: 'Exit full screen' }, () => {
131
- onExit?.();
132
- });
129
+ deckRef.current.addKeyBinding({ keyCode: 27, key: 'Escape', description: 'Exit full screen' }, () => {
130
+ onExit?.();
133
131
  });
134
132
 
135
133
  return () => {
136
134
  try {
137
- clearTimeout(t);
138
135
  if (deckRef.current) {
139
136
  deckRef.current.destroy();
140
137
  deckRef.current = null;
141
138
  }
142
- } catch (err) {
139
+ } catch {
143
140
  // Ignore.
144
141
  }
145
142
  };
146
143
  });
147
144
 
145
+ // TOOD(burdon): Trap cursor keys (otherwise tabster grabs focus.)
148
146
  return (
149
- <div className={mx('absolute flex h-full w-full items-center justify-center', fullscreen && 'inset-0', classNames)}>
150
- <div className='relative aspect-video w-full'>
151
- <div ref={deckDivRef} className='reveal'>
152
- {/* TODO(burdon): Must be in head. */}
147
+ <div
148
+ className={mx(
149
+ 'grid place-items-center is-full bs-full overflow-hidden bg-black',
150
+ fullscreen && 'absolute inset-0',
151
+ classNames,
152
+ )}
153
+ >
154
+ <div className='relative aspect-video is-full bs-full bs-auto max-bs-full overflow-hidden'>
155
+ <div ref={deckDivRef} className='absolute inset-0 reveal'>
156
+ {/* NOTE: Must be in head. */}
153
157
  <style>
154
158
  <link rel='preconnect' href='https://fonts.googleapis.com' />
155
159
  <link rel='preconnect' href='https://fonts.gstatic.com' {...{ crossOrigin: '' }} />
package/src/meta.ts CHANGED
@@ -3,13 +3,16 @@
3
3
  //
4
4
 
5
5
  import { type PluginMeta } from '@dxos/app-framework';
6
-
7
- export const PRESENTER_PLUGIN = 'dxos.org/plugin/presenter';
6
+ import { trim } from '@dxos/util';
8
7
 
9
8
  export const meta: PluginMeta = {
10
- id: PRESENTER_PLUGIN,
9
+ id: 'dxos.org/plugin/presenter',
11
10
  name: 'Presenter',
12
- description: 'Present documents as slideshows.',
11
+ description: trim`
12
+ Transform markdown documents into interactive presentation slideshows.
13
+ Navigate between slides with keyboard controls and present content in full-screen mode.
14
+ `,
13
15
  icon: 'ph--presentation--regular',
16
+ iconHue: 'indigo',
14
17
  source: 'https://github.com/dxos/dxos/tree/main/packages/plugins/plugin-presenter',
15
18
  };
@@ -11,6 +11,7 @@ export const translations = [
11
11
  'en-US': {
12
12
  [meta.id]: {
13
13
  'plugin name': 'Presenter',
14
+ 'settings title': 'Presenter settings',
14
15
  'toggle presentation label': 'Present',
15
16
  'present collections label': 'Present collections (experimental)',
16
17
  },
package/src/types.ts CHANGED
@@ -2,22 +2,22 @@
2
2
  // Copyright 2023 DXOS.org
3
3
  //
4
4
 
5
- import { Schema } from 'effect';
5
+ import * as Schema from 'effect/Schema';
6
6
  import { type Context, createContext } from 'react';
7
7
 
8
8
  import { Markdown } from '@dxos/plugin-markdown/types';
9
- import { DataType } from '@dxos/schema';
9
+ import { Collection } from '@dxos/schema';
10
10
 
11
- import { PRESENTER_PLUGIN } from './meta';
11
+ import { meta } from './meta';
12
12
 
13
13
  export namespace PresenterAction {
14
- const PRESENTER_ACTION = `${PRESENTER_PLUGIN}/action`;
14
+ const PRESENTER_ACTION = `${meta.id}/action`;
15
15
 
16
16
  export class TogglePresentation extends Schema.TaggedClass<TogglePresentation>()(
17
17
  `${PRESENTER_ACTION}/toggle-presentation`,
18
18
  {
19
19
  input: Schema.Struct({
20
- object: Schema.Union(Markdown.Document, DataType.Collection),
20
+ object: Schema.Union(Markdown.Document, Collection.Collection),
21
21
  state: Schema.optional(Schema.Boolean),
22
22
  }),
23
23
  output: Schema.Void,
@@ -4,18 +4,20 @@
4
4
 
5
5
  import { useCallback } from 'react';
6
6
 
7
- import { LayoutAction, createIntent, useCapability, useIntentDispatcher } from '@dxos/app-framework';
7
+ import { LayoutAction, createIntent } from '@dxos/app-framework';
8
+ import { useCapability, useIntentDispatcher } from '@dxos/app-framework/react';
9
+ import { Obj } from '@dxos/echo';
8
10
  import { type Live } from '@dxos/live-object';
9
11
  import { DeckCapabilities } from '@dxos/plugin-deck';
10
12
  import { DeckAction } from '@dxos/plugin-deck/types';
11
- import { fullyQualifiedId, getSpace } from '@dxos/react-client/echo';
13
+ import { getSpace } from '@dxos/react-client/echo';
12
14
 
13
15
  export const useExitPresenter = (object: Live<any>) => {
14
16
  const { dispatchPromise: dispatch } = useIntentDispatcher();
15
17
  const layout = useCapability(DeckCapabilities.MutableDeckState);
16
18
 
17
19
  return useCallback(() => {
18
- const objectId = fullyQualifiedId(object);
20
+ const objectId = Obj.getDXN(object).toString();
19
21
  if (layout.deck.fullscreen) {
20
22
  void dispatch(
21
23
  createIntent(DeckAction.Adjust, {
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../../src/components/CollectionPresenterContainer.tsx", "../../../src/components/Presenter/Layout.tsx", "../../../src/components/Presenter/Pager.tsx"],
4
- "sourcesContent": ["//\n// Copyright 2023 DXOS.org\n//\n\nimport React, { type FC, useContext, useState } from 'react';\n\nimport { Surface } from '@dxos/app-framework';\nimport { StackItem } from '@dxos/react-ui-stack';\nimport { type DataType } from '@dxos/schema';\n\nimport { PresenterContext } from '../types';\nimport { useExitPresenter } from '../useExitPresenter';\n\nimport { Layout, PageNumber, Pager } from './Presenter';\n\nconst CollectionPresenterContainer: FC<{ collection: DataType.Collection }> = ({ collection }) => {\n const [slide, setSlide] = useState(0);\n\n const { running } = useContext(PresenterContext);\n\n const handleExit = useExitPresenter(collection);\n\n return (\n <StackItem.Content classNames='relative'>\n <Layout\n bottomRight={<PageNumber index={slide} count={collection.objects.length} />}\n bottomLeft={\n <Pager\n index={slide}\n count={collection.objects.length}\n keys={running}\n onChange={setSlide}\n onExit={handleExit}\n />\n }\n >\n {/* TODO(wittjosiah): Better slide placeholder. */}\n <Surface role='slide' data={{ subject: collection.objects[slide] }} placeholder={<></>} />\n </Layout>\n </StackItem.Content>\n );\n};\n\nexport default CollectionPresenterContainer;\n", "//\n// Copyright 2023 DXOS.org\n//\n\nimport React, { type PropsWithChildren, type ReactNode } from 'react';\n\nimport { type ThemedClassName } from '@dxos/react-ui';\nimport { mx } from '@dxos/react-ui-theme';\n\nexport type LayoutProps = ThemedClassName<\n PropsWithChildren<{\n className?: string;\n topLeft?: ReactNode;\n topRight?: ReactNode;\n bottomLeft?: ReactNode;\n bottomRight?: ReactNode;\n }>\n>;\n\nexport const Layout = ({ children, classNames, topLeft, topRight, bottomLeft, bottomRight }: LayoutProps) => {\n return (\n <div className={mx('flex grow relative overflow-hidden bg-attention', classNames)}>\n <div className={mx('flex flex-col grow overflow-hidden')}>{children}</div>\n\n <div className='z-[200]'>\n <div className='absolute top-4 left-4'>{topLeft}</div>\n <div className='absolute top-4 right-4'>{topRight}</div>\n <div className='absolute bottom-4 left-4'>{bottomLeft}</div>\n <div className='absolute bottom-4 right-4'>{bottomRight}</div>\n </div>\n </div>\n );\n};\n", "//\n// Copyright 2023 DXOS.org\n//\n\nimport React, { useEffect } from 'react';\n\nimport { Button, Icon, useControlledState } from '@dxos/react-ui';\n\nexport type PagerProps = {\n index?: number;\n count?: number;\n keys?: boolean; // TODO(burdon): Rename.\n onChange?: (index: number) => void;\n onExit?: () => void;\n};\n\nexport const Pager = ({ index: controlledIndex = 0, count = 0, keys, onChange, onExit }: PagerProps) => {\n const [index, setIndex] = useControlledState(controlledIndex);\n useEffect(() => {\n onChange?.(index);\n }, [index]);\n\n const handleChangeIndex = (dir: number) => {\n setIndex((index) => {\n const next = index + dir;\n return next >= 0 && next < count ? next : index;\n });\n };\n\n // TODO(burdon): Standardize via system key binding.\n useEffect(() => {\n if (!keys) {\n return;\n }\n\n const keydownHandler = (event: KeyboardEvent) => {\n switch (event.key) {\n case 'Escape': {\n onExit?.();\n break;\n }\n case 'ArrowLeft': {\n if (event.shiftKey) {\n onChange?.(0);\n } else {\n handleChangeIndex(-1);\n }\n break;\n }\n case 'ArrowRight': {\n if (event.shiftKey) {\n onChange?.(count - 1);\n } else {\n handleChangeIndex(1);\n }\n break;\n }\n case 'ArrowUp': {\n onChange?.(0);\n break;\n }\n case 'ArrowDown': {\n onChange?.(count - 1);\n break;\n }\n }\n };\n\n window.addEventListener('keydown', keydownHandler);\n return () => window.removeEventListener('keydown', keydownHandler);\n }, [keys, count]);\n\n if (index === undefined || !count) {\n return null;\n }\n\n return (\n <div className='flex items-center text-neutral-500'>\n <Button variant='ghost' classNames='p-0' onClick={() => onChange?.(0)}>\n <Icon icon='ph--caret-double-left--regular' size={6} />\n </Button>\n <Button variant='ghost' classNames='p-0' onClick={() => handleChangeIndex(-1)}>\n <Icon icon='ph--caret-left--regular' size={6} />\n </Button>\n <Button variant='ghost' classNames='p-0' onClick={() => handleChangeIndex(1)}>\n <Icon icon='ph--caret-right--regular' size={6} />\n </Button>\n <Button variant='ghost' classNames='p-0' onClick={() => onChange?.(count - 1)}>\n <Icon icon='ph--caret-double-right--regular' size={6} />\n </Button>\n </div>\n );\n};\n\nexport type PageNumberProps = {\n index?: number;\n count?: number;\n};\n\nexport const PageNumber = ({ index = 0, count = 1 }: PageNumberProps) => {\n if (index === undefined || !count) {\n return null;\n }\n\n return (\n <div className='flex items-center text-neutral-500 text-2xl'>\n <div>\n {index + 1} / {count}\n </div>\n </div>\n );\n};\n\nexport const StartButton = ({ running, onClick }: { running?: boolean; onClick?: (start: boolean) => void }) => {\n return (\n <Button variant='ghost' classNames='p-0' onClick={() => onClick?.(!running)}>\n {(running && <Icon icon='ph--x--regular' size={6} />) || <Icon icon='ph--play--regular' size={6} />}\n </Button>\n );\n};\n"],
5
- "mappings": "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",
6
- "names": ["React", "useContext", "useState", "Surface", "StackItem", "React", "mx", "Layout", "children", "classNames", "topLeft", "topRight", "bottomLeft", "bottomRight", "div", "className", "mx", "React", "useEffect", "Button", "Icon", "useControlledState", "Pager", "index", "controlledIndex", "count", "keys", "onChange", "onExit", "setIndex", "useControlledState", "useEffect", "handleChangeIndex", "dir", "next", "keydownHandler", "event", "key", "shiftKey", "window", "addEventListener", "removeEventListener", "undefined", "React", "div", "className", "Button", "variant", "classNames", "onClick", "Icon", "icon", "size", "PageNumber", "CollectionPresenterContainer", "collection", "slide", "setSlide", "useState", "running", "useContext", "PresenterContext", "handleExit", "useExitPresenter", "React", "StackItem", "Content", "classNames", "Layout", "bottomRight", "PageNumber", "index", "count", "objects", "length", "bottomLeft", "Pager", "keys", "onChange", "onExit", "Surface", "role", "data", "subject", "placeholder"]
7
- }
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../../src/components/DocumentPresenterContainer.tsx", "../../../src/components/RevealPlayer/RevealPlayer.tsx"],
4
- "sourcesContent": ["//\n// Copyright 2023 DXOS.org\n//\nimport React, { type FC } from 'react';\n\nimport { type Markdown } from '@dxos/plugin-markdown/types';\nimport { StackItem } from '@dxos/react-ui-stack';\n\nimport { useExitPresenter } from '../useExitPresenter';\n\nimport { RevealPlayer } from './RevealPlayer';\n\nconst DocumentPresenterContainer: FC<{ document: Markdown.Document }> = ({ document }) => {\n const handleExit = useExitPresenter(document);\n\n return (\n <StackItem.Content classNames='relative'>\n <RevealPlayer content={document.content.target?.content ?? ''} onExit={handleExit} />\n </StackItem.Content>\n );\n};\n\nexport default DocumentPresenterContainer;\n", "//\n// Copyright 2024 DXOS.org\n//\n\n// eslint-disable-next-line no-restricted-imports\nimport 'reveal.js/dist/reveal.css';\n// eslint-disable-next-line no-restricted-imports\nimport 'reveal.js/dist/theme/black.css';\n\n// https://github.com/highlightjs/highlight.js/tree/main/src/styles\n// import 'highlight.js/styles/github-dark.css';\nimport 'highlight.js/styles/tokyo-night-dark.css';\n\nimport hljs from 'highlight.js';\nimport typescript from 'highlight.js/lib/languages/typescript';\nimport React, { useEffect, useRef } from 'react';\nimport Reveal from 'reveal.js';\nimport RevealHighlight from 'reveal.js/plugin/highlight/highlight';\nimport RevealMarkdown from 'reveal.js/plugin/markdown/plugin.js';\n\nimport { type ThemedClassName } from '@dxos/react-ui';\nimport { mx } from '@dxos/react-ui-theme';\n\nconst styles = `\n<style type=\"text/css\">\n .reveal h1 {\n font-weight: 100;\n font-size: 60px;\n opacity: 0.5;\n }\n .reveal h2 {\n font-weight: 100;\n padding-top: 60px;\n padding-left: 40px;\n font-size: 48px;\n opacity: 0.3;\n }\n .reveal h1, h2, p {\n font-family: \"Raleway\", sans-serif;\n text-align: left;\n font-weight: 200;\n }\n .reveal ul {\n font-family: \"Raleway\", sans-serif;\n display: block;\n list-style: \"- \";\n }\n .reveal blockquote p {\n text-align: center;\n font-weight: 100;\n padding: 32px;\n }\n .reveal pre {\n margin-left: 0;\n }\n .reveal code {\n font-size: 20px;\n background: #111111;\n color: #eeeeee;\n max-height: unset !important;\n }\n</style>\n`;\n\nexport type RevealProps = ThemedClassName<{\n content: string;\n slide?: number;\n fullscreen?: boolean;\n onExit?: () => void;\n}>;\n\nexport const RevealPlayer = ({ classNames, content, slide, fullscreen = true, onExit }: RevealProps) => {\n const deckDivRef = useRef<HTMLDivElement>(null);\n const deckRef = useRef<Reveal.Api | null>(null);\n useEffect(() => {\n if (deckRef.current) {\n return;\n }\n\n // Required for syntax highlighting.\n hljs.registerLanguage('typescript', typescript);\n\n const t = setTimeout(async () => {\n // https://revealjs.com/react\n // https://revealjs.com/config\n // https://github.com/hakimel/reveal.js\n // TODO(burdon): Fragments and scroll view steps 2 at a time (safe mode?)\n deckRef.current = new Reveal(deckDivRef.current!, {\n // view: 'scroll',\n progress: false,\n transition: 'none',\n slideNumber: false,\n embedded: true,\n\n // TODO(burdon): Speaker view requires server to serve popout window.\n // https://revealjs.com/speaker-view\n showNotes: false,\n\n // width: 1600,\n // height: 900,\n margin: 0.1,\n // center: false,\n // minScale: 0.1,\n // maxScale: 1.4,\n\n // https://revealjs.com/markdown\n // TODO(burdon): Requires server to serve popout window.\n plugins: [RevealMarkdown, RevealHighlight],\n\n // See https://marked.js.org/using_advanced#options\n markdown: {\n gfm: true,\n smartypants: true,\n highlight: (code, language) => {\n if (language) {\n return hljs.highlight(code, { language }).value;\n }\n\n return hljs.highlightAuto(code).value;\n },\n },\n });\n\n await deckRef.current.initialize();\n\n if (slide !== undefined) {\n deckRef.current.slide(slide < 0 ? deckRef.current?.getTotalSlides() + slide : slide - 1);\n }\n\n deckRef.current.addKeyBinding({ keyCode: 27, key: 'Escape', description: 'Exit full screen' }, () => {\n onExit?.();\n });\n });\n\n return () => {\n try {\n clearTimeout(t);\n if (deckRef.current) {\n deckRef.current.destroy();\n deckRef.current = null;\n }\n } catch (err) {\n // Ignore.\n }\n };\n });\n\n return (\n <div className={mx('absolute flex h-full w-full items-center justify-center', fullscreen && 'inset-0', classNames)}>\n <div className='relative aspect-video w-full'>\n <div ref={deckDivRef} className='reveal'>\n {/* TODO(burdon): Must be in head. */}\n <style>\n <link rel='preconnect' href='https://fonts.googleapis.com' />\n <link rel='preconnect' href='https://fonts.gstatic.com' {...{ crossOrigin: '' }} />\n <link\n rel='stylesheet'\n href='https://fonts.googleapis.com/css2?family=Raleway:ital,wght@0,100..900;1,100..900&display=swap'\n />\n </style>\n <div className='slides'>\n <div className='!text-center' />\n <section {...{ 'data-markdown': [] }}>\n <textarea {...{ 'data-template': true }} defaultValue={[styles, content].join('\\n')}></textarea>\n </section>\n </div>\n </div>\n </div>\n </div>\n );\n};\n"],
5
- "mappings": "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",
6
- "names": ["React", "StackItem", "hljs", "typescript", "React", "useEffect", "useRef", "Reveal", "RevealHighlight", "RevealMarkdown", "mx", "styles", "RevealPlayer", "classNames", "content", "slide", "fullscreen", "onExit", "deckDivRef", "useRef", "deckRef", "useEffect", "current", "hljs", "registerLanguage", "typescript", "t", "setTimeout", "Reveal", "progress", "transition", "slideNumber", "embedded", "showNotes", "margin", "plugins", "RevealMarkdown", "RevealHighlight", "markdown", "gfm", "smartypants", "highlight", "code", "language", "value", "highlightAuto", "initialize", "undefined", "getTotalSlides", "addKeyBinding", "keyCode", "key", "description", "clearTimeout", "destroy", "err", "div", "className", "mx", "ref", "style", "link", "rel", "href", "crossOrigin", "section", "textarea", "defaultValue", "join", "DocumentPresenterContainer", "document", "handleExit", "useExitPresenter", "React", "StackItem", "Content", "classNames", "RevealPlayer", "content", "target", "onExit"]
7
- }