@goodfellow-cms/admin 0.7.0 → 0.8.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.
- package/dist/editor.js +199 -32
- package/dist/{entry-values-DO01xZ9L.js → entry-values-Bu8ljnoX.js} +398 -374
- package/dist/es-Dxyy-khR.js +2122 -0
- package/dist/index.d.ts +118 -5
- package/dist/index.js +4603 -3343
- package/dist/plugin-protocol-BgYL9WSm.js +458 -0
- package/dist/plugin.js +38 -3
- package/package.json +6 -5
- package/styles.css +240 -12
- package/dist/plugin-protocol-DkvBDqsF.js +0 -119
package/styles.css
CHANGED
|
@@ -177,6 +177,153 @@ body,
|
|
|
177
177
|
white-space: nowrap;
|
|
178
178
|
}
|
|
179
179
|
|
|
180
|
+
/* The header's links, the site's address and the account: in the header itself, or under the menu button in narrow windows. */
|
|
181
|
+
.gfa-topbar-menu {
|
|
182
|
+
display: contents;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
.gfa-menu-button {
|
|
186
|
+
display: none;
|
|
187
|
+
align-items: center;
|
|
188
|
+
justify-content: center;
|
|
189
|
+
flex-shrink: 0;
|
|
190
|
+
width: 36px;
|
|
191
|
+
height: 36px;
|
|
192
|
+
padding: 0;
|
|
193
|
+
border: 1px solid var(--gfa-input-border);
|
|
194
|
+
border-radius: var(--gfa-radius);
|
|
195
|
+
background: var(--gfa-surface);
|
|
196
|
+
color: var(--gfa-text);
|
|
197
|
+
cursor: pointer;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
@media (min-width: 721px) {
|
|
201
|
+
.gfa-topbar-menu > .gfa-account,
|
|
202
|
+
.gfa-topbar-menu > .gfa-language {
|
|
203
|
+
order: 1;
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/* The admin panel's language, as small as the header's other controls. */
|
|
208
|
+
.gfa-language select {
|
|
209
|
+
height: 28px;
|
|
210
|
+
padding: 0 6px;
|
|
211
|
+
border: 1px solid var(--gfa-input-border);
|
|
212
|
+
border-radius: var(--gfa-radius);
|
|
213
|
+
background: var(--gfa-surface);
|
|
214
|
+
color: var(--gfa-text);
|
|
215
|
+
font: inherit;
|
|
216
|
+
font-size: 13px;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
@media (max-width: 720px) {
|
|
220
|
+
.gfa-topbar {
|
|
221
|
+
position: relative;
|
|
222
|
+
gap: 12px;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
.gfa-brand {
|
|
226
|
+
flex: 1;
|
|
227
|
+
min-width: 0;
|
|
228
|
+
max-width: none;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
.gfa-menu-button {
|
|
232
|
+
display: inline-flex;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
.gfa-topbar-menu {
|
|
236
|
+
display: none;
|
|
237
|
+
position: absolute;
|
|
238
|
+
top: 100%;
|
|
239
|
+
left: 0;
|
|
240
|
+
right: 0;
|
|
241
|
+
z-index: 50;
|
|
242
|
+
flex-direction: column;
|
|
243
|
+
align-items: stretch;
|
|
244
|
+
gap: 12px;
|
|
245
|
+
max-height: calc(100vh - var(--gfa-topbar-height));
|
|
246
|
+
overflow-y: auto;
|
|
247
|
+
padding: 8px 16px 16px;
|
|
248
|
+
background: var(--gfa-surface);
|
|
249
|
+
border-bottom: 1px solid var(--gfa-border);
|
|
250
|
+
box-shadow: 0 8px 16px rgb(0 0 0 / 0.12);
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
.gfa-topbar-menu[data-open] {
|
|
254
|
+
display: flex;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
.gfa-topbar-menu .gfa-nav {
|
|
258
|
+
flex-direction: column;
|
|
259
|
+
flex: none;
|
|
260
|
+
overflow: visible;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
.gfa-topbar-menu .gfa-nav a {
|
|
264
|
+
padding: 10px 12px;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
.gfa-topbar-menu .gfa-topbar-link {
|
|
268
|
+
padding: 0 12px;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
.gfa-topbar-menu .gfa-account {
|
|
272
|
+
flex-wrap: wrap;
|
|
273
|
+
padding: 12px 12px 0;
|
|
274
|
+
border-top: 1px solid var(--gfa-border);
|
|
275
|
+
white-space: normal;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
.gfa-topbar-menu .gfa-language {
|
|
279
|
+
padding: 0 12px;
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
/* Dark mode on or off: a track with a sun or moon on its thumb. */
|
|
284
|
+
.gfa-dark-switch {
|
|
285
|
+
position: relative;
|
|
286
|
+
flex-shrink: 0;
|
|
287
|
+
width: 44px;
|
|
288
|
+
height: 24px;
|
|
289
|
+
padding: 0;
|
|
290
|
+
border: 1px solid var(--gfa-input-border);
|
|
291
|
+
border-radius: 999px;
|
|
292
|
+
background: var(--gfa-bg);
|
|
293
|
+
cursor: pointer;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
.gfa-dark-switch-thumb {
|
|
297
|
+
position: absolute;
|
|
298
|
+
top: 2px;
|
|
299
|
+
left: 2px;
|
|
300
|
+
display: grid;
|
|
301
|
+
place-items: center;
|
|
302
|
+
width: 18px;
|
|
303
|
+
height: 18px;
|
|
304
|
+
border-radius: 50%;
|
|
305
|
+
background: var(--gfa-surface);
|
|
306
|
+
color: var(--gfa-muted);
|
|
307
|
+
box-shadow: 0 1px 2px rgb(0 0 0 / 0.25);
|
|
308
|
+
transition: transform 150ms ease;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
.gfa-dark-switch[aria-checked="true"] {
|
|
312
|
+
background: var(--gfa-accent);
|
|
313
|
+
border-color: var(--gfa-accent);
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
.gfa-dark-switch[aria-checked="true"] .gfa-dark-switch-thumb {
|
|
317
|
+
transform: translateX(20px);
|
|
318
|
+
color: var(--gfa-accent);
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
@media (prefers-reduced-motion: reduce) {
|
|
322
|
+
.gfa-dark-switch-thumb {
|
|
323
|
+
transition: none;
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
|
|
180
327
|
.gfa-content {
|
|
181
328
|
flex: 1;
|
|
182
329
|
min-height: 0;
|
|
@@ -439,7 +586,9 @@ body,
|
|
|
439
586
|
.gfa-button:focus-visible,
|
|
440
587
|
.gfa-input:focus-visible,
|
|
441
588
|
.gfa-nav a:focus-visible,
|
|
442
|
-
.gfa-tab:focus-visible
|
|
589
|
+
.gfa-tab:focus-visible,
|
|
590
|
+
.gfa-dark-switch:focus-visible,
|
|
591
|
+
.gfa-menu-button:focus-visible {
|
|
443
592
|
outline: 2px solid var(--gfa-accent);
|
|
444
593
|
outline-offset: 2px;
|
|
445
594
|
}
|
|
@@ -1444,6 +1593,33 @@ body,
|
|
|
1444
1593
|
}
|
|
1445
1594
|
|
|
1446
1595
|
.gfa-media-actions .gfa-button,
|
|
1596
|
+
/* A setting only the site's owners may change, shown to editors as it is (frame/owners-only.tsx). */
|
|
1597
|
+
.gfa-locked-field {
|
|
1598
|
+
padding: 0 16px 16px;
|
|
1599
|
+
font:
|
|
1600
|
+
14px / 1.5 ui-sans-serif,
|
|
1601
|
+
system-ui,
|
|
1602
|
+
sans-serif;
|
|
1603
|
+
}
|
|
1604
|
+
|
|
1605
|
+
.gfa-locked-field-label {
|
|
1606
|
+
margin-bottom: 8px;
|
|
1607
|
+
font-weight: 600;
|
|
1608
|
+
}
|
|
1609
|
+
|
|
1610
|
+
.gfa-locked-field-value {
|
|
1611
|
+
padding: 10px 12px;
|
|
1612
|
+
border: 1px solid var(--gfa-border);
|
|
1613
|
+
border-radius: 4px;
|
|
1614
|
+
background: var(--gfa-bg);
|
|
1615
|
+
}
|
|
1616
|
+
|
|
1617
|
+
.gfa-locked-field-note {
|
|
1618
|
+
margin: 6px 0 0;
|
|
1619
|
+
color: var(--gfa-muted);
|
|
1620
|
+
font-size: 13px;
|
|
1621
|
+
}
|
|
1622
|
+
|
|
1447
1623
|
/* A table's cells, in the editor's fields. */
|
|
1448
1624
|
.gfa-table-field {
|
|
1449
1625
|
padding: 0 16px 16px;
|
|
@@ -1908,17 +2084,6 @@ body,
|
|
|
1908
2084
|
--puck-color-white: light-dark(#ffffff, #111827);
|
|
1909
2085
|
}
|
|
1910
2086
|
|
|
1911
|
-
.gfa-theme-menu {
|
|
1912
|
-
min-height: 32px;
|
|
1913
|
-
padding: 4px 8px;
|
|
1914
|
-
border: 1px solid var(--gfa-input-border);
|
|
1915
|
-
border-radius: var(--gfa-radius);
|
|
1916
|
-
background: var(--gfa-surface);
|
|
1917
|
-
color: var(--gfa-text);
|
|
1918
|
-
font: inherit;
|
|
1919
|
-
font-size: 14px;
|
|
1920
|
-
}
|
|
1921
|
-
|
|
1922
2087
|
/* The Domain screen's records: values such as verification codes are long and unbroken. */
|
|
1923
2088
|
.gfa-records code {
|
|
1924
2089
|
overflow-wrap: anywhere;
|
|
@@ -2071,6 +2236,69 @@ body,
|
|
|
2071
2236
|
padding-left: 20px;
|
|
2072
2237
|
}
|
|
2073
2238
|
|
|
2239
|
+
/* Comments */
|
|
2240
|
+
.gfa-comments-thread {
|
|
2241
|
+
padding: 12px 16px;
|
|
2242
|
+
border: 1px solid var(--gfa-border);
|
|
2243
|
+
border-radius: var(--gfa-radius);
|
|
2244
|
+
}
|
|
2245
|
+
|
|
2246
|
+
.gfa-comments-thread > summary {
|
|
2247
|
+
display: flex;
|
|
2248
|
+
flex-wrap: wrap;
|
|
2249
|
+
align-items: center;
|
|
2250
|
+
gap: 8px;
|
|
2251
|
+
cursor: pointer;
|
|
2252
|
+
}
|
|
2253
|
+
|
|
2254
|
+
.gfa-comments-actions {
|
|
2255
|
+
display: flex;
|
|
2256
|
+
flex-wrap: wrap;
|
|
2257
|
+
align-items: center;
|
|
2258
|
+
gap: 8px;
|
|
2259
|
+
margin-top: 8px;
|
|
2260
|
+
}
|
|
2261
|
+
|
|
2262
|
+
.gfa-comment-list {
|
|
2263
|
+
display: grid;
|
|
2264
|
+
gap: 12px;
|
|
2265
|
+
margin: 12px 0 0;
|
|
2266
|
+
padding: 0;
|
|
2267
|
+
list-style: none;
|
|
2268
|
+
}
|
|
2269
|
+
|
|
2270
|
+
.gfa-comment-list .gfa-comment-list {
|
|
2271
|
+
padding-left: 16px;
|
|
2272
|
+
border-left: 2px solid var(--gfa-border);
|
|
2273
|
+
}
|
|
2274
|
+
|
|
2275
|
+
.gfa-comment-byline {
|
|
2276
|
+
display: flex;
|
|
2277
|
+
flex-wrap: wrap;
|
|
2278
|
+
align-items: center;
|
|
2279
|
+
gap: 6px;
|
|
2280
|
+
margin: 0;
|
|
2281
|
+
}
|
|
2282
|
+
|
|
2283
|
+
.gfa-comment-text {
|
|
2284
|
+
margin: 4px 0 0;
|
|
2285
|
+
white-space: pre-line;
|
|
2286
|
+
overflow-wrap: anywhere;
|
|
2287
|
+
}
|
|
2288
|
+
|
|
2289
|
+
.gfa-comment-hidden .gfa-comment-text {
|
|
2290
|
+
color: var(--gfa-muted);
|
|
2291
|
+
}
|
|
2292
|
+
|
|
2293
|
+
.gfa-comment-quote {
|
|
2294
|
+
margin: 0;
|
|
2295
|
+
padding: 8px 12px;
|
|
2296
|
+
border-left: 3px solid var(--gfa-border);
|
|
2297
|
+
color: var(--gfa-muted);
|
|
2298
|
+
white-space: pre-line;
|
|
2299
|
+
overflow-wrap: anywhere;
|
|
2300
|
+
}
|
|
2301
|
+
|
|
2074
2302
|
/* Failed rebuilds */
|
|
2075
2303
|
.gfa-deploy .gfa-deploy-why {
|
|
2076
2304
|
padding: 0 4px;
|
|
@@ -1,119 +0,0 @@
|
|
|
1
|
-
//#region src/frame/channel.ts
|
|
2
|
-
/**
|
|
3
|
-
* Requests and events between the admin panel and a frame running the site's
|
|
4
|
-
* code, over one `MessagePort`. The admin panel's side treats everything a
|
|
5
|
-
* frame sends as untrusted: the site's blocks run there, and could send anything.
|
|
6
|
-
*/
|
|
7
|
-
/** The message the admin panel's page sends a frame once it has loaded, with the port to talk on. */
|
|
8
|
-
const CONNECT_MESSAGE = "goodfellow:connect";
|
|
9
|
-
/** A request the other side refused or couldn't answer. */
|
|
10
|
-
var ChannelError = class extends Error {
|
|
11
|
-
name = "ChannelError";
|
|
12
|
-
};
|
|
13
|
-
function isMessage(data) {
|
|
14
|
-
if (typeof data !== "object" || data === null) return false;
|
|
15
|
-
const type = data.type;
|
|
16
|
-
return type === "request" || type === "response" || type === "event";
|
|
17
|
-
}
|
|
18
|
-
/** What an error says, as text: errors can't cross the port as they are. */
|
|
19
|
-
function errorText(error) {
|
|
20
|
-
return error instanceof Error ? error.message : String(error);
|
|
21
|
-
}
|
|
22
|
-
function createChannel(port, handlers = {}) {
|
|
23
|
-
const own = { ...handlers };
|
|
24
|
-
const pending = /* @__PURE__ */ new Map();
|
|
25
|
-
const listeners = /* @__PURE__ */ new Map();
|
|
26
|
-
let next = 1;
|
|
27
|
-
let closed = false;
|
|
28
|
-
port.onmessage = async (event) => {
|
|
29
|
-
const message = event.data;
|
|
30
|
-
if (!isMessage(message)) return;
|
|
31
|
-
if (message.type === "response") {
|
|
32
|
-
const waiting = pending.get(message.id);
|
|
33
|
-
if (!waiting) return;
|
|
34
|
-
pending.delete(message.id);
|
|
35
|
-
if (message.ok) waiting.resolve(message.result);
|
|
36
|
-
else waiting.reject(new ChannelError(message.error));
|
|
37
|
-
return;
|
|
38
|
-
}
|
|
39
|
-
if (message.type === "event") {
|
|
40
|
-
for (const listener of listeners.get(message.name) ?? []) listener(message.payload);
|
|
41
|
-
return;
|
|
42
|
-
}
|
|
43
|
-
const handler = typeof message.method === "string" ? Object.hasOwn(own, message.method) && own[message.method] : void 0;
|
|
44
|
-
if (!handler) {
|
|
45
|
-
port.postMessage({
|
|
46
|
-
type: "response",
|
|
47
|
-
id: message.id,
|
|
48
|
-
ok: false,
|
|
49
|
-
error: `No such request: ${message.method}`
|
|
50
|
-
});
|
|
51
|
-
return;
|
|
52
|
-
}
|
|
53
|
-
try {
|
|
54
|
-
const result = await handler(message.params);
|
|
55
|
-
if (!closed) port.postMessage({
|
|
56
|
-
type: "response",
|
|
57
|
-
id: message.id,
|
|
58
|
-
ok: true,
|
|
59
|
-
result
|
|
60
|
-
});
|
|
61
|
-
} catch (error) {
|
|
62
|
-
if (!closed) port.postMessage({
|
|
63
|
-
type: "response",
|
|
64
|
-
id: message.id,
|
|
65
|
-
ok: false,
|
|
66
|
-
error: errorText(error)
|
|
67
|
-
});
|
|
68
|
-
}
|
|
69
|
-
};
|
|
70
|
-
return {
|
|
71
|
-
call(method, params, transfer = []) {
|
|
72
|
-
if (closed) return Promise.reject(new ChannelError("The frame has closed."));
|
|
73
|
-
const id = next++;
|
|
74
|
-
return new Promise((resolve, reject) => {
|
|
75
|
-
pending.set(id, {
|
|
76
|
-
resolve,
|
|
77
|
-
reject
|
|
78
|
-
});
|
|
79
|
-
port.postMessage({
|
|
80
|
-
type: "request",
|
|
81
|
-
id,
|
|
82
|
-
method,
|
|
83
|
-
params
|
|
84
|
-
}, transfer);
|
|
85
|
-
});
|
|
86
|
-
},
|
|
87
|
-
emit(name, payload) {
|
|
88
|
-
if (!closed) port.postMessage({
|
|
89
|
-
type: "event",
|
|
90
|
-
name,
|
|
91
|
-
payload
|
|
92
|
-
});
|
|
93
|
-
},
|
|
94
|
-
on(name, listener) {
|
|
95
|
-
const set = listeners.get(name) ?? /* @__PURE__ */ new Set();
|
|
96
|
-
listeners.set(name, set);
|
|
97
|
-
set.add(listener);
|
|
98
|
-
return () => set.delete(listener);
|
|
99
|
-
},
|
|
100
|
-
handle(method, handler) {
|
|
101
|
-
own[method] = handler;
|
|
102
|
-
return () => {
|
|
103
|
-
if (own[method] === handler) delete own[method];
|
|
104
|
-
};
|
|
105
|
-
},
|
|
106
|
-
close() {
|
|
107
|
-
closed = true;
|
|
108
|
-
port.close();
|
|
109
|
-
for (const waiting of pending.values()) waiting.reject(new ChannelError("The frame has closed."));
|
|
110
|
-
pending.clear();
|
|
111
|
-
}
|
|
112
|
-
};
|
|
113
|
-
}
|
|
114
|
-
//#endregion
|
|
115
|
-
//#region src/frame/plugin-protocol.ts
|
|
116
|
-
/** A plugin's frame sends this to the admin panel's page once it's listening, and the page answers with a port. */
|
|
117
|
-
const PLUGIN_READY_MESSAGE = "goodfellow:plugin-ready";
|
|
118
|
-
//#endregion
|
|
119
|
-
export { CONNECT_MESSAGE as n, createChannel as r, PLUGIN_READY_MESSAGE as t };
|