@fmsim/board 2.0.0-beta.3 → 2.0.0-beta.32

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 (63) hide show
  1. package/custom-elements.json +3062 -1859
  2. package/demo/index-modeller.html +1 -1
  3. package/demo/index-player.html +2 -2
  4. package/demo/index-viewer.html +2 -2
  5. package/demo/index.html +2 -2
  6. package/dist/src/component/etc.js +35 -0
  7. package/dist/src/component/etc.js.map +1 -1
  8. package/dist/src/data-storage/board-model-cache.d.ts +13 -0
  9. package/dist/src/data-storage/board-model-cache.js +66 -0
  10. package/dist/src/data-storage/board-model-cache.js.map +1 -0
  11. package/dist/src/index.d.ts +3 -0
  12. package/dist/src/index.js +2 -0
  13. package/dist/src/index.js.map +1 -1
  14. package/dist/src/modeller/edit-toolbar-style.js +43 -3
  15. package/dist/src/modeller/edit-toolbar-style.js.map +1 -1
  16. package/dist/src/modeller/edit-toolbar.d.ts +8 -14
  17. package/dist/src/modeller/edit-toolbar.js +208 -211
  18. package/dist/src/modeller/edit-toolbar.js.map +1 -1
  19. package/dist/src/modeller/property-sidebar/property-sidebar.js +3 -16
  20. package/dist/src/modeller/property-sidebar/property-sidebar.js.map +1 -1
  21. package/dist/src/modeller/property-sidebar/shapes/shapes.js +31 -0
  22. package/dist/src/modeller/property-sidebar/shapes/shapes.js.map +1 -1
  23. package/dist/src/modeller/property-sidebar/specifics/specifics.d.ts +1 -0
  24. package/dist/src/modeller/property-sidebar/specifics/specifics.js +10 -0
  25. package/dist/src/modeller/property-sidebar/specifics/specifics.js.map +1 -1
  26. package/dist/src/modeller/property-sidebar/styles/styles.d.ts +6 -4
  27. package/dist/src/modeller/property-sidebar/styles/styles.js +139 -436
  28. package/dist/src/modeller/property-sidebar/styles/styles.js.map +1 -1
  29. package/dist/src/modeller/scene-viewer/ox-scene-viewer.d.ts +2 -1
  30. package/dist/src/modeller/scene-viewer/ox-scene-viewer.js +5 -1
  31. package/dist/src/modeller/scene-viewer/ox-scene-viewer.js.map +1 -1
  32. package/dist/src/ox-board-component-info.d.ts +1 -0
  33. package/dist/src/ox-board-component-info.js +5 -1
  34. package/dist/src/ox-board-component-info.js.map +1 -1
  35. package/dist/src/ox-board-list.js +2 -2
  36. package/dist/src/ox-board-list.js.map +1 -1
  37. package/dist/src/ox-board-modeller.d.ts +5 -2
  38. package/dist/src/ox-board-modeller.js +14 -4
  39. package/dist/src/ox-board-modeller.js.map +1 -1
  40. package/dist/src/ox-board-viewer.d.ts +22 -2
  41. package/dist/src/ox-board-viewer.js +246 -21
  42. package/dist/src/ox-board-viewer.js.map +1 -1
  43. package/dist/src/ox-editor-board-selector.d.ts +3 -0
  44. package/dist/src/ox-editor-board-selector.js +38 -9
  45. package/dist/src/ox-editor-board-selector.js.map +1 -1
  46. package/dist/src/ox-playback-controls.d.ts +60 -0
  47. package/dist/src/ox-playback-controls.js +512 -0
  48. package/dist/src/ox-playback-controls.js.map +1 -0
  49. package/dist/src/playback/playback-engine.d.ts +78 -0
  50. package/dist/src/playback/playback-engine.js +215 -0
  51. package/dist/src/playback/playback-engine.js.map +1 -0
  52. package/dist/src/selector/board-creation-popup.js +2 -2
  53. package/dist/src/selector/board-creation-popup.js.map +1 -1
  54. package/dist/src/selector/board-thumbnail-card.js +6 -6
  55. package/dist/src/selector/board-thumbnail-card.js.map +1 -1
  56. package/dist/src/selector/ox-board-creation-card.js +2 -2
  57. package/dist/src/selector/ox-board-creation-card.js.map +1 -1
  58. package/dist/src/selector/ox-board-selector.js +21 -10
  59. package/dist/src/selector/ox-board-selector.js.map +1 -1
  60. package/dist/tsconfig.tsbuildinfo +1 -1
  61. package/icons/components/text.png +0 -0
  62. package/icons/icon-htoolbar.png +0 -0
  63. package/package.json +3 -6
@@ -0,0 +1,215 @@
1
+ /**
2
+ * PlaybackEngine
3
+ *
4
+ * 서버에서 받은 시계열 데이터(snapshot + diff)를 시간순으로 재생한다.
5
+ * snapshot/diff 구분 없이 각 프레임의 data를 그대로 scene 컴포넌트에 바인딩한다.
6
+ *
7
+ * 사용법:
8
+ * const engine = new PlaybackEngine()
9
+ * await engine.load(startTime, endTime)
10
+ * engine.attachScene(scene)
11
+ * engine.play(speed)
12
+ * engine.pause()
13
+ * engine.seekTo(time)
14
+ * engine.stop()
15
+ */
16
+ export class PlaybackEngine {
17
+ constructor() {
18
+ this._state = 'idle';
19
+ this._frames = [];
20
+ this._currentIndex = 0;
21
+ this._speed = 1;
22
+ this._scene = null;
23
+ this._scenarioNames = [];
24
+ this._listeners = new Map();
25
+ }
26
+ // ── 공개 API ──
27
+ get state() { return this._state; }
28
+ get currentIndex() { return this._currentIndex; }
29
+ get totalFrames() { return this._frames.length; }
30
+ get currentTime() { var _a, _b; return (_b = (_a = this._frames[this._currentIndex]) === null || _a === void 0 ? void 0 : _a.time) !== null && _b !== void 0 ? _b : null; }
31
+ get scenarioNames() { return this._scenarioNames; }
32
+ /**
33
+ * 데이터 로드. fetchPlayback을 외부에서 호출하여 결과를 전달한다.
34
+ */
35
+ loadData(scenarios) {
36
+ this._setState('loading');
37
+ this._scenarioNames = scenarios.map(s => s.scenarioName);
38
+ // 모든 시나리오의 프레임을 시간 기준으로 병합
39
+ const timeMap = new Map();
40
+ for (const scenario of scenarios) {
41
+ for (const frame of scenario.snapshots) {
42
+ if (!timeMap.has(frame.time)) {
43
+ timeMap.set(frame.time, new Map());
44
+ }
45
+ timeMap.get(frame.time).set(scenario.scenarioName, frame.data);
46
+ }
47
+ }
48
+ // 시간순 정렬
49
+ const sortedTimes = [...timeMap.keys()].sort();
50
+ this._frames = sortedTimes.map(time => ({
51
+ time,
52
+ data: timeMap.get(time)
53
+ }));
54
+ this._currentIndex = 0;
55
+ this._setState('stopped');
56
+ this._emit('load-complete', {
57
+ totalFrames: this._frames.length,
58
+ scenarios: this._scenarioNames
59
+ });
60
+ }
61
+ attachScene(scene) {
62
+ this._scene = scene;
63
+ }
64
+ detachScene() {
65
+ this._scene = null;
66
+ }
67
+ play(speed) {
68
+ if (this._frames.length === 0)
69
+ return;
70
+ if (speed != null)
71
+ this._speed = speed;
72
+ // 첫 프레임 즉시 적용
73
+ this._applyCurrentFrame();
74
+ this._setState('playing');
75
+ this._startTimer();
76
+ }
77
+ pause() {
78
+ this._stopTimer();
79
+ this._setState('paused');
80
+ }
81
+ resume() {
82
+ if (this._state !== 'paused')
83
+ return;
84
+ this._setState('playing');
85
+ this._startTimer();
86
+ }
87
+ stop() {
88
+ this._stopTimer();
89
+ this._currentIndex = 0;
90
+ this._setState('stopped');
91
+ }
92
+ setSpeed(speed) {
93
+ this._speed = speed;
94
+ if (this._state === 'playing') {
95
+ this._stopTimer();
96
+ this._startTimer();
97
+ }
98
+ }
99
+ /**
100
+ * 특정 시간으로 이동.
101
+ * 해당 시간 이하의 가장 가까운 프레임을 찾고,
102
+ * snapshot부터 그 프레임까지 누적 적용한다.
103
+ */
104
+ seekTo(time) {
105
+ const target = this._formatTime(time);
106
+ let targetIndex = 0;
107
+ for (let i = 0; i < this._frames.length; i++) {
108
+ if (this._frames[i].time <= target) {
109
+ targetIndex = i;
110
+ }
111
+ else {
112
+ break;
113
+ }
114
+ }
115
+ // snapshot(첫 프레임)부터 targetIndex까지 순차 적용
116
+ for (let i = 0; i <= targetIndex; i++) {
117
+ this._applyFrame(i);
118
+ }
119
+ this._currentIndex = targetIndex;
120
+ this._emitFrame();
121
+ // 재생 중이었으면 타이머 재시작
122
+ if (this._state === 'playing') {
123
+ this._stopTimer();
124
+ this._startTimer();
125
+ }
126
+ }
127
+ /**
128
+ * 이벤트 리스너 등록
129
+ */
130
+ on(event, listener) {
131
+ if (!this._listeners.has(event))
132
+ this._listeners.set(event, new Set());
133
+ this._listeners.get(event).add(listener);
134
+ }
135
+ off(event, listener) {
136
+ var _a;
137
+ (_a = this._listeners.get(event)) === null || _a === void 0 ? void 0 : _a.delete(listener);
138
+ }
139
+ dispose() {
140
+ this._stopTimer();
141
+ this._scene = null;
142
+ this._frames = [];
143
+ this._listeners.clear();
144
+ }
145
+ // ── 내부 ──
146
+ _startTimer() {
147
+ this._stopTimer();
148
+ const intervalMs = 1000 / this._speed;
149
+ this._timer = window.setInterval(() => {
150
+ this._currentIndex++;
151
+ if (this._currentIndex >= this._frames.length) {
152
+ // 재생 완료
153
+ this._currentIndex = this._frames.length - 1;
154
+ this._stopTimer();
155
+ this._setState('stopped');
156
+ return;
157
+ }
158
+ this._applyCurrentFrame();
159
+ this._emitFrame();
160
+ }, intervalMs);
161
+ }
162
+ _stopTimer() {
163
+ if (this._timer != null) {
164
+ clearInterval(this._timer);
165
+ this._timer = undefined;
166
+ }
167
+ }
168
+ _applyCurrentFrame() {
169
+ this._applyFrame(this._currentIndex);
170
+ this._emitFrame();
171
+ }
172
+ _applyFrame(index) {
173
+ var _a, _b;
174
+ const frame = this._frames[index];
175
+ if (!frame || !this._scene)
176
+ return;
177
+ for (const [_scenarioName, records] of frame.data) {
178
+ for (const record of records) {
179
+ if (!record.NAME)
180
+ continue;
181
+ const component = (_b = (_a = this._scene.root) === null || _a === void 0 ? void 0 : _a.findById) === null || _b === void 0 ? void 0 : _b.call(_a, record.NAME);
182
+ if (component) {
183
+ component.data = record;
184
+ }
185
+ }
186
+ }
187
+ }
188
+ _emitFrame() {
189
+ const frame = this._frames[this._currentIndex];
190
+ if (frame) {
191
+ this._emit('frame', {
192
+ time: frame.time,
193
+ index: this._currentIndex,
194
+ total: this._frames.length
195
+ });
196
+ }
197
+ }
198
+ _setState(state) {
199
+ this._state = state;
200
+ this._emit('state-change', state);
201
+ }
202
+ _emit(event, detail) {
203
+ const listeners = this._listeners.get(event);
204
+ if (listeners) {
205
+ for (const fn of listeners) {
206
+ fn(detail);
207
+ }
208
+ }
209
+ }
210
+ _formatTime(date) {
211
+ const pad = (n) => String(n).padStart(2, '0');
212
+ return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())} ${pad(date.getHours())}:${pad(date.getMinutes())}:${pad(date.getSeconds())}`;
213
+ }
214
+ }
215
+ //# sourceMappingURL=playback-engine.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"playback-engine.js","sourceRoot":"","sources":["../../../src/playback/playback-engine.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * PlaybackEngine\n *\n * 서버에서 받은 시계열 데이터(snapshot + diff)를 시간순으로 재생한다.\n * snapshot/diff 구분 없이 각 프레임의 data를 그대로 scene 컴포넌트에 바인딩한다.\n *\n * 사용법:\n * const engine = new PlaybackEngine()\n * await engine.load(startTime, endTime)\n * engine.attachScene(scene)\n * engine.play(speed)\n * engine.pause()\n * engine.seekTo(time)\n * engine.stop()\n */\n\nimport type { PlaybackFrame, PlaybackScenario } from '@fmsim/api'\n\nexport type PlaybackState = 'idle' | 'loading' | 'playing' | 'paused' | 'stopped'\n\nexport interface PlaybackEventMap {\n 'state-change': PlaybackState\n 'frame': { time: string; index: number; total: number }\n 'error': string\n 'load-complete': { totalFrames: number; scenarios: string[] }\n}\n\ntype PlaybackListener<K extends keyof PlaybackEventMap> = (detail: PlaybackEventMap[K]) => void\n\n/** 시간순 정렬된 통합 프레임 */\ninterface MergedFrame {\n time: string\n /** scenario → records */\n data: Map<string, any[]>\n}\n\nexport class PlaybackEngine {\n private _state: PlaybackState = 'idle'\n private _frames: MergedFrame[] = []\n private _currentIndex = 0\n private _timer?: number\n private _speed = 1\n private _scene: any = null\n private _scenarioNames: string[] = []\n private _listeners = new Map<string, Set<Function>>()\n\n // ── 공개 API ──\n\n get state(): PlaybackState { return this._state }\n get currentIndex(): number { return this._currentIndex }\n get totalFrames(): number { return this._frames.length }\n get currentTime(): string | null { return this._frames[this._currentIndex]?.time ?? null }\n get scenarioNames(): string[] { return this._scenarioNames }\n\n /**\n * 데이터 로드. fetchPlayback을 외부에서 호출하여 결과를 전달한다.\n */\n loadData(scenarios: PlaybackScenario[]): void {\n this._setState('loading')\n this._scenarioNames = scenarios.map(s => s.scenarioName)\n\n // 모든 시나리오의 프레임을 시간 기준으로 병합\n const timeMap = new Map<string, Map<string, any[]>>()\n\n for (const scenario of scenarios) {\n for (const frame of scenario.snapshots) {\n if (!timeMap.has(frame.time)) {\n timeMap.set(frame.time, new Map())\n }\n timeMap.get(frame.time)!.set(scenario.scenarioName, frame.data)\n }\n }\n\n // 시간순 정렬\n const sortedTimes = [...timeMap.keys()].sort()\n this._frames = sortedTimes.map(time => ({\n time,\n data: timeMap.get(time)!\n }))\n\n this._currentIndex = 0\n this._setState('stopped')\n\n this._emit('load-complete', {\n totalFrames: this._frames.length,\n scenarios: this._scenarioNames\n })\n }\n\n attachScene(scene: any): void {\n this._scene = scene\n }\n\n detachScene(): void {\n this._scene = null\n }\n\n play(speed?: number): void {\n if (this._frames.length === 0) return\n\n if (speed != null) this._speed = speed\n\n // 첫 프레임 즉시 적용\n this._applyCurrentFrame()\n this._setState('playing')\n this._startTimer()\n }\n\n pause(): void {\n this._stopTimer()\n this._setState('paused')\n }\n\n resume(): void {\n if (this._state !== 'paused') return\n this._setState('playing')\n this._startTimer()\n }\n\n stop(): void {\n this._stopTimer()\n this._currentIndex = 0\n this._setState('stopped')\n }\n\n setSpeed(speed: number): void {\n this._speed = speed\n if (this._state === 'playing') {\n this._stopTimer()\n this._startTimer()\n }\n }\n\n /**\n * 특정 시간으로 이동.\n * 해당 시간 이하의 가장 가까운 프레임을 찾고,\n * snapshot부터 그 프레임까지 누적 적용한다.\n */\n seekTo(time: Date): void {\n const target = this._formatTime(time)\n let targetIndex = 0\n\n for (let i = 0; i < this._frames.length; i++) {\n if (this._frames[i].time <= target) {\n targetIndex = i\n } else {\n break\n }\n }\n\n // snapshot(첫 프레임)부터 targetIndex까지 순차 적용\n for (let i = 0; i <= targetIndex; i++) {\n this._applyFrame(i)\n }\n\n this._currentIndex = targetIndex\n this._emitFrame()\n\n // 재생 중이었으면 타이머 재시작\n if (this._state === 'playing') {\n this._stopTimer()\n this._startTimer()\n }\n }\n\n /**\n * 이벤트 리스너 등록\n */\n on<K extends keyof PlaybackEventMap>(event: K, listener: PlaybackListener<K>): void {\n if (!this._listeners.has(event)) this._listeners.set(event, new Set())\n this._listeners.get(event)!.add(listener)\n }\n\n off<K extends keyof PlaybackEventMap>(event: K, listener: PlaybackListener<K>): void {\n this._listeners.get(event)?.delete(listener)\n }\n\n dispose(): void {\n this._stopTimer()\n this._scene = null\n this._frames = []\n this._listeners.clear()\n }\n\n // ── 내부 ──\n\n private _startTimer(): void {\n this._stopTimer()\n const intervalMs = 1000 / this._speed\n\n this._timer = window.setInterval(() => {\n this._currentIndex++\n\n if (this._currentIndex >= this._frames.length) {\n // 재생 완료\n this._currentIndex = this._frames.length - 1\n this._stopTimer()\n this._setState('stopped')\n return\n }\n\n this._applyCurrentFrame()\n this._emitFrame()\n }, intervalMs)\n }\n\n private _stopTimer(): void {\n if (this._timer != null) {\n clearInterval(this._timer)\n this._timer = undefined\n }\n }\n\n private _applyCurrentFrame(): void {\n this._applyFrame(this._currentIndex)\n this._emitFrame()\n }\n\n private _applyFrame(index: number): void {\n const frame = this._frames[index]\n if (!frame || !this._scene) return\n\n for (const [_scenarioName, records] of frame.data) {\n for (const record of records) {\n if (!record.NAME) continue\n const component = this._scene.root?.findById?.(record.NAME)\n if (component) {\n component.data = record\n }\n }\n }\n }\n\n private _emitFrame(): void {\n const frame = this._frames[this._currentIndex]\n if (frame) {\n this._emit('frame', {\n time: frame.time,\n index: this._currentIndex,\n total: this._frames.length\n })\n }\n }\n\n private _setState(state: PlaybackState): void {\n this._state = state\n this._emit('state-change', state)\n }\n\n private _emit<K extends keyof PlaybackEventMap>(event: K, detail: PlaybackEventMap[K]): void {\n const listeners = this._listeners.get(event)\n if (listeners) {\n for (const fn of listeners) {\n (fn as PlaybackListener<K>)(detail)\n }\n }\n }\n\n private _formatTime(date: Date): string {\n const pad = (n: number) => String(n).padStart(2, '0')\n return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())} ${pad(date.getHours())}:${pad(date.getMinutes())}:${pad(date.getSeconds())}`\n }\n}\n"]}
@@ -36,7 +36,7 @@ let BoardCreationPopup = class BoardCreationPopup extends localize(i18next)(LitE
36
36
  ];
37
37
  }
38
38
  render() {
39
- var groups = this.groups || [];
39
+ const groups = this.groups || [];
40
40
  return html `
41
41
  <div content>
42
42
  <md-filled-text-field label=${String(i18next.t('label.name'))} name="name" required field-name></md-filled-text-field>
@@ -69,7 +69,7 @@ let BoardCreationPopup = class BoardCreationPopup extends localize(i18next)(LitE
69
69
  }, 100);
70
70
  }
71
71
  onClickSubmit() {
72
- var [name, description, groupId] = ['name', 'description', 'group'].map(attr => {
72
+ const [name, description, groupId] = ['name', 'description', 'group'].map(attr => {
73
73
  var _a;
74
74
  return (_a = this.renderRoot.querySelector(`[field-${attr}]`)) === null || _a === void 0 ? void 0 : _a.value;
75
75
  });
@@ -1 +1 @@
1
- {"version":3,"file":"board-creation-popup.js","sourceRoot":"","sources":["../../../src/selector/board-creation-popup.ts"],"names":[],"mappings":";AAAA,OAAO,8CAA8C,CAAA;AACrD,OAAO,uCAAuC,CAAA;AAC9C,OAAO,uCAAuC,CAAA;AAC9C,OAAO,uCAAuC,CAAA;AAE9C,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,KAAK,CAAA;AAC3C,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAA;AAE3D,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AAG1C,IAAM,kBAAkB,GAAxB,MAAM,kBAAmB,SAAQ,QAAQ,CAAC,OAAO,CAAC,CAAC,UAAU,CAAC;IACnE,MAAM,KAAK,MAAM;QACf,OAAO;YACL,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;OAuBF;SACF,CAAA;IACH,CAAC;IAKD,MAAM;QACJ,IAAI,MAAM,GAAG,IAAI,CAAC,MAAM,IAAI,EAAE,CAAA;QAE9B,OAAO,IAAI,CAAA;;sCAEuB,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC;;;kBAGnD,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,mBAAmB,CAAC,CAAC;;;;;kBAKtC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC;;;YAGtC,MAAM,CAAC,GAAG,CACV,KAAK,CAAC,EAAE,CAAC,IAAI,CAAA;wCACe,KAAK,CAAC,EAAE,cAAc,IAAI,CAAC,YAAY,IAAI,KAAK,CAAC,EAAE,yBAAyB,KAAK,CAAC,IAAI;aACjH,CACF;;;;;iBAKM,CAAC,CAAa,EAAE,EAAE,CAAC,IAAI,CAAC,aAAa,EAAE;SAC/C,OAAO,CAAC,CAAC,CAAC,eAAe,CAAC;KAC9B,CAAA;IACH,CAAC;IAED,YAAY;QACV,UAAU,CAAC,GAAG,EAAE;;YACd,CAAC;YAAA,MAAC,IAAI,CAAC,UAAU,CAAC,aAAa,CAAC,sBAAsB,CAAS,0CAAE,KAAK,EAAE,CAAA;QAC1E,CAAC,EAAE,GAAG,CAAC,CAAA;IACT,CAAC;IAED,aAAa;QACX,IAAI,CAAC,IAAI,EAAE,WAAW,EAAE,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,aAAa,EAAE,OAAO,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE;;YAC7E,OAAO,MAAC,IAAI,CAAC,UAAU,CAAC,aAAa,CAAC,UAAU,IAAI,GAAG,CAAS,0CAAE,KAAK,CAAA;QACzE,CAAC,CAAC,CAAA;QAEF,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,OAAM;QACR,CAAC;QAED,IAAI,CAAC,aAAa,CAChB,IAAI,WAAW,CAAC,cAAc,EAAE;YAC9B,MAAM,EAAE;gBACN,IAAI;gBACJ,WAAW;gBACX,OAAO;aACR;SACF,CAAC,CACH,CAAA;IACH,CAAC;CACF,CAAA;AA1D6B;IAA3B,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;wDAAsB;AACtB;IAA1B,QAAQ,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;kDAAwC;AA/BvD,kBAAkB;IAD9B,aAAa,CAAC,sBAAsB,CAAC;GACzB,kBAAkB,CAwF9B","sourcesContent":["import '@material/web/textfield/filled-text-field.js'\nimport '@material/web/select/filled-select.js'\nimport '@material/web/select/select-option.js'\nimport '@material/web/button/filled-button.js'\n\nimport { css, html, LitElement } from 'lit'\nimport { customElement, property } from 'lit/decorators.js'\n\nimport { i18next, localize } from '@operato/i18n'\n\n@customElement('board-creation-popup')\nexport class BoardCreationPopup extends localize(i18next)(LitElement) {\n static get styles() {\n return [\n css`\n :host {\n display: flex;\n flex-direction: column;\n\n padding: 10px;\n background-color: white;\n }\n\n :host > * {\n margin: 10px;\n }\n\n [content] {\n flex: 1;\n display: flex;\n flex-direction: column;\n overflow: auto;\n }\n\n [content] > * {\n margin: 10px 0;\n }\n `\n ]\n }\n\n @property({ type: String }) defaultGroup?: string\n @property({ type: Array }) groups?: { id: string; name: string }[]\n\n render() {\n var groups = this.groups || []\n\n return html`\n <div content>\n <md-filled-text-field label=${String(i18next.t('label.name'))} name=\"name\" required field-name></md-filled-text-field>\n <md-filled-text-field\n type=\"textarea\"\n label=${String(i18next.t('label.description'))}\n name=\"description\"\n field-description\n ></md-filled-text-field>\n <md-filled-select\n label=${String(i18next.t('label.group'))}\n field-group\n >\n ${groups.map(\n group => html`\n <md-select-option value=${group.id} ?selected=${this.defaultGroup == group.id}><div slot=\"headline\">${group.name}</div></md-select-option>\n `\n )}\n </md-filled-select>\n </div>\n\n <md-filled-button\n @click=${(e: MouseEvent) => this.onClickSubmit()}\n >${i18next.t('button.create')}</md-filled-button>\n `\n }\n\n firstUpdated() {\n setTimeout(() => {\n ;(this.renderRoot.querySelector('md-filled-text-field') as any)?.focus()\n }, 100)\n }\n\n onClickSubmit() {\n var [name, description, groupId] = ['name', 'description', 'group'].map(attr => {\n return (this.renderRoot.querySelector(`[field-${attr}]`) as any)?.value\n })\n\n if (!name) {\n return\n }\n\n this.dispatchEvent(\n new CustomEvent('create-board', {\n detail: {\n name,\n description,\n groupId\n }\n })\n )\n }\n}\n"]}
1
+ {"version":3,"file":"board-creation-popup.js","sourceRoot":"","sources":["../../../src/selector/board-creation-popup.ts"],"names":[],"mappings":";AAAA,OAAO,8CAA8C,CAAA;AACrD,OAAO,uCAAuC,CAAA;AAC9C,OAAO,uCAAuC,CAAA;AAC9C,OAAO,uCAAuC,CAAA;AAE9C,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,KAAK,CAAA;AAC3C,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAA;AAE3D,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AAG1C,IAAM,kBAAkB,GAAxB,MAAM,kBAAmB,SAAQ,QAAQ,CAAC,OAAO,CAAC,CAAC,UAAU,CAAC;IACnE,MAAM,KAAK,MAAM;QACf,OAAO;YACL,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;OAuBF;SACF,CAAA;IACH,CAAC;IAKD,MAAM;QACJ,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,IAAI,EAAE,CAAA;QAEhC,OAAO,IAAI,CAAA;;sCAEuB,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC;;;kBAGnD,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,mBAAmB,CAAC,CAAC;;;;;kBAKtC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC;;;YAGtC,MAAM,CAAC,GAAG,CACV,KAAK,CAAC,EAAE,CAAC,IAAI,CAAA;wCACe,KAAK,CAAC,EAAE,cAAc,IAAI,CAAC,YAAY,IAAI,KAAK,CAAC,EAAE,yBAAyB,KAAK,CAAC,IAAI;aACjH,CACF;;;;;iBAKM,CAAC,CAAa,EAAE,EAAE,CAAC,IAAI,CAAC,aAAa,EAAE;SAC/C,OAAO,CAAC,CAAC,CAAC,eAAe,CAAC;KAC9B,CAAA;IACH,CAAC;IAED,YAAY;QACV,UAAU,CAAC,GAAG,EAAE;;YACd,CAAC;YAAA,MAAC,IAAI,CAAC,UAAU,CAAC,aAAa,CAAC,sBAAsB,CAAS,0CAAE,KAAK,EAAE,CAAA;QAC1E,CAAC,EAAE,GAAG,CAAC,CAAA;IACT,CAAC;IAED,aAAa;QACX,MAAM,CAAC,IAAI,EAAE,WAAW,EAAE,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,aAAa,EAAE,OAAO,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE;;YAC/E,OAAO,MAAC,IAAI,CAAC,UAAU,CAAC,aAAa,CAAC,UAAU,IAAI,GAAG,CAAS,0CAAE,KAAK,CAAA;QACzE,CAAC,CAAC,CAAA;QAEF,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,OAAM;QACR,CAAC;QAED,IAAI,CAAC,aAAa,CAChB,IAAI,WAAW,CAAC,cAAc,EAAE;YAC9B,MAAM,EAAE;gBACN,IAAI;gBACJ,WAAW;gBACX,OAAO;aACR;SACF,CAAC,CACH,CAAA;IACH,CAAC;CACF,CAAA;AA1D6B;IAA3B,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;wDAAsB;AACtB;IAA1B,QAAQ,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;kDAAwC;AA/BvD,kBAAkB;IAD9B,aAAa,CAAC,sBAAsB,CAAC;GACzB,kBAAkB,CAwF9B","sourcesContent":["import '@material/web/textfield/filled-text-field.js'\nimport '@material/web/select/filled-select.js'\nimport '@material/web/select/select-option.js'\nimport '@material/web/button/filled-button.js'\n\nimport { css, html, LitElement } from 'lit'\nimport { customElement, property } from 'lit/decorators.js'\n\nimport { i18next, localize } from '@operato/i18n'\n\n@customElement('board-creation-popup')\nexport class BoardCreationPopup extends localize(i18next)(LitElement) {\n static get styles() {\n return [\n css`\n :host {\n display: flex;\n flex-direction: column;\n\n padding: 10px;\n background-color: white;\n }\n\n :host > * {\n margin: 10px;\n }\n\n [content] {\n flex: 1;\n display: flex;\n flex-direction: column;\n overflow: auto;\n }\n\n [content] > * {\n margin: 10px 0;\n }\n `\n ]\n }\n\n @property({ type: String }) defaultGroup?: string\n @property({ type: Array }) groups?: { id: string; name: string }[]\n\n render() {\n const groups = this.groups || []\n\n return html`\n <div content>\n <md-filled-text-field label=${String(i18next.t('label.name'))} name=\"name\" required field-name></md-filled-text-field>\n <md-filled-text-field\n type=\"textarea\"\n label=${String(i18next.t('label.description'))}\n name=\"description\"\n field-description\n ></md-filled-text-field>\n <md-filled-select\n label=${String(i18next.t('label.group'))}\n field-group\n >\n ${groups.map(\n group => html`\n <md-select-option value=${group.id} ?selected=${this.defaultGroup == group.id}><div slot=\"headline\">${group.name}</div></md-select-option>\n `\n )}\n </md-filled-select>\n </div>\n\n <md-filled-button\n @click=${(e: MouseEvent) => this.onClickSubmit()}\n >${i18next.t('button.create')}</md-filled-button>\n `\n }\n\n firstUpdated() {\n setTimeout(() => {\n ;(this.renderRoot.querySelector('md-filled-text-field') as any)?.focus()\n }, 100)\n }\n\n onClickSubmit() {\n const [name, description, groupId] = ['name', 'description', 'group'].map(attr => {\n return (this.renderRoot.querySelector(`[field-${attr}]`) as any)?.value\n })\n\n if (!name) {\n return\n }\n\n this.dispatchEvent(\n new CustomEvent('create-board', {\n detail: {\n name,\n description,\n groupId\n }\n })\n )\n }\n}\n"]}
@@ -101,7 +101,7 @@ let BoardThumbnailCard = class BoardThumbnailCard extends localize(i18next)(LitE
101
101
  ];
102
102
  }
103
103
  render() {
104
- var groups = this.groups || [];
104
+ const groups = this.groups || [];
105
105
  return html `
106
106
  <div @click=${(e) => this.onClickFlip(e)} front><md-icon>add_circle_outline</md-icon>create board</div>
107
107
 
@@ -135,10 +135,10 @@ let BoardThumbnailCard = class BoardThumbnailCard extends localize(i18next)(LitE
135
135
  onClickSubmit(e) {
136
136
  e.preventDefault();
137
137
  e.stopPropagation();
138
- var form = e.target;
139
- var name = form.elements['name'].value;
140
- var description = form.elements['description'].value;
141
- var groupId = form.elements['groupId'].value;
138
+ const form = e.target;
139
+ const name = form.elements['name'].value;
140
+ const description = form.elements['description'].value;
141
+ const groupId = form.elements['groupId'].value;
142
142
  this.dispatchEvent(new CustomEvent('create-board', {
143
143
  detail: {
144
144
  name,
@@ -149,7 +149,7 @@ let BoardThumbnailCard = class BoardThumbnailCard extends localize(i18next)(LitE
149
149
  }
150
150
  reset() {
151
151
  var _a;
152
- var form = (_a = this.shadowRoot) === null || _a === void 0 ? void 0 : _a.querySelector('form');
152
+ const form = (_a = this.shadowRoot) === null || _a === void 0 ? void 0 : _a.querySelector('form');
153
153
  if (form) {
154
154
  form.reset();
155
155
  }
@@ -1 +1 @@
1
- {"version":3,"file":"board-thumbnail-card.js","sourceRoot":"","sources":["../../../src/selector/board-thumbnail-card.ts"],"names":[],"mappings":"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","sourcesContent":["import { css, html, LitElement } from 'lit'\nimport { customElement, property } from 'lit/decorators.js'\n\nimport { i18next, localize } from '@operato/i18n'\n\n@customElement('board-thumbnail-card')\nexport class BoardThumbnailCard extends localize(i18next)(LitElement) {\n static get styles() {\n return [\n css`\n :host {\n position: relative;\n\n padding: 0;\n margin: 0;\n height: 100%;\n\n -webkit-transform-style: preserve-3d;\n transform-style: preserve-3d;\n -webkit-transition: all 0.5s ease-in-out;\n transition: all 0.5s ease-in-out;\n }\n\n :host(.flipped) {\n -webkit-transform: var(--card-list-flip-transform);\n transform: var(--card-list-flip-transform);\n }\n\n [front],\n [back] {\n position: absolute;\n\n width: 100%;\n height: 100%;\n margin: 0;\n padding: 0;\n\n border: var(--card-list-create-border);\n border-radius: var(--card-list-create-border-radius);\n\n background-color: #fff;\n\n -webkit-backface-visibility: hidden;\n backface-visibility: hidden;\n }\n\n [front] {\n text-align: center;\n font-size: 0.8em;\n color: var(--card-list-create-color);\n text-transform: capitalize;\n }\n\n [front] md-icon {\n margin-top: 15%;\n display: block;\n font-size: 3.5em;\n color: var(--card-list-create-icon-color);\n }\n\n [back] {\n -webkit-transform: var(--card-list-flip-transform);\n transform: var(--card-list-flip-transform);\n }\n\n [back] form {\n padding: var(--card-list-create-form-padding);\n display: flex;\n flex-flow: row wrap;\n }\n\n [back] form label {\n flex: 1 1 25%;\n font: var(--card-list-create-label-font);\n color: var(--card-list-create-label-color);\n }\n\n [back] form input,\n [back] form select {\n flex: 1 1 60%;\n width: 10px;\n background-color: #fff;\n border: var(--card-list-create-input-border);\n border-radius: var(--card-list-create-input-border-radius);\n padding: var(--card-list-create-input-padding);\n font: var(--card-list-create-input-font);\n color: var(--card-list-create-input-color);\n }\n\n form * {\n margin: var(--card-list-create-margin);\n }\n\n input[type='submit'] {\n background-color: var(--button-background-color) !important;\n margin: var(--button-margin);\n font: var(--button-font);\n color: var(--button-color) !important;\n border-radius: var(--button-radius);\n border: var(--button-border);\n }\n `\n ]\n }\n\n @property({ type: String }) defaultGroup?: string\n @property({ type: Array }) groups?: { id: string; name: string }[]\n\n render() {\n var groups = this.groups || []\n\n return html`\n <div @click=${(e: Event) => this.onClickFlip(e)} front><md-icon>add_circle_outline</md-icon>create board</div>\n\n <div @click=${(e: Event) => this.onClickFlip(e)} back>\n <form @submit=${(e: Event) => this.onClickSubmit(e)}>\n <label>${i18next.t('label.name')}</label>\n <input type=\"text\" name=\"name\" />\n\n <label>${i18next.t('label.description')}</label>\n <input type=\"text\" name=\"description\" />\n\n <label>${i18next.t('label.group')}</label>\n <select .value=${this.defaultGroup || ''} name=\"groupId\">\n ${groups.map(\n group => html`\n <option value=${group.id} ?selected=${this.defaultGroup == group.id}>${group.name}</option>\n `\n )}\n </select>\n\n <input type=\"submit\" value=${String(i18next.t('button.create'))} />\n </form>\n </div>\n `\n }\n\n onClickFlip(e: Event) {\n if ((e.currentTarget as any)?.hasAttribute('front') || (e.target as any)?.hasAttribute('back')) {\n this.classList.toggle('flipped')\n }\n\n e.stopPropagation()\n }\n\n onClickSubmit(e: Event) {\n e.preventDefault()\n e.stopPropagation()\n\n var form = e.target as any\n\n var name = form.elements['name'].value\n var description = form.elements['description'].value\n var groupId = form.elements['groupId'].value\n\n this.dispatchEvent(\n new CustomEvent('create-board', {\n detail: {\n name,\n description,\n groupId\n }\n })\n )\n }\n\n reset() {\n var form = this.shadowRoot?.querySelector('form')\n if (form) {\n form.reset()\n }\n\n this.classList.remove('flipped')\n }\n}\n"]}
1
+ {"version":3,"file":"board-thumbnail-card.js","sourceRoot":"","sources":["../../../src/selector/board-thumbnail-card.ts"],"names":[],"mappings":"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","sourcesContent":["import { css, html, LitElement } from 'lit'\nimport { customElement, property } from 'lit/decorators.js'\n\nimport { i18next, localize } from '@operato/i18n'\n\n@customElement('board-thumbnail-card')\nexport class BoardThumbnailCard extends localize(i18next)(LitElement) {\n static get styles() {\n return [\n css`\n :host {\n position: relative;\n\n padding: 0;\n margin: 0;\n height: 100%;\n\n -webkit-transform-style: preserve-3d;\n transform-style: preserve-3d;\n -webkit-transition: all 0.5s ease-in-out;\n transition: all 0.5s ease-in-out;\n }\n\n :host(.flipped) {\n -webkit-transform: var(--card-list-flip-transform);\n transform: var(--card-list-flip-transform);\n }\n\n [front],\n [back] {\n position: absolute;\n\n width: 100%;\n height: 100%;\n margin: 0;\n padding: 0;\n\n border: var(--card-list-create-border);\n border-radius: var(--card-list-create-border-radius);\n\n background-color: #fff;\n\n -webkit-backface-visibility: hidden;\n backface-visibility: hidden;\n }\n\n [front] {\n text-align: center;\n font-size: 0.8em;\n color: var(--card-list-create-color);\n text-transform: capitalize;\n }\n\n [front] md-icon {\n margin-top: 15%;\n display: block;\n font-size: 3.5em;\n color: var(--card-list-create-icon-color);\n }\n\n [back] {\n -webkit-transform: var(--card-list-flip-transform);\n transform: var(--card-list-flip-transform);\n }\n\n [back] form {\n padding: var(--card-list-create-form-padding);\n display: flex;\n flex-flow: row wrap;\n }\n\n [back] form label {\n flex: 1 1 25%;\n font: var(--card-list-create-label-font);\n color: var(--card-list-create-label-color);\n }\n\n [back] form input,\n [back] form select {\n flex: 1 1 60%;\n width: 10px;\n background-color: #fff;\n border: var(--card-list-create-input-border);\n border-radius: var(--card-list-create-input-border-radius);\n padding: var(--card-list-create-input-padding);\n font: var(--card-list-create-input-font);\n color: var(--card-list-create-input-color);\n }\n\n form * {\n margin: var(--card-list-create-margin);\n }\n\n input[type='submit'] {\n background-color: var(--button-background-color) !important;\n margin: var(--button-margin);\n font: var(--button-font);\n color: var(--button-color) !important;\n border-radius: var(--button-radius);\n border: var(--button-border);\n }\n `\n ]\n }\n\n @property({ type: String }) defaultGroup?: string\n @property({ type: Array }) groups?: { id: string; name: string }[]\n\n render() {\n const groups = this.groups || []\n\n return html`\n <div @click=${(e: Event) => this.onClickFlip(e)} front><md-icon>add_circle_outline</md-icon>create board</div>\n\n <div @click=${(e: Event) => this.onClickFlip(e)} back>\n <form @submit=${(e: Event) => this.onClickSubmit(e)}>\n <label>${i18next.t('label.name')}</label>\n <input type=\"text\" name=\"name\" />\n\n <label>${i18next.t('label.description')}</label>\n <input type=\"text\" name=\"description\" />\n\n <label>${i18next.t('label.group')}</label>\n <select .value=${this.defaultGroup || ''} name=\"groupId\">\n ${groups.map(\n group => html`\n <option value=${group.id} ?selected=${this.defaultGroup == group.id}>${group.name}</option>\n `\n )}\n </select>\n\n <input type=\"submit\" value=${String(i18next.t('button.create'))} />\n </form>\n </div>\n `\n }\n\n onClickFlip(e: Event) {\n if ((e.currentTarget as any)?.hasAttribute('front') || (e.target as any)?.hasAttribute('back')) {\n this.classList.toggle('flipped')\n }\n\n e.stopPropagation()\n }\n\n onClickSubmit(e: Event) {\n e.preventDefault()\n e.stopPropagation()\n\n const form = e.target as any\n\n const name = form.elements['name'].value\n const description = form.elements['description'].value\n const groupId = form.elements['groupId'].value\n\n this.dispatchEvent(\n new CustomEvent('create-board', {\n detail: {\n name,\n description,\n groupId\n }\n })\n )\n }\n\n reset() {\n const form = this.shadowRoot?.querySelector('form')\n if (form) {\n form.reset()\n }\n\n this.classList.remove('flipped')\n }\n}\n"]}
@@ -47,12 +47,12 @@ let BoardCreationCard = class BoardCreationCard extends localize(i18next)(LitEle
47
47
  * 주의. value는 object일 수도 있고, string일 수도 있다.
48
48
  * string인 경우에는 해당 보드의 id로 해석한다.
49
49
  */
50
- var template = html `
50
+ const template = html `
51
51
  <board-creation-popup
52
52
  .defaultGroup=${this.defaultGroup}
53
53
  .groups=${this.groups}
54
54
  @create-board=${async (e) => {
55
- var { name, description, groupId } = e.detail;
55
+ const { name, description, groupId } = e.detail;
56
56
  this.dispatchEvent(new CustomEvent('create-board', {
57
57
  detail: {
58
58
  name,
@@ -1 +1 @@
1
- {"version":3,"file":"ox-board-creation-card.js","sourceRoot":"","sources":["../../../src/selector/ox-board-creation-card.ts"],"names":[],"mappings":";AAAA,OAAO,4BAA4B,CAAA;AACnC,OAAO,wBAAwB,CAAA;AAE/B,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,KAAK,CAAA;AAC3C,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAA;AAE3D,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AACjD,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAA;AAGpC,IAAM,iBAAiB,GAAvB,MAAM,iBAAkB,SAAQ,QAAQ,CAAC,OAAO,CAAC,CAAC,UAAU,CAAC;IAClE,MAAM,KAAK,MAAM;QACf,OAAO;YACL,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;OAwBF;SACF,CAAA;IACH,CAAC;IAQD,MAAM;QACJ,OAAO,IAAI,CAAA,eAAe,CAAC,CAAQ,EAAE,EAAE,CAAC,IAAI,CAAC,OAAO,EAAE,2DAA2D,CAAA;IACnH,CAAC;IAED,OAAO;QACL,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;YACf,OAAO,IAAI,CAAC,KAAK,CAAA;QACnB,CAAC;QAED;;;;WAIG;QACH,IAAI,QAAQ,GAAG,IAAI,CAAA;;wBAEC,IAAI,CAAC,YAAY;kBACvB,IAAI,CAAC,MAAM;wBACL,KAAK,EAAE,CAAc,EAAE,EAAE;YACvC,IAAI,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,GAAG,CAAC,CAAC,MAAM,CAAA;YAE7C,IAAI,CAAC,aAAa,CAChB,IAAI,WAAW,CAAC,cAAc,EAAE;gBAC9B,MAAM,EAAE;oBACN,IAAI;oBACJ,WAAW;oBACX,OAAO;iBACR;aACF,CAAC,CACH,CAAA;YAED,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAA;QAClC,CAAC;;KAEJ,CAAA;QAED,IAAI,CAAC,KAAK,GAAG,SAAS,CAAC,QAAQ,EAAE;YAC/B,QAAQ,EAAE,IAAI;YACd,IAAI,EAAE,OAAO;YACb,KAAK,EAAE,OAAO,CAAC,CAAC,CAAC,oBAAoB,CAAC;SACvC,CAAC,CAAA;IACJ,CAAC;IAED,KAAK,KAAI,CAAC;CACX,CAAA;AAjD6B;IAA3B,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;uDAAsB;AACtB;IAA1B,QAAQ,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;iDAAY;AAjC3B,iBAAiB;IAD7B,aAAa,CAAC,wBAAwB,CAAC;GAC3B,iBAAiB,CAiF7B","sourcesContent":["import '@material/web/icon/icon.js'\nimport './board-creation-popup'\n\nimport { css, html, LitElement } from 'lit'\nimport { customElement, property } from 'lit/decorators.js'\n\nimport { i18next, localize } from '@operato/i18n'\nimport { openPopup } from '@operato/layout'\n\n@customElement('ox-board-creation-card')\nexport class BoardCreationCard extends localize(i18next)(LitElement) {\n static get styles() {\n return [\n css`\n :host {\n display: flex;\n border: var(--card-list-create-border);\n border-radius: var(--card-list-create-border-radius);\n\n background-color: #fff;\n\n align-items: center;\n justify-content: center;\n }\n\n div {\n text-align: center;\n font-size: 0.8em;\n color: var(--card-list-create-color);\n text-transform: capitalize;\n }\n\n md-icon {\n display: block;\n --md-icon-size: 3.5em;\n color: var(--card-list-create-icon-color);\n }\n `\n ]\n }\n\n /* default group id */\n @property({ type: String }) defaultGroup?: string\n @property({ type: Array }) groups: any\n\n private popup: any\n\n render() {\n return html`<div @click=${(e: Event) => this.onClick()}><md-icon>add_circle_outline</md-icon>create board</div> `\n }\n\n onClick() {\n if (this.popup) {\n delete this.popup\n }\n\n /*\n * 기존 설정된 이미지가 선택된 상태가 되게 하기 위해서는 selector에 value를 전달해줄 필요가 있음.\n * 주의. value는 object일 수도 있고, string일 수도 있다.\n * string인 경우에는 해당 보드의 id로 해석한다.\n */\n var template = html`\n <board-creation-popup\n .defaultGroup=${this.defaultGroup}\n .groups=${this.groups}\n @create-board=${async (e: CustomEvent) => {\n var { name, description, groupId } = e.detail\n\n this.dispatchEvent(\n new CustomEvent('create-board', {\n detail: {\n name,\n description,\n groupId\n }\n })\n )\n\n this.popup && this.popup.close()\n }}\n ></board-creation-popup>\n `\n\n this.popup = openPopup(template, {\n backdrop: true,\n size: 'large',\n title: i18next.t('title.create-board')\n })\n }\n\n reset() {}\n}\n"]}
1
+ {"version":3,"file":"ox-board-creation-card.js","sourceRoot":"","sources":["../../../src/selector/ox-board-creation-card.ts"],"names":[],"mappings":";AAAA,OAAO,4BAA4B,CAAA;AACnC,OAAO,wBAAwB,CAAA;AAE/B,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,KAAK,CAAA;AAC3C,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAA;AAE3D,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AACjD,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAA;AAGpC,IAAM,iBAAiB,GAAvB,MAAM,iBAAkB,SAAQ,QAAQ,CAAC,OAAO,CAAC,CAAC,UAAU,CAAC;IAClE,MAAM,KAAK,MAAM;QACf,OAAO;YACL,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;OAwBF;SACF,CAAA;IACH,CAAC;IAQD,MAAM;QACJ,OAAO,IAAI,CAAA,eAAe,CAAC,CAAQ,EAAE,EAAE,CAAC,IAAI,CAAC,OAAO,EAAE,2DAA2D,CAAA;IACnH,CAAC;IAED,OAAO;QACL,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;YACf,OAAO,IAAI,CAAC,KAAK,CAAA;QACnB,CAAC;QAED;;;;WAIG;QACH,MAAM,QAAQ,GAAG,IAAI,CAAA;;wBAED,IAAI,CAAC,YAAY;kBACvB,IAAI,CAAC,MAAM;wBACL,KAAK,EAAE,CAAc,EAAE,EAAE;YACvC,MAAM,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,GAAG,CAAC,CAAC,MAAM,CAAA;YAE/C,IAAI,CAAC,aAAa,CAChB,IAAI,WAAW,CAAC,cAAc,EAAE;gBAC9B,MAAM,EAAE;oBACN,IAAI;oBACJ,WAAW;oBACX,OAAO;iBACR;aACF,CAAC,CACH,CAAA;YAED,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAA;QAClC,CAAC;;KAEJ,CAAA;QAED,IAAI,CAAC,KAAK,GAAG,SAAS,CAAC,QAAQ,EAAE;YAC/B,QAAQ,EAAE,IAAI;YACd,IAAI,EAAE,OAAO;YACb,KAAK,EAAE,OAAO,CAAC,CAAC,CAAC,oBAAoB,CAAC;SACvC,CAAC,CAAA;IACJ,CAAC;IAED,KAAK,KAAI,CAAC;CACX,CAAA;AAjD6B;IAA3B,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;uDAAsB;AACtB;IAA1B,QAAQ,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;iDAAY;AAjC3B,iBAAiB;IAD7B,aAAa,CAAC,wBAAwB,CAAC;GAC3B,iBAAiB,CAiF7B","sourcesContent":["import '@material/web/icon/icon.js'\nimport './board-creation-popup'\n\nimport { css, html, LitElement } from 'lit'\nimport { customElement, property } from 'lit/decorators.js'\n\nimport { i18next, localize } from '@operato/i18n'\nimport { openPopup } from '@operato/layout'\n\n@customElement('ox-board-creation-card')\nexport class BoardCreationCard extends localize(i18next)(LitElement) {\n static get styles() {\n return [\n css`\n :host {\n display: flex;\n border: var(--card-list-create-border);\n border-radius: var(--card-list-create-border-radius);\n\n background-color: #fff;\n\n align-items: center;\n justify-content: center;\n }\n\n div {\n text-align: center;\n font-size: 0.8em;\n color: var(--card-list-create-color);\n text-transform: capitalize;\n }\n\n md-icon {\n display: block;\n --md-icon-size: 3.5em;\n color: var(--card-list-create-icon-color);\n }\n `\n ]\n }\n\n /* default group id */\n @property({ type: String }) defaultGroup?: string\n @property({ type: Array }) groups: any\n\n private popup: any\n\n render() {\n return html`<div @click=${(e: Event) => this.onClick()}><md-icon>add_circle_outline</md-icon>create board</div> `\n }\n\n onClick() {\n if (this.popup) {\n delete this.popup\n }\n\n /*\n * 기존 설정된 이미지가 선택된 상태가 되게 하기 위해서는 selector에 value를 전달해줄 필요가 있음.\n * 주의. value는 object일 수도 있고, string일 수도 있다.\n * string인 경우에는 해당 보드의 id로 해석한다.\n */\n const template = html`\n <board-creation-popup\n .defaultGroup=${this.defaultGroup}\n .groups=${this.groups}\n @create-board=${async (e: CustomEvent) => {\n const { name, description, groupId } = e.detail\n\n this.dispatchEvent(\n new CustomEvent('create-board', {\n detail: {\n name,\n description,\n groupId\n }\n })\n )\n\n this.popup && this.popup.close()\n }}\n ></board-creation-popup>\n `\n\n this.popup = openPopup(template, {\n backdrop: true,\n size: 'large',\n title: i18next.t('title.create-board')\n })\n }\n\n reset() {}\n}\n"]}
@@ -37,7 +37,10 @@ let BoardSelector = class BoardSelector extends InfiniteScrollable(localize(i18n
37
37
  }
38
38
 
39
39
  .card[selected] {
40
- border: red solid;
40
+ border: 3px solid var(--md-sys-color-primary, #6750a4);
41
+ box-shadow: 0 0 0 3px color-mix(in srgb, var(--md-sys-color-primary, #6750a4) 30%, transparent), 0 4px 12px rgba(0, 0, 0, 0.25);
42
+ transform: scale(1.02);
43
+ transition: all 0.2s ease;
41
44
  }
42
45
 
43
46
  .card.create {
@@ -161,6 +164,14 @@ let BoardSelector = class BoardSelector extends InfiniteScrollable(localize(i18n
161
164
  if (changed.has('group')) {
162
165
  this.refreshBoards();
163
166
  }
167
+ // 선택된 카드로 자동 스크롤
168
+ if (changed.has('boards') || changed.has('value')) {
169
+ await this.updateComplete;
170
+ const selected = this.renderRoot.querySelector('.card[selected]');
171
+ if (selected) {
172
+ selected.scrollIntoView({ behavior: 'smooth', block: 'center' });
173
+ }
174
+ }
164
175
  }
165
176
  onClickSelect(board) {
166
177
  this.dispatchEvent(new CustomEvent('board-selected', {
@@ -172,7 +183,7 @@ let BoardSelector = class BoardSelector extends InfiniteScrollable(localize(i18n
172
183
  }));
173
184
  }
174
185
  async onCreateBoard(e) {
175
- var { name, description, groupId } = e.detail;
186
+ const { name, description, groupId } = e.detail;
176
187
  await this.createBoard(name, description, groupId);
177
188
  this.refreshBoards();
178
189
  }
@@ -182,22 +193,22 @@ let BoardSelector = class BoardSelector extends InfiniteScrollable(localize(i18n
182
193
  this.group = groups.filter((group) => group.id == this.group).length > 0 ? this.group : '';
183
194
  }
184
195
  async refreshBoards() {
185
- var boards = await this.getBoards();
196
+ const boards = await this.getBoards();
186
197
  this.boards = [...boards];
187
- var creationCard = this.renderRoot.querySelector('ox-board-creation-card');
198
+ const creationCard = this.renderRoot.querySelector('ox-board-creation-card');
188
199
  if (creationCard) {
189
200
  ;
190
201
  creationCard.reset();
191
202
  }
192
203
  }
193
204
  async appendBoards() {
194
- var boards = await this.getBoards({ page: this._page + 1 });
205
+ const boards = await this.getBoards({ page: this._page + 1 });
195
206
  this.boards = [...this.boards, ...boards];
196
207
  }
197
208
  async getBoards({ page = 1, limit = this._infiniteScrollOptions.limit } = {}) {
198
- var filters = [];
199
- var sortings = [];
200
- var pagination = {
209
+ const filters = [];
210
+ const sortings = [];
211
+ const pagination = {
201
212
  limit,
202
213
  page
203
214
  };
@@ -207,7 +218,7 @@ let BoardSelector = class BoardSelector extends InfiniteScrollable(localize(i18n
207
218
  operator: 'eq',
208
219
  value: this.group
209
220
  });
210
- var variables = {
221
+ const variables = {
211
222
  filters,
212
223
  sortings,
213
224
  pagination
@@ -228,7 +239,7 @@ let BoardSelector = class BoardSelector extends InfiniteScrollable(localize(i18n
228
239
  }
229
240
  }
230
241
  async createBoard(name, description, groupId) {
231
- var model = JSON.stringify({
242
+ const model = JSON.stringify({
232
243
  width: 1600,
233
244
  height: 1200,
234
245
  fillStyle: 'white'
@@ -1 +1 @@
1
- {"version":3,"file":"ox-board-selector.js","sourceRoot":"","sources":["../../../src/selector/ox-board-selector.ts"],"names":[],"mappings":"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","sourcesContent":["import './ox-board-creation-card'\n\nimport { css, html, LitElement, PropertyValues } from 'lit'\nimport { customElement, property } from 'lit/decorators.js'\n\nimport { i18next, localize } from '@operato/i18n'\nimport { ScrollbarStyles } from '@operato/styles'\nimport InfiniteScrollable from '@operato/utils/mixins/infinite-scrollable.js'\nimport { createBoard, fetchBoardList, fetchGroupList } from '@fmsim/api'\n\n@customElement('ox-board-selector')\nexport class BoardSelector extends InfiniteScrollable(localize(i18next)(LitElement)) {\n static get styles() {\n return [\n ScrollbarStyles,\n css`\n :host {\n display: grid;\n grid-template-rows: auto auto 1fr;\n overflow: hidden;\n background-color: var(--popup-content-background-color);\n }\n\n #main {\n overflow: auto;\n padding: var(--popup-content-padding);\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));\n grid-auto-rows: var(--card-list-rows-height);\n grid-gap: 20px;\n }\n\n .card {\n display: flex;\n flex-direction: column;\n align-items: center;\n overflow: hidden;\n border-radius: var(--card-list-border-radius);\n background-color: var(--card-list-background-color);\n }\n\n .card[selected] {\n border: red solid;\n }\n\n .card.create {\n overflow: visible;\n }\n\n .card:hover {\n cursor: pointer;\n }\n\n .card > .name {\n background-color: var(--board-renderer-name-background-color);\n opacity: 0.8;\n margin-top: -35px;\n width: 100%;\n color: #fff;\n font-weight: bolder;\n font-size: 13px;\n text-indent: 7px;\n }\n\n .card > .description {\n background-color: rgba(0, 0, 0, 0.7);\n width: 100%;\n min-height: 15px;\n font-size: 0.6rem;\n color: #fff;\n text-indent: 7px;\n }\n .card img {\n max-height: 100%;\n min-height: 100%;\n }\n\n #filter {\n padding: var(--popup-content-padding);\n background-color: #fff;\n box-shadow: var(--box-shadow);\n }\n\n #filter > div {\n float: right;\n margin-left: 10px;\n }\n\n #filter * {\n font-size: 15px;\n }\n\n select {\n text-transform: capitalize;\n }\n `\n ]\n }\n\n @property({ type: Array }) groups: { id: string; name: string; description: string }[] = []\n @property({ type: Array }) boards: any[] = []\n @property({ type: String }) group?: string\n // @property({ type: String }) inherited?: InheritedValueType = InheritedValueType.Include\n @property({ type: Boolean }) creatable: boolean = false\n @property({ type: String }) value?: string\n\n private _page: number = 1\n private _total: number = 0\n\n constructor() {\n super()\n\n this._infiniteScrollOptions.limit = 50\n }\n\n render() {\n return html`\n <div id=\"filter\">\n <div>\n <label for=\"group\">Group</label>\n <select\n id=\"group\"\n @change=${(e: Event) => {\n this.group = (e.currentTarget as any)?.value\n this.requestUpdate()\n }}\n >\n <option value=\"\">${i18next.t('label.all')}</option>\n ${this.groups.map(group => html` <option value=${group.id}>${group.description}</option> `)}\n </select>\n </div>\n </div>\n\n <div\n id=\"main\"\n @scroll=${(e: Event) => {\n this.onScroll(e)\n }}\n >\n ${this.creatable\n ? html`\n <ox-board-creation-card\n class=\"card create\"\n .groups=${this.groups}\n .defaultGroup=${this.group}\n @create-board=${(e: CustomEvent) => this.onCreateBoard(e)}\n ></ox-board-creation-card>\n `\n : html``}\n ${this.boards.map(\n board => html`\n <div class=\"card\" @click=${(e: Event) => this.onClickSelect(board)} ?selected=${this.value === board.id}>\n <img src=${board.thumbnail} />\n <div class=\"name\">${board.name}</div>\n <div class=\"description\">${board.description}</div>\n </div>\n `\n )}\n </div>\n `\n }\n\n get scrollTargetEl(): HTMLElement | null {\n return this.renderRoot.querySelector('#main') as HTMLElement\n }\n\n async scrollAction() {\n return this.appendBoards()\n }\n\n firstUpdated() {\n this.refreshGroups()\n }\n\n async updated(changed: PropertyValues<this>) {\n if (changed.has('group')) {\n this.refreshBoards()\n }\n }\n\n onClickSelect(board: any) {\n this.dispatchEvent(\n new CustomEvent('board-selected', {\n composed: true,\n bubbles: true,\n detail: {\n board\n }\n })\n )\n }\n\n async onCreateBoard(e: CustomEvent) {\n var { name, description, groupId } = e.detail\n\n await this.createBoard(name, description, groupId)\n this.refreshBoards()\n }\n\n async refreshGroups() {\n const fetched = await fetchGroupList()\n\n const groups = 'groups' in fetched /* graphql */ ? fetched.groups.items : fetched.data.groups\n\n this.group = groups.filter((group: { id: string }) => group.id == this.group).length > 0 ? this.group : ''\n }\n\n async refreshBoards() {\n var boards = await this.getBoards()\n this.boards = [...boards]\n\n var creationCard = this.renderRoot.querySelector('ox-board-creation-card')\n if (creationCard) {\n ;(creationCard as any).reset()\n }\n }\n\n async appendBoards() {\n var boards = await this.getBoards({ page: this._page + 1 })\n this.boards = [...this.boards, ...boards]\n }\n\n async getBoards({ page = 1, limit = this._infiniteScrollOptions.limit } = {}) {\n var filters = []\n var sortings = [] as any[]\n var pagination = {\n limit,\n page\n }\n\n if (this.group)\n filters.push({\n name: 'groupId',\n operator: 'eq',\n value: this.group\n })\n\n var variables = {\n filters,\n sortings,\n pagination\n // inherited: this.inherited || InheritedValueType.Include\n }\n\n const fetched = await fetchBoardList(variables)\n\n if ('boards' in fetched /* graphql */) {\n const { total, items } = fetched.boards\n\n this._total = total\n this._page = page\n\n return items\n } else {\n const { boards } = fetched.data\n this._total = boards.length\n this._page = 1\n\n return boards\n }\n }\n\n async createBoard(name: string, description: string, groupId: string) {\n var model = JSON.stringify({\n width: 1600,\n height: 1200,\n fillStyle: 'white'\n })\n\n const { data } = await createBoard({\n name,\n description,\n groupId,\n model\n })\n\n return data\n }\n}\n"]}
1
+ {"version":3,"file":"ox-board-selector.js","sourceRoot":"","sources":["../../../src/selector/ox-board-selector.ts"],"names":[],"mappings":"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","sourcesContent":["import './ox-board-creation-card'\n\nimport { css, html, LitElement, PropertyValues } from 'lit'\nimport { customElement, property } from 'lit/decorators.js'\n\nimport { i18next, localize } from '@operato/i18n'\nimport { ScrollbarStyles } from '@operato/styles'\nimport InfiniteScrollable from '@operato/utils/mixins/infinite-scrollable.js'\nimport { createBoard, fetchBoardList, fetchGroupList } from '@fmsim/api'\n\n@customElement('ox-board-selector')\nexport class BoardSelector extends InfiniteScrollable(localize(i18next)(LitElement)) {\n static get styles() {\n return [\n ScrollbarStyles,\n css`\n :host {\n display: grid;\n grid-template-rows: auto auto 1fr;\n overflow: hidden;\n background-color: var(--popup-content-background-color);\n }\n\n #main {\n overflow: auto;\n padding: var(--popup-content-padding);\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));\n grid-auto-rows: var(--card-list-rows-height);\n grid-gap: 20px;\n }\n\n .card {\n display: flex;\n flex-direction: column;\n align-items: center;\n overflow: hidden;\n border-radius: var(--card-list-border-radius);\n background-color: var(--card-list-background-color);\n }\n\n .card[selected] {\n border: 3px solid var(--md-sys-color-primary, #6750a4);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--md-sys-color-primary, #6750a4) 30%, transparent), 0 4px 12px rgba(0, 0, 0, 0.25);\n transform: scale(1.02);\n transition: all 0.2s ease;\n }\n\n .card.create {\n overflow: visible;\n }\n\n .card:hover {\n cursor: pointer;\n }\n\n .card > .name {\n background-color: var(--board-renderer-name-background-color);\n opacity: 0.8;\n margin-top: -35px;\n width: 100%;\n color: #fff;\n font-weight: bolder;\n font-size: 13px;\n text-indent: 7px;\n }\n\n .card > .description {\n background-color: rgba(0, 0, 0, 0.7);\n width: 100%;\n min-height: 15px;\n font-size: 0.6rem;\n color: #fff;\n text-indent: 7px;\n }\n .card img {\n max-height: 100%;\n min-height: 100%;\n }\n\n #filter {\n padding: var(--popup-content-padding);\n background-color: #fff;\n box-shadow: var(--box-shadow);\n }\n\n #filter > div {\n float: right;\n margin-left: 10px;\n }\n\n #filter * {\n font-size: 15px;\n }\n\n select {\n text-transform: capitalize;\n }\n `\n ]\n }\n\n @property({ type: Array }) groups: { id: string; name: string; description: string }[] = []\n @property({ type: Array }) boards: any[] = []\n @property({ type: String }) group?: string\n // @property({ type: String }) inherited?: InheritedValueType = InheritedValueType.Include\n @property({ type: Boolean }) creatable: boolean = false\n @property({ type: String }) value?: string\n\n private _page: number = 1\n private _total: number = 0\n\n constructor() {\n super()\n\n this._infiniteScrollOptions.limit = 50\n }\n\n render() {\n return html`\n <div id=\"filter\">\n <div>\n <label for=\"group\">Group</label>\n <select\n id=\"group\"\n @change=${(e: Event) => {\n this.group = (e.currentTarget as any)?.value\n this.requestUpdate()\n }}\n >\n <option value=\"\">${i18next.t('label.all')}</option>\n ${this.groups.map(group => html` <option value=${group.id}>${group.description}</option> `)}\n </select>\n </div>\n </div>\n\n <div\n id=\"main\"\n @scroll=${(e: Event) => {\n this.onScroll(e)\n }}\n >\n ${this.creatable\n ? html`\n <ox-board-creation-card\n class=\"card create\"\n .groups=${this.groups}\n .defaultGroup=${this.group}\n @create-board=${(e: CustomEvent) => this.onCreateBoard(e)}\n ></ox-board-creation-card>\n `\n : html``}\n ${this.boards.map(\n board => html`\n <div class=\"card\" @click=${(e: Event) => this.onClickSelect(board)} ?selected=${this.value === board.id}>\n <img src=${board.thumbnail} />\n <div class=\"name\">${board.name}</div>\n <div class=\"description\">${board.description}</div>\n </div>\n `\n )}\n </div>\n `\n }\n\n get scrollTargetEl(): HTMLElement | null {\n return this.renderRoot.querySelector('#main') as HTMLElement\n }\n\n async scrollAction() {\n return this.appendBoards()\n }\n\n firstUpdated() {\n this.refreshGroups()\n }\n\n async updated(changed: PropertyValues<this>) {\n if (changed.has('group')) {\n this.refreshBoards()\n }\n\n // 선택된 카드로 자동 스크롤\n if (changed.has('boards') || changed.has('value')) {\n await this.updateComplete\n const selected = this.renderRoot.querySelector('.card[selected]') as HTMLElement\n if (selected) {\n selected.scrollIntoView({ behavior: 'smooth', block: 'center' })\n }\n }\n }\n\n onClickSelect(board: any) {\n this.dispatchEvent(\n new CustomEvent('board-selected', {\n composed: true,\n bubbles: true,\n detail: {\n board\n }\n })\n )\n }\n\n async onCreateBoard(e: CustomEvent) {\n const { name, description, groupId } = e.detail\n\n await this.createBoard(name, description, groupId)\n this.refreshBoards()\n }\n\n async refreshGroups() {\n const fetched = await fetchGroupList()\n\n const groups = 'groups' in fetched /* graphql */ ? fetched.groups.items : fetched.data.groups\n\n this.group = groups.filter((group: { id: string }) => group.id == this.group).length > 0 ? this.group : ''\n }\n\n async refreshBoards() {\n const boards = await this.getBoards()\n this.boards = [...boards]\n\n const creationCard = this.renderRoot.querySelector('ox-board-creation-card')\n if (creationCard) {\n ;(creationCard as any).reset()\n }\n }\n\n async appendBoards() {\n const boards = await this.getBoards({ page: this._page + 1 })\n this.boards = [...this.boards, ...boards]\n }\n\n async getBoards({ page = 1, limit = this._infiniteScrollOptions.limit } = {}) {\n const filters = []\n const sortings = [] as any[]\n const pagination = {\n limit,\n page\n }\n\n if (this.group)\n filters.push({\n name: 'groupId',\n operator: 'eq',\n value: this.group\n })\n\n const variables = {\n filters,\n sortings,\n pagination\n // inherited: this.inherited || InheritedValueType.Include\n }\n\n const fetched = await fetchBoardList(variables)\n\n if ('boards' in fetched /* graphql */) {\n const { total, items } = fetched.boards\n\n this._total = total\n this._page = page\n\n return items\n } else {\n const { boards } = fetched.data\n this._total = boards.length\n this._page = 1\n\n return boards\n }\n }\n\n async createBoard(name: string, description: string, groupId: string) {\n const model = JSON.stringify({\n width: 1600,\n height: 1200,\n fillStyle: 'white'\n })\n\n const { data } = await createBoard({\n name,\n description,\n groupId,\n model\n })\n\n return data\n }\n}\n"]}