@operato/data-grist 8.0.0-beta.1 → 8.0.0-beta.5

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/CHANGELOG.md CHANGED
@@ -3,6 +3,23 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ ## [8.0.0-beta.5](https://github.com/hatiolab/operato/compare/v8.0.0-beta.4...v8.0.0-beta.5) (2025-01-10)
7
+
8
+ **Note:** Version bump only for package @operato/data-grist
9
+
10
+
11
+
12
+
13
+
14
+ ## [8.0.0-beta.2](https://github.com/hatiolab/operato/compare/v8.0.0-beta.1...v8.0.0-beta.2) (2025-01-08)
15
+
16
+
17
+ ### :bug: Bug Fix
18
+
19
+ * typo .npmignore ([d9c0c8c](https://github.com/hatiolab/operato/commit/d9c0c8c79abc688c3c2cfb6c37fcb689483a5977))
20
+
21
+
22
+
6
23
  ## [8.0.0-beta.1](https://github.com/hatiolab/operato/compare/v8.0.0-beta.0...v8.0.0-beta.1) (2025-01-08)
7
24
 
8
25
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@operato/data-grist",
3
- "version": "8.0.0-beta.1",
3
+ "version": "8.0.0-beta.5",
4
4
  "description": "User interface for grid (desktop) and list (mobile)",
5
5
  "author": "heartyoh",
6
6
  "main": "dist/index.js",
@@ -62,14 +62,14 @@
62
62
  },
63
63
  "dependencies": {
64
64
  "@material/web": "^2.0.0",
65
- "@operato/headroom": "^8.0.0-beta.1",
66
- "@operato/input": "^8.0.0-beta.1",
67
- "@operato/p13n": "^8.0.0-beta.1",
68
- "@operato/popup": "^8.0.0-beta.1",
69
- "@operato/pull-to-refresh": "^8.0.0-beta.1",
70
- "@operato/styles": "^8.0.0-beta.1",
71
- "@operato/time-calculator": "^8.0.0-beta.1",
72
- "@operato/utils": "^8.0.0-beta.1",
65
+ "@operato/headroom": "^8.0.0-beta.2",
66
+ "@operato/input": "^8.0.0-beta.5",
67
+ "@operato/p13n": "^8.0.0-beta.5",
68
+ "@operato/popup": "^8.0.0-beta.5",
69
+ "@operato/pull-to-refresh": "^8.0.0-beta.2",
70
+ "@operato/styles": "^8.0.0-beta.2",
71
+ "@operato/time-calculator": "^8.0.0-beta.2",
72
+ "@operato/utils": "^8.0.0-beta.2",
73
73
  "i18next": "^23.11.5",
74
74
  "json5": "^2.2.0",
75
75
  "lit": "^3.1.2",
@@ -108,5 +108,5 @@
108
108
  "prettier --write"
109
109
  ]
110
110
  },
111
- "gitHead": "d5b28a2e9deb632c0dc80132f6a7196dd6fe4220"
111
+ "gitHead": "7c70814f95cd4f22508b513575984ceca6eb1bff"
112
112
  }
@@ -1,468 +0,0 @@
1
- <!doctype html>
2
- <html lang="en-GB">
3
- <head>
4
- <meta charset="utf-8" />
5
- <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" />
6
- <style>
7
- body {
8
- /* box-sizing: border-box; */
9
- margin: 0;
10
- padding: 0;
11
- overflow: hidden;
12
-
13
- /* This is a font-stack that tries to use the system-default sans-serifs first */
14
- font-family: Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol';
15
- line-height: 1.5;
16
- -webkit-font-smoothing: antialiased;
17
- }
18
-
19
- #app {
20
- width: 100vw;
21
- height: 100dvh;
22
-
23
- display: flex;
24
- flex-direction: column;
25
- }
26
-
27
- #demo {
28
- flex: 1;
29
-
30
- display: flex;
31
- flex-direction: column;
32
- overflow: hidden;
33
- }
34
-
35
- grist-demo {
36
- flex: 1;
37
- overflow: auto;
38
- }
39
- </style>
40
- <link href="https://fonts.googleapis.com/css?family=Roboto:300,400,500" rel="stylesheet" />
41
- <link
42
- href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL@20..48,100..700,0..1"
43
- rel="stylesheet"
44
- />
45
- <link
46
- href="https://fonts.googleapis.com/css2?family=Material+Symbols+Rounded:opsz,wght,FILL@20..48,100..700,0..1"
47
- rel="stylesheet"
48
- />
49
- <link
50
- href="https://fonts.googleapis.com/css2?family=Material+Symbols+Sharp:opsz,wght,FILL@20..48,100..700,0..1"
51
- rel="stylesheet"
52
- />
53
-
54
- <link href="/themes/app-theme.css" rel="stylesheet" />
55
- <link href="/themes/oops-theme.css" rel="stylesheet" />
56
- <link href="/themes/grist-theme.css" rel="stylesheet" />
57
- </head>
58
-
59
- <body>
60
- <script type="module">
61
- import { LitElement, html, css, render } from 'lit'
62
- import '../dist/index.js'
63
- import '../dist/src/filters/filters-form.js'
64
- import '../dist/src/sorters/sorters-control.js'
65
- import '../dist/src/record-view/record-creator.js'
66
- import '@operato/popup/ox-popup-list.js'
67
- import '@material/web/icon/icon.js'
68
- import { CommonGristStyles } from '@operato/styles'
69
-
70
- const fetchHandler = async ({ page, limit, sorters = [] }) => {
71
- var total = 120993
72
- var start = (page - 1) * limit
73
-
74
- await new Promise(resolve => setTimeout(resolve, 500))
75
-
76
- return {
77
- total,
78
- records: Array(limit * page > total ? total % limit : limit)
79
- .fill()
80
- .map((item, idx) => {
81
- return {
82
- id: idx,
83
- name: idx % 2 ? `shnam-${start + idx + 1}` : `heartyoh-${start + idx + 1}`,
84
- description:
85
- idx % 2 ? `hatiolabmanager${start + idx + 1}1234567890` : `hatiosea manager-${start + idx + 1}`,
86
- email: idx % 2 ? `shnam-${start + idx + 1}@gmail.com` : `heartyoh-${start + idx + 1}@gmail.com`,
87
- active: Math.round(Math.random() * 2) % 2 ? true : false,
88
- barcode: idx % 2 ? `1234567890${start + idx + 1}` : `0987654321${start + idx + 1}`,
89
- company:
90
- idx % 2
91
- ? {
92
- id: '2',
93
- name: 'HatioLAB',
94
- description: `경기도 성남시-${start + idx + 1}`
95
- }
96
- : {
97
- id: '3',
98
- name: 'HatioSEA',
99
- description: `말레이시아 세티아알람-${start + idx + 1}`
100
- },
101
- thumbnail:
102
- idx % 4 === 0
103
- ? '' /* no source */
104
- : idx % 4 === 1
105
- ? `http://www.hatiolab.com/assets/img/operato-biz3.png`
106
- : idx % 4 === 2
107
- ? `http://www.hatiolab.com/assets/img/thingsboard-30.png`
108
- : `http://www.hatiolab.com/wrong-url.png` /* wrong source */,
109
- role: ['admin', 'worker', 'tester'][idx % 3],
110
- color: idx % 2 ? `#87f018` : `#180f87`,
111
- rate: Math.round(Math.random() * 100),
112
- dynamicType: ['text', 'email', 'checkbox', 'color', 'progress', 'barcode'][idx % 5],
113
- dynamicValue: ['abcdefghijkl', 'heartyoh@hatiolab.com', 'true', 'orange', '50', '1234567890'][idx % 5],
114
- homepage:
115
- idx % 2
116
- ? `http://hatiolab.com/${start + idx + 1}`
117
- : `http://deadpool.hatiolab.com/${start + idx + 1}`,
118
- json5: {
119
- abc: 'abc',
120
- value: 123
121
- },
122
- createdAt: Date.now(),
123
- updatedAt: Date.now()
124
- }
125
- })
126
- }
127
- }
128
-
129
- const config = {
130
- list: {
131
- thumbnail: 'thumbnail',
132
- fields: ['name', 'description'],
133
- details: ['role', 'email']
134
- },
135
- columns: [
136
- {
137
- type: 'gutter',
138
- gutterName: 'dirty'
139
- },
140
- {
141
- type: 'gutter',
142
- gutterName: 'sequence'
143
- },
144
- {
145
- type: 'gutter',
146
- gutterName: 'row-selector',
147
- multiple: true
148
- },
149
- {
150
- type: 'gutter',
151
- gutterName: 'button',
152
- icon: 'edit',
153
- handlers: {
154
- click: function () {
155
- console.log('clicked')
156
- }
157
- }
158
- },
159
- {
160
- type: 'gutter',
161
- gutterName: 'button',
162
- icon: 'add',
163
- handlers: {
164
- click: 'record-copy'
165
- }
166
- },
167
- {
168
- type: 'gutter',
169
- gutterName: 'button',
170
- icon: 'arrow_downward',
171
- handlers: {
172
- click: 'move-down'
173
- }
174
- },
175
- {
176
- type: 'string',
177
- name: 'id',
178
- hidden: true
179
- },
180
- {
181
- type: 'link',
182
- name: 'name',
183
- label: true,
184
- header: 'name',
185
- record: {
186
- editable: true,
187
- options: {
188
- // href: 'http://hatiolab.com',
189
- href: function (column, record, rowIndex) {
190
- return record['homepage']
191
- },
192
- target: '_blank'
193
- }
194
- },
195
- filter: 'search',
196
- sortable: true,
197
- width: 120
198
- },
199
- {
200
- type: 'string',
201
- name: 'description',
202
- header: 'description',
203
- filter: 'search',
204
- record: {
205
- editable: true,
206
- align: 'left'
207
- },
208
- width: 200,
209
- handlers: {
210
- click: (columns, data, column, record, rowIndex, target) => {
211
- alert(`${column.name} ${record[column.name]}, row : ${rowIndex}`)
212
- }
213
- }
214
- },
215
- {
216
- type: 'email',
217
- name: 'email',
218
- label: true,
219
- header: 'email',
220
- record: {
221
- editable: true
222
- },
223
- filter: 'search',
224
- sortable: true,
225
- width: 130,
226
- validation: function (after, before, record, column) {
227
- if (after.indexOf('@') == -1) {
228
- document.dispatchEvent(
229
- new CustomEvent('notify', {
230
- detail: {
231
- type: 'error',
232
- message: `invalid value - ${after}`
233
- }
234
- })
235
- )
236
- return false
237
- }
238
- return true
239
- }
240
- },
241
- {
242
- type: 'boolean',
243
- name: 'active',
244
- header: 'active',
245
- record: {
246
- editable: true
247
- },
248
- filter: true,
249
- handlers: {
250
- dblclick: () => {
251
- const grist = document.querySelector('ox-grist')
252
- console.log(grist.dirtyRecords)
253
- }
254
- },
255
- sortable: true,
256
- width: 60
257
- },
258
- {
259
- type: 'select',
260
- name: 'role',
261
- label: true,
262
- header: 'role',
263
- record: {
264
- options: ['', 'admin', 'worker', 'tester'],
265
- editable: true
266
- },
267
- filter: true,
268
- sortable: true,
269
- width: 120
270
- },
271
- {
272
- type: 'color',
273
- name: 'color',
274
- header: 'color',
275
- record: {
276
- editable: true
277
- },
278
- sortable: true,
279
- width: 50
280
- },
281
- {
282
- type: 'float',
283
- name: 'rate',
284
- header: 'rate',
285
- record: {
286
- align: 'right',
287
- editable: true
288
- },
289
- filter: 'between',
290
- sortable: true,
291
- width: 50
292
- },
293
- {
294
- type: 'json5',
295
- name: 'json5',
296
- header: 'JSON5',
297
- width: 200
298
- },
299
- {
300
- type: 'image',
301
- name: 'thumbnail',
302
- header: 'thumbnail',
303
- record: {
304
- editable: true
305
- },
306
- width: 120
307
- },
308
- {
309
- type: 'datetime',
310
- name: 'updatedAt',
311
- header: 'updated at',
312
- record: {
313
- editable: true
314
- },
315
- filter: 'between',
316
- sortable: true,
317
- width: 180
318
- },
319
- {
320
- type: 'datetime',
321
- name: 'createdAt',
322
- header: 'created at',
323
- record: {
324
- editable: false
325
- },
326
- sortable: true,
327
- width: 180
328
- }
329
- ],
330
- rows: {
331
- selectable: {
332
- multiple: true
333
- },
334
- handlers: {
335
- click: 'select-row-toggle'
336
- },
337
- classifier: function (record, rowIndex) {
338
- const rate = record['rate']
339
- const emphasized =
340
- rate < 10 ? ['black', 'white'] : rate < 25 ? ['yellow', 'blue'] : rate < 40 ? ['cyan', 'red'] : undefined
341
- return {
342
- emphasized
343
- }
344
- }
345
- },
346
- sorters: [
347
- {
348
- name: 'name',
349
- desc: true
350
- },
351
- {
352
- name: 'email'
353
- }
354
- ],
355
- pagination: {
356
- pages: [20, 30, 50, 100, 200]
357
- }
358
- }
359
-
360
- class GristDemo extends LitElement {
361
- static styles = [
362
- CommonGristStyles,
363
- css`
364
- :host {
365
- display: flex;
366
- flex-direction: column;
367
- }
368
-
369
- #tailer {
370
- display: flex;
371
- flex-direction: row;
372
- margin: 0 var(--margin-default);
373
- }
374
-
375
- #tailer a {
376
- padding: 0 var(--padding-default) 0 var(--padding-default);
377
- margin: 0 var(--spacing-small);
378
- border-right: 1px solid rgba(0, 0, 0, 0.1);
379
- font-size: var(--fontsize-default);
380
- color: var(--md-sys-color-on-primary-container);
381
- }
382
- `
383
- ]
384
-
385
- static get properties() {
386
- return {
387
- mode: String
388
- }
389
- }
390
-
391
- get grist() {
392
- return this.renderRoot.querySelector('ox-grist')
393
- }
394
-
395
- render() {
396
- const mode = this.mode || 'CARD'
397
-
398
- return html`
399
- <ox-grist .config=${config} .mode=${mode} auto-fetch .fetchHandler=${fetchHandler}>
400
- <div id="filters" slot="headroom">
401
- <ox-filters-form @filters-change=${e => console.log('changed', e.detail)}></ox-filters-form>
402
- </div>
403
-
404
- <div slot="headroom" id="headroom">
405
- <div id="tailer">
406
- <a href="./report-test.html">Report Test</a>
407
- <a
408
- href="#"
409
- @click=${() => {
410
- this.renderRoot.querySelector('ox-grist').reset()
411
- }}
412
- >Reset</a
413
- >
414
- <a
415
- href="#"
416
- @click=${() => {
417
- this.renderRoot.querySelector('ox-grist').fetch(true)
418
- }}
419
- >Fetch</a
420
- >
421
- </div>
422
-
423
- <div id="sorters">
424
- Sort
425
- <md-icon
426
- @click=${e => {
427
- const target = e.currentTarget
428
- this.renderRoot.querySelector('#sorter-control').open({
429
- right: 0,
430
- top: target.offsetTop + target.offsetHeight
431
- })
432
- }}
433
- >expand_more</md-icon
434
- >
435
- <ox-popup id="sorter-control">
436
- <ox-sorters-control> </ox-sorters-control>
437
- </ox-popup>
438
- </div>
439
-
440
- <div id="modes">
441
- <md-icon @click=${() => (this.mode = 'GRID')} ?active=${mode == 'GRID'}>view_list</md-icon>
442
- <md-icon @click=${() => (this.mode = 'LIST')} ?active=${mode == 'LIST'}>menu</md-icon>
443
- <md-icon @click=${() => (this.mode = 'CARD')} ?active=${mode == 'CARD'}>apps</md-icon>
444
- </div>
445
-
446
- <ox-record-creator id="add" light-popup>
447
- <button><md-icon>add</md-icon></button>
448
- </ox-record-creator>
449
-
450
- <button @click=${e => this.grist.cloneSelectedRecords()}><md-icon>add</md-icon></button>
451
- </div>
452
- </ox-grist>
453
- `
454
- }
455
- }
456
-
457
- customElements.define('grist-demo', GristDemo)
458
-
459
- setTimeout(() => {
460
- render(html` <grist-demo mode="LIST"></grist-demo> `, document.querySelector('#demo'))
461
- })
462
- </script>
463
-
464
- <div id="app">
465
- <div id="demo"></div>
466
- </div>
467
- </body>
468
- </html>
package/demo/favicon.ico DELETED
Binary file
package/demo/index.html DELETED
@@ -1,541 +0,0 @@
1
- <!doctype html>
2
- <html lang="en-GB">
3
- <head>
4
- <meta charset="utf-8" />
5
- <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" />
6
-
7
- <style>
8
- body {
9
- /* box-sizing: border-box; */
10
- margin: 0;
11
- padding: 0;
12
- overflow: hidden;
13
-
14
- /* This is a font-stack that tries to use the system-default sans-serifs first */
15
- font-family: Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol';
16
- line-height: 1.5;
17
- -webkit-font-smoothing: antialiased;
18
- }
19
-
20
- #app {
21
- width: 100vw;
22
- height: 100dvh;
23
-
24
- display: flex;
25
- flex-direction: column;
26
- }
27
-
28
- #demo {
29
- flex: 1;
30
-
31
- display: flex;
32
- flex-direction: column;
33
- overflow: hidden;
34
- }
35
-
36
- grist-demo {
37
- flex: 1;
38
- overflow: auto;
39
- }
40
- </style>
41
- <link href="https://fonts.googleapis.com/css?family=Roboto:300,400,500" rel="stylesheet" />
42
- <link
43
- href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL@20..48,100..700,0..1"
44
- rel="stylesheet"
45
- />
46
- <link
47
- href="https://fonts.googleapis.com/css2?family=Material+Symbols+Rounded:opsz,wght,FILL@20..48,100..700,0..1"
48
- rel="stylesheet"
49
- />
50
- <link
51
- href="https://fonts.googleapis.com/css2?family=Material+Symbols+Sharp:opsz,wght,FILL@20..48,100..700,0..1"
52
- rel="stylesheet"
53
- />
54
-
55
- <link href="/themes/app-theme.css" rel="stylesheet" />
56
- <link href="/themes/oops-theme.css" rel="stylesheet" />
57
- <link href="/themes/grist-theme.css" rel="stylesheet" />
58
- </head>
59
-
60
- <body>
61
- <script type="module">
62
- import { LitElement, html, css, render } from 'lit'
63
- import '../dist/index.js'
64
- import '../dist/src/filters/filters-form.js'
65
- import '../dist/src/sorters/sorters-control.js'
66
- import '../dist/src/record-view/record-creator.js'
67
- import '@operato/popup/ox-popup-list.js'
68
- import '@material/web/icon/icon.js'
69
- import { CommonGristStyles } from '@operato/styles'
70
-
71
- const fetchHandler = async ({ page, limit, sorters = [], filters }) => {
72
- console.log('sorters, filters', sorters, filters)
73
- var total = 120993
74
- var start = (page - 1) * limit
75
-
76
- await new Promise(resolve => setTimeout(resolve, 500))
77
-
78
- return {
79
- total,
80
- records: Array(limit * page > total ? total % limit : limit)
81
- .fill()
82
- .map((item, idx) => {
83
- return {
84
- id: idx,
85
- name: idx % 2 ? `shnam-${start + idx + 1}` : `heartyoh-${start + idx + 1}`,
86
- description:
87
- idx % 2 ? `hatiolabmanager${start + idx + 1}1234567890` : `hatiosea manager-${start + idx + 1}`,
88
- email: idx % 2 ? `shnam-${start + idx + 1}@gmail.com` : `heartyoh-${start + idx + 1}@gmail.com`,
89
- active: Math.round(Math.random() * 2) % 2 ? true : false,
90
- barcode: idx % 2 ? `1234567890${start + idx + 1}` : `0987654321${start + idx + 1}`,
91
- company:
92
- idx % 2
93
- ? {
94
- id: '2',
95
- name: 'HatioLAB',
96
- description: `경기도 성남시-${start + idx + 1}`
97
- }
98
- : {
99
- id: '3',
100
- name: 'HatioSEA',
101
- description: `말레이시아 세티아알람-${start + idx + 1}`
102
- },
103
- thumbnail:
104
- idx % 4 === 0
105
- ? '' /* no source */
106
- : idx % 4 === 1
107
- ? `http://www.hatiolab.com/assets/img/operato-biz3.png`
108
- : idx % 4 === 2
109
- ? `http://www.hatiolab.com/assets/img/thingsboard-30.png`
110
- : `http://www.hatiolab.com/wrong-url.png` /* wrong source */,
111
- file: 'abce.txt',
112
- number: 100200300,
113
- role: ['admin', 'worker', 'tester'][idx % 3],
114
- privilege: [undefined, 'read', 'write'][idx % 3],
115
- color: idx % 2 ? `#87f018` : `#180f87`,
116
- rate: Math.round(Math.random() * 100),
117
- dynamicType: ['text', 'email', 'checkbox', 'color', 'progress', 'barcode'][idx % 5],
118
- dynamicValue: ['abcdefghijkl', 'heartyoh@hatiolab.com', 'true', 'orange', '50', '1234567890'][idx % 5],
119
- homepage:
120
- idx % 2
121
- ? `http://hatiolab.com/${start + idx + 1}`
122
- : `http://deadpool.hatiolab.com/${start + idx + 1}`,
123
- json5: {
124
- abc: 'abc',
125
- value: 123,
126
- xyz: [1, 2, 3, 4, 5, 6, 7, 8, 9, 0],
127
- quantity: 6782341
128
- },
129
- createdAt: Date.now(),
130
- updatedAt: Date.now()
131
- }
132
- })
133
- }
134
- }
135
-
136
- const config = {
137
- list: {
138
- thumbnail: 'thumbnail',
139
- fields: ['name', 'description'],
140
- details: ['role', 'email', 'json5']
141
- },
142
- columns: [
143
- {
144
- type: 'gutter',
145
- gutterName: 'dirty'
146
- },
147
- {
148
- type: 'gutter',
149
- gutterName: 'sequence'
150
- },
151
- {
152
- type: 'gutter',
153
- gutterName: 'row-selector',
154
- title: 'row selector',
155
- multiple: true
156
- },
157
- {
158
- type: 'gutter',
159
- gutterName: 'button',
160
- icon: 'edit',
161
- title: 'edit item',
162
- handlers: {
163
- click: function () {
164
- console.log('clicked')
165
- }
166
- }
167
- },
168
- {
169
- type: 'gutter',
170
- gutterName: 'button',
171
- icon: 'add',
172
- title: 'record copy',
173
- handlers: {
174
- click: 'record-copy'
175
- }
176
- },
177
- {
178
- type: 'gutter',
179
- gutterName: 'button',
180
- icon: 'arrow_downward',
181
- title: '아래로',
182
- handlers: {
183
- click: 'move-down'
184
- }
185
- },
186
- {
187
- type: 'string',
188
- name: 'id',
189
- hidden: true
190
- },
191
- {
192
- type: 'link',
193
- name: 'name',
194
- label: true,
195
- header: 'name',
196
- record: {
197
- editable: true,
198
- options: {
199
- // href: 'http://hatiolab.com',
200
- href: function (column, record, rowIndex) {
201
- return record['homepage']
202
- },
203
- target: '_blank'
204
- }
205
- },
206
- filter: 'search',
207
- sortable: true,
208
- width: 120
209
- },
210
- {
211
- type: 'string',
212
- name: 'description',
213
- header: 'description',
214
- filter: 'search',
215
- record: {
216
- editable: true,
217
- align: 'left'
218
- },
219
- width: 200,
220
- handlers: {
221
- click: (columns, data, column, record, rowIndex, target) => {
222
- alert(`${column.name} ${record[column.name]}, row : ${rowIndex}`)
223
- }
224
- }
225
- },
226
- {
227
- type: 'number',
228
- name: 'number',
229
- header: 'number',
230
- record: {
231
- format: '#,##0.0%'
232
- },
233
- width: 120
234
- },
235
- {
236
- type: 'email',
237
- name: 'email',
238
- label: true,
239
- header: 'email',
240
- record: {
241
- editable: true
242
- },
243
- filter: 'search',
244
- sortable: true,
245
- width: 130,
246
- validation: function (after, before, record, column) {
247
- if (after.indexOf('@') == -1) {
248
- document.dispatchEvent(
249
- new CustomEvent('notify', {
250
- detail: {
251
- type: 'error',
252
- message: `invalid value - ${after}`
253
- }
254
- })
255
- )
256
- return false
257
- }
258
- return true
259
- }
260
- },
261
- {
262
- type: 'boolean',
263
- name: 'active',
264
- header: 'active',
265
- record: {
266
- editable: true,
267
- align: 'center'
268
- },
269
- filter: true,
270
- handlers: {
271
- dblclick: () => {
272
- const grist = document.querySelector('ox-grist')
273
- console.log(grist.dirtyRecords)
274
- }
275
- },
276
- sortable: true,
277
- width: 60
278
- },
279
- {
280
- type: 'select-buttons',
281
- name: 'role',
282
- label: true,
283
- header: 'role',
284
- record: {
285
- options: ['', 'admin', 'worker', 'tester'],
286
- editable: true
287
- },
288
- filter: true,
289
- sortable: true,
290
- width: 120
291
- },
292
- {
293
- type: 'select',
294
- name: 'privilege',
295
- label: true,
296
- header: 'privilege',
297
- record: {
298
- options: ['read', 'write'],
299
- multiple: true,
300
- editable: true
301
- },
302
- filter: 'in',
303
- sortable: true,
304
- width: 120
305
- },
306
- {
307
- type: 'color',
308
- name: 'color',
309
- header: 'color',
310
- record: {
311
- editable: true
312
- },
313
- sortable: true,
314
- width: 50
315
- },
316
- {
317
- type: 'float',
318
- name: 'rate',
319
- header: 'rate',
320
- record: {
321
- align: 'right',
322
- editable: true
323
- },
324
- filter: 'between',
325
- sortable: true,
326
- width: 50
327
- },
328
- {
329
- type: 'json5',
330
- name: 'json5',
331
- header: 'JSON5',
332
- label: true,
333
- width: 200
334
- },
335
- {
336
- type: 'progress',
337
- name: 'rate',
338
- header: 'progress',
339
- record: {
340
- editable: true
341
- },
342
- width: 200
343
- },
344
- {
345
- type: 'image',
346
- name: 'thumbnail',
347
- header: 'thumbnail',
348
- record: {
349
- editable: true
350
- },
351
- handlers: {
352
- click: () => {
353
- console.log('thumbnail clicked...')
354
- }
355
- },
356
- width: 200
357
- },
358
- {
359
- type: 'file',
360
- name: 'file',
361
- header: 'file',
362
- record: {
363
- editable: true
364
- },
365
- handlers: {
366
- click: () => {
367
- console.log('thumbnail clicked...')
368
- }
369
- },
370
- width: 200
371
- },
372
- {
373
- type: 'datetime',
374
- name: 'updatedAt',
375
- header: 'updated at',
376
- record: {
377
- editable: true
378
- },
379
- filter: 'between',
380
- sortable: true,
381
- width: 180
382
- },
383
- {
384
- type: 'datetime',
385
- name: 'createdAt',
386
- header: 'created at',
387
- record: {
388
- editable: false
389
- },
390
- sortable: true,
391
- width: 180
392
- }
393
- ],
394
- rows: {
395
- selectable: {
396
- multiple: true
397
- },
398
- handlers: {
399
- click: 'select-row-toggle'
400
- },
401
- classifier: function (record, rowIndex) {
402
- const rate = record['rate']
403
- const emphasized =
404
- rate < 10 ? ['black', 'white'] : rate < 25 ? ['yellow', 'blue'] : rate < 40 ? ['cyan', 'red'] : undefined
405
- return {
406
- emphasized
407
- }
408
- }
409
- },
410
- sorters: [
411
- {
412
- name: 'name',
413
- desc: true
414
- },
415
- {
416
- name: 'email'
417
- }
418
- ],
419
- pagination: {
420
- pages: [30, 500, 1000, 1500, 2000]
421
- }
422
- }
423
-
424
- class GristDemo extends LitElement {
425
- static styles = [
426
- CommonGristStyles,
427
- css`
428
- :host {
429
- display: flex;
430
- flex-direction: column;
431
- }
432
-
433
- #tailer {
434
- display: flex;
435
- flex-direction: row;
436
- margin: 0 var(--margin-default);
437
- }
438
-
439
- #tailer a {
440
- padding: 0 var(--padding-default) 0 var(--padding-default);
441
- margin: 0 var(--spacing-small);
442
- border-right: 1px solid rgba(0, 0, 0, 0.1);
443
- font-size: var(--fontsize-default);
444
- color: var(--md-sys-color-on-primary-container);
445
- }
446
- `
447
- ]
448
-
449
- static get properties() {
450
- return {
451
- sorters: Object,
452
- filters: Object,
453
- mode: String
454
- }
455
- }
456
-
457
- get grist() {
458
- return this.renderRoot.querySelector('ox-grist')
459
- }
460
-
461
- render() {
462
- const mode = this.mode || 'CARD'
463
-
464
- return html`
465
- <ox-grist
466
- .config=${config}
467
- .mode=${mode}
468
- auto-fetch
469
- url-params-sensitive
470
- .fetchHandler=${fetchHandler}
471
- @filters-change=${e => console.log('changed', e.detail)}
472
- >
473
- <div slot="headroom">
474
- <ox-filters-form></ox-filters-form>
475
- </div>
476
-
477
- <div slot="headroom" id="headroom">
478
- <div id="tailer">
479
- <a href="./report-test.html">Report Test</a>
480
- <a
481
- href="#"
482
- @click=${() => {
483
- this.renderRoot.querySelector('ox-grist').reset()
484
- }}
485
- >Reset</a
486
- >
487
- <a
488
- href="#"
489
- @click=${() => {
490
- this.renderRoot.querySelector('ox-grist').fetch(true)
491
- }}
492
- >Fetch</a
493
- >
494
- </div>
495
-
496
- <div id="sorters">
497
- Sort
498
- <md-icon
499
- @click=${e => {
500
- const target = e.currentTarget
501
- this.renderRoot.querySelector('#sorter-control').open({
502
- right: 0,
503
- top: target.offsetTop + target.offsetHeight
504
- })
505
- }}
506
- >expand_more</md-icon
507
- >
508
- <ox-popup id="sorter-control">
509
- <ox-sorters-control> </ox-sorters-control>
510
- </ox-popup>
511
- </div>
512
-
513
- <div id="modes">
514
- <md-icon @click=${() => (this.mode = 'GRID')} ?active=${mode == 'GRID'}>view_list</md-icon>
515
- <md-icon @click=${() => (this.mode = 'LIST')} ?active=${mode == 'LIST'}>menu</md-icon>
516
- <md-icon @click=${() => (this.mode = 'CARD')} ?active=${mode == 'CARD'}>apps</md-icon>
517
- </div>
518
-
519
- <ox-record-creator id="add" light-popup>
520
- <button><md-icon>add</md-icon></button>
521
- </ox-record-creator>
522
-
523
- <button @click=${e => this.grist.cloneSelectedRecords()}><md-icon>add</md-icon></button>
524
- </div>
525
- </ox-grist>
526
- `
527
- }
528
- }
529
-
530
- customElements.define('grist-demo', GristDemo)
531
-
532
- setTimeout(() => {
533
- render(html` <grist-demo mode="GRID"></grist-demo> `, document.querySelector('#demo'))
534
- })
535
- </script>
536
-
537
- <div id="app">
538
- <div id="demo"></div>
539
- </div>
540
- </body>
541
- </html>
@@ -1,249 +0,0 @@
1
- <!doctype html>
2
- <html lang="en-GB">
3
- <head>
4
- <meta charset="utf-8" />
5
- <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" />
6
- <style>
7
- body {
8
- /* box-sizing: border-box; */
9
- margin: 0;
10
- padding: 0;
11
- overflow: hidden;
12
-
13
- /* This is a font-stack that tries to use the system-default sans-serifs first */
14
- font-family: Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol';
15
- line-height: 1.5;
16
- -webkit-font-smoothing: antialiased;
17
-
18
- width: 100vw;
19
- height: 100dvh;
20
-
21
- display: flex;
22
- flex-direction: column;
23
- }
24
-
25
- #demo {
26
- flex: 1;
27
- overflow: hidden;
28
-
29
- display: flex;
30
- flex-direction: column;
31
- }
32
-
33
- ox-report {
34
- flex: 1;
35
- }
36
- </style>
37
- <link href="https://fonts.googleapis.com/css?family=Roboto:300,400,500" rel="stylesheet" />
38
- <link
39
- href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL@20..48,100..700,0..1"
40
- rel="stylesheet"
41
- />
42
- <link
43
- href="https://fonts.googleapis.com/css2?family=Material+Symbols+Rounded:opsz,wght,FILL@20..48,100..700,0..1"
44
- rel="stylesheet"
45
- />
46
- <link
47
- href="https://fonts.googleapis.com/css2?family=Material+Symbols+Sharp:opsz,wght,FILL@20..48,100..700,0..1"
48
- rel="stylesheet"
49
- />
50
-
51
- <link href="/themes/app-theme.css" rel="stylesheet" />
52
- <link href="/themes/oops-theme.css" rel="stylesheet" />
53
- <link href="/themes/report-theme.css" rel="stylesheet" />
54
- </head>
55
- <body>
56
- <script type="module">
57
- import { html, render } from 'lit'
58
- import '../dist/index.js'
59
-
60
- const fetchHandler = async ({ page, limit, sorters = [] }) => {
61
- var limit = 500
62
- var total = 120993
63
- var start = (page - 1) * limit
64
-
65
- await new Promise(resolve => setTimeout(resolve, 1000))
66
-
67
- return {
68
- total,
69
- records: Array(limit * page > total ? total % limit : limit)
70
- .fill()
71
- .map((item, idx) => {
72
- return {
73
- id: idx,
74
- name: idx % 2 ? `shnam-${start + idx + 1}` : `heartyoh-${start + idx + 1}`,
75
- description: idx % 2 ? `hatiolab manager-${start + idx + 1}` : `hatiosea manager-${start + idx + 1}`,
76
- email: idx % 2 ? `shnam@gmail.com` : `heartyoh@gmail.com`,
77
- active: Math.round(Math.random() * 2) % 2 ? true : false,
78
- company: idx % 5 ? 'HatioLAB' : 'HatioSEA',
79
- role: ['admin', 'worker', 'tester'][idx % 3],
80
- color: idx % 2 ? `#87f018` : `#180f87`,
81
- height: Math.round(Math.random() * 100),
82
- weight: Math.round(Math.random() * 100),
83
- count: Math.round(Math.random() * 100),
84
- homepage:
85
- idx % 2
86
- ? `http://hatiolab.com/${start + idx + 1}`
87
- : `http://deadpool.hatiolab.com/${start + idx + 1}`,
88
- createdAt: Date.now(),
89
- updatedAt: Date.now()
90
- }
91
- })
92
- }
93
- }
94
-
95
- const config = {
96
- columns: [
97
- {
98
- type: 'string',
99
- name: 'company',
100
- header: 'company',
101
- record: {
102
- align: 'center',
103
- options: {}
104
- },
105
- sortable: false,
106
- width: 240
107
- },
108
- {
109
- type: 'email',
110
- name: 'email',
111
- header: 'email',
112
- record: {
113
- align: 'center'
114
- },
115
- sortable: false,
116
- width: 130
117
- },
118
- {
119
- type: 'string',
120
- name: 'id',
121
- hidden: true
122
- },
123
- {
124
- type: 'link',
125
- name: 'name',
126
- header: 'name',
127
- record: {
128
- align: 'center',
129
- editable: true,
130
- options: {
131
- // href: 'http://hatiolab.com',
132
- href: function (column, record, rowIndex) {
133
- return record['homepage']
134
- }
135
- // target: '_blank'
136
- }
137
- },
138
- sortable: false,
139
- width: 120
140
- },
141
- {
142
- type: 'string',
143
- name: 'description',
144
- header: 'description',
145
- record: {
146
- align: 'left'
147
- },
148
- width: 200,
149
- handlers: {
150
- dblclick: (columns, data, column, record, rowIndex) => {
151
- alert(`${column.name} ${record[column.name]}, row : ${rowIndex}`)
152
- }
153
- }
154
- },
155
- {
156
- type: 'boolean',
157
- name: 'active',
158
- header: 'active',
159
- record: {
160
- align: 'center'
161
- },
162
- handlers: {
163
- dblclick: () => {
164
- console.log(this.report.dirtyRecords)
165
- }
166
- },
167
- sortable: false,
168
- width: 60
169
- },
170
- {
171
- type: 'string',
172
- name: 'role',
173
- header: 'role',
174
- record: {
175
- align: 'center'
176
- },
177
- sortable: false,
178
- width: 120
179
- },
180
- {
181
- type: 'number',
182
- name: 'weight',
183
- header: 'weight',
184
- record: {},
185
- sortable: false,
186
- width: 50
187
- },
188
- {
189
- type: 'number',
190
- name: 'height',
191
- header: 'height',
192
- record: {},
193
- sortable: false,
194
- width: 50
195
- },
196
- {
197
- type: 'number',
198
- name: 'count',
199
- header: 'count',
200
- record: {},
201
- sortable: false,
202
- width: 50
203
- },
204
- {
205
- type: 'datetime',
206
- name: 'updatedAt',
207
- header: 'updated_at',
208
- record: {
209
- align: 'center'
210
- },
211
- sortable: false,
212
- width: 180
213
- },
214
- {
215
- type: 'datetime',
216
- name: 'createdAt',
217
- header: 'created_at',
218
- record: {
219
- align: 'center'
220
- },
221
- sortable: false,
222
- width: 180
223
- }
224
- ],
225
- rows: {
226
- groups: [{ column: 'company', title: 'company total', align: 'right' }, { column: 'email' }],
227
- totals: ['weight', 'height', 'count']
228
- },
229
- sorters: [
230
- {
231
- name: 'company',
232
- desc: true
233
- },
234
- {
235
- name: 'email'
236
- }
237
- ]
238
- }
239
-
240
- render(
241
- html` <ox-report .config=${config} .fetchHandler=${fetchHandler} auto-fetch></ox-report> `,
242
- document.querySelector('#demo')
243
- )
244
- </script>
245
-
246
- <a href="./index.html">Grist Test</a>
247
- <div id="demo"></div>
248
- </body>
249
- </html>