@bison-lab/payload-core 3.22.0 → 3.25.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/README.md +15 -7
- package/dist/admin.d.mts +16 -5
- package/dist/admin.d.mts.map +1 -1
- package/dist/admin.mjs +480 -321
- package/dist/admin.mjs.map +1 -1
- package/dist/index.d.mts +41 -13
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +219 -37
- package/dist/index.mjs.map +1 -1
- package/package.json +9 -3
package/dist/admin.mjs
CHANGED
|
@@ -4,8 +4,11 @@ import { ArrayField, Button, CheckboxInput, FieldDescription, FieldError, FieldL
|
|
|
4
4
|
import { GREY_SCALES, SHADE_STEPS, contrastForeground, contrastRatio, createColorScale, deriveDarkPalette, deriveLightPalette, hexToHSL, hslToString, includedShadeSteps, isThemeHex, presetHints, setColorScaleInclude } from "@bison-lab/tokens";
|
|
5
5
|
import { useCallback, useEffect, useId, useLayoutEffect, useMemo, useRef, useState } from "react";
|
|
6
6
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
7
|
+
import { Badge, Button as Button$1, Dialog, Field, Input, KitProvider, Label, Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@bison-lab/admin-ui";
|
|
8
|
+
import { HexColorPicker } from "react-colorful";
|
|
7
9
|
import { createPortal } from "react-dom";
|
|
8
10
|
import { findFont, fontFaceCss, isFontId } from "@bison-lab/fonts";
|
|
11
|
+
import "payload";
|
|
9
12
|
//#region src/admin/color-field.tsx
|
|
10
13
|
const HEX_ERROR = "Enter a six-digit hex colour like #1e3a5f";
|
|
11
14
|
/**
|
|
@@ -41,7 +44,7 @@ const ColorField = ({ field, path, readOnly }) => {
|
|
|
41
44
|
/* @__PURE__ */ jsx("style", {
|
|
42
45
|
href: "bl-color-field",
|
|
43
46
|
precedence: "default",
|
|
44
|
-
children: CSS$
|
|
47
|
+
children: CSS$5
|
|
45
48
|
}),
|
|
46
49
|
/* @__PURE__ */ jsx(FieldLabel, {
|
|
47
50
|
htmlFor: hexId,
|
|
@@ -100,7 +103,7 @@ const ColorField = ({ field, path, readOnly }) => {
|
|
|
100
103
|
]
|
|
101
104
|
});
|
|
102
105
|
};
|
|
103
|
-
const CSS$
|
|
106
|
+
const CSS$5 = `
|
|
104
107
|
.bl-color-field__control{display:flex;align-items:center;gap:calc(var(--base) * .4)}
|
|
105
108
|
.bl-color-field__swatch{flex:none;width:calc(var(--base) * 1.6);height:calc(var(--base) * 1.6);border:1px solid var(--theme-elevation-150);border-radius:var(--style-radius-s);background:var(--theme-elevation-50)}
|
|
106
109
|
.bl-color-field__picker{flex:none;width:calc(var(--base) * 2);height:calc(var(--base) * 2);padding:0;border:1px solid var(--theme-elevation-150);border-radius:var(--style-radius-s);background:transparent;cursor:pointer}
|
|
@@ -345,6 +348,123 @@ function readabilityRatioLine(sample, target = 7) {
|
|
|
345
348
|
const READABILITY_FIX = "Darken or lighten the hex, then regenerate the scale. The site picks light or dark type for you.";
|
|
346
349
|
const READABILITY_PUBLISH_NOTE = "You can still publish. To improve a color, darken or lighten it and regenerate.";
|
|
347
350
|
//#endregion
|
|
351
|
+
//#region src/admin/portal.tsx
|
|
352
|
+
/** Theme overlays must leave Payload's transformed/clipped admin tree. */
|
|
353
|
+
function ThemePortal({ children }) {
|
|
354
|
+
if (typeof document === "undefined") return null;
|
|
355
|
+
return createPortal(children, document.body);
|
|
356
|
+
}
|
|
357
|
+
//#endregion
|
|
358
|
+
//#region src/admin/brand-hex-field.tsx
|
|
359
|
+
/** Keep a leading # and at most six hex digits. Drop everything else. */
|
|
360
|
+
function filterThemeHexInput(raw) {
|
|
361
|
+
const trimmed = raw.trim();
|
|
362
|
+
if (trimmed === "") return "";
|
|
363
|
+
return `#${trimmed.replace(/^#/, "").replace(/[^0-9a-fA-F]/g, "").slice(0, 6)}`;
|
|
364
|
+
}
|
|
365
|
+
function BrandHexField({ name, value, onChange, readOnly, placeholder = "#DB0082", picker = "dialog" }) {
|
|
366
|
+
const [draft, setDraft] = useState(value);
|
|
367
|
+
const [open, setOpen] = useState(false);
|
|
368
|
+
const [pickerDraft, setPickerDraft] = useState(value);
|
|
369
|
+
useEffect(() => {
|
|
370
|
+
setDraft(value);
|
|
371
|
+
}, [value]);
|
|
372
|
+
function typeHex(next) {
|
|
373
|
+
const filtered = filterThemeHexInput(next);
|
|
374
|
+
setDraft(filtered);
|
|
375
|
+
if (isThemeHex(filtered)) onChange(filtered);
|
|
376
|
+
}
|
|
377
|
+
function openPicker() {
|
|
378
|
+
setPickerDraft(isThemeHex(draft) ? draft : value);
|
|
379
|
+
setOpen(true);
|
|
380
|
+
}
|
|
381
|
+
function applyPicker() {
|
|
382
|
+
if (!isThemeHex(pickerDraft)) return;
|
|
383
|
+
onChange(pickerDraft);
|
|
384
|
+
setDraft(pickerDraft);
|
|
385
|
+
setOpen(false);
|
|
386
|
+
}
|
|
387
|
+
const input = /* @__PURE__ */ jsx(Input, {
|
|
388
|
+
"aria-label": `${name} hex`,
|
|
389
|
+
value: draft,
|
|
390
|
+
placeholder,
|
|
391
|
+
spellCheck: false,
|
|
392
|
+
autoComplete: "off",
|
|
393
|
+
disabled: readOnly,
|
|
394
|
+
onChange: (event) => typeHex(event.target.value),
|
|
395
|
+
onBlur: () => {
|
|
396
|
+
if (!isThemeHex(draft)) setDraft(value);
|
|
397
|
+
}
|
|
398
|
+
});
|
|
399
|
+
return /* @__PURE__ */ jsxs(KitProvider, { children: [
|
|
400
|
+
/* @__PURE__ */ jsx("style", {
|
|
401
|
+
href: "bl-brand-hex",
|
|
402
|
+
precedence: "default",
|
|
403
|
+
children: CSS$4
|
|
404
|
+
}),
|
|
405
|
+
picker === "inline" ? /* @__PURE__ */ jsxs("div", {
|
|
406
|
+
className: "bl-brand-hex bl-brand-hex--inline",
|
|
407
|
+
children: [/* @__PURE__ */ jsx(HexColorPicker, {
|
|
408
|
+
color: isThemeHex(draft) ? draft : "#000000",
|
|
409
|
+
onChange: (hex) => {
|
|
410
|
+
setDraft(hex);
|
|
411
|
+
onChange(hex);
|
|
412
|
+
}
|
|
413
|
+
}), /* @__PURE__ */ jsxs(Field, {
|
|
414
|
+
as: "div",
|
|
415
|
+
children: [/* @__PURE__ */ jsx(Label, { children: "Hex" }), input]
|
|
416
|
+
})]
|
|
417
|
+
}) : /* @__PURE__ */ jsxs("div", {
|
|
418
|
+
className: "bl-brand-hex",
|
|
419
|
+
children: [/* @__PURE__ */ jsx("button", {
|
|
420
|
+
type: "button",
|
|
421
|
+
className: "bl-brand-hex__swatch",
|
|
422
|
+
"aria-label": `${name} picker`,
|
|
423
|
+
disabled: readOnly,
|
|
424
|
+
style: { background: isThemeHex(draft) ? draft : "transparent" },
|
|
425
|
+
onClick: openPicker
|
|
426
|
+
}), input]
|
|
427
|
+
}),
|
|
428
|
+
picker === "dialog" ? /* @__PURE__ */ jsx(ThemePortal, { children: /* @__PURE__ */ jsx("div", {
|
|
429
|
+
className: "bl-theme-dialog",
|
|
430
|
+
children: /* @__PURE__ */ jsx(Dialog, {
|
|
431
|
+
open,
|
|
432
|
+
title: `Pick ${name}`,
|
|
433
|
+
onCancel: () => setOpen(false),
|
|
434
|
+
confirmLabel: "Apply",
|
|
435
|
+
onConfirm: applyPicker,
|
|
436
|
+
confirmDisabled: !isThemeHex(pickerDraft),
|
|
437
|
+
children: /* @__PURE__ */ jsxs("div", {
|
|
438
|
+
className: "bl-brand-hex bl-brand-hex--inline",
|
|
439
|
+
children: [/* @__PURE__ */ jsx(HexColorPicker, {
|
|
440
|
+
color: isThemeHex(pickerDraft) ? pickerDraft : "#000000",
|
|
441
|
+
onChange: setPickerDraft
|
|
442
|
+
}), /* @__PURE__ */ jsxs(Field, {
|
|
443
|
+
as: "div",
|
|
444
|
+
children: [/* @__PURE__ */ jsx(Label, { children: "Hex" }), /* @__PURE__ */ jsx(Input, {
|
|
445
|
+
"aria-label": `${name} picker hex`,
|
|
446
|
+
value: pickerDraft,
|
|
447
|
+
placeholder,
|
|
448
|
+
spellCheck: false,
|
|
449
|
+
autoComplete: "off",
|
|
450
|
+
onChange: (event) => setPickerDraft(filterThemeHexInput(event.target.value))
|
|
451
|
+
})]
|
|
452
|
+
})]
|
|
453
|
+
})
|
|
454
|
+
})
|
|
455
|
+
}) }) : null
|
|
456
|
+
] });
|
|
457
|
+
}
|
|
458
|
+
const CSS$4 = `
|
|
459
|
+
.bl-brand-hex{display:flex;align-items:stretch;gap:8px;min-width:0}
|
|
460
|
+
.bl-brand-hex--inline{flex-direction:column;gap:12px}
|
|
461
|
+
.bl-brand-hex .react-colorful{width:100%;height:200px}
|
|
462
|
+
.bl-brand-hex__swatch{flex:none;width:38px;border:1px solid #3a3d46;border-radius:8px;padding:0;cursor:pointer;background:#1d1f24}
|
|
463
|
+
.bl-brand-hex__swatch:disabled{opacity:.5;cursor:not-allowed}
|
|
464
|
+
.bl-brand-hex .bl-nav-kit__input{font-family:var(--font-mono,ui-monospace,monospace)}
|
|
465
|
+
.bl-theme-dialog .bl-nav-kit__modal{z-index:10000}
|
|
466
|
+
`;
|
|
467
|
+
//#endregion
|
|
348
468
|
//#region src/admin/colors-layout.ts
|
|
349
469
|
/**
|
|
350
470
|
* Theme Colors tab chrome. Payload group-in-group draws a left gutter;
|
|
@@ -386,13 +506,6 @@ const THEME_COLORS_LAYOUT_CSS = `
|
|
|
386
506
|
}
|
|
387
507
|
`;
|
|
388
508
|
//#endregion
|
|
389
|
-
//#region src/admin/portal.tsx
|
|
390
|
-
/** Theme overlays must leave Payload's transformed/clipped admin tree. */
|
|
391
|
-
function ThemePortal({ children }) {
|
|
392
|
-
if (typeof document === "undefined") return null;
|
|
393
|
-
return createPortal(children, document.body);
|
|
394
|
-
}
|
|
395
|
-
//#endregion
|
|
396
509
|
//#region src/admin/preview-mode.tsx
|
|
397
510
|
const ATTR = "data-bl-theme-preview";
|
|
398
511
|
const EVENT = "bl-theme-preview";
|
|
@@ -410,7 +523,11 @@ const PREVIEW_BRAND = {
|
|
|
410
523
|
secondary: "#111111",
|
|
411
524
|
success: "#111111"
|
|
412
525
|
};
|
|
413
|
-
|
|
526
|
+
function readDocumentTheme() {
|
|
527
|
+
if (typeof document === "undefined") return "light";
|
|
528
|
+
return document.documentElement.getAttribute("data-theme") === "dark" ? "dark" : "light";
|
|
529
|
+
}
|
|
530
|
+
let currentMode = readDocumentTheme();
|
|
414
531
|
function readMode() {
|
|
415
532
|
return currentMode;
|
|
416
533
|
}
|
|
@@ -450,7 +567,10 @@ function previewVarsFor(grey, mode) {
|
|
|
450
567
|
"--bl-preview-border": `hsl(${palette.border})`,
|
|
451
568
|
"--bl-preview-text": `hsl(${palette.foreground})`,
|
|
452
569
|
"--bl-preview-muted": `hsl(${palette["muted-foreground"]})`,
|
|
453
|
-
"--bl-preview-input": `hsl(${palette.input})
|
|
570
|
+
"--bl-preview-input": `hsl(${palette.input})`,
|
|
571
|
+
"--theme-elevation-0": `hsl(${palette.card})`,
|
|
572
|
+
"--theme-elevation-150": `hsl(${palette.border})`,
|
|
573
|
+
"--theme-elevation-800": `hsl(${palette.foreground})`
|
|
454
574
|
};
|
|
455
575
|
}
|
|
456
576
|
function useGreyScale() {
|
|
@@ -471,30 +591,6 @@ function usePreviewCanvas() {
|
|
|
471
591
|
style: previewVarsFor(useGreyScale(), mode)
|
|
472
592
|
};
|
|
473
593
|
}
|
|
474
|
-
function ThemePreviewToggle() {
|
|
475
|
-
const mode = useThemePreviewMode();
|
|
476
|
-
return /* @__PURE__ */ jsxs("div", {
|
|
477
|
-
className: "bl-preview-toggle",
|
|
478
|
-
role: "group",
|
|
479
|
-
"aria-label": "Preview theme in",
|
|
480
|
-
children: [/* @__PURE__ */ jsx("button", {
|
|
481
|
-
type: "button",
|
|
482
|
-
"data-on": mode === "light" ? "" : void 0,
|
|
483
|
-
onClick: () => setThemePreviewMode("light"),
|
|
484
|
-
children: "Light"
|
|
485
|
-
}), /* @__PURE__ */ jsx("button", {
|
|
486
|
-
type: "button",
|
|
487
|
-
"data-on": mode === "dark" ? "" : void 0,
|
|
488
|
-
onClick: () => setThemePreviewMode("dark"),
|
|
489
|
-
children: "Dark"
|
|
490
|
-
})]
|
|
491
|
-
});
|
|
492
|
-
}
|
|
493
|
-
const THEME_PREVIEW_TOGGLE_CSS = `
|
|
494
|
-
.bl-preview-toggle{display:inline-flex;padding:3px;border:1px solid var(--theme-elevation-150,#e2e8f0);border-radius:10px;background:var(--theme-elevation-0,#fff)}
|
|
495
|
-
.bl-preview-toggle button{min-height:2rem;padding:.25rem .75rem;border:0;border-radius:7px;background:transparent;color:var(--theme-elevation-600,#475569);font:inherit;font-size:13px;font-weight:600;cursor:pointer}
|
|
496
|
-
.bl-preview-toggle button[data-on]{background:var(--theme-text,#0f172a);color:var(--theme-bg,#fff)}
|
|
497
|
-
`;
|
|
498
594
|
//#endregion
|
|
499
595
|
//#region src/admin/readability-list.tsx
|
|
500
596
|
function ReadabilityDetail({ item, target = 7 }) {
|
|
@@ -614,13 +710,9 @@ function ColorScaleCard({ id, name, hint, required, custom, state, onChange, onD
|
|
|
614
710
|
const canvas = usePreviewCanvas();
|
|
615
711
|
const [attentionOpen, setAttentionOpen] = useState(false);
|
|
616
712
|
const [shakeStep, setShakeStep] = useState(null);
|
|
617
|
-
const [hexDraft, setHexDraft] = useState(state.hex);
|
|
618
713
|
const titleId = useId();
|
|
619
714
|
const included = new Set(includedShadeSteps(state));
|
|
620
715
|
const hueDrift = role === "success" ? Boolean(successHueWarning(state.hex)) : role === "destructive" ? Boolean(destructiveHueWarning(state.hex)) : false;
|
|
621
|
-
useEffect(() => {
|
|
622
|
-
setHexDraft(state.hex);
|
|
623
|
-
}, [state.hex]);
|
|
624
716
|
function commitHex(hex) {
|
|
625
717
|
onChange(createColorScale(hex, state.sourceStep, state.include));
|
|
626
718
|
}
|
|
@@ -638,211 +730,182 @@ function ColorScaleCard({ id, name, hint, required, custom, state, onChange, onD
|
|
|
638
730
|
else next.add(step);
|
|
639
731
|
onChange(setColorScaleInclude(state, SHADE_STEPS.filter((item) => next.has(item))));
|
|
640
732
|
}
|
|
641
|
-
return /* @__PURE__ */
|
|
642
|
-
|
|
643
|
-
"
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
className: "bl-scale-
|
|
650
|
-
children: [
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
733
|
+
return /* @__PURE__ */ jsx(KitProvider, {
|
|
734
|
+
accent: id === "primary" && isThemeHex(state.hex) ? state.hex : void 0,
|
|
735
|
+
children: /* @__PURE__ */ jsxs("article", {
|
|
736
|
+
className: `bl-scale-card ${canvas.className}`,
|
|
737
|
+
"data-preview": canvas.mode,
|
|
738
|
+
style: canvas.style,
|
|
739
|
+
children: [
|
|
740
|
+
/* @__PURE__ */ jsxs("header", {
|
|
741
|
+
className: "bl-scale-card__head",
|
|
742
|
+
children: [/* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsxs("div", {
|
|
743
|
+
className: "bl-scale-card__title-row",
|
|
744
|
+
children: [
|
|
745
|
+
/* @__PURE__ */ jsx("h3", {
|
|
746
|
+
className: "bl-scale-card__title",
|
|
747
|
+
children: name
|
|
748
|
+
}),
|
|
749
|
+
required ? /* @__PURE__ */ jsx(Badge, { children: "Required" }) : null,
|
|
750
|
+
custom ? /* @__PURE__ */ jsx(Badge, { children: "Optional" }) : null,
|
|
751
|
+
warning && !warning.meets ? /* @__PURE__ */ jsx(Badge, {
|
|
752
|
+
as: "button",
|
|
753
|
+
variant: "danger",
|
|
754
|
+
"aria-haspopup": "dialog",
|
|
755
|
+
onClick: () => setAttentionOpen(true),
|
|
756
|
+
children: "Needs attention"
|
|
757
|
+
}) : null
|
|
758
|
+
]
|
|
759
|
+
}), hint ? /* @__PURE__ */ jsx("p", {
|
|
760
|
+
className: "bl-scale-card__hint",
|
|
761
|
+
children: hint
|
|
762
|
+
}) : null] }), onDelete ? /* @__PURE__ */ jsx("button", {
|
|
763
|
+
type: "button",
|
|
764
|
+
className: "bl-scale-card__delete",
|
|
765
|
+
disabled: readOnly,
|
|
766
|
+
onClick: onDelete,
|
|
767
|
+
children: "Delete"
|
|
768
|
+
}) : null]
|
|
769
|
+
}),
|
|
770
|
+
/* @__PURE__ */ jsxs("div", {
|
|
771
|
+
className: "bl-scale-card__row",
|
|
772
|
+
children: [/* @__PURE__ */ jsxs(Field, {
|
|
773
|
+
as: "div",
|
|
774
|
+
children: [/* @__PURE__ */ jsx(Label, { children: "Brand hex" }), /* @__PURE__ */ jsx(BrandHexField, {
|
|
775
|
+
name,
|
|
776
|
+
value: state.hex,
|
|
777
|
+
onChange: commitHex,
|
|
778
|
+
readOnly
|
|
779
|
+
})]
|
|
780
|
+
}), /* @__PURE__ */ jsxs(Field, {
|
|
781
|
+
as: "div",
|
|
782
|
+
children: [/* @__PURE__ */ jsx(Label, { children: "This color is" }), /* @__PURE__ */ jsxs(Select, {
|
|
783
|
+
value: String(state.sourceStep),
|
|
784
|
+
onValueChange: (value) => commitStep(Number(value)),
|
|
785
|
+
disabled: readOnly,
|
|
786
|
+
children: [/* @__PURE__ */ jsx(SelectTrigger, {
|
|
787
|
+
"aria-label": "This color is",
|
|
788
|
+
children: /* @__PURE__ */ jsx(SelectValue, {})
|
|
789
|
+
}), /* @__PURE__ */ jsx(SelectContent, { children: SHADE_STEPS.map((step) => /* @__PURE__ */ jsx(SelectItem, {
|
|
790
|
+
value: String(step),
|
|
791
|
+
children: step
|
|
792
|
+
}, step)) })]
|
|
793
|
+
})]
|
|
794
|
+
})]
|
|
795
|
+
}),
|
|
796
|
+
role ? /* @__PURE__ */ jsxs("div", {
|
|
797
|
+
className: "bl-scale-card__family",
|
|
798
|
+
"data-role": role,
|
|
799
|
+
"data-drift": hueDrift ? "" : void 0,
|
|
800
|
+
children: [/* @__PURE__ */ jsx("div", {
|
|
801
|
+
className: "bl-scale-card__family-mark",
|
|
802
|
+
"aria-hidden": "true",
|
|
803
|
+
children: "!"
|
|
804
|
+
}), /* @__PURE__ */ jsxs("div", { children: [
|
|
805
|
+
/* @__PURE__ */ jsx("div", {
|
|
806
|
+
className: "bl-scale-card__family-title",
|
|
807
|
+
children: STATUS_COPY[role].title
|
|
654
808
|
}),
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
custom ? /* @__PURE__ */ jsx("span", {
|
|
660
|
-
className: "bl-scale-card__badge",
|
|
661
|
-
children: "Optional"
|
|
662
|
-
}) : null,
|
|
663
|
-
warning && !warning.meets ? /* @__PURE__ */ jsx("button", {
|
|
664
|
-
type: "button",
|
|
665
|
-
className: "bl-scale-card__badge bl-scale-card__badge--attention",
|
|
666
|
-
"aria-haspopup": "dialog",
|
|
667
|
-
onClick: () => setAttentionOpen(true),
|
|
668
|
-
children: "Needs attention"
|
|
809
|
+
/* @__PURE__ */ jsx("p", { children: STATUS_COPY[role].body }),
|
|
810
|
+
hueDrift ? /* @__PURE__ */ jsx("p", {
|
|
811
|
+
className: "bl-scale-card__family-drift",
|
|
812
|
+
children: STATUS_COPY[role].drift
|
|
669
813
|
}) : null
|
|
670
|
-
]
|
|
671
|
-
})
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
type: "color",
|
|
690
|
-
"aria-label": `${name} picker`,
|
|
814
|
+
] })]
|
|
815
|
+
}) : null,
|
|
816
|
+
/* @__PURE__ */ jsxs("div", {
|
|
817
|
+
className: "bl-scale-card__scale-head",
|
|
818
|
+
children: [/* @__PURE__ */ jsx("span", { children: "Generated scale" }), /* @__PURE__ */ jsxs("span", { children: [SHADE_STEPS.length, " shades"] })]
|
|
819
|
+
}),
|
|
820
|
+
/* @__PURE__ */ jsx("div", {
|
|
821
|
+
className: "bl-scale-card__steps",
|
|
822
|
+
role: "group",
|
|
823
|
+
"aria-label": `${name} scale steps`,
|
|
824
|
+
children: SHADE_STEPS.map((step) => {
|
|
825
|
+
const source = step === state.sourceStep;
|
|
826
|
+
const on = included.has(step);
|
|
827
|
+
return /* @__PURE__ */ jsxs("button", {
|
|
828
|
+
type: "button",
|
|
829
|
+
className: "bl-scale-card__step",
|
|
830
|
+
"data-source": source ? "" : void 0,
|
|
831
|
+
"data-excluded": on ? void 0 : "",
|
|
832
|
+
"data-shake": shakeStep === step ? "" : void 0,
|
|
691
833
|
disabled: readOnly,
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
834
|
+
"aria-pressed": on,
|
|
835
|
+
"aria-label": source ? `Source step ${step} cannot be excluded` : on ? `Shade ${step}, available — click to exclude from the palette` : `Shade ${step}, excluded — click to include in the palette`,
|
|
836
|
+
title: source ? `Source step ${step} cannot be excluded` : on ? "Available to page editors — click to exclude" : "Excluded from page editors — click to include",
|
|
837
|
+
onClick: (event) => {
|
|
696
838
|
event.preventDefault();
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
} catch {
|
|
700
|
-
input.click();
|
|
701
|
-
}
|
|
839
|
+
event.stopPropagation();
|
|
840
|
+
toggleStep(step);
|
|
702
841
|
},
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
"
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
842
|
+
children: [/* @__PURE__ */ jsxs("span", {
|
|
843
|
+
className: "bl-scale-card__chip-wrap",
|
|
844
|
+
children: [/* @__PURE__ */ jsx("span", {
|
|
845
|
+
className: "bl-scale-card__chip",
|
|
846
|
+
style: { backgroundColor: hslCss(state.scale[step]) }
|
|
847
|
+
}), /* @__PURE__ */ jsx(IncludeMark, { on })]
|
|
848
|
+
}), /* @__PURE__ */ jsx("span", {
|
|
849
|
+
className: "bl-scale-card__step-label",
|
|
850
|
+
children: step
|
|
851
|
+
})]
|
|
852
|
+
}, step);
|
|
853
|
+
})
|
|
854
|
+
}),
|
|
855
|
+
/* @__PURE__ */ jsxs("div", {
|
|
856
|
+
className: "bl-scale-card__editors",
|
|
857
|
+
children: [/* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("div", { children: "Available to page editors" }), /* @__PURE__ */ jsxs("p", { children: [
|
|
858
|
+
included.size,
|
|
859
|
+
" of ",
|
|
860
|
+
SHADE_STEPS.length,
|
|
861
|
+
" shades available · Choose which shades editors can select when building pages."
|
|
862
|
+
] })] }), /* @__PURE__ */ jsxs("span", { children: [/* @__PURE__ */ jsx("button", {
|
|
863
|
+
type: "button",
|
|
724
864
|
disabled: readOnly,
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
value: step,
|
|
729
|
-
children: step
|
|
730
|
-
}, step))
|
|
731
|
-
})]
|
|
732
|
-
})]
|
|
733
|
-
}),
|
|
734
|
-
role ? /* @__PURE__ */ jsxs("div", {
|
|
735
|
-
className: "bl-scale-card__family",
|
|
736
|
-
"data-role": role,
|
|
737
|
-
"data-drift": hueDrift ? "" : void 0,
|
|
738
|
-
children: [/* @__PURE__ */ jsx("div", {
|
|
739
|
-
className: "bl-scale-card__family-mark",
|
|
740
|
-
"aria-hidden": "true",
|
|
741
|
-
children: "!"
|
|
742
|
-
}), /* @__PURE__ */ jsxs("div", { children: [
|
|
743
|
-
/* @__PURE__ */ jsx("div", {
|
|
744
|
-
className: "bl-scale-card__family-title",
|
|
745
|
-
children: STATUS_COPY[role].title
|
|
746
|
-
}),
|
|
747
|
-
/* @__PURE__ */ jsx("p", { children: STATUS_COPY[role].body }),
|
|
748
|
-
hueDrift ? /* @__PURE__ */ jsx("p", {
|
|
749
|
-
className: "bl-scale-card__family-drift",
|
|
750
|
-
children: STATUS_COPY[role].drift
|
|
751
|
-
}) : null
|
|
752
|
-
] })]
|
|
753
|
-
}) : null,
|
|
754
|
-
/* @__PURE__ */ jsxs("div", {
|
|
755
|
-
className: "bl-scale-card__scale-head",
|
|
756
|
-
children: [/* @__PURE__ */ jsx("span", { children: "Generated scale" }), /* @__PURE__ */ jsxs("span", { children: [SHADE_STEPS.length, " shades"] })]
|
|
757
|
-
}),
|
|
758
|
-
/* @__PURE__ */ jsx("div", {
|
|
759
|
-
className: "bl-scale-card__steps",
|
|
760
|
-
role: "group",
|
|
761
|
-
"aria-label": `${name} scale steps`,
|
|
762
|
-
children: SHADE_STEPS.map((step) => {
|
|
763
|
-
const source = step === state.sourceStep;
|
|
764
|
-
const on = included.has(step);
|
|
765
|
-
return /* @__PURE__ */ jsxs("button", {
|
|
865
|
+
onClick: () => onChange(setColorScaleInclude(state, "all")),
|
|
866
|
+
children: "Include all"
|
|
867
|
+
}), /* @__PURE__ */ jsx("button", {
|
|
766
868
|
type: "button",
|
|
767
|
-
className: "bl-scale-card__step",
|
|
768
|
-
"data-source": source ? "" : void 0,
|
|
769
|
-
"data-excluded": on ? void 0 : "",
|
|
770
|
-
"data-shake": shakeStep === step ? "" : void 0,
|
|
771
869
|
disabled: readOnly,
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
type: "button",
|
|
802
|
-
disabled: readOnly,
|
|
803
|
-
onClick: () => onChange(setColorScaleInclude(state, "all")),
|
|
804
|
-
children: "Include all"
|
|
805
|
-
}), /* @__PURE__ */ jsx("button", {
|
|
806
|
-
type: "button",
|
|
807
|
-
disabled: readOnly,
|
|
808
|
-
onClick: () => onChange(setColorScaleInclude(state, "source")),
|
|
809
|
-
children: "Source only"
|
|
810
|
-
})] })]
|
|
811
|
-
}),
|
|
812
|
-
attentionOpen && warning ? /* @__PURE__ */ jsx(ThemePortal, { children: /* @__PURE__ */ jsx("div", {
|
|
813
|
-
className: "bl-scale-card__modal",
|
|
814
|
-
role: "dialog",
|
|
815
|
-
"aria-modal": "true",
|
|
816
|
-
"aria-labelledby": titleId,
|
|
817
|
-
onClick: (event) => {
|
|
818
|
-
if (event.target === event.currentTarget) setAttentionOpen(false);
|
|
819
|
-
},
|
|
820
|
-
children: /* @__PURE__ */ jsxs("div", {
|
|
821
|
-
className: "bl-scale-card__panel",
|
|
822
|
-
children: [
|
|
823
|
-
/* @__PURE__ */ jsxs("div", {
|
|
824
|
-
className: "bl-scale-card__panel-head",
|
|
825
|
-
children: [/* @__PURE__ */ jsx("h4", {
|
|
826
|
-
id: titleId,
|
|
827
|
-
children: readabilityHeadline(warning)
|
|
828
|
-
}), /* @__PURE__ */ jsx("button", {
|
|
870
|
+
onClick: () => onChange(setColorScaleInclude(state, "source")),
|
|
871
|
+
children: "Source only"
|
|
872
|
+
})] })]
|
|
873
|
+
}),
|
|
874
|
+
attentionOpen && warning ? /* @__PURE__ */ jsx(ThemePortal, { children: /* @__PURE__ */ jsx("div", {
|
|
875
|
+
className: "bl-scale-card__modal",
|
|
876
|
+
role: "dialog",
|
|
877
|
+
"aria-modal": "true",
|
|
878
|
+
"aria-labelledby": titleId,
|
|
879
|
+
onClick: (event) => {
|
|
880
|
+
if (event.target === event.currentTarget) setAttentionOpen(false);
|
|
881
|
+
},
|
|
882
|
+
children: /* @__PURE__ */ jsxs("div", {
|
|
883
|
+
className: "bl-scale-card__panel",
|
|
884
|
+
children: [
|
|
885
|
+
/* @__PURE__ */ jsxs("div", {
|
|
886
|
+
className: "bl-scale-card__panel-head",
|
|
887
|
+
children: [/* @__PURE__ */ jsx("h4", {
|
|
888
|
+
id: titleId,
|
|
889
|
+
children: readabilityHeadline(warning)
|
|
890
|
+
}), /* @__PURE__ */ jsx("button", {
|
|
891
|
+
type: "button",
|
|
892
|
+
onClick: () => setAttentionOpen(false),
|
|
893
|
+
"aria-label": "Close",
|
|
894
|
+
children: "×"
|
|
895
|
+
})]
|
|
896
|
+
}),
|
|
897
|
+
/* @__PURE__ */ jsx(ReadabilityDetail, { item: warning }),
|
|
898
|
+
/* @__PURE__ */ jsx("button", {
|
|
829
899
|
type: "button",
|
|
900
|
+
className: "bl-scale-card__panel-done",
|
|
830
901
|
onClick: () => setAttentionOpen(false),
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
className: "bl-scale-card__panel-done",
|
|
839
|
-
onClick: () => setAttentionOpen(false),
|
|
840
|
-
children: "Keep editing this color"
|
|
841
|
-
})
|
|
842
|
-
]
|
|
843
|
-
})
|
|
844
|
-
}) }) : null
|
|
845
|
-
]
|
|
902
|
+
children: "Keep editing this color"
|
|
903
|
+
})
|
|
904
|
+
]
|
|
905
|
+
})
|
|
906
|
+
}) }) : null
|
|
907
|
+
]
|
|
908
|
+
})
|
|
846
909
|
});
|
|
847
910
|
}
|
|
848
911
|
const COLOR_SCALE_CARD_CSS = `
|
|
@@ -850,18 +913,10 @@ const COLOR_SCALE_CARD_CSS = `
|
|
|
850
913
|
.bl-scale-card__head{display:flex;justify-content:space-between;gap:1rem;align-items:flex-start}
|
|
851
914
|
.bl-scale-card__title-row{position:relative;display:flex;align-items:center;flex-wrap:wrap;gap:.5rem}
|
|
852
915
|
.bl-scale-card__title{margin:0;font-size:1rem}
|
|
853
|
-
.bl-scale-card__badge{font:inherit;font-size:10px;text-transform:uppercase;letter-spacing:.04em;padding:.15rem .45rem;border-radius:999px;border:0;background:#e2e8f0;color:#0f172a}
|
|
854
|
-
.bl-scale-card__badge--attention{background:#fff1f2;color:#be123c;cursor:pointer}
|
|
855
916
|
.bl-scale-card__hint{margin:.35rem 0 0;color:var(--bl-preview-muted,var(--theme-elevation-500,#64748b));font-size:12px}
|
|
856
917
|
.bl-scale-card__delete{border:0;background:none;color:#be123c;font:inherit;font-size:13px;font-weight:600;cursor:pointer}
|
|
857
|
-
.bl-scale-card__row{display:grid;grid-template-columns:1fr 8rem;gap:.75rem;margin-top:1rem}
|
|
858
|
-
.bl-scale-
|
|
859
|
-
.bl-scale-card__hex-wrap{display:flex;border:1px solid var(--bl-preview-border,var(--theme-elevation-150,#e2e8f0));border-radius:8px;background:var(--bl-preview-card,var(--theme-input-bg,#fff))}
|
|
860
|
-
.bl-scale-card__hex-wrap input[type=color]{width:2.75rem;height:2.25rem;padding:0;border:0;border-right:1px solid var(--bl-preview-border,var(--theme-elevation-150,#e2e8f0));border-radius:8px 0 0 8px;background:transparent;cursor:pointer;color-scheme:light;appearance:none;-webkit-appearance:none}
|
|
861
|
-
.bl-scale-card__hex-wrap input[type=color]::-webkit-color-swatch-wrapper{padding:0}
|
|
862
|
-
.bl-scale-card__hex-wrap input[type=color]::-webkit-color-swatch{border:0;border-radius:0;width:100%;height:100%}
|
|
863
|
-
.bl-scale-card__hex-wrap input[type=text]{flex:1;min-width:0;border:0;padding:.4rem .7rem;font-family:var(--font-mono,ui-monospace,monospace);font-size:13px;background:transparent;color:inherit;border-radius:0 8px 8px 0}
|
|
864
|
-
.bl-scale-card__field select{min-height:2.25rem;border:1px solid var(--bl-preview-border,var(--theme-elevation-150,#e2e8f0));border-radius:8px;padding:.35rem .5rem;background:var(--bl-preview-card,var(--theme-input-bg,#fff));color:inherit}
|
|
918
|
+
.bl-scale-card__row{display:grid;grid-template-columns:1fr 8rem;gap:.75rem;margin-top:1rem;align-items:start}
|
|
919
|
+
.bl-scale-card__row .bl-nav-kit__field{margin-bottom:0}
|
|
865
920
|
.bl-scale-card__family{display:flex;gap:.75rem;align-items:flex-start;margin-top:1rem;padding:.75rem .85rem;border-radius:8px}
|
|
866
921
|
.bl-scale-card__family[data-role=success]{border:1px solid #a7f3d0;background:#ecfdf5;color:#065f46}
|
|
867
922
|
.bl-scale-card__family[data-role=destructive]{border:1px solid #fecdd3;background:#fff1f2;color:#9f1239}
|
|
@@ -1122,63 +1177,52 @@ const LibraryField = ({ field, path, readOnly }) => {
|
|
|
1122
1177
|
})]
|
|
1123
1178
|
}),
|
|
1124
1179
|
adding ? /* @__PURE__ */ jsx(ThemePortal, { children: /* @__PURE__ */ jsx("div", {
|
|
1125
|
-
className: "bl-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1180
|
+
className: "bl-theme-dialog",
|
|
1181
|
+
children: /* @__PURE__ */ jsx(KitProvider, { children: /* @__PURE__ */ jsxs(Dialog, {
|
|
1182
|
+
open: true,
|
|
1183
|
+
title: "New color",
|
|
1184
|
+
onCancel: () => {
|
|
1185
|
+
setAdding(false);
|
|
1186
|
+
setName("");
|
|
1187
|
+
setHex("");
|
|
1188
|
+
setSourceStep(500);
|
|
1189
|
+
},
|
|
1190
|
+
confirmLabel: "Create color scale",
|
|
1191
|
+
onConfirm: add,
|
|
1192
|
+
confirmDisabled: !slugify(name) || !isThemeHex(hex),
|
|
1134
1193
|
children: [
|
|
1135
|
-
/* @__PURE__ */
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
id: "bl-library-add-title",
|
|
1139
|
-
children: "New color"
|
|
1140
|
-
}), /* @__PURE__ */ jsx("p", { children: "Give it a useful name, enter your brand hex, then say which scale step that hex is." })] }), /* @__PURE__ */ jsx("button", {
|
|
1141
|
-
type: "button",
|
|
1142
|
-
onClick: () => setAdding(false),
|
|
1143
|
-
"aria-label": "Close",
|
|
1144
|
-
children: "×"
|
|
1145
|
-
})]
|
|
1146
|
-
}),
|
|
1147
|
-
/* @__PURE__ */ jsxs("label", { children: ["Name", /* @__PURE__ */ jsx("input", {
|
|
1194
|
+
/* @__PURE__ */ jsx("p", { children: "Give it a useful name, enter your brand hex, then say which scale step that hex is." }),
|
|
1195
|
+
/* @__PURE__ */ jsxs(Field, { children: [/* @__PURE__ */ jsx(Label, { children: "Name" }), /* @__PURE__ */ jsx(Input, {
|
|
1196
|
+
"aria-label": "Name",
|
|
1148
1197
|
value: name,
|
|
1149
1198
|
placeholder: "e.g. Coral",
|
|
1150
1199
|
onChange: (event) => setName(event.target.value)
|
|
1151
1200
|
})] }),
|
|
1152
|
-
/* @__PURE__ */ jsxs(
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
}), /* @__PURE__ */ jsx("button", {
|
|
1174
|
-
type: "button",
|
|
1175
|
-
disabled: !slugify(name) || !isThemeHex(hex),
|
|
1176
|
-
onClick: add,
|
|
1177
|
-
children: "Create color scale"
|
|
1201
|
+
/* @__PURE__ */ jsxs(Field, {
|
|
1202
|
+
as: "div",
|
|
1203
|
+
children: [/* @__PURE__ */ jsx(Label, { children: "Brand hex" }), /* @__PURE__ */ jsx(BrandHexField, {
|
|
1204
|
+
name: "Brand",
|
|
1205
|
+
value: hex,
|
|
1206
|
+
onChange: setHex,
|
|
1207
|
+
picker: "inline"
|
|
1208
|
+
})]
|
|
1209
|
+
}),
|
|
1210
|
+
/* @__PURE__ */ jsxs(Field, {
|
|
1211
|
+
as: "div",
|
|
1212
|
+
children: [/* @__PURE__ */ jsx(Label, { children: "This color is" }), /* @__PURE__ */ jsxs(Select, {
|
|
1213
|
+
value: String(sourceStep),
|
|
1214
|
+
onValueChange: (value) => setSourceStep(Number(value)),
|
|
1215
|
+
children: [/* @__PURE__ */ jsx(SelectTrigger, {
|
|
1216
|
+
"aria-label": "This color is",
|
|
1217
|
+
children: /* @__PURE__ */ jsx(SelectValue, {})
|
|
1218
|
+
}), /* @__PURE__ */ jsx(SelectContent, { children: SHADE_STEPS.map((step) => /* @__PURE__ */ jsx(SelectItem, {
|
|
1219
|
+
value: String(step),
|
|
1220
|
+
children: step
|
|
1221
|
+
}, step)) })]
|
|
1178
1222
|
})]
|
|
1179
1223
|
})
|
|
1180
1224
|
]
|
|
1181
|
-
})
|
|
1225
|
+
}) })
|
|
1182
1226
|
}) }) : null,
|
|
1183
1227
|
replacing ? /* @__PURE__ */ jsx(ThemePortal, { children: /* @__PURE__ */ jsx("div", {
|
|
1184
1228
|
className: "bl-library__modal",
|
|
@@ -1278,26 +1322,24 @@ const CSS$3 = `
|
|
|
1278
1322
|
.bl-library__panel-head button{border:0;background:none;font:inherit;font-size:1.25rem;line-height:1;color:#94a3b8;cursor:pointer}
|
|
1279
1323
|
.bl-library__panel h2{margin:0}
|
|
1280
1324
|
.bl-library__panel p{margin:.5rem 0 0;color:#475569;font-size:14px}
|
|
1281
|
-
.bl-library__panel label{display:flex;flex-direction:column;gap:.4rem;margin-top:1rem;font-size:13px;font-weight:600}
|
|
1325
|
+
.bl-library__panel label,.bl-library__field{display:flex;flex-direction:column;gap:.4rem;margin-top:1rem;font-size:13px;font-weight:600}
|
|
1282
1326
|
.bl-library__panel input,.bl-library__panel select{min-height:2.25rem;border:1px solid #cbd5e1;border-radius:8px;padding:.35rem .5rem;background:#fff;color:#0f172a}
|
|
1283
1327
|
.bl-library__usages{margin:1rem 0 0;padding-left:1.1rem;color:#475569;font-size:13px;font-weight:400}
|
|
1284
1328
|
.bl-library__usages li{margin:.25rem 0}
|
|
1285
1329
|
.bl-library__actions{display:flex;flex-wrap:wrap;justify-content:flex-end;gap:.5rem;margin-top:1rem}
|
|
1286
1330
|
.bl-library__actions button:last-child{border:0;background:#0f172a;color:#fff;font-weight:600}
|
|
1287
1331
|
.bl-library__actions button:last-child:disabled{opacity:.4;cursor:not-allowed}
|
|
1332
|
+
.bl-theme-dialog .bl-nav-kit__modal{z-index:10000}
|
|
1288
1333
|
`;
|
|
1289
1334
|
//#endregion
|
|
1290
1335
|
//#region src/admin/typography-pairing.tsx
|
|
1291
1336
|
function FontRoleCard({ title, hint, required, family, preview, children }) {
|
|
1292
|
-
return /* @__PURE__ */ jsxs("article", {
|
|
1337
|
+
return /* @__PURE__ */ jsx(KitProvider, { children: /* @__PURE__ */ jsxs("article", {
|
|
1293
1338
|
className: "bl-font-role",
|
|
1294
1339
|
children: [
|
|
1295
1340
|
/* @__PURE__ */ jsxs("header", {
|
|
1296
1341
|
className: "bl-font-role__head",
|
|
1297
|
-
children: [/* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("h3", { children: title }), /* @__PURE__ */ jsx("p", { children: hint })] }), required ? /* @__PURE__ */ jsx("
|
|
1298
|
-
className: "bl-font-role__badge",
|
|
1299
|
-
children: "Required"
|
|
1300
|
-
}) : null]
|
|
1342
|
+
children: [/* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("h3", { children: title }), /* @__PURE__ */ jsx("p", { children: hint })] }), required ? /* @__PURE__ */ jsx(Badge, { children: "Required" }) : null]
|
|
1301
1343
|
}),
|
|
1302
1344
|
children,
|
|
1303
1345
|
/* @__PURE__ */ jsxs("div", {
|
|
@@ -1313,7 +1355,7 @@ function FontRoleCard({ title, hint, required, family, preview, children }) {
|
|
|
1313
1355
|
})]
|
|
1314
1356
|
})
|
|
1315
1357
|
]
|
|
1316
|
-
});
|
|
1358
|
+
}) });
|
|
1317
1359
|
}
|
|
1318
1360
|
function TypographyPairing({ headingFamily, bodyFamily }) {
|
|
1319
1361
|
return /* @__PURE__ */ jsxs("section", {
|
|
@@ -1358,7 +1400,6 @@ const TYPOGRAPHY_PAIRING_CSS = `
|
|
|
1358
1400
|
.bl-font-role__head{display:flex;justify-content:space-between;align-items:flex-start;gap:1rem}
|
|
1359
1401
|
.bl-font-role__head h3{margin:0;font-size:1rem}
|
|
1360
1402
|
.bl-font-role__head p{margin:.3rem 0 0;font-size:12px;color:var(--bl-preview-muted,var(--theme-elevation-500,#64748b))}
|
|
1361
|
-
.bl-font-role__badge{font-size:10px;text-transform:uppercase;letter-spacing:.04em;padding:.15rem .45rem;border-radius:999px;background:#e2e8f0;color:#0f172a}
|
|
1362
1403
|
.bl-font-role__preview{margin-top:1rem;padding:.85rem .9rem;border:1px solid var(--bl-preview-border,var(--theme-elevation-150,#e2e8f0));border-radius:12px;background:var(--bl-preview-bg,var(--theme-elevation-50,#f8fafc))}
|
|
1363
1404
|
.bl-font-role__preview > span{display:block;margin-bottom:.4rem;font-size:11px;color:var(--bl-preview-muted,var(--theme-elevation-500,#64748b))}
|
|
1364
1405
|
.bl-font-role__heading{margin:0;font-size:1.5rem;line-height:1.2;font-weight:600}
|
|
@@ -1889,7 +1930,7 @@ const SWATCHES = [
|
|
|
1889
1930
|
];
|
|
1890
1931
|
function GreyScaleChoices({ value, onChange, readOnly }) {
|
|
1891
1932
|
const canvas = usePreviewCanvas();
|
|
1892
|
-
return /* @__PURE__ */ jsxs("section", {
|
|
1933
|
+
return /* @__PURE__ */ jsx(KitProvider, { children: /* @__PURE__ */ jsxs("section", {
|
|
1893
1934
|
className: `bl-grey ${canvas.className}`,
|
|
1894
1935
|
"data-preview": canvas.mode,
|
|
1895
1936
|
style: canvas.style,
|
|
@@ -1900,10 +1941,7 @@ function GreyScaleChoices({ value, onChange, readOnly }) {
|
|
|
1900
1941
|
}),
|
|
1901
1942
|
/* @__PURE__ */ jsxs("header", {
|
|
1902
1943
|
className: "bl-grey__head",
|
|
1903
|
-
children: [/* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("h2", { children: "Gray family" }), /* @__PURE__ */ jsx("p", { children: "Choose the neutral family used for page backgrounds, cards, borders, inputs, and muted text. Readability for these system neutrals is handled automatically." })] }), /* @__PURE__ */ jsx("
|
|
1904
|
-
className: "bl-grey__badge",
|
|
1905
|
-
children: "Required"
|
|
1906
|
-
})]
|
|
1944
|
+
children: [/* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("h2", { children: "Gray family" }), /* @__PURE__ */ jsx("p", { children: "Choose the neutral family used for page backgrounds, cards, borders, inputs, and muted text. Readability for these system neutrals is handled automatically." })] }), /* @__PURE__ */ jsx(Badge, { children: "Required" })]
|
|
1907
1945
|
}),
|
|
1908
1946
|
/* @__PURE__ */ jsx("div", {
|
|
1909
1947
|
className: "bl-grey__choices",
|
|
@@ -1937,7 +1975,7 @@ function GreyScaleChoices({ value, onChange, readOnly }) {
|
|
|
1937
1975
|
})
|
|
1938
1976
|
})
|
|
1939
1977
|
]
|
|
1940
|
-
});
|
|
1978
|
+
}) });
|
|
1941
1979
|
}
|
|
1942
1980
|
/**
|
|
1943
1981
|
* Visual picker over the five grey-scale presets. Replaces the stock select
|
|
@@ -1966,7 +2004,6 @@ const GREY_SCALE_FIELD_CSS = `
|
|
|
1966
2004
|
.bl-grey__head{display:flex;justify-content:space-between;align-items:flex-start;gap:1rem;margin:0;padding:1.1rem 1.15rem .85rem;border:1px solid var(--bl-preview-border,var(--theme-elevation-150,#e2e8f0));border-bottom:0;border-radius:12px 12px 0 0;background:var(--bl-preview-card,var(--theme-elevation-0,#fff));color:var(--bl-preview-text,inherit)}
|
|
1967
2005
|
.bl-grey__head h2{margin:0;font-size:1.1rem}
|
|
1968
2006
|
.bl-grey__head p{margin:.35rem 0 0;max-width:40rem;font-size:13px;color:var(--bl-preview-muted,var(--theme-elevation-500,#64748b))}
|
|
1969
|
-
.bl-grey__badge{font:inherit;font-size:10px;text-transform:uppercase;letter-spacing:.04em;padding:.15rem .45rem;border-radius:999px;background:#e2e8f0;color:#0f172a}
|
|
1970
2007
|
.bl-grey__choices{display:grid;grid-template-columns:repeat(5,minmax(0,1fr));gap:.6rem;padding:0 1.15rem 1.15rem;border:1px solid var(--bl-preview-border,var(--theme-elevation-150,#e2e8f0));border-top:0;border-radius:0 0 12px 12px;background:var(--bl-preview-card,var(--theme-elevation-0,#fff));color:var(--bl-preview-text,inherit)}
|
|
1971
2008
|
.bl-grey__choice{display:flex;flex-direction:column;gap:.45rem;padding:.75rem;border:1px solid var(--bl-preview-border,var(--theme-elevation-150,#e2e8f0));border-radius:12px;background:var(--bl-preview-bg,var(--theme-elevation-0,#fff));color:inherit;cursor:pointer}
|
|
1972
2009
|
.bl-grey__choice[data-selected]{box-shadow:inset 0 0 0 2px var(--bl-preview-text,#0f172a);border-color:var(--bl-preview-text,#0f172a)}
|
|
@@ -2325,9 +2362,8 @@ function ThemePublishActions({ child }) {
|
|
|
2325
2362
|
/* @__PURE__ */ jsx("style", {
|
|
2326
2363
|
href: "bl-publish-child",
|
|
2327
2364
|
precedence: "default",
|
|
2328
|
-
children:
|
|
2365
|
+
children: `.bl-publish-child{display:flex;align-items:center;justify-content:flex-end;gap:.5rem}.bl-publish-child__button{min-height:2.25rem;padding:.4rem 1rem;border:0;border-radius:8px;background:var(--theme-text,#0f172a);color:var(--theme-bg,#fff);font:inherit;font-weight:600;cursor:pointer}`
|
|
2329
2366
|
}),
|
|
2330
|
-
child !== "identity" ? /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsx(ThemePreviewToggle, {}) }) : null,
|
|
2331
2367
|
/* @__PURE__ */ jsxs("button", {
|
|
2332
2368
|
type: "button",
|
|
2333
2369
|
className: "bl-publish-child__button",
|
|
@@ -2374,16 +2410,12 @@ function readActiveThemeTab(root = typeof document === "undefined" ? null : docu
|
|
|
2374
2410
|
//#endregion
|
|
2375
2411
|
//#region src/admin/save-button.tsx
|
|
2376
2412
|
/**
|
|
2377
|
-
* Light/Dark
|
|
2378
|
-
*
|
|
2379
|
-
* Save
|
|
2413
|
+
* Theme used to put a Light/Dark pair here. Admin chrome now follows
|
|
2414
|
+
* Payload's own theme from the header sun/moon, so this slot is empty
|
|
2415
|
+
* and Save stays in the Save slot.
|
|
2380
2416
|
*/
|
|
2381
2417
|
function ThemeDocumentControls() {
|
|
2382
|
-
return
|
|
2383
|
-
href: "bl-doc-controls",
|
|
2384
|
-
precedence: "default",
|
|
2385
|
-
children: THEME_PREVIEW_TOGGLE_CSS
|
|
2386
|
-
}), /* @__PURE__ */ jsx(ThemePreviewToggle, {})] });
|
|
2418
|
+
return null;
|
|
2387
2419
|
}
|
|
2388
2420
|
/**
|
|
2389
2421
|
* Import-map Save slot used by the older single-Global Theme. Theme pages
|
|
@@ -2973,6 +3005,90 @@ const RoleSlugField = ({ field, path, readOnly }) => {
|
|
|
2973
3005
|
});
|
|
2974
3006
|
};
|
|
2975
3007
|
//#endregion
|
|
3008
|
+
//#region src/fields/slug.ts
|
|
3009
|
+
const SLUG_UNLOCK_WARNING = "This page is live. Changing the address will send visitors from the old URL to the new one.";
|
|
3010
|
+
function slugifySegment(segment) {
|
|
3011
|
+
return segment.normalize("NFKD").replace(/\p{M}/gu, "").toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
|
|
3012
|
+
}
|
|
3013
|
+
/**
|
|
3014
|
+
* A stored slug from whatever was typed: NFKD, hyphenated, slash segments
|
|
3015
|
+
* kept, so `Café / About Us` becomes `cafe/about-us`.
|
|
3016
|
+
*/
|
|
3017
|
+
function normalizeSlug(value) {
|
|
3018
|
+
return value.split("/").map(slugifySegment).filter(Boolean).join("/");
|
|
3019
|
+
}
|
|
3020
|
+
//#endregion
|
|
3021
|
+
//#region src/admin/slug-field.tsx
|
|
3022
|
+
/**
|
|
3023
|
+
* Slug follows the title until first publish. After that it is read-only
|
|
3024
|
+
* until Unlock, which warns that the old address will redirect.
|
|
3025
|
+
*/
|
|
3026
|
+
const SlugField = ({ field, path, readOnly }) => {
|
|
3027
|
+
const { value, setValue, showError, errorMessage } = useField({ path });
|
|
3028
|
+
const { value: unlock, setValue: setUnlock } = useField({ path: "slugUnlock" });
|
|
3029
|
+
const title = useFormFields(([fields]) => fields.title?.value);
|
|
3030
|
+
const slugLocked = Boolean(useFormFields(([fields]) => fields.slugLocked?.value));
|
|
3031
|
+
const locked = Boolean(readOnly) || slugLocked && !unlock;
|
|
3032
|
+
const required = Boolean(field.required);
|
|
3033
|
+
const id = `field-${path.replace(/\./g, "__")}`;
|
|
3034
|
+
useEffect(() => {
|
|
3035
|
+
if (slugLocked || typeof title !== "string") return;
|
|
3036
|
+
const next = normalizeSlug(title);
|
|
3037
|
+
if (next !== (value ?? "")) setValue(next);
|
|
3038
|
+
}, [
|
|
3039
|
+
setValue,
|
|
3040
|
+
slugLocked,
|
|
3041
|
+
title,
|
|
3042
|
+
value
|
|
3043
|
+
]);
|
|
3044
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
3045
|
+
className: [
|
|
3046
|
+
fieldBaseClass,
|
|
3047
|
+
"text",
|
|
3048
|
+
locked && "read-only"
|
|
3049
|
+
].filter(Boolean).join(" "),
|
|
3050
|
+
children: [
|
|
3051
|
+
/* @__PURE__ */ jsx(FieldLabel, {
|
|
3052
|
+
htmlFor: id,
|
|
3053
|
+
label: field.label,
|
|
3054
|
+
required
|
|
3055
|
+
}),
|
|
3056
|
+
/* @__PURE__ */ jsxs("div", {
|
|
3057
|
+
className: `${fieldBaseClass}__wrap`,
|
|
3058
|
+
children: [
|
|
3059
|
+
/* @__PURE__ */ jsx(FieldError, {
|
|
3060
|
+
message: errorMessage,
|
|
3061
|
+
path,
|
|
3062
|
+
showError
|
|
3063
|
+
}),
|
|
3064
|
+
/* @__PURE__ */ jsx("input", {
|
|
3065
|
+
id,
|
|
3066
|
+
type: "text",
|
|
3067
|
+
autoComplete: "off",
|
|
3068
|
+
spellCheck: false,
|
|
3069
|
+
readOnly: locked,
|
|
3070
|
+
disabled: locked,
|
|
3071
|
+
value: value ?? "",
|
|
3072
|
+
onChange: (event) => {
|
|
3073
|
+
if (!locked) setValue(event.target.value);
|
|
3074
|
+
}
|
|
3075
|
+
}),
|
|
3076
|
+
slugLocked && !unlock ? /* @__PURE__ */ jsx(Button$1, {
|
|
3077
|
+
variant: "outline",
|
|
3078
|
+
onClick: () => setUnlock(true),
|
|
3079
|
+
children: "Unlock"
|
|
3080
|
+
}) : null
|
|
3081
|
+
]
|
|
3082
|
+
}),
|
|
3083
|
+
unlock ? /* @__PURE__ */ jsx("p", { children: SLUG_UNLOCK_WARNING }) : null,
|
|
3084
|
+
/* @__PURE__ */ jsx(FieldDescription, {
|
|
3085
|
+
description: field.admin?.description,
|
|
3086
|
+
path
|
|
3087
|
+
})
|
|
3088
|
+
]
|
|
3089
|
+
});
|
|
3090
|
+
};
|
|
3091
|
+
//#endregion
|
|
2976
3092
|
//#region src/admin/role-name-field.tsx
|
|
2977
3093
|
/**
|
|
2978
3094
|
* Role name. Letters and spaces only, so the hidden slug stays
|
|
@@ -3316,6 +3432,44 @@ const FeaturesMatrixField = (props) => {
|
|
|
3316
3432
|
});
|
|
3317
3433
|
};
|
|
3318
3434
|
//#endregion
|
|
3435
|
+
//#region src/admin/theme-kit-accent.tsx
|
|
3436
|
+
function primaryHex(doc) {
|
|
3437
|
+
const hex = doc?.colors?.brand?.primary?.hex;
|
|
3438
|
+
return typeof hex === "string" && isThemeHex(hex) ? hex : void 0;
|
|
3439
|
+
}
|
|
3440
|
+
/**
|
|
3441
|
+
* Site Theme primary → `--bl-kit-accent`. Saved value for the whole
|
|
3442
|
+
* admin; the Primary color card also writes the live hex so pickers
|
|
3443
|
+
* and kit chrome update as the field is edited.
|
|
3444
|
+
*/
|
|
3445
|
+
function ThemeKitAccent({ children }) {
|
|
3446
|
+
const { config } = useConfig();
|
|
3447
|
+
const [accent, setAccent] = useState();
|
|
3448
|
+
useEffect(() => {
|
|
3449
|
+
const url = `${config.serverURL}${config.routes.api}/globals/theme?depth=0`;
|
|
3450
|
+
let cancelled = false;
|
|
3451
|
+
function load() {
|
|
3452
|
+
fetch(url, { credentials: "include" }).then((response) => response.ok ? response.json() : null).then((doc) => {
|
|
3453
|
+
const hex = primaryHex(doc);
|
|
3454
|
+
if (!cancelled && hex) setAccent(hex);
|
|
3455
|
+
}).catch(() => void 0);
|
|
3456
|
+
}
|
|
3457
|
+
load();
|
|
3458
|
+
const onVis = () => {
|
|
3459
|
+
if (document.visibilityState === "visible") load();
|
|
3460
|
+
};
|
|
3461
|
+
document.addEventListener("visibilitychange", onVis);
|
|
3462
|
+
return () => {
|
|
3463
|
+
cancelled = true;
|
|
3464
|
+
document.removeEventListener("visibilitychange", onVis);
|
|
3465
|
+
};
|
|
3466
|
+
}, [config.serverURL, config.routes.api]);
|
|
3467
|
+
return /* @__PURE__ */ jsx(KitProvider, {
|
|
3468
|
+
accent,
|
|
3469
|
+
children
|
|
3470
|
+
});
|
|
3471
|
+
}
|
|
3472
|
+
//#endregion
|
|
3319
3473
|
//#region src/admin/document-title-actions.tsx
|
|
3320
3474
|
/**
|
|
3321
3475
|
* Shared document header: title on the left, primary actions on the
|
|
@@ -3357,7 +3511,7 @@ function DocumentTitleActions({ children }) {
|
|
|
3357
3511
|
});
|
|
3358
3512
|
return () => observer.disconnect();
|
|
3359
3513
|
}, []);
|
|
3360
|
-
return /* @__PURE__ */ jsxs(
|
|
3514
|
+
return /* @__PURE__ */ jsxs(ThemeKitAccent, { children: [/* @__PURE__ */ jsx("style", {
|
|
3361
3515
|
href: "bl-doc-title-actions",
|
|
3362
3516
|
precedence: "default",
|
|
3363
3517
|
children: TITLE_ACTIONS_CSS
|
|
@@ -3497,6 +3651,8 @@ function resolveAdminNav({ config, doc, visibleEntities }) {
|
|
|
3497
3651
|
//#endregion
|
|
3498
3652
|
//#region src/admin/admin-nav.tsx
|
|
3499
3653
|
const BASE = "nav";
|
|
3654
|
+
/** Survives AdminNav remounting on every admin route so the first-seen walk does not flash. */
|
|
3655
|
+
let cachedDoc;
|
|
3500
3656
|
function isAbortError(error) {
|
|
3501
3657
|
return error instanceof DOMException ? error.name === "AbortError" : error instanceof Error && error.name === "AbortError";
|
|
3502
3658
|
}
|
|
@@ -3529,7 +3685,7 @@ function AdminNavShell({ children }) {
|
|
|
3529
3685
|
*/
|
|
3530
3686
|
function AdminNav({ visibleEntities }) {
|
|
3531
3687
|
const { config } = useConfig();
|
|
3532
|
-
const [doc, setDoc] = useState(null);
|
|
3688
|
+
const [doc, setDoc] = useState(() => cachedDoc ?? null);
|
|
3533
3689
|
const adminRoute = config.routes.admin ?? "/admin";
|
|
3534
3690
|
const apiRoute = config.routes.api ?? "/api";
|
|
3535
3691
|
useEffect(() => {
|
|
@@ -3540,9 +3696,12 @@ function AdminNav({ visibleEntities }) {
|
|
|
3540
3696
|
signal: controller.signal
|
|
3541
3697
|
}).then((response) => response.ok ? response.json() : null).then((payload) => {
|
|
3542
3698
|
if (controller.signal.aborted) return;
|
|
3699
|
+
cachedDoc = payload;
|
|
3543
3700
|
setDoc(payload);
|
|
3544
3701
|
}).catch((error) => {
|
|
3545
3702
|
if (isAbortError(error) || controller.signal.aborted) return;
|
|
3703
|
+
if (cachedDoc !== void 0) return;
|
|
3704
|
+
cachedDoc = null;
|
|
3546
3705
|
setDoc(null);
|
|
3547
3706
|
});
|
|
3548
3707
|
return () => controller.abort();
|
|
@@ -3669,6 +3828,6 @@ const AdminNavEntityField = ({ field, path, permissions, readOnly, schemaPath })
|
|
|
3669
3828
|
});
|
|
3670
3829
|
};
|
|
3671
3830
|
//#endregion
|
|
3672
|
-
export { AdminNav, AdminNavEntityField, AdminNavItemRowLabel, AdminNavRowLabel, AppearanceField, ColorField, ColorScaleField, ContrastReport, DocumentCreateNew, DocumentTitleActions, FeaturesMatrixField, FontField, GreyScaleField, HiddenSaveButton, IdentityFallback, LibraryField, LookField, PairingField, PublishChild, RoleNameField, RoleSlugField, RolesField, RolesGrantsField, RolesMatrixField, RolesRowLabel, SectionHeading, ThemeDocumentControls, ThemeSaveButton };
|
|
3831
|
+
export { AdminNav, AdminNavEntityField, AdminNavItemRowLabel, AdminNavRowLabel, AppearanceField, ColorField, ColorScaleField, ContrastReport, DocumentCreateNew, DocumentTitleActions, FeaturesMatrixField, FontField, GreyScaleField, HiddenSaveButton, IdentityFallback, LibraryField, LookField, PairingField, PublishChild, RoleNameField, RoleSlugField, RolesField, RolesGrantsField, RolesMatrixField, RolesRowLabel, SectionHeading, SlugField, ThemeDocumentControls, ThemeSaveButton, setThemePreviewMode };
|
|
3673
3832
|
|
|
3674
3833
|
//# sourceMappingURL=admin.mjs.map
|