@operato/board 0.2.15

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 (69) hide show
  1. package/.storybook/main.js +3 -0
  2. package/.storybook/server.mjs +8 -0
  3. package/CHANGELOG.md +22 -0
  4. package/LICENSE +21 -0
  5. package/README.md +95 -0
  6. package/custom-elements.json +1377 -0
  7. package/demo/index-player.html +101 -0
  8. package/demo/index-viewer.html +101 -0
  9. package/demo/index.html +101 -0
  10. package/dist/src/index.d.ts +2 -0
  11. package/dist/src/index.js +3 -0
  12. package/dist/src/index.js.map +1 -0
  13. package/dist/src/ox-board-player copy.d.ts +39 -0
  14. package/dist/src/ox-board-player copy.js +258 -0
  15. package/dist/src/ox-board-player copy.js.map +1 -0
  16. package/dist/src/ox-board-player-control.d.ts +39 -0
  17. package/dist/src/ox-board-player-control.js +390 -0
  18. package/dist/src/ox-board-player-control.js.map +1 -0
  19. package/dist/src/ox-board-player-style.d.ts +1 -0
  20. package/dist/src/ox-board-player-style.js +200 -0
  21. package/dist/src/ox-board-player-style.js.map +1 -0
  22. package/dist/src/ox-board-player.d.ts +39 -0
  23. package/dist/src/ox-board-player.js +284 -0
  24. package/dist/src/ox-board-player.js.map +1 -0
  25. package/dist/src/ox-board-viewer.d.ts +45 -0
  26. package/dist/src/ox-board-viewer.js +491 -0
  27. package/dist/src/ox-board-viewer.js.map +1 -0
  28. package/dist/src/ox-board-wrapper.d.ts +1 -0
  29. package/dist/src/ox-board-wrapper.js +88 -0
  30. package/dist/src/ox-board-wrapper.js.map +1 -0
  31. package/dist/src/player/board-player-carousel.d.ts +1 -0
  32. package/dist/src/player/board-player-carousel.js +205 -0
  33. package/dist/src/player/board-player-carousel.js.map +1 -0
  34. package/dist/src/player/board-player-grid.d.ts +1 -0
  35. package/dist/src/player/board-player-grid.js +78 -0
  36. package/dist/src/player/board-player-grid.js.map +1 -0
  37. package/dist/src/utils/fullscreen.d.ts +14 -0
  38. package/dist/src/utils/fullscreen.js +69 -0
  39. package/dist/src/utils/fullscreen.js.map +1 -0
  40. package/dist/src/utils/os.d.ts +20 -0
  41. package/dist/src/utils/os.js +41 -0
  42. package/dist/src/utils/os.js.map +1 -0
  43. package/dist/src/utils/swipe-listener.d.ts +10 -0
  44. package/dist/src/utils/swipe-listener.js +257 -0
  45. package/dist/src/utils/swipe-listener.js.map +1 -0
  46. package/dist/stories/index.stories.d.ts +33 -0
  47. package/dist/stories/index.stories.js +33 -0
  48. package/dist/stories/index.stories.js.map +1 -0
  49. package/dist/test/board-viewer.test.d.ts +1 -0
  50. package/dist/test/board-viewer.test.js +24 -0
  51. package/dist/test/board-viewer.test.js.map +1 -0
  52. package/dist/tsconfig.tsbuildinfo +1 -0
  53. package/package.json +76 -0
  54. package/src/index.ts +2 -0
  55. package/src/ox-board-player-style.ts +200 -0
  56. package/src/ox-board-player.ts +292 -0
  57. package/src/ox-board-viewer.ts +534 -0
  58. package/src/ox-board-wrapper.ts +93 -0
  59. package/src/player/board-player-carousel.ts +197 -0
  60. package/src/player/board-player-grid.ts +78 -0
  61. package/src/utils/fullscreen.ts +82 -0
  62. package/src/utils/os.ts +41 -0
  63. package/src/utils/swipe-listener.ts +290 -0
  64. package/src/utils/things-scene.d.ts +1 -0
  65. package/stories/index.stories.ts +52 -0
  66. package/test/board-viewer.test.ts +35 -0
  67. package/tsconfig.json +22 -0
  68. package/web-dev-server.config.mjs +28 -0
  69. package/web-test-runner.config.mjs +29 -0
@@ -0,0 +1,200 @@
1
+ import { css } from 'lit-element'
2
+
3
+ export const style = css`
4
+ :host {
5
+ display: flex;
6
+ position: relative;
7
+ flex-direction: column;
8
+ width: 100%;
9
+ height: 100%;
10
+ overflow: hidden;
11
+ justify-content: center;
12
+ align-items: center;
13
+ }
14
+
15
+ ::slotted(*) {
16
+ border: none;
17
+ }
18
+
19
+ ::slotted > * {
20
+ flex: 1;
21
+ }
22
+
23
+ board-wrapper {
24
+ width: 100%;
25
+ height: 100%;
26
+ position: relative;
27
+ }
28
+
29
+ board-wrapper[front] {
30
+ background: black;
31
+ }
32
+
33
+ board-wrapper[back] {
34
+ background: black;
35
+ }
36
+
37
+ #control {
38
+ position: absolute;
39
+ bottom: 1vh;
40
+ width: 100vw;
41
+ max-width: 435px;
42
+ display: grid;
43
+ grid-template-columns: 42px 42px 1fr;
44
+ color: white;
45
+ justify-content: center;
46
+ align-items: center;
47
+ grid-auto-flow: dense;
48
+ padding: 5px;
49
+ box-sizing: border-box;
50
+ grid-template-rows: 12px 60px 12px;
51
+ }
52
+
53
+ #control[hidden] {
54
+ display: none;
55
+ }
56
+
57
+ #control > div > * {
58
+ cursor: pointer;
59
+ user-select: none;
60
+ }
61
+
62
+ #joystick {
63
+ position: relative;
64
+ box-sizing: border-box;
65
+ border: 2px solid tomato;
66
+ background-color: #c34827;
67
+ box-shadow: 0 0 5px #000;
68
+ width: 100%;
69
+ height: 100%;
70
+ grid-column: 1 / span 2;
71
+ border-radius: 50%;
72
+ z-index: 2;
73
+ grid-row: 1 / span 3;
74
+ }
75
+
76
+ #joystick mwc-icon {
77
+ position: absolute;
78
+ display: block;
79
+ width: 20px;
80
+ height: 20px;
81
+ font-size: 25px;
82
+ line-height: 0.7;
83
+ }
84
+
85
+ mwc-icon#up {
86
+ left: 29px;
87
+ }
88
+
89
+ mwc-icon#left {
90
+ top: 32px;
91
+ left: -2px;
92
+ }
93
+
94
+ mwc-icon#play,
95
+ mwc-icon#pause {
96
+ left: 20px;
97
+ top: 20px;
98
+ width: 40px;
99
+ height: 40px;
100
+ border: 1px solid rgba(0, 0, 0, 0.15);
101
+ border-radius: 50%;
102
+ background-color: rgba(0, 0, 0, 0.15);
103
+ font-size: 45px;
104
+ line-height: 0.9;
105
+ }
106
+
107
+ mwc-icon#right {
108
+ top: 31px;
109
+ left: 60px;
110
+ }
111
+
112
+ mwc-icon#down {
113
+ left: 29px;
114
+ top: 63px;
115
+ }
116
+
117
+ mwc-icon#pause {
118
+ text-indent: -2px;
119
+ }
120
+
121
+ #setting-container {
122
+ grid-column: 2 / span 2;
123
+ grid-row: 2;
124
+ gap: 0 10px;
125
+ border-radius: 12px;
126
+ background: rgba(0, 0, 0, 0.7);
127
+ height: 100%;
128
+ box-shadow: rgb(0, 0, 0) 0px 0px 5px;
129
+ display: grid;
130
+ grid-template-columns: 1fr 60px;
131
+ align-items: center;
132
+ padding-left: 60px;
133
+ padding-right: 5px;
134
+ }
135
+
136
+ #setting {
137
+ display: grid;
138
+ grid-template-columns: 1fr 1fr;
139
+ grid-gap: 0 10px;
140
+ }
141
+
142
+ #setting mwc-icon {
143
+ font-size: 22px;
144
+ color: rgba(255, 174, 53, 0.8);
145
+ }
146
+
147
+ #setting input {
148
+ width: 50px;
149
+ margin-right: 5px;
150
+ font-size: 14px;
151
+ background-color: transparent;
152
+ border: none;
153
+ border-bottom: 1px solid #fff;
154
+ color: #fff;
155
+ text-align: right;
156
+ }
157
+
158
+ #setting select {
159
+ border: none;
160
+ font-size: 14px;
161
+ }
162
+
163
+ #setting input:focus {
164
+ outline: none;
165
+ }
166
+
167
+ #schedule-container {
168
+ display: flex;
169
+ align-items: center;
170
+ justify-content: space-between;
171
+ }
172
+
173
+ #grid-setting-container {
174
+ display: flex;
175
+ align-items: center;
176
+ justify-content: space-between;
177
+ }
178
+
179
+ #etc {
180
+ display: grid;
181
+ grid-template-columns: 1fr 1fr;
182
+ align-items: center;
183
+ justify-items: center;
184
+ }
185
+
186
+ #etc mwc-icon {
187
+ font-size: 30px;
188
+ }
189
+
190
+ #control [hidden] {
191
+ display: none;
192
+ }
193
+
194
+ @media screen and (max-width: 460px) {
195
+ #setting {
196
+ grid-template-columns: 1fr;
197
+ grid-template-rows: 1fr 1fr;
198
+ }
199
+ }
200
+ `
@@ -0,0 +1,292 @@
1
+ import '@material/mwc-fab'
2
+ import '@material/mwc-icon'
3
+ import './ox-board-wrapper'
4
+ import './player/board-player-carousel'
5
+
6
+ import { LitElement, PropertyValues, html } from 'lit'
7
+ import { customElement, property, query, state } from 'lit/decorators.js'
8
+ import { exitfullscreen, togglefullscreen } from './utils/fullscreen'
9
+
10
+ import { SwipeListener } from './utils/swipe-listener'
11
+ import { style } from './ox-board-player-style'
12
+
13
+ @customElement('ox-board-player')
14
+ export class BoardPlayer extends LitElement {
15
+ static styles = style
16
+
17
+ @property({ type: Array }) boards: Array<any> = []
18
+ @property({ type: Number }) playtime = 30
19
+ @property({ type: Number }) columns = 1
20
+ @property({ type: Number }) rows = 1
21
+ @property({ type: Boolean }) started = false
22
+ @property({ type: Boolean }) playing = false
23
+ @property({ type: Object }) provider: any
24
+
25
+ @state() _controlAnimation?: Animation
26
+ @state() _transferTimer?: any
27
+ @state() _currentPlayer?: any
28
+ @state() _fullscreened = false
29
+
30
+ @query('#control') _control!: HTMLElement
31
+
32
+ render() {
33
+ return html`
34
+ <slot @mousemove=${() => this.onMousemove()} @transform=${() => this.onTransform()} tabindex="-1">
35
+ ${this.started
36
+ ? html`
37
+ <ox-board-player-carousel axis="y" .rows=${this.rows} .columns=${this.columns} player>
38
+ ${this.boards.map(
39
+ item =>
40
+ html` <ox-board-wrapper page .sceneId=${item.id} .provider=${this.provider}> </ox-board-wrapper> `
41
+ )}
42
+ </ox-board-player-carousel>
43
+ `
44
+ : html``}
45
+ </slot>
46
+
47
+ <div id="control" @mouseover=${() => this.onMouseoverControl()} hidden>
48
+ <div id="joystick">
49
+ <mwc-icon id="up" @click=${() => this.moveUp()}>keyboard_arrow_up</mwc-icon>
50
+ <mwc-icon id="left" @click=${() => this.moveLeft()}>keyboard_arrow_left</mwc-icon>
51
+ <mwc-icon id="play" @click=${() => this.play()} ?hidden=${this.playing}>play_arrow</mwc-icon>
52
+ <mwc-icon id="pause" @click=${() => this.pause()} ?hidden=${!this.playing}>pause</mwc-icon>
53
+ <mwc-icon id="right" @click=${() => this.moveRight()}>keyboard_arrow_right</mwc-icon>
54
+ <mwc-icon id="down" @click=${() => this.moveDown()}>keyboard_arrow_down</mwc-icon>
55
+ </div>
56
+
57
+ <div id="setting-container">
58
+ <div id="setting">
59
+ <label id="schedule-container">
60
+ <mwc-icon id="schedule">schedule</mwc-icon>
61
+ <input
62
+ .value=${this.playtime}
63
+ @change=${(e: Event) => (this.playtime = Number((e.target as HTMLInputElement).value))}
64
+ />
65
+ sec.
66
+ </label>
67
+ <div id="grid-setting-container">
68
+ <mwc-icon id="view_module">view_module</mwc-icon>
69
+ <select
70
+ .value=${this.rows}
71
+ @change=${(e: Event) => (this.rows = Number((e.target as HTMLInputElement).value))}
72
+ >
73
+ ${[1, 2, 3, 4, 5].map(row => html` <option>${row}</option> `)}
74
+ </select>
75
+ x
76
+ <select
77
+ .value=${this.columns}
78
+ @change=${(e: Event) => (this.columns = Number((e.target as HTMLInputElement).value))}
79
+ >
80
+ ${[1, 2, 3, 4, 5].map(column => html` <option>${column}</option> `)}
81
+ </select>
82
+ </div>
83
+ </div>
84
+
85
+ <div id="etc">
86
+ <mwc-icon id="fullscreen" @click=${() => this.onTapFullscreen()} ?hidden=${this._fullscreened}
87
+ >fullscreen</mwc-icon
88
+ >
89
+ <mwc-icon id="fullscreen-exit" @click=${() => this.onTapFullscreen()} ?hidden=${!this._fullscreened}
90
+ >fullscreen_exit</mwc-icon
91
+ >
92
+ <mwc-icon id="close" @click=${() => this.onTapClose()}>close</mwc-icon>
93
+ </div>
94
+ </div>
95
+ </div>
96
+ `
97
+ }
98
+
99
+ firstUpdated() {
100
+ SwipeListener(this)
101
+
102
+ this.addEventListener('swipe', (e: Event) => {
103
+ var directions = (e as any).detail.directions
104
+
105
+ if (directions.left) {
106
+ this.moveRight()
107
+ } else if (directions.right) {
108
+ this.moveLeft()
109
+ } else if (directions.top) {
110
+ this.moveDown()
111
+ } else if (directions.bottom) {
112
+ this.moveUp()
113
+ }
114
+ })
115
+
116
+ this.setAttribute('tabindex', '0')
117
+ this.addEventListener('keydown', (e: KeyboardEvent) => {
118
+ switch (e.key) {
119
+ case 'Right': // for IE/Edge
120
+ case 'ArrowRight':
121
+ e.stopPropagation()
122
+ this.moveRight()
123
+ break
124
+
125
+ case 'Left': // for IE/Edge
126
+ case 'ArrowLeft':
127
+ e.stopPropagation()
128
+ this.moveLeft()
129
+ break
130
+
131
+ case 'Up': // for IE/Edge
132
+ case 'ArrowUp':
133
+ e.stopPropagation()
134
+ this.moveUp()
135
+ break
136
+
137
+ case 'Down': // for IE/Edge
138
+ case 'ArrowDown':
139
+ e.stopPropagation()
140
+ this.moveDown()
141
+ break
142
+ }
143
+ })
144
+
145
+ this.focus()
146
+ }
147
+
148
+ updated(changes: PropertyValues<this>) {
149
+ if (changes.has('boards') || changes.has('columns') || changes.has('rows')) {
150
+ this.boards && this.boards.length > 0 ? this.restart() : this.stop()
151
+ } else if (changes.has('playtime') && this.playing) {
152
+ this._resetTransformTimer()
153
+ }
154
+ }
155
+
156
+ async _resetFadeTimer(stop?: boolean) {
157
+ if (!this._controlAnimation) {
158
+ this._controlAnimation = this._control.animate(
159
+ [
160
+ {
161
+ opacity: 1,
162
+ easing: 'ease-in'
163
+ },
164
+ { opacity: 0 }
165
+ ],
166
+ { delay: 1000, duration: 2000 }
167
+ )
168
+ }
169
+
170
+ this._control.hidden = false
171
+
172
+ this._controlAnimation.cancel()
173
+ if (stop) return
174
+
175
+ try {
176
+ this._controlAnimation.play()
177
+ await this._controlAnimation.finished
178
+ this._control.hidden = true
179
+ } catch (e) {
180
+ /* cancelled */
181
+ }
182
+ }
183
+
184
+ _resetTransformTimer() {
185
+ clearTimeout(this._transferTimer)
186
+
187
+ this.playing = true
188
+
189
+ if (this._currentPlayer) {
190
+ this._transferTimer = setTimeout(() => {
191
+ if (this._transferTimer) this._currentPlayer.next()
192
+ }, this.playtime * 1000)
193
+ }
194
+ }
195
+
196
+ onMousemove() {
197
+ this._resetFadeTimer()
198
+ }
199
+
200
+ onMouseoverControl() {
201
+ this._resetFadeTimer(true)
202
+ }
203
+
204
+ onTapFullscreen() {
205
+ togglefullscreen(
206
+ this,
207
+ () => {
208
+ this._fullscreened = true
209
+ this.focus()
210
+ },
211
+ () => {
212
+ this._fullscreened = false
213
+ this.focus()
214
+ }
215
+ )
216
+ }
217
+
218
+ onTransform() {
219
+ requestAnimationFrame(() => this.started && this.playing && this._resetTransformTimer())
220
+ }
221
+
222
+ play() {
223
+ this._resetTransformTimer()
224
+ }
225
+
226
+ pause() {
227
+ clearTimeout(this._transferTimer)
228
+ this.playing = false
229
+ }
230
+
231
+ moveLeft() {
232
+ this._currentPlayer.axis = 'y'
233
+ this._currentPlayer.previous()
234
+ }
235
+
236
+ moveRight() {
237
+ this._currentPlayer.axis = 'y'
238
+ this._currentPlayer.next()
239
+ }
240
+
241
+ moveUp() {
242
+ this._currentPlayer.axis = 'x'
243
+ this._currentPlayer.next()
244
+ }
245
+
246
+ moveDown() {
247
+ this._currentPlayer.axis = 'x'
248
+ this._currentPlayer.previous()
249
+ }
250
+
251
+ onTapClose() {
252
+ if (this._fullscreened) {
253
+ exitfullscreen()
254
+ }
255
+
256
+ window.history.back()
257
+ }
258
+
259
+ async restart() {
260
+ await this.stop()
261
+ await this.start()
262
+ }
263
+
264
+ async start() {
265
+ if (!this.boards || this.boards.length == 0) return
266
+
267
+ this.started = true
268
+ this.playing = true
269
+
270
+ await this.updateComplete
271
+
272
+ this._currentPlayer = this.renderRoot.querySelector(':not([style*="display: none"])[player]')
273
+
274
+ this._resetTransformTimer()
275
+ this._resetFadeTimer()
276
+
277
+ this.focus()
278
+ }
279
+
280
+ async stop() {
281
+ clearTimeout(this._transferTimer)
282
+
283
+ this._currentPlayer && this._currentPlayer.stop()
284
+ this.started = false
285
+
286
+ /**
287
+ * this.started = false 로 인한 update를 강제하기 위함임.
288
+ * this.start() 가 바로 호출되어 this.started 의 변화가 render에 반영되지 않을 수 있으므로.
289
+ */
290
+ await this.updateComplete
291
+ }
292
+ }