@obelism/content 0.1.0 → 0.1.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/bridge.js +218 -77
- package/dist/bridge.mjs +218 -77
- package/package.json +1 -1
package/dist/bridge.js
CHANGED
|
@@ -308,46 +308,158 @@ const DEFAULT_PROMPT_LABELS = {
|
|
|
308
308
|
viewingDrafts: 'Viewing drafts',
|
|
309
309
|
selectHint: 'Click a block to change only that block'
|
|
310
310
|
};
|
|
311
|
-
|
|
311
|
+
// Icons (Lucide), drawn in the text colour.
|
|
312
|
+
const ICONS = {
|
|
313
|
+
page: '<path d="M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z"/><path d="M14 2v4a2 2 0 0 0 2 2h4"/>',
|
|
314
|
+
block: '<rect width="18" height="18" x="3" y="3" rx="2"/><path d="M7 8h10"/><path d="M7 12h6"/>',
|
|
315
|
+
undo: '<path d="M9 14 4 9l5-5"/><path d="M4 9h10.5a5.5 5.5 0 0 1 0 11H11"/>',
|
|
316
|
+
close: '<path d="M18 6 6 18"/><path d="m6 6 12 12"/>',
|
|
317
|
+
send: '<path d="M3.714 3.048a.498.498 0 0 0-.683.627l2.843 7.627a2 2 0 0 1 0 1.396l-2.842 7.627a.498.498 0 0 0 .682.627l18-8.5a.5.5 0 0 0 0-.904z"/><path d="M6 12h16"/>'
|
|
318
|
+
};
|
|
319
|
+
// Obelism's design tokens (obelism.studio/design.md), under their own names:
|
|
320
|
+
// beige and near-black, one orange accent, Inter, pill buttons.
|
|
312
321
|
const CSS = `
|
|
313
322
|
:host { all: initial; }
|
|
314
|
-
* { box-sizing: border-box; font:
|
|
323
|
+
* { box-sizing: border-box; font: inherit; color: inherit; margin: 0; }
|
|
315
324
|
.root {
|
|
316
|
-
--
|
|
317
|
-
|
|
318
|
-
|
|
325
|
+
--color-white-rgb: 248 248 248; --color-beige-rgb: 238 236 233; --color-beige-off-rgb: 228 225 217;
|
|
326
|
+
--color-grey-light-rgb: 132 132 132; --color-grey-rgb: 108 108 108; --color-grey-mid-rgb: 100 100 100; --color-grey-dark-rgb: 40 40 40;
|
|
327
|
+
--color-black-off-rgb: 20 20 20; --color-black-rgb: 12 12 12;
|
|
328
|
+
--color-orange-rgb: 212 130 30; --color-red-rgb: 240 93 93;
|
|
329
|
+
--theme-foreground-rgb: var(--color-black-rgb);
|
|
330
|
+
--theme-background-alt-rgb: var(--color-white-rgb);
|
|
331
|
+
--theme-background-actions-rgb: var(--color-beige-off-rgb);
|
|
332
|
+
--theme-border-rgb: var(--color-grey-light-rgb);
|
|
333
|
+
--theme-accent-rgb: var(--color-orange-rgb);
|
|
334
|
+
--theme-foreground-muted-rgb: var(--color-grey-mid-rgb);
|
|
335
|
+
--theme-error: #b3261e;
|
|
336
|
+
--border-radius-medium: 20px; --border-radius-pill: 5em;
|
|
337
|
+
--ease-roll: cubic-bezier(0.65, 0, 0.35, 1);
|
|
338
|
+
--shadow: 0 18px 40px -16px rgb(var(--color-black-rgb) / .3), 0 2px 6px rgb(var(--color-black-rgb) / .05);
|
|
339
|
+
--font-inter: 'InterVariable', 'Inter', system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI',
|
|
340
|
+
Roboto, 'Helvetica Neue', Arial, 'Noto Sans', sans-serif;
|
|
341
|
+
position: fixed; left: 50%; bottom: 20px; transform: translateX(-50%);
|
|
342
|
+
z-index: 2147483647; width: min(640px, calc(100vw - 32px)); color-scheme: light dark;
|
|
343
|
+
font: 400 14px/1.4 var(--font-inter); color: rgb(var(--theme-foreground-rgb));
|
|
344
|
+
-webkit-font-smoothing: antialiased;
|
|
319
345
|
}
|
|
320
346
|
@media (prefers-color-scheme: dark) {
|
|
321
|
-
.root {
|
|
347
|
+
.root {
|
|
348
|
+
--theme-foreground-rgb: var(--color-white-rgb);
|
|
349
|
+
--theme-background-alt-rgb: var(--color-black-off-rgb);
|
|
350
|
+
--theme-background-actions-rgb: var(--color-grey-dark-rgb);
|
|
351
|
+
--theme-border-rgb: var(--color-grey-rgb);
|
|
352
|
+
--theme-foreground-muted-rgb: var(--color-grey-light-rgb);
|
|
353
|
+
--theme-error: rgb(var(--color-red-rgb));
|
|
354
|
+
--shadow: 0 18px 40px -14px rgb(0 0 0 / .7), 0 2px 6px rgb(0 0 0 / .3);
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
.icon { display: inline-flex; flex: none; }
|
|
358
|
+
.icon svg {
|
|
359
|
+
width: 16px; height: 16px; fill: none; stroke: currentColor; stroke-width: 1.75;
|
|
360
|
+
stroke-linecap: round; stroke-linejoin: round;
|
|
322
361
|
}
|
|
323
|
-
.
|
|
362
|
+
.visually-hidden {
|
|
363
|
+
position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap;
|
|
364
|
+
}
|
|
365
|
+
button { cursor: pointer; background: none; border: 0; padding: 0; }
|
|
366
|
+
button:disabled { cursor: not-allowed; }
|
|
367
|
+
button:focus-visible { outline: 2px solid rgb(var(--theme-accent-rgb)); outline-offset: 2px; }
|
|
368
|
+
|
|
369
|
+
/* Closed: one floating pill that reads like an empty field, with the mark. */
|
|
370
|
+
.bar { display: flex; justify-content: center; }
|
|
324
371
|
.pill {
|
|
325
|
-
display:
|
|
326
|
-
|
|
372
|
+
display: flex; align-items: center; gap: 12px; width: min(560px, 100%); height: 56px;
|
|
373
|
+
padding: 0 22px 0 26px; border-radius: var(--border-radius-pill);
|
|
374
|
+
background: rgb(var(--theme-background-alt-rgb));
|
|
375
|
+
border: 1px solid rgb(var(--theme-border-rgb) / .25); box-shadow: var(--shadow);
|
|
376
|
+
color: rgb(var(--theme-foreground-muted-rgb)); font-size: 16px; text-align: left;
|
|
377
|
+
transition: transform .25s var(--ease-roll), color .25s var(--ease-roll);
|
|
378
|
+
}
|
|
379
|
+
button.pill:hover { color: rgb(var(--theme-foreground-rgb)); transform: translateY(-2px); }
|
|
380
|
+
.pill > span:first-child { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
381
|
+
.mark { color: rgb(var(--theme-accent-rgb)); font-size: 22px; line-height: 1; }
|
|
382
|
+
.pill.compact { width: auto; height: 40px; padding: 0 18px; font-size: 14px; gap: 4px; }
|
|
383
|
+
|
|
384
|
+
/* Open: a floating card, the text on top and a row of pill buttons below. */
|
|
385
|
+
.panel {
|
|
386
|
+
display: grid; background: rgb(var(--theme-background-alt-rgb));
|
|
387
|
+
border: 1px solid rgb(var(--theme-border-rgb) / .25); border-radius: var(--border-radius-medium);
|
|
388
|
+
box-shadow: var(--shadow); overflow: hidden;
|
|
389
|
+
transition: border-color .25s var(--ease-roll), box-shadow .25s var(--ease-roll);
|
|
390
|
+
animation: rise .25s var(--ease-roll);
|
|
391
|
+
}
|
|
392
|
+
.panel:focus-within {
|
|
393
|
+
border-color: rgb(var(--theme-accent-rgb) / .6);
|
|
394
|
+
box-shadow: 0 0 0 3px rgb(var(--theme-accent-rgb) / .18), var(--shadow);
|
|
395
|
+
}
|
|
396
|
+
@keyframes rise { from { opacity: 0; transform: translateY(8px) scale(.98); } }
|
|
397
|
+
@keyframes spin { to { transform: rotate(1turn); } }
|
|
398
|
+
@media (prefers-reduced-motion: reduce) {
|
|
399
|
+
.panel { animation: none; }
|
|
400
|
+
.pill { transition: none; }
|
|
327
401
|
}
|
|
328
|
-
.
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
.
|
|
402
|
+
.status {
|
|
403
|
+
padding: 16px 22px 0; font-size: 14px; color: rgb(var(--theme-foreground-muted-rgb));
|
|
404
|
+
display: flex; align-items: center; gap: 8px;
|
|
405
|
+
}
|
|
406
|
+
.status.working::before {
|
|
407
|
+
content: ''; width: 12px; height: 12px; flex: none; border-radius: 50%;
|
|
408
|
+
border: 2px solid rgb(var(--theme-border-rgb) / .3); border-top-color: rgb(var(--theme-accent-rgb));
|
|
409
|
+
animation: spin .7s linear infinite;
|
|
410
|
+
}
|
|
411
|
+
.status.error { color: var(--theme-error); }
|
|
333
412
|
textarea {
|
|
334
|
-
width: 100%; resize: none; min-height:
|
|
335
|
-
|
|
413
|
+
display: block; width: 100%; resize: none; min-height: 76px; max-height: 200px;
|
|
414
|
+
padding: 16px 22px 6px; border: 0; outline: 0; background: transparent;
|
|
415
|
+
font-size: 16px; line-height: 1.6; color: rgb(var(--theme-foreground-rgb));
|
|
416
|
+
}
|
|
417
|
+
textarea::placeholder { color: rgb(var(--theme-foreground-muted-rgb)); }
|
|
418
|
+
textarea:disabled { opacity: .5; }
|
|
419
|
+
.toolbar { display: flex; align-items: center; gap: 6px; padding: 8px 12px 12px; }
|
|
420
|
+
.spacer { flex: 1; }
|
|
421
|
+
.chip {
|
|
422
|
+
display: inline-flex; align-items: center; gap: 6px; height: 34px; padding: .4em 1.1em .4em .9em;
|
|
423
|
+
border: 1px solid rgb(var(--theme-border-rgb) / .2); border-radius: var(--border-radius-pill);
|
|
424
|
+
background: rgb(var(--theme-background-actions-rgb) / .6); white-space: nowrap;
|
|
425
|
+
transition: background-color .25s var(--ease-roll);
|
|
426
|
+
}
|
|
427
|
+
button.chip:hover:not(:disabled) { background: rgb(var(--theme-background-actions-rgb)); }
|
|
428
|
+
button.chip:disabled { opacity: .5; }
|
|
429
|
+
.scope { min-width: 0; background: transparent; }
|
|
430
|
+
.scope > span:not(.icon) { overflow: hidden; text-overflow: ellipsis; }
|
|
431
|
+
.scope button {
|
|
432
|
+
display: inline-flex; margin-right: -6px; padding: 3px; border-radius: 50%;
|
|
433
|
+
color: rgb(var(--theme-foreground-muted-rgb));
|
|
336
434
|
}
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
435
|
+
.scope button:hover { background: rgb(var(--theme-background-actions-rgb)); color: rgb(var(--theme-foreground-rgb)); }
|
|
436
|
+
.scope button svg { width: 14px; height: 14px; }
|
|
437
|
+
.icon-button {
|
|
438
|
+
display: inline-flex; align-items: center; justify-content: center;
|
|
439
|
+
width: 34px; height: 34px; border-radius: 50%; color: rgb(var(--theme-foreground-muted-rgb));
|
|
440
|
+
transition: background-color .25s var(--ease-roll), color .25s var(--ease-roll), opacity .25s var(--ease-roll);
|
|
441
|
+
}
|
|
442
|
+
.icon-button:hover:not(:disabled) { background: rgb(var(--theme-background-actions-rgb)); color: rgb(var(--theme-foreground-rgb)); }
|
|
443
|
+
/* The one call to action: white on orange. */
|
|
444
|
+
.icon-button.primary { background: rgb(var(--theme-accent-rgb)); color: #fff; }
|
|
445
|
+
.icon-button.primary:hover:not(:disabled) { background: rgb(var(--theme-accent-rgb)); color: #fff; opacity: .88; }
|
|
446
|
+
.icon-button.primary:disabled { opacity: .35; }
|
|
447
|
+
.divider { width: 1px; height: 20px; background: rgb(var(--theme-border-rgb) / .3); margin: 0 4px; }
|
|
448
|
+
|
|
449
|
+
/* On the site: storing the draft, and the way out. */
|
|
450
|
+
.footer {
|
|
451
|
+
display: flex; align-items: center; gap: 8px; padding: 10px 12px 10px 22px;
|
|
452
|
+
border-top: 1px solid rgb(var(--theme-border-rgb) / .2);
|
|
453
|
+
background: rgb(var(--theme-background-actions-rgb) / .45);
|
|
454
|
+
}
|
|
455
|
+
.footer .chip { height: 30px; padding: .4em 1.2em; background: rgb(var(--theme-background-alt-rgb)); }
|
|
456
|
+
.unsaved { color: rgb(var(--theme-foreground-muted-rgb)); display: inline-flex; align-items: center; }
|
|
457
|
+
.link { color: rgb(var(--theme-foreground-muted-rgb)); text-decoration: underline; text-underline-offset: 3px; padding: 0 6px; }
|
|
458
|
+
.link:hover { color: rgb(var(--theme-foreground-rgb)); }
|
|
459
|
+
.dot {
|
|
460
|
+
display: inline-block; width: 7px; height: 7px; border-radius: 50%;
|
|
461
|
+
background: rgb(var(--theme-accent-rgb)); margin-right: 8px;
|
|
341
462
|
}
|
|
342
|
-
button.primary { background: ${ACCENT}; border-color: ${ACCENT}; color: #fff; }
|
|
343
|
-
button:disabled { opacity: .5; cursor: default; }
|
|
344
|
-
.close { border: 0; background: none; color: var(--muted); cursor: pointer; font-size: 18px; line-height: 1; padding: 2px 6px; }
|
|
345
|
-
.status { font-size: 13px; color: var(--muted); flex: 1; min-width: 0; }
|
|
346
|
-
.status.error { color: var(--error); }
|
|
347
|
-
.bar { display: flex; justify-content: center; gap: 8px; }
|
|
348
|
-
.row > .link { margin-right: auto; }
|
|
349
|
-
.link { border: 0; background: none; color: var(--muted); cursor: pointer; font-size: 12px; text-decoration: underline; padding: 0; }
|
|
350
|
-
.dot { display: inline-block; width: 7px; height: 7px; border-radius: 50%; background: ${ACCENT}; margin-right: 6px; vertical-align: 1px; }
|
|
351
463
|
[hidden] { display: none !important; }
|
|
352
464
|
`;
|
|
353
465
|
const element = (doc, tag, props = {}, ...children)=>{
|
|
@@ -360,6 +472,14 @@ const element = (doc, tag, props = {}, ...children)=>{
|
|
|
360
472
|
}
|
|
361
473
|
return node;
|
|
362
474
|
};
|
|
475
|
+
const icon = (doc, name)=>{
|
|
476
|
+
const span = element(doc, 'span', {
|
|
477
|
+
className: 'icon'
|
|
478
|
+
});
|
|
479
|
+
span.setAttribute('aria-hidden', 'true');
|
|
480
|
+
span.innerHTML = `<svg viewBox="0 0 24 24">${ICONS[name]}</svg>`;
|
|
481
|
+
return span;
|
|
482
|
+
};
|
|
363
483
|
// Mounts the box on the page; returns a function that removes it.
|
|
364
484
|
const mountPromptBox = (doc, bridge, options = {})=>{
|
|
365
485
|
const labels = {
|
|
@@ -374,13 +494,18 @@ const mountPromptBox = (doc, bridge, options = {})=>{
|
|
|
374
494
|
const site = bridge.mode === 'site';
|
|
375
495
|
const pill = element(doc, 'button', {
|
|
376
496
|
className: 'pill',
|
|
377
|
-
type: 'button'
|
|
378
|
-
|
|
379
|
-
|
|
497
|
+
type: 'button'
|
|
498
|
+
}, element(doc, 'span', {
|
|
499
|
+
textContent: labels.open
|
|
500
|
+
}), // The Obelism mark.
|
|
501
|
+
element(doc, 'span', {
|
|
502
|
+
className: 'mark',
|
|
503
|
+
textContent: '⁜'
|
|
504
|
+
}));
|
|
380
505
|
// Someone signed in who may only read: a note that drafts show, and a
|
|
381
506
|
// way out.
|
|
382
507
|
const viewing = element(doc, 'span', {
|
|
383
|
-
className: 'pill'
|
|
508
|
+
className: 'pill compact'
|
|
384
509
|
}, `${labels.viewingDrafts} · `);
|
|
385
510
|
const pillSignOut = element(doc, 'button', {
|
|
386
511
|
className: 'link',
|
|
@@ -388,71 +513,83 @@ const mountPromptBox = (doc, bridge, options = {})=>{
|
|
|
388
513
|
textContent: labels.signOut
|
|
389
514
|
});
|
|
390
515
|
viewing.appendChild(pillSignOut);
|
|
391
|
-
const
|
|
392
|
-
|
|
393
|
-
type: 'button',
|
|
394
|
-
textContent: labels.clearBlock
|
|
395
|
-
});
|
|
396
|
-
const scope = element(doc, 'div', {
|
|
397
|
-
className: 'scope'
|
|
398
|
-
}, '✨ ', scopeText, clearBlock);
|
|
399
|
-
const close = element(doc, 'button', {
|
|
400
|
-
className: 'close',
|
|
401
|
-
type: 'button',
|
|
402
|
-
textContent: '×',
|
|
403
|
-
title: labels.close
|
|
516
|
+
const status = element(doc, 'p', {
|
|
517
|
+
className: 'status'
|
|
404
518
|
});
|
|
405
|
-
|
|
519
|
+
status.setAttribute('role', 'status');
|
|
406
520
|
const input = element(doc, 'textarea', {
|
|
407
521
|
placeholder: labels.placeholder,
|
|
408
522
|
rows: 1
|
|
409
523
|
});
|
|
410
524
|
input.setAttribute('aria-label', labels.open);
|
|
411
|
-
|
|
412
|
-
|
|
525
|
+
// What the prompt acts on: the whole page, or the selected block with a
|
|
526
|
+
// way back to the page.
|
|
527
|
+
const pageIcon = icon(doc, 'page');
|
|
528
|
+
const blockIcon = icon(doc, 'block');
|
|
529
|
+
const scopeText = element(doc, 'span');
|
|
530
|
+
const clearBlock = element(doc, 'button', {
|
|
531
|
+
type: 'button',
|
|
532
|
+
title: labels.clearBlock
|
|
413
533
|
});
|
|
414
|
-
|
|
534
|
+
clearBlock.setAttribute('aria-label', labels.clearBlock);
|
|
535
|
+
clearBlock.appendChild(icon(doc, 'close'));
|
|
536
|
+
const scope = element(doc, 'span', {
|
|
537
|
+
className: 'chip scope'
|
|
538
|
+
}, pageIcon, blockIcon, scopeText, clearBlock);
|
|
415
539
|
const undo = element(doc, 'button', {
|
|
416
|
-
className: 'action',
|
|
540
|
+
className: 'action chip',
|
|
541
|
+
type: 'button'
|
|
542
|
+
}, icon(doc, 'undo'), labels.undo);
|
|
543
|
+
const close = element(doc, 'button', {
|
|
544
|
+
className: 'close icon-button',
|
|
417
545
|
type: 'button',
|
|
418
|
-
|
|
419
|
-
});
|
|
546
|
+
title: labels.close
|
|
547
|
+
}, icon(doc, 'close'));
|
|
548
|
+
close.setAttribute('aria-label', labels.close);
|
|
420
549
|
const send = element(doc, 'button', {
|
|
421
|
-
className: 'action primary',
|
|
422
|
-
type: 'submit'
|
|
550
|
+
className: 'action primary icon-button',
|
|
551
|
+
type: 'submit'
|
|
552
|
+
}, element(doc, 'span', {
|
|
553
|
+
className: 'visually-hidden',
|
|
423
554
|
textContent: labels.send
|
|
555
|
+
}), icon(doc, 'send'));
|
|
556
|
+
send.title = labels.send;
|
|
557
|
+
const unsaved = element(doc, 'span', {
|
|
558
|
+
className: 'unsaved'
|
|
559
|
+
});
|
|
560
|
+
unsaved.appendChild(element(doc, 'span', {
|
|
561
|
+
className: 'dot'
|
|
562
|
+
}));
|
|
563
|
+
unsaved.appendChild(doc.createTextNode(labels.unsaved));
|
|
564
|
+
const signOut = element(doc, 'button', {
|
|
565
|
+
className: 'link',
|
|
566
|
+
type: 'button',
|
|
567
|
+
textContent: labels.signOut
|
|
424
568
|
});
|
|
425
569
|
const save = element(doc, 'button', {
|
|
426
|
-
className: 'action',
|
|
570
|
+
className: 'action chip',
|
|
427
571
|
type: 'button',
|
|
428
572
|
textContent: labels.save
|
|
429
573
|
});
|
|
430
574
|
const publish = element(doc, 'button', {
|
|
431
|
-
className: 'action',
|
|
575
|
+
className: 'action chip',
|
|
432
576
|
type: 'button',
|
|
433
577
|
textContent: labels.publish
|
|
434
578
|
});
|
|
435
|
-
const
|
|
436
|
-
className: '
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
});
|
|
440
|
-
const unsaved = element(doc, 'span', {
|
|
441
|
-
className: 'scope'
|
|
442
|
-
});
|
|
443
|
-
unsaved.appendChild(element(doc, 'span', {
|
|
444
|
-
className: 'dot'
|
|
445
|
-
}));
|
|
446
|
-
unsaved.appendChild(doc.createTextNode(labels.unsaved));
|
|
579
|
+
const footer = element(doc, 'div', {
|
|
580
|
+
className: 'footer'
|
|
581
|
+
}, unsaved, element(doc, 'span', {
|
|
582
|
+
className: 'spacer'
|
|
583
|
+
}), signOut, save, publish);
|
|
447
584
|
const panel = element(doc, 'form', {
|
|
448
585
|
className: 'panel'
|
|
449
|
-
}, element(doc, 'div', {
|
|
450
|
-
className: '
|
|
451
|
-
}, scope,
|
|
452
|
-
className: '
|
|
453
|
-
},
|
|
454
|
-
className: '
|
|
455
|
-
},
|
|
586
|
+
}, status, input, element(doc, 'div', {
|
|
587
|
+
className: 'toolbar'
|
|
588
|
+
}, scope, undo, element(doc, 'span', {
|
|
589
|
+
className: 'spacer'
|
|
590
|
+
}), close, element(doc, 'span', {
|
|
591
|
+
className: 'divider'
|
|
592
|
+
}), send), footer);
|
|
456
593
|
const root = element(doc, 'div', {
|
|
457
594
|
className: 'root'
|
|
458
595
|
}, element(doc, 'div', {
|
|
@@ -473,6 +610,8 @@ const mountPromptBox = (doc, bridge, options = {})=>{
|
|
|
473
610
|
panel.hidden = !open || !available;
|
|
474
611
|
scopeText.textContent = state.selectedUid ? labels.scopeBlock : labels.scopeEntry;
|
|
475
612
|
clearBlock.hidden = !state.selectedUid;
|
|
613
|
+
pageIcon.hidden = !!state.selectedUid;
|
|
614
|
+
blockIcon.hidden = !state.selectedUid;
|
|
476
615
|
undo.hidden = !state.canUndo;
|
|
477
616
|
undo.disabled = busy;
|
|
478
617
|
send.disabled = busy || input.value.trim() === '';
|
|
@@ -484,10 +623,12 @@ const mountPromptBox = (doc, bridge, options = {})=>{
|
|
|
484
623
|
publish.disabled = busy;
|
|
485
624
|
publish.textContent = state.publishing ? labels.publishing : labels.publish;
|
|
486
625
|
signOut.hidden = !site;
|
|
626
|
+
footer.hidden = !site;
|
|
487
627
|
unsaved.hidden = !state.unsaved;
|
|
488
628
|
const text = state.prompting ? labels.working : message?.text ?? (site && !state.selectedUid ? labels.selectHint : '');
|
|
489
629
|
status.textContent = text;
|
|
490
|
-
status.
|
|
630
|
+
status.hidden = !text;
|
|
631
|
+
status.className = `status${state.prompting ? ' working' : ''}${!busy && message?.error ? ' error' : ''}`;
|
|
491
632
|
};
|
|
492
633
|
const refresh = ()=>render(bridge.getState());
|
|
493
634
|
const grow = ()=>{
|
package/dist/bridge.mjs
CHANGED
|
@@ -306,46 +306,158 @@ const DEFAULT_PROMPT_LABELS = {
|
|
|
306
306
|
viewingDrafts: 'Viewing drafts',
|
|
307
307
|
selectHint: 'Click a block to change only that block'
|
|
308
308
|
};
|
|
309
|
-
|
|
309
|
+
// Icons (Lucide), drawn in the text colour.
|
|
310
|
+
const ICONS = {
|
|
311
|
+
page: '<path d="M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z"/><path d="M14 2v4a2 2 0 0 0 2 2h4"/>',
|
|
312
|
+
block: '<rect width="18" height="18" x="3" y="3" rx="2"/><path d="M7 8h10"/><path d="M7 12h6"/>',
|
|
313
|
+
undo: '<path d="M9 14 4 9l5-5"/><path d="M4 9h10.5a5.5 5.5 0 0 1 0 11H11"/>',
|
|
314
|
+
close: '<path d="M18 6 6 18"/><path d="m6 6 12 12"/>',
|
|
315
|
+
send: '<path d="M3.714 3.048a.498.498 0 0 0-.683.627l2.843 7.627a2 2 0 0 1 0 1.396l-2.842 7.627a.498.498 0 0 0 .682.627l18-8.5a.5.5 0 0 0 0-.904z"/><path d="M6 12h16"/>'
|
|
316
|
+
};
|
|
317
|
+
// Obelism's design tokens (obelism.studio/design.md), under their own names:
|
|
318
|
+
// beige and near-black, one orange accent, Inter, pill buttons.
|
|
310
319
|
const CSS = `
|
|
311
320
|
:host { all: initial; }
|
|
312
|
-
* { box-sizing: border-box; font:
|
|
321
|
+
* { box-sizing: border-box; font: inherit; color: inherit; margin: 0; }
|
|
313
322
|
.root {
|
|
314
|
-
--
|
|
315
|
-
|
|
316
|
-
|
|
323
|
+
--color-white-rgb: 248 248 248; --color-beige-rgb: 238 236 233; --color-beige-off-rgb: 228 225 217;
|
|
324
|
+
--color-grey-light-rgb: 132 132 132; --color-grey-rgb: 108 108 108; --color-grey-mid-rgb: 100 100 100; --color-grey-dark-rgb: 40 40 40;
|
|
325
|
+
--color-black-off-rgb: 20 20 20; --color-black-rgb: 12 12 12;
|
|
326
|
+
--color-orange-rgb: 212 130 30; --color-red-rgb: 240 93 93;
|
|
327
|
+
--theme-foreground-rgb: var(--color-black-rgb);
|
|
328
|
+
--theme-background-alt-rgb: var(--color-white-rgb);
|
|
329
|
+
--theme-background-actions-rgb: var(--color-beige-off-rgb);
|
|
330
|
+
--theme-border-rgb: var(--color-grey-light-rgb);
|
|
331
|
+
--theme-accent-rgb: var(--color-orange-rgb);
|
|
332
|
+
--theme-foreground-muted-rgb: var(--color-grey-mid-rgb);
|
|
333
|
+
--theme-error: #b3261e;
|
|
334
|
+
--border-radius-medium: 20px; --border-radius-pill: 5em;
|
|
335
|
+
--ease-roll: cubic-bezier(0.65, 0, 0.35, 1);
|
|
336
|
+
--shadow: 0 18px 40px -16px rgb(var(--color-black-rgb) / .3), 0 2px 6px rgb(var(--color-black-rgb) / .05);
|
|
337
|
+
--font-inter: 'InterVariable', 'Inter', system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI',
|
|
338
|
+
Roboto, 'Helvetica Neue', Arial, 'Noto Sans', sans-serif;
|
|
339
|
+
position: fixed; left: 50%; bottom: 20px; transform: translateX(-50%);
|
|
340
|
+
z-index: 2147483647; width: min(640px, calc(100vw - 32px)); color-scheme: light dark;
|
|
341
|
+
font: 400 14px/1.4 var(--font-inter); color: rgb(var(--theme-foreground-rgb));
|
|
342
|
+
-webkit-font-smoothing: antialiased;
|
|
317
343
|
}
|
|
318
344
|
@media (prefers-color-scheme: dark) {
|
|
319
|
-
.root {
|
|
345
|
+
.root {
|
|
346
|
+
--theme-foreground-rgb: var(--color-white-rgb);
|
|
347
|
+
--theme-background-alt-rgb: var(--color-black-off-rgb);
|
|
348
|
+
--theme-background-actions-rgb: var(--color-grey-dark-rgb);
|
|
349
|
+
--theme-border-rgb: var(--color-grey-rgb);
|
|
350
|
+
--theme-foreground-muted-rgb: var(--color-grey-light-rgb);
|
|
351
|
+
--theme-error: rgb(var(--color-red-rgb));
|
|
352
|
+
--shadow: 0 18px 40px -14px rgb(0 0 0 / .7), 0 2px 6px rgb(0 0 0 / .3);
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
.icon { display: inline-flex; flex: none; }
|
|
356
|
+
.icon svg {
|
|
357
|
+
width: 16px; height: 16px; fill: none; stroke: currentColor; stroke-width: 1.75;
|
|
358
|
+
stroke-linecap: round; stroke-linejoin: round;
|
|
320
359
|
}
|
|
321
|
-
.
|
|
360
|
+
.visually-hidden {
|
|
361
|
+
position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap;
|
|
362
|
+
}
|
|
363
|
+
button { cursor: pointer; background: none; border: 0; padding: 0; }
|
|
364
|
+
button:disabled { cursor: not-allowed; }
|
|
365
|
+
button:focus-visible { outline: 2px solid rgb(var(--theme-accent-rgb)); outline-offset: 2px; }
|
|
366
|
+
|
|
367
|
+
/* Closed: one floating pill that reads like an empty field, with the mark. */
|
|
368
|
+
.bar { display: flex; justify-content: center; }
|
|
322
369
|
.pill {
|
|
323
|
-
display:
|
|
324
|
-
|
|
370
|
+
display: flex; align-items: center; gap: 12px; width: min(560px, 100%); height: 56px;
|
|
371
|
+
padding: 0 22px 0 26px; border-radius: var(--border-radius-pill);
|
|
372
|
+
background: rgb(var(--theme-background-alt-rgb));
|
|
373
|
+
border: 1px solid rgb(var(--theme-border-rgb) / .25); box-shadow: var(--shadow);
|
|
374
|
+
color: rgb(var(--theme-foreground-muted-rgb)); font-size: 16px; text-align: left;
|
|
375
|
+
transition: transform .25s var(--ease-roll), color .25s var(--ease-roll);
|
|
376
|
+
}
|
|
377
|
+
button.pill:hover { color: rgb(var(--theme-foreground-rgb)); transform: translateY(-2px); }
|
|
378
|
+
.pill > span:first-child { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
379
|
+
.mark { color: rgb(var(--theme-accent-rgb)); font-size: 22px; line-height: 1; }
|
|
380
|
+
.pill.compact { width: auto; height: 40px; padding: 0 18px; font-size: 14px; gap: 4px; }
|
|
381
|
+
|
|
382
|
+
/* Open: a floating card, the text on top and a row of pill buttons below. */
|
|
383
|
+
.panel {
|
|
384
|
+
display: grid; background: rgb(var(--theme-background-alt-rgb));
|
|
385
|
+
border: 1px solid rgb(var(--theme-border-rgb) / .25); border-radius: var(--border-radius-medium);
|
|
386
|
+
box-shadow: var(--shadow); overflow: hidden;
|
|
387
|
+
transition: border-color .25s var(--ease-roll), box-shadow .25s var(--ease-roll);
|
|
388
|
+
animation: rise .25s var(--ease-roll);
|
|
389
|
+
}
|
|
390
|
+
.panel:focus-within {
|
|
391
|
+
border-color: rgb(var(--theme-accent-rgb) / .6);
|
|
392
|
+
box-shadow: 0 0 0 3px rgb(var(--theme-accent-rgb) / .18), var(--shadow);
|
|
393
|
+
}
|
|
394
|
+
@keyframes rise { from { opacity: 0; transform: translateY(8px) scale(.98); } }
|
|
395
|
+
@keyframes spin { to { transform: rotate(1turn); } }
|
|
396
|
+
@media (prefers-reduced-motion: reduce) {
|
|
397
|
+
.panel { animation: none; }
|
|
398
|
+
.pill { transition: none; }
|
|
325
399
|
}
|
|
326
|
-
.
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
.
|
|
400
|
+
.status {
|
|
401
|
+
padding: 16px 22px 0; font-size: 14px; color: rgb(var(--theme-foreground-muted-rgb));
|
|
402
|
+
display: flex; align-items: center; gap: 8px;
|
|
403
|
+
}
|
|
404
|
+
.status.working::before {
|
|
405
|
+
content: ''; width: 12px; height: 12px; flex: none; border-radius: 50%;
|
|
406
|
+
border: 2px solid rgb(var(--theme-border-rgb) / .3); border-top-color: rgb(var(--theme-accent-rgb));
|
|
407
|
+
animation: spin .7s linear infinite;
|
|
408
|
+
}
|
|
409
|
+
.status.error { color: var(--theme-error); }
|
|
331
410
|
textarea {
|
|
332
|
-
width: 100%; resize: none; min-height:
|
|
333
|
-
|
|
411
|
+
display: block; width: 100%; resize: none; min-height: 76px; max-height: 200px;
|
|
412
|
+
padding: 16px 22px 6px; border: 0; outline: 0; background: transparent;
|
|
413
|
+
font-size: 16px; line-height: 1.6; color: rgb(var(--theme-foreground-rgb));
|
|
414
|
+
}
|
|
415
|
+
textarea::placeholder { color: rgb(var(--theme-foreground-muted-rgb)); }
|
|
416
|
+
textarea:disabled { opacity: .5; }
|
|
417
|
+
.toolbar { display: flex; align-items: center; gap: 6px; padding: 8px 12px 12px; }
|
|
418
|
+
.spacer { flex: 1; }
|
|
419
|
+
.chip {
|
|
420
|
+
display: inline-flex; align-items: center; gap: 6px; height: 34px; padding: .4em 1.1em .4em .9em;
|
|
421
|
+
border: 1px solid rgb(var(--theme-border-rgb) / .2); border-radius: var(--border-radius-pill);
|
|
422
|
+
background: rgb(var(--theme-background-actions-rgb) / .6); white-space: nowrap;
|
|
423
|
+
transition: background-color .25s var(--ease-roll);
|
|
424
|
+
}
|
|
425
|
+
button.chip:hover:not(:disabled) { background: rgb(var(--theme-background-actions-rgb)); }
|
|
426
|
+
button.chip:disabled { opacity: .5; }
|
|
427
|
+
.scope { min-width: 0; background: transparent; }
|
|
428
|
+
.scope > span:not(.icon) { overflow: hidden; text-overflow: ellipsis; }
|
|
429
|
+
.scope button {
|
|
430
|
+
display: inline-flex; margin-right: -6px; padding: 3px; border-radius: 50%;
|
|
431
|
+
color: rgb(var(--theme-foreground-muted-rgb));
|
|
334
432
|
}
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
433
|
+
.scope button:hover { background: rgb(var(--theme-background-actions-rgb)); color: rgb(var(--theme-foreground-rgb)); }
|
|
434
|
+
.scope button svg { width: 14px; height: 14px; }
|
|
435
|
+
.icon-button {
|
|
436
|
+
display: inline-flex; align-items: center; justify-content: center;
|
|
437
|
+
width: 34px; height: 34px; border-radius: 50%; color: rgb(var(--theme-foreground-muted-rgb));
|
|
438
|
+
transition: background-color .25s var(--ease-roll), color .25s var(--ease-roll), opacity .25s var(--ease-roll);
|
|
439
|
+
}
|
|
440
|
+
.icon-button:hover:not(:disabled) { background: rgb(var(--theme-background-actions-rgb)); color: rgb(var(--theme-foreground-rgb)); }
|
|
441
|
+
/* The one call to action: white on orange. */
|
|
442
|
+
.icon-button.primary { background: rgb(var(--theme-accent-rgb)); color: #fff; }
|
|
443
|
+
.icon-button.primary:hover:not(:disabled) { background: rgb(var(--theme-accent-rgb)); color: #fff; opacity: .88; }
|
|
444
|
+
.icon-button.primary:disabled { opacity: .35; }
|
|
445
|
+
.divider { width: 1px; height: 20px; background: rgb(var(--theme-border-rgb) / .3); margin: 0 4px; }
|
|
446
|
+
|
|
447
|
+
/* On the site: storing the draft, and the way out. */
|
|
448
|
+
.footer {
|
|
449
|
+
display: flex; align-items: center; gap: 8px; padding: 10px 12px 10px 22px;
|
|
450
|
+
border-top: 1px solid rgb(var(--theme-border-rgb) / .2);
|
|
451
|
+
background: rgb(var(--theme-background-actions-rgb) / .45);
|
|
452
|
+
}
|
|
453
|
+
.footer .chip { height: 30px; padding: .4em 1.2em; background: rgb(var(--theme-background-alt-rgb)); }
|
|
454
|
+
.unsaved { color: rgb(var(--theme-foreground-muted-rgb)); display: inline-flex; align-items: center; }
|
|
455
|
+
.link { color: rgb(var(--theme-foreground-muted-rgb)); text-decoration: underline; text-underline-offset: 3px; padding: 0 6px; }
|
|
456
|
+
.link:hover { color: rgb(var(--theme-foreground-rgb)); }
|
|
457
|
+
.dot {
|
|
458
|
+
display: inline-block; width: 7px; height: 7px; border-radius: 50%;
|
|
459
|
+
background: rgb(var(--theme-accent-rgb)); margin-right: 8px;
|
|
339
460
|
}
|
|
340
|
-
button.primary { background: ${ACCENT}; border-color: ${ACCENT}; color: #fff; }
|
|
341
|
-
button:disabled { opacity: .5; cursor: default; }
|
|
342
|
-
.close { border: 0; background: none; color: var(--muted); cursor: pointer; font-size: 18px; line-height: 1; padding: 2px 6px; }
|
|
343
|
-
.status { font-size: 13px; color: var(--muted); flex: 1; min-width: 0; }
|
|
344
|
-
.status.error { color: var(--error); }
|
|
345
|
-
.bar { display: flex; justify-content: center; gap: 8px; }
|
|
346
|
-
.row > .link { margin-right: auto; }
|
|
347
|
-
.link { border: 0; background: none; color: var(--muted); cursor: pointer; font-size: 12px; text-decoration: underline; padding: 0; }
|
|
348
|
-
.dot { display: inline-block; width: 7px; height: 7px; border-radius: 50%; background: ${ACCENT}; margin-right: 6px; vertical-align: 1px; }
|
|
349
461
|
[hidden] { display: none !important; }
|
|
350
462
|
`;
|
|
351
463
|
const element = (doc, tag, props = {}, ...children)=>{
|
|
@@ -358,6 +470,14 @@ const element = (doc, tag, props = {}, ...children)=>{
|
|
|
358
470
|
}
|
|
359
471
|
return node;
|
|
360
472
|
};
|
|
473
|
+
const icon = (doc, name)=>{
|
|
474
|
+
const span = element(doc, 'span', {
|
|
475
|
+
className: 'icon'
|
|
476
|
+
});
|
|
477
|
+
span.setAttribute('aria-hidden', 'true');
|
|
478
|
+
span.innerHTML = `<svg viewBox="0 0 24 24">${ICONS[name]}</svg>`;
|
|
479
|
+
return span;
|
|
480
|
+
};
|
|
361
481
|
// Mounts the box on the page; returns a function that removes it.
|
|
362
482
|
const mountPromptBox = (doc, bridge, options = {})=>{
|
|
363
483
|
const labels = {
|
|
@@ -372,13 +492,18 @@ const mountPromptBox = (doc, bridge, options = {})=>{
|
|
|
372
492
|
const site = bridge.mode === 'site';
|
|
373
493
|
const pill = element(doc, 'button', {
|
|
374
494
|
className: 'pill',
|
|
375
|
-
type: 'button'
|
|
376
|
-
|
|
377
|
-
|
|
495
|
+
type: 'button'
|
|
496
|
+
}, element(doc, 'span', {
|
|
497
|
+
textContent: labels.open
|
|
498
|
+
}), // The Obelism mark.
|
|
499
|
+
element(doc, 'span', {
|
|
500
|
+
className: 'mark',
|
|
501
|
+
textContent: '⁜'
|
|
502
|
+
}));
|
|
378
503
|
// Someone signed in who may only read: a note that drafts show, and a
|
|
379
504
|
// way out.
|
|
380
505
|
const viewing = element(doc, 'span', {
|
|
381
|
-
className: 'pill'
|
|
506
|
+
className: 'pill compact'
|
|
382
507
|
}, `${labels.viewingDrafts} · `);
|
|
383
508
|
const pillSignOut = element(doc, 'button', {
|
|
384
509
|
className: 'link',
|
|
@@ -386,71 +511,83 @@ const mountPromptBox = (doc, bridge, options = {})=>{
|
|
|
386
511
|
textContent: labels.signOut
|
|
387
512
|
});
|
|
388
513
|
viewing.appendChild(pillSignOut);
|
|
389
|
-
const
|
|
390
|
-
|
|
391
|
-
type: 'button',
|
|
392
|
-
textContent: labels.clearBlock
|
|
393
|
-
});
|
|
394
|
-
const scope = element(doc, 'div', {
|
|
395
|
-
className: 'scope'
|
|
396
|
-
}, '✨ ', scopeText, clearBlock);
|
|
397
|
-
const close = element(doc, 'button', {
|
|
398
|
-
className: 'close',
|
|
399
|
-
type: 'button',
|
|
400
|
-
textContent: '×',
|
|
401
|
-
title: labels.close
|
|
514
|
+
const status = element(doc, 'p', {
|
|
515
|
+
className: 'status'
|
|
402
516
|
});
|
|
403
|
-
|
|
517
|
+
status.setAttribute('role', 'status');
|
|
404
518
|
const input = element(doc, 'textarea', {
|
|
405
519
|
placeholder: labels.placeholder,
|
|
406
520
|
rows: 1
|
|
407
521
|
});
|
|
408
522
|
input.setAttribute('aria-label', labels.open);
|
|
409
|
-
|
|
410
|
-
|
|
523
|
+
// What the prompt acts on: the whole page, or the selected block with a
|
|
524
|
+
// way back to the page.
|
|
525
|
+
const pageIcon = icon(doc, 'page');
|
|
526
|
+
const blockIcon = icon(doc, 'block');
|
|
527
|
+
const scopeText = element(doc, 'span');
|
|
528
|
+
const clearBlock = element(doc, 'button', {
|
|
529
|
+
type: 'button',
|
|
530
|
+
title: labels.clearBlock
|
|
411
531
|
});
|
|
412
|
-
|
|
532
|
+
clearBlock.setAttribute('aria-label', labels.clearBlock);
|
|
533
|
+
clearBlock.appendChild(icon(doc, 'close'));
|
|
534
|
+
const scope = element(doc, 'span', {
|
|
535
|
+
className: 'chip scope'
|
|
536
|
+
}, pageIcon, blockIcon, scopeText, clearBlock);
|
|
413
537
|
const undo = element(doc, 'button', {
|
|
414
|
-
className: 'action',
|
|
538
|
+
className: 'action chip',
|
|
539
|
+
type: 'button'
|
|
540
|
+
}, icon(doc, 'undo'), labels.undo);
|
|
541
|
+
const close = element(doc, 'button', {
|
|
542
|
+
className: 'close icon-button',
|
|
415
543
|
type: 'button',
|
|
416
|
-
|
|
417
|
-
});
|
|
544
|
+
title: labels.close
|
|
545
|
+
}, icon(doc, 'close'));
|
|
546
|
+
close.setAttribute('aria-label', labels.close);
|
|
418
547
|
const send = element(doc, 'button', {
|
|
419
|
-
className: 'action primary',
|
|
420
|
-
type: 'submit'
|
|
548
|
+
className: 'action primary icon-button',
|
|
549
|
+
type: 'submit'
|
|
550
|
+
}, element(doc, 'span', {
|
|
551
|
+
className: 'visually-hidden',
|
|
421
552
|
textContent: labels.send
|
|
553
|
+
}), icon(doc, 'send'));
|
|
554
|
+
send.title = labels.send;
|
|
555
|
+
const unsaved = element(doc, 'span', {
|
|
556
|
+
className: 'unsaved'
|
|
557
|
+
});
|
|
558
|
+
unsaved.appendChild(element(doc, 'span', {
|
|
559
|
+
className: 'dot'
|
|
560
|
+
}));
|
|
561
|
+
unsaved.appendChild(doc.createTextNode(labels.unsaved));
|
|
562
|
+
const signOut = element(doc, 'button', {
|
|
563
|
+
className: 'link',
|
|
564
|
+
type: 'button',
|
|
565
|
+
textContent: labels.signOut
|
|
422
566
|
});
|
|
423
567
|
const save = element(doc, 'button', {
|
|
424
|
-
className: 'action',
|
|
568
|
+
className: 'action chip',
|
|
425
569
|
type: 'button',
|
|
426
570
|
textContent: labels.save
|
|
427
571
|
});
|
|
428
572
|
const publish = element(doc, 'button', {
|
|
429
|
-
className: 'action',
|
|
573
|
+
className: 'action chip',
|
|
430
574
|
type: 'button',
|
|
431
575
|
textContent: labels.publish
|
|
432
576
|
});
|
|
433
|
-
const
|
|
434
|
-
className: '
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
});
|
|
438
|
-
const unsaved = element(doc, 'span', {
|
|
439
|
-
className: 'scope'
|
|
440
|
-
});
|
|
441
|
-
unsaved.appendChild(element(doc, 'span', {
|
|
442
|
-
className: 'dot'
|
|
443
|
-
}));
|
|
444
|
-
unsaved.appendChild(doc.createTextNode(labels.unsaved));
|
|
577
|
+
const footer = element(doc, 'div', {
|
|
578
|
+
className: 'footer'
|
|
579
|
+
}, unsaved, element(doc, 'span', {
|
|
580
|
+
className: 'spacer'
|
|
581
|
+
}), signOut, save, publish);
|
|
445
582
|
const panel = element(doc, 'form', {
|
|
446
583
|
className: 'panel'
|
|
447
|
-
}, element(doc, 'div', {
|
|
448
|
-
className: '
|
|
449
|
-
}, scope,
|
|
450
|
-
className: '
|
|
451
|
-
},
|
|
452
|
-
className: '
|
|
453
|
-
},
|
|
584
|
+
}, status, input, element(doc, 'div', {
|
|
585
|
+
className: 'toolbar'
|
|
586
|
+
}, scope, undo, element(doc, 'span', {
|
|
587
|
+
className: 'spacer'
|
|
588
|
+
}), close, element(doc, 'span', {
|
|
589
|
+
className: 'divider'
|
|
590
|
+
}), send), footer);
|
|
454
591
|
const root = element(doc, 'div', {
|
|
455
592
|
className: 'root'
|
|
456
593
|
}, element(doc, 'div', {
|
|
@@ -471,6 +608,8 @@ const mountPromptBox = (doc, bridge, options = {})=>{
|
|
|
471
608
|
panel.hidden = !open || !available;
|
|
472
609
|
scopeText.textContent = state.selectedUid ? labels.scopeBlock : labels.scopeEntry;
|
|
473
610
|
clearBlock.hidden = !state.selectedUid;
|
|
611
|
+
pageIcon.hidden = !!state.selectedUid;
|
|
612
|
+
blockIcon.hidden = !state.selectedUid;
|
|
474
613
|
undo.hidden = !state.canUndo;
|
|
475
614
|
undo.disabled = busy;
|
|
476
615
|
send.disabled = busy || input.value.trim() === '';
|
|
@@ -482,10 +621,12 @@ const mountPromptBox = (doc, bridge, options = {})=>{
|
|
|
482
621
|
publish.disabled = busy;
|
|
483
622
|
publish.textContent = state.publishing ? labels.publishing : labels.publish;
|
|
484
623
|
signOut.hidden = !site;
|
|
624
|
+
footer.hidden = !site;
|
|
485
625
|
unsaved.hidden = !state.unsaved;
|
|
486
626
|
const text = state.prompting ? labels.working : message?.text ?? (site && !state.selectedUid ? labels.selectHint : '');
|
|
487
627
|
status.textContent = text;
|
|
488
|
-
status.
|
|
628
|
+
status.hidden = !text;
|
|
629
|
+
status.className = `status${state.prompting ? ' working' : ''}${!busy && message?.error ? ' error' : ''}`;
|
|
489
630
|
};
|
|
490
631
|
const refresh = ()=>render(bridge.getState());
|
|
491
632
|
const grow = ()=>{
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@obelism/content",
|
|
3
3
|
"description": "Obelism Content SDK: the delivery API client, the visual editor bridge with prompt editing, editing on your own site, and the content model CLI",
|
|
4
|
-
"version": "0.1.
|
|
4
|
+
"version": "0.1.1",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"cms",
|
|
7
7
|
"headless-cms",
|