@netless/app-slide 0.2.39 → 0.2.40
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/LICENSE +21 -0
- package/README-zh.md +53 -53
- package/README.md +68 -68
- package/dist/index.d.ts +294 -294
- package/dist/main.cjs.js +4 -4
- package/dist/main.cjs.js.map +1 -1
- package/dist/main.es.js +6 -6
- package/dist/main.es.js.map +1 -1
- package/dist/main.iife.js +4 -4
- package/dist/main.iife.js.map +1 -1
- package/package.json +9 -9
- package/src/DocsViewer/icons/arrow-left.svg +4 -4
- package/src/DocsViewer/icons/arrow-left.ts +18 -18
- package/src/DocsViewer/icons/arrow-right.svg +4 -4
- package/src/DocsViewer/icons/arrow-right.ts +18 -18
- package/src/DocsViewer/icons/pause.svg +4 -4
- package/src/DocsViewer/icons/pause.ts +18 -18
- package/src/DocsViewer/icons/play.svg +4 -4
- package/src/DocsViewer/icons/play.ts +18 -18
- package/src/DocsViewer/icons/sidebar.svg +4 -4
- package/src/DocsViewer/icons/sidebar.ts +18 -18
- package/src/DocsViewer/index.ts +381 -381
- package/src/DocsViewer/style.scss +228 -228
- package/src/DocsViewer/variables.scss +1 -1
- package/src/SlideController/helpers.ts +48 -48
- package/src/SlideController/index.ts +351 -351
- package/src/SlideDocsViewer/style.scss +28 -28
- package/src/SlidePreviewer/index.ts +225 -225
- package/src/index.ts +283 -283
- package/src/style.scss +14 -14
- package/src/typings.ts +21 -21
- package/src/utils/bgcolor.ts +45 -45
- package/src/utils/freezer.ts +116 -116
- package/src/utils/helpers.ts +32 -32
- package/src/utils/logger.ts +106 -106
package/src/index.ts
CHANGED
|
@@ -1,283 +1,283 @@
|
|
|
1
|
-
import type { NetlessApp } from "@netless/window-manager";
|
|
2
|
-
import type { RoomState } from "white-web-sdk";
|
|
3
|
-
import type { ISlideConfig } from "@netless/slide";
|
|
4
|
-
import type { MountSlideOptions } from "./SlideDocsViewer";
|
|
5
|
-
import type { Attributes, MagixEvents } from "./typings";
|
|
6
|
-
import type { AddHooks, FreezableSlide } from "./utils/freezer";
|
|
7
|
-
|
|
8
|
-
import { Slide } from "@netless/slide";
|
|
9
|
-
import { SideEffectManager } from "side-effect-manager";
|
|
10
|
-
import {
|
|
11
|
-
DefaultUrl,
|
|
12
|
-
EmptyAttributes,
|
|
13
|
-
syncSceneWithSlide,
|
|
14
|
-
SlideController,
|
|
15
|
-
} from "./SlideController";
|
|
16
|
-
import { SlideDocsViewer } from "./SlideDocsViewer";
|
|
17
|
-
import { apps, FreezerLength, addHooks, useFreezer } from "./utils/freezer";
|
|
18
|
-
import { log, logger } from "./utils/logger";
|
|
19
|
-
import styles from "./style.scss?inline";
|
|
20
|
-
|
|
21
|
-
export type { PreviewParams } from "./SlidePreviewer";
|
|
22
|
-
export { SlidePreviewer, default as previewSlide } from "./SlidePreviewer";
|
|
23
|
-
|
|
24
|
-
export type { Attributes, AddHooks, FreezableSlide };
|
|
25
|
-
export { Slide };
|
|
26
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
27
|
-
export const usePlugin: (plugin: any) => any = /* @__PURE__ */ Slide.usePlugin.bind(Slide);
|
|
28
|
-
|
|
29
|
-
export const version = __APP_VERSION__;
|
|
30
|
-
|
|
31
|
-
export { DefaultUrl, apps, FreezerLength, addHooks };
|
|
32
|
-
|
|
33
|
-
export { setFreezerLength, getFreezerLength, onCreated, onDestroyed } from "./utils/freezer";
|
|
34
|
-
|
|
35
|
-
export interface AppOptions
|
|
36
|
-
extends Pick<
|
|
37
|
-
ISlideConfig,
|
|
38
|
-
| "rtcAudio"
|
|
39
|
-
| "useLocalCache"
|
|
40
|
-
| "resourceTimeout"
|
|
41
|
-
| "loaderDelegate"
|
|
42
|
-
| "urlInterrupter"
|
|
43
|
-
| "navigatorDelegate"
|
|
44
|
-
| "fixedFrameSize"
|
|
45
|
-
| "logger"
|
|
46
|
-
> {
|
|
47
|
-
/** show debug controller */
|
|
48
|
-
debug?: boolean;
|
|
49
|
-
/** scale */
|
|
50
|
-
resolution?: number;
|
|
51
|
-
/** background color for slide animations */
|
|
52
|
-
bgColor?: string;
|
|
53
|
-
/** minimal fps @default 25 */
|
|
54
|
-
minFPS?: number;
|
|
55
|
-
/** maximal fps @default 30 */
|
|
56
|
-
maxFPS?: number;
|
|
57
|
-
/** automatically decrease fps @default true */
|
|
58
|
-
autoFPS?: boolean;
|
|
59
|
-
/** whether to re-scale automatically @default true */
|
|
60
|
-
autoResolution?: boolean;
|
|
61
|
-
/** 1~4, default: 3 */
|
|
62
|
-
maxResolutionLevel?: number;
|
|
63
|
-
/** use canvas2d mode, downside: some 3d effects are lost */
|
|
64
|
-
forceCanvas?: boolean;
|
|
65
|
-
/** fix windows 11 nvidia rendering bug, downside: render next page slows down */
|
|
66
|
-
enableNvidiaDetect?: boolean;
|
|
67
|
-
/** custom error handler */
|
|
68
|
-
onRenderError?: (error: Error, pageIndex: number) => void;
|
|
69
|
-
/** whether to show an overlay of error message @default: true */
|
|
70
|
-
showRenderError?: boolean;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
export interface ILogger {
|
|
74
|
-
info?(msg: string): void;
|
|
75
|
-
error?(msg: string): void;
|
|
76
|
-
warn?(msg: string): void;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
export interface AppResult {
|
|
80
|
-
viewer: () => SlideDocsViewer | null;
|
|
81
|
-
controller: () => SlideController | null | undefined;
|
|
82
|
-
slide: () => Slide | undefined;
|
|
83
|
-
position: () => [page: number, pageCount: number] | undefined;
|
|
84
|
-
nextStep: () => boolean;
|
|
85
|
-
prevStep: () => boolean;
|
|
86
|
-
nextPage: () => boolean;
|
|
87
|
-
prevPage: () => boolean;
|
|
88
|
-
jumpToPage: (page: number) => boolean;
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
const SlideApp: NetlessApp<Attributes, MagixEvents, AppOptions, AppResult> = {
|
|
92
|
-
kind: "Slide",
|
|
93
|
-
setup(context) {
|
|
94
|
-
console.log("[Slide] setup @ " + version);
|
|
95
|
-
|
|
96
|
-
if (context.getIsWritable()) {
|
|
97
|
-
context.storage.ensureState(EmptyAttributes);
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
if (!context.storage.state.taskId) {
|
|
101
|
-
throw new Error("[Slide] no taskId");
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
const view = context.getView();
|
|
105
|
-
if (!view) {
|
|
106
|
-
throw new Error("[Slide] no view, please set scenePath on addApp()");
|
|
107
|
-
}
|
|
108
|
-
view.disableCameraTransform = true;
|
|
109
|
-
|
|
110
|
-
const box = context.getBox();
|
|
111
|
-
box.mountStyles(styles);
|
|
112
|
-
try {
|
|
113
|
-
box.$content.dataset.appSlideVersion = version;
|
|
114
|
-
} catch {
|
|
115
|
-
// ignore
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
// must exist because of view
|
|
119
|
-
const baseScenePath = context.getInitScenePath() as string;
|
|
120
|
-
|
|
121
|
-
let docsViewer: SlideDocsViewer | null = null;
|
|
122
|
-
|
|
123
|
-
const onPageChanged = (page: number) => {
|
|
124
|
-
const room = context.getRoom();
|
|
125
|
-
if (docsViewer && docsViewer.slideController) {
|
|
126
|
-
let synced = false;
|
|
127
|
-
if (room && context.getIsWritable()) {
|
|
128
|
-
syncSceneWithSlide(room, context, docsViewer.slideController.slide, baseScenePath);
|
|
129
|
-
synced = true;
|
|
130
|
-
}
|
|
131
|
-
log("[Slide] page to", page, synced ? "(synced)" : "");
|
|
132
|
-
docsViewer.viewer.setPageIndex(page - 1);
|
|
133
|
-
}
|
|
134
|
-
};
|
|
135
|
-
|
|
136
|
-
const mountSlideController = (options: MountSlideOptions): SlideController => {
|
|
137
|
-
const appOptions = context.getAppOptions() || {};
|
|
138
|
-
|
|
139
|
-
const slideController = new SlideController({
|
|
140
|
-
context,
|
|
141
|
-
...options,
|
|
142
|
-
onPageChanged,
|
|
143
|
-
onRenderError: appOptions.onRenderError,
|
|
144
|
-
showRenderError: appOptions.showRenderError,
|
|
145
|
-
});
|
|
146
|
-
if (useFreezer) apps.set(context.appId, slideController, box);
|
|
147
|
-
logger.setAppController(context.appId, slideController);
|
|
148
|
-
if (import.meta.env.DEV) {
|
|
149
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
150
|
-
(window as any).slideController = slideController;
|
|
151
|
-
}
|
|
152
|
-
slideController.readyPromise.then(options.onReady).then(() => {
|
|
153
|
-
const room = context.getRoom();
|
|
154
|
-
let synced = false;
|
|
155
|
-
if (room && context.getIsWritable()) {
|
|
156
|
-
syncSceneWithSlide(room, context, slideController.slide, baseScenePath);
|
|
157
|
-
synced = true;
|
|
158
|
-
}
|
|
159
|
-
const page = slideController.slide.slideState.currentSlideIndex;
|
|
160
|
-
log("[Slide] page to", page, synced ? "(synced)" : "", "(on ready)");
|
|
161
|
-
slideController.slide.on("renderEnd", options.onRenderEnd);
|
|
162
|
-
});
|
|
163
|
-
return slideController;
|
|
164
|
-
};
|
|
165
|
-
|
|
166
|
-
docsViewer = new SlideDocsViewer({
|
|
167
|
-
box,
|
|
168
|
-
view,
|
|
169
|
-
mountSlideController,
|
|
170
|
-
mountWhiteboard: context.mountView.bind(context),
|
|
171
|
-
baseScenePath,
|
|
172
|
-
appId: context.appId,
|
|
173
|
-
urlInterrupter: context.getAppOptions()?.urlInterrupter,
|
|
174
|
-
});
|
|
175
|
-
|
|
176
|
-
if (import.meta.env.DEV) {
|
|
177
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
178
|
-
(window as any).slideDoc = docsViewer;
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
const room = context.getRoom();
|
|
182
|
-
const sideEffect = new SideEffectManager();
|
|
183
|
-
|
|
184
|
-
sideEffect.add(() => {
|
|
185
|
-
logger.setAppContext(context.appId, context);
|
|
186
|
-
logger.enable = context.getAppOptions()?.debug || import.meta.env.DEV;
|
|
187
|
-
logger.level = import.meta.env.DEV ? "verbose" : "debug";
|
|
188
|
-
return () => logger.deleteApp(context.appId);
|
|
189
|
-
});
|
|
190
|
-
|
|
191
|
-
if (room) {
|
|
192
|
-
docsViewer.toggleClickThrough(room.state.memberState.currentApplianceName);
|
|
193
|
-
sideEffect.add(() => {
|
|
194
|
-
const onRoomStateChanged = (e: Partial<RoomState>) => {
|
|
195
|
-
if (e.memberState && docsViewer) {
|
|
196
|
-
docsViewer.toggleClickThrough(e.memberState.currentApplianceName);
|
|
197
|
-
}
|
|
198
|
-
};
|
|
199
|
-
room.callbacks.on("onRoomStateChanged", onRoomStateChanged);
|
|
200
|
-
return () => room.callbacks.off("onRoomStateChanged", onRoomStateChanged);
|
|
201
|
-
});
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
context.emitter.on("destroy", () => {
|
|
205
|
-
log("[Slide] destroy", context.appId);
|
|
206
|
-
if (useFreezer) apps.delete(context.appId);
|
|
207
|
-
sideEffect.flushAll();
|
|
208
|
-
if (docsViewer) {
|
|
209
|
-
docsViewer.destroy();
|
|
210
|
-
docsViewer = null;
|
|
211
|
-
}
|
|
212
|
-
});
|
|
213
|
-
|
|
214
|
-
docsViewer.mount();
|
|
215
|
-
|
|
216
|
-
return {
|
|
217
|
-
viewer: () => {
|
|
218
|
-
return docsViewer;
|
|
219
|
-
},
|
|
220
|
-
controller: () => {
|
|
221
|
-
return docsViewer?.slideController;
|
|
222
|
-
},
|
|
223
|
-
slide: () => {
|
|
224
|
-
return docsViewer?.slideController?.slide;
|
|
225
|
-
},
|
|
226
|
-
nextStep: () => {
|
|
227
|
-
if (docsViewer && docsViewer.slideController) {
|
|
228
|
-
docsViewer?.slideController?.slide.nextStep();
|
|
229
|
-
return true;
|
|
230
|
-
}
|
|
231
|
-
return false;
|
|
232
|
-
},
|
|
233
|
-
prevStep: () => {
|
|
234
|
-
if (docsViewer && docsViewer.slideController) {
|
|
235
|
-
docsViewer?.slideController?.slide.prevStep();
|
|
236
|
-
return true;
|
|
237
|
-
}
|
|
238
|
-
return false;
|
|
239
|
-
},
|
|
240
|
-
position: () => {
|
|
241
|
-
const controller = docsViewer?.slideController;
|
|
242
|
-
if (controller) {
|
|
243
|
-
return [controller.page, controller.pageCount] as [page: number, pageCount: number];
|
|
244
|
-
}
|
|
245
|
-
},
|
|
246
|
-
nextPage: () => {
|
|
247
|
-
const controller = docsViewer?.slideController;
|
|
248
|
-
if (controller) {
|
|
249
|
-
const { page, pageCount } = controller;
|
|
250
|
-
if (pageCount > 0 && page < pageCount) {
|
|
251
|
-
controller.jumpToPage(page + 1);
|
|
252
|
-
return true;
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
|
-
return false;
|
|
256
|
-
},
|
|
257
|
-
prevPage: () => {
|
|
258
|
-
const controller = docsViewer?.slideController;
|
|
259
|
-
if (controller) {
|
|
260
|
-
const { page, pageCount } = controller;
|
|
261
|
-
if (pageCount > 0 && page > 1) {
|
|
262
|
-
controller.jumpToPage(page - 1);
|
|
263
|
-
return true;
|
|
264
|
-
}
|
|
265
|
-
}
|
|
266
|
-
return false;
|
|
267
|
-
},
|
|
268
|
-
jumpToPage: (newPage: number) => {
|
|
269
|
-
const controller = docsViewer?.slideController;
|
|
270
|
-
if (controller) {
|
|
271
|
-
const { page, pageCount } = controller;
|
|
272
|
-
if (pageCount > 0 && page > 0 && page <= pageCount) {
|
|
273
|
-
controller.jumpToPage(newPage);
|
|
274
|
-
return true;
|
|
275
|
-
}
|
|
276
|
-
}
|
|
277
|
-
return false;
|
|
278
|
-
},
|
|
279
|
-
};
|
|
280
|
-
},
|
|
281
|
-
};
|
|
282
|
-
|
|
283
|
-
export default SlideApp;
|
|
1
|
+
import type { NetlessApp } from "@netless/window-manager";
|
|
2
|
+
import type { RoomState } from "white-web-sdk";
|
|
3
|
+
import type { ISlideConfig } from "@netless/slide";
|
|
4
|
+
import type { MountSlideOptions } from "./SlideDocsViewer";
|
|
5
|
+
import type { Attributes, MagixEvents } from "./typings";
|
|
6
|
+
import type { AddHooks, FreezableSlide } from "./utils/freezer";
|
|
7
|
+
|
|
8
|
+
import { Slide } from "@netless/slide";
|
|
9
|
+
import { SideEffectManager } from "side-effect-manager";
|
|
10
|
+
import {
|
|
11
|
+
DefaultUrl,
|
|
12
|
+
EmptyAttributes,
|
|
13
|
+
syncSceneWithSlide,
|
|
14
|
+
SlideController,
|
|
15
|
+
} from "./SlideController";
|
|
16
|
+
import { SlideDocsViewer } from "./SlideDocsViewer";
|
|
17
|
+
import { apps, FreezerLength, addHooks, useFreezer } from "./utils/freezer";
|
|
18
|
+
import { log, logger } from "./utils/logger";
|
|
19
|
+
import styles from "./style.scss?inline";
|
|
20
|
+
|
|
21
|
+
export type { PreviewParams } from "./SlidePreviewer";
|
|
22
|
+
export { SlidePreviewer, default as previewSlide } from "./SlidePreviewer";
|
|
23
|
+
|
|
24
|
+
export type { Attributes, AddHooks, FreezableSlide };
|
|
25
|
+
export { Slide };
|
|
26
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
27
|
+
export const usePlugin: (plugin: any) => any = /* @__PURE__ */ Slide.usePlugin.bind(Slide);
|
|
28
|
+
|
|
29
|
+
export const version = __APP_VERSION__;
|
|
30
|
+
|
|
31
|
+
export { DefaultUrl, apps, FreezerLength, addHooks };
|
|
32
|
+
|
|
33
|
+
export { setFreezerLength, getFreezerLength, onCreated, onDestroyed } from "./utils/freezer";
|
|
34
|
+
|
|
35
|
+
export interface AppOptions
|
|
36
|
+
extends Pick<
|
|
37
|
+
ISlideConfig,
|
|
38
|
+
| "rtcAudio"
|
|
39
|
+
| "useLocalCache"
|
|
40
|
+
| "resourceTimeout"
|
|
41
|
+
| "loaderDelegate"
|
|
42
|
+
| "urlInterrupter"
|
|
43
|
+
| "navigatorDelegate"
|
|
44
|
+
| "fixedFrameSize"
|
|
45
|
+
| "logger"
|
|
46
|
+
> {
|
|
47
|
+
/** show debug controller */
|
|
48
|
+
debug?: boolean;
|
|
49
|
+
/** scale */
|
|
50
|
+
resolution?: number;
|
|
51
|
+
/** background color for slide animations */
|
|
52
|
+
bgColor?: string;
|
|
53
|
+
/** minimal fps @default 25 */
|
|
54
|
+
minFPS?: number;
|
|
55
|
+
/** maximal fps @default 30 */
|
|
56
|
+
maxFPS?: number;
|
|
57
|
+
/** automatically decrease fps @default true */
|
|
58
|
+
autoFPS?: boolean;
|
|
59
|
+
/** whether to re-scale automatically @default true */
|
|
60
|
+
autoResolution?: boolean;
|
|
61
|
+
/** 1~4, default: 3 */
|
|
62
|
+
maxResolutionLevel?: number;
|
|
63
|
+
/** use canvas2d mode, downside: some 3d effects are lost */
|
|
64
|
+
forceCanvas?: boolean;
|
|
65
|
+
/** fix windows 11 nvidia rendering bug, downside: render next page slows down */
|
|
66
|
+
enableNvidiaDetect?: boolean;
|
|
67
|
+
/** custom error handler */
|
|
68
|
+
onRenderError?: (error: Error, pageIndex: number) => void;
|
|
69
|
+
/** whether to show an overlay of error message @default: true */
|
|
70
|
+
showRenderError?: boolean;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export interface ILogger {
|
|
74
|
+
info?(msg: string): void;
|
|
75
|
+
error?(msg: string): void;
|
|
76
|
+
warn?(msg: string): void;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export interface AppResult {
|
|
80
|
+
viewer: () => SlideDocsViewer | null;
|
|
81
|
+
controller: () => SlideController | null | undefined;
|
|
82
|
+
slide: () => Slide | undefined;
|
|
83
|
+
position: () => [page: number, pageCount: number] | undefined;
|
|
84
|
+
nextStep: () => boolean;
|
|
85
|
+
prevStep: () => boolean;
|
|
86
|
+
nextPage: () => boolean;
|
|
87
|
+
prevPage: () => boolean;
|
|
88
|
+
jumpToPage: (page: number) => boolean;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const SlideApp: NetlessApp<Attributes, MagixEvents, AppOptions, AppResult> = {
|
|
92
|
+
kind: "Slide",
|
|
93
|
+
setup(context) {
|
|
94
|
+
console.log("[Slide] setup @ " + version);
|
|
95
|
+
|
|
96
|
+
if (context.getIsWritable()) {
|
|
97
|
+
context.storage.ensureState(EmptyAttributes);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
if (!context.storage.state.taskId) {
|
|
101
|
+
throw new Error("[Slide] no taskId");
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const view = context.getView();
|
|
105
|
+
if (!view) {
|
|
106
|
+
throw new Error("[Slide] no view, please set scenePath on addApp()");
|
|
107
|
+
}
|
|
108
|
+
view.disableCameraTransform = true;
|
|
109
|
+
|
|
110
|
+
const box = context.getBox();
|
|
111
|
+
box.mountStyles(styles);
|
|
112
|
+
try {
|
|
113
|
+
box.$content.dataset.appSlideVersion = version;
|
|
114
|
+
} catch {
|
|
115
|
+
// ignore
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// must exist because of view
|
|
119
|
+
const baseScenePath = context.getInitScenePath() as string;
|
|
120
|
+
|
|
121
|
+
let docsViewer: SlideDocsViewer | null = null;
|
|
122
|
+
|
|
123
|
+
const onPageChanged = (page: number) => {
|
|
124
|
+
const room = context.getRoom();
|
|
125
|
+
if (docsViewer && docsViewer.slideController) {
|
|
126
|
+
let synced = false;
|
|
127
|
+
if (room && context.getIsWritable()) {
|
|
128
|
+
syncSceneWithSlide(room, context, docsViewer.slideController.slide, baseScenePath);
|
|
129
|
+
synced = true;
|
|
130
|
+
}
|
|
131
|
+
log("[Slide] page to", page, synced ? "(synced)" : "");
|
|
132
|
+
docsViewer.viewer.setPageIndex(page - 1);
|
|
133
|
+
}
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
const mountSlideController = (options: MountSlideOptions): SlideController => {
|
|
137
|
+
const appOptions = context.getAppOptions() || {};
|
|
138
|
+
|
|
139
|
+
const slideController = new SlideController({
|
|
140
|
+
context,
|
|
141
|
+
...options,
|
|
142
|
+
onPageChanged,
|
|
143
|
+
onRenderError: appOptions.onRenderError,
|
|
144
|
+
showRenderError: appOptions.showRenderError,
|
|
145
|
+
});
|
|
146
|
+
if (useFreezer) apps.set(context.appId, slideController, box);
|
|
147
|
+
logger.setAppController(context.appId, slideController);
|
|
148
|
+
if (import.meta.env.DEV) {
|
|
149
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
150
|
+
(window as any).slideController = slideController;
|
|
151
|
+
}
|
|
152
|
+
slideController.readyPromise.then(options.onReady).then(() => {
|
|
153
|
+
const room = context.getRoom();
|
|
154
|
+
let synced = false;
|
|
155
|
+
if (room && context.getIsWritable()) {
|
|
156
|
+
syncSceneWithSlide(room, context, slideController.slide, baseScenePath);
|
|
157
|
+
synced = true;
|
|
158
|
+
}
|
|
159
|
+
const page = slideController.slide.slideState.currentSlideIndex;
|
|
160
|
+
log("[Slide] page to", page, synced ? "(synced)" : "", "(on ready)");
|
|
161
|
+
slideController.slide.on("renderEnd", options.onRenderEnd);
|
|
162
|
+
});
|
|
163
|
+
return slideController;
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
docsViewer = new SlideDocsViewer({
|
|
167
|
+
box,
|
|
168
|
+
view,
|
|
169
|
+
mountSlideController,
|
|
170
|
+
mountWhiteboard: context.mountView.bind(context),
|
|
171
|
+
baseScenePath,
|
|
172
|
+
appId: context.appId,
|
|
173
|
+
urlInterrupter: context.getAppOptions()?.urlInterrupter,
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
if (import.meta.env.DEV) {
|
|
177
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
178
|
+
(window as any).slideDoc = docsViewer;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
const room = context.getRoom();
|
|
182
|
+
const sideEffect = new SideEffectManager();
|
|
183
|
+
|
|
184
|
+
sideEffect.add(() => {
|
|
185
|
+
logger.setAppContext(context.appId, context);
|
|
186
|
+
logger.enable = context.getAppOptions()?.debug || import.meta.env.DEV;
|
|
187
|
+
logger.level = import.meta.env.DEV ? "verbose" : "debug";
|
|
188
|
+
return () => logger.deleteApp(context.appId);
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
if (room) {
|
|
192
|
+
docsViewer.toggleClickThrough(room.state.memberState.currentApplianceName);
|
|
193
|
+
sideEffect.add(() => {
|
|
194
|
+
const onRoomStateChanged = (e: Partial<RoomState>) => {
|
|
195
|
+
if (e.memberState && docsViewer) {
|
|
196
|
+
docsViewer.toggleClickThrough(e.memberState.currentApplianceName);
|
|
197
|
+
}
|
|
198
|
+
};
|
|
199
|
+
room.callbacks.on("onRoomStateChanged", onRoomStateChanged);
|
|
200
|
+
return () => room.callbacks.off("onRoomStateChanged", onRoomStateChanged);
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
context.emitter.on("destroy", () => {
|
|
205
|
+
log("[Slide] destroy", context.appId);
|
|
206
|
+
if (useFreezer) apps.delete(context.appId);
|
|
207
|
+
sideEffect.flushAll();
|
|
208
|
+
if (docsViewer) {
|
|
209
|
+
docsViewer.destroy();
|
|
210
|
+
docsViewer = null;
|
|
211
|
+
}
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
docsViewer.mount();
|
|
215
|
+
|
|
216
|
+
return {
|
|
217
|
+
viewer: () => {
|
|
218
|
+
return docsViewer;
|
|
219
|
+
},
|
|
220
|
+
controller: () => {
|
|
221
|
+
return docsViewer?.slideController;
|
|
222
|
+
},
|
|
223
|
+
slide: () => {
|
|
224
|
+
return docsViewer?.slideController?.slide;
|
|
225
|
+
},
|
|
226
|
+
nextStep: () => {
|
|
227
|
+
if (docsViewer && docsViewer.slideController) {
|
|
228
|
+
docsViewer?.slideController?.slide.nextStep();
|
|
229
|
+
return true;
|
|
230
|
+
}
|
|
231
|
+
return false;
|
|
232
|
+
},
|
|
233
|
+
prevStep: () => {
|
|
234
|
+
if (docsViewer && docsViewer.slideController) {
|
|
235
|
+
docsViewer?.slideController?.slide.prevStep();
|
|
236
|
+
return true;
|
|
237
|
+
}
|
|
238
|
+
return false;
|
|
239
|
+
},
|
|
240
|
+
position: () => {
|
|
241
|
+
const controller = docsViewer?.slideController;
|
|
242
|
+
if (controller) {
|
|
243
|
+
return [controller.page, controller.pageCount] as [page: number, pageCount: number];
|
|
244
|
+
}
|
|
245
|
+
},
|
|
246
|
+
nextPage: () => {
|
|
247
|
+
const controller = docsViewer?.slideController;
|
|
248
|
+
if (controller) {
|
|
249
|
+
const { page, pageCount } = controller;
|
|
250
|
+
if (pageCount > 0 && page < pageCount) {
|
|
251
|
+
controller.jumpToPage(page + 1);
|
|
252
|
+
return true;
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
return false;
|
|
256
|
+
},
|
|
257
|
+
prevPage: () => {
|
|
258
|
+
const controller = docsViewer?.slideController;
|
|
259
|
+
if (controller) {
|
|
260
|
+
const { page, pageCount } = controller;
|
|
261
|
+
if (pageCount > 0 && page > 1) {
|
|
262
|
+
controller.jumpToPage(page - 1);
|
|
263
|
+
return true;
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
return false;
|
|
267
|
+
},
|
|
268
|
+
jumpToPage: (newPage: number) => {
|
|
269
|
+
const controller = docsViewer?.slideController;
|
|
270
|
+
if (controller) {
|
|
271
|
+
const { page, pageCount } = controller;
|
|
272
|
+
if (pageCount > 0 && page > 0 && page <= pageCount) {
|
|
273
|
+
controller.jumpToPage(newPage);
|
|
274
|
+
return true;
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
return false;
|
|
278
|
+
},
|
|
279
|
+
};
|
|
280
|
+
},
|
|
281
|
+
};
|
|
282
|
+
|
|
283
|
+
export default SlideApp;
|
package/src/style.scss
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
@import "./DocsViewer/style.scss";
|
|
2
|
-
@import "./SlideDocsViewer/style.scss";
|
|
3
|
-
|
|
4
|
-
.netless-app-slide-slide {
|
|
5
|
-
width: 100%;
|
|
6
|
-
height: 100%;
|
|
7
|
-
display: flex;
|
|
8
|
-
align-items: center;
|
|
9
|
-
justify-content: center;
|
|
10
|
-
|
|
11
|
-
canvas {
|
|
12
|
-
transform: scale(var(--netless-app-slide-scale, 1));
|
|
13
|
-
}
|
|
14
|
-
}
|
|
1
|
+
@import "./DocsViewer/style.scss";
|
|
2
|
+
@import "./SlideDocsViewer/style.scss";
|
|
3
|
+
|
|
4
|
+
.netless-app-slide-slide {
|
|
5
|
+
width: 100%;
|
|
6
|
+
height: 100%;
|
|
7
|
+
display: flex;
|
|
8
|
+
align-items: center;
|
|
9
|
+
justify-content: center;
|
|
10
|
+
|
|
11
|
+
canvas {
|
|
12
|
+
transform: scale(var(--netless-app-slide-scale, 1));
|
|
13
|
+
}
|
|
14
|
+
}
|
package/src/typings.ts
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
import type { Slide, SLIDE_EVENTS, SyncEvent } from "@netless/slide";
|
|
2
|
-
|
|
3
|
-
export type SlideState = Slide["slideState"];
|
|
4
|
-
|
|
5
|
-
export interface Attributes {
|
|
6
|
-
/** convert task id */
|
|
7
|
-
taskId: string;
|
|
8
|
-
/** base url of converted resources */
|
|
9
|
-
url: string;
|
|
10
|
-
/** internal state of slide, do not change */
|
|
11
|
-
state: SlideState | null;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export type MagixPayload = {
|
|
15
|
-
type: typeof SLIDE_EVENTS.syncDispatch;
|
|
16
|
-
payload: SyncEvent;
|
|
17
|
-
};
|
|
18
|
-
|
|
19
|
-
export type MagixEvents = {
|
|
20
|
-
[SLIDE_EVENTS.syncDispatch]: MagixPayload;
|
|
21
|
-
};
|
|
1
|
+
import type { Slide, SLIDE_EVENTS, SyncEvent } from "@netless/slide";
|
|
2
|
+
|
|
3
|
+
export type SlideState = Slide["slideState"];
|
|
4
|
+
|
|
5
|
+
export interface Attributes {
|
|
6
|
+
/** convert task id */
|
|
7
|
+
taskId: string;
|
|
8
|
+
/** base url of converted resources */
|
|
9
|
+
url: string;
|
|
10
|
+
/** internal state of slide, do not change */
|
|
11
|
+
state: SlideState | null;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export type MagixPayload = {
|
|
15
|
+
type: typeof SLIDE_EVENTS.syncDispatch;
|
|
16
|
+
payload: SyncEvent;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export type MagixEvents = {
|
|
20
|
+
[SLIDE_EVENTS.syncDispatch]: MagixPayload;
|
|
21
|
+
};
|