@netless/fastboard-ui 0.3.0-canary.6 → 0.3.1

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@netless/fastboard-ui",
3
- "version": "0.3.0-canary.6",
3
+ "version": "0.3.1",
4
4
  "description": "The front-end of @netless/fastboard-core.",
5
5
  "main": "dist/index.js",
6
6
  "svelte": "dist/index.svelte.mjs",
@@ -10,14 +10,14 @@
10
10
  ],
11
11
  "repository": "netless-io/fastboard",
12
12
  "peerDependencies": {
13
- "@netless/fastboard-core": "0.3.0-canary.6"
13
+ "@netless/fastboard-core": "0.3.1"
14
14
  },
15
15
  "dependencies": {
16
16
  "tippy.js": "^6.3.7"
17
17
  },
18
18
  "devDependencies": {
19
19
  "@netless/esbuild-plugin-inline-sass": "0.1.0",
20
- "@netless/fastboard-core": "0.3.0-canary.6"
20
+ "@netless/fastboard-core": "0.3.1"
21
21
  },
22
22
  "scripts": {
23
23
  "cleanup": "rimraf dist",
@@ -64,6 +64,7 @@ export function tippy_hide_all() {
64
64
 
65
65
  export const tippy_menu: Partial<Props> = {
66
66
  delay: 0,
67
+ duration: [50, 300],
67
68
  placement: "right-start",
68
69
  interactive: true,
69
70
  trigger: "click",
@@ -0,0 +1,70 @@
1
+ import type { FastboardApp } from "@netless/fastboard-core";
2
+ import code_editor_svg from "./icons/visual-studio-code.svg";
3
+ import geogebra_svg from "./icons/geogebra.svg";
4
+ import countdown_svg from "./icons/countdown.svg";
5
+
6
+ export interface AppInToolbar {
7
+ kind: string;
8
+ icon: string;
9
+ label: string;
10
+ onClick: (app: FastboardApp) => void;
11
+ }
12
+
13
+ class AppsInToolbar {
14
+ _listeners: Array<(data: AppInToolbar[]) => void> = [];
15
+ constructor(private _data: AppInToolbar[]) {}
16
+ get data() {
17
+ return this._data;
18
+ }
19
+ get length() {
20
+ return this._data.length;
21
+ }
22
+ subscribe(fn: (data: AppInToolbar[]) => void) {
23
+ this._listeners.push(fn);
24
+ fn(this._data);
25
+ return () => {
26
+ this._listeners = this._listeners.filter(item => item !== fn);
27
+ };
28
+ }
29
+ push(...data: AppInToolbar[]) {
30
+ this._data.push(...data);
31
+ this._listeners.forEach(fn => fn(this._data));
32
+ }
33
+ insert(data: AppInToolbar, index: number) {
34
+ this._data.splice(index, 0, data);
35
+ this._listeners.forEach(fn => fn(this._data));
36
+ }
37
+ delete(filter: (data: AppInToolbar) => boolean) {
38
+ this._data = this._data.filter(item => !filter(item));
39
+ this._listeners.forEach(fn => fn(this._data));
40
+ }
41
+ }
42
+
43
+ export type { AppsInToolbar };
44
+
45
+ export const apps = new AppsInToolbar([
46
+ {
47
+ kind: "Monaco",
48
+ icon: code_editor_svg,
49
+ label: "Code Editor",
50
+ onClick(app) {
51
+ app.insertCodeEditor();
52
+ },
53
+ },
54
+ {
55
+ kind: "GeoGebra",
56
+ icon: geogebra_svg,
57
+ label: "GeoGebra",
58
+ onClick(app) {
59
+ app.insertGeoGebra();
60
+ },
61
+ },
62
+ {
63
+ kind: "Countdown",
64
+ icon: countdown_svg,
65
+ label: "Countdown",
66
+ onClick(app) {
67
+ app.insertCountdown();
68
+ },
69
+ },
70
+ ]);
@@ -1,68 +1 @@
1
- import type { FastboardApp } from "@netless/fastboard-core";
2
- import code_editor_svg from "./icons/visual-studio-code.svg";
3
- import geogebra_svg from "./icons/geogebra.svg";
4
- import countdown_svg from "./icons/countdown.svg";
5
-
6
- export interface AppInToolbar {
7
- kind: string;
8
- icon: string;
9
- label: string;
10
- onClick: (app: FastboardApp) => void;
11
- }
12
-
13
- class AppsInToolbar {
14
- _listeners: Array<(data: AppInToolbar[]) => void> = [];
15
- constructor(private _data: AppInToolbar[]) {}
16
- get data() {
17
- return this._data;
18
- }
19
- get length() {
20
- return this._data.length;
21
- }
22
- subscribe(fn: (data: AppInToolbar[]) => void) {
23
- this._listeners.push(fn);
24
- fn(this._data);
25
- return () => {
26
- this._listeners = this._listeners.filter(item => item !== fn);
27
- };
28
- }
29
- push(data: AppInToolbar) {
30
- this._data.push(data);
31
- this._listeners.forEach(fn => fn(this._data));
32
- }
33
- insert(data: AppInToolbar, index: number) {
34
- this._data.splice(index, 0, data);
35
- this._listeners.forEach(fn => fn(this._data));
36
- }
37
- delete(filter: (data: AppInToolbar) => boolean) {
38
- this._data = this._data.filter(item => !filter(item));
39
- this._listeners.forEach(fn => fn(this._data));
40
- }
41
- }
42
-
43
- export const apps = new AppsInToolbar([
44
- {
45
- kind: "Monaco",
46
- icon: code_editor_svg,
47
- label: "Code Editor",
48
- onClick(app) {
49
- app.insertCodeEditor();
50
- },
51
- },
52
- {
53
- kind: "GeoGebra",
54
- icon: geogebra_svg,
55
- label: "GeoGebra",
56
- onClick(app) {
57
- app.insertGeoGebra();
58
- },
59
- },
60
- {
61
- kind: "Countdown",
62
- icon: countdown_svg,
63
- label: "Countdown",
64
- onClick(app) {
65
- app.insertCountdown();
66
- },
67
- },
68
- ]);
1
+ export * from "./apps";
@@ -21,6 +21,7 @@
21
21
  top: 8px;
22
22
  left: 0;
23
23
  z-index: 200;
24
+ pointer-events: none;
24
25
 
25
26
  .fastboard-toolbar {
26
27
  padding-left: 16px;
@@ -35,6 +36,7 @@
35
36
  left: 8px;
36
37
  padding: 8px;
37
38
  z-index: 200;
39
+ pointer-events: none;
38
40
  }
39
41
 
40
42
  .fastboard-bottom-right {
@@ -47,3 +49,13 @@
47
49
  @extend .fastboard-bottom-left;
48
50
  right: 8px;
49
51
  }
52
+
53
+ .fastboard-left,
54
+ .fastboard-bottom,
55
+ .fastboard-bottom-left,
56
+ .fastboard-bottom-right {
57
+ &.hidden * {
58
+ opacity: 0;
59
+ pointer-events: none;
60
+ }
61
+ }
@@ -14,8 +14,26 @@
14
14
  export let containerRef: ((element: HTMLDivElement | null) => void) | undefined = undefined;
15
15
 
16
16
  const name = "fastboard";
17
+ const AppsShowToolbar = ["DocsViewer", "Slide"];
17
18
 
18
19
  let container: HTMLDivElement;
20
+ let layout: "hidden" | "toolbar-only" | "visible" = "hidden";
21
+
22
+ $: writable = app?.writable;
23
+ $: boxState = app?.boxState;
24
+ $: focusedApp = app?.focusedApp;
25
+
26
+ $: if (!$writable) {
27
+ layout = "hidden";
28
+ } else if ($boxState === "maximized") {
29
+ if ($focusedApp && AppsShowToolbar.some(kind => ($focusedApp || "").includes(kind))) {
30
+ layout = "toolbar-only";
31
+ } else {
32
+ layout = "hidden";
33
+ }
34
+ } else {
35
+ layout = "visible";
36
+ }
19
37
 
20
38
  $: try {
21
39
  if (app && container) app.bindContainer(container);
@@ -24,6 +42,10 @@
24
42
  console.error(err);
25
43
  }
26
44
 
45
+ $: if (app && theme) {
46
+ app.manager.setPrefersColorScheme(theme);
47
+ }
48
+
27
49
  onMount(() => {
28
50
  if (containerRef) {
29
51
  containerRef(container);
@@ -36,14 +58,14 @@
36
58
 
37
59
  <div class="{name}-root" class:loading={!app}>
38
60
  <div class="{name}-view" bind:this={container} on:touchstart|capture={tippy_hide_all} />
39
- <div class="{name}-left">
61
+ <div class="{name}-left" class:hidden={!(layout === "visible" || layout === "toolbar-only")}>
40
62
  <Toolbar {app} {theme} {language} />
41
63
  </div>
42
- <div class="{name}-bottom-left">
64
+ <div class="{name}-bottom-left" class:hidden={layout !== "visible"}>
43
65
  <RedoUndo {app} {theme} {language} />
44
66
  <ZoomControl {app} {theme} {language} />
45
67
  </div>
46
- <div class="{name}-bottom-right">
68
+ <div class="{name}-bottom-right" class:hidden={layout !== "visible"}>
47
69
  <PageControl {app} {theme} {language} />
48
70
  </div>
49
71
  </div>
@@ -21,6 +21,10 @@
21
21
  console.error(err);
22
22
  }
23
23
 
24
+ $: if (player && theme) {
25
+ player.manager.setPrefersColorScheme(theme);
26
+ }
27
+
24
28
  onMount(() => {
25
29
  if (containerRef) {
26
30
  containerRef(container);
@@ -49,6 +49,7 @@
49
49
 
50
50
  function addPage() {
51
51
  app?.addPage({ after: true });
52
+ app?.nextPage();
52
53
  }
53
54
  </script>
54
55
 
@@ -46,7 +46,7 @@
46
46
  $: disabled = !canPlay;
47
47
  $: duration = player?.duration;
48
48
  $: current = player?.currentTime;
49
- $: speed = player?.speed;
49
+ $: playbackRate = player?.playbackRate;
50
50
 
51
51
  $: phase = player?.phase;
52
52
  $: loading = $phase === "waitingFirstFrame" || $phase === "buffering";
@@ -76,9 +76,9 @@
76
76
  player.seek(seconds * 1000);
77
77
  }
78
78
 
79
- function setSpeed(speed: number) {
79
+ function setPlaybackRate(speed: number) {
80
80
  if (!player) return;
81
- player.setSpeed(speed);
81
+ player.setPlaybackRate(speed);
82
82
  }
83
83
  </script>
84
84
 
@@ -132,7 +132,7 @@
132
132
  menu={speed_panel}
133
133
  menu_placement="top-end"
134
134
  >
135
- <span class="{name}-speed-text">{$speed}x</span>
135
+ <span class="{name}-speed-text">{$playbackRate || 1}x</span>
136
136
  </Button>
137
137
  </div>
138
138
 
@@ -140,11 +140,11 @@
140
140
  <div class="{name}-panel speed" bind:this={speed_panel}>
141
141
  {#each speeds as s (s)}
142
142
  <Button
143
- class="speed {s === $speed ? 'is-active' : ''}"
143
+ class="speed {s === $playbackRate ? 'is-active' : ''}"
144
144
  {name}
145
145
  {theme}
146
146
  {disabled}
147
- on:click={() => setSpeed(s)}
147
+ on:click={() => setPlaybackRate(s)}
148
148
  >
149
149
  {s}x
150
150
  </Button>
@@ -9,6 +9,7 @@ $name: "fastboard-toolbar";
9
9
  position: relative;
10
10
  transform: translateX(0);
11
11
  transition: transform 0.5s cubic-bezier(0.34, 1.56, 0.64, 1);
12
+ pointer-events: none;
12
13
 
13
14
  &.collapsed {
14
15
  transform: translateX(-100%);
@@ -21,6 +22,7 @@ $name: "fastboard-toolbar";
21
22
  width: 17px;
22
23
  font-size: 0;
23
24
  cursor: pointer;
25
+ pointer-events: auto;
24
26
 
25
27
  input[type="checkbox"] {
26
28
  position: absolute;
@@ -112,14 +112,15 @@ $name: "fastboard-toolbar";
112
112
 
113
113
  .#{$name}-panel.apps {
114
114
  display: grid;
115
- grid-template-columns: repeat(3, 1fr);
115
+ grid-template-columns: repeat(min(var(--n, 3), 3), minmax(max-content, 1fr));
116
116
  gap: 4px;
117
117
  }
118
118
 
119
119
  .#{$name}-app-btn {
120
120
  margin: 0;
121
121
  border: 0;
122
- padding: 4px;
122
+ border-radius: 2px;
123
+ padding: 4px 6px;
123
124
  background-color: transparent;
124
125
  display: inline-flex;
125
126
  flex-direction: column;
@@ -139,6 +140,7 @@ $name: "fastboard-toolbar";
139
140
 
140
141
  &-text {
141
142
  font-size: 14px;
143
+ line-height: 1;
142
144
  max-width: 100%;
143
145
  overflow: hidden;
144
146
  text-overflow: ellipsis;
@@ -172,8 +172,8 @@
172
172
  <div class="{name}-panel-divider" />
173
173
  <StrokeColor {app} {theme} {disabled} />
174
174
  </div>
175
- <div class="{name}-panel apps" bind:this={apps_panel}>
176
- {#each apps.data as netless_app (netless_app.kind)}
175
+ <div class="{name}-panel apps" style="--n:{$apps.length}" bind:this={apps_panel}>
176
+ {#each $apps as netless_app}
177
177
  {@const { icon, label, kind, onClick } = netless_app}
178
178
  {@const state = $status && $status[kind]}
179
179
  <button
@@ -45,6 +45,7 @@ $themes: (
45
45
  border-radius: 4px;
46
46
  font-size: 14px;
47
47
  font-family: system-ui;
48
+ pointer-events: auto;
48
49
  backdrop-filter: blur(5px);
49
50
  -webkit-backdrop-filter: blur(5px);
50
51