mockaton 13.11.1 → 13.11.3
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/README.md +11 -8
- package/package.json +1 -1
- package/skills/mockaton/SKILL.md +8 -5
- package/src/client/ApiConstants.js +1 -1
- package/src/client/IndexHtml.js +1 -1
- package/src/client/app-header.css +231 -0
- package/src/client/app-header.js +13 -6
- package/src/client/app-mock-list.css +340 -0
- package/src/client/app-mock-list.js +370 -0
- package/src/client/app-payload-viewer.css +90 -0
- package/src/client/app-payload-viewer.js +4 -4
- package/src/client/app-store.js +1 -0
- package/src/client/app.css +0 -654
- package/src/client/app.js +18 -360
- package/src/client/utils/css.js +7 -0
- package/src/client/utils/watcherDev.js +4 -1
- package/src/server/Api.js +54 -53
- package/src/server/MockDispatcher.js +6 -5
- package/src/server/Mockaton.js +11 -12
- package/src/server/Mockaton.test.js +65 -51
- package/src/server/ProxyRelay.js +3 -2
- package/src/server/UrlParsers.js +1 -1
- package/src/server/UrlParsers.test.js +1 -1
- package/src/server/cli.js +37 -33
- package/src/server/cli.test.js +2 -4
- package/src/server/{Watcher.js → stores/Watcher.js} +18 -9
- package/src/server/{mockBrokersCollection.js → stores/brokers.js} +3 -3
- package/src/server/{config.js → stores/config.js} +28 -14
- package/src/server/utils/HttpServerResponse.test.js +5 -7
- package/src/server/utils/WatcherDevClient.js +1 -1
- package/src/server/utils/openInBrowser.js +15 -10
- package/www/src/assets/openapi.json +1 -1
- /package/src/server/{resolverBypassImportCache.js → ResolverBypassImportCache.js} +0 -0
- /package/src/server/{resolverResolveExtensionless.js → ResolverResolveExtensionless.js} +0 -0
- /package/src/server/{cookie.js → stores/cookies.js} +0 -0
|
@@ -0,0 +1,370 @@
|
|
|
1
|
+
import { createElement as r, t, Fragment } from './utils/dom.js'
|
|
2
|
+
|
|
3
|
+
import { store } from './app-store.js'
|
|
4
|
+
import { previewMock } from './app-payload-viewer.js'
|
|
5
|
+
import { classNames, adoptSheet } from './utils/css.js'
|
|
6
|
+
import { TimerIcon, CloudIcon, ChevronDownIcon } from './graphics.js'
|
|
7
|
+
|
|
8
|
+
import CSS from './app-mock-list.css' with { type: 'css' }
|
|
9
|
+
adoptSheet(CSS, './app-mock-list.css')
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
export function MockList() {
|
|
13
|
+
return Fragment(
|
|
14
|
+
r('div', { className: CSS.SubToolbar },
|
|
15
|
+
GroupByMethod(),
|
|
16
|
+
BulkSelector()),
|
|
17
|
+
Table())
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
function GroupByMethod() {
|
|
22
|
+
return (
|
|
23
|
+
r('label', { className: CSS.GroupByMethod },
|
|
24
|
+
r('input', {
|
|
25
|
+
type: 'checkbox',
|
|
26
|
+
checked: store.groupByMethod,
|
|
27
|
+
onChange: store.toggleGroupByMethod
|
|
28
|
+
}),
|
|
29
|
+
r('span', { className: CSS.checkboxBody }, t`Group by Method`)))
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
function BulkSelector() {
|
|
34
|
+
const { comments } = store
|
|
35
|
+
const firstOption = t`Pick Comment…`
|
|
36
|
+
function onChange() {
|
|
37
|
+
const value = this.value
|
|
38
|
+
this.value = firstOption // hack so it’s always selected
|
|
39
|
+
store.bulkSelectByComment(value)
|
|
40
|
+
}
|
|
41
|
+
const disabled = !comments.length
|
|
42
|
+
return (
|
|
43
|
+
r('label', { className: CSS.BulkSelector },
|
|
44
|
+
r('span', null, t`Bulk Select`),
|
|
45
|
+
r('select', {
|
|
46
|
+
disabled,
|
|
47
|
+
autocomplete: 'off',
|
|
48
|
+
title: disabled
|
|
49
|
+
? t`No mock files have comments which are anything within parentheses on the filename.`
|
|
50
|
+
: undefined,
|
|
51
|
+
onChange
|
|
52
|
+
},
|
|
53
|
+
r('option', { value: firstOption }, firstOption),
|
|
54
|
+
r('hr'),
|
|
55
|
+
comments.map(value => r('option', { value }, value)))))
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function Table() {
|
|
59
|
+
return (
|
|
60
|
+
r('div', {
|
|
61
|
+
ref: Table.ref,
|
|
62
|
+
className: CSS.Table
|
|
63
|
+
},
|
|
64
|
+
TableContent()))
|
|
65
|
+
}
|
|
66
|
+
Table.ref = { width: undefined }
|
|
67
|
+
Table.$ = selector => Table.ref.elem.querySelector(selector)
|
|
68
|
+
Table.$$ = selector => Table.ref.elem.querySelectorAll(selector)
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
function TableContent() {
|
|
74
|
+
if (!Object.keys(store.brokersByMethod).length)
|
|
75
|
+
return r('div', null, t`No mocks found`)
|
|
76
|
+
|
|
77
|
+
if (store.groupByMethod)
|
|
78
|
+
return Object.keys(store.brokersByMethod).map(method => Fragment(
|
|
79
|
+
r('div', {
|
|
80
|
+
className: classNames(CSS.TableHeading, store.canProxy && CSS.canProxy)
|
|
81
|
+
}, method),
|
|
82
|
+
FolderGroups(store.folderGroupsByMethod(method))))
|
|
83
|
+
|
|
84
|
+
return FolderGroups(store.folderGroupsByMethod('*'))
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
function FolderGroups(brokersTree) {
|
|
89
|
+
const res = []
|
|
90
|
+
for (const b of brokersTree) {
|
|
91
|
+
if (!b.children.length)
|
|
92
|
+
res.push(Row(b))
|
|
93
|
+
else
|
|
94
|
+
res.push(FolderGroup(b))
|
|
95
|
+
}
|
|
96
|
+
return res
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function FolderGroup(broker) {
|
|
100
|
+
const folder = broker.urlMask
|
|
101
|
+
const children = broker.children
|
|
102
|
+
return (
|
|
103
|
+
r('details', {
|
|
104
|
+
className: CSS.FolderGroup,
|
|
105
|
+
open: !store.collapsedFolders.has(folder),
|
|
106
|
+
onToggle() {
|
|
107
|
+
store.setFolderCollapsed(folder, !this.open)
|
|
108
|
+
}
|
|
109
|
+
},
|
|
110
|
+
r('summary', null,
|
|
111
|
+
r('span', { className: CSS.FolderChevron }, ChevronDownIcon()),
|
|
112
|
+
r('span', {
|
|
113
|
+
className: classNames(
|
|
114
|
+
CSS.FolderName,
|
|
115
|
+
store.groupByMethod && CSS.groupedByMethod,
|
|
116
|
+
store.canProxy && CSS.canProxy)
|
|
117
|
+
},
|
|
118
|
+
folder + '…')),
|
|
119
|
+
Row(broker),
|
|
120
|
+
children.map(c => c.children.length
|
|
121
|
+
? FolderGroup(c)
|
|
122
|
+
: Row(c))))
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/** @param {BrokerRowModel} row */
|
|
126
|
+
function Row(row) {
|
|
127
|
+
const { method, urlMask } = row
|
|
128
|
+
return (
|
|
129
|
+
r('div', {
|
|
130
|
+
key: row.key,
|
|
131
|
+
className: classNames(CSS.TableRow, store.mounted && row.isNew && CSS.animIn)
|
|
132
|
+
},
|
|
133
|
+
|
|
134
|
+
store.canProxy && ClickDragToggler({
|
|
135
|
+
className: CSS.ProxyToggler,
|
|
136
|
+
title: t`Proxy Toggler`,
|
|
137
|
+
body: CloudIcon(),
|
|
138
|
+
checked: row.proxied,
|
|
139
|
+
commit(checked) {
|
|
140
|
+
store.setProxied(method, urlMask, checked)
|
|
141
|
+
}
|
|
142
|
+
}),
|
|
143
|
+
|
|
144
|
+
ClickDragToggler({
|
|
145
|
+
className: CSS.DelayToggler,
|
|
146
|
+
title: t`Delay`,
|
|
147
|
+
body: TimerIcon(),
|
|
148
|
+
checked: row.delayed,
|
|
149
|
+
commit(checked) {
|
|
150
|
+
store.setDelayed(method, urlMask, checked)
|
|
151
|
+
}
|
|
152
|
+
}),
|
|
153
|
+
|
|
154
|
+
ClickDragToggler(
|
|
155
|
+
row.isStatic
|
|
156
|
+
? {
|
|
157
|
+
className: CSS.StatusCodeToggler,
|
|
158
|
+
title: t`Not Found`,
|
|
159
|
+
body: t`404`,
|
|
160
|
+
disabled: row.opts.length === 1 && row.status === 404,
|
|
161
|
+
checked: !row.proxied && row.status === 404,
|
|
162
|
+
commit() { store.toggleStatus(method, urlMask, 404) }
|
|
163
|
+
}
|
|
164
|
+
: {
|
|
165
|
+
className: CSS.StatusCodeToggler,
|
|
166
|
+
title: t`Internal Server Error`,
|
|
167
|
+
body: t`500`,
|
|
168
|
+
disabled: row.opts.length === 1 && row.status === 500,
|
|
169
|
+
checked: !row.proxied && row.status === 500,
|
|
170
|
+
commit() { store.toggleStatus(method, urlMask, 500) }
|
|
171
|
+
}),
|
|
172
|
+
|
|
173
|
+
!store.groupByMethod && r('span', { className: CSS.Method }, method),
|
|
174
|
+
|
|
175
|
+
PreviewLink(method, urlMask, row.urlMaskDittoed),
|
|
176
|
+
|
|
177
|
+
MockSelector(row)))
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
export function renderRow(method, urlMask) {
|
|
182
|
+
unChooseOld()
|
|
183
|
+
const row = store.brokerAsRow(method, urlMask)
|
|
184
|
+
const tr = Table.$(`.${CSS.TableRow}[key="${row.key}"]`)
|
|
185
|
+
mergeTableRow(tr, Row(row))
|
|
186
|
+
previewMock()
|
|
187
|
+
|
|
188
|
+
function unChooseOld() {
|
|
189
|
+
return Table.$(`a.${CSS.chosen}`)
|
|
190
|
+
?.classList.remove(CSS.chosen)
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
function mergeTableRow(oldRow, newRow) {
|
|
194
|
+
for (let i = 0; i < newRow.children.length; i++) {
|
|
195
|
+
const oldEl = oldRow.children[i]
|
|
196
|
+
const newEl = newRow.children[i]
|
|
197
|
+
switch (newEl.tagName) {
|
|
198
|
+
case 'LABEL': {
|
|
199
|
+
const oldInput = oldEl.querySelector('[type="checkbox"]')
|
|
200
|
+
const newInput = newEl.querySelector('[type="checkbox"]')
|
|
201
|
+
oldInput.checked = newInput.checked
|
|
202
|
+
oldInput.disabled = newInput.disabled
|
|
203
|
+
break
|
|
204
|
+
}
|
|
205
|
+
case 'A':
|
|
206
|
+
oldEl.className = newEl.className
|
|
207
|
+
break
|
|
208
|
+
case 'SELECT':
|
|
209
|
+
oldEl.replaceChildren(...newEl.cloneNode(true).children)
|
|
210
|
+
oldEl.className = newEl.className
|
|
211
|
+
oldEl.disabled = newEl.disabled
|
|
212
|
+
oldEl.value = newEl.value
|
|
213
|
+
break
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
function PreviewLink(method, urlMask, urlMaskDittoed) {
|
|
221
|
+
function onClick(event) {
|
|
222
|
+
event.preventDefault()
|
|
223
|
+
store.previewLink(method, urlMask)
|
|
224
|
+
}
|
|
225
|
+
const isChosen = store.chosenLink.method === method && store.chosenLink.urlMask === urlMask
|
|
226
|
+
const [ditto, tail] = urlMaskDittoed
|
|
227
|
+
return (
|
|
228
|
+
r('a', {
|
|
229
|
+
className: classNames(CSS.PreviewLink, isChosen && CSS.chosen),
|
|
230
|
+
href: urlMask,
|
|
231
|
+
onClick
|
|
232
|
+
}, ditto
|
|
233
|
+
? [r('span', { className: CSS.dittoDir }, ditto), tail]
|
|
234
|
+
: tail))
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
|
|
238
|
+
/** @param {BrokerRowModel} row */
|
|
239
|
+
function MockSelector(row) {
|
|
240
|
+
return (
|
|
241
|
+
r('select', {
|
|
242
|
+
onChange() {
|
|
243
|
+
store.selectFile(this.value)
|
|
244
|
+
},
|
|
245
|
+
onKeyDown(event) {
|
|
246
|
+
if (event.key === 'ArrowRight' || event.key === 'ArrowLeft')
|
|
247
|
+
event.preventDefault()
|
|
248
|
+
// Because in Firefox they change the select.option, and
|
|
249
|
+
// we use those keys for spreadsheet-like navigation.
|
|
250
|
+
},
|
|
251
|
+
'aria-label': t`Mock Selector`,
|
|
252
|
+
disabled: row.opts.length < 2,
|
|
253
|
+
className: classNames(
|
|
254
|
+
CSS.MockSelector,
|
|
255
|
+
row.selectedIdx > 0 && CSS.nonDefault,
|
|
256
|
+
row.selectedFileIs4xx && CSS.status4xx)
|
|
257
|
+
}, row.opts.map(([value, label, selected]) =>
|
|
258
|
+
r('option', { value, selected }, label))))
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
|
|
262
|
+
function ClickDragToggler({ checked, commit, className, title, body }) {
|
|
263
|
+
function onPointerEnter(event) {
|
|
264
|
+
if (event.buttons === 1)
|
|
265
|
+
onPointerDown.call(this, event)
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
function onPointerDown(event) {
|
|
269
|
+
if (event.altKey) {
|
|
270
|
+
onExclusiveClick.call(this)
|
|
271
|
+
return
|
|
272
|
+
}
|
|
273
|
+
this.checked = !this.checked
|
|
274
|
+
this.focus()
|
|
275
|
+
commit(this.checked)
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
function onExclusiveClick() {
|
|
279
|
+
const selector = selectorForColumnOf(this)
|
|
280
|
+
if (!selector)
|
|
281
|
+
return
|
|
282
|
+
|
|
283
|
+
// Uncheck all other in the column.
|
|
284
|
+
for (const elem of Table.$$(selector))
|
|
285
|
+
if (elem !== this && elem.checked && !elem.disabled) {
|
|
286
|
+
elem.checked = false
|
|
287
|
+
elem.dispatchEvent(new Event('change'))
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
if (!this.checked) {
|
|
291
|
+
this.checked = true
|
|
292
|
+
this.dispatchEvent(new Event('change'))
|
|
293
|
+
}
|
|
294
|
+
this.focus()
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
function onClick(event) {
|
|
298
|
+
if (event.pointerType === 'mouse')
|
|
299
|
+
event.preventDefault()
|
|
300
|
+
}
|
|
301
|
+
function onChange() {
|
|
302
|
+
commit(this.checked)
|
|
303
|
+
}
|
|
304
|
+
return (
|
|
305
|
+
r('label', { className: classNames(CSS.Toggler, className), title },
|
|
306
|
+
r('input', {
|
|
307
|
+
type: 'checkbox',
|
|
308
|
+
checked,
|
|
309
|
+
onPointerEnter,
|
|
310
|
+
onPointerDown,
|
|
311
|
+
onClick,
|
|
312
|
+
onChange
|
|
313
|
+
}),
|
|
314
|
+
r('span', { className: CSS.checkboxBody }, body)))
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
|
|
318
|
+
|
|
319
|
+
function selectorForColumnOf(elem) {
|
|
320
|
+
return columnSelectors().find(s => elem?.matches(s))
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
function columnSelectors() {
|
|
324
|
+
return [
|
|
325
|
+
`.${CSS.TableRow} .${CSS.ProxyToggler} input`,
|
|
326
|
+
`.${CSS.TableRow} .${CSS.DelayToggler} input`,
|
|
327
|
+
`.${CSS.TableRow} .${CSS.StatusCodeToggler} input`,
|
|
328
|
+
`.${CSS.TableRow} .${CSS.PreviewLink}`,
|
|
329
|
+
// No .MockSelector because down/up arrows have native behavior on them
|
|
330
|
+
]
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
export function initKeyboardNavigation() {
|
|
334
|
+
const rowSelectors = [
|
|
335
|
+
...columnSelectors(),
|
|
336
|
+
`.${CSS.TableRow} .${CSS.MockSelector}:enabled`,
|
|
337
|
+
]
|
|
338
|
+
|
|
339
|
+
addEventListener('keydown', function ({ key }) {
|
|
340
|
+
switch (key) {
|
|
341
|
+
case 'ArrowDown':
|
|
342
|
+
case 'ArrowUp': {
|
|
343
|
+
const pivot = document.activeElement
|
|
344
|
+
const sel = selectorForColumnOf(pivot)
|
|
345
|
+
if (sel) {
|
|
346
|
+
const offset = key === 'ArrowDown' ? +1 : -1
|
|
347
|
+
const siblings = Table.$$(sel)
|
|
348
|
+
circularAdjacent(offset, siblings, pivot).focus()
|
|
349
|
+
}
|
|
350
|
+
break
|
|
351
|
+
}
|
|
352
|
+
case 'ArrowRight':
|
|
353
|
+
case 'ArrowLeft': {
|
|
354
|
+
const pivot = document.activeElement
|
|
355
|
+
const sel = rowSelectors.find(s => pivot?.matches(s))
|
|
356
|
+
if (sel) {
|
|
357
|
+
const offset = key === 'ArrowRight' ? +1 : -1
|
|
358
|
+
const siblings = pivot.closest(`.${CSS.TableRow}`).querySelectorAll(rowSelectors.join(','))
|
|
359
|
+
circularAdjacent(offset, siblings, pivot).focus()
|
|
360
|
+
}
|
|
361
|
+
break
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
})
|
|
365
|
+
|
|
366
|
+
function circularAdjacent(step, siblings, pivot) {
|
|
367
|
+
const arr = Array.from(siblings)
|
|
368
|
+
return arr[(arr.indexOf(pivot) + step + arr.length) % arr.length]
|
|
369
|
+
}
|
|
370
|
+
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
.PayloadSubToolbar {
|
|
2
|
+
display: flex;
|
|
3
|
+
align-items: center;
|
|
4
|
+
justify-content: space-between;
|
|
5
|
+
padding-right: 14px;
|
|
6
|
+
padding-left: 16px;
|
|
7
|
+
border-bottom: 1px solid var(--colorBorder);
|
|
8
|
+
background: var(--colorBgHeader);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
.PayloadViewer {
|
|
13
|
+
display: grid;
|
|
14
|
+
height: 100%;
|
|
15
|
+
grid-template-rows: var(--subtoolbarHeight) 1fr;
|
|
16
|
+
|
|
17
|
+
> pre {
|
|
18
|
+
overflow: auto;
|
|
19
|
+
height: 100%;
|
|
20
|
+
padding: 16px;
|
|
21
|
+
padding-top: 12px;
|
|
22
|
+
font-family: monospace;
|
|
23
|
+
|
|
24
|
+
&:has(> code > :is(iframe, video)) {
|
|
25
|
+
padding: 0;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
> code {
|
|
29
|
+
line-height: 1.3;
|
|
30
|
+
white-space: pre;
|
|
31
|
+
tab-size: 2;
|
|
32
|
+
color: var(--colorLabel);
|
|
33
|
+
|
|
34
|
+
> video {
|
|
35
|
+
width: 100%;
|
|
36
|
+
}
|
|
37
|
+
> iframe {
|
|
38
|
+
width: 100%;
|
|
39
|
+
height: 100%;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
.syntaxPunc {
|
|
46
|
+
color: var(--colorLabel);
|
|
47
|
+
}
|
|
48
|
+
.syntaxKey,
|
|
49
|
+
.syntaxTag {
|
|
50
|
+
color: var(--colorPink);
|
|
51
|
+
}
|
|
52
|
+
.syntaxVal,
|
|
53
|
+
.syntaxAttr {
|
|
54
|
+
color: var(--colorPurple);
|
|
55
|
+
}
|
|
56
|
+
.syntaxStr,
|
|
57
|
+
.syntaxAttrVal {
|
|
58
|
+
color: var(--colorGreen);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
.ProgressBar {
|
|
63
|
+
position: relative;
|
|
64
|
+
top: -12px;
|
|
65
|
+
left: -16px;
|
|
66
|
+
width: calc(100% + 32px);
|
|
67
|
+
height: 2px;
|
|
68
|
+
background: var(--colorBgHeaderField);
|
|
69
|
+
|
|
70
|
+
> div {
|
|
71
|
+
position: absolute;
|
|
72
|
+
top: 0;
|
|
73
|
+
left: 0;
|
|
74
|
+
width: 0;
|
|
75
|
+
height: 100%;
|
|
76
|
+
background: var(--colorAccent);
|
|
77
|
+
animation-name: _kfProgress;
|
|
78
|
+
animation-timing-function: linear;
|
|
79
|
+
animation-iteration-count: infinite;
|
|
80
|
+
animation-direction: alternate;
|
|
81
|
+
/* animation-duration is set in JS */
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
@keyframes _kfProgress {
|
|
85
|
+
to {
|
|
86
|
+
width: 100%;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { createElement as r, t } from './utils/dom.js'
|
|
2
2
|
import { parseFilename } from './Filename.js'
|
|
3
3
|
import { store } from './app-store.js'
|
|
4
|
+
import { adoptSheet } from './utils/css.js'
|
|
4
5
|
|
|
5
|
-
import CSS from './app.css' with { type: 'css' }
|
|
6
|
-
|
|
7
|
-
Object.assign(CSS, extractClassNames(CSS))
|
|
6
|
+
import CSS from './app-payload-viewer.css' with { type: 'css' }
|
|
7
|
+
adoptSheet(CSS, './app-payload-viewer.css')
|
|
8
8
|
|
|
9
9
|
|
|
10
10
|
const titleRef = {}
|
|
@@ -14,7 +14,7 @@ export function PayloadViewer() {
|
|
|
14
14
|
return (
|
|
15
15
|
r('div', { className: CSS.PayloadViewer },
|
|
16
16
|
|
|
17
|
-
r('div', { className: CSS.
|
|
17
|
+
r('div', { className: CSS.PayloadSubToolbar },
|
|
18
18
|
r('h2', { ref: titleRef },
|
|
19
19
|
!store.hasChosenLink && t`Preview`)),
|
|
20
20
|
|