@operato/data-grist 1.11.22 → 1.12.0

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 (64) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/dist/src/configure/config-builder.js +3 -1
  3. package/dist/src/configure/config-builder.js.map +1 -1
  4. package/dist/src/configure/tree-option-builder.d.ts +2 -0
  5. package/dist/src/configure/tree-option-builder.js +7 -0
  6. package/dist/src/configure/tree-option-builder.js.map +1 -0
  7. package/dist/src/configure/zero-config.d.ts +2 -1
  8. package/dist/src/configure/zero-config.js +5 -1
  9. package/dist/src/configure/zero-config.js.map +1 -1
  10. package/dist/src/data-card/data-card-field.js +0 -5
  11. package/dist/src/data-card/data-card-field.js.map +1 -1
  12. package/dist/src/data-grid/data-grid-accum-field.js +0 -6
  13. package/dist/src/data-grid/data-grid-accum-field.js.map +1 -1
  14. package/dist/src/data-grid/data-grid-body.js +8 -0
  15. package/dist/src/data-grid/data-grid-body.js.map +1 -1
  16. package/dist/src/data-grid/data-grid-field.d.ts +1 -0
  17. package/dist/src/data-grid/data-grid-field.js +3 -6
  18. package/dist/src/data-grid/data-grid-field.js.map +1 -1
  19. package/dist/src/data-grid/data-grid-header.js +0 -6
  20. package/dist/src/data-grid/data-grid-header.js.map +1 -1
  21. package/dist/src/data-grist.d.ts +21 -13
  22. package/dist/src/data-grist.js +162 -77
  23. package/dist/src/data-grist.js.map +1 -1
  24. package/dist/src/data-list/data-list-field.js +0 -5
  25. package/dist/src/data-list/data-list-field.js.map +1 -1
  26. package/dist/src/data-list/record-partial.js +0 -5
  27. package/dist/src/data-list/record-partial.js.map +1 -1
  28. package/dist/src/editors/ox-grist-editor.js +0 -4
  29. package/dist/src/editors/ox-grist-editor.js.map +1 -1
  30. package/dist/src/renderers/ox-grist-renderer-tree.d.ts +11 -0
  31. package/dist/src/renderers/ox-grist-renderer-tree.js +177 -0
  32. package/dist/src/renderers/ox-grist-renderer-tree.js.map +1 -0
  33. package/dist/src/renderers/registry.js +3 -1
  34. package/dist/src/renderers/registry.js.map +1 -1
  35. package/dist/src/types.d.ts +8 -0
  36. package/dist/src/types.js.map +1 -1
  37. package/dist/stories/accumulator.stories.js +5 -1
  38. package/dist/stories/accumulator.stories.js.map +1 -1
  39. package/dist/stories/grist-modes.stories.js +5 -0
  40. package/dist/stories/grist-modes.stories.js.map +1 -1
  41. package/dist/stories/tree-column.stories.d.ts +26 -0
  42. package/dist/stories/tree-column.stories.js +325 -0
  43. package/dist/stories/tree-column.stories.js.map +1 -0
  44. package/dist/tsconfig.tsbuildinfo +1 -1
  45. package/package.json +2 -2
  46. package/src/configure/config-builder.ts +3 -1
  47. package/src/configure/tree-option-builder.ts +8 -0
  48. package/src/configure/zero-config.ts +7 -1
  49. package/src/data-card/data-card-field.ts +0 -5
  50. package/src/data-grid/data-grid-accum-field.ts +0 -6
  51. package/src/data-grid/data-grid-body.ts +8 -0
  52. package/src/data-grid/data-grid-field.ts +3 -6
  53. package/src/data-grid/data-grid-header.ts +0 -6
  54. package/src/data-grist.ts +212 -101
  55. package/src/data-list/data-list-field.ts +0 -5
  56. package/src/data-list/record-partial.ts +0 -5
  57. package/src/editors/ox-grist-editor.ts +0 -4
  58. package/src/renderers/ox-grist-renderer-tree.ts +182 -0
  59. package/src/renderers/registry.ts +3 -1
  60. package/src/types.ts +10 -0
  61. package/stories/accumulator.stories.ts +5 -1
  62. package/stories/grist-modes.stories.ts +5 -0
  63. package/stories/tree-column.stories.ts +353 -0
  64. package/themes/grist-theme.css +0 -7
@@ -0,0 +1,182 @@
1
+ import { PropertyValues, css, html } from 'lit'
2
+ import { customElement, property, state } from 'lit/decorators.js'
3
+ import { ifDefined } from 'lit/directives/if-defined.js'
4
+
5
+ import { OxGristRenderer } from './ox-grist-renderer'
6
+
7
+ @customElement('ox-grist-tree-renderer')
8
+ export class OxGristRendererTree extends OxGristRenderer {
9
+ static styles = css`
10
+ :host {
11
+ overflow: hidden;
12
+ }
13
+
14
+ div[wrap] {
15
+ position: relative;
16
+
17
+ display: flex;
18
+ align-items: center;
19
+ gap: 6px;
20
+
21
+ width: 100%;
22
+ padding-left: calc(var(--tree-depth, 0) * 18px);
23
+ }
24
+
25
+ span[expander] {
26
+ display: inline-block;
27
+ vertical-align: middle;
28
+ width: 12px;
29
+ height: 20px;
30
+ cursor: pointer;
31
+ position: relative;
32
+ }
33
+
34
+ span[expander][collapsed]::before {
35
+ position: absolute;
36
+ top: 50%;
37
+ left: 50%;
38
+ transform: translate(-25%, -50%) rotate(-90deg);
39
+ content: ' ';
40
+ border: 5px solid transparent;
41
+ border-top: 5px solid var(--primary-color, #1890ff);
42
+ }
43
+
44
+ span[expander][expanded]::before {
45
+ position: absolute;
46
+ top: 50%;
47
+ left: 50%;
48
+ transform: translate(-50%, -25%);
49
+ content: ' ';
50
+ border: 5px solid transparent;
51
+ border-top: 5px solid var(--primary-color, #1890ff);
52
+ }
53
+
54
+ span[checkbox] {
55
+ display: inline-block;
56
+ vertical-align: middle;
57
+ width: 12px;
58
+ height: 20px;
59
+ cursor: pointer;
60
+ position: relative;
61
+ }
62
+
63
+ span[checkbox]::before {
64
+ cursor: pointer;
65
+ position: absolute;
66
+ top: 50%;
67
+ left: 50%;
68
+ transform: translate(-50%, -50%);
69
+ content: ' ';
70
+ display: block;
71
+ width: 10px;
72
+ height: 10px;
73
+ border: 1px solid var(--primary-color, #1890ff);
74
+ border-radius: 2px;
75
+ }
76
+
77
+ span[label][selected] {
78
+ background-color: var(--primary-color, #1890ff);
79
+ }
80
+
81
+ span[checkbox][checked='checked']::before {
82
+ background-color: var(--primary-color, #1890ff);
83
+ border-color: var(--primary-color, #1890ff);
84
+ }
85
+
86
+ span[checkbox][checked='checked']::after {
87
+ position: absolute;
88
+ content: ' ';
89
+ display: block;
90
+ top: 50%;
91
+ left: 50%;
92
+ width: 3px;
93
+ height: 7px;
94
+ border: 2px solid #fff;
95
+ border-top: none;
96
+ border-left: none;
97
+ -webkit-transform: translate(-50%, -50%) rotate(45deg);
98
+ -ms-transform: translate(-50%, -50%) rotate(45deg);
99
+ transform: translate(-50%, -50%) rotate(45deg);
100
+ }
101
+
102
+ span[checkbox][checked='half-checked']::before {
103
+ background-color: var(--primary-color, #1890ff);
104
+ border-color: var(--primary-color, #1890ff);
105
+ }
106
+
107
+ span[checkbox][checked='half-checked']::after {
108
+ position: absolute;
109
+ content: ' ';
110
+ display: block;
111
+ top: 50%;
112
+ left: 50%;
113
+ transform: translate(-50%, -50%);
114
+ width: 10px;
115
+ height: 2px;
116
+ background-color: #fff;
117
+ }
118
+ `
119
+
120
+ @state() private checked?: 'checked' | 'half-checked' | 'unchecked'
121
+ @state() private expanded?: boolean = false
122
+
123
+ get rendererTemplate() {
124
+ var { childrenProperty = 'children' } = this.column.record.options || {}
125
+ var { [childrenProperty]: children } = this.record
126
+
127
+ const expandable = children && children.length > 0
128
+
129
+ return html`
130
+ <div wrap>
131
+ ${expandable
132
+ ? html`
133
+ <span
134
+ expander
135
+ @click=${this.onClickExpander.bind(this)}
136
+ ?expanded=${this.expanded}
137
+ ?collapsed=${!this.expanded}
138
+ ></span>
139
+ `
140
+ : html`<span expander></span>`}
141
+ <span checkbox @click=${this.onClickCheckbox.bind(this)} checked=${ifDefined(this.checked)}></span>
142
+ <span label>${this.value}</span>
143
+ </div>
144
+ `
145
+ }
146
+
147
+ updated(changes: PropertyValues<this>) {
148
+ var { __depth__, __check_in_tree__, __expanded__ } = this.record
149
+ this.checked = __check_in_tree__
150
+ this.expanded = __expanded__
151
+
152
+ this.style.setProperty('--tree-depth', String(__depth__))
153
+ }
154
+
155
+ onClickCheckbox(e: MouseEvent) {
156
+ e.stopPropagation()
157
+
158
+ this.dispatchEvent(
159
+ new CustomEvent('check-in-tree', {
160
+ bubbles: true,
161
+ composed: true,
162
+ detail: this.record
163
+ })
164
+ )
165
+
166
+ this.requestUpdate()
167
+ }
168
+
169
+ onClickExpander(e: MouseEvent) {
170
+ e.stopPropagation()
171
+
172
+ this.dispatchEvent(
173
+ new CustomEvent(this.record.__expanded__ ? 'collapsed' : 'expanded', {
174
+ bubbles: true,
175
+ composed: true,
176
+ detail: this.record
177
+ })
178
+ )
179
+
180
+ this.requestUpdate()
181
+ }
182
+ }
@@ -19,6 +19,7 @@ import { OxGristRendererProgress } from './ox-grist-renderer-progress.js'
19
19
  import { OxGristRendererSelect } from './ox-grist-renderer-select.js'
20
20
  import { OxGristRendererText } from './ox-grist-renderer-text.js'
21
21
  import { OxGristRendererTextarea } from './ox-grist-renderer-textarea.js'
22
+ import { OxGristRendererTree } from './ox-grist-renderer-tree.js'
22
23
  import { OxGristRenderer } from './ox-grist-renderer.js'
23
24
 
24
25
  interface OxGristRendererConstructor {
@@ -54,7 +55,8 @@ var RENDERERS: {
54
55
  link: OxGristRendererLink,
55
56
  image: OxGristRendererImage,
56
57
  file: OxGristRendererFile,
57
- json5: OxGristRendererJson5
58
+ json5: OxGristRendererJson5,
59
+ tree: OxGristRendererTree
58
60
  }
59
61
 
60
62
  export function registerRenderer(type: string, renderer: FieldRenderer) {
package/src/types.ts CHANGED
@@ -16,6 +16,7 @@ export type GristConfig = {
16
16
  columns: ColumnConfig[]
17
17
  rows: RowsConfig
18
18
  list: ListConfig
19
+ tree: TreeConfig
19
20
  pagination?: PaginationConfig
20
21
  sorters?: SortersConfig
21
22
  filters?: FiltersConfig
@@ -234,6 +235,10 @@ export type ListConfig = {
234
235
  details: string[]
235
236
  }
236
237
 
238
+ export type TreeConfig = {
239
+ childrenProperty?: string
240
+ }
241
+
237
242
  export type ImexConfig = {
238
243
  header: string
239
244
  key: string
@@ -276,12 +281,17 @@ export type RowSelectableConfig = {
276
281
  export type GristRecord = {
277
282
  id?: string
278
283
  name?: string
284
+ children?: GristRecord[]
279
285
  __seq__?: number
280
286
  __dirty__?: string
281
287
  __selected__?: boolean
282
288
  __changes__?: object[]
283
289
  __dirtyfields__?: { [key: string]: any }
284
290
  __origin__?: any
291
+ __collapsed__?: boolean
292
+ __depth__?: number
293
+ __check_in_tree__?: 'checked' | 'half-checked' | 'unchecked'
294
+ // __children__?: GristRecord[]
285
295
  [key: string]: any
286
296
  }
287
297
 
@@ -17,7 +17,7 @@ import {
17
17
  } from '../src/types.js'
18
18
 
19
19
  const fetchHandler: FetchHandler = async ({ page, limit }) => {
20
- var total = 3
20
+ var total = 25
21
21
  var start = (page! - 1) * limit!
22
22
 
23
23
  await new Promise(resolve => setTimeout(resolve, 500))
@@ -192,6 +192,10 @@ const Template: Story<ArgTypes> = ({
192
192
  <link href="/themes/grist-theme.css" rel="stylesheet" />
193
193
 
194
194
  <style>
195
+ ox-grist {
196
+ height: 600px;
197
+ }
198
+
195
199
  [slot='headroom'] {
196
200
  display: flex;
197
201
  flex-direction: row;
@@ -347,6 +347,11 @@ const Template: Story<ArgTypes> = ({
347
347
  <link href="/themes/grist-theme.css" rel="stylesheet" />
348
348
 
349
349
  <style>
350
+ ox-grist {
351
+ width: 100%;
352
+ height: 600px;
353
+ }
354
+
350
355
  [slot='headroom'] {
351
356
  display: flex;
352
357
  flex-direction: row;
@@ -0,0 +1,353 @@
1
+ import '../src/index.js'
2
+ import '../src/filters/filters-form.js'
3
+ import '../src/sorters/sorters-control.js'
4
+ import '../src/record-view/record-creator.js'
5
+ import '@operato/popup/ox-popup-list.js'
6
+ import '@material/mwc-icon'
7
+
8
+ import { html, TemplateResult } from 'lit'
9
+
10
+ import {
11
+ ColumnConfig,
12
+ FetchHandler,
13
+ GristClassifier,
14
+ GristEventHandlerSet,
15
+ GristRecord,
16
+ ValidationCallback
17
+ } from '../src/types.js'
18
+
19
+ const fetchHandler: FetchHandler = async ({ page, limit }) => {
20
+ var total = 120993
21
+ var start = (page! - 1) * limit!
22
+
23
+ await new Promise(resolve => setTimeout(resolve, 500))
24
+
25
+ var records = Array(limit! * page! > total ? total % limit! : limit)
26
+ .fill('')
27
+ .map((item, idx) => {
28
+ return {
29
+ id: String(idx),
30
+ name: idx % 2 ? `shnam-${start + idx + 1}` : `heartyoh-${start + idx + 1}`,
31
+ description: idx % 2 ? `hatiolabmanager${start + idx + 1}1234567890` : `hatiosea manager-${start + idx + 1}`,
32
+ active: Math.round(Math.random() * 2) % 2 ? true : false,
33
+ accval: Math.random(),
34
+ createdAt: Date.now(),
35
+ updatedAt: Date.now(),
36
+ children: [
37
+ ...Array.from({ length: 3 }, (_, idx) => {
38
+ return {
39
+ id: `sub:${idx}`,
40
+ name: 'subitem' + idx,
41
+ description: 'sub items...',
42
+ active: Math.round(Math.random() * 2) % 2 ? true : false,
43
+ children: [
44
+ ...Array.from({ length: 3 }, (_, idx2) => {
45
+ return {
46
+ id: `sub-sub:${idx}:${idx2}`,
47
+ name: 'sub-subitem:' + idx2,
48
+ description: 'sub sub items...',
49
+ active: Math.round(Math.random() * 2) % 2 ? true : false,
50
+ accval: Math.random(),
51
+ children: [],
52
+ createdAt: Date.now(),
53
+ updatedAt: Date.now()
54
+ }
55
+ })
56
+ ],
57
+ createdAt: Date.now(),
58
+ updatedAt: Date.now()
59
+ }
60
+ })
61
+ ]
62
+ }
63
+ })
64
+
65
+ return {
66
+ total,
67
+ records
68
+ }
69
+ }
70
+
71
+ const config = {
72
+ list: {
73
+ thumbnail: 'thumbnail',
74
+ fields: ['name', 'description'],
75
+ details: ['role', 'email']
76
+ },
77
+ columns: [
78
+ {
79
+ type: 'gutter',
80
+ gutterName: 'dirty',
81
+ fixed: true
82
+ },
83
+ // {
84
+ // type: 'gutter',
85
+ // gutterName: 'sequence',
86
+ // fixed: true
87
+ // },
88
+ {
89
+ type: 'tree',
90
+ name: 'name',
91
+ label: true,
92
+ header: 'name',
93
+ record: {
94
+ editable: false,
95
+ childrenProperty: 'children'
96
+ },
97
+ filter: 'search',
98
+ sortable: true,
99
+ width: 200,
100
+ fixed: true
101
+ },
102
+ {
103
+ type: 'gutter',
104
+ gutterName: 'row-selector',
105
+ multiple: true
106
+ },
107
+ {
108
+ type: 'string',
109
+ name: 'description',
110
+ header: 'description',
111
+ filter: 'search',
112
+ record: {
113
+ editable: true,
114
+ align: 'left'
115
+ },
116
+ width: 200
117
+ },
118
+ {
119
+ type: 'boolean',
120
+ name: 'active',
121
+ header: 'active',
122
+ record: {
123
+ editable: true
124
+ },
125
+ filter: true,
126
+ sortable: true,
127
+ width: 60
128
+ },
129
+ {
130
+ type: 'number',
131
+ name: 'accval',
132
+ label: true,
133
+ header: 'accval',
134
+ record: {
135
+ editable: true,
136
+ align: 'right'
137
+ },
138
+ accumulator: 'sum',
139
+ sortable: true,
140
+ width: 130
141
+ },
142
+ {
143
+ type: 'datetime',
144
+ name: 'updatedAt',
145
+ header: 'updated at',
146
+ record: {
147
+ editable: true,
148
+ defaultValue: {
149
+ name: 'now'
150
+ }
151
+ },
152
+ filter: 'between',
153
+ sortable: true,
154
+ width: 180
155
+ }
156
+ ],
157
+ rows: {
158
+ selectable: {
159
+ multiple: true
160
+ },
161
+ handlers: {
162
+ // focus: 'select-row-toggle'
163
+ },
164
+ classifier: function (record, rowIndex) {
165
+ const rate = record['rate']
166
+ const emphasized =
167
+ rate < 10 ? ['black', 'white'] : rate < 25 ? ['yellow', 'blue'] : rate < 40 ? ['cyan', 'red'] : undefined
168
+ return {
169
+ emphasized
170
+ }
171
+ } as GristClassifier,
172
+ accumulator: true
173
+ },
174
+ sorters: [
175
+ {
176
+ name: 'name',
177
+ desc: true
178
+ },
179
+ {
180
+ name: 'email'
181
+ }
182
+ ],
183
+ pagination: {
184
+ pages: [20, 30, 50, 100, 200]
185
+ }
186
+ }
187
+
188
+ export default {
189
+ title: 'tree column',
190
+ component: 'ox-grist',
191
+ argTypes: {
192
+ config: { control: 'object' }
193
+ }
194
+ }
195
+
196
+ interface Story<T> {
197
+ (args: T): TemplateResult
198
+ args?: Partial<T>
199
+ argTypes?: Record<string, unknown>
200
+ }
201
+
202
+ interface ArgTypes {
203
+ config: object
204
+ }
205
+
206
+ const Template: Story<ArgTypes> = ({ config }: ArgTypes) => html` <link
207
+ href="https://fonts.googleapis.com/css?family=Material+Icons&display=block"
208
+ rel="stylesheet"
209
+ />
210
+ <link href="/themes/app-theme.css" rel="stylesheet" />
211
+ <link href="/themes/oops-theme.css" rel="stylesheet" />
212
+ <link href="/themes/grist-theme.css" rel="stylesheet" />
213
+
214
+ <style>
215
+ ox-grist {
216
+ width: 100%;
217
+ height: 600px;
218
+ }
219
+
220
+ [slot='headroom'] {
221
+ display: flex;
222
+ flex-direction: row;
223
+ align-items: center;
224
+ padding: var(--padding-default) var(--padding-wide);
225
+ background-color: var(--theme-white-color);
226
+ box-shadow: var(--box-shadow);
227
+
228
+ --mdc-icon-size: 24px;
229
+ }
230
+ #sorters mwc-icon,
231
+ #modes mwc-icon {
232
+ --mdc-icon-size: 18px;
233
+ }
234
+ #sorters {
235
+ margin-left: auto;
236
+ margin-right: var(--margin-default);
237
+ padding-left: var(--padding-narrow);
238
+ border-bottom: var(--border-dark-color);
239
+ position: relative;
240
+ color: var(--secondary-color);
241
+ font-size: var(--fontsize-default);
242
+ user-select: none;
243
+ }
244
+
245
+ #sorters > * {
246
+ padding: var(--padding-narrow);
247
+ vertical-align: middle;
248
+ }
249
+
250
+ #modes > * {
251
+ padding: var(--padding-narrow);
252
+ opacity: 0.5;
253
+ color: var(--primary-text-color);
254
+ cursor: pointer;
255
+ }
256
+
257
+ #modes > mwc-icon[active] {
258
+ border-radius: 9px;
259
+ background-color: rgba(var(--primary-color-rgb), 0.05);
260
+ opacity: 1;
261
+ color: var(--secondary-text-color);
262
+ cursor: default;
263
+ }
264
+
265
+ #modes > mwc-icon:hover {
266
+ opacity: 1;
267
+ color: var(--secondary-text-color);
268
+ }
269
+
270
+ #add {
271
+ width: 50px;
272
+ text-align: right;
273
+ }
274
+
275
+ #add button {
276
+ background-color: var(--primary-color);
277
+ border: 0;
278
+ border-radius: 50%;
279
+ padding: 5px;
280
+ width: 36px;
281
+ height: 36px;
282
+ cursor: pointer;
283
+ }
284
+
285
+ #add button:hover {
286
+ background-color: var(--focus-background-color);
287
+ box-shadow: var(--box-shadow);
288
+ }
289
+
290
+ #add button mwc-icon {
291
+ font-size: 2em;
292
+ color: var(--theme-white-color);
293
+ }
294
+
295
+ #filters {
296
+ display: flex;
297
+ justify-content: center;
298
+ align-items: center;
299
+ }
300
+
301
+ #filters * {
302
+ margin-right: var(--margin-default);
303
+ }
304
+
305
+ @media only screen and (max-width: 460px) {
306
+ #filters {
307
+ flex-direction: column;
308
+ }
309
+
310
+ #modes {
311
+ display: none;
312
+ }
313
+ }
314
+ </style>
315
+
316
+ <ox-grist
317
+ mode="GRID"
318
+ .config=${config}
319
+ .fetchHandler=${fetchHandler}
320
+ @filters-change=${(e: Event) => console.log('filters', (e.target as any).filters)}
321
+ >
322
+ <div slot="headroom">
323
+ <div id="filters">
324
+ <ox-filters-form autofocus></ox-filters-form>
325
+ </div>
326
+
327
+ <div id="sorters">
328
+ Sort
329
+ <mwc-icon
330
+ @click=${(e: Event) => {
331
+ const target = e.currentTarget as HTMLElement
332
+ ;(target.closest('#sorters')!.querySelector('#sorter-control') as any).open({
333
+ right: 0,
334
+ top: target.offsetTop + target.offsetHeight
335
+ })
336
+ }}
337
+ >expand_more</mwc-icon
338
+ >
339
+ <ox-popup id="sorter-control">
340
+ <ox-sorters-control> </ox-sorters-control>
341
+ </ox-popup>
342
+ </div>
343
+
344
+ <ox-record-creator id="add" light-popup>
345
+ <button><mwc-icon>add</mwc-icon></button>
346
+ </ox-record-creator>
347
+ </div>
348
+ </ox-grist>`
349
+
350
+ export const Regular = Template.bind({})
351
+ Regular.args = {
352
+ config
353
+ }
@@ -18,7 +18,6 @@ body {
18
18
  --grist-object-editor-font: normal 1em var(--theme-font);
19
19
  --grist-object-editor-color: var(--secondary-color);
20
20
 
21
- --grist-input-zoom: 1;
22
21
  --grist-input-progress-border: 1px solid rgba(255, 255, 255, 0.5);
23
22
  --grist-input-progress-background: rgba(121, 110, 110, 0.1);
24
23
  --grist-input-progress-bar-background: #4ac5fd;
@@ -150,12 +149,6 @@ body {
150
149
  --ox-grist-padding: var(--padding-default) var(--padding-default) 0 var(--padding-default);
151
150
  }
152
151
 
153
- @media print {
154
- body {
155
- --grist-input-zoom: 0.7;
156
- }
157
- }
158
-
159
152
  @media only screen and (max-width: 460px) {
160
153
  body {
161
154
  --record-view-label-font: bold 15px/32px var(--theme-font);