ywana-core8 0.0.1
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/dist/index.cjs +2 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.css +2 -0
- package/dist/index.css.map +1 -0
- package/dist/index.modern.js +2 -0
- package/dist/index.modern.js.map +1 -0
- package/dist/index.umd.js +2 -0
- package/dist/index.umd.js.map +1 -0
- package/package.json +27 -0
- package/publish.sh +5 -0
- package/src/css/fonts.css +162 -0
- package/src/css/html.css +36 -0
- package/src/css/theme.css +89 -0
- package/src/css/theme_dark.css +85 -0
- package/src/css/theme_light.css +87 -0
- package/src/domain/CollectionPage.css +34 -0
- package/src/domain/CollectionPage.js +346 -0
- package/src/domain/ContentEditor.css +174 -0
- package/src/domain/ContentEditor.js +425 -0
- package/src/domain/ContentForm.js +74 -0
- package/src/domain/ContentType.js +187 -0
- package/src/domain/CreateContentDialog.js +59 -0
- package/src/domain/EditContentDialog.js +50 -0
- package/src/domain/TablePage.css +29 -0
- package/src/domain/TablePage.js +395 -0
- package/src/domain/index.js +5 -0
- package/src/fonts/Assistant-Bold.ttf +0 -0
- package/src/fonts/Assistant-ExtraBold.ttf +0 -0
- package/src/fonts/Assistant-ExtraLight.ttf +0 -0
- package/src/fonts/Assistant-Light.ttf +0 -0
- package/src/fonts/Assistant-Medium.ttf +0 -0
- package/src/fonts/Assistant-Regular.ttf +0 -0
- package/src/fonts/Assistant-SemiBold.ttf +0 -0
- package/src/fonts/Assistant-VariableFont_wght.ttf +0 -0
- package/src/html/button.css +79 -0
- package/src/html/button.js +26 -0
- package/src/html/checkbox.css +51 -0
- package/src/html/checkbox.js +33 -0
- package/src/html/chip.css +63 -0
- package/src/html/chip.js +39 -0
- package/src/html/form.css +17 -0
- package/src/html/form.js +80 -0
- package/src/html/header.css +64 -0
- package/src/html/header.js +30 -0
- package/src/html/icon.css +53 -0
- package/src/html/icon.js +21 -0
- package/src/html/index.js +18 -0
- package/src/html/list.css +72 -0
- package/src/html/list.js +78 -0
- package/src/html/menu.css +76 -0
- package/src/html/menu.js +80 -0
- package/src/html/progress.css +20 -0
- package/src/html/progress.js +27 -0
- package/src/html/property.css +18 -0
- package/src/html/property.js +16 -0
- package/src/html/radio.css +50 -0
- package/src/html/radio.js +25 -0
- package/src/html/section.css +6 -0
- package/src/html/section.js +31 -0
- package/src/html/tab.css +45 -0
- package/src/html/tab.js +68 -0
- package/src/html/table.css +56 -0
- package/src/html/table.js +186 -0
- package/src/html/text.js +20 -0
- package/src/html/textfield-outlined.css +52 -0
- package/src/html/textfield.css +130 -0
- package/src/html/textfield.js +99 -0
- package/src/html/tokenfield.css +51 -0
- package/src/html/tokenfield.js +74 -0
- package/src/html/tree.css +63 -0
- package/src/html/tree.js +49 -0
- package/src/http/client.js +62 -0
- package/src/http/index.js +2 -0
- package/src/http/session.js +39 -0
- package/src/index.js +9 -0
- package/src/site/details.css +58 -0
- package/src/site/dialog.css +63 -0
- package/src/site/dialog.js +43 -0
- package/src/site/index.js +3 -0
- package/src/site/layouts.css +27 -0
- package/src/site/page.css +44 -0
- package/src/site/page.js +36 -0
- package/src/site/site.css +85 -0
- package/src/site/site.js +234 -0
- package/src/site/siteContext.js +4 -0
- package/src/site/workspace.js +57 -0
- package/src/upload/UploadArea.js +64 -0
- package/src/upload/UploadDialog.js +41 -0
- package/src/upload/UploadFile.js +31 -0
- package/src/upload/index.js +1 -0
- package/src/upload/uploader.css +57 -0
- package/src/upload/uploader.js +69 -0
- package/src/widgets/index.js +4 -0
- package/src/widgets/kanban/Kanban.css +80 -0
- package/src/widgets/kanban/Kanban.js +65 -0
- package/src/widgets/login/LoginBox.css +89 -0
- package/src/widgets/login/LoginBox.js +66 -0
- package/src/widgets/login/ResetPasswordBox.css +50 -0
- package/src/widgets/login/ResetPasswordBox.js +56 -0
- package/src/widgets/viewer/Viewer.css +87 -0
- package/src/widgets/viewer/Viewer.js +47 -0
@@ -0,0 +1,346 @@
|
|
1
|
+
import { Fragment, useContext, useEffect, useState, useRef } from 'react'
|
2
|
+
import equal from 'deep-equal'
|
3
|
+
import { Content, ContentEditor, EditContentDialog, TabbedContentEditor, TreededContentEditor } from '.'
|
4
|
+
import { HTTPClient, Session, PageContext, SiteContext } from '..'
|
5
|
+
import { Header, List, Text, Button, Icon, MenuIcon, Menu, MenuItem, Tree, TreeNode, TreeItem } from '../html'
|
6
|
+
import "./CollectionPage.css"
|
7
|
+
|
8
|
+
const http = HTTPClient(window.API || process.env.REACT_APP_API, Session);
|
9
|
+
|
10
|
+
/**
|
11
|
+
* Collection Page
|
12
|
+
*/
|
13
|
+
export const CollectionPage = (props) => {
|
14
|
+
|
15
|
+
const site = useContext(SiteContext)
|
16
|
+
const { id = "collection", icon, title, name = "Collection 1", schema, url, groupBy, editor, field, autosave = false, delay = 1000, actions, levels } = props
|
17
|
+
const [pageContext, setPageContext] = useContext(PageContext)
|
18
|
+
const context = CollectionContext(url, field)
|
19
|
+
|
20
|
+
useEffect(async () => {
|
21
|
+
await context.load()
|
22
|
+
setPageContext(context)
|
23
|
+
}, [])
|
24
|
+
|
25
|
+
async function reload() {
|
26
|
+
await pageContext.load()
|
27
|
+
setPageContext(Object.assign({}, pageContext))
|
28
|
+
}
|
29
|
+
|
30
|
+
function add() {
|
31
|
+
const onOK = async (form) => {
|
32
|
+
await pageContext.create(form);
|
33
|
+
setPageContext(Object.assign({}, pageContext))
|
34
|
+
}
|
35
|
+
site.openDialog(<EditContentDialog label={`Crear ${name}`} type={schema} onOK={onOK} />);
|
36
|
+
}
|
37
|
+
|
38
|
+
return (
|
39
|
+
<Fragment>
|
40
|
+
<Header className="collection-page" title={<Text>{title}</Text>}>
|
41
|
+
<Button icon="add" label="Add" action={add} />
|
42
|
+
<Button icon="refresh" label="Reload" action={reload} />
|
43
|
+
{actions}
|
44
|
+
</Header>
|
45
|
+
<menu className="collection-page">
|
46
|
+
<Header title={<Text>Lista de {name}</Text>} >
|
47
|
+
</Header>
|
48
|
+
{levels ? <CollectionTree levels={levels} /> : <CollectionList groupBy={groupBy} />}
|
49
|
+
</menu>
|
50
|
+
<main key={id} className="collection-page">
|
51
|
+
<CollectionEditor icon={icon} schema={schema} layout={editor} autosave={autosave} delay={delay} />
|
52
|
+
</main>
|
53
|
+
</Fragment>
|
54
|
+
)
|
55
|
+
}
|
56
|
+
|
57
|
+
/**
|
58
|
+
* Collection List
|
59
|
+
*/
|
60
|
+
const CollectionList = (props) => {
|
61
|
+
|
62
|
+
const { groupBy } = props
|
63
|
+
const [pageContext, setPageContext] = useContext(PageContext)
|
64
|
+
const { all = [] } = pageContext
|
65
|
+
|
66
|
+
function clear() {
|
67
|
+
pageContext.clear()
|
68
|
+
setPageContext(Object.assign({}, pageContext))
|
69
|
+
}
|
70
|
+
|
71
|
+
async function select(id) {
|
72
|
+
clear()
|
73
|
+
await pageContext.select(id)
|
74
|
+
setPageContext(Object.assign({}, pageContext))
|
75
|
+
}
|
76
|
+
|
77
|
+
const items = all ? all.map(content => ({
|
78
|
+
id: content.id,
|
79
|
+
line1: content.name,
|
80
|
+
line2: content.description,
|
81
|
+
content
|
82
|
+
})) : []
|
83
|
+
|
84
|
+
return (
|
85
|
+
<List items={items} onSelect={select} groupBy={groupBy} />
|
86
|
+
)
|
87
|
+
}
|
88
|
+
|
89
|
+
/**
|
90
|
+
* Collection Tree
|
91
|
+
*/
|
92
|
+
const CollectionTree = (props) => {
|
93
|
+
|
94
|
+
const { levels } = props
|
95
|
+
const [pageContext, setPageContext] = useContext(PageContext)
|
96
|
+
const { all = [] } = pageContext
|
97
|
+
|
98
|
+
function clear() {
|
99
|
+
pageContext.clear()
|
100
|
+
setPageContext(Object.assign({}, pageContext))
|
101
|
+
}
|
102
|
+
|
103
|
+
async function select(id) {
|
104
|
+
clear()
|
105
|
+
await pageContext.select(id)
|
106
|
+
setPageContext(Object.assign({}, pageContext))
|
107
|
+
}
|
108
|
+
|
109
|
+
function group(items, by) {
|
110
|
+
return items.reduce((nodes, field) => {
|
111
|
+
let node = nodes.find(n => n.name === field[by])
|
112
|
+
if (!node) {
|
113
|
+
let name = field[by]
|
114
|
+
node = { name, items: [], field: by }
|
115
|
+
nodes.push(node)
|
116
|
+
}
|
117
|
+
node.items.push(field)
|
118
|
+
return nodes
|
119
|
+
}, [])
|
120
|
+
}
|
121
|
+
|
122
|
+
function generateNodes(levels, items) {
|
123
|
+
const by = levels[0]
|
124
|
+
const nodes = group(items, by)
|
125
|
+
if (levels.length > 1) nodes.forEach(node => node.nodes = generateNodes(levels.slice(1), node.items))
|
126
|
+
return nodes
|
127
|
+
}
|
128
|
+
|
129
|
+
function renderNodes(nodes) {
|
130
|
+
return nodes.map(node => {
|
131
|
+
const title = typeof node.name === 'boolean' ? `${node.field} = ${node.name}` : node.name
|
132
|
+
return (
|
133
|
+
<TreeNode key={node.name} icon={null} label={title} open={true}>
|
134
|
+
{node.nodes ? renderNodes(node.nodes) : node.items.map(item => <TreeItem key={item.id} id={item.id} label={item.name} onSelect={select}>item</TreeItem>)}
|
135
|
+
</TreeNode>
|
136
|
+
)
|
137
|
+
})
|
138
|
+
}
|
139
|
+
|
140
|
+
const nodes = generateNodes(levels, all)
|
141
|
+
return (
|
142
|
+
<main>
|
143
|
+
<Tree>
|
144
|
+
{renderNodes(nodes)}
|
145
|
+
</Tree>
|
146
|
+
</main>
|
147
|
+
)
|
148
|
+
}
|
149
|
+
|
150
|
+
/**
|
151
|
+
* Collection Editor
|
152
|
+
*/
|
153
|
+
const CollectionEditor = (props) => {
|
154
|
+
const [pageContext, setPageContext] = useContext(PageContext)
|
155
|
+
const { selected } = pageContext
|
156
|
+
const { icon, schema, layout, autosave = false, delay = 1000 } = props
|
157
|
+
const timer = useRef(null)
|
158
|
+
const [form, setForm] = useState(selected)
|
159
|
+
|
160
|
+
useEffect(() => {
|
161
|
+
setForm(selected)
|
162
|
+
}, [selected])
|
163
|
+
|
164
|
+
useEffect(() => {
|
165
|
+
if (autosave) {
|
166
|
+
clearTimeout(timer.current)
|
167
|
+
timer.current = setTimeout(() => {
|
168
|
+
if (canSave()) save()
|
169
|
+
}, delay)
|
170
|
+
}
|
171
|
+
}, [form])
|
172
|
+
|
173
|
+
function clear() {
|
174
|
+
pageContext.clear()
|
175
|
+
setPageContext(Object.assign({}, pageContext))
|
176
|
+
}
|
177
|
+
|
178
|
+
async function remove() {
|
179
|
+
await pageContext.remove(selected.id)
|
180
|
+
pageContext.clear()
|
181
|
+
setPageContext(Object.assign({}, pageContext))
|
182
|
+
}
|
183
|
+
|
184
|
+
function change(next) {
|
185
|
+
setForm(next)
|
186
|
+
}
|
187
|
+
|
188
|
+
function canSave() {
|
189
|
+
const can = !equal(form, selected)
|
190
|
+
return can
|
191
|
+
}
|
192
|
+
|
193
|
+
async function save() {
|
194
|
+
console.log('saving.....')
|
195
|
+
await pageContext.update(form)
|
196
|
+
setPageContext(Object.assign({}, pageContext))
|
197
|
+
}
|
198
|
+
|
199
|
+
function renderEditor() {
|
200
|
+
const content = new Content(schema, form)
|
201
|
+
switch (layout) {
|
202
|
+
case 'TABBED': return <TabbedContentEditor {...props} content={content} onChange={change} />
|
203
|
+
case 'TREEDED': return <TreededContentEditor {...props} content={content} onChange={change} />
|
204
|
+
default: return <ContentEditor {...props} content={content} onChange={change} />
|
205
|
+
}
|
206
|
+
}
|
207
|
+
|
208
|
+
return selected && form ? (
|
209
|
+
<Fragment>
|
210
|
+
<Header icon={icon} title={<Text>{selected.name}</Text>}>
|
211
|
+
<Icon icon="close" clickable action={clear} />
|
212
|
+
<MenuIcon align="alignRight">
|
213
|
+
<Menu>
|
214
|
+
<MenuItem label="Eliminar" onSelect={remove} />
|
215
|
+
</Menu>
|
216
|
+
</MenuIcon>
|
217
|
+
{autosave === true ? null : <Button icon="save" label="Guardar Cambios" raised disabled={!canSave()} action={save} />}
|
218
|
+
</Header>
|
219
|
+
{renderEditor()}
|
220
|
+
</Fragment>
|
221
|
+
) : null
|
222
|
+
}
|
223
|
+
|
224
|
+
/**
|
225
|
+
* Collection Context
|
226
|
+
*/
|
227
|
+
export const CollectionContext = (url, field) => {
|
228
|
+
|
229
|
+
const API = CollectionAPI(url)
|
230
|
+
|
231
|
+
return {
|
232
|
+
|
233
|
+
all: [],
|
234
|
+
selected: null,
|
235
|
+
|
236
|
+
async load() {
|
237
|
+
try {
|
238
|
+
const data = await API.all();
|
239
|
+
this.all = field ? data[field] : data;
|
240
|
+
} catch (error) {
|
241
|
+
console.log(error)
|
242
|
+
}
|
243
|
+
return
|
244
|
+
},
|
245
|
+
|
246
|
+
select(id) {
|
247
|
+
const result = this.all.find(item => item.id === id);
|
248
|
+
this.selected = result;
|
249
|
+
},
|
250
|
+
|
251
|
+
clear() {
|
252
|
+
this.selected = null
|
253
|
+
},
|
254
|
+
|
255
|
+
async create(form) {
|
256
|
+
try {
|
257
|
+
await API.create(form);
|
258
|
+
await this.load();
|
259
|
+
} catch (error) {
|
260
|
+
console.log("CREATE ERROR", error)
|
261
|
+
}
|
262
|
+
return
|
263
|
+
},
|
264
|
+
|
265
|
+
async update(form) {
|
266
|
+
try {
|
267
|
+
await API.update(form)
|
268
|
+
await this.load()
|
269
|
+
} catch (error) {
|
270
|
+
console.log(error)
|
271
|
+
}
|
272
|
+
return
|
273
|
+
},
|
274
|
+
|
275
|
+
async patch(id, form) {
|
276
|
+
try {
|
277
|
+
await API.patch(id, form)
|
278
|
+
await this.load()
|
279
|
+
} catch (error) {
|
280
|
+
console.log(error)
|
281
|
+
}
|
282
|
+
return
|
283
|
+
},
|
284
|
+
|
285
|
+
async updateProperty(id, propertyName, form) {
|
286
|
+
try {
|
287
|
+
await API.updateProperty(id, propertyName, form)
|
288
|
+
await this.load()
|
289
|
+
} catch (error) {
|
290
|
+
console.log(error)
|
291
|
+
}
|
292
|
+
return
|
293
|
+
},
|
294
|
+
|
295
|
+
async remove(id) {
|
296
|
+
try {
|
297
|
+
await API.remove(id)
|
298
|
+
await this.load()
|
299
|
+
} catch (error) {
|
300
|
+
console.log(error)
|
301
|
+
}
|
302
|
+
return
|
303
|
+
},
|
304
|
+
}
|
305
|
+
}
|
306
|
+
|
307
|
+
/**
|
308
|
+
* Collection API
|
309
|
+
*/
|
310
|
+
const CollectionAPI = (url) => {
|
311
|
+
|
312
|
+
return {
|
313
|
+
all() {
|
314
|
+
return http.GET(url)
|
315
|
+
},
|
316
|
+
|
317
|
+
find(id) {
|
318
|
+
return http.GET(`${url}/${id}`)
|
319
|
+
},
|
320
|
+
|
321
|
+
create(form) {
|
322
|
+
const body = JSON.stringify(form)
|
323
|
+
return http.POST(url, body)
|
324
|
+
},
|
325
|
+
|
326
|
+
update(form) {
|
327
|
+
const body = JSON.stringify(form)
|
328
|
+
return http.PUT(`${url}/${form.id}`, body)
|
329
|
+
},
|
330
|
+
|
331
|
+
patch(id, form) {
|
332
|
+
const body = JSON.stringify(form)
|
333
|
+
return http.PATCH(`${url}/${id}`, body)
|
334
|
+
},
|
335
|
+
|
336
|
+
updateProperty(id, propertyName, form) {
|
337
|
+
const body = JSON.stringify(form)
|
338
|
+
return http.PUT(`${url}/${id}/${propertyName}`, body)
|
339
|
+
},
|
340
|
+
|
341
|
+
remove(id) {
|
342
|
+
return http.DELETE(`${url}/${id}`)
|
343
|
+
}
|
344
|
+
|
345
|
+
}
|
346
|
+
}
|
@@ -0,0 +1,174 @@
|
|
1
|
+
.content-editor {
|
2
|
+
padding: 0 1rem;
|
3
|
+
}
|
4
|
+
|
5
|
+
.content-editor>section {
|
6
|
+
|
7
|
+
margin-bottom: 1rem;
|
8
|
+
}
|
9
|
+
|
10
|
+
.content-editor>section>header {
|
11
|
+
padding: .5rem;
|
12
|
+
border-bottom: solid 1px var(--divider-color);
|
13
|
+
margin-bottom: .5rem;
|
14
|
+
}
|
15
|
+
|
16
|
+
.entity-editor {
|
17
|
+
}
|
18
|
+
|
19
|
+
.entity-editor>header {
|
20
|
+
padding: .5rem;
|
21
|
+
}
|
22
|
+
|
23
|
+
.collection-editor {
|
24
|
+
}
|
25
|
+
|
26
|
+
.collection-editor>header {
|
27
|
+
padding: 0 .5rem;
|
28
|
+
display: flex;
|
29
|
+
align-items: flex-end;
|
30
|
+
}
|
31
|
+
|
32
|
+
.collection-editor>header>.actions {
|
33
|
+
flex: 1;
|
34
|
+
display: flex;
|
35
|
+
justify-content: flex-end;
|
36
|
+
}
|
37
|
+
|
38
|
+
.collection-editor>header>.actions button {
|
39
|
+
height: 2rem !important;
|
40
|
+
padding: 0 !important;
|
41
|
+
}
|
42
|
+
|
43
|
+
.collection-editor>footer {
|
44
|
+
display: flex;
|
45
|
+
justify-content: flex-end;
|
46
|
+
}
|
47
|
+
|
48
|
+
.collection-editor td {
|
49
|
+
padding-left: 0px;
|
50
|
+
}
|
51
|
+
|
52
|
+
.collection-editor .mdc-text-field {
|
53
|
+
width: 99%;
|
54
|
+
}
|
55
|
+
|
56
|
+
.collection-editor .actions {
|
57
|
+
width: 8rem;
|
58
|
+
text-align: right;
|
59
|
+
padding: .5rem;
|
60
|
+
}
|
61
|
+
|
62
|
+
.collection-adder {
|
63
|
+
display: flex;
|
64
|
+
}
|
65
|
+
|
66
|
+
.collection-adder .data-table {
|
67
|
+
width: 100%;
|
68
|
+
border: 0px;
|
69
|
+
background-color: rgb(242, 242, 242);
|
70
|
+
}
|
71
|
+
|
72
|
+
.collection-adder table {
|
73
|
+
width: 100%;
|
74
|
+
border: 0px;
|
75
|
+
}
|
76
|
+
|
77
|
+
.collection-adder th {
|
78
|
+
display: ;
|
79
|
+
}
|
80
|
+
|
81
|
+
.collection-adder tr {
|
82
|
+
border: 0;
|
83
|
+
}
|
84
|
+
|
85
|
+
.collection-adder td {
|
86
|
+
padding-left: 0px;
|
87
|
+
}
|
88
|
+
|
89
|
+
.collection-adder td>label {
|
90
|
+
background-color: var(--paper-color) !important;
|
91
|
+
}
|
92
|
+
|
93
|
+
|
94
|
+
.collection-adder td.actions {
|
95
|
+
border: solid 0px red;
|
96
|
+
display: flex;
|
97
|
+
align-items: center;
|
98
|
+
}
|
99
|
+
|
100
|
+
|
101
|
+
.field-editor {
|
102
|
+
padding: 0;
|
103
|
+
}
|
104
|
+
|
105
|
+
.field-editor>* {
|
106
|
+
width: 100%;
|
107
|
+
}
|
108
|
+
|
109
|
+
.function-editor {
|
110
|
+
width: 100%;
|
111
|
+
min-height: 10rem;
|
112
|
+
display: flex;
|
113
|
+
}
|
114
|
+
|
115
|
+
.function-editor>main {
|
116
|
+
flex: 1;
|
117
|
+
}
|
118
|
+
|
119
|
+
.function-editor>aside {
|
120
|
+
min-width: 10rem;
|
121
|
+
padding: 0 .5rem;
|
122
|
+
}
|
123
|
+
|
124
|
+
.function-editor>aside>table {
|
125
|
+
min-width: 20rem;
|
126
|
+
border: solid 1px var(--divider-color);
|
127
|
+
margin: 0;
|
128
|
+
padding: 0;
|
129
|
+
}
|
130
|
+
|
131
|
+
.function-editor>aside>table>tr {
|
132
|
+
border-bottom: solid 1px var(--divider-color);
|
133
|
+
}
|
134
|
+
|
135
|
+
.function-editor>aside>table>tr>td {
|
136
|
+
width: 10rem;
|
137
|
+
overflow: hidden;
|
138
|
+
padding: 0 0 0 .5rem;
|
139
|
+
}
|
140
|
+
|
141
|
+
.function-editor>aside>table>tr>td input {
|
142
|
+
appearance: none;
|
143
|
+
border: 0px;
|
144
|
+
background-color: rgba(240,240,240);
|
145
|
+
margin: .2rem;
|
146
|
+
}
|
147
|
+
|
148
|
+
.treeded-editor {
|
149
|
+
display: flex;
|
150
|
+
}
|
151
|
+
|
152
|
+
.group-caption {
|
153
|
+
border-bottom: solid 1px var(--divider-color);
|
154
|
+
margin: .5rem 0;
|
155
|
+
}
|
156
|
+
|
157
|
+
.multiselection-editor {
|
158
|
+
position: relative;
|
159
|
+
border: solid 1px var(--divider-color);
|
160
|
+
display: flex;
|
161
|
+
align-items: center;
|
162
|
+
border-radius: .3rem;
|
163
|
+
padding: 1rem;
|
164
|
+
margin: 1rem 0;
|
165
|
+
}
|
166
|
+
|
167
|
+
.multiselection-editor>label {
|
168
|
+
position: absolute;
|
169
|
+
top:-9px;
|
170
|
+
padding: 2px 6px 2px 4px;
|
171
|
+
font-size: .8rem;
|
172
|
+
background-color: var(--paper-color);
|
173
|
+
color: var(--text-color-light)
|
174
|
+
}
|