@netless/app-slide 0.3.0-canary.1 → 0.3.0-canary.11

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/src/index.ts CHANGED
@@ -6,11 +6,15 @@ export type { SlideState, AddHooks, AppOptions, Attributes, MagixEvents, SlideVi
6
6
 
7
7
  import ColorString from "color-string";
8
8
  import { SideEffectManager } from "side-effect-manager";
9
+ import { Slide } from "@netless/slide";
9
10
  import { SlideViewer } from "./SlideViewer";
10
11
  import { refrigerator, addHooks } from "./Refrigerator";
11
- import { noop } from "./utils";
12
+ import { DefaultUrl } from "./constants";
12
13
 
13
- export { SlideViewer, refrigerator, addHooks };
14
+ export { Slide, SlideViewer, refrigerator, addHooks, DefaultUrl };
15
+
16
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
17
+ export const usePlugin = /* @__PURE__ */ Slide.usePlugin.bind(Slide) as (plugin: any) => void;
14
18
 
15
19
  export const version = __APP_VERSION__;
16
20
 
@@ -23,29 +27,36 @@ const SlideApp: NetlessApp<Attributes, MagixEvents, AppOptions, void> = {
23
27
  throw new Error("[Slide] no taskId");
24
28
  }
25
29
 
26
- const options = context.getAppOptions() || {};
27
- const debug = Boolean(options.debug);
30
+ const appOptions = context.getAppOptions() || {};
31
+ const options = appOptions.renderOptions || {};
32
+ const logger = make_logger(context, appOptions.debug);
33
+ logger.info("[Slide] setup @ " + __APP_VERSION__);
28
34
 
29
35
  const sideEffect = new SideEffectManager();
30
36
 
31
- // create ui
37
+ // Create UI
32
38
  const viewer = new SlideViewer({
33
39
  interactive: true,
34
40
  mode: "interactive",
35
41
  resize: true,
36
42
  enableGlobalClick: true,
37
- controller: debug,
38
43
  timestamp: make_timestamp(context),
39
- logger: make_logger(context),
44
+ logger: appOptions.logger || logger,
40
45
  renderOptions: {
41
46
  minFPS: options.minFPS || 25,
42
47
  maxFPS: options.maxFPS || 30,
43
48
  autoFPS: options.autoFPS ?? true,
44
49
  autoResolution: options.autoResolution ?? true,
45
50
  resolution: options.resolution,
46
- transactionBgColor: options.bgColor || make_bg_color(context.box.$content),
51
+ maxResolutionLevel: options.maxResolutionLevel,
52
+ transactionBgColor: options.transactionBgColor || make_bg_color(context.box.$content),
47
53
  },
48
-
54
+ rtcAudio: appOptions.rtcAudio,
55
+ useLocalCache: appOptions.useLocalCache,
56
+ resourceTimeout: appOptions.resourceTimeout,
57
+ loaderDelegate: appOptions.loaderDelegate,
58
+ navigatorDelegate: appOptions.navigatorDelegate,
59
+ fixedFrameSize: appOptions.fixedFrameSize,
49
60
  taskId: context.storage.state.taskId,
50
61
  url: context.storage.state.url,
51
62
  });
@@ -61,37 +72,45 @@ const SlideApp: NetlessApp<Attributes, MagixEvents, AppOptions, void> = {
61
72
  (window as any).slideViewer = viewer;
62
73
  }
63
74
 
64
- // mount ui
75
+ // Mount UI
65
76
  context.box.mountStyles(SlideViewer.styles);
66
77
  context.box.mountStage(viewer.$slide);
67
78
  context.box.mountFooter(viewer.$footer);
68
79
  context.box.mountContent(viewer.$content);
69
80
  sideEffect.addDisposer(() => viewer.destroy());
70
81
 
71
- // connect ui with netless app
72
- connect({ context, viewer, sideEffect, debug });
82
+ // Connect UI with Netless App
83
+ connect({ context, viewer, sideEffect, logger });
73
84
 
74
85
  onUnmount(context, () => {
75
- console.log("[Slide] destroy");
86
+ logger.info("[Slide] destroy");
76
87
  sideEffect.flushAll();
77
88
  });
89
+
90
+ return viewer;
78
91
  },
79
92
  };
80
93
 
81
94
  export default SlideApp;
82
95
 
83
96
  export function previewSlide(options: SlideViewerOptions & { container: HTMLElement }) {
84
- const { container } = options;
85
- container.style.cssText = "display:flex;flex-direction:column";
86
- const viewer = new SlideViewer(options);
87
- container.appendChild(document.createElement("style")).textContent = SlideViewer.styles;
88
- container.appendChild(viewer.$content);
89
- container.appendChild(viewer.$footer);
97
+ const { container, ...slideOptions } = options;
98
+ const wrapper = document.createElement("div");
99
+ wrapper.className = "netless-app-slide-preview-wrapper";
100
+ const viewer = new SlideViewer(slideOptions);
101
+ wrapper.appendChild(document.createElement("style")).textContent = SlideViewer.styles;
102
+ wrapper.appendChild(viewer.$content);
103
+ wrapper.appendChild(viewer.$footer);
104
+ container.appendChild(wrapper);
90
105
  viewer.prepare(() => viewer.slide.renderSlide(1));
91
- viewer.slide.on("slideChange", page => viewer.setPage(page));
92
106
  return viewer;
93
107
  }
94
108
 
109
+ if (import.meta.env.DEV) {
110
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
111
+ (window as any).previewSlide = previewSlide;
112
+ }
113
+
95
114
  function make_timestamp(context: AppContext): () => number {
96
115
  const room = context.room;
97
116
  const player = context.displayer as Player;
@@ -104,7 +123,8 @@ function make_timestamp(context: AppContext): () => number {
104
123
  }
105
124
  }
106
125
 
107
- function make_logger(context: AppContext) {
126
+ function make_logger(context: AppContext, debug?: boolean): { info: (msg: string) => void } {
127
+ void debug; // not used for now
108
128
  if (import.meta.env.DEV) {
109
129
  return { info: console.debug.bind(console) };
110
130
  }
@@ -155,18 +175,19 @@ interface ConnectParams {
155
175
  context: AppContext;
156
176
  viewer: SlideViewer;
157
177
  sideEffect: SideEffectManager;
158
- debug: boolean;
178
+ logger: { info: (msg: string) => void };
159
179
  }
160
180
 
161
- function connect({ context, viewer, sideEffect, debug }: ConnectParams) {
162
- const log = debug ? console.log.bind(console) : noop;
181
+ function connect({ context, viewer, sideEffect, logger }: ConnectParams) {
182
+ const log = import.meta.env.DEV ? console.log.bind(console) : logger.info.bind(logger);
163
183
 
164
184
  let whiteboard: WhiteBoardView | null = null;
165
185
 
166
186
  viewer.prepare(({ width, height, slideCount }) => {
167
187
  if (context.destroyed) return;
168
188
  width && context.box.setStageRatio(height / width);
169
- whiteboard = context.createWhiteBoardView(slideCount);
189
+ whiteboard = context.createWhiteBoardView({ size: slideCount });
190
+ whiteboard.setBaseRect({ width, height });
170
191
  kick_start();
171
192
  });
172
193
 
@@ -229,9 +250,10 @@ function connect({ context, viewer, sideEffect, debug }: ConnectParams) {
229
250
 
230
251
  // save state
231
252
  slide.on("slideChange", page => {
232
- log("[Slide] page to", page);
233
- whiteboard && whiteboard.jumpPage(page - 1);
234
- viewer.setPage(page);
253
+ if (context.isWritable && whiteboard) {
254
+ log("[Slide] page to", page);
255
+ whiteboard.jumpPage(page - 1);
256
+ }
235
257
  });
236
258
 
237
259
  // handle ui events
@@ -241,4 +263,15 @@ function connect({ context, viewer, sideEffect, debug }: ConnectParams) {
241
263
  viewer.setReadonly(!w);
242
264
  })
243
265
  );
266
+
267
+ sideEffect.addEventListener(window, "keydown", ev => {
268
+ if (context.box.focus) {
269
+ if (ev.key === "ArrowUp" || ev.key === "ArrowLeft") {
270
+ viewer.slide.prevStep();
271
+ }
272
+ if (ev.key === "ArrowRight" || ev.key === "ArrowDown") {
273
+ viewer.slide.nextStep();
274
+ }
275
+ }
276
+ });
244
277
  }
package/src/style.scss CHANGED
@@ -1,5 +1,13 @@
1
1
  @import "./fancy-scrollbar.scss";
2
2
 
3
+ @mixin no-user-select {
4
+ -webkit-touch-callout: none;
5
+ -webkit-user-select: none;
6
+ -moz-user-select: none;
7
+ -ms-user-select: none;
8
+ user-select: none;
9
+ }
10
+
3
11
  $namespace: "netless-app-slide";
4
12
 
5
13
  .#{$namespace}-content {
@@ -11,12 +19,13 @@ $namespace: "netless-app-slide";
11
19
  .#{$namespace}-slide {
12
20
  width: 100%;
13
21
  height: 100%;
22
+ @include no-user-select;
14
23
  }
15
24
 
16
25
  .#{$namespace}-preview-mask {
17
26
  display: none;
18
27
  position: absolute;
19
- z-index: 6000;
28
+ z-index: 10200;
20
29
  top: 0;
21
30
  left: 0;
22
31
  width: 100%;
@@ -28,7 +37,7 @@ $namespace: "netless-app-slide";
28
37
  flex-direction: column;
29
38
  align-items: center;
30
39
  position: absolute;
31
- z-index: 6100;
40
+ z-index: 10300;
32
41
  top: 0;
33
42
  left: 0;
34
43
  width: 33%;
@@ -39,6 +48,7 @@ $namespace: "netless-app-slide";
39
48
  background: rgba(237, 237, 240, 0.9);
40
49
  box-shadow: inset -1px 0 0 rgba(0, 0, 0, 0.11);
41
50
  transition: transform 0.4s;
51
+ @include no-user-select;
42
52
  }
43
53
 
44
54
  .#{$namespace}-preview-active {
@@ -62,7 +72,7 @@ $namespace: "netless-app-slide";
62
72
  border: 7px solid transparent;
63
73
  border-radius: 4px;
64
74
  transition: border-color 0.3s;
65
- user-select: none;
75
+ @include no-user-select;
66
76
 
67
77
  &:hover,
68
78
  &.#{$namespace}-preview-page-active {
@@ -88,7 +98,23 @@ $namespace: "netless-app-slide";
88
98
  text-align: right;
89
99
  font-size: 12px;
90
100
  color: #5f5f5f;
91
- user-select: none;
101
+ @include no-user-select;
102
+ }
103
+
104
+ .#{$namespace}-overlay {
105
+ display: flex;
106
+ align-items: center;
107
+ justify-content: center;
108
+ position: absolute;
109
+ z-index: 10100;
110
+ top: 0;
111
+ left: 0;
112
+ width: 100%;
113
+ height: 100%;
114
+ background: rgba(255, 0, 0, 0.25);
115
+ transition: opacity 0.3s;
116
+ opacity: 0;
117
+ pointer-events: none;
92
118
  }
93
119
 
94
120
  .#{$namespace}-footer {
@@ -98,7 +124,8 @@ $namespace: "netless-app-slide";
98
124
  align-items: center;
99
125
  padding: 0 16px;
100
126
  border-top: 1px solid #eeeef7;
101
- color: #191919;
127
+ font-family: system-ui, -apple-system, "Segoe UI", "Roboto", "Ubuntu", "Cantarell", "Noto Sans",
128
+ sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
102
129
  }
103
130
 
104
131
  .#{$namespace}-float-footer {
@@ -126,7 +153,7 @@ $namespace: "netless-app-slide";
126
153
  background: transparent;
127
154
  transition: background 0.4s;
128
155
  cursor: pointer;
129
- user-select: none;
156
+ @include no-user-select;
130
157
  -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
131
158
 
132
159
  &:hover {
@@ -171,11 +198,15 @@ $namespace: "netless-app-slide";
171
198
  }
172
199
 
173
200
  .#{$namespace}-page-number {
201
+ display: flex;
202
+ align-items: center;
203
+ height: 26px;
174
204
  margin-left: auto;
175
205
  font-size: 13px;
176
- user-select: none;
206
+ @include no-user-select;
177
207
  white-space: nowrap;
178
208
  word-break: keep-all;
209
+ font-variant-numeric: tabular-nums;
179
210
  }
180
211
 
181
212
  .#{$namespace}-page-number-input {
@@ -183,7 +214,7 @@ $namespace: "netless-app-slide";
183
214
  outline: none;
184
215
  width: 3em;
185
216
  margin: 0;
186
- padding: 0 2px;
217
+ padding: 0 0.5em 0 2px;
187
218
  text-align: right;
188
219
  font-size: 13px;
189
220
  line-height: 1;
@@ -191,14 +222,17 @@ $namespace: "netless-app-slide";
191
222
  font-family: inherit;
192
223
  border-radius: 2px;
193
224
  color: currentColor;
225
+ font-family: system-ui, -apple-system, "Segoe UI", "Roboto", "Ubuntu", "Cantarell", "Noto Sans",
226
+ sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
194
227
  background: transparent;
195
228
  transition: background 0.4s;
196
- user-select: text;
229
+ font-variant-numeric: tabular-nums;
197
230
  -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
198
231
 
199
232
  &:hover,
200
233
  &:focus,
201
234
  &:active {
235
+ user-select: text;
202
236
  background: #fff;
203
237
  box-shadow: rgba(99, 99, 99, 0.2) 0px 2px 8px 0px;
204
238
  }
@@ -234,17 +268,13 @@ $namespace: "netless-app-slide";
234
268
  }
235
269
 
236
270
  .telebox-color-scheme-dark {
237
- .#{$namespace}-page-number-input {
238
- color: #a6a6a8;
239
- }
240
271
  .#{$namespace}-page-number-input:active,
241
272
  .#{$namespace}-page-number-input:focus,
242
273
  .#{$namespace}-page-number-input:hover {
243
- color: #222;
274
+ color: currentColor;
275
+ background: #25282e;
244
276
  }
245
277
  .#{$namespace}-footer {
246
- color: #a6a6a8;
247
- background: #2d2d33;
248
278
  border-top: none;
249
279
  }
250
280
  .#{$namespace}-footer-btn:hover {
@@ -254,3 +284,19 @@ $namespace: "netless-app-slide";
254
284
  background: rgba(50, 50, 50, 0.9);
255
285
  }
256
286
  }
287
+
288
+ .#{$namespace}-preview-wrapper {
289
+ width: 100%;
290
+ height: 100%;
291
+ overflow: hidden;
292
+ display: flex;
293
+ flex-flow: column nowrap;
294
+
295
+ .#{$namespace}-content {
296
+ flex: 1;
297
+ }
298
+
299
+ .#{$namespace}-footer {
300
+ flex-shrink: 0;
301
+ }
302
+ }
package/src/typings.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { Slide, SLIDE_EVENTS, SyncEvent } from "@netless/slide";
1
+ import type { ISlideConfig, Slide, SLIDE_EVENTS, SyncEvent } from "@netless/slide";
2
2
  import type { RegisterParams } from "@netless/window-manager";
3
3
 
4
4
  export type SlideState = Slide["slideState"];
@@ -18,19 +18,23 @@ export interface MagixEvents {
18
18
  [SLIDE_EVENTS.syncDispatch]: SyncEvent;
19
19
  }
20
20
 
21
- export interface AppOptions {
22
- /** show debug controller */
21
+ export interface AppOptions
22
+ extends Pick<
23
+ ISlideConfig,
24
+ | "renderOptions"
25
+ | "rtcAudio"
26
+ | "useLocalCache"
27
+ | "resourceTimeout"
28
+ | "loaderDelegate"
29
+ | "navigatorDelegate"
30
+ | "fixedFrameSize"
31
+ | "logger"
32
+ > {
23
33
  debug?: boolean;
24
- /** scale */
25
- resolution?: number;
26
- /** background color for slide animations */
27
- bgColor?: string;
28
- /** minimal fps (default: 25) */
29
- minFPS?: number;
30
- /** maximal fps (default: 30) */
31
- maxFPS?: number;
32
- /** automatically decrease fps (default: true) */
33
- autoFPS?: boolean;
34
- /** whether to re-scale automatically (default: true) */
35
- autoResolution?: boolean;
34
+ }
35
+
36
+ export interface ILogger {
37
+ info?(msg: string): void;
38
+ error?(msg: string): void;
39
+ warn?(msg: string): void;
36
40
  }