@operato/board 8.0.0-alpha.2 → 8.0.0-alpha.20

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": "@operato/board",
3
- "version": "8.0.0-alpha.2",
3
+ "version": "8.0.0-alpha.20",
4
4
  "description": "Webcomponent for board following open-wc recommendations",
5
5
  "author": "heartyoh",
6
6
  "main": "dist/src/index.js",
@@ -26,6 +26,7 @@
26
26
  "./ox-board-list.js": "./dist/src/ox-board-list.js",
27
27
  "./ox-board-template-list.js": "./dist/src/ox-board-template-list.js",
28
28
  "./ox-board-viewer.js": "./dist/src/ox-board-viewer.js",
29
+ "./ox-board-template-viewer.js": "./dist/src/ox-board-template-viewer.js",
29
30
  "./ox-board-player.js": "./dist/src/ox-board-player.js",
30
31
  "./ox-board-modeller.js": "./dist/src/ox-board-modeller.js",
31
32
  "./ox-editor-board-selector.js": "./dist/src/ox-editor-board-selector.js",
@@ -57,6 +58,9 @@
57
58
  "ox-board-viewer.js": [
58
59
  "./dist/src/ox-board-viewer.d.ts"
59
60
  ],
61
+ "ox-board-template-viewer.js": [
62
+ "./dist/src/ox-board-template-viewer.d.ts"
63
+ ],
60
64
  "ox-board-player.js": [
61
65
  "./dist/src/ox-board-player.d.ts"
62
66
  ],
@@ -95,17 +99,17 @@
95
99
  "dependencies": {
96
100
  "@material/web": "^2.0.0",
97
101
  "@open-wc/scoped-elements": "^2.1.3",
98
- "@operato/app": "^8.0.0-alpha.2",
99
- "@operato/data-grist": "^8.0.0-alpha.2",
100
- "@operato/font": "^8.0.0-alpha.2",
102
+ "@operato/app": "^8.0.0-alpha.20",
103
+ "@operato/data-grist": "^8.0.0-alpha.20",
104
+ "@operato/font": "^8.0.0-alpha.20",
101
105
  "@operato/graphql": "^8.0.0-alpha.0",
102
106
  "@operato/i18n": "^8.0.0-alpha.0",
103
- "@operato/input": "^8.0.0-alpha.2",
104
- "@operato/layout": "^8.0.0-alpha.0",
105
- "@operato/markdown": "^8.0.0-alpha.0",
106
- "@operato/popup": "^8.0.0-alpha.0",
107
- "@operato/property-editor": "^8.0.0-alpha.2",
108
- "@operato/styles": "^8.0.0-alpha.0",
107
+ "@operato/input": "^8.0.0-alpha.20",
108
+ "@operato/layout": "^8.0.0-alpha.4",
109
+ "@operato/markdown": "^8.0.0-alpha.4",
110
+ "@operato/popup": "^8.0.0-alpha.4",
111
+ "@operato/property-editor": "^8.0.0-alpha.20",
112
+ "@operato/styles": "^8.0.0-alpha.4",
109
113
  "@operato/utils": "^8.0.0-alpha.0",
110
114
  "@polymer/paper-dropdown-menu": "^3.2.0",
111
115
  "@types/file-saver": "^2.0.4",
@@ -123,8 +127,8 @@
123
127
  "@hatiolab/things-scene": "^8.0.0-alpha",
124
128
  "@open-wc/eslint-config": "^12.0.3",
125
129
  "@open-wc/testing": "^3.1.6",
126
- "@rollup/plugin-image": "^2.1.1",
127
- "@rollup/plugin-json": "^4.1.0",
130
+ "@rollup/plugin-image": "^3.0.3",
131
+ "@rollup/plugin-json": "^6.1.0",
128
132
  "@types/lodash-es": "^4.17.6",
129
133
  "@types/w3c-web-usb": "^1.0.5",
130
134
  "@typescript-eslint/eslint-plugin": "^7.0.1",
@@ -155,5 +159,5 @@
155
159
  "prettier --write"
156
160
  ]
157
161
  },
158
- "gitHead": "868f7fd1dfcf1758b0fd8f8c7f198489b3b3bbf8"
162
+ "gitHead": "c8a1305148d5f9190d79f7107001455e46906b8e"
159
163
  }
package/src/index.ts CHANGED
@@ -7,3 +7,4 @@ export * from './ox-board-viewer.js'
7
7
  export * from './ox-board-player.js'
8
8
  export * from './ox-board-modeller.js'
9
9
  export * from './ox-board-list.js'
10
+ export * from './ox-board-template-viewer.js'
@@ -301,7 +301,9 @@ export class BoardPlayer extends LitElement {
301
301
  }
302
302
 
303
303
  async start() {
304
- if (!this.boards || this.boards.length == 0) return
304
+ if (!this.boards || this.boards.length == 0) {
305
+ return
306
+ }
305
307
 
306
308
  this.started = true
307
309
  this.playing = true
@@ -0,0 +1,198 @@
1
+ import '@material/web/icon/icon.js'
2
+ import '@material/web/fab/fab.js'
3
+
4
+ import { css, html, LitElement, PropertyValues } from 'lit'
5
+ import { customElement, property, query, state } from 'lit/decorators.js'
6
+
7
+ import { create, SCENE_MODE } from '@hatiolab/things-scene'
8
+ import { ScrollbarStyles } from '@operato/styles'
9
+
10
+ @customElement('ox-board-template-viewer')
11
+ export class BoardTemplateViewer extends LitElement {
12
+ static styles = [
13
+ ScrollbarStyles,
14
+ css`
15
+ :host {
16
+ display: flex;
17
+ flex-direction: column;
18
+
19
+ position: relative;
20
+
21
+ width: 100%; /* 전체화면보기를 위해서 필요함. */
22
+ overflow: hidden;
23
+ }
24
+
25
+ #target {
26
+ flex: 1;
27
+
28
+ width: 100%; /* 전체화면보기를 위해서 필요함. */
29
+ height: 100%;
30
+
31
+ outline: 0;
32
+ }
33
+
34
+ @media print {
35
+ md-fab,
36
+ md-icon {
37
+ display: none;
38
+ }
39
+ }
40
+ `
41
+ ]
42
+
43
+ @property({ type: Object }) boardTemplate: any = {}
44
+
45
+ @state() _scene: any = null
46
+
47
+ @query('#target') _target!: HTMLElement
48
+
49
+ render() {
50
+ return html` <div id="target"></div> `
51
+ }
52
+
53
+ private resizeHandler = () => {
54
+ this._scene && this._scene.fit()
55
+ }
56
+
57
+ connectedCallback() {
58
+ super.connectedCallback()
59
+
60
+ window.addEventListener('resize', this.resizeHandler)
61
+
62
+ window.addEventListener('orientationchange', this.resizeHandler)
63
+ }
64
+
65
+ disconnectedCallback() {
66
+ window.removeEventListener('resize', this.resizeHandler)
67
+ window.removeEventListener('orientationchange', this.resizeHandler)
68
+
69
+ super.disconnectedCallback()
70
+
71
+ this.closeScene()
72
+ }
73
+
74
+ updated(changes: PropertyValues<this>) {
75
+ if (changes.has('boardTemplate')) {
76
+ this.closeScene()
77
+
78
+ if (this.boardTemplate && this.boardTemplate.id) {
79
+ this.initScene()
80
+ }
81
+ }
82
+ }
83
+
84
+ initScene() {
85
+ if (!this.boardTemplate || !this.boardTemplate.id) return
86
+
87
+ this._scene = create({
88
+ model: {
89
+ ...this.boardTemplate.model
90
+ },
91
+ mode: SCENE_MODE.VIEW
92
+ })
93
+
94
+ this.setupScene({ id: this.boardTemplate.id, scene: this._scene })
95
+ }
96
+
97
+ closeScene() {
98
+ if (this._scene) {
99
+ this._scene.target = null
100
+ this._scene.release && this._scene.release()
101
+
102
+ this._scene = null
103
+ }
104
+ }
105
+
106
+ releaseScene() {
107
+ this.closeScene()
108
+ }
109
+
110
+ setupScene({ id, scene }: { id: string; scene: any }) {
111
+ this._scene = scene
112
+
113
+ const backgroundColor = this._scene?.root.state.fillStyle
114
+ if (typeof backgroundColor === 'string') {
115
+ this.style.backgroundColor = backgroundColor
116
+ } else {
117
+ this.style.backgroundColor = 'initial'
118
+ }
119
+
120
+ /* scene의 기존 target을 보관한다. */
121
+
122
+ this._scene.fit(this._scene.fitMode)
123
+ this._scene.target = this._target
124
+ }
125
+
126
+ /* event handlers */
127
+ async getSceneImageData(base64 = false) {
128
+ if (!this._scene) {
129
+ return
130
+ }
131
+
132
+ var { width, height } = this._scene.model
133
+ var pixelRatio = window.devicePixelRatio
134
+
135
+ // 1. Scene의 바운드에 근거하여, 오프스크린 캔바스를 만든다.
136
+ var canvas = document.createElement('canvas')
137
+ canvas.width = Number(width)
138
+ canvas.height = Number(height)
139
+
140
+ var root = this._scene.root
141
+ // 2. 모델레이어의 원래 위치와 스케일을 저장한다.
142
+ var translate = root.get('translate')
143
+ var scale = root.get('scale')
144
+
145
+ // 3. 위치와 스케일 기본 설정.
146
+ root.set('translate', { x: 0, y: 0 })
147
+ root.set('scale', { x: 1 / pixelRatio, y: 1 / pixelRatio })
148
+
149
+ // 4. 오프스크린 캔바스의 Context2D를 구한뒤, 모델레이어를 그 위에 그린다.
150
+ var context = canvas.getContext('2d')
151
+
152
+ root.draw(context)
153
+
154
+ root.set('translate', translate)
155
+ root.set('scale', scale)
156
+
157
+ var data = base64 ? canvas.toDataURL() : context!.getImageData(0, 0, width, height).data
158
+
159
+ return {
160
+ width,
161
+ height,
162
+ data
163
+ }
164
+ }
165
+
166
+ async printTrick(image: string) {
167
+ var viewTarget: HTMLElement | null = null
168
+ var printTarget: HTMLImageElement | null = null
169
+
170
+ if (!image) {
171
+ image = (await this.getSceneImageData(true))?.data as string
172
+ }
173
+
174
+ printTarget = document.createElement('img')
175
+ printTarget.id = 'target'
176
+ printTarget.src = image
177
+ printTarget.style.width = '100%'
178
+ printTarget.style.height = '100%'
179
+
180
+ const x = (mql: MediaQueryListEvent) => {
181
+ if (mql.matches) {
182
+ if (!viewTarget) {
183
+ viewTarget = (this.renderRoot as ShadowRoot)!.getElementById('target')
184
+ this.renderRoot.replaceChild(printTarget!, viewTarget!)
185
+ }
186
+ } else {
187
+ this.renderRoot.replaceChild(viewTarget!, printTarget!)
188
+ printTarget!.remove()
189
+ mediaQueryList.removeEventListener('change', x)
190
+ }
191
+ }
192
+
193
+ if (window.matchMedia) {
194
+ var mediaQueryList = window.matchMedia('print')
195
+ mediaQueryList.addEventListener('change', x)
196
+ }
197
+ }
198
+ }
@@ -81,6 +81,8 @@ class BoardWrapper extends LitElement {
81
81
  }
82
82
 
83
83
  _onBoardChanged() {
84
+ this.closeScene()
85
+
84
86
  this.initScene()
85
87
  }
86
88
 
@@ -138,7 +140,7 @@ class BoardWrapper extends LitElement {
138
140
  this._scene.target = this._targetEl
139
141
 
140
142
  requestAnimationFrame(() => {
141
- if (this._scene.target.offsetWidth) {
143
+ if (this._scene?.target.offsetWidth) {
142
144
  this._scene.fit()
143
145
  }
144
146
  })
@@ -1,3 +1,4 @@
1
+ import '@operato/input/ox-input-search.js'
1
2
  import './ox-board-creation-card'
2
3
 
3
4
  import gql from 'graphql-tag'
@@ -9,6 +10,7 @@ import { i18next, localize } from '@operato/i18n'
9
10
  import { ScrollbarStyles } from '@operato/styles'
10
11
  import InfiniteScrollable from '@operato/utils/mixins/infinite-scrollable.js'
11
12
  import { InheritedValueType } from '@operato/shell'
13
+ import { adjustFilters } from '@operato/utils'
12
14
 
13
15
  const FETCH_BOARD_LIST_GQL = gql`
14
16
  query ($filters: [Filter!], $pagination: Pagination, $sortings: [Sorting!], $inherited: InheritedValueType) {
@@ -97,7 +99,7 @@ export class BoardSelector extends InfiniteScrollable(localize(i18next)(LitEleme
97
99
  .card > .name {
98
100
  color: var(--md-sys-color-on-secondary);
99
101
  background-color: var(--md-sys-color-secondary);
100
- opacity: 0.8;
102
+ opacity: 0.9;
101
103
  margin-top: -35px;
102
104
  width: 100%;
103
105
  font-weight: bolder;
@@ -106,12 +108,11 @@ export class BoardSelector extends InfiniteScrollable(localize(i18next)(LitEleme
106
108
  }
107
109
 
108
110
  .card > .description {
109
- color: var(--md-sys-color-on-surface);
110
- background-color: var(--md-sys-color-surface);
111
+ color: var(--md-sys-color-on-secondary);
112
+ background-color: var(--md-sys-color-secondary);
111
113
  width: 100%;
112
- min-height: 15px;
114
+ min-height: 16px;
113
115
  font-size: 0.6rem;
114
- color: #fff;
115
116
  text-indent: 7px;
116
117
  }
117
118
  .card img {
@@ -120,12 +121,22 @@ export class BoardSelector extends InfiniteScrollable(localize(i18next)(LitEleme
120
121
  }
121
122
 
122
123
  #filter {
124
+ display: flex;
125
+ align-items: center;
123
126
  padding: var(--popup-content-padding);
124
127
  color: var(--md-sys-color-on-surface-variant);
125
128
  background-color: var(--md-sys-color-surface-variant);
126
129
  box-shadow: var(--box-shadow);
127
130
  }
128
131
 
132
+ #filter > ox-input-search {
133
+ margin-right: auto;
134
+ border: var(--md-sys-color-primary) 1px solid;
135
+ padding: var(--spacing-small) var(--spacing-small);
136
+ border-radius: 999px;
137
+ color: var(--md-sys-color-primary);
138
+ }
139
+
129
140
  #filter > div {
130
141
  float: right;
131
142
  margin-left: 10px;
@@ -145,6 +156,7 @@ export class BoardSelector extends InfiniteScrollable(localize(i18next)(LitEleme
145
156
  @property({ type: Array }) groups: { id: string; name: string; description: string }[] = []
146
157
  @property({ type: Array }) boards: any[] = []
147
158
  @property({ type: String }) group?: string
159
+ @property({ type: String }) search?: string
148
160
  @property({ type: String }) inherited?: InheritedValueType = InheritedValueType.Include
149
161
  @property({ type: Boolean }) creatable: boolean = false
150
162
  @property({ type: String }) value?: string
@@ -161,6 +173,11 @@ export class BoardSelector extends InfiniteScrollable(localize(i18next)(LitEleme
161
173
  render() {
162
174
  return html`
163
175
  <div id="filter">
176
+ <ox-input-search
177
+ @change=${(e: Event) => {
178
+ this.search = (e.currentTarget as any)?.value
179
+ }}
180
+ ></ox-input-search>
164
181
  <div>
165
182
  <label for="group">Group</label>
166
183
  <select
@@ -233,7 +250,7 @@ export class BoardSelector extends InfiniteScrollable(localize(i18next)(LitEleme
233
250
  }
234
251
 
235
252
  async updated(changed: PropertyValues<this>) {
236
- if (changed.has('group') || changed.has('inherited')) {
253
+ if (changed.has('group') || changed.has('inherited') || changed.has('search')) {
237
254
  this.refreshBoards()
238
255
  }
239
256
  }
@@ -294,12 +311,29 @@ export class BoardSelector extends InfiniteScrollable(localize(i18next)(LitEleme
294
311
  page
295
312
  }
296
313
 
297
- if (this.group)
314
+ if (this.group) {
298
315
  filters.push({
299
316
  name: 'groupId',
300
317
  operator: 'eq',
301
318
  value: this.group
302
319
  })
320
+ }
321
+
322
+ if (this.search) {
323
+ const value = `%${this.search.trim()}%`
324
+
325
+ filters.push({
326
+ name: 'name',
327
+ operator: 'search',
328
+ value: this.search
329
+ })
330
+
331
+ filters.push({
332
+ name: 'description',
333
+ operator: 'search',
334
+ value: this.search
335
+ })
336
+ }
303
337
 
304
338
  var variables = {
305
339
  filters,
@@ -310,7 +344,6 @@ export class BoardSelector extends InfiniteScrollable(localize(i18next)(LitEleme
310
344
 
311
345
  var boardListResponse = await client.query({
312
346
  query: FETCH_BOARD_LIST_GQL,
313
- context: gqlContext(),
314
347
  variables
315
348
  })
316
349