@netless/telebox-insider 0.3.0-beta.5 → 0.3.0-beta.7

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/telebox-insider",
3
- "version": "0.3.0-beta.5",
3
+ "version": "0.3.0-beta.7",
4
4
  "private": false,
5
5
  "description": "Window widget for Whiteboard",
6
6
  "author": "CRIMX <straybugs@gmail.com> (https://github.com/crimx/)",
@@ -69,7 +69,7 @@
69
69
  "react-dom": "^17.0.2",
70
70
  "react-refresh": "^0.8.3",
71
71
  "rimraf": "^3.0.0",
72
- "sass": "^1.36.0",
72
+ "sass": "^1.77.0",
73
73
  "sass-loader": "^10.1.1",
74
74
  "side-effect-manager": "0.1.5",
75
75
  "typescript": "^4.9.5",
@@ -0,0 +1,145 @@
1
+ import './style.scss';
2
+ import { TeleBoxManager } from '../TeleBoxManager';
3
+ import { TeleBoxColorScheme, TeleBoxState, TELE_BOX_STATE } from '..';
4
+
5
+ export type AppId = string;
6
+
7
+ export interface AppMenuProps {
8
+ manager: TeleBoxManager;
9
+ container: HTMLDivElement;
10
+ theme: TeleBoxColorScheme;
11
+ getBoxesStatus?: () => Map<string, TeleBoxState>;
12
+ }
13
+
14
+ export class AppMenu {
15
+ private readonly namespace: string = 'telebox-app-menu';
16
+ public readonly container: HTMLDivElement;
17
+ private readonly badge: HTMLDivElement = document.createElement('div');
18
+ private readonly menuView: HTMLDivElement = document.createElement('div');
19
+ private readonly manager: TeleBoxManager;
20
+ private theme: TeleBoxColorScheme;
21
+ private getBoxesStatus?: () => Map<string, TeleBoxState>;
22
+
23
+ constructor(props: AppMenuProps) {
24
+ this.container = props.container;
25
+ this.manager = props.manager;
26
+ this.theme = props.theme;
27
+ this.getBoxesStatus = props.getBoxesStatus;
28
+ this.init();
29
+ }
30
+
31
+ get boxesStatus(): Map<string, TeleBoxState> {
32
+ return this.getBoxesStatus?.() || new Map();
33
+ }
34
+
35
+ get minimizedBoxesStatus(): TeleBoxState[] {
36
+ const arr: TeleBoxState[] = [];
37
+ this.boxesStatus.forEach((status) => {
38
+ if (status === TELE_BOX_STATE.Minimized) {
39
+ arr.push(status);
40
+ }
41
+ });
42
+ return arr;
43
+ }
44
+
45
+ private c(className: string): string {
46
+ return `${this.namespace}-${className}`;
47
+ }
48
+
49
+ public containerClickHandler = () => {
50
+ if (this.manager.readonly) {
51
+ return;
52
+ }
53
+ const isShowMenuView = getComputedStyle(this.menuView).display === 'flex';
54
+ if (isShowMenuView) {
55
+ this.menuView.style.display = 'none';
56
+ } else {
57
+ this.menuView.style.display = 'flex';
58
+ }
59
+ };
60
+
61
+ private menuViewClickHandler = (e: MouseEvent | TouchEvent) => {
62
+ e.stopPropagation();
63
+ e.stopImmediatePropagation();
64
+ const target = e.target as HTMLElement;
65
+ const id = target.getAttribute(`data-${this.c('app-id')}`);
66
+ if (id) {
67
+ const lastNotMinimizedBoxStatus = this.manager.getLastNotMinimizedBoxStatus(id) || TELE_BOX_STATE.Normal;
68
+ const zIndex = (lastNotMinimizedBoxStatus===TELE_BOX_STATE.Maximized ? this.manager.getMaxMaximizedBoxZIndex() : this.manager.getMaxNormalBoxZIndex()) + 1;
69
+ this.manager.setBox(id, {
70
+ status: lastNotMinimizedBoxStatus,
71
+ zIndex
72
+ }, false, ()=>{
73
+ this.manager.focusBox(id);
74
+ })
75
+ return;
76
+ }
77
+ };
78
+
79
+ private createDefaultAppMenu(){
80
+ this.badge.classList.add(this.c('app-menu-badge'));
81
+ this.menuView.classList.add(this.c('app-menu-tooltip'));
82
+ this.container.classList.add(this.c('app-menu-container'), this.theme);
83
+ this.menuView.addEventListener('click', this.menuViewClickHandler);
84
+ this.container.append(this.badge, this.menuView);
85
+ }
86
+
87
+ private async init(){
88
+ this.createDefaultAppMenu();
89
+ this.appMenuChange();
90
+ }
91
+
92
+ updatePrefersColorSchemeHandler = () => {
93
+ this.container.classList.remove(this.theme);
94
+ this.theme = this.manager.prefersColorScheme;
95
+ this.container.classList.add(this.theme);
96
+ };
97
+
98
+ appMenuChange = () => {
99
+ const minimizedBoxesStatus = this.manager.getMinimizedBoxesStatus();
100
+ this.render(minimizedBoxesStatus);
101
+ }
102
+
103
+ private createMinimizedItem(appId: AppId){
104
+ const appItem = document.createElement('div');
105
+ appItem.classList.add(this.c('app-menu-item'));
106
+ console.log("appId=====>", appId);
107
+ appItem.setAttribute(`data-${this.c('app-id')}`, appId);
108
+ const titleDiv = document.createElement('div');
109
+ titleDiv.classList.add(this.c('app-menu-item-title'));
110
+ const app = this.manager.getBox(appId);
111
+ titleDiv.innerText = app?.title || appId;
112
+ appItem.appendChild(titleDiv);
113
+ return appItem;
114
+ }
115
+
116
+ private renderMenuView(minimizedBoxesStatus: Map<AppId, TELE_BOX_STATE.Minimized>){
117
+ const items: HTMLDivElement[] = [];
118
+ minimizedBoxesStatus.forEach((_, appId) => {
119
+ items.push(this.createMinimizedItem(appId));
120
+ });
121
+ this.menuView.append(...items);
122
+ }
123
+
124
+ render(minimizedBoxesStatus: Map<AppId, TELE_BOX_STATE.Minimized>) {
125
+ this.menuView.style.display = 'none';
126
+ this.badge.innerText = '';
127
+ this.menuView.innerHTML = '';
128
+ if (minimizedBoxesStatus.size === 0) {
129
+ this.container.style.display = 'none';
130
+ } else {
131
+ this.badge.innerText = minimizedBoxesStatus.size.toString();
132
+ this.renderMenuView(minimizedBoxesStatus);
133
+ this.container.style.display = 'block';
134
+ }
135
+ }
136
+ destroy(){
137
+
138
+ this.badge.remove();
139
+ this.menuView.removeEventListener('click', this.menuViewClickHandler);
140
+ this.menuView.remove();
141
+ this.container.remove();
142
+ // this.removeContainer();
143
+ }
144
+ }
145
+
@@ -0,0 +1,109 @@
1
+ $namespace: "telebox-app-menu";
2
+ .#{$namespace}-app-menu-container {
3
+ // &.dark {
4
+ // background-color: #43434d;
5
+ // color-scheme: dark;
6
+ // .#{$namespace}-app-menu-tooltip {
7
+ // background-color: #43434d;
8
+ // color-scheme: dark;
9
+ // .#{$namespace}-app-menu-item{
10
+ // color: #999;
11
+ // &:hover {
12
+ // background-color: #383b42;
13
+ // }
14
+ // &.active{
15
+ // color: #fff;
16
+ // }
17
+ // }
18
+ // }
19
+ // }
20
+ }
21
+ .#{$namespace}-app-menu-badge {
22
+ position: absolute;
23
+ right: 0;
24
+ top: 0;
25
+ z-index: 1;
26
+ width: auto;
27
+ height: 12px;
28
+ max-width: 100%;
29
+ overflow: hidden;
30
+ text-overflow: ellipsis;
31
+ white-space: nowrap;
32
+ color: #fff;
33
+ background-color: red;
34
+ border-radius: 6px;
35
+ padding: 0 4px;
36
+ font-size: 12px;
37
+ line-height: 12px;
38
+ text-align: center;
39
+ transform: scale(0.7);
40
+ }
41
+
42
+ .#{$namespace}-app-menu-tooltip {
43
+ position: absolute;
44
+ right: 0;
45
+ bottom: 0;
46
+ transform: translateY(-50px);
47
+ width: 100px;
48
+ height: auto;
49
+ display: flex;
50
+ flex-flow: column nowrap;
51
+ align-items: center;
52
+ justify-content: flex-end;
53
+ box-shadow: 0 2px 6px #2f419226;
54
+ border-radius: 4px;
55
+ padding: 3px 0;
56
+ background-color: #fff;
57
+ pointer-events: none;
58
+ }
59
+ .#{$namespace}-app-menu-item {
60
+ display: flex;
61
+ flex-flow: row nowrap;
62
+ align-items: center;
63
+ justify-content: space-between;
64
+ padding: 0 5px 0 15px;
65
+ box-sizing: border-box;
66
+ width: 100%;
67
+ pointer-events: auto;
68
+ color: #999;
69
+
70
+ &:hover {
71
+ background-color: #f0f0f0;
72
+ }
73
+
74
+ &.show-all,
75
+ &.hidden-all{
76
+ padding-left: 20px;
77
+ pointer-events: none;
78
+ background-size: 15%;
79
+ background-position-y: center;
80
+ background-position-x: 2px;
81
+ background-repeat: no-repeat;
82
+ }
83
+
84
+ &.active{
85
+ color: #333;
86
+ pointer-events: auto;
87
+ }
88
+
89
+ &.hidden-all{
90
+ background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB2aWV3Qm94PSIwIDAgMjggMjgiPgogICAgPGRlZnM+CiAgICAgICAgPHBhdGggaWQ9ImEiIGQ9Ik0wIDBoMjZ2MjZIMHoiIC8+CiAgICAgICAgPHBhdGggaWQ9ImMiIGQ9Ik0yNi44NjkgMEwyOCAxLjEzMVYyNi44N0wyNi44NjkgMjhIMS4xM0wwIDI2Ljg3VjEuMTMxTDEuMTMgMHoiIC8+CiAgICA8L2RlZnM+CiAgICA8ZyBmaWxsPSJub25lIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiPgogICAgICAgIDxnIHRyYW5zZm9ybT0idHJhbnNsYXRlKDEgMSkiPgogICAgICAgICAgICA8bWFzayBpZD0iYiIgZmlsbD0iI2ZmZiI+CiAgICAgICAgICAgICAgICA8dXNlIHhsaW5rOmhyZWY9IiNhIiAvPgogICAgICAgICAgICA8L21hc2s+CiAgICAgICAgICAgIDxwYXRoIGZpbGw9Im5vbmUiIGQ9Ik0tNC42NDI5LTQuNjQyOWgzNS4yODU4djM1LjI4NThILTQuNjQyOXoiIG1hc2s9InVybCgjYikiIC8+CiAgICAgICAgPC9nPgogICAgICAgIDxnPgogICAgICAgICAgICA8bWFzayBpZD0iZCIgZmlsbD0iI2ZmZiI+CiAgICAgICAgICAgICAgICA8dXNlIHhsaW5rOmhyZWY9IiNjIiAvPgogICAgICAgICAgICA8L21hc2s+CiAgICAgICAgICAgIDxwYXRoIGZpbGw9Im5vbmUiIGQ9Ik0tMTcuNTE2OCAxNEwxNC0xNy41MTY4IDQ1LjUxNjggMTQgMTQgNDUuNTE2OHoiIG1hc2s9InVybCgjZCkiIC8+CiAgICAgICAgPC9nPgogICAgICAgIDxwYXRoIHN0cm9rZT0iI0E3QTdDQSIgc3Ryb2tlLXdpZHRoPSIxLjIiCiAgICAgICAgICAgIGQ9Ik0xMC4wODg2IDIxLjQ4NjV2LTMuNjk2Nkg2LjM5Mk0yMS4zODU1IDEwLjE4OTVoLTMuNjk2NlY2LjQ5M00yMS40MDIgMTcuNzk4M2gtMy42OTY2djMuNjk2Nk0xMC4yNTAzIDYuMTQ5OHYzLjg5ODVINi4zNTE3IiAvPgogICAgPC9nPgo8L3N2Zz4K);
91
+ }
92
+
93
+ &.show-all{
94
+ border-top: 1px solid #ccc;
95
+ background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB2aWV3Qm94PSIwIDAgMjggMjgiPgogICAgPGRlZnM+CiAgICAgICAgPHBhdGggaWQ9ImEiIGQ9Ik0wIDBoMjh2MjhIMHoiIC8+CiAgICA8L2RlZnM+CiAgICA8ZyBmaWxsPSJub25lIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiPgogICAgICAgIDxtYXNrIGlkPSJiIiBmaWxsPSIjZmZmIj4KICAgICAgICAgICAgPHVzZSB4bGluazpocmVmPSIjYSIgLz4KICAgICAgICA8L21hc2s+CiAgICAgICAgPGcgZmlsbD0iI0E3QTdDQSIgZmlsbC1ydWxlPSJub256ZXJvIiBtYXNrPSJ1cmwoI2IpIj4KICAgICAgICAgICAgPHBhdGgKICAgICAgICAgICAgICAgIGQ9Ik0yMC40ODEgMTcuMWgxLjJ2NC41ODFIMTcuMXYtMS4yaDMuMzgxVjE3LjF6bS0xNC4xOTA1LS4wMDloMS4ydjMuMzgxaDMuMzgwOXYxLjJoLTQuNTgxdi00LjU4MXpNMTcuMSA2LjE5MDVoNC41ODF2NC41ODA5aC0xLjJ2LTMuMzgxSDE3LjF2LTEuMnptLTEwLjcwMDguMTA4N2g0Ljc5ODV2MS4ySDcuNTk5MnYzLjU5ODVoLTEuMlY2LjI5OTJ6IiAvPgogICAgICAgIDwvZz4KICAgIDwvZz4KPC9zdmc+Cg==);
96
+ }
97
+ }
98
+
99
+ .#{$namespace}-app-menu-item-title {
100
+ flex: 1;
101
+ overflow: hidden;
102
+ text-overflow: ellipsis;
103
+ white-space: nowrap;
104
+ font-size: 12px;
105
+ line-height: 20px;
106
+ text-align: left;
107
+ height: 20px;
108
+ pointer-events: none;
109
+ }
@@ -1,5 +1,5 @@
1
- @import "../scss/variables.scss";
2
- @import "../scss/mixins.scss";
1
+ @use "../scss/variables" as *;
2
+ @use "../scss/mixins" as *;
3
3
 
4
4
  .#{$namespace}-box {
5
5
  position: absolute;
@@ -1,6 +1,8 @@
1
1
  import "./style.scss";
2
2
  import collectorSVG from "./icons/collector.svg";
3
3
  import { TeleStyles } from "../typings";
4
+ import { TeleBoxState } from "../TeleBox/typings";
5
+ import { TELE_BOX_STATE } from "../TeleBox/constants";
4
6
 
5
7
  export interface TeleBoxCollectorConfig {
6
8
  visible?: boolean;
@@ -9,9 +11,11 @@ export interface TeleBoxCollectorConfig {
9
11
  namespace?: string;
10
12
  styles?: TeleStyles;
11
13
  onClick?: () => void;
14
+ getBoxesStatus?: () => Map<string, TeleBoxState>;
12
15
  }
13
16
 
14
17
  export class TeleBoxCollector {
18
+ public getBoxesStatus?: () => Map<string, TeleBoxState>;
15
19
  public constructor({
16
20
  visible = true,
17
21
  readonly = false,
@@ -19,13 +23,19 @@ export class TeleBoxCollector {
19
23
  namespace = "telebox",
20
24
  styles = {},
21
25
  onClick,
22
- }: TeleBoxCollectorConfig = {}) {
26
+ getBoxesStatus
27
+ }: TeleBoxCollectorConfig) {
23
28
  this._visible = visible;
24
29
  this._readonly = readonly;
25
30
  this._darkMode = darkMode;
26
31
  this.namespace = namespace;
27
32
  this.styles = styles;
28
33
  this.onClick = onClick;
34
+ this.getBoxesStatus = getBoxesStatus;
35
+ }
36
+
37
+ get boxesStatus(): Map<string, TeleBoxState> | undefined {
38
+ return this.getBoxesStatus?.();
29
39
  }
30
40
 
31
41
  public readonly styles: TeleStyles;
@@ -48,6 +58,9 @@ export class TeleBoxCollector {
48
58
 
49
59
  public $collector: HTMLElement | undefined;
50
60
 
61
+ public $appMenuContainer: HTMLDivElement = document.createElement('div');
62
+
63
+
51
64
  /**
52
65
  * Mount collector to a root element.
53
66
  */
@@ -66,6 +79,23 @@ export class TeleBoxCollector {
66
79
  return this;
67
80
  }
68
81
 
82
+ private hasMinimizedBox(): boolean {
83
+ const boxesStatus = this.boxesStatus;
84
+ if (boxesStatus) {
85
+ for (const status of boxesStatus.values()) {
86
+ if (status === TELE_BOX_STATE.Minimized) {
87
+ return true;
88
+ }
89
+ }
90
+ }
91
+ return false;
92
+ }
93
+
94
+ public updateBoxesStatus(): void {
95
+ const hasMinimizedBox = this.hasMinimizedBox();
96
+ this.setVisible(hasMinimizedBox);
97
+ }
98
+
69
99
  public setVisible(visible: boolean): this {
70
100
  if (this._visible !== visible) {
71
101
  this._visible = visible;
@@ -151,6 +181,9 @@ export class TeleBoxCollector {
151
181
  )
152
182
  );
153
183
 
184
+ this.$appMenuContainer.classList.add(this.wrapClassName("collector-shadow"));
185
+ this.$collector.append(this.$appMenuContainer);
186
+
154
187
  this.setStyles(this.styles);
155
188
  }
156
189
 
@@ -184,4 +217,5 @@ export class TeleBoxCollector {
184
217
  this.onClick();
185
218
  }
186
219
  };
220
+
187
221
  }
@@ -1,5 +1,5 @@
1
- @import "../scss/variables.scss";
2
- @import "../scss/mixins.scss";
1
+ @use "../scss/variables" as *;
2
+ @use "../scss/mixins" as *;
3
3
 
4
4
  .#{$namespace}-collector {
5
5
  @include no-user-select;
@@ -7,7 +7,7 @@
7
7
  visibility: hidden;
8
8
  display: block;
9
9
  position: absolute;
10
- z-index: $base-z-index * 2;
10
+ z-index: $base-z-index * 10;
11
11
  width: 40px;
12
12
  height: 40px;
13
13
  margin: 0;
@@ -43,3 +43,13 @@
43
43
  background-color: #43434d;
44
44
  }
45
45
  }
46
+
47
+ .#{$namespace}-collector-shadow {
48
+ position: absolute;
49
+ top: 0;
50
+ left: 0;
51
+ width: 100%;
52
+ height: 100%;
53
+ z-index: -1;
54
+ pointer-events: none;
55
+ }
@@ -16,8 +16,7 @@ export interface MaxTitleBarConfig extends DefaultTitleBarConfig {
16
16
  }
17
17
 
18
18
  export class MaxTitleBar extends DefaultTitleBar {
19
-
20
- public getBoxesStatus?: MaxTitleBarConfig["getBoxesStatus"];
19
+ public getBoxesStatus?: () => Map<string, TeleBoxState>;
21
20
  public constructor(config: MaxTitleBarConfig) {
22
21
  super(config);
23
22
 
@@ -27,6 +26,10 @@ export class MaxTitleBar extends DefaultTitleBar {
27
26
  this.darkMode = config.darkMode;
28
27
  this.getBoxesStatus = config.getBoxesStatus;
29
28
  }
29
+
30
+ get boxesStatus(): Map<string, TeleBoxState> | undefined {
31
+ return this.getBoxesStatus?.();
32
+ }
30
33
  public hasMaximizedBoxInStatus(): boolean {
31
34
  if (this.getBoxesStatus) {
32
35
  const boxesStatus = this.getBoxesStatus();
@@ -1,5 +1,5 @@
1
- @import "../../scss/variables.scss";
2
- @import "../../scss/mixins.scss";
1
+ @use "../../scss/variables" as *;
2
+ @use "../../scss/mixins" as *;
3
3
 
4
4
  $scrollbar-size: 8px;
5
5
  $scrollbar-ff-width: auto; // FF-only accepts auto, thin, none
@@ -16,7 +16,7 @@ $scrollbar-color-active: rgba(238, 238, 247, 1);
16
16
  position: absolute;
17
17
  top: 0;
18
18
  left: 0;
19
- z-index: $base-z-index * 500;
19
+ z-index: $base-z-index * 10;
20
20
 
21
21
  .#{$namespace}-title {
22
22
  display: none;