colorsbymax 0.3.3 → 0.4.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/CHANGELOG.md +110 -94
- package/README.md +482 -476
- package/dist/{ThemeSwitcher-Bcf9w2Ce.js → ThemeSwitcher-DB_-2YB8.js} +1251 -264
- package/dist/auto.js +1 -1
- package/dist/index.js +1 -1
- package/package.json +5 -3
- package/types/index.d.ts +337 -321
|
@@ -934,7 +934,7 @@ var PRESETS = RAW_PRESETS.map((t) => ({
|
|
|
934
934
|
var DARK_SUFFIX = "~dark";
|
|
935
935
|
/** True when a theme's page background is dark. */
|
|
936
936
|
var isDarkTheme = (tokens) => luminance(tokens.background) < .2;
|
|
937
|
-
var hslOf$
|
|
937
|
+
var hslOf$4 = (hex) => rgbToHsl(hexToRgb(hex));
|
|
938
938
|
var hsl$1 = (h, s, l) => rgbToHex(hslToRgb([
|
|
939
939
|
h,
|
|
940
940
|
Math.min(1, Math.max(0, s)),
|
|
@@ -942,12 +942,12 @@ var hsl$1 = (h, s, l) => rgbToHex(hslToRgb([
|
|
|
942
942
|
]));
|
|
943
943
|
/** Same hue, saturation capped at `maxS`, lightness set to `l`. */
|
|
944
944
|
var tone = (hex, l, maxS = 1) => {
|
|
945
|
-
const [h, s] = hslOf$
|
|
945
|
+
const [h, s] = hslOf$4(hex);
|
|
946
946
|
return hsl$1(h, Math.min(s, maxS), l);
|
|
947
947
|
};
|
|
948
948
|
/** Keeps hue and saturation, lifting lightness into [min, max] so it reads on a dark page. */
|
|
949
949
|
var lift = (hex, min, max = .78) => {
|
|
950
|
-
const [h, s, l] = hslOf$
|
|
950
|
+
const [h, s, l] = hslOf$4(hex);
|
|
951
951
|
return hsl$1(h, s, Math.min(max, Math.max(min, l)));
|
|
952
952
|
};
|
|
953
953
|
/**
|
|
@@ -955,7 +955,7 @@ var lift = (hex, min, max = .78) => {
|
|
|
955
955
|
* Lightness alone doesn't guarantee that: a vivid blue or violet at 60% lightness still reads dark.
|
|
956
956
|
*/
|
|
957
957
|
var readOn = (hex, bg, ratio) => {
|
|
958
|
-
const [h, s, l] = hslOf$
|
|
958
|
+
const [h, s, l] = hslOf$4(hex);
|
|
959
959
|
let out = hex;
|
|
960
960
|
for (let x = l; contrastRatio(out, bg) < ratio && x < .96; x += .01) out = hsl$1(h, s, x);
|
|
961
961
|
return out;
|
|
@@ -1033,6 +1033,139 @@ function toDark(theme) {
|
|
|
1033
1033
|
* @param {'light' | 'dark'} mode
|
|
1034
1034
|
*/
|
|
1035
1035
|
var inMode = (theme, mode) => mode === "dark" && !theme.custom ? toDark(theme) : theme;
|
|
1036
|
+
var QUIET = [
|
|
1037
|
+
"background",
|
|
1038
|
+
"surface",
|
|
1039
|
+
"secondary",
|
|
1040
|
+
"accent",
|
|
1041
|
+
"border",
|
|
1042
|
+
"app-background",
|
|
1043
|
+
"app-input",
|
|
1044
|
+
"app-border"
|
|
1045
|
+
];
|
|
1046
|
+
var ON_QUIET = {
|
|
1047
|
+
secondary: "on-secondary",
|
|
1048
|
+
accent: "on-accent"
|
|
1049
|
+
};
|
|
1050
|
+
/**
|
|
1051
|
+
* The Subtle style on a site painted with the colour tokens: the page's backgrounds, cards,
|
|
1052
|
+
* borders and tints go nearly neutral (same lightness, a hint of the hue), so the theme's colour
|
|
1053
|
+
* stays on what matters: buttons, links, headings, highlights and charts.
|
|
1054
|
+
*/
|
|
1055
|
+
function subtleTokens(t) {
|
|
1056
|
+
const out = { ...t };
|
|
1057
|
+
for (const key of QUIET) {
|
|
1058
|
+
if (!t[key]) continue;
|
|
1059
|
+
const [h, s, l] = hslOf$4(t[key]);
|
|
1060
|
+
out[key] = hsl$1(h, s * .18, l);
|
|
1061
|
+
}
|
|
1062
|
+
for (const [bg, fg] of Object.entries(ON_QUIET)) {
|
|
1063
|
+
if (!out[bg] || !out[fg] || contrastRatio(out[fg], out[bg]) >= 4.5) continue;
|
|
1064
|
+
out[fg] = contrastRatio(t.ink, out[bg]) >= 4.5 ? t.ink : luminance(out[bg]) > .4 ? "#000000" : "#ffffff";
|
|
1065
|
+
}
|
|
1066
|
+
return out;
|
|
1067
|
+
}
|
|
1068
|
+
/** The ten, in the order a card shows them. */
|
|
1069
|
+
var SWATCH_KEYS = [
|
|
1070
|
+
"primary",
|
|
1071
|
+
"primary-alt",
|
|
1072
|
+
"primary-dark",
|
|
1073
|
+
"secondary",
|
|
1074
|
+
"background",
|
|
1075
|
+
"ink",
|
|
1076
|
+
"data-1",
|
|
1077
|
+
"data-2",
|
|
1078
|
+
"data-3",
|
|
1079
|
+
"data-4"
|
|
1080
|
+
];
|
|
1081
|
+
var CHART = [
|
|
1082
|
+
"data-1",
|
|
1083
|
+
"data-2",
|
|
1084
|
+
"data-3",
|
|
1085
|
+
"data-4"
|
|
1086
|
+
];
|
|
1087
|
+
var HIDDEN_CHART = [
|
|
1088
|
+
"data-5",
|
|
1089
|
+
"data-6",
|
|
1090
|
+
"data-7",
|
|
1091
|
+
"data-8"
|
|
1092
|
+
];
|
|
1093
|
+
var hslOf$3 = (hex) => rgbToHsl(hexToRgb(hex));
|
|
1094
|
+
var hueGap$1 = (a, b) => {
|
|
1095
|
+
const d = Math.abs(a - b);
|
|
1096
|
+
return Math.min(d, 360 - d);
|
|
1097
|
+
};
|
|
1098
|
+
var clampColours = (n) => Math.min(10, Math.max(5, Math.round(Number(n) || 10)));
|
|
1099
|
+
/** How far a colour's hue is from the theme's brand colours (0 = one of them); greys fit anything. */
|
|
1100
|
+
function misfit(tokens, key) {
|
|
1101
|
+
const [h, s] = hslOf$3(tokens[key]);
|
|
1102
|
+
if (s < .15) return 0;
|
|
1103
|
+
const brand = ["primary", "primary-alt"].map((k) => hslOf$3(tokens[k])).filter(([, bs]) => bs >= .15);
|
|
1104
|
+
if (!brand.length) return 90;
|
|
1105
|
+
return Math.min(...brand.map(([bh]) => hueGap$1(h, bh)));
|
|
1106
|
+
}
|
|
1107
|
+
/** The swatch keys a theme keeps at `count` colours, in card order. */
|
|
1108
|
+
function paletteKeys(tokens, count = 10) {
|
|
1109
|
+
const n = clampColours(count);
|
|
1110
|
+
if (n >= 10) return SWATCH_KEYS;
|
|
1111
|
+
const extras = ["secondary", ...[...CHART].sort((a, b) => misfit(tokens, a) - misfit(tokens, b))];
|
|
1112
|
+
const kept = /* @__PURE__ */ new Set([
|
|
1113
|
+
"primary",
|
|
1114
|
+
"primary-alt",
|
|
1115
|
+
"primary-dark",
|
|
1116
|
+
"background",
|
|
1117
|
+
"ink",
|
|
1118
|
+
...extras.slice(0, n - 5)
|
|
1119
|
+
]);
|
|
1120
|
+
return SWATCH_KEYS.filter((k) => kept.has(k));
|
|
1121
|
+
}
|
|
1122
|
+
/** Same hue and saturation as `hex`, at lightness `l`. */
|
|
1123
|
+
var atLightness = (hex, l) => {
|
|
1124
|
+
const [h, s] = hslOf$3(hex);
|
|
1125
|
+
return rgbToHex(hslToRgb([
|
|
1126
|
+
h,
|
|
1127
|
+
s,
|
|
1128
|
+
l
|
|
1129
|
+
]));
|
|
1130
|
+
};
|
|
1131
|
+
/**
|
|
1132
|
+
* A theme's tokens using only `count` of its colours. Chart colours that go are painted with
|
|
1133
|
+
* the ones that stay (brand colours first), at their own lightness so charts keep their
|
|
1134
|
+
* contrast; a soft tint that goes becomes a tint of the brand colour. The colours it replaces are
|
|
1135
|
+
* then run through the contrast fixes (lightness only), so a smaller palette still reads.
|
|
1136
|
+
*/
|
|
1137
|
+
function reducePalette(tokens, count = 10) {
|
|
1138
|
+
const n = clampColours(count);
|
|
1139
|
+
if (n >= 10) return tokens;
|
|
1140
|
+
const kept = new Set(paletteKeys(tokens, n));
|
|
1141
|
+
const out = { ...tokens };
|
|
1142
|
+
const replaced = /* @__PURE__ */ new Set();
|
|
1143
|
+
const pool = [
|
|
1144
|
+
"primary",
|
|
1145
|
+
"primary-alt",
|
|
1146
|
+
...CHART.filter((k) => kept.has(k))
|
|
1147
|
+
].map((k) => tokens[k]);
|
|
1148
|
+
[...CHART.filter((k) => !kept.has(k)), ...HIDDEN_CHART].forEach((key, i) => {
|
|
1149
|
+
if (!tokens[key]) return;
|
|
1150
|
+
out[key] = atLightness(pool[i % pool.length], hslOf$3(tokens[key])[2]);
|
|
1151
|
+
replaced.add(key);
|
|
1152
|
+
});
|
|
1153
|
+
if (!kept.has("secondary")) {
|
|
1154
|
+
out.secondary = mix(tokens.primary, tokens.background, .14);
|
|
1155
|
+
out["on-secondary"] = [
|
|
1156
|
+
tokens["on-secondary"],
|
|
1157
|
+
tokens["primary-dark"],
|
|
1158
|
+
tokens.ink
|
|
1159
|
+
].find((c) => c && contrastRatio(c, out.secondary) >= 4.5) ?? tokens.ink;
|
|
1160
|
+
replaced.add("secondary").add("on-secondary");
|
|
1161
|
+
}
|
|
1162
|
+
for (const [key, value] of Object.entries(fixAll(out))) if (replaced.has(key)) out[key] = value;
|
|
1163
|
+
return out;
|
|
1164
|
+
}
|
|
1165
|
+
/** A theme's saved colour count: its own, or the visitor's default for every theme. */
|
|
1166
|
+
var coloursFor = (sizes, themeId, fallback = 10) => clampColours(sizes?.[baseId(themeId)] ?? fallback);
|
|
1167
|
+
/** Light and dark versions of a theme share one count. */
|
|
1168
|
+
var baseId = (id) => String(id).replace(/~dark$/, "");
|
|
1036
1169
|
//#endregion
|
|
1037
1170
|
//#region src/scan.js
|
|
1038
1171
|
/** Elements beyond this count are ignored so scanning stays fast on huge pages. */
|
|
@@ -1083,8 +1216,8 @@ function withoutAppliedTheme(fn) {
|
|
|
1083
1216
|
const freeze = document.createElement("style");
|
|
1084
1217
|
freeze.textContent = "*,*::before,*::after{transition:none!important}";
|
|
1085
1218
|
document.head.appendChild(freeze);
|
|
1086
|
-
const
|
|
1087
|
-
|
|
1219
|
+
const applied = [...document.querySelectorAll("style[data-colorsbymax=\"recolour\"], style[data-colorsbymax=\"vivid\"]")];
|
|
1220
|
+
for (const sheet of applied) sheet.disabled = true;
|
|
1088
1221
|
const style = document.documentElement.style;
|
|
1089
1222
|
const saved = [];
|
|
1090
1223
|
for (let i = style.length - 1; i >= 0; i--) {
|
|
@@ -1098,7 +1231,7 @@ function withoutAppliedTheme(fn) {
|
|
|
1098
1231
|
return fn();
|
|
1099
1232
|
} finally {
|
|
1100
1233
|
for (const [prop, value] of saved) style.setProperty(prop, value);
|
|
1101
|
-
|
|
1234
|
+
for (const sheet of applied) sheet.disabled = false;
|
|
1102
1235
|
getComputedStyle(document.documentElement).color;
|
|
1103
1236
|
document.body.offsetHeight;
|
|
1104
1237
|
freeze.remove();
|
|
@@ -1305,6 +1438,337 @@ function suggestThemes(scan, siteName, library = []) {
|
|
|
1305
1438
|
return [...themes, ...matches];
|
|
1306
1439
|
}
|
|
1307
1440
|
//#endregion
|
|
1441
|
+
//#region src/vivid.js
|
|
1442
|
+
var ZONE = "data-cbm-z";
|
|
1443
|
+
var ROLE = "data-cbm-v";
|
|
1444
|
+
var MIN_TEXT = 4.5;
|
|
1445
|
+
var MIN_LARGE = 3;
|
|
1446
|
+
var IGNORE = /* @__PURE__ */ new Set([
|
|
1447
|
+
"script",
|
|
1448
|
+
"style",
|
|
1449
|
+
"noscript",
|
|
1450
|
+
"template",
|
|
1451
|
+
"link",
|
|
1452
|
+
"meta",
|
|
1453
|
+
"colorsbymax-root"
|
|
1454
|
+
]);
|
|
1455
|
+
var BUTTON_INPUTS = /* @__PURE__ */ new Set([
|
|
1456
|
+
"button",
|
|
1457
|
+
"submit",
|
|
1458
|
+
"reset"
|
|
1459
|
+
]);
|
|
1460
|
+
var FIELD_SKIP = /* @__PURE__ */ new Set([
|
|
1461
|
+
"checkbox",
|
|
1462
|
+
"radio",
|
|
1463
|
+
"range",
|
|
1464
|
+
"color",
|
|
1465
|
+
"file",
|
|
1466
|
+
"hidden",
|
|
1467
|
+
"image",
|
|
1468
|
+
...BUTTON_INPUTS
|
|
1469
|
+
]);
|
|
1470
|
+
var WRAPPERS = /* @__PURE__ */ new Set([
|
|
1471
|
+
"div",
|
|
1472
|
+
"main",
|
|
1473
|
+
"section",
|
|
1474
|
+
"article"
|
|
1475
|
+
]);
|
|
1476
|
+
var visibleBlocks = (el) => [...el.children].filter((c) => {
|
|
1477
|
+
if (IGNORE.has(c.localName) || c.dataset?.colorsbymax !== void 0) return false;
|
|
1478
|
+
return c.getBoundingClientRect().height > 8 && getComputedStyle(c).display !== "none";
|
|
1479
|
+
});
|
|
1480
|
+
var pageHeight = () => Math.max(document.documentElement.scrollHeight, 1);
|
|
1481
|
+
var isTag = (el, ...tags) => tags.includes(el.localName);
|
|
1482
|
+
/**
|
|
1483
|
+
* The page's top-level parts, top to bottom: past any single wrapper (an app's root div), with a
|
|
1484
|
+
* <main>, or a wrapper holding most of the page, opened up into its sections.
|
|
1485
|
+
*/
|
|
1486
|
+
function pageParts() {
|
|
1487
|
+
let container = document.body;
|
|
1488
|
+
for (let i = 0; i < 6; i++) {
|
|
1489
|
+
const kids = visibleBlocks(container);
|
|
1490
|
+
if (kids.length !== 1) break;
|
|
1491
|
+
container = kids[0];
|
|
1492
|
+
}
|
|
1493
|
+
const parts = [];
|
|
1494
|
+
for (const kid of visibleBlocks(container)) {
|
|
1495
|
+
const r = kid.getBoundingClientRect();
|
|
1496
|
+
if (kid.localName === "main" || kid.getAttribute("role") === "main" || WRAPPERS.has(kid.localName) && r.height > pageHeight() * .5 && visibleBlocks(kid).length > 1) parts.push(...visibleBlocks(kid));
|
|
1497
|
+
else parts.push(kid);
|
|
1498
|
+
}
|
|
1499
|
+
return parts.filter((p) => p.getBoundingClientRect().height > 30);
|
|
1500
|
+
}
|
|
1501
|
+
var hasButton = (el) => el.querySelector("button, [role=\"button\"], input[type=\"submit\"], a[class*=\"btn\" i], a[class*=\"button\" i]");
|
|
1502
|
+
/** Marks the page's header, hero, sections, closing call to action and footer. */
|
|
1503
|
+
function markZones() {
|
|
1504
|
+
for (const el of document.querySelectorAll(`[${ZONE}]`)) el.removeAttribute(ZONE);
|
|
1505
|
+
const parts = pageParts();
|
|
1506
|
+
if (parts.length < 2) return;
|
|
1507
|
+
let header = parts.find((p) => isTag(p, "header") || p.getAttribute("role") === "banner");
|
|
1508
|
+
if (!header && parts[0].getBoundingClientRect().height < 200 && parts[0].querySelector("nav, a")) header = parts[0];
|
|
1509
|
+
const last = parts[parts.length - 1];
|
|
1510
|
+
const footer = parts.find((p) => isTag(p, "footer") || p.getAttribute("role") === "contentinfo") ?? (isTag(last, "footer") ? last : null);
|
|
1511
|
+
const body = parts.filter((p) => p !== header && p !== footer);
|
|
1512
|
+
const hero = body.find((p) => p.querySelector("h1")) ?? body[0];
|
|
1513
|
+
const end = body[body.length - 1];
|
|
1514
|
+
const cta = end && end !== hero && end.querySelector("h1, h2, h3") && hasButton(end) && end.textContent.trim().length < 400 ? end : null;
|
|
1515
|
+
if (header) header.setAttribute(ZONE, "header");
|
|
1516
|
+
if (footer) footer.setAttribute(ZONE, "footer");
|
|
1517
|
+
if (hero) hero.setAttribute(ZONE, "hero");
|
|
1518
|
+
if (cta) cta.setAttribute(ZONE, "cta");
|
|
1519
|
+
body.filter((p) => p !== hero && p !== cta).forEach((p, i) => i % 2 === 0 && p.setAttribute("data-cbm-z", "tint"));
|
|
1520
|
+
}
|
|
1521
|
+
/** What an element paints over: 'primary' (a brand-coloured band), 'secondary' (the footer), or 'page'. */
|
|
1522
|
+
var zoneOf = (el) => {
|
|
1523
|
+
const z = el.closest(`[${ZONE}]`)?.getAttribute(ZONE);
|
|
1524
|
+
return z === "cta" ? "primary" : z === "footer" ? "secondary" : "page";
|
|
1525
|
+
};
|
|
1526
|
+
var px = (v) => parseFloat(v) || 0;
|
|
1527
|
+
var allBorders = (cs) => [
|
|
1528
|
+
"top",
|
|
1529
|
+
"right",
|
|
1530
|
+
"bottom",
|
|
1531
|
+
"left"
|
|
1532
|
+
].every((s) => px(cs.getPropertyValue(`border-${s}-width`)) > 0 && cs.getPropertyValue(`border-${s}-style`) !== "none");
|
|
1533
|
+
/**
|
|
1534
|
+
* The roles an element plays, from its original look. `ownFill` is its own background (a hex, or
|
|
1535
|
+
* null if it has none worth counting) and `under` the hex of what it sits on.
|
|
1536
|
+
*/
|
|
1537
|
+
function rolesOf(el, cs, ownFill, under) {
|
|
1538
|
+
const roles = [];
|
|
1539
|
+
const name = el.localName;
|
|
1540
|
+
const zoneRole = el.getAttribute(ZONE);
|
|
1541
|
+
const zone = zoneOf(el);
|
|
1542
|
+
if (zoneRole) roles.push(`z-${zoneRole}`);
|
|
1543
|
+
const inButton = el.parentElement?.closest(`[${ROLE}~="btn"], [${ROLE}~="btn2"], [${ROLE}~="btn-inv"]`);
|
|
1544
|
+
if (inButton) {
|
|
1545
|
+
const kind = inButton.getAttribute(ROLE).match(/\b(btn-inv|btn2|btn)\b/)[1];
|
|
1546
|
+
roles.push(`${kind}-in`);
|
|
1547
|
+
return roles;
|
|
1548
|
+
}
|
|
1549
|
+
if (zone === "primary") roles.push("on1");
|
|
1550
|
+
else if (zone === "secondary") roles.push("on2");
|
|
1551
|
+
const type = (el.getAttribute("type") || "").toLowerCase();
|
|
1552
|
+
const radius = px(cs.borderTopLeftRadius);
|
|
1553
|
+
const filled = Boolean(ownFill) && deltaE(ownFill, under) > 12;
|
|
1554
|
+
if (name === "button" || el.getAttribute("role") === "button" || name === "input" && BUTTON_INPUTS.has(type) || (name === "a" || name === "label") && (filled || allBorders(cs)) && px(cs.paddingLeft) >= 6 && cs.display !== "inline") {
|
|
1555
|
+
roles.push(zone === "primary" ? "btn-inv" : filled ? "btn" : "btn2");
|
|
1556
|
+
return roles;
|
|
1557
|
+
}
|
|
1558
|
+
if (name === "a") {
|
|
1559
|
+
roles.push(el.closest(`nav, [data-cbm-z="header"]`) ? "navlink" : zone === "page" ? "link" : "link-on");
|
|
1560
|
+
return roles;
|
|
1561
|
+
}
|
|
1562
|
+
if (/^h[1-3]$/.test(name) && zone === "page") roles.push("head");
|
|
1563
|
+
if (zone === "page" && [
|
|
1564
|
+
"em",
|
|
1565
|
+
"strong",
|
|
1566
|
+
"b",
|
|
1567
|
+
"i",
|
|
1568
|
+
"span",
|
|
1569
|
+
"mark"
|
|
1570
|
+
].includes(name) && el.parentElement?.localName === "h1") roles.push("hl");
|
|
1571
|
+
if (name === "input" && !FIELD_SKIP.has(type)) roles.push("field");
|
|
1572
|
+
else if (name === "textarea" || name === "select") roles.push("field");
|
|
1573
|
+
if (zone !== "page") return roles;
|
|
1574
|
+
if (name === "th") roles.push("th");
|
|
1575
|
+
else if (name === "blockquote") roles.push("quote");
|
|
1576
|
+
else if (name === "pre" || name === "code" && el.parentElement?.localName !== "pre") roles.push("code");
|
|
1577
|
+
else if (name === "hr") roles.push("rule");
|
|
1578
|
+
else if (name === "mark") roles.push("mark");
|
|
1579
|
+
const blockish = [
|
|
1580
|
+
"block",
|
|
1581
|
+
"flex",
|
|
1582
|
+
"grid",
|
|
1583
|
+
"flow-root",
|
|
1584
|
+
"list-item"
|
|
1585
|
+
].includes(cs.display);
|
|
1586
|
+
if (blockish && !zoneRole && radius >= 6 && (allBorders(cs) || cs.boxShadow !== "none" || filled) && ![
|
|
1587
|
+
"input",
|
|
1588
|
+
"textarea",
|
|
1589
|
+
"select",
|
|
1590
|
+
"img"
|
|
1591
|
+
].includes(name)) {
|
|
1592
|
+
const r = el.getBoundingClientRect();
|
|
1593
|
+
const parent = el.parentElement?.getBoundingClientRect();
|
|
1594
|
+
if (r.height >= 56 && parent && r.width <= parent.width * .96 && el.textContent.trim()) roles.push("card");
|
|
1595
|
+
}
|
|
1596
|
+
const tinted = Boolean(ownFill) && deltaE(ownFill, under) > 2;
|
|
1597
|
+
if (!blockish && tinted && radius >= 6 && el.textContent.trim().length <= 30 && !el.querySelector("div, p")) roles.push("badge");
|
|
1598
|
+
return roles;
|
|
1599
|
+
}
|
|
1600
|
+
var readsOn = (fg, bgs, min) => bgs.every((bg) => contrastRatio(fg, bg) >= min);
|
|
1601
|
+
/** The first colour that reads on every background, else the theme's plain text colour. */
|
|
1602
|
+
var firstReadable = (candidates, bgs, min) => candidates.find((c) => c && readsOn(c, bgs, min)) ?? candidates[candidates.length - 1];
|
|
1603
|
+
/** The Colourful stylesheet for a theme's tokens. */
|
|
1604
|
+
function vividCss(t) {
|
|
1605
|
+
const bg = t.background;
|
|
1606
|
+
const tint = mix(t.secondary, bg, .55);
|
|
1607
|
+
const glow = mix(t.primary, bg, .16);
|
|
1608
|
+
const glowAlt = mix(t["primary-alt"], bg, .12);
|
|
1609
|
+
const pageBgs = [
|
|
1610
|
+
bg,
|
|
1611
|
+
t.surface,
|
|
1612
|
+
tint,
|
|
1613
|
+
glow
|
|
1614
|
+
];
|
|
1615
|
+
const ink = firstReadable([t.ink], pageBgs, MIN_TEXT);
|
|
1616
|
+
const head = firstReadable([t["primary-dark"], ink], pageBgs, MIN_LARGE);
|
|
1617
|
+
const link = firstReadable([
|
|
1618
|
+
t.primary,
|
|
1619
|
+
t["primary-dark"],
|
|
1620
|
+
ink
|
|
1621
|
+
], pageBgs, MIN_TEXT);
|
|
1622
|
+
const linkHover = firstReadable([t["primary-dark"], ink], pageBgs, MIN_TEXT);
|
|
1623
|
+
const navHover = firstReadable([
|
|
1624
|
+
t.primary,
|
|
1625
|
+
t["primary-dark"],
|
|
1626
|
+
ink
|
|
1627
|
+
], [t.surface, bg], MIN_TEXT);
|
|
1628
|
+
const bandEnd = mix(t["primary-alt"], t.primary, .45);
|
|
1629
|
+
const onPrimary = firstReadable([
|
|
1630
|
+
t["on-primary"],
|
|
1631
|
+
"#ffffff",
|
|
1632
|
+
"#000000"
|
|
1633
|
+
], [t.primary], MIN_TEXT);
|
|
1634
|
+
const band = readsOn(onPrimary, [t.primary, bandEnd], MIN_TEXT) ? `linear-gradient(135deg,${t.primary},${bandEnd})` : t.primary;
|
|
1635
|
+
const footerBg = t.secondary;
|
|
1636
|
+
const onSecondary = firstReadable([t["on-secondary"], ink], [footerBg], MIN_TEXT);
|
|
1637
|
+
const btnHover = mix(t["primary-dark"], t.primary, .22);
|
|
1638
|
+
const onBtnHover = firstReadable([
|
|
1639
|
+
onPrimary,
|
|
1640
|
+
"#ffffff",
|
|
1641
|
+
"#000000"
|
|
1642
|
+
], [btnHover], MIN_TEXT);
|
|
1643
|
+
const quiet = firstReadable([t["on-secondary"], ink], [t.secondary], MIN_TEXT);
|
|
1644
|
+
const badgeBg = mix(t.primary, t.surface, .2);
|
|
1645
|
+
const badgeInk = firstReadable([
|
|
1646
|
+
t["primary-dark"],
|
|
1647
|
+
t["on-secondary"],
|
|
1648
|
+
ink
|
|
1649
|
+
], [badgeBg], MIN_TEXT);
|
|
1650
|
+
const hlGradient = readsOn(t.primary, [bg, glow], MIN_LARGE) && readsOn(t["primary-alt"], [bg, glow], MIN_LARGE);
|
|
1651
|
+
const shadow = `0 18px 40px -22px ${t.shadow}`;
|
|
1652
|
+
const move = "transition:background-color .25s,color .25s,border-color .25s,box-shadow .25s,transform .25s!important";
|
|
1653
|
+
const r = (role, css) => `[${ROLE}~="${role}"]{${css}}`;
|
|
1654
|
+
const imp = (decls) => decls.map((d) => `${d}!important`).join(";");
|
|
1655
|
+
return [
|
|
1656
|
+
`html{accent-color:${t.primary}}`,
|
|
1657
|
+
`::selection{background:${mix(t.primary, bg, .28)}}`,
|
|
1658
|
+
`[${ROLE}] li::marker,li[${ROLE}]::marker{color:${t.primary}}`,
|
|
1659
|
+
r("z-header", imp([`background-color:${t.surface}`, `border-bottom-color:${t.border}`])),
|
|
1660
|
+
r("z-hero", imp([`background-color:${bg}`, `background-image:radial-gradient(120% 85% at 50% -10%,${glow} 0%,transparent 62%),radial-gradient(60% 60% at 100% 100%,${glowAlt} 0%,transparent 70%)`])),
|
|
1661
|
+
r("z-tint", imp([`background-color:${tint}`])),
|
|
1662
|
+
r("z-cta", imp([
|
|
1663
|
+
`background-color:${t.primary}`,
|
|
1664
|
+
`background-image:${band}`,
|
|
1665
|
+
`color:${onPrimary}`
|
|
1666
|
+
])),
|
|
1667
|
+
r("z-footer", imp([
|
|
1668
|
+
`background-color:${footerBg}`,
|
|
1669
|
+
`border-top-color:transparent`,
|
|
1670
|
+
`color:${onSecondary}`
|
|
1671
|
+
])),
|
|
1672
|
+
r("on1", imp([`color:${onPrimary}`])),
|
|
1673
|
+
r("on2", imp([`color:${onSecondary}`])),
|
|
1674
|
+
r("head", imp([`color:${head}`])),
|
|
1675
|
+
r("hl", hlGradient ? imp([
|
|
1676
|
+
`background-image:linear-gradient(100deg,${t.primary},${t["primary-alt"]})`,
|
|
1677
|
+
"background-color:transparent",
|
|
1678
|
+
"-webkit-background-clip:text",
|
|
1679
|
+
"background-clip:text",
|
|
1680
|
+
"color:transparent",
|
|
1681
|
+
"-webkit-text-fill-color:transparent"
|
|
1682
|
+
]) : imp([`color:${t.primary}`])),
|
|
1683
|
+
r("link", imp([
|
|
1684
|
+
`color:${link}`,
|
|
1685
|
+
`text-decoration-color:${mix(link, bg, .45)}`,
|
|
1686
|
+
move
|
|
1687
|
+
])),
|
|
1688
|
+
`[${ROLE}~="link"]:hover{${imp([`color:${linkHover}`, `text-decoration-color:${linkHover}`])}}`,
|
|
1689
|
+
r("link-on", imp(["color:inherit", "text-decoration-color:currentColor"])),
|
|
1690
|
+
r("navlink", imp([`color:${firstReadable([t["ink-secondary"], ink], [t.surface, bg], MIN_TEXT)}`, move])),
|
|
1691
|
+
`[${ROLE}~="navlink"]:hover{${imp([`color:${navHover}`])}}`,
|
|
1692
|
+
r("card", imp([
|
|
1693
|
+
`background-color:${t.surface}`,
|
|
1694
|
+
`border-color:${t.border}`,
|
|
1695
|
+
move
|
|
1696
|
+
])),
|
|
1697
|
+
`[${ROLE}~="card"]:hover{${imp([
|
|
1698
|
+
`border-color:${t.primary}`,
|
|
1699
|
+
`box-shadow:${shadow}`,
|
|
1700
|
+
"transform:translateY(-2px)"
|
|
1701
|
+
])}}`,
|
|
1702
|
+
r("badge", imp([
|
|
1703
|
+
`background-color:${badgeBg}`,
|
|
1704
|
+
`color:${badgeInk}`,
|
|
1705
|
+
`border-color:transparent`
|
|
1706
|
+
])),
|
|
1707
|
+
r("field", imp([
|
|
1708
|
+
`background-color:${t.surface}`,
|
|
1709
|
+
`border-color:${t.border}`,
|
|
1710
|
+
`color:${ink}`,
|
|
1711
|
+
move
|
|
1712
|
+
])),
|
|
1713
|
+
`[${ROLE}~="field"]:focus{${imp([
|
|
1714
|
+
`border-color:${t.primary}`,
|
|
1715
|
+
`outline:2px solid ${mix(t.primary, bg, .35)}`,
|
|
1716
|
+
"outline-offset:1px"
|
|
1717
|
+
])}}`,
|
|
1718
|
+
r("th", imp([`background-color:${tint}`, `color:${head}`])),
|
|
1719
|
+
r("quote", imp([
|
|
1720
|
+
`border-left-color:${t.primary}`,
|
|
1721
|
+
`background-color:${t.surface}`,
|
|
1722
|
+
"border-radius:0 12px 12px 0"
|
|
1723
|
+
])),
|
|
1724
|
+
r("code", imp([`background-color:${t.secondary}`, `color:${quiet}`])),
|
|
1725
|
+
r("rule", imp([`border-color:${t.border}`])),
|
|
1726
|
+
r("mark", imp([`background-color:${mix(t["primary-alt"], bg, .3)}`, `color:${ink}`])),
|
|
1727
|
+
r("btn", imp([
|
|
1728
|
+
`background-color:${t.primary}`,
|
|
1729
|
+
"background-image:none",
|
|
1730
|
+
`color:${onPrimary}`,
|
|
1731
|
+
`border-color:${t.primary}`,
|
|
1732
|
+
`box-shadow:0 8px 20px -10px ${t.primary}`,
|
|
1733
|
+
move
|
|
1734
|
+
])),
|
|
1735
|
+
`[${ROLE}~="btn"]:hover{${imp([
|
|
1736
|
+
`background-color:${btnHover}`,
|
|
1737
|
+
`border-color:${btnHover}`,
|
|
1738
|
+
`color:${onBtnHover}`,
|
|
1739
|
+
"transform:translateY(-1px)"
|
|
1740
|
+
])}}`,
|
|
1741
|
+
r("btn-in", imp([`color:${onPrimary}`])),
|
|
1742
|
+
`[${ROLE}~="btn"]:hover [${ROLE}~="btn-in"]{${imp([`color:${onBtnHover}`])}}`,
|
|
1743
|
+
r("btn2", imp([
|
|
1744
|
+
`background-color:${t.secondary}`,
|
|
1745
|
+
"background-image:none",
|
|
1746
|
+
`color:${quiet}`,
|
|
1747
|
+
`border-color:${t.border}`,
|
|
1748
|
+
move
|
|
1749
|
+
])),
|
|
1750
|
+
`[${ROLE}~="btn2"]:hover{${imp([`border-color:${t.primary}`, "transform:translateY(-1px)"])}}`,
|
|
1751
|
+
r("btn2-in", imp([`color:${quiet}`])),
|
|
1752
|
+
r("btn-inv", imp([
|
|
1753
|
+
`background-color:${onPrimary}`,
|
|
1754
|
+
"background-image:none",
|
|
1755
|
+
`color:${firstReadable([
|
|
1756
|
+
t.primary,
|
|
1757
|
+
t["primary-dark"],
|
|
1758
|
+
ink
|
|
1759
|
+
], [onPrimary], MIN_TEXT)}`,
|
|
1760
|
+
`border-color:${onPrimary}`,
|
|
1761
|
+
move
|
|
1762
|
+
])),
|
|
1763
|
+
`[${ROLE}~="btn-inv"]:hover{${imp(["transform:translateY(-1px)", `box-shadow:0 10px 24px -12px ${t.shadow}`])}}`,
|
|
1764
|
+
r("btn-inv-in", imp([`color:${firstReadable([
|
|
1765
|
+
t.primary,
|
|
1766
|
+
t["primary-dark"],
|
|
1767
|
+
ink
|
|
1768
|
+
], [onPrimary], MIN_TEXT)}`]))
|
|
1769
|
+
].join("\n");
|
|
1770
|
+
}
|
|
1771
|
+
//#endregion
|
|
1308
1772
|
//#region src/recolour.js
|
|
1309
1773
|
var ATTR = "data-cbm";
|
|
1310
1774
|
/** Elements the engine never touches: the switcher itself. */
|
|
@@ -1382,7 +1846,7 @@ var fillsElement = (cs) => Boolean(cs.backgroundImage && cs.backgroundImage !==
|
|
|
1382
1846
|
var hueDist = (a, b) => Math.min(Math.abs(a - b), 360 - Math.abs(a - b));
|
|
1383
1847
|
/** How far hue `a` is from `b`, signed, in -180..180. */
|
|
1384
1848
|
var signedHue = (a, b) => (a - b + 540) % 360 - 180;
|
|
1385
|
-
var hslOf$
|
|
1849
|
+
var hslOf$2 = (hex) => rgbToHsl(hexToRgb(hex));
|
|
1386
1850
|
/** True when the site defines colorsbymax's variables itself, so no re-colouring is needed. */
|
|
1387
1851
|
function usesColourTokens() {
|
|
1388
1852
|
return withoutAppliedTheme(() => getComputedStyle(document.documentElement).getPropertyValue("--color-primary").trim() !== "");
|
|
@@ -1417,16 +1881,20 @@ function createParser() {
|
|
|
1417
1881
|
* Starts re-colouring the page. Returns the site's own colours as tokens (`site`), `apply(tokens)`
|
|
1418
1882
|
* to show a theme (null restores the original look) and `stop()`.
|
|
1419
1883
|
*/
|
|
1420
|
-
function createRecolourer() {
|
|
1884
|
+
function createRecolourer({ colourful = false } = {}) {
|
|
1421
1885
|
const parse = createParser();
|
|
1422
1886
|
const sheet = document.createElement("style");
|
|
1423
1887
|
sheet.dataset.colorsbymax = "recolour";
|
|
1424
1888
|
document.head.append(sheet);
|
|
1889
|
+
const vividSheet = document.createElement("style");
|
|
1890
|
+
vividSheet.dataset.colorsbymax = "vivid";
|
|
1891
|
+
document.head.append(vividSheet);
|
|
1892
|
+
let vivid = colourful;
|
|
1425
1893
|
const { roles } = inferRoles(collectColors());
|
|
1426
1894
|
const site = themeFromRoles(roles);
|
|
1427
1895
|
const plain = !roles.primary;
|
|
1428
|
-
const siteBgL = hslOf$
|
|
1429
|
-
const siteInkL = hslOf$
|
|
1896
|
+
const siteBgL = hslOf$2(site.background)[2];
|
|
1897
|
+
const siteInkL = hslOf$2(site.ink)[2];
|
|
1430
1898
|
/** Each distinct painted value, keyed "prop|value", plus the background under text and icons. */
|
|
1431
1899
|
const entries = /* @__PURE__ */ new Map();
|
|
1432
1900
|
let theme = null;
|
|
@@ -1497,11 +1965,18 @@ function createRecolourer() {
|
|
|
1497
1965
|
if (el.localName === SKIP$1) continue;
|
|
1498
1966
|
if (el.closest(skip)) {
|
|
1499
1967
|
el.removeAttribute(ATTR);
|
|
1968
|
+
el.removeAttribute(ROLE);
|
|
1500
1969
|
continue;
|
|
1501
1970
|
}
|
|
1502
1971
|
const ids = read(el);
|
|
1503
1972
|
if (ids.length) el.setAttribute(ATTR, ids.join(" "));
|
|
1504
1973
|
else el.removeAttribute(ATTR);
|
|
1974
|
+
const cs = getComputedStyle(el);
|
|
1975
|
+
const own = parse(cs.backgroundColor);
|
|
1976
|
+
const under = parse(backdropOf(el.parentElement))?.hex ?? "#ffffff";
|
|
1977
|
+
const roles = rolesOf(el, cs, own && own.alpha >= .5 ? own.hex : null, under);
|
|
1978
|
+
if (roles.length) el.setAttribute(ROLE, roles.join(" "));
|
|
1979
|
+
else el.removeAttribute(ROLE);
|
|
1505
1980
|
}
|
|
1506
1981
|
}
|
|
1507
1982
|
});
|
|
@@ -1513,17 +1988,17 @@ function createRecolourer() {
|
|
|
1513
1988
|
const mapHex = (css, kind) => {
|
|
1514
1989
|
const c = parse(css);
|
|
1515
1990
|
if (!c) return null;
|
|
1516
|
-
const [, s, l] = hslOf$
|
|
1991
|
+
const [, s, l] = hslOf$2(c.hex);
|
|
1517
1992
|
let hex;
|
|
1518
1993
|
if (s < NEUTRAL_SATURATION) {
|
|
1519
1994
|
const span = siteInkL - siteBgL;
|
|
1520
1995
|
const t = Math.abs(span) < .05 ? l > .5 ? 0 : 1 : clamp$1((l - siteBgL) / span);
|
|
1521
1996
|
hex = mix(theme.ink, theme.background, t);
|
|
1522
1997
|
} else {
|
|
1523
|
-
const hue = hslOf$
|
|
1524
|
-
const near = (token, within) => hueDist(hue, hslOf$
|
|
1998
|
+
const hue = hslOf$2(c.hex)[0];
|
|
1999
|
+
const near = (token, within) => hueDist(hue, hslOf$2(site[token])[0]) <= within;
|
|
1525
2000
|
let anchor = near("primary", FAMILY_HUE) ? "primary" : null;
|
|
1526
|
-
if (!anchor && s >= .25) anchor = STATUS.filter((token) => near(token, STATUS_HUE)).sort((a, b) => hueDist(hue, hslOf$
|
|
2001
|
+
if (!anchor && s >= .25) anchor = STATUS.filter((token) => near(token, STATUS_HUE)).sort((a, b) => hueDist(hue, hslOf$2(site[a])[0]) - hueDist(hue, hslOf$2(site[b])[0]))[0] ?? null;
|
|
1527
2002
|
if (!anchor && near("primary-alt", FAMILY_HUE)) anchor = "primary-alt";
|
|
1528
2003
|
if (!anchor) {
|
|
1529
2004
|
let bestD = Infinity;
|
|
@@ -1532,10 +2007,10 @@ function createRecolourer() {
|
|
|
1532
2007
|
if (d < bestD) [anchor, bestD] = [token, d];
|
|
1533
2008
|
}
|
|
1534
2009
|
}
|
|
1535
|
-
const [sh, ss, sl] = hslOf$
|
|
1536
|
-
const [th, ts, tl] = hslOf$
|
|
1537
|
-
const themeBgL = hslOf$
|
|
1538
|
-
const themeInkL = hslOf$
|
|
2010
|
+
const [sh, ss, sl] = hslOf$2(site[anchor]);
|
|
2011
|
+
const [th, ts, tl] = hslOf$2(theme[anchor]);
|
|
2012
|
+
const themeBgL = hslOf$2(theme.background)[2];
|
|
2013
|
+
const themeInkL = hslOf$2(theme.ink)[2];
|
|
1539
2014
|
const toBg = sl - siteBgL;
|
|
1540
2015
|
const toInk = siteInkL - sl;
|
|
1541
2016
|
const u = Math.abs(toBg) < .05 ? null : (l - siteBgL) / toBg;
|
|
@@ -1591,7 +2066,7 @@ function createRecolourer() {
|
|
|
1591
2066
|
if (entry.prop === "background-image") value = entry.value.replace(COLOR_IN_GRADIENT, (stop) => mapColour(stop, entry.kind));
|
|
1592
2067
|
else if (entry.backdrop) {
|
|
1593
2068
|
const own = parse(entry.value);
|
|
1594
|
-
const brand = entry.accent && own && hslOf$
|
|
2069
|
+
const brand = entry.accent && own && hslOf$2(own.hex)[1] < NEUTRAL_SATURATION;
|
|
1595
2070
|
const fg = brand ? {
|
|
1596
2071
|
hex: theme.primary,
|
|
1597
2072
|
alpha: own.alpha
|
|
@@ -1614,7 +2089,22 @@ function createRecolourer() {
|
|
|
1614
2089
|
return `[${ATTR}~="${entry.id}"]{${entry.prop}:${value}!important}`;
|
|
1615
2090
|
};
|
|
1616
2091
|
let skip = `${SKIP$1}, ${LOGO_SELECTOR}`;
|
|
2092
|
+
withoutAppliedTheme(markZones);
|
|
1617
2093
|
tag([document.body], true);
|
|
2094
|
+
const LOGO_ATTR = "data-cbm-logo";
|
|
2095
|
+
const logos = withoutAppliedTheme(() => [...document.querySelectorAll(LOGO_SELECTOR)].filter((el) => !el.parentElement?.closest(LOGO_SELECTOR) && !el.closest(SKIP$1)).map((el) => ({
|
|
2096
|
+
el,
|
|
2097
|
+
color: getComputedStyle(el).color
|
|
2098
|
+
})));
|
|
2099
|
+
const logoRules = () => {
|
|
2100
|
+
if (!theme || !skip.includes(LOGO_SELECTOR)) return "";
|
|
2101
|
+
return logos.map(({ el, color }, i) => {
|
|
2102
|
+
const own = parse(color);
|
|
2103
|
+
if (!own || hslOf$2(own.hex)[1] >= NEUTRAL_SATURATION || !el.isConnected) return "";
|
|
2104
|
+
el.setAttribute(LOGO_ATTR, i);
|
|
2105
|
+
return `[${LOGO_ATTR}="${i}"]{color:${mapColour(color, "text")}!important}`;
|
|
2106
|
+
}).join("");
|
|
2107
|
+
};
|
|
1618
2108
|
const observer = new MutationObserver((records) => {
|
|
1619
2109
|
const added = [];
|
|
1620
2110
|
const changed = /* @__PURE__ */ new Set();
|
|
@@ -1638,7 +2128,13 @@ function createRecolourer() {
|
|
|
1638
2128
|
/** Shows `tokens` in place of the site's colours; null brings back the original look. */
|
|
1639
2129
|
apply(tokens) {
|
|
1640
2130
|
theme = tokens;
|
|
1641
|
-
sheet.textContent = tokens ? [...entries.values()].map(rule).join("") : "";
|
|
2131
|
+
sheet.textContent = tokens ? [...entries.values()].map(rule).join("") + logoRules() : "";
|
|
2132
|
+
vividSheet.textContent = tokens && vivid ? vividCss(tokens) : "";
|
|
2133
|
+
},
|
|
2134
|
+
/** Colourful (true) paints the page's parts by role; Subtle (false) only swaps its colours. */
|
|
2135
|
+
setColourful(on) {
|
|
2136
|
+
vivid = on;
|
|
2137
|
+
vividSheet.textContent = theme && vivid ? vividCss(theme) : "";
|
|
1642
2138
|
},
|
|
1643
2139
|
/** Whether the logo is re-coloured with the rest (off keeps it in its own colours). */
|
|
1644
2140
|
setLogoColouring(on) {
|
|
@@ -1646,11 +2142,18 @@ function createRecolourer() {
|
|
|
1646
2142
|
if (next === skip) return;
|
|
1647
2143
|
skip = next;
|
|
1648
2144
|
tag([document.body], true);
|
|
2145
|
+
if (theme) sheet.textContent = [...entries.values()].map(rule).join("") + logoRules();
|
|
1649
2146
|
},
|
|
1650
2147
|
stop() {
|
|
1651
2148
|
observer.disconnect();
|
|
1652
2149
|
sheet.remove();
|
|
1653
|
-
|
|
2150
|
+
vividSheet.remove();
|
|
2151
|
+
for (const el of document.querySelectorAll(`[${ATTR}], [${ROLE}], [${ZONE}], [${LOGO_ATTR}]`)) {
|
|
2152
|
+
el.removeAttribute(LOGO_ATTR);
|
|
2153
|
+
el.removeAttribute(ATTR);
|
|
2154
|
+
el.removeAttribute(ROLE);
|
|
2155
|
+
el.removeAttribute(ZONE);
|
|
2156
|
+
}
|
|
1654
2157
|
}
|
|
1655
2158
|
};
|
|
1656
2159
|
}
|
|
@@ -1670,6 +2173,9 @@ function createRecolourer() {
|
|
|
1670
2173
|
* @property {number | 'full' | null} panelHeight Pixels, 'full' for all the room there is, or null to fit the content
|
|
1671
2174
|
* @property {boolean} libraryCollapsed Whether the library's category chips are folded away
|
|
1672
2175
|
* @property {boolean} colourLogo Whether themes re-colour the site's logo too (off keeps its own colours)
|
|
2176
|
+
* @property {number} paletteSize How many of a theme's ten colours every theme uses (5 to 10; 5 to start, the core ones)
|
|
2177
|
+
* @property {'colourful' | 'subtle'} colourStyle On a re-coloured site: 'colourful' paints its parts by role
|
|
2178
|
+
* (header, hero, sections, cards, buttons, footer), 'subtle' only swaps the colours it already has
|
|
1673
2179
|
* @property {boolean} hideButton Hidden on this device from the finish screen (Alt+Shift+C brings it back)
|
|
1674
2180
|
*/
|
|
1675
2181
|
/** @type {PanelSettings} */
|
|
@@ -1686,6 +2192,8 @@ var DEFAULT_SETTINGS = {
|
|
|
1686
2192
|
panelHeight: null,
|
|
1687
2193
|
libraryCollapsed: false,
|
|
1688
2194
|
colourLogo: false,
|
|
2195
|
+
colourStyle: "colourful",
|
|
2196
|
+
paletteSize: 5,
|
|
1689
2197
|
hideButton: false
|
|
1690
2198
|
};
|
|
1691
2199
|
/** Size presets offered in settings; dragging an edge gives a custom size instead. */
|
|
@@ -1725,6 +2233,8 @@ function loadSettings(storageKey, defaults = DEFAULT_SETTINGS) {
|
|
|
1725
2233
|
"dark",
|
|
1726
2234
|
"system"
|
|
1727
2235
|
].includes(out.mode)) out.mode = defaults.mode;
|
|
2236
|
+
if (!["colourful", "subtle"].includes(out.colourStyle)) out.colourStyle = defaults.colourStyle;
|
|
2237
|
+
if (!Number.isInteger(out.paletteSize) || out.paletteSize < 5 || out.paletteSize > 10) out.paletteSize = defaults.paletteSize;
|
|
1728
2238
|
const size = (v) => typeof v === "number" && v > 0 && v < 1e4;
|
|
1729
2239
|
out.panelWidth = size(saved.panelWidth) ? saved.panelWidth : null;
|
|
1730
2240
|
out.panelHeight = size(saved.panelHeight) || saved.panelHeight === "full" ? saved.panelHeight : null;
|
|
@@ -1785,7 +2295,8 @@ var initialState = (defaultId) => ({
|
|
|
1785
2295
|
overrides: {},
|
|
1786
2296
|
customs: [],
|
|
1787
2297
|
snapshot: null,
|
|
1788
|
-
scanned: null
|
|
2298
|
+
scanned: null,
|
|
2299
|
+
paletteSizes: {}
|
|
1789
2300
|
});
|
|
1790
2301
|
/** Keeps only known token keys with valid hex values. */
|
|
1791
2302
|
function sanitizeTokens(input) {
|
|
@@ -1840,7 +2351,8 @@ function loadState(storageKey, defaultTheme) {
|
|
|
1840
2351
|
overrides: sanitizeTokens(data.overrides),
|
|
1841
2352
|
customs,
|
|
1842
2353
|
snapshot,
|
|
1843
|
-
scanned
|
|
2354
|
+
scanned,
|
|
2355
|
+
paletteSizes: Object.fromEntries(Object.entries(data.paletteSizes && typeof data.paletteSizes === "object" ? data.paletteSizes : {}).filter(([id, n]) => typeof id === "string" && Number.isInteger(n) && n >= 5 && n <= 10))
|
|
1844
2356
|
};
|
|
1845
2357
|
} catch {
|
|
1846
2358
|
return fresh;
|
|
@@ -1922,6 +2434,13 @@ var newId = () => `custom-${Date.now().toString(36)}-${Math.random().toString(36
|
|
|
1922
2434
|
* `hidden: import.meta.env.PROD` to keep it out of production once the colours are chosen.
|
|
1923
2435
|
* @property {'bottom-right' | 'bottom-left' | 'top-left' | 'top-right'} [position] Where the colour
|
|
1924
2436
|
* button starts (default 'bottom-right'). 'top-right' sits under a floating nav bar.
|
|
2437
|
+
* @property {'colourful' | 'subtle'} [colourStyle] How boldly a re-coloured site takes a theme, for a
|
|
2438
|
+
* first-time visitor. 'colourful' (default) paints the page's parts by role, as a designer would:
|
|
2439
|
+
* header, hero, alternating sections, cards, buttons, links, headings and footer. 'subtle' only
|
|
2440
|
+
* swaps the colours the site already has. Visitors can switch in the panel.
|
|
2441
|
+
* @property {Partial<Record<keyof typeof FEATURES, boolean>>} [features] Parts of the panel to switch off
|
|
2442
|
+
* for everyone, e.g. { scan: false, audit: false } (all on by default). Unlike the rest of the
|
|
2443
|
+
* config it's read live, so a site can change it after loading (from its own settings).
|
|
1925
2444
|
* @property {boolean | 'auto'} [recolour] Re-colour a site that doesn't paint with the --color-*
|
|
1926
2445
|
* variables, by swapping the colours actually on the page. 'auto' (default) does it only when
|
|
1927
2446
|
* the site doesn't define --color-primary itself.
|
|
@@ -1972,9 +2491,28 @@ function resolveSite(config, pageColours) {
|
|
|
1972
2491
|
};
|
|
1973
2492
|
}
|
|
1974
2493
|
/** @param {{ config?: ColorsByMaxConfig, children: import('react').ReactNode }} props */
|
|
2494
|
+
/** Parts of the panel a site can switch off for everyone (config `features`). All on by default. */
|
|
2495
|
+
var FEATURES = {
|
|
2496
|
+
picks: true,
|
|
2497
|
+
library: true,
|
|
2498
|
+
search: true,
|
|
2499
|
+
surprise: true,
|
|
2500
|
+
scan: true,
|
|
2501
|
+
custom: true,
|
|
2502
|
+
overrides: true,
|
|
2503
|
+
importExport: true,
|
|
2504
|
+
audit: true,
|
|
2505
|
+
addToSite: true,
|
|
2506
|
+
colourStyle: true,
|
|
2507
|
+
colourCount: true
|
|
2508
|
+
};
|
|
1975
2509
|
function ThemeProvider({ config = {}, children }) {
|
|
1976
2510
|
const storageKey = config.storageKey || "colorsbymax";
|
|
1977
2511
|
const [initialConfig] = useState(config);
|
|
2512
|
+
const features = useMemo(() => ({
|
|
2513
|
+
...FEATURES,
|
|
2514
|
+
...Object.fromEntries(Object.entries(config.features ?? {}).filter(([k, v]) => k in FEATURES && typeof v === "boolean"))
|
|
2515
|
+
}), [config.features]);
|
|
1978
2516
|
const [pageColours, setPageColours] = useState(null);
|
|
1979
2517
|
const site = useMemo(() => resolveSite(initialConfig, pageColours), [initialConfig, pageColours]);
|
|
1980
2518
|
const { siteName, defaultTheme } = site;
|
|
@@ -1988,10 +2526,17 @@ function ThemeProvider({ config = {}, children }) {
|
|
|
1988
2526
|
const find = (id) => allThemes.find((t) => t.id === id);
|
|
1989
2527
|
const lightOfTwin = state.activeId.endsWith("~dark") ? find(state.activeId.slice(0, -DARK_SUFFIX.length)) : null;
|
|
1990
2528
|
const base = find(state.activeId) ?? (lightOfTwin ? toDark(lightOfTwin) : null) ?? (state.snapshot?.id === state.activeId ? state.snapshot : null) ?? defaultTheme;
|
|
2529
|
+
const [paletteDefault, setPaletteDefault] = useState(() => loadSettings(storageKey, DEFAULT_SETTINGS).paletteSize);
|
|
2530
|
+
const coloursOf = useCallback((id) => coloursFor(state.paletteSizes, id, paletteDefault), [state.paletteSizes, paletteDefault]);
|
|
2531
|
+
const colourCount = coloursOf(base.id);
|
|
1991
2532
|
const tokens = useMemo(() => ({
|
|
1992
|
-
...base.tokens,
|
|
2533
|
+
...reducePalette(base.tokens, colourCount),
|
|
1993
2534
|
...state.overrides
|
|
1994
|
-
}), [
|
|
2535
|
+
}), [
|
|
2536
|
+
base,
|
|
2537
|
+
colourCount,
|
|
2538
|
+
state.overrides
|
|
2539
|
+
]);
|
|
1995
2540
|
const issues = useMemo(() => checkTheme(tokens), [tokens]);
|
|
1996
2541
|
useLayoutEffect(() => {
|
|
1997
2542
|
applyTokens(tokens);
|
|
@@ -2020,6 +2565,7 @@ function ThemeProvider({ config = {}, children }) {
|
|
|
2020
2565
|
const settingDefaults = useMemo(() => ({
|
|
2021
2566
|
...DEFAULT_SETTINGS,
|
|
2022
2567
|
colourLogo: Boolean(initialConfig.colourLogo),
|
|
2568
|
+
colourStyle: initialConfig.colourStyle === "subtle" ? "subtle" : "colourful",
|
|
2023
2569
|
mode: [
|
|
2024
2570
|
"light",
|
|
2025
2571
|
"dark",
|
|
@@ -2030,6 +2576,18 @@ function ThemeProvider({ config = {}, children }) {
|
|
|
2030
2576
|
useLayoutEffect(() => {
|
|
2031
2577
|
recolourer.current?.setLogoColouring(logoColouring);
|
|
2032
2578
|
}, [logoColouring, pageColours]);
|
|
2579
|
+
const [colourStyle, setColourStyle] = useState(() => loadSettings(storageKey, settingDefaults).colourStyle);
|
|
2580
|
+
useLayoutEffect(() => {
|
|
2581
|
+
recolourer.current?.setColourful(colourStyle === "colourful");
|
|
2582
|
+
}, [colourStyle, pageColours]);
|
|
2583
|
+
useLayoutEffect(() => {
|
|
2584
|
+
if (!pageColours) applyTokens(colourStyle === "subtle" ? subtleTokens(tokens) : tokens);
|
|
2585
|
+
}, [
|
|
2586
|
+
tokens,
|
|
2587
|
+
state,
|
|
2588
|
+
colourStyle,
|
|
2589
|
+
pageColours
|
|
2590
|
+
]);
|
|
2033
2591
|
useLayoutEffect(() => {
|
|
2034
2592
|
if (logoColouring || pageColours) return;
|
|
2035
2593
|
const style = document.createElement("style");
|
|
@@ -2171,6 +2729,22 @@ function ThemeProvider({ config = {}, children }) {
|
|
|
2171
2729
|
recolouring: Boolean(pageColours),
|
|
2172
2730
|
/** Turns re-colouring of the site's logo on or off (the switcher's "Colour the logo" setting). */
|
|
2173
2731
|
setLogoColouring,
|
|
2732
|
+
/** Sets how boldly a re-coloured site takes the theme: 'colourful' or 'subtle'. */
|
|
2733
|
+
setColourStyle,
|
|
2734
|
+
/** Which parts of the panel are on (config `features`). */
|
|
2735
|
+
features,
|
|
2736
|
+
/** How many colours a theme uses (5 to 10): its own count, or the visitor's default. */
|
|
2737
|
+
coloursOf,
|
|
2738
|
+
/** Sets one theme's colour count (light and dark share it). */
|
|
2739
|
+
setThemeColours: (id, n) => setState((s) => ({
|
|
2740
|
+
...s,
|
|
2741
|
+
paletteSizes: {
|
|
2742
|
+
...s.paletteSizes,
|
|
2743
|
+
[baseId(id)]: clampColours(n)
|
|
2744
|
+
}
|
|
2745
|
+
})),
|
|
2746
|
+
/** The default count for every theme (the panel's settings); themes given their own count keep it. */
|
|
2747
|
+
setPaletteDefault,
|
|
2174
2748
|
siteThemes,
|
|
2175
2749
|
defaultTheme,
|
|
2176
2750
|
presets: PRESETS,
|
|
@@ -2544,6 +3118,95 @@ var ToggleRight = icon("toggle-right", [["circle", {
|
|
|
2544
3118
|
"y": "5",
|
|
2545
3119
|
"rx": "7"
|
|
2546
3120
|
}]]);
|
|
3121
|
+
var LibraryBig = icon("library-big", [
|
|
3122
|
+
["rect", {
|
|
3123
|
+
"width": "8",
|
|
3124
|
+
"height": "18",
|
|
3125
|
+
"x": "3",
|
|
3126
|
+
"y": "3",
|
|
3127
|
+
"rx": "1"
|
|
3128
|
+
}],
|
|
3129
|
+
["path", { "d": "M7 3v18" }],
|
|
3130
|
+
["path", { "d": "M20.4 18.9c.2.5-.1 1.1-.6 1.3l-1.9.7c-.5.2-1.1-.1-1.3-.6L11.1 5.1c-.2-.5.1-1.1.6-1.3l1.9-.7c.5-.2 1.1.1 1.3.6Z" }]
|
|
3131
|
+
]);
|
|
3132
|
+
var Minus = icon("minus", [["path", { "d": "M5 12h14" }]]);
|
|
3133
|
+
var Plus = icon("plus", [["path", { "d": "M5 12h14" }], ["path", { "d": "M12 5v14" }]]);
|
|
3134
|
+
//#endregion
|
|
3135
|
+
//#region src/burst.jsx
|
|
3136
|
+
var BURST_TIME = 1100;
|
|
3137
|
+
var BURST_KEYS = [
|
|
3138
|
+
"primary",
|
|
3139
|
+
"primary-alt",
|
|
3140
|
+
"data-1",
|
|
3141
|
+
"data-2",
|
|
3142
|
+
"data-3",
|
|
3143
|
+
"data-4",
|
|
3144
|
+
"warning",
|
|
3145
|
+
"data-5"
|
|
3146
|
+
];
|
|
3147
|
+
var BURST_PIECES = Array.from({ length: 12 }, (_, i) => {
|
|
3148
|
+
const angle = (i * 30 + (i % 2 ? 9 : -6)) * (Math.PI / 180);
|
|
3149
|
+
const distance = 30 + i % 3 * 9;
|
|
3150
|
+
return {
|
|
3151
|
+
x: Math.round(Math.cos(angle) * distance),
|
|
3152
|
+
y: Math.round(Math.sin(angle) * distance),
|
|
3153
|
+
r: Math.round(angle * 180 / Math.PI),
|
|
3154
|
+
shape: [
|
|
3155
|
+
"squiggle",
|
|
3156
|
+
"dot",
|
|
3157
|
+
"dash"
|
|
3158
|
+
][i % 3],
|
|
3159
|
+
delay: i % 4 * 25
|
|
3160
|
+
};
|
|
3161
|
+
});
|
|
3162
|
+
/** `spread` scales how far the pieces fly, for something wider than the colour button. */
|
|
3163
|
+
function Burst({ tokens, spread = 1 }) {
|
|
3164
|
+
return /* @__PURE__ */ jsx("span", {
|
|
3165
|
+
"aria-hidden": "true",
|
|
3166
|
+
className: "theme-burst pointer-events-none absolute inset-0",
|
|
3167
|
+
children: BURST_PIECES.map((p, i) => /* @__PURE__ */ jsx("span", {
|
|
3168
|
+
className: `theme-burst-piece ${p.shape === "squiggle" ? "" : `theme-piece-${p.shape}`}`,
|
|
3169
|
+
style: {
|
|
3170
|
+
"--x": `${Math.round(p.x * spread)}px`,
|
|
3171
|
+
"--y": `${Math.round(p.y * spread)}px`,
|
|
3172
|
+
"--r": `${p.r}deg`,
|
|
3173
|
+
color: tokens[BURST_KEYS[i % BURST_KEYS.length]],
|
|
3174
|
+
animationDelay: `${p.delay}ms`
|
|
3175
|
+
},
|
|
3176
|
+
children: p.shape === "squiggle" && /* @__PURE__ */ jsx("svg", {
|
|
3177
|
+
width: "16",
|
|
3178
|
+
height: "10",
|
|
3179
|
+
viewBox: "0 0 16 10",
|
|
3180
|
+
fill: "none",
|
|
3181
|
+
children: /* @__PURE__ */ jsx("path", {
|
|
3182
|
+
d: "M1 5c1.6-3.6 3.4-3.6 4.6 0s3 3.6 4.6 0 3-3.6 4.4 0",
|
|
3183
|
+
stroke: "currentColor",
|
|
3184
|
+
strokeWidth: "2.2",
|
|
3185
|
+
strokeLinecap: "round"
|
|
3186
|
+
})
|
|
3187
|
+
})
|
|
3188
|
+
}, i))
|
|
3189
|
+
});
|
|
3190
|
+
}
|
|
3191
|
+
/**
|
|
3192
|
+
* A burst to show on demand: `celebrate()` starts one (restarting it if one is running), and
|
|
3193
|
+
* `burst` is the key to render `<Burst key={burst} />` with while `bursting`.
|
|
3194
|
+
*/
|
|
3195
|
+
function useBurst() {
|
|
3196
|
+
const [burst, setBurst] = useState(0);
|
|
3197
|
+
const [bursting, setBursting] = useState(false);
|
|
3198
|
+
useEffect(() => {
|
|
3199
|
+
if (!burst) return;
|
|
3200
|
+
setBursting(true);
|
|
3201
|
+
const id = setTimeout(() => setBursting(false), BURST_TIME);
|
|
3202
|
+
return () => clearTimeout(id);
|
|
3203
|
+
}, [burst]);
|
|
3204
|
+
return {
|
|
3205
|
+
burst,
|
|
3206
|
+
bursting,
|
|
3207
|
+
celebrate: () => setBurst((n) => n + 1)
|
|
3208
|
+
};
|
|
3209
|
+
}
|
|
2547
3210
|
/** Images are scaled down to at most this many pixels on their longest side before sampling. */
|
|
2548
3211
|
var SAMPLE_SIZE = 200;
|
|
2549
3212
|
/** PDF pages read, from the first. */
|
|
@@ -2555,7 +3218,7 @@ var MIN_SHARE = .004;
|
|
|
2555
3218
|
/** How close (CIE76 ΔE) a colour must be to a mix of two others to count as their edge blend. */
|
|
2556
3219
|
var BLEND_DELTA_E = 6;
|
|
2557
3220
|
var HEX_IN_TEXT = /#([0-9a-f]{6}|[0-9a-f]{3})\b/gi;
|
|
2558
|
-
var hslOf = (hex) => rgbToHsl(hexToRgb(hex));
|
|
3221
|
+
var hslOf$1 = (hex) => rgbToHsl(hexToRgb(hex));
|
|
2559
3222
|
/**
|
|
2560
3223
|
* The main colours in an image or PDF, most important first.
|
|
2561
3224
|
* @param {File} file
|
|
@@ -2709,7 +3372,7 @@ var expandHex = (h) => `#${(h.length === 3 ? h.replace(/./g, (c) => c + c) : h).
|
|
|
2709
3372
|
*/
|
|
2710
3373
|
function rolesFromPalette(colours) {
|
|
2711
3374
|
const info = colours.map((hex, i) => {
|
|
2712
|
-
const [h, s, l] = hslOf(hex);
|
|
3375
|
+
const [h, s, l] = hslOf$1(hex);
|
|
2713
3376
|
return {
|
|
2714
3377
|
hex,
|
|
2715
3378
|
h,
|
|
@@ -2925,20 +3588,167 @@ function LogoMark({ tokens, background, className = "" }) {
|
|
|
2925
3588
|
});
|
|
2926
3589
|
}
|
|
2927
3590
|
//#endregion
|
|
3591
|
+
//#region src/colourWords.js
|
|
3592
|
+
var inHue = (h, from, to) => from <= to ? h >= from && h <= to : h >= from || h <= to;
|
|
3593
|
+
/** [word, other words for it, test on [hue 0-360, saturation 0-1, lightness 0-1]] */
|
|
3594
|
+
var COLOURS = [
|
|
3595
|
+
[
|
|
3596
|
+
"red",
|
|
3597
|
+
["crimson", "scarlet"],
|
|
3598
|
+
([h, s, l]) => inHue(h, 345, 12) && s >= .35 && l >= .2 && l <= .7
|
|
3599
|
+
],
|
|
3600
|
+
[
|
|
3601
|
+
"orange",
|
|
3602
|
+
["tangerine"],
|
|
3603
|
+
([h, s, l]) => inHue(h, 13, 38) && s >= .45 && l >= .35
|
|
3604
|
+
],
|
|
3605
|
+
[
|
|
3606
|
+
"coral",
|
|
3607
|
+
["salmon", "peach"],
|
|
3608
|
+
([h, s, l]) => inHue(h, 0, 25) && s >= .45 && l >= .55
|
|
3609
|
+
],
|
|
3610
|
+
[
|
|
3611
|
+
"yellow",
|
|
3612
|
+
["lemon"],
|
|
3613
|
+
([h, s, l]) => inHue(h, 45, 64) && s >= .45 && l >= .45
|
|
3614
|
+
],
|
|
3615
|
+
[
|
|
3616
|
+
"gold",
|
|
3617
|
+
["mustard", "amber"],
|
|
3618
|
+
([h, s, l]) => inHue(h, 36, 52) && s >= .4 && l >= .3 && l <= .65
|
|
3619
|
+
],
|
|
3620
|
+
[
|
|
3621
|
+
"lime",
|
|
3622
|
+
["chartreuse"],
|
|
3623
|
+
([h, s, l]) => inHue(h, 65, 95) && s >= .45 && l >= .35
|
|
3624
|
+
],
|
|
3625
|
+
[
|
|
3626
|
+
"green",
|
|
3627
|
+
[
|
|
3628
|
+
"emerald",
|
|
3629
|
+
"olive",
|
|
3630
|
+
"forest",
|
|
3631
|
+
"sage",
|
|
3632
|
+
"mint"
|
|
3633
|
+
],
|
|
3634
|
+
([h, s]) => inHue(h, 75, 160) && s >= .2
|
|
3635
|
+
],
|
|
3636
|
+
[
|
|
3637
|
+
"teal",
|
|
3638
|
+
["turquoise"],
|
|
3639
|
+
([h, s]) => inHue(h, 160, 195) && s >= .25
|
|
3640
|
+
],
|
|
3641
|
+
[
|
|
3642
|
+
"cyan",
|
|
3643
|
+
["aqua"],
|
|
3644
|
+
([h, s, l]) => inHue(h, 180, 200) && s >= .45 && l >= .4
|
|
3645
|
+
],
|
|
3646
|
+
[
|
|
3647
|
+
"blue",
|
|
3648
|
+
[
|
|
3649
|
+
"sky",
|
|
3650
|
+
"cobalt",
|
|
3651
|
+
"azure"
|
|
3652
|
+
],
|
|
3653
|
+
([h, s]) => inHue(h, 196, 250) && s >= .25
|
|
3654
|
+
],
|
|
3655
|
+
[
|
|
3656
|
+
"navy",
|
|
3657
|
+
["indigo"],
|
|
3658
|
+
([h, s, l]) => inHue(h, 205, 255) && s >= .2 && l <= .35
|
|
3659
|
+
],
|
|
3660
|
+
[
|
|
3661
|
+
"purple",
|
|
3662
|
+
[
|
|
3663
|
+
"violet",
|
|
3664
|
+
"plum",
|
|
3665
|
+
"lavender",
|
|
3666
|
+
"lilac"
|
|
3667
|
+
],
|
|
3668
|
+
([h, s]) => inHue(h, 251, 295) && s >= .2
|
|
3669
|
+
],
|
|
3670
|
+
[
|
|
3671
|
+
"pink",
|
|
3672
|
+
[
|
|
3673
|
+
"rose",
|
|
3674
|
+
"blush",
|
|
3675
|
+
"fuchsia",
|
|
3676
|
+
"magenta",
|
|
3677
|
+
"berry"
|
|
3678
|
+
],
|
|
3679
|
+
([h, s, l]) => inHue(h, 296, 344) && s >= .3 && l >= .3
|
|
3680
|
+
],
|
|
3681
|
+
[
|
|
3682
|
+
"brown",
|
|
3683
|
+
[
|
|
3684
|
+
"chocolate",
|
|
3685
|
+
"coffee",
|
|
3686
|
+
"camel",
|
|
3687
|
+
"rust",
|
|
3688
|
+
"terracotta"
|
|
3689
|
+
],
|
|
3690
|
+
([h, s, l]) => inHue(h, 10, 45) && s >= .2 && l <= .45
|
|
3691
|
+
],
|
|
3692
|
+
[
|
|
3693
|
+
"beige",
|
|
3694
|
+
[
|
|
3695
|
+
"cream",
|
|
3696
|
+
"sand",
|
|
3697
|
+
"tan",
|
|
3698
|
+
"ivory"
|
|
3699
|
+
],
|
|
3700
|
+
([h, s, l]) => inHue(h, 25, 60) && s >= .1 && l >= .6
|
|
3701
|
+
],
|
|
3702
|
+
[
|
|
3703
|
+
"grey",
|
|
3704
|
+
[
|
|
3705
|
+
"gray",
|
|
3706
|
+
"slate",
|
|
3707
|
+
"silver",
|
|
3708
|
+
"charcoal",
|
|
3709
|
+
"monochrome"
|
|
3710
|
+
],
|
|
3711
|
+
([, s]) => s < .14
|
|
3712
|
+
],
|
|
3713
|
+
[
|
|
3714
|
+
"black",
|
|
3715
|
+
["dark"],
|
|
3716
|
+
([, , l]) => l <= .18
|
|
3717
|
+
],
|
|
3718
|
+
[
|
|
3719
|
+
"white",
|
|
3720
|
+
["light"],
|
|
3721
|
+
([, , l]) => l >= .9
|
|
3722
|
+
]
|
|
3723
|
+
];
|
|
3724
|
+
var WORDS = [...COLOURS.map(([word]) => word), ...COLOURS.flatMap(([, aliases]) => aliases)];
|
|
3725
|
+
var hslOf = (hex) => rgbToHsl(hexToRgb(hex));
|
|
3726
|
+
/**
|
|
3727
|
+
* The colour test for a search, or null if it isn't a colour word. "reds" and "Red" count too.
|
|
3728
|
+
* @returns {((tokens: Record<string, string>) => boolean) | null}
|
|
3729
|
+
*/
|
|
3730
|
+
function colourMatcher(query) {
|
|
3731
|
+
const q = query.trim().toLowerCase().replace(/s$/, "");
|
|
3732
|
+
const found = COLOURS.find(([word, aliases]) => word === q || aliases.includes(q));
|
|
3733
|
+
if (!found) return null;
|
|
3734
|
+
const [, , test] = found;
|
|
3735
|
+
const keys = ["black", "white"].includes(found[0]) ? [
|
|
3736
|
+
"primary",
|
|
3737
|
+
"primary-dark",
|
|
3738
|
+
"background"
|
|
3739
|
+
] : ["primary", "primary-alt"];
|
|
3740
|
+
return (tokens) => keys.some((k) => tokens[k] && test(hslOf(tokens[k])));
|
|
3741
|
+
}
|
|
3742
|
+
/** Words that finish what's being typed (at most `max`), colours first, then `extra` (e.g. moods). */
|
|
3743
|
+
function suggestWords(query, extra = [], max = 6) {
|
|
3744
|
+
const q = query.trim().toLowerCase();
|
|
3745
|
+
if (!q) return [];
|
|
3746
|
+
const starts = [...WORDS, ...extra.map((w) => w.toLowerCase())].filter((w) => w.startsWith(q) && w !== q);
|
|
3747
|
+
return [...new Set(starts)].slice(0, max);
|
|
3748
|
+
}
|
|
3749
|
+
//#endregion
|
|
2928
3750
|
//#region src/ThemePanel.jsx
|
|
2929
3751
|
var PANEL_DARK = "#18181b";
|
|
2930
|
-
var SWATCH_KEYS = [
|
|
2931
|
-
"primary",
|
|
2932
|
-
"primary-alt",
|
|
2933
|
-
"primary-dark",
|
|
2934
|
-
"secondary",
|
|
2935
|
-
"background",
|
|
2936
|
-
"ink",
|
|
2937
|
-
"data-1",
|
|
2938
|
-
"data-2",
|
|
2939
|
-
"data-3",
|
|
2940
|
-
"data-4"
|
|
2941
|
-
];
|
|
2942
3752
|
var btn = "inline-flex items-center justify-center gap-1.5 rounded-lg border border-zinc-300 bg-white px-2.5 py-1.5 text-xs font-medium text-zinc-800 hover:bg-zinc-50 disabled:opacity-50 cursor-pointer focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-zinc-900 focus-visible:ring-offset-1";
|
|
2943
3753
|
var btnPrimary = "inline-flex items-center justify-center gap-1.5 rounded-lg bg-zinc-900 px-2.5 py-1.5 text-xs font-medium text-white hover:bg-zinc-700 disabled:opacity-50 cursor-pointer focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-zinc-900 focus-visible:ring-offset-2";
|
|
2944
3754
|
var field = "w-full rounded-lg border border-zinc-300 bg-white px-2.5 py-1.5 text-sm text-zinc-900 placeholder:text-zinc-500 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-zinc-900";
|
|
@@ -2972,7 +3782,12 @@ function useSavedToYours() {
|
|
|
2972
3782
|
});
|
|
2973
3783
|
};
|
|
2974
3784
|
}
|
|
2975
|
-
|
|
3785
|
+
/**
|
|
3786
|
+
* The panel's contents. It stays mounted while the panel is closed (see ThemeSwitcher), so closing
|
|
3787
|
+
* it is like minimising: the chosen group or mood, a search, open sections and the view all stay.
|
|
3788
|
+
* `open` brings the scroll position back, since a hidden panel can't keep its own.
|
|
3789
|
+
*/
|
|
3790
|
+
function ThemePanel({ open = true }) {
|
|
2976
3791
|
const theme = useTheme();
|
|
2977
3792
|
const { settings, mode, audit, update } = useSettings();
|
|
2978
3793
|
const overrideCount = Object.keys(theme.state.overrides).length;
|
|
@@ -2981,6 +3796,11 @@ function ThemePanel() {
|
|
|
2981
3796
|
const rootRef = useRef(null);
|
|
2982
3797
|
const [toasts, setToasts] = useState([]);
|
|
2983
3798
|
const [reveal, setReveal] = useState(null);
|
|
3799
|
+
const scrollTop = useRef(0);
|
|
3800
|
+
useLayoutEffect(() => {
|
|
3801
|
+
const el = rootRef.current;
|
|
3802
|
+
if (open && el) el.scrollTop = scrollTop.current;
|
|
3803
|
+
}, [open]);
|
|
2984
3804
|
const toast = useCallback((text, action) => setToasts((list) => [...list.slice(-2), {
|
|
2985
3805
|
id: ++toastSeq,
|
|
2986
3806
|
text,
|
|
@@ -3023,32 +3843,32 @@ function ThemePanel() {
|
|
|
3023
3843
|
value: panelApi,
|
|
3024
3844
|
children: [/* @__PURE__ */ jsxs("div", {
|
|
3025
3845
|
ref: rootRef,
|
|
3846
|
+
onScroll: (e) => {
|
|
3847
|
+
if (open) scrollTop.current = e.currentTarget.scrollTop;
|
|
3848
|
+
},
|
|
3026
3849
|
className: "theme-scroll @container flex min-h-0 flex-1 flex-col overflow-y-auto overscroll-contain rounded-[inherit]",
|
|
3027
3850
|
children: [
|
|
3028
3851
|
/* @__PURE__ */ jsxs("header", {
|
|
3029
|
-
className: "sticky top-0 z-10 flex items-
|
|
3852
|
+
className: "sticky top-0 z-10 flex flex-wrap items-center justify-between gap-x-3 gap-y-3.5 border-b border-zinc-200 bg-white px-4 py-3",
|
|
3030
3853
|
children: [/* @__PURE__ */ jsxs("div", {
|
|
3031
|
-
className: "flex
|
|
3854
|
+
className: "flex w-full shrink-0 items-center justify-center gap-2 @min-[520px]:w-auto @min-[520px]:justify-start",
|
|
3032
3855
|
children: [/* @__PURE__ */ jsx(LogoMark, {
|
|
3033
3856
|
tokens: theme.tokens,
|
|
3034
3857
|
background: mode === "dark" ? PANEL_DARK : "#ffffff",
|
|
3035
3858
|
className: "h-7 w-auto shrink-0"
|
|
3036
|
-
}), /* @__PURE__ */ jsxs("div", {
|
|
3037
|
-
|
|
3038
|
-
|
|
3039
|
-
|
|
3040
|
-
className: "text-
|
|
3041
|
-
children:
|
|
3042
|
-
className: "align-super text-[10px] font-medium",
|
|
3043
|
-
children: "™"
|
|
3044
|
-
})]
|
|
3045
|
-
}), /* @__PURE__ */ jsx("p", {
|
|
3046
|
-
className: "text-[11px] text-zinc-500",
|
|
3047
|
-
children: "by mrmaxdesigns"
|
|
3859
|
+
}), /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsxs("h2", {
|
|
3860
|
+
id: "theme-panel-title",
|
|
3861
|
+
className: "text-base font-semibold tracking-tight",
|
|
3862
|
+
children: ["colorsbymax", /* @__PURE__ */ jsx("span", {
|
|
3863
|
+
className: "align-super text-[10px] font-medium",
|
|
3864
|
+
children: "™"
|
|
3048
3865
|
})]
|
|
3049
|
-
})
|
|
3866
|
+
}), /* @__PURE__ */ jsx("p", {
|
|
3867
|
+
className: "text-[11px] text-zinc-500",
|
|
3868
|
+
children: "by mrmaxdesigns"
|
|
3869
|
+
})] })]
|
|
3050
3870
|
}), /* @__PURE__ */ jsxs("div", {
|
|
3051
|
-
className: "flex items-center gap-1",
|
|
3871
|
+
className: "flex w-full items-center justify-center gap-1 @min-[520px]:ml-auto @min-[520px]:w-auto",
|
|
3052
3872
|
children: [
|
|
3053
3873
|
/* @__PURE__ */ jsx("div", {
|
|
3054
3874
|
role: "radiogroup",
|
|
@@ -3071,7 +3891,7 @@ function ThemePanel() {
|
|
|
3071
3891
|
}, id);
|
|
3072
3892
|
})
|
|
3073
3893
|
}),
|
|
3074
|
-
/* @__PURE__ */ jsxs("button", {
|
|
3894
|
+
theme.features.addToSite && /* @__PURE__ */ jsxs("button", {
|
|
3075
3895
|
type: "button",
|
|
3076
3896
|
onClick: (e) => view === "mode-toggle" ? setView("main") : showView("mode-toggle", e.currentTarget),
|
|
3077
3897
|
className: `${btn} shrink-0 whitespace-nowrap px-1.5 @min-[500px]:px-2 ${view === "mode-toggle" ? "border-zinc-900 bg-zinc-100" : "border-transparent"}`,
|
|
@@ -3086,7 +3906,7 @@ function ThemePanel() {
|
|
|
3086
3906
|
children: "Add to site"
|
|
3087
3907
|
})]
|
|
3088
3908
|
}),
|
|
3089
|
-
/* @__PURE__ */ jsxs("button", {
|
|
3909
|
+
theme.features.audit && /* @__PURE__ */ jsxs("button", {
|
|
3090
3910
|
type: "button",
|
|
3091
3911
|
onClick: audit.toggle,
|
|
3092
3912
|
className: `${btn} px-2 ${audit.on ? "border-zinc-900 bg-zinc-100" : "border-transparent"}`,
|
|
@@ -3123,7 +3943,6 @@ function ThemePanel() {
|
|
|
3123
3943
|
children: [
|
|
3124
3944
|
/* @__PURE__ */ jsx(Section, {
|
|
3125
3945
|
title: "Preset themes",
|
|
3126
|
-
defaultOpen: true,
|
|
3127
3946
|
children: /* @__PURE__ */ jsx(PresetGrid, {})
|
|
3128
3947
|
}),
|
|
3129
3948
|
settings.showCustom && /* @__PURE__ */ jsx(Section, {
|
|
@@ -3423,8 +4242,9 @@ var FINISH_OPTIONS = [
|
|
|
3423
4242
|
* here only, or remove colorsbymax, each with code and a prompt for an AI editor. Cancel goes back.
|
|
3424
4243
|
*/
|
|
3425
4244
|
function FinishView({ onBack }) {
|
|
3426
|
-
const { tokens, active, recolouring } = useTheme();
|
|
3427
|
-
const { update } = useSettings();
|
|
4245
|
+
const { tokens: themeTokens, active, recolouring } = useTheme();
|
|
4246
|
+
const { settings, update } = useSettings();
|
|
4247
|
+
const tokens = !recolouring && settings.colourStyle === "subtle" ? subtleTokens(themeTokens) : themeTokens;
|
|
3428
4248
|
const [choice, setChoice] = useState("keep");
|
|
3429
4249
|
const [kind, setKind] = useState(() => document.querySelector("[data-colorsbymax=\"auto\"]") ? "auto" : "provider");
|
|
3430
4250
|
const headingRef = useRef(null);
|
|
@@ -3671,6 +4491,7 @@ var MODES = [
|
|
|
3671
4491
|
/** The visitor's preferences for the panel and colour button. */
|
|
3672
4492
|
function SettingsView({ onBack }) {
|
|
3673
4493
|
const { settings, update, reset, resetButton } = useSettings();
|
|
4494
|
+
const { active, features } = useTheme();
|
|
3674
4495
|
const { toast } = usePanel();
|
|
3675
4496
|
const headingRef = useRef(null);
|
|
3676
4497
|
useEffect(() => headingRef.current?.focus(), []);
|
|
@@ -3727,6 +4548,40 @@ function SettingsView({ onBack }) {
|
|
|
3727
4548
|
})
|
|
3728
4549
|
]
|
|
3729
4550
|
}),
|
|
4551
|
+
features.colourCount && /* @__PURE__ */ jsxs("fieldset", {
|
|
4552
|
+
className: "space-y-1.5",
|
|
4553
|
+
children: [
|
|
4554
|
+
/* @__PURE__ */ jsx("legend", {
|
|
4555
|
+
className: "mb-1 text-[11px] font-semibold uppercase tracking-wide text-zinc-600",
|
|
4556
|
+
children: "Colours per theme"
|
|
4557
|
+
}),
|
|
4558
|
+
/* @__PURE__ */ jsxs("div", {
|
|
4559
|
+
className: "flex items-center gap-3 rounded-xl border border-zinc-200 p-2.5",
|
|
4560
|
+
children: [/* @__PURE__ */ jsx("div", {
|
|
4561
|
+
className: "min-w-0 flex-1",
|
|
4562
|
+
children: /* @__PURE__ */ jsx(Swatches, {
|
|
4563
|
+
tokens: active.tokens,
|
|
4564
|
+
count: settings.paletteSize
|
|
4565
|
+
})
|
|
4566
|
+
}), /* @__PURE__ */ jsx(ColourStepper, {
|
|
4567
|
+
value: settings.paletteSize,
|
|
4568
|
+
onChange: (n) => update({ paletteSize: n }),
|
|
4569
|
+
label: "Colours every theme uses",
|
|
4570
|
+
size: "md"
|
|
4571
|
+
})]
|
|
4572
|
+
}),
|
|
4573
|
+
/* @__PURE__ */ jsxs("p", {
|
|
4574
|
+
className: "text-[11px] text-zinc-600",
|
|
4575
|
+
children: [
|
|
4576
|
+
"How many colours every theme uses, from ",
|
|
4577
|
+
5,
|
|
4578
|
+
" to ",
|
|
4579
|
+
10,
|
|
4580
|
+
". Fewer keeps a site calmer, with only a theme’s main colours; the ones that fit it best stay. You can still change it on any theme with − and + on its card."
|
|
4581
|
+
]
|
|
4582
|
+
})
|
|
4583
|
+
]
|
|
4584
|
+
}),
|
|
3730
4585
|
/* @__PURE__ */ jsxs("fieldset", {
|
|
3731
4586
|
className: "space-y-1.5",
|
|
3732
4587
|
children: [
|
|
@@ -3769,29 +4624,29 @@ function SettingsView({ onBack }) {
|
|
|
3769
4624
|
className: "mb-1 text-[11px] font-semibold uppercase tracking-wide text-zinc-600",
|
|
3770
4625
|
children: "Show"
|
|
3771
4626
|
}),
|
|
3772
|
-
/* @__PURE__ */ jsx(Toggle, {
|
|
4627
|
+
features.picks && /* @__PURE__ */ jsx(Toggle, {
|
|
3773
4628
|
checked: settings.showPicks,
|
|
3774
4629
|
onChange: (v) => update({ showPicks: v }),
|
|
3775
4630
|
label: "Max’s picks",
|
|
3776
4631
|
note: "Hand-tuned colorsbymax themes"
|
|
3777
4632
|
}),
|
|
3778
|
-
/* @__PURE__ */ jsx(Toggle, {
|
|
4633
|
+
features.library && /* @__PURE__ */ jsx(Toggle, {
|
|
3779
4634
|
checked: settings.showLibrary,
|
|
3780
4635
|
onChange: (v) => update({ showLibrary: v }),
|
|
3781
4636
|
label: "Theme library",
|
|
3782
4637
|
note: "Hundreds of themes in categories, with search"
|
|
3783
4638
|
}),
|
|
3784
|
-
/* @__PURE__ */ jsx(Toggle, {
|
|
4639
|
+
features.custom && /* @__PURE__ */ jsx(Toggle, {
|
|
3785
4640
|
checked: settings.showCustom,
|
|
3786
4641
|
onChange: (v) => update({ showCustom: v }),
|
|
3787
4642
|
label: "Custom palettes"
|
|
3788
4643
|
}),
|
|
3789
|
-
/* @__PURE__ */ jsx(Toggle, {
|
|
4644
|
+
features.overrides && /* @__PURE__ */ jsx(Toggle, {
|
|
3790
4645
|
checked: settings.showOverrides,
|
|
3791
4646
|
onChange: (v) => update({ showOverrides: v }),
|
|
3792
4647
|
label: "Override a single colour"
|
|
3793
4648
|
}),
|
|
3794
|
-
/* @__PURE__ */ jsx(Toggle, {
|
|
4649
|
+
features.importExport && /* @__PURE__ */ jsx(Toggle, {
|
|
3795
4650
|
checked: settings.showImportExport,
|
|
3796
4651
|
onChange: (v) => update({ showImportExport: v }),
|
|
3797
4652
|
label: "Import / export"
|
|
@@ -4009,20 +4864,78 @@ function IssuesLink() {
|
|
|
4009
4864
|
]
|
|
4010
4865
|
});
|
|
4011
4866
|
}
|
|
4012
|
-
|
|
4867
|
+
/** A theme's colours as a strip: the `count` it uses (5 to 10), its most fitting ones. */
|
|
4868
|
+
function Swatches({ tokens, count = 10 }) {
|
|
4013
4869
|
return /* @__PURE__ */ jsx("div", {
|
|
4014
4870
|
className: "flex overflow-hidden rounded-md border border-zinc-200",
|
|
4015
4871
|
"aria-hidden": "true",
|
|
4016
|
-
children:
|
|
4872
|
+
children: paletteKeys(tokens, count).map((key) => /* @__PURE__ */ jsx("span", {
|
|
4017
4873
|
className: "h-5 flex-1",
|
|
4018
4874
|
style: { background: tokens[key] }
|
|
4019
4875
|
}, key))
|
|
4020
4876
|
});
|
|
4021
4877
|
}
|
|
4878
|
+
/**
|
|
4879
|
+
* − n + for how many colours a theme uses. Each end dims when it's as far as it goes.
|
|
4880
|
+
* @param {{ value: number, onChange: (n: number) => void, label: string, size?: 'sm' | 'md' }} props
|
|
4881
|
+
*/
|
|
4882
|
+
function ColourStepper({ value, onChange, label, size = "sm" }) {
|
|
4883
|
+
const box = size === "sm" ? "h-6 w-6" : "h-8 w-8";
|
|
4884
|
+
const step = (d) => (e) => {
|
|
4885
|
+
e.stopPropagation();
|
|
4886
|
+
onChange(value + d);
|
|
4887
|
+
};
|
|
4888
|
+
return /* @__PURE__ */ jsxs("span", {
|
|
4889
|
+
role: "group",
|
|
4890
|
+
"aria-label": label,
|
|
4891
|
+
className: "inline-flex items-center gap-1",
|
|
4892
|
+
children: [
|
|
4893
|
+
/* @__PURE__ */ jsx("button", {
|
|
4894
|
+
type: "button",
|
|
4895
|
+
onClick: step(-1),
|
|
4896
|
+
disabled: value <= 5,
|
|
4897
|
+
"aria-label": `Fewer colours (${value} now)`,
|
|
4898
|
+
"data-tip": value <= 5 ? `5 is the fewest` : "Use fewer colours",
|
|
4899
|
+
className: `${box} grid place-items-center rounded-full border border-zinc-300 bg-white text-zinc-800 cursor-pointer hover:border-zinc-900 disabled:cursor-default disabled:opacity-35 disabled:hover:border-zinc-300 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-zinc-900`,
|
|
4900
|
+
children: /* @__PURE__ */ jsx(Minus, {
|
|
4901
|
+
className: "w-3.5 h-3.5",
|
|
4902
|
+
"aria-hidden": "true"
|
|
4903
|
+
})
|
|
4904
|
+
}),
|
|
4905
|
+
/* @__PURE__ */ jsx("span", {
|
|
4906
|
+
className: "min-w-[1.25rem] text-center text-xs font-semibold tabular-nums text-zinc-900",
|
|
4907
|
+
"aria-live": "polite",
|
|
4908
|
+
children: value
|
|
4909
|
+
}),
|
|
4910
|
+
/* @__PURE__ */ jsx("button", {
|
|
4911
|
+
type: "button",
|
|
4912
|
+
onClick: step(1),
|
|
4913
|
+
disabled: value >= 10,
|
|
4914
|
+
"aria-label": `More colours (${value} now)`,
|
|
4915
|
+
"data-tip": value >= 10 ? `10 is every colour` : "Use more colours",
|
|
4916
|
+
className: `${box} grid place-items-center rounded-full border border-zinc-300 bg-white text-zinc-800 cursor-pointer hover:border-zinc-900 disabled:cursor-default disabled:opacity-35 disabled:hover:border-zinc-300 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-zinc-900`,
|
|
4917
|
+
children: /* @__PURE__ */ jsx(Plus, {
|
|
4918
|
+
className: "w-3.5 h-3.5",
|
|
4919
|
+
"aria-hidden": "true"
|
|
4920
|
+
})
|
|
4921
|
+
})
|
|
4922
|
+
]
|
|
4923
|
+
});
|
|
4924
|
+
}
|
|
4022
4925
|
var PAGE_SIZE = 24;
|
|
4023
4926
|
var NO_THEMES = [];
|
|
4927
|
+
var COLOUR_STYLES = [{
|
|
4928
|
+
id: "subtle",
|
|
4929
|
+
label: "Subtle",
|
|
4930
|
+
Icon: Contrast
|
|
4931
|
+
}, {
|
|
4932
|
+
id: "colourful",
|
|
4933
|
+
label: "Colourful",
|
|
4934
|
+
Icon: Paintbrush
|
|
4935
|
+
}];
|
|
4024
4936
|
function PresetGrid() {
|
|
4025
|
-
const { siteName, siteThemes, presets: allPresets, customs, active, selectTheme, state, clearOverrides } = useTheme();
|
|
4937
|
+
const { siteName, siteThemes, presets: allPresets, customs, active, selectTheme, state, clearOverrides, tokens, recolouring, features } = useTheme();
|
|
4938
|
+
const surpriseBurst = useBurst();
|
|
4026
4939
|
const { settings, mode, update } = useSettings();
|
|
4027
4940
|
const categoriesId = useId();
|
|
4028
4941
|
const [loaded, setLoaded] = useState(null);
|
|
@@ -4051,6 +4964,8 @@ function PresetGrid() {
|
|
|
4051
4964
|
if (scrollToThemes.current && themesRef.current) {
|
|
4052
4965
|
scrollToThemes.current = false;
|
|
4053
4966
|
const still = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
|
|
4967
|
+
const header = themesRef.current.closest(".theme-scroll")?.querySelector("header");
|
|
4968
|
+
themesRef.current.style.scrollMarginTop = `${(header?.offsetHeight ?? 0) + 12}px`;
|
|
4054
4969
|
themesRef.current.scrollIntoView({
|
|
4055
4970
|
block: "start",
|
|
4056
4971
|
behavior: still ? "auto" : "smooth"
|
|
@@ -4125,7 +5040,9 @@ function PresetGrid() {
|
|
|
4125
5040
|
else list = (library?.themes ?? []).filter((t) => t.tags.includes(category));
|
|
4126
5041
|
if (q) {
|
|
4127
5042
|
const labels = Object.fromEntries((library?.categories ?? []).map((c) => [c.id, c.label.toLowerCase()]));
|
|
4128
|
-
|
|
5043
|
+
const byName = (t) => t.name.toLowerCase().includes(q) || t.tags?.some((tag) => labels[tag]?.includes(q));
|
|
5044
|
+
const byColour = colourMatcher(q);
|
|
5045
|
+
list = [...list.filter(byName), ...byColour ? list.filter((t) => !byName(t) && byColour(t.tokens)) : []];
|
|
4129
5046
|
}
|
|
4130
5047
|
return list;
|
|
4131
5048
|
}, [
|
|
@@ -4151,14 +5068,20 @@ function PresetGrid() {
|
|
|
4151
5068
|
};
|
|
4152
5069
|
const pick = (t) => selectTheme(t.id, t);
|
|
4153
5070
|
const surprise = () => {
|
|
4154
|
-
const
|
|
5071
|
+
const everything = library?.themes ?? [...siteThemes, ...presets];
|
|
5072
|
+
const pool = (visible.length > 1 ? visible : everything).filter((t) => t.id !== active.id && inMode(t, mode).id !== active.id);
|
|
5073
|
+
if (!pool.length) return;
|
|
4155
5074
|
pick(inMode(pool[Math.floor(Math.random() * pool.length)], mode));
|
|
5075
|
+
surpriseBurst.celebrate();
|
|
4156
5076
|
};
|
|
5077
|
+
const suggestions = suggestWords(query, categories.map((c) => c.label));
|
|
5078
|
+
const themeCount = (library?.themes.length ?? 0) + presets.length + siteThemes.length + customs.length;
|
|
5079
|
+
const roughCount = themeCount >= 100 ? `${Math.floor(themeCount / 100) * 100}+` : themeCount;
|
|
4157
5080
|
return /* @__PURE__ */ jsxs("div", {
|
|
4158
5081
|
ref: wrapRef,
|
|
4159
5082
|
className: "space-y-3",
|
|
4160
5083
|
children: [
|
|
4161
|
-
/* @__PURE__ */ jsx(ScanCard, {}),
|
|
5084
|
+
features.scan && /* @__PURE__ */ jsx(ScanCard, {}),
|
|
4162
5085
|
/* @__PURE__ */ jsxs("p", {
|
|
4163
5086
|
className: "text-xs text-zinc-600",
|
|
4164
5087
|
children: ["Current theme: ", /* @__PURE__ */ jsx("strong", {
|
|
@@ -4166,6 +5089,31 @@ function PresetGrid() {
|
|
|
4166
5089
|
children: active.name
|
|
4167
5090
|
})]
|
|
4168
5091
|
}),
|
|
5092
|
+
features.colourStyle && /* @__PURE__ */ jsxs("div", {
|
|
5093
|
+
className: "rounded-xl border border-zinc-200 p-2.5",
|
|
5094
|
+
children: [/* @__PURE__ */ jsx("div", {
|
|
5095
|
+
role: "radiogroup",
|
|
5096
|
+
"aria-label": "Colour style",
|
|
5097
|
+
className: "grid grid-cols-2 gap-1 rounded-lg bg-zinc-100 p-1",
|
|
5098
|
+
children: COLOUR_STYLES.map(({ id, label, Icon }) => {
|
|
5099
|
+
const on = settings.colourStyle === id;
|
|
5100
|
+
return /* @__PURE__ */ jsxs("button", {
|
|
5101
|
+
type: "button",
|
|
5102
|
+
role: "radio",
|
|
5103
|
+
"aria-checked": on,
|
|
5104
|
+
onClick: () => update({ colourStyle: id }),
|
|
5105
|
+
className: `inline-flex h-8 cursor-pointer items-center justify-center gap-1.5 rounded-md text-xs font-semibold focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-zinc-900 ${on ? "bg-white text-zinc-900 shadow-sm" : "text-zinc-600 hover:text-zinc-900"}`,
|
|
5106
|
+
children: [/* @__PURE__ */ jsx(Icon, {
|
|
5107
|
+
className: "w-3.5 h-3.5",
|
|
5108
|
+
"aria-hidden": "true"
|
|
5109
|
+
}), label]
|
|
5110
|
+
}, id);
|
|
5111
|
+
})
|
|
5112
|
+
}), /* @__PURE__ */ jsx("p", {
|
|
5113
|
+
className: "mt-2 px-0.5 text-[11px] leading-snug text-zinc-600",
|
|
5114
|
+
children: settings.colourStyle === "colourful" ? "Colourful: the theme paints your header, hero, sections, cards, buttons and footer, like a designer would." : recolouring ? "Subtle: the theme only swaps the colours your site already has." : "Subtle: calm, nearly neutral backgrounds and cards, with the theme’s colour on buttons, links and highlights."
|
|
5115
|
+
})]
|
|
5116
|
+
}),
|
|
4169
5117
|
overrideCount > 0 && /* @__PURE__ */ jsxs("p", {
|
|
4170
5118
|
className: "flex items-center justify-between gap-2 rounded-lg bg-zinc-100 px-3 py-2 text-xs text-zinc-700",
|
|
4171
5119
|
children: [
|
|
@@ -4184,38 +5132,94 @@ function PresetGrid() {
|
|
|
4184
5132
|
})
|
|
4185
5133
|
]
|
|
4186
5134
|
}),
|
|
4187
|
-
/* @__PURE__ */ jsxs("div", {
|
|
5135
|
+
(features.search || features.surprise) && /* @__PURE__ */ jsxs("div", {
|
|
4188
5136
|
className: "flex gap-2",
|
|
4189
|
-
children: [
|
|
4190
|
-
|
|
4191
|
-
|
|
4192
|
-
|
|
4193
|
-
|
|
4194
|
-
|
|
4195
|
-
|
|
4196
|
-
|
|
4197
|
-
|
|
4198
|
-
|
|
4199
|
-
|
|
4200
|
-
value
|
|
4201
|
-
|
|
4202
|
-
|
|
4203
|
-
|
|
4204
|
-
|
|
4205
|
-
}
|
|
4206
|
-
|
|
4207
|
-
|
|
4208
|
-
|
|
4209
|
-
|
|
4210
|
-
disabled: !library && needsLibrary,
|
|
4211
|
-
children: [/* @__PURE__ */ jsx(Shuffle, {
|
|
5137
|
+
children: [features.search && /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("label", {
|
|
5138
|
+
htmlFor: searchId,
|
|
5139
|
+
className: "sr-only",
|
|
5140
|
+
children: "Search themes"
|
|
5141
|
+
}), /* @__PURE__ */ jsx("input", {
|
|
5142
|
+
id: searchId,
|
|
5143
|
+
type: "search",
|
|
5144
|
+
className: field,
|
|
5145
|
+
placeholder: `Search ${roughCount} themes…`,
|
|
5146
|
+
value: query,
|
|
5147
|
+
onChange: (e) => {
|
|
5148
|
+
setQuery(e.target.value);
|
|
5149
|
+
setLimit(PAGE_SIZE);
|
|
5150
|
+
}
|
|
5151
|
+
})] }), features.surprise && /* @__PURE__ */ jsxs("button", {
|
|
5152
|
+
type: "button",
|
|
5153
|
+
className: `${btn} relative shrink-0 ${features.search ? "" : "flex-1"}`,
|
|
5154
|
+
onClick: surprise,
|
|
5155
|
+
disabled: !library && needsLibrary,
|
|
5156
|
+
children: [
|
|
5157
|
+
/* @__PURE__ */ jsx(Shuffle, {
|
|
4212
5158
|
className: "w-3.5 h-3.5",
|
|
4213
5159
|
"aria-hidden": "true"
|
|
4214
|
-
}),
|
|
5160
|
+
}),
|
|
5161
|
+
/* @__PURE__ */ jsxs("span", { children: ["Surprise", /* @__PURE__ */ jsx("span", {
|
|
5162
|
+
className: "hidden @min-[400px]:inline",
|
|
5163
|
+
children: " me"
|
|
5164
|
+
})] }),
|
|
5165
|
+
surpriseBurst.bursting && /* @__PURE__ */ jsx(Burst, {
|
|
5166
|
+
tokens,
|
|
5167
|
+
spread: 1.7
|
|
5168
|
+
}, surpriseBurst.burst)
|
|
5169
|
+
]
|
|
5170
|
+
})]
|
|
5171
|
+
}),
|
|
5172
|
+
suggestions.length > 0 && /* @__PURE__ */ jsxs("div", {
|
|
5173
|
+
role: "group",
|
|
5174
|
+
"aria-label": "Suggestions",
|
|
5175
|
+
className: "-mt-1 flex flex-wrap items-center gap-1.5",
|
|
5176
|
+
children: [/* @__PURE__ */ jsx("span", {
|
|
5177
|
+
className: "text-[11px] text-zinc-500",
|
|
5178
|
+
children: "Try"
|
|
5179
|
+
}), suggestions.map((w) => /* @__PURE__ */ jsx("button", {
|
|
5180
|
+
type: "button",
|
|
5181
|
+
onClick: () => {
|
|
5182
|
+
setQuery(w);
|
|
5183
|
+
setLimit(PAGE_SIZE);
|
|
5184
|
+
},
|
|
5185
|
+
className: "rounded-full border border-zinc-300 bg-white px-2.5 py-0.5 text-xs font-medium text-zinc-800 capitalize hover:border-zinc-900 cursor-pointer focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-zinc-900",
|
|
5186
|
+
children: w
|
|
5187
|
+
}, w))]
|
|
5188
|
+
}),
|
|
5189
|
+
q && /* @__PURE__ */ jsxs("div", {
|
|
5190
|
+
className: "flex items-center justify-between gap-2",
|
|
5191
|
+
children: [/* @__PURE__ */ jsxs("p", {
|
|
5192
|
+
className: "text-xs text-zinc-600",
|
|
5193
|
+
role: "status",
|
|
5194
|
+
children: [
|
|
5195
|
+
visible.length,
|
|
5196
|
+
" ",
|
|
5197
|
+
visible.length === 1 ? "theme" : "themes",
|
|
5198
|
+
" for “",
|
|
5199
|
+
query.trim(),
|
|
5200
|
+
"”"
|
|
5201
|
+
]
|
|
5202
|
+
}), /* @__PURE__ */ jsx("div", {
|
|
5203
|
+
role: "radiogroup",
|
|
5204
|
+
"aria-label": "Show them in",
|
|
5205
|
+
className: "flex shrink-0 items-center rounded-lg border border-zinc-200 p-0.5",
|
|
5206
|
+
children: MODES.filter((m) => m.id !== "system").map(({ id, label, Icon }) => {
|
|
5207
|
+
const on = mode === id;
|
|
5208
|
+
return /* @__PURE__ */ jsxs("button", {
|
|
5209
|
+
type: "button",
|
|
5210
|
+
role: "radio",
|
|
5211
|
+
"aria-checked": on,
|
|
5212
|
+
onClick: () => update({ mode: id }),
|
|
5213
|
+
className: `inline-flex h-7 items-center gap-1 rounded-md px-2 text-xs font-semibold cursor-pointer focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-zinc-900 ${on ? "bg-zinc-900 text-white" : "text-zinc-600 hover:bg-zinc-100 hover:text-zinc-900"}`,
|
|
5214
|
+
children: [/* @__PURE__ */ jsx(Icon, {
|
|
5215
|
+
className: "w-3.5 h-3.5",
|
|
5216
|
+
"aria-hidden": "true"
|
|
5217
|
+
}), label]
|
|
5218
|
+
}, id);
|
|
4215
5219
|
})
|
|
4216
|
-
]
|
|
5220
|
+
})]
|
|
4217
5221
|
}),
|
|
4218
|
-
/* @__PURE__ */ jsx("div", {
|
|
5222
|
+
!q && /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("div", {
|
|
4219
5223
|
role: "group",
|
|
4220
5224
|
"aria-label": "Your groups",
|
|
4221
5225
|
"data-groups": true,
|
|
@@ -4226,77 +5230,87 @@ function PresetGrid() {
|
|
|
4226
5230
|
type: "button",
|
|
4227
5231
|
"aria-pressed": on,
|
|
4228
5232
|
"data-tip": `${g.description} (${g.count} ${g.count === 1 ? "theme" : "themes"})`,
|
|
4229
|
-
onClick: () => choose(g.id),
|
|
4230
|
-
className: `flex h-12 min-w-0 flex-col items-center justify-center gap-
|
|
5233
|
+
onClick: () => choose(g.id, { scroll: true }),
|
|
5234
|
+
className: `flex min-h-12 min-w-0 flex-col items-center justify-center gap-1 rounded-xl border px-1.5 py-2 text-[11px] leading-tight font-semibold @min-[460px]:h-10 @min-[460px]:min-h-0 @min-[460px]:flex-row @min-[460px]:justify-start @min-[460px]:gap-1.5 @min-[460px]:px-2.5 @min-[460px]:py-0 @min-[460px]:text-xs cursor-pointer focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-zinc-900 focus-visible:ring-offset-1 ${on ? "border-zinc-900 bg-zinc-900 text-white shadow-sm" : "border-zinc-200 bg-zinc-100 text-zinc-900 hover:bg-zinc-200"}`,
|
|
4231
5235
|
children: [
|
|
4232
5236
|
/* @__PURE__ */ jsx(g.Icon, {
|
|
4233
5237
|
className: "w-4 h-4 shrink-0",
|
|
4234
5238
|
"aria-hidden": "true"
|
|
4235
5239
|
}),
|
|
4236
5240
|
/* @__PURE__ */ jsx("span", {
|
|
4237
|
-
className: "max-w-full truncate",
|
|
5241
|
+
className: "max-w-full text-center break-words @min-[460px]:truncate @min-[460px]:text-left",
|
|
4238
5242
|
children: g.label
|
|
4239
5243
|
}),
|
|
4240
5244
|
/* @__PURE__ */ jsx("span", {
|
|
4241
|
-
className: `ml-auto hidden pl-1 font-medium tabular-nums @min-[
|
|
5245
|
+
className: `ml-auto hidden pl-1 font-medium tabular-nums @min-[460px]:inline ${on ? "text-zinc-300" : "text-zinc-500"}`,
|
|
4242
5246
|
children: g.count
|
|
4243
5247
|
})
|
|
4244
5248
|
]
|
|
4245
5249
|
}, g.id);
|
|
4246
5250
|
})
|
|
4247
|
-
}),
|
|
4248
|
-
|
|
4249
|
-
|
|
4250
|
-
"
|
|
4251
|
-
|
|
4252
|
-
|
|
4253
|
-
|
|
4254
|
-
|
|
4255
|
-
|
|
4256
|
-
|
|
4257
|
-
|
|
4258
|
-
|
|
4259
|
-
|
|
4260
|
-
|
|
4261
|
-
|
|
4262
|
-
|
|
4263
|
-
|
|
4264
|
-
|
|
4265
|
-
|
|
4266
|
-
|
|
4267
|
-
|
|
4268
|
-
|
|
4269
|
-
|
|
4270
|
-
|
|
4271
|
-
|
|
4272
|
-
|
|
4273
|
-
|
|
4274
|
-
|
|
4275
|
-
className: "grid grid-cols-2 @min-[380px]:grid-cols-3 gap-2",
|
|
4276
|
-
children: categories.map((c) => {
|
|
4277
|
-
const on = !q && category === c.id;
|
|
4278
|
-
return /* @__PURE__ */ jsxs("button", {
|
|
4279
|
-
type: "button",
|
|
4280
|
-
"aria-pressed": on,
|
|
4281
|
-
"data-tip": c.description,
|
|
4282
|
-
onClick: () => choose(c.id, { scroll: true }),
|
|
4283
|
-
className: `flex h-8 min-w-0 items-center gap-1 rounded-lg border px-2 text-xs font-medium cursor-pointer focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-zinc-900 focus-visible:ring-offset-1 ${on ? "border-zinc-900 bg-zinc-900 text-white" : "border-zinc-300 bg-white text-zinc-800 hover:bg-zinc-50"}`,
|
|
4284
|
-
children: [
|
|
4285
|
-
on && /* @__PURE__ */ jsx(Check, {
|
|
4286
|
-
className: "w-3 h-3 shrink-0",
|
|
5251
|
+
}), categories.length > 0 && /* @__PURE__ */ jsxs("section", {
|
|
5252
|
+
"aria-label": "Theme library",
|
|
5253
|
+
className: "rounded-xl border border-zinc-200 bg-zinc-50 p-2.5",
|
|
5254
|
+
children: [/* @__PURE__ */ jsxs("button", {
|
|
5255
|
+
type: "button",
|
|
5256
|
+
"aria-expanded": !settings.libraryCollapsed,
|
|
5257
|
+
"aria-controls": categoriesId,
|
|
5258
|
+
onClick: () => update({ libraryCollapsed: !settings.libraryCollapsed }),
|
|
5259
|
+
className: "flex w-full items-center gap-2.5 rounded-lg px-1 py-0.5 text-left cursor-pointer focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-zinc-900",
|
|
5260
|
+
children: [
|
|
5261
|
+
/* @__PURE__ */ jsx(LibraryBig, {
|
|
5262
|
+
className: "h-5 w-5 shrink-0 text-zinc-700",
|
|
5263
|
+
"aria-hidden": "true"
|
|
5264
|
+
}),
|
|
5265
|
+
/* @__PURE__ */ jsxs("span", {
|
|
5266
|
+
className: "min-w-0 flex-1",
|
|
5267
|
+
children: [/* @__PURE__ */ jsx("span", {
|
|
5268
|
+
className: "block text-sm font-semibold text-zinc-900",
|
|
5269
|
+
children: "Library"
|
|
5270
|
+
}), /* @__PURE__ */ jsx("span", {
|
|
5271
|
+
className: "block text-[11px] leading-snug text-zinc-600",
|
|
5272
|
+
children: settings.libraryCollapsed && activeCategory ? `Showing ${activeCategory.label}` : `${library ? `${library.themes.length} palettes` : "Palettes"} sorted by mood. Pick one to see its themes.`
|
|
5273
|
+
})]
|
|
5274
|
+
}),
|
|
5275
|
+
/* @__PURE__ */ jsxs("span", {
|
|
5276
|
+
className: "flex shrink-0 items-center gap-1 text-[11px] font-medium text-zinc-600",
|
|
5277
|
+
children: [settings.libraryCollapsed ? "Show" : "Hide", /* @__PURE__ */ jsx(ChevronRight, {
|
|
5278
|
+
className: `w-3.5 h-3.5 transition-transform motion-reduce:transition-none ${settings.libraryCollapsed ? "" : "rotate-90"}`,
|
|
4287
5279
|
"aria-hidden": "true"
|
|
4288
|
-
})
|
|
4289
|
-
|
|
4290
|
-
|
|
4291
|
-
|
|
4292
|
-
|
|
4293
|
-
|
|
4294
|
-
|
|
4295
|
-
|
|
4296
|
-
|
|
4297
|
-
|
|
4298
|
-
|
|
4299
|
-
|
|
5280
|
+
})]
|
|
5281
|
+
})
|
|
5282
|
+
]
|
|
5283
|
+
}), /* @__PURE__ */ jsx("div", {
|
|
5284
|
+
id: categoriesId,
|
|
5285
|
+
hidden: settings.libraryCollapsed,
|
|
5286
|
+
role: "group",
|
|
5287
|
+
"aria-label": "Library moods",
|
|
5288
|
+
className: "mt-2.5 grid grid-cols-2 @min-[380px]:grid-cols-3 gap-2",
|
|
5289
|
+
children: categories.map((c) => {
|
|
5290
|
+
const on = !q && category === c.id;
|
|
5291
|
+
return /* @__PURE__ */ jsxs("button", {
|
|
5292
|
+
type: "button",
|
|
5293
|
+
"aria-pressed": on,
|
|
5294
|
+
"data-tip": c.description,
|
|
5295
|
+
onClick: () => choose(c.id, { scroll: true }),
|
|
5296
|
+
className: `flex h-8 min-w-0 items-center gap-1 rounded-lg border px-2 text-xs font-medium cursor-pointer focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-zinc-900 focus-visible:ring-offset-1 ${on ? "border-zinc-900 bg-zinc-900 text-white" : "border-zinc-300 bg-white text-zinc-800 hover:bg-zinc-50"}`,
|
|
5297
|
+
children: [
|
|
5298
|
+
on && /* @__PURE__ */ jsx(Check, {
|
|
5299
|
+
className: "w-3 h-3 shrink-0",
|
|
5300
|
+
"aria-hidden": "true"
|
|
5301
|
+
}),
|
|
5302
|
+
/* @__PURE__ */ jsx("span", {
|
|
5303
|
+
className: "truncate",
|
|
5304
|
+
children: c.label
|
|
5305
|
+
}),
|
|
5306
|
+
c.count != null && /* @__PURE__ */ jsx("span", {
|
|
5307
|
+
className: `ml-auto pl-1 tabular-nums ${on ? "text-zinc-300" : "text-zinc-500"}`,
|
|
5308
|
+
children: c.count
|
|
5309
|
+
})
|
|
5310
|
+
]
|
|
5311
|
+
}, c.id);
|
|
5312
|
+
})
|
|
5313
|
+
})]
|
|
4300
5314
|
})] }),
|
|
4301
5315
|
/* @__PURE__ */ jsx("div", {
|
|
4302
5316
|
ref: themesRef,
|
|
@@ -4322,7 +5336,7 @@ function PresetGrid() {
|
|
|
4322
5336
|
"”."
|
|
4323
5337
|
]
|
|
4324
5338
|
}) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
4325
|
-
/* @__PURE__ */ jsxs("p", {
|
|
5339
|
+
!q && /* @__PURE__ */ jsxs("p", {
|
|
4326
5340
|
className: "sr-only",
|
|
4327
5341
|
role: "status",
|
|
4328
5342
|
children: [visible.length, " themes"]
|
|
@@ -4441,58 +5455,73 @@ function ScanCard() {
|
|
|
4441
5455
|
});
|
|
4442
5456
|
}
|
|
4443
5457
|
function ThemeCard({ theme: t, isActive, onSelect }) {
|
|
4444
|
-
const { issues } = useTheme();
|
|
5458
|
+
const { issues, coloursOf, setThemeColours, features } = useTheme();
|
|
5459
|
+
const colours = coloursOf(t.id);
|
|
4445
5460
|
const showContrast = useContext(ContrastNav);
|
|
4446
5461
|
const stored = useMemo(() => t.library && !t.derived ? 0 : checkTheme(t.tokens).length, [t]);
|
|
4447
5462
|
const count = isActive ? issues.length : stored;
|
|
4448
5463
|
return /* @__PURE__ */ jsxs("div", {
|
|
4449
5464
|
className: "relative",
|
|
4450
|
-
children: [
|
|
4451
|
-
|
|
4452
|
-
|
|
4453
|
-
|
|
4454
|
-
|
|
4455
|
-
|
|
4456
|
-
|
|
4457
|
-
|
|
4458
|
-
|
|
4459
|
-
|
|
4460
|
-
|
|
4461
|
-
|
|
4462
|
-
|
|
4463
|
-
|
|
4464
|
-
|
|
4465
|
-
|
|
4466
|
-
|
|
4467
|
-
|
|
4468
|
-
|
|
4469
|
-
|
|
4470
|
-
|
|
4471
|
-
|
|
4472
|
-
|
|
4473
|
-
|
|
4474
|
-
|
|
4475
|
-
|
|
4476
|
-
|
|
4477
|
-
|
|
4478
|
-
|
|
4479
|
-
|
|
5465
|
+
children: [
|
|
5466
|
+
/* @__PURE__ */ jsxs("button", {
|
|
5467
|
+
type: "button",
|
|
5468
|
+
"aria-pressed": isActive,
|
|
5469
|
+
onClick: onSelect,
|
|
5470
|
+
className: `flex w-full flex-col gap-2 rounded-xl border p-2.5 text-left cursor-pointer hover:bg-zinc-50 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-zinc-900 ${isActive ? "border-zinc-900 ring-1 ring-zinc-900" : "border-zinc-200"} ${count ? "pr-12" : ""}`,
|
|
5471
|
+
children: [
|
|
5472
|
+
/* @__PURE__ */ jsx("span", {
|
|
5473
|
+
className: "truncate text-sm font-medium",
|
|
5474
|
+
children: t.name
|
|
5475
|
+
}),
|
|
5476
|
+
/* @__PURE__ */ jsx(Swatches, {
|
|
5477
|
+
tokens: t.tokens,
|
|
5478
|
+
count: colours
|
|
5479
|
+
}),
|
|
5480
|
+
(isActive || t.custom || t.scanned) && /* @__PURE__ */ jsxs("span", {
|
|
5481
|
+
className: "flex items-center gap-1.5 text-[11px]",
|
|
5482
|
+
children: [
|
|
5483
|
+
isActive && /* @__PURE__ */ jsxs("span", {
|
|
5484
|
+
className: "flex items-center gap-0.5 font-semibold text-zinc-900",
|
|
5485
|
+
children: [/* @__PURE__ */ jsx(Check, {
|
|
5486
|
+
className: "w-3.5 h-3.5",
|
|
5487
|
+
"aria-hidden": "true"
|
|
5488
|
+
}), " Active"]
|
|
5489
|
+
}),
|
|
5490
|
+
t.custom && /* @__PURE__ */ jsx("span", {
|
|
5491
|
+
className: "rounded bg-zinc-100 px-1 font-medium text-zinc-700",
|
|
5492
|
+
children: "Custom"
|
|
5493
|
+
}),
|
|
5494
|
+
t.scanned && /* @__PURE__ */ jsx("span", {
|
|
5495
|
+
className: "rounded bg-sky-50 px-1 font-medium text-sky-900",
|
|
5496
|
+
children: t.match ? "Library match" : "From scan"
|
|
5497
|
+
})
|
|
5498
|
+
]
|
|
5499
|
+
})
|
|
5500
|
+
]
|
|
5501
|
+
}),
|
|
5502
|
+
count > 0 && /* @__PURE__ */ jsxs("button", {
|
|
5503
|
+
type: "button",
|
|
5504
|
+
onClick: (e) => {
|
|
5505
|
+
if (!isActive) onSelect();
|
|
5506
|
+
showContrast(e.currentTarget);
|
|
5507
|
+
},
|
|
5508
|
+
"aria-label": `${t.name} has ${count} contrast ${count === 1 ? "problem" : "problems"}. Review and fix`,
|
|
5509
|
+
"data-tip": "Contrast problems: review and fix",
|
|
5510
|
+
className: "absolute right-1.5 top-1.5 inline-flex items-center gap-0.5 rounded-full border border-amber-300 bg-amber-100 px-1.5 py-0.5 text-[11px] font-semibold text-amber-900 hover:bg-amber-200 cursor-pointer focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-zinc-900",
|
|
5511
|
+
children: [/* @__PURE__ */ jsx(AlertTriangle, {
|
|
5512
|
+
className: "w-3 h-3",
|
|
5513
|
+
"aria-hidden": "true"
|
|
5514
|
+
}), count]
|
|
5515
|
+
}),
|
|
5516
|
+
isActive && features.colourCount && /* @__PURE__ */ jsx("span", {
|
|
5517
|
+
className: "absolute right-2 bottom-2",
|
|
5518
|
+
children: /* @__PURE__ */ jsx(ColourStepper, {
|
|
5519
|
+
value: colours,
|
|
5520
|
+
onChange: (n) => setThemeColours(t.id, n),
|
|
5521
|
+
label: `Colours ${t.name} uses`
|
|
4480
5522
|
})
|
|
4481
|
-
|
|
4482
|
-
|
|
4483
|
-
type: "button",
|
|
4484
|
-
onClick: (e) => {
|
|
4485
|
-
if (!isActive) onSelect();
|
|
4486
|
-
showContrast(e.currentTarget);
|
|
4487
|
-
},
|
|
4488
|
-
"aria-label": `${t.name} has ${count} contrast ${count === 1 ? "problem" : "problems"}. Review and fix`,
|
|
4489
|
-
"data-tip": "Contrast problems: review and fix",
|
|
4490
|
-
className: "absolute right-1.5 top-1.5 inline-flex items-center gap-0.5 rounded-full border border-amber-300 bg-amber-100 px-1.5 py-0.5 text-[11px] font-semibold text-amber-900 hover:bg-amber-200 cursor-pointer focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-zinc-900",
|
|
4491
|
-
children: [/* @__PURE__ */ jsx(AlertTriangle, {
|
|
4492
|
-
className: "w-3 h-3",
|
|
4493
|
-
"aria-hidden": "true"
|
|
4494
|
-
}), count]
|
|
4495
|
-
})]
|
|
5523
|
+
})
|
|
5524
|
+
]
|
|
4496
5525
|
});
|
|
4497
5526
|
}
|
|
4498
5527
|
function CustomPalettes() {
|
|
@@ -5739,7 +6768,7 @@ function AuditBar({ anchorRect, open, hiddenCount, themeIssues, onRecheck, onClo
|
|
|
5739
6768
|
}
|
|
5740
6769
|
//#endregion
|
|
5741
6770
|
//#region src/panel-css.generated.js
|
|
5742
|
-
var panel_css_generated_default = "/*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */\n@layer properties{@supports (display:block){*,:before,:after,::backdrop{--tw-translate-x:0;--tw-translate-y:0;--tw-translate-z:0;--tw-scale-x:1;--tw-scale-y:1;--tw-scale-z:1;--tw-space-y-reverse:0;--tw-border-style:solid;--tw-leading:initial;--tw-font-weight:initial;--tw-tracking:initial;--tw-ordinal:initial;--tw-slashed-zero:initial;--tw-numeric-figure:initial;--tw-numeric-spacing:initial;--tw-numeric-fraction:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-blur:initial;--tw-brightness:initial;--tw-contrast:initial;--tw-grayscale:initial;--tw-hue-rotate:initial;--tw-invert:initial;--tw-opacity:initial;--tw-saturate:initial;--tw-sepia:initial;--tw-drop-shadow:initial;--tw-drop-shadow-color:initial;--tw-drop-shadow-alpha:100%;--tw-drop-shadow-size:initial;--tw-backdrop-blur:initial;--tw-backdrop-brightness:initial;--tw-backdrop-contrast:initial;--tw-backdrop-grayscale:initial;--tw-backdrop-hue-rotate:initial;--tw-backdrop-invert:initial;--tw-backdrop-opacity:initial;--tw-backdrop-saturate:initial;--tw-backdrop-sepia:initial;--tw-duration:initial;--tw-ease:initial}}}@layer theme{:root,:host{--font-sans:-apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, \"Helvetica Neue\", \"Noto Sans\", Arial, sans-serif, \"Apple Color Emoji\", \"Segoe UI Emoji\", \"Segoe UI Symbol\", \"Noto Color Emoji\";--font-mono:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, \"Liberation Mono\", \"Courier New\", monospace;--color-red-600:oklch(57.7% .245 27.325);--color-red-700:oklch(50.5% .213 27.518);--color-amber-50:oklch(98.7% .022 95.277);--color-amber-100:oklch(96.2% .059 95.617);--color-amber-200:oklch(92.4% .12 95.746);--color-amber-300:oklch(87.9% .169 91.605);--color-amber-400:oklch(82.8% .189 84.429);--color-amber-700:oklch(55.5% .163 48.998);--color-amber-800:oklch(47.3% .137 46.201);--color-amber-900:oklch(41.4% .112 45.904);--color-amber-950:oklch(27.9% .077 45.635);--color-emerald-50:oklch(97.9% .021 166.113);--color-emerald-800:oklch(43.2% .095 166.913);--color-emerald-900:oklch(37.8% .077 168.94);--color-sky-50:oklch(97.7% .013 236.62);--color-sky-100:oklch(95.1% .026 236.824);--color-sky-900:oklch(39.1% .09 240.876);--color-zinc-50:oklch(98.5% 0 none);--color-zinc-100:oklch(96.7% .001 286.375);--color-zinc-200:oklch(92% .004 286.32);--color-zinc-300:oklch(87.1% .006 286.286);--color-zinc-400:oklch(70.5% .015 286.067);--color-zinc-500:oklch(55.2% .016 285.938);--color-zinc-600:oklch(44.2% .017 285.786);--color-zinc-700:oklch(37% .013 285.805);--color-zinc-800:oklch(27.4% .006 286.033);--color-zinc-900:oklch(21% .006 285.885);--color-white:#fff;--spacing:4px;--text-xs:12px;--text-xs--line-height:calc(1 / .75);--text-sm:14px;--text-sm--line-height:calc(1.25 / .875);--text-base:16px;--text-base--line-height:calc(1.5 / 1);--font-weight-medium:500;--font-weight-semibold:600;--font-weight-bold:700;--tracking-tight:-.025em;--tracking-normal:0em;--tracking-wide:.025em;--leading-snug:1.375;--radius-md:6px;--radius-lg:8px;--radius-xl:12px;--radius-2xl:16px;--ease-in-out:cubic-bezier(.4, 0, .2, 1);--animate-spin:spin 1s linear infinite;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4, 0, .2, 1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono)}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;tab-size:4;line-height:1.5;font-family:var(--default-font-family,-apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, \"Helvetica Neue\", \"Noto Sans\", Arial, sans-serif, \"Apple Color Emoji\", \"Segoe UI Emoji\", \"Segoe UI Symbol\", \"Noto Color Emoji\");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, \"Liberation Mono\", \"Courier New\", monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring:where(:not(iframe)){outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab, red, red)){::placeholder{color:color-mix(in oklab, currentcolor 50%, transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){appearance:button}::file-selector-button{appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}.theme-switcher{letter-spacing:normal;color:var(--color-zinc-900);font-family:Inter,ui-sans-serif,system-ui,sans-serif;font-size:16px;line-height:1.5}}@layer components;@layer utilities{.\\@container{container-type:inline-size}.pointer-events-auto{pointer-events:auto}.pointer-events-none{pointer-events:none}.invisible{visibility:hidden}.visible{visibility:visible}.sr-only{clip-path:inset(50%);white-space:nowrap;border-width:0;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}.absolute{position:absolute}.fixed{position:fixed}.relative{position:relative}.sticky{position:sticky}.inset-0{inset:0}.inset-x-3{inset-inline:calc(var(--spacing) * 3)}.inset-x-5{inset-inline:calc(var(--spacing) * 5)}.inset-y-5{inset-block:calc(var(--spacing) * 5)}.-top-2{top:calc(var(--spacing) * -2)}.-top-\\[6px\\]{top:-6px}.top-0{top:0}.top-1\\.5{top:calc(var(--spacing) * 1.5)}.top-1\\/2{top:50%}.top-5{top:calc(var(--spacing) * 5)}.top-\\[84px\\]{top:84px}.-right-0\\.5{right:calc(var(--spacing) * -.5)}.-right-2{right:calc(var(--spacing) * -2)}.right-1\\.5{right:calc(var(--spacing) * 1.5)}.right-5{right:calc(var(--spacing) * 5)}.right-6{right:calc(var(--spacing) * 6)}.right-full{right:100%}.-bottom-0\\.5{bottom:calc(var(--spacing) * -.5)}.-bottom-2{bottom:calc(var(--spacing) * -2)}.-bottom-\\[6px\\]{bottom:-6px}.bottom-3{bottom:calc(var(--spacing) * 3)}.bottom-5{bottom:calc(var(--spacing) * 5)}.-left-2{left:calc(var(--spacing) * -2)}.left-5{left:calc(var(--spacing) * 5)}.left-full{left:100%}.z-10{z-index:10}.z-20{z-index:20}.z-30{z-index:30}.z-\\[55\\]{z-index:55}.z-\\[56\\]{z-index:56}.z-\\[57\\]{z-index:57}.z-\\[60\\]{z-index:60}.z-\\[61\\]{z-index:61}.z-\\[62\\]{z-index:62}.z-\\[70\\]{z-index:70}.container{width:100%}@media (min-width:640px){.container{max-width:640px}}@media (min-width:768px){.container{max-width:768px}}@media (min-width:1024px){.container{max-width:1024px}}@media (min-width:1280px){.container{max-width:1280px}}@media (min-width:1536px){.container{max-width:1536px}}.mt-0\\.5{margin-top:calc(var(--spacing) * .5)}.mt-1{margin-top:var(--spacing)}.mt-1\\.5{margin-top:calc(var(--spacing) * 1.5)}.mt-2{margin-top:calc(var(--spacing) * 2)}.mt-2\\.5{margin-top:calc(var(--spacing) * 2.5)}.mt-px{margin-top:1px}.-mr-1{margin-right:calc(var(--spacing) * -1)}.mr-2{margin-right:calc(var(--spacing) * 2)}.mb-1{margin-bottom:var(--spacing)}.mb-2\\.5{margin-bottom:calc(var(--spacing) * 2.5)}.ml-2{margin-left:calc(var(--spacing) * 2)}.ml-auto{margin-left:auto}.block{display:block}.flex{display:flex}.grid{display:grid}.hidden{display:none}.inline-flex{display:inline-flex}.h-2\\.5{height:calc(var(--spacing) * 2.5)}.h-3{height:calc(var(--spacing) * 3)}.h-3\\.5{height:calc(var(--spacing) * 3.5)}.h-4{height:calc(var(--spacing) * 4)}.h-5{height:calc(var(--spacing) * 5)}.h-6{height:calc(var(--spacing) * 6)}.h-7{height:calc(var(--spacing) * 7)}.h-8{height:calc(var(--spacing) * 8)}.h-9{height:calc(var(--spacing) * 9)}.h-12{height:calc(var(--spacing) * 12)}.h-16{height:calc(var(--spacing) * 16)}.h-px{height:1px}.max-h-40{max-height:calc(var(--spacing) * 40)}.min-h-0{min-height:0}.w-2\\.5{width:calc(var(--spacing) * 2.5)}.w-3{width:calc(var(--spacing) * 3)}.w-3\\.5{width:calc(var(--spacing) * 3.5)}.w-4{width:calc(var(--spacing) * 4)}.w-5{width:calc(var(--spacing) * 5)}.w-6{width:calc(var(--spacing) * 6)}.w-7{width:calc(var(--spacing) * 7)}.w-9{width:calc(var(--spacing) * 9)}.w-16{width:calc(var(--spacing) * 16)}.w-24{width:calc(var(--spacing) * 24)}.w-\\[5\\.5rem\\]{width:88px}.w-auto{width:auto}.w-full{width:100%}.max-w-\\[240px\\]{max-width:240px}.max-w-\\[calc\\(100vw-80px\\)\\]{max-width:calc(100vw - 80px)}.max-w-full{max-width:100%}.min-w-0{min-width:0}.flex-1{flex:1}.shrink-0{flex-shrink:0}.-translate-y-1\\/2{--tw-translate-y:calc(calc(1 / 2 * 100%) * -1);translate:var(--tw-translate-x) var(--tw-translate-y)}.scale-110{--tw-scale-x:110%;--tw-scale-y:110%;--tw-scale-z:110%;scale:var(--tw-scale-x) var(--tw-scale-y)}.rotate-45{rotate:45deg}.rotate-90{rotate:90deg}.animate-spin{animation:var(--animate-spin)}.cursor-ew-resize{cursor:ew-resize}.cursor-grabbing{cursor:grabbing}.cursor-nesw-resize{cursor:nesw-resize}.cursor-ns-resize{cursor:ns-resize}.cursor-nwse-resize{cursor:nwse-resize}.cursor-pointer{cursor:pointer}.touch-none{touch-action:none}.resize{resize:both}.scroll-mt-3{scroll-margin-top:calc(var(--spacing) * 3)}.list-decimal{list-style-type:decimal}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.place-items-center{place-items:center}.items-center{align-items:center}.items-start{align-items:flex-start}.justify-between{justify-content:space-between}.justify-center{justify-content:center}.gap-0\\.5{gap:calc(var(--spacing) * .5)}.gap-1{gap:var(--spacing)}.gap-1\\.5{gap:calc(var(--spacing) * 1.5)}.gap-2{gap:calc(var(--spacing) * 2)}.gap-2\\.5{gap:calc(var(--spacing) * 2.5)}.gap-3{gap:calc(var(--spacing) * 3)}:where(.space-y-0\\.5>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * .5) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * .5) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-1>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(var(--spacing) * var(--tw-space-y-reverse));margin-block-end:calc(var(--spacing) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-1\\.5>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 1.5) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 1.5) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-2>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 2) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 2) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-3>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 3) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 3) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-4>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 4) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 4) * calc(1 - var(--tw-space-y-reverse)))}.truncate{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.overflow-auto{overflow:auto}.overflow-hidden{overflow:hidden}.overflow-y-auto{overflow-y:auto}.overscroll-contain{overscroll-behavior:contain}.rounded{border-radius:4px}.rounded-2xl{border-radius:var(--radius-2xl)}.rounded-\\[inherit\\]{border-radius:inherit}.rounded-full{border-radius:3.40282e38px}.rounded-lg{border-radius:var(--radius-lg)}.rounded-md{border-radius:var(--radius-md)}.rounded-xl{border-radius:var(--radius-xl)}.border{border-style:var(--tw-border-style);border-width:1px}.border-2{border-style:var(--tw-border-style);border-width:2px}.border-t{border-top-style:var(--tw-border-style);border-top-width:1px}.border-r{border-right-style:var(--tw-border-style);border-right-width:1px}.border-b{border-bottom-style:var(--tw-border-style);border-bottom-width:1px}.border-l{border-left-style:var(--tw-border-style);border-left-width:1px}.border-dashed{--tw-border-style:dashed;border-style:dashed}.border-amber-300{border-color:var(--color-amber-300)}.border-amber-400{border-color:var(--color-amber-400)}.border-red-600{border-color:var(--color-red-600)}.border-transparent{border-color:#0000}.border-white{border-color:var(--color-white)}.border-zinc-200{border-color:var(--color-zinc-200)}.border-zinc-300{border-color:var(--color-zinc-300)}.border-zinc-900{border-color:var(--color-zinc-900)}.bg-amber-50{background-color:var(--color-amber-50)}.bg-amber-100{background-color:var(--color-amber-100)}.bg-amber-400{background-color:var(--color-amber-400)}.bg-emerald-50{background-color:var(--color-emerald-50)}.bg-sky-50{background-color:var(--color-sky-50)}.bg-sky-100{background-color:var(--color-sky-100)}.bg-white{background-color:var(--color-white)}.bg-white\\/90{background-color:#ffffffe6}@supports (color:color-mix(in lab, red, red)){.bg-white\\/90{background-color:color-mix(in oklab, var(--color-white) 90%, transparent)}}.bg-zinc-50{background-color:var(--color-zinc-50)}.bg-zinc-100{background-color:var(--color-zinc-100)}.bg-zinc-200{background-color:var(--color-zinc-200)}.bg-zinc-900{background-color:var(--color-zinc-900)}.object-contain{object-fit:contain}.p-0\\.5{padding:calc(var(--spacing) * .5)}.p-2{padding:calc(var(--spacing) * 2)}.p-2\\.5{padding:calc(var(--spacing) * 2.5)}.p-3{padding:calc(var(--spacing) * 3)}.px-1{padding-inline:var(--spacing)}.px-1\\.5{padding-inline:calc(var(--spacing) * 1.5)}.px-2{padding-inline:calc(var(--spacing) * 2)}.px-2\\.5{padding-inline:calc(var(--spacing) * 2.5)}.px-3{padding-inline:calc(var(--spacing) * 3)}.px-4{padding-inline:calc(var(--spacing) * 4)}.py-0\\.5{padding-block:calc(var(--spacing) * .5)}.py-1{padding-block:var(--spacing)}.py-1\\.5{padding-block:calc(var(--spacing) * 1.5)}.py-2{padding-block:calc(var(--spacing) * 2)}.py-2\\.5{padding-block:calc(var(--spacing) * 2.5)}.py-3{padding-block:calc(var(--spacing) * 3)}.py-5{padding-block:calc(var(--spacing) * 5)}.py-6{padding-block:calc(var(--spacing) * 6)}.pr-1\\.5{padding-right:calc(var(--spacing) * 1.5)}.pr-12{padding-right:calc(var(--spacing) * 12)}.pb-4{padding-bottom:calc(var(--spacing) * 4)}.pl-1{padding-left:var(--spacing)}.pl-3{padding-left:calc(var(--spacing) * 3)}.pl-4{padding-left:calc(var(--spacing) * 4)}.text-center{text-align:center}.text-left{text-align:left}.align-super{vertical-align:super}.font-mono{font-family:var(--font-mono)}.text-base{font-size:var(--text-base);line-height:var(--tw-leading,var(--text-base--line-height))}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.text-xs{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}.text-\\[10px\\]{font-size:10px}.text-\\[11px\\]{font-size:11px}.leading-snug{--tw-leading:var(--leading-snug);line-height:var(--leading-snug)}.font-bold{--tw-font-weight:var(--font-weight-bold);font-weight:var(--font-weight-bold)}.font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.font-semibold{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.tracking-normal{--tw-tracking:var(--tracking-normal);letter-spacing:var(--tracking-normal)}.tracking-tight{--tw-tracking:var(--tracking-tight);letter-spacing:var(--tracking-tight)}.tracking-wide{--tw-tracking:var(--tracking-wide);letter-spacing:var(--tracking-wide)}.break-all{word-break:break-all}.whitespace-nowrap{white-space:nowrap}.whitespace-pre-wrap{white-space:pre-wrap}.text-amber-700{color:var(--color-amber-700)}.text-amber-800{color:var(--color-amber-800)}.text-amber-900{color:var(--color-amber-900)}.text-amber-950{color:var(--color-amber-950)}.text-emerald-800{color:var(--color-emerald-800)}.text-emerald-900{color:var(--color-emerald-900)}.text-red-700{color:var(--color-red-700)}.text-sky-900{color:var(--color-sky-900)}.text-white{color:var(--color-white)}.text-zinc-300{color:var(--color-zinc-300)}.text-zinc-500{color:var(--color-zinc-500)}.text-zinc-600{color:var(--color-zinc-600)}.text-zinc-700{color:var(--color-zinc-700)}.text-zinc-800{color:var(--color-zinc-800)}.text-zinc-900{color:var(--color-zinc-900)}.normal-case{text-transform:none}.uppercase{text-transform:uppercase}.tabular-nums{--tw-numeric-spacing:tabular-nums;font-variant-numeric:var(--tw-ordinal,) var(--tw-slashed-zero,) var(--tw-numeric-figure,) var(--tw-numeric-spacing,) var(--tw-numeric-fraction,)}.underline{text-decoration-line:underline}.underline-offset-2{text-underline-offset:2px}.accent-zinc-900{accent-color:var(--color-zinc-900)}.opacity-25{opacity:.25}.opacity-70{opacity:.7}.shadow{--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a), 0 1px 2px -1px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow-2xl{--tw-shadow:0 25px 50px -12px var(--tw-shadow-color,#00000040);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow-lg{--tw-shadow:0 10px 15px -3px var(--tw-shadow-color,#0000001a), 0 4px 6px -4px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow-md{--tw-shadow:0 4px 6px -1px var(--tw-shadow-color,#0000001a), 0 2px 4px -2px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow-sm{--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a), 0 1px 2px -1px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow-xl{--tw-shadow:0 20px 25px -5px var(--tw-shadow-color,#0000001a), 0 8px 10px -6px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.ring-1{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.ring-2{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.ring-white{--tw-ring-color:var(--color-white)}.ring-zinc-900{--tw-ring-color:var(--color-zinc-900)}.ring-offset-1{--tw-ring-offset-width:1px;--tw-ring-offset-shadow:var(--tw-ring-inset,) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color)}.invert{--tw-invert:invert(100%);filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}.filter{filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}.backdrop-blur{--tw-backdrop-blur:blur(8px);-webkit-backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,)}.transition-\\[color\\,background-color\\,box-shadow\\,scale\\]{transition-property:color,background-color,box-shadow,scale;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-colors{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-shadow{transition-property:box-shadow;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-transform{transition-property:transform,translate,scale,rotate;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.duration-700{--tw-duration:.7s;transition-duration:.7s}.ease-in-out{--tw-ease:var(--ease-in-out);transition-timing-function:var(--ease-in-out)}.select-none{-webkit-user-select:none;user-select:none}.placeholder\\:text-zinc-500::placeholder{color:var(--color-zinc-500)}@media (hover:hover){.hover\\:bg-amber-200:hover{background-color:var(--color-amber-200)}.hover\\:bg-white:hover{background-color:var(--color-white)}.hover\\:bg-zinc-50:hover{background-color:var(--color-zinc-50)}.hover\\:bg-zinc-100:hover{background-color:var(--color-zinc-100)}.hover\\:bg-zinc-200:hover{background-color:var(--color-zinc-200)}.hover\\:bg-zinc-400\\/30:hover{background-color:#9f9fa94d}@supports (color:color-mix(in lab, red, red)){.hover\\:bg-zinc-400\\/30:hover{background-color:color-mix(in oklab, var(--color-zinc-400) 30%, transparent)}}.hover\\:bg-zinc-700:hover{background-color:var(--color-zinc-700)}.hover\\:text-amber-950:hover{color:var(--color-amber-950)}.hover\\:text-zinc-900:hover{color:var(--color-zinc-900)}.hover\\:opacity-100:hover{opacity:1}}.focus\\:outline-none:focus{--tw-outline-style:none;outline-style:none}.focus-visible\\:ring-2:focus-visible{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.focus-visible\\:ring-white:focus-visible{--tw-ring-color:var(--color-white)}.focus-visible\\:ring-zinc-900:focus-visible{--tw-ring-color:var(--color-zinc-900)}.focus-visible\\:ring-offset-1:focus-visible{--tw-ring-offset-width:1px;--tw-ring-offset-shadow:var(--tw-ring-inset,) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color)}.focus-visible\\:ring-offset-2:focus-visible{--tw-ring-offset-width:2px;--tw-ring-offset-shadow:var(--tw-ring-inset,) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color)}.focus-visible\\:outline-none:focus-visible{--tw-outline-style:none;outline-style:none}.focus-visible\\:ring-inset:focus-visible{--tw-ring-inset:inset}.disabled\\:opacity-50:disabled{opacity:.5}@media (prefers-reduced-motion:reduce){.motion-reduce\\:animate-none{animation:none}.motion-reduce\\:transition-none{transition-property:none}}@media (min-width:1200px){.min-\\[1200px\\]\\:top-\\[27px\\]{top:27px}.min-\\[1200px\\]\\:right-4{right:calc(var(--spacing) * 4)}}@media (min-width:640px){.sm\\:inline{display:inline}}@container (min-width:380px){.\\@min-\\[380px\\]\\:h-10{height:calc(var(--spacing) * 10)}.\\@min-\\[380px\\]\\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.\\@min-\\[380px\\]\\:flex-row{flex-direction:row}.\\@min-\\[380px\\]\\:justify-start{justify-content:flex-start}.\\@min-\\[380px\\]\\:gap-1\\.5{gap:calc(var(--spacing) * 1.5)}}@container (min-width:440px){.\\@min-\\[440px\\]\\:inline{display:inline}.\\@min-\\[440px\\]\\:px-2\\.5{padding-inline:calc(var(--spacing) * 2.5)}}@container (min-width:500px){.\\@min-\\[500px\\]\\:inline{display:inline}.\\@min-\\[500px\\]\\:px-2{padding-inline:calc(var(--spacing) * 2)}}@container (min-width:520px){.\\@min-\\[520px\\]\\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}}}:host{all:initial}.cbm-dark{color-scheme:dark;--color-white:oklch(21% .006 285.885);--color-zinc-50:oklch(24.5% .006 286);--color-zinc-100:oklch(27.4% .006 286.033);--color-zinc-200:oklch(33% .01 285.9);--color-zinc-300:oklch(42% .015 285.8);--color-zinc-400:oklch(52% .016 285.9);--color-zinc-500:oklch(68% .015 286.067);--color-zinc-600:oklch(74% .012 286);--color-zinc-700:oklch(82% .008 286.2);--color-zinc-800:oklch(88% .006 286.3);--color-zinc-900:oklch(96.7% .001 286.375);--color-zinc-950:oklch(98.5% 0 0);--color-amber-50:oklch(27.9% .077 45.635);--color-amber-100:oklch(33% .09 46);--color-amber-200:oklch(41.4% .112 45.904);--color-amber-300:oklch(55.5% .163 48.998);--color-amber-700:oklch(87.9% .169 91.605);--color-amber-800:oklch(92.4% .12 95.746);--color-amber-900:oklch(96.2% .059 95.617);--color-amber-950:oklch(98.7% .022 95.277);--color-emerald-50:oklch(26.2% .051 172.552);--color-emerald-800:oklch(90.5% .093 164.15);--color-emerald-900:oklch(95% .052 163.051);--color-sky-50:oklch(29.3% .066 243.157);--color-sky-100:oklch(39.1% .09 240.876);--color-sky-900:oklch(95.1% .026 236.824);--color-red-600:oklch(70.4% .191 22.216);--color-red-700:oklch(80.8% .114 19.571)}.cbm-dark *{--tw-ring-offset-color:oklch(21% .006 285.885)}.theme-scroll{--cbm-thumb:var(--color-primary,oklch(55.2% .016 285.938))}@supports (color:color-mix(in lab, red, red)){.theme-scroll{--cbm-thumb:color-mix(in srgb, var(--color-primary,var(--color-zinc-500)) 55%, var(--color-white))}}.theme-scroll{--cbm-thumb-hover:var(--color-primary,oklch(55.2% .016 285.938))}@supports (color:color-mix(in lab, red, red)){.theme-scroll{--cbm-thumb-hover:color-mix(in srgb, var(--color-primary,var(--color-zinc-500)) 80%, var(--color-white))}}.theme-scroll{scrollbar-width:thin;scrollbar-color:var(--cbm-thumb) transparent}.theme-scroll:hover{scrollbar-color:var(--cbm-thumb-hover) transparent}.theme-scroll::-webkit-scrollbar{width:6px}.theme-scroll::-webkit-scrollbar-track{background:0 0}.theme-scroll::-webkit-scrollbar-thumb{background:var(--cbm-thumb);border-radius:9999px}.theme-scroll:hover::-webkit-scrollbar-thumb{background:var(--cbm-thumb-hover)}.theme-panel{transform-origin:100% 0;animation:.16s ease-out theme-panel-in}@keyframes theme-panel-in{0%{opacity:0;transform:translateY(-6px)scale(.98)}}.theme-hint{animation:.12s ease-out theme-hint-in}.theme-toast{animation:.18s ease-out theme-toast-in}@keyframes theme-toast-in{0%{opacity:0;transform:translateY(8px)}}@keyframes theme-hint-in{0%{opacity:0}}.theme-arrive{animation:.62s cubic-bezier(.34,1.56,.64,1) both theme-arrive}@keyframes theme-arrive{0%{opacity:0;transform:scale(.2)rotate(-45deg)}60%{opacity:1;transform:scale(1.16)rotate(8deg)}to{transform:scale(1)rotate(0)}}.theme-burst-piece{line-height:0;animation:.95s cubic-bezier(.15,.75,.3,1) both theme-burst-piece;display:block;position:absolute;top:50%;left:50%}@keyframes theme-burst-piece{0%{opacity:0;transform:translate(-50%, -50%) rotate(var(--r)) scale(.3)}12%{opacity:1}65%{opacity:1}to{opacity:0;transform:translate(calc(-50% + var(--x)), calc(-50% + var(--y))) rotate(calc(var(--r) + 150deg)) scale(1)}}.theme-piece-dot{background:currentColor;border-radius:9999px;width:6px;height:6px}.theme-piece-dash{background:currentColor;border-radius:9999px;width:10px;height:3px}@media (prefers-reduced-motion:reduce){.theme-panel,.theme-hint,.theme-toast{animation:none}.theme-arrive{animation:.3s ease-out both theme-hint-in}.theme-burst{display:none}}.theme-panel summary{list-style:none}.theme-panel summary::-webkit-details-marker{display:none}.theme-panel details[open]>summary .theme-chevron{transform:rotate(90deg)}@keyframes spin{to{transform:rotate(360deg)}}";
|
|
6771
|
+
var panel_css_generated_default = "/*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */\n@layer properties{@supports (display:block){*,:before,:after,::backdrop{--tw-translate-x:0;--tw-translate-y:0;--tw-translate-z:0;--tw-scale-x:1;--tw-scale-y:1;--tw-scale-z:1;--tw-space-y-reverse:0;--tw-border-style:solid;--tw-leading:initial;--tw-font-weight:initial;--tw-tracking:initial;--tw-ordinal:initial;--tw-slashed-zero:initial;--tw-numeric-figure:initial;--tw-numeric-spacing:initial;--tw-numeric-fraction:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-blur:initial;--tw-brightness:initial;--tw-contrast:initial;--tw-grayscale:initial;--tw-hue-rotate:initial;--tw-invert:initial;--tw-opacity:initial;--tw-saturate:initial;--tw-sepia:initial;--tw-drop-shadow:initial;--tw-drop-shadow-color:initial;--tw-drop-shadow-alpha:100%;--tw-drop-shadow-size:initial;--tw-backdrop-blur:initial;--tw-backdrop-brightness:initial;--tw-backdrop-contrast:initial;--tw-backdrop-grayscale:initial;--tw-backdrop-hue-rotate:initial;--tw-backdrop-invert:initial;--tw-backdrop-opacity:initial;--tw-backdrop-saturate:initial;--tw-backdrop-sepia:initial;--tw-duration:initial;--tw-ease:initial}}}@layer theme{:root,:host{--font-sans:-apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, \"Helvetica Neue\", \"Noto Sans\", Arial, sans-serif, \"Apple Color Emoji\", \"Segoe UI Emoji\", \"Segoe UI Symbol\", \"Noto Color Emoji\";--font-mono:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, \"Liberation Mono\", \"Courier New\", monospace;--color-red-600:oklch(57.7% .245 27.325);--color-red-700:oklch(50.5% .213 27.518);--color-amber-50:oklch(98.7% .022 95.277);--color-amber-100:oklch(96.2% .059 95.617);--color-amber-200:oklch(92.4% .12 95.746);--color-amber-300:oklch(87.9% .169 91.605);--color-amber-400:oklch(82.8% .189 84.429);--color-amber-700:oklch(55.5% .163 48.998);--color-amber-800:oklch(47.3% .137 46.201);--color-amber-900:oklch(41.4% .112 45.904);--color-amber-950:oklch(27.9% .077 45.635);--color-emerald-50:oklch(97.9% .021 166.113);--color-emerald-800:oklch(43.2% .095 166.913);--color-emerald-900:oklch(37.8% .077 168.94);--color-sky-50:oklch(97.7% .013 236.62);--color-sky-100:oklch(95.1% .026 236.824);--color-sky-900:oklch(39.1% .09 240.876);--color-zinc-50:oklch(98.5% 0 none);--color-zinc-100:oklch(96.7% .001 286.375);--color-zinc-200:oklch(92% .004 286.32);--color-zinc-300:oklch(87.1% .006 286.286);--color-zinc-400:oklch(70.5% .015 286.067);--color-zinc-500:oklch(55.2% .016 285.938);--color-zinc-600:oklch(44.2% .017 285.786);--color-zinc-700:oklch(37% .013 285.805);--color-zinc-800:oklch(27.4% .006 286.033);--color-zinc-900:oklch(21% .006 285.885);--color-white:#fff;--spacing:4px;--text-xs:12px;--text-xs--line-height:calc(1 / .75);--text-sm:14px;--text-sm--line-height:calc(1.25 / .875);--text-base:16px;--text-base--line-height:calc(1.5 / 1);--font-weight-medium:500;--font-weight-semibold:600;--font-weight-bold:700;--tracking-tight:-.025em;--tracking-wide:.025em;--leading-tight:1.25;--leading-snug:1.375;--radius-md:6px;--radius-lg:8px;--radius-xl:12px;--radius-2xl:16px;--ease-in-out:cubic-bezier(.4, 0, .2, 1);--animate-spin:spin 1s linear infinite;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4, 0, .2, 1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono)}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;tab-size:4;line-height:1.5;font-family:var(--default-font-family,-apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, \"Helvetica Neue\", \"Noto Sans\", Arial, sans-serif, \"Apple Color Emoji\", \"Segoe UI Emoji\", \"Segoe UI Symbol\", \"Noto Color Emoji\");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, \"Liberation Mono\", \"Courier New\", monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring:where(:not(iframe)){outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab, red, red)){::placeholder{color:color-mix(in oklab, currentcolor 50%, transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){appearance:button}::file-selector-button{appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}.theme-switcher{letter-spacing:normal;color:var(--color-zinc-900);font-family:Inter,ui-sans-serif,system-ui,sans-serif;font-size:16px;line-height:1.5}}@layer components;@layer utilities{.\\@container{container-type:inline-size}.pointer-events-auto{pointer-events:auto}.pointer-events-none{pointer-events:none}.invisible{visibility:hidden}.visible{visibility:visible}.sr-only{clip-path:inset(50%);white-space:nowrap;border-width:0;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}.absolute{position:absolute}.fixed{position:fixed}.relative{position:relative}.sticky{position:sticky}.inset-x-3{inset-inline:calc(var(--spacing) * 3)}.inset-x-5{inset-inline:calc(var(--spacing) * 5)}.inset-y-5{inset-block:calc(var(--spacing) * 5)}.-top-2{top:calc(var(--spacing) * -2)}.-top-\\[6px\\]{top:-6px}.top-0{top:0}.top-1\\.5{top:calc(var(--spacing) * 1.5)}.top-1\\/2{top:50%}.top-5{top:calc(var(--spacing) * 5)}.top-\\[84px\\]{top:84px}.-right-0\\.5{right:calc(var(--spacing) * -.5)}.-right-2{right:calc(var(--spacing) * -2)}.right-1\\.5{right:calc(var(--spacing) * 1.5)}.right-2{right:calc(var(--spacing) * 2)}.right-5{right:calc(var(--spacing) * 5)}.right-6{right:calc(var(--spacing) * 6)}.right-full{right:100%}.-bottom-0\\.5{bottom:calc(var(--spacing) * -.5)}.-bottom-2{bottom:calc(var(--spacing) * -2)}.-bottom-\\[6px\\]{bottom:-6px}.bottom-2{bottom:calc(var(--spacing) * 2)}.bottom-3{bottom:calc(var(--spacing) * 3)}.bottom-5{bottom:calc(var(--spacing) * 5)}.-left-2{left:calc(var(--spacing) * -2)}.left-5{left:calc(var(--spacing) * 5)}.left-full{left:100%}.z-10{z-index:10}.z-20{z-index:20}.z-30{z-index:30}.z-\\[55\\]{z-index:55}.z-\\[56\\]{z-index:56}.z-\\[57\\]{z-index:57}.z-\\[60\\]{z-index:60}.z-\\[61\\]{z-index:61}.z-\\[62\\]{z-index:62}.z-\\[70\\]{z-index:70}.container{width:100%}@media (min-width:640px){.container{max-width:640px}}@media (min-width:768px){.container{max-width:768px}}@media (min-width:1024px){.container{max-width:1024px}}@media (min-width:1280px){.container{max-width:1280px}}@media (min-width:1536px){.container{max-width:1536px}}.-mt-1{margin-top:calc(var(--spacing) * -1)}.mt-0\\.5{margin-top:calc(var(--spacing) * .5)}.mt-1{margin-top:var(--spacing)}.mt-1\\.5{margin-top:calc(var(--spacing) * 1.5)}.mt-2{margin-top:calc(var(--spacing) * 2)}.mt-2\\.5{margin-top:calc(var(--spacing) * 2.5)}.mt-px{margin-top:1px}.-mr-1{margin-right:calc(var(--spacing) * -1)}.mr-2{margin-right:calc(var(--spacing) * 2)}.mb-1{margin-bottom:var(--spacing)}.mb-2\\.5{margin-bottom:calc(var(--spacing) * 2.5)}.ml-2{margin-left:calc(var(--spacing) * 2)}.ml-auto{margin-left:auto}.block{display:block}.flex{display:flex}.grid{display:grid}.hidden{display:none}.inline-flex{display:inline-flex}.h-2\\.5{height:calc(var(--spacing) * 2.5)}.h-3{height:calc(var(--spacing) * 3)}.h-3\\.5{height:calc(var(--spacing) * 3.5)}.h-4{height:calc(var(--spacing) * 4)}.h-5{height:calc(var(--spacing) * 5)}.h-6{height:calc(var(--spacing) * 6)}.h-7{height:calc(var(--spacing) * 7)}.h-8{height:calc(var(--spacing) * 8)}.h-9{height:calc(var(--spacing) * 9)}.h-16{height:calc(var(--spacing) * 16)}.max-h-40{max-height:calc(var(--spacing) * 40)}.min-h-0{min-height:0}.min-h-12{min-height:calc(var(--spacing) * 12)}.w-2\\.5{width:calc(var(--spacing) * 2.5)}.w-3{width:calc(var(--spacing) * 3)}.w-3\\.5{width:calc(var(--spacing) * 3.5)}.w-4{width:calc(var(--spacing) * 4)}.w-5{width:calc(var(--spacing) * 5)}.w-6{width:calc(var(--spacing) * 6)}.w-7{width:calc(var(--spacing) * 7)}.w-8{width:calc(var(--spacing) * 8)}.w-9{width:calc(var(--spacing) * 9)}.w-16{width:calc(var(--spacing) * 16)}.w-24{width:calc(var(--spacing) * 24)}.w-\\[5\\.5rem\\]{width:88px}.w-auto{width:auto}.w-full{width:100%}.max-w-\\[240px\\]{max-width:240px}.max-w-\\[calc\\(100vw-80px\\)\\]{max-width:calc(100vw - 80px)}.max-w-full{max-width:100%}.min-w-0{min-width:0}.min-w-\\[1\\.25rem\\]{min-width:20px}.flex-1{flex:1}.shrink-0{flex-shrink:0}.-translate-y-1\\/2{--tw-translate-y:calc(calc(1 / 2 * 100%) * -1);translate:var(--tw-translate-x) var(--tw-translate-y)}.scale-110{--tw-scale-x:110%;--tw-scale-y:110%;--tw-scale-z:110%;scale:var(--tw-scale-x) var(--tw-scale-y)}.rotate-45{rotate:45deg}.rotate-90{rotate:90deg}.animate-spin{animation:var(--animate-spin)}.cursor-ew-resize{cursor:ew-resize}.cursor-grabbing{cursor:grabbing}.cursor-nesw-resize{cursor:nesw-resize}.cursor-ns-resize{cursor:ns-resize}.cursor-nwse-resize{cursor:nwse-resize}.cursor-pointer{cursor:pointer}.touch-none{touch-action:none}.resize{resize:both}.scroll-mt-3{scroll-margin-top:calc(var(--spacing) * 3)}.list-decimal{list-style-type:decimal}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.place-items-center{place-items:center}.items-center{align-items:center}.items-start{align-items:flex-start}.justify-between{justify-content:space-between}.justify-center{justify-content:center}.gap-0\\.5{gap:calc(var(--spacing) * .5)}.gap-1{gap:var(--spacing)}.gap-1\\.5{gap:calc(var(--spacing) * 1.5)}.gap-2{gap:calc(var(--spacing) * 2)}.gap-2\\.5{gap:calc(var(--spacing) * 2.5)}.gap-3{gap:calc(var(--spacing) * 3)}:where(.space-y-0\\.5>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * .5) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * .5) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-1>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(var(--spacing) * var(--tw-space-y-reverse));margin-block-end:calc(var(--spacing) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-1\\.5>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 1.5) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 1.5) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-2>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 2) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 2) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-3>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 3) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 3) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-4>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 4) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 4) * calc(1 - var(--tw-space-y-reverse)))}.gap-x-3{column-gap:calc(var(--spacing) * 3)}.gap-y-3\\.5{row-gap:calc(var(--spacing) * 3.5)}.truncate{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.overflow-auto{overflow:auto}.overflow-hidden{overflow:hidden}.overflow-y-auto{overflow-y:auto}.overscroll-contain{overscroll-behavior:contain}.rounded{border-radius:4px}.rounded-2xl{border-radius:var(--radius-2xl)}.rounded-\\[inherit\\]{border-radius:inherit}.rounded-full{border-radius:3.40282e38px}.rounded-lg{border-radius:var(--radius-lg)}.rounded-md{border-radius:var(--radius-md)}.rounded-xl{border-radius:var(--radius-xl)}.border{border-style:var(--tw-border-style);border-width:1px}.border-2{border-style:var(--tw-border-style);border-width:2px}.border-t{border-top-style:var(--tw-border-style);border-top-width:1px}.border-r{border-right-style:var(--tw-border-style);border-right-width:1px}.border-b{border-bottom-style:var(--tw-border-style);border-bottom-width:1px}.border-l{border-left-style:var(--tw-border-style);border-left-width:1px}.border-dashed{--tw-border-style:dashed;border-style:dashed}.border-amber-300{border-color:var(--color-amber-300)}.border-amber-400{border-color:var(--color-amber-400)}.border-red-600{border-color:var(--color-red-600)}.border-transparent{border-color:#0000}.border-white{border-color:var(--color-white)}.border-zinc-200{border-color:var(--color-zinc-200)}.border-zinc-300{border-color:var(--color-zinc-300)}.border-zinc-900{border-color:var(--color-zinc-900)}.bg-amber-50{background-color:var(--color-amber-50)}.bg-amber-100{background-color:var(--color-amber-100)}.bg-amber-400{background-color:var(--color-amber-400)}.bg-emerald-50{background-color:var(--color-emerald-50)}.bg-sky-50{background-color:var(--color-sky-50)}.bg-sky-100{background-color:var(--color-sky-100)}.bg-white{background-color:var(--color-white)}.bg-white\\/90{background-color:#ffffffe6}@supports (color:color-mix(in lab, red, red)){.bg-white\\/90{background-color:color-mix(in oklab, var(--color-white) 90%, transparent)}}.bg-zinc-50{background-color:var(--color-zinc-50)}.bg-zinc-100{background-color:var(--color-zinc-100)}.bg-zinc-900{background-color:var(--color-zinc-900)}.object-contain{object-fit:contain}.p-0\\.5{padding:calc(var(--spacing) * .5)}.p-1{padding:var(--spacing)}.p-2{padding:calc(var(--spacing) * 2)}.p-2\\.5{padding:calc(var(--spacing) * 2.5)}.p-3{padding:calc(var(--spacing) * 3)}.px-0\\.5{padding-inline:calc(var(--spacing) * .5)}.px-1{padding-inline:var(--spacing)}.px-1\\.5{padding-inline:calc(var(--spacing) * 1.5)}.px-2{padding-inline:calc(var(--spacing) * 2)}.px-2\\.5{padding-inline:calc(var(--spacing) * 2.5)}.px-3{padding-inline:calc(var(--spacing) * 3)}.px-4{padding-inline:calc(var(--spacing) * 4)}.py-0\\.5{padding-block:calc(var(--spacing) * .5)}.py-1{padding-block:var(--spacing)}.py-1\\.5{padding-block:calc(var(--spacing) * 1.5)}.py-2{padding-block:calc(var(--spacing) * 2)}.py-2\\.5{padding-block:calc(var(--spacing) * 2.5)}.py-3{padding-block:calc(var(--spacing) * 3)}.py-5{padding-block:calc(var(--spacing) * 5)}.py-6{padding-block:calc(var(--spacing) * 6)}.pr-1\\.5{padding-right:calc(var(--spacing) * 1.5)}.pr-12{padding-right:calc(var(--spacing) * 12)}.pb-4{padding-bottom:calc(var(--spacing) * 4)}.pl-1{padding-left:var(--spacing)}.pl-3{padding-left:calc(var(--spacing) * 3)}.pl-4{padding-left:calc(var(--spacing) * 4)}.text-center{text-align:center}.text-left{text-align:left}.align-super{vertical-align:super}.font-mono{font-family:var(--font-mono)}.text-base{font-size:var(--text-base);line-height:var(--tw-leading,var(--text-base--line-height))}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.text-xs{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}.text-\\[10px\\]{font-size:10px}.text-\\[11px\\]{font-size:11px}.leading-snug{--tw-leading:var(--leading-snug);line-height:var(--leading-snug)}.leading-tight{--tw-leading:var(--leading-tight);line-height:var(--leading-tight)}.font-bold{--tw-font-weight:var(--font-weight-bold);font-weight:var(--font-weight-bold)}.font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.font-semibold{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.tracking-tight{--tw-tracking:var(--tracking-tight);letter-spacing:var(--tracking-tight)}.tracking-wide{--tw-tracking:var(--tracking-wide);letter-spacing:var(--tracking-wide)}.break-words{overflow-wrap:break-word}.break-all{word-break:break-all}.whitespace-nowrap{white-space:nowrap}.whitespace-pre-wrap{white-space:pre-wrap}.text-amber-700{color:var(--color-amber-700)}.text-amber-800{color:var(--color-amber-800)}.text-amber-900{color:var(--color-amber-900)}.text-amber-950{color:var(--color-amber-950)}.text-emerald-800{color:var(--color-emerald-800)}.text-emerald-900{color:var(--color-emerald-900)}.text-red-700{color:var(--color-red-700)}.text-sky-900{color:var(--color-sky-900)}.text-white{color:var(--color-white)}.text-zinc-300{color:var(--color-zinc-300)}.text-zinc-500{color:var(--color-zinc-500)}.text-zinc-600{color:var(--color-zinc-600)}.text-zinc-700{color:var(--color-zinc-700)}.text-zinc-800{color:var(--color-zinc-800)}.text-zinc-900{color:var(--color-zinc-900)}.capitalize{text-transform:capitalize}.uppercase{text-transform:uppercase}.tabular-nums{--tw-numeric-spacing:tabular-nums;font-variant-numeric:var(--tw-ordinal,) var(--tw-slashed-zero,) var(--tw-numeric-figure,) var(--tw-numeric-spacing,) var(--tw-numeric-fraction,)}.underline{text-decoration-line:underline}.underline-offset-2{text-underline-offset:2px}.accent-zinc-900{accent-color:var(--color-zinc-900)}.opacity-25{opacity:.25}.opacity-70{opacity:.7}.shadow{--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a), 0 1px 2px -1px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow-2xl{--tw-shadow:0 25px 50px -12px var(--tw-shadow-color,#00000040);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow-lg{--tw-shadow:0 10px 15px -3px var(--tw-shadow-color,#0000001a), 0 4px 6px -4px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow-md{--tw-shadow:0 4px 6px -1px var(--tw-shadow-color,#0000001a), 0 2px 4px -2px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow-sm{--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a), 0 1px 2px -1px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow-xl{--tw-shadow:0 20px 25px -5px var(--tw-shadow-color,#0000001a), 0 8px 10px -6px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.ring-1{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.ring-2{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.ring-white{--tw-ring-color:var(--color-white)}.ring-zinc-900{--tw-ring-color:var(--color-zinc-900)}.ring-offset-1{--tw-ring-offset-width:1px;--tw-ring-offset-shadow:var(--tw-ring-inset,) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color)}.invert{--tw-invert:invert(100%);filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}.filter{filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}.backdrop-blur{--tw-backdrop-blur:blur(8px);-webkit-backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,)}.transition-\\[color\\,background-color\\,box-shadow\\,scale\\]{transition-property:color,background-color,box-shadow,scale;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-colors{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-shadow{transition-property:box-shadow;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-transform{transition-property:transform,translate,scale,rotate;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.duration-700{--tw-duration:.7s;transition-duration:.7s}.ease-in-out{--tw-ease:var(--ease-in-out);transition-timing-function:var(--ease-in-out)}.select-none{-webkit-user-select:none;user-select:none}.placeholder\\:text-zinc-500::placeholder{color:var(--color-zinc-500)}@media (hover:hover){.hover\\:border-zinc-900:hover{border-color:var(--color-zinc-900)}.hover\\:bg-amber-200:hover{background-color:var(--color-amber-200)}.hover\\:bg-white:hover{background-color:var(--color-white)}.hover\\:bg-zinc-50:hover{background-color:var(--color-zinc-50)}.hover\\:bg-zinc-100:hover{background-color:var(--color-zinc-100)}.hover\\:bg-zinc-200:hover{background-color:var(--color-zinc-200)}.hover\\:bg-zinc-400\\/30:hover{background-color:#9f9fa94d}@supports (color:color-mix(in lab, red, red)){.hover\\:bg-zinc-400\\/30:hover{background-color:color-mix(in oklab, var(--color-zinc-400) 30%, transparent)}}.hover\\:bg-zinc-700:hover{background-color:var(--color-zinc-700)}.hover\\:text-amber-950:hover{color:var(--color-amber-950)}.hover\\:text-zinc-900:hover{color:var(--color-zinc-900)}.hover\\:opacity-100:hover{opacity:1}}.focus\\:outline-none:focus{--tw-outline-style:none;outline-style:none}.focus-visible\\:ring-2:focus-visible{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.focus-visible\\:ring-white:focus-visible{--tw-ring-color:var(--color-white)}.focus-visible\\:ring-zinc-900:focus-visible{--tw-ring-color:var(--color-zinc-900)}.focus-visible\\:ring-offset-1:focus-visible{--tw-ring-offset-width:1px;--tw-ring-offset-shadow:var(--tw-ring-inset,) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color)}.focus-visible\\:ring-offset-2:focus-visible{--tw-ring-offset-width:2px;--tw-ring-offset-shadow:var(--tw-ring-inset,) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color)}.focus-visible\\:outline-none:focus-visible{--tw-outline-style:none;outline-style:none}.focus-visible\\:ring-inset:focus-visible{--tw-ring-inset:inset}.disabled\\:cursor-default:disabled{cursor:default}.disabled\\:opacity-35:disabled{opacity:.35}.disabled\\:opacity-50:disabled{opacity:.5}@media (hover:hover){.disabled\\:hover\\:border-zinc-300:disabled:hover{border-color:var(--color-zinc-300)}}@media (prefers-reduced-motion:reduce){.motion-reduce\\:animate-none{animation:none}.motion-reduce\\:transition-none{transition-property:none}}@media (min-width:1200px){.min-\\[1200px\\]\\:top-\\[27px\\]{top:27px}.min-\\[1200px\\]\\:right-4{right:calc(var(--spacing) * 4)}}@media (min-width:640px){.sm\\:inline{display:inline}}@container (min-width:380px){.\\@min-\\[380px\\]\\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}}@container (min-width:400px){.\\@min-\\[400px\\]\\:inline{display:inline}}@container (min-width:460px){.\\@min-\\[460px\\]\\:inline{display:inline}.\\@min-\\[460px\\]\\:h-10{height:calc(var(--spacing) * 10)}.\\@min-\\[460px\\]\\:min-h-0{min-height:0}.\\@min-\\[460px\\]\\:flex-row{flex-direction:row}.\\@min-\\[460px\\]\\:justify-start{justify-content:flex-start}.\\@min-\\[460px\\]\\:gap-1\\.5{gap:calc(var(--spacing) * 1.5)}.\\@min-\\[460px\\]\\:truncate{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.\\@min-\\[460px\\]\\:px-2\\.5{padding-inline:calc(var(--spacing) * 2.5)}.\\@min-\\[460px\\]\\:py-0{padding-block:0}.\\@min-\\[460px\\]\\:text-left{text-align:left}.\\@min-\\[460px\\]\\:text-xs{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}}@container (min-width:500px){.\\@min-\\[500px\\]\\:inline{display:inline}.\\@min-\\[500px\\]\\:px-2{padding-inline:calc(var(--spacing) * 2)}}@container (min-width:520px){.\\@min-\\[520px\\]\\:ml-auto{margin-left:auto}.\\@min-\\[520px\\]\\:w-auto{width:auto}.\\@min-\\[520px\\]\\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.\\@min-\\[520px\\]\\:justify-start{justify-content:flex-start}}}:host{all:initial}.cbm-dark{color-scheme:dark;--color-white:oklch(21% .006 285.885);--color-zinc-50:oklch(24.5% .006 286);--color-zinc-100:oklch(27.4% .006 286.033);--color-zinc-200:oklch(33% .01 285.9);--color-zinc-300:oklch(42% .015 285.8);--color-zinc-400:oklch(52% .016 285.9);--color-zinc-500:oklch(68% .015 286.067);--color-zinc-600:oklch(74% .012 286);--color-zinc-700:oklch(82% .008 286.2);--color-zinc-800:oklch(88% .006 286.3);--color-zinc-900:oklch(96.7% .001 286.375);--color-zinc-950:oklch(98.5% 0 0);--color-amber-50:oklch(27.9% .077 45.635);--color-amber-100:oklch(33% .09 46);--color-amber-200:oklch(41.4% .112 45.904);--color-amber-300:oklch(55.5% .163 48.998);--color-amber-700:oklch(87.9% .169 91.605);--color-amber-800:oklch(92.4% .12 95.746);--color-amber-900:oklch(96.2% .059 95.617);--color-amber-950:oklch(98.7% .022 95.277);--color-emerald-50:oklch(26.2% .051 172.552);--color-emerald-800:oklch(90.5% .093 164.15);--color-emerald-900:oklch(95% .052 163.051);--color-sky-50:oklch(29.3% .066 243.157);--color-sky-100:oklch(39.1% .09 240.876);--color-sky-900:oklch(95.1% .026 236.824);--color-red-600:oklch(70.4% .191 22.216);--color-red-700:oklch(80.8% .114 19.571)}.cbm-dark *{--tw-ring-offset-color:oklch(21% .006 285.885)}.theme-scroll{--cbm-thumb:var(--color-primary,oklch(55.2% .016 285.938))}@supports (color:color-mix(in lab, red, red)){.theme-scroll{--cbm-thumb:color-mix(in srgb, var(--color-primary,var(--color-zinc-500)) 55%, var(--color-white))}}.theme-scroll{--cbm-thumb-hover:var(--color-primary,oklch(55.2% .016 285.938))}@supports (color:color-mix(in lab, red, red)){.theme-scroll{--cbm-thumb-hover:color-mix(in srgb, var(--color-primary,var(--color-zinc-500)) 80%, var(--color-white))}}.theme-scroll{scrollbar-width:thin;scrollbar-color:var(--cbm-thumb) transparent}.theme-scroll:hover{scrollbar-color:var(--cbm-thumb-hover) transparent}.theme-scroll::-webkit-scrollbar{width:6px}.theme-scroll::-webkit-scrollbar-track{background:0 0}.theme-scroll::-webkit-scrollbar-thumb{background:var(--cbm-thumb);border-radius:9999px}.theme-scroll:hover::-webkit-scrollbar-thumb{background:var(--cbm-thumb-hover)}.theme-panel{transform-origin:100% 0;animation:.16s ease-out theme-panel-in}@keyframes theme-panel-in{0%{opacity:0;transform:translateY(-6px)scale(.98)}}.theme-hint{animation:.12s ease-out theme-hint-in}.theme-toast{animation:.18s ease-out theme-toast-in}@keyframes theme-toast-in{0%{opacity:0;transform:translateY(8px)}}@keyframes theme-hint-in{0%{opacity:0}}.theme-arrive{animation:.62s cubic-bezier(.34,1.56,.64,1) both theme-arrive}@keyframes theme-arrive{0%{opacity:0;transform:scale(.2)rotate(-45deg)}60%{opacity:1;transform:scale(1.16)rotate(8deg)}to{transform:scale(1)rotate(0)}}.theme-burst-piece{line-height:0;animation:.95s cubic-bezier(.15,.75,.3,1) both theme-burst-piece;display:block;position:absolute;top:50%;left:50%}@keyframes theme-burst-piece{0%{opacity:0;transform:translate(-50%, -50%) rotate(var(--r)) scale(.3)}12%{opacity:1}65%{opacity:1}to{opacity:0;transform:translate(calc(-50% + var(--x)), calc(-50% + var(--y))) rotate(calc(var(--r) + 150deg)) scale(1)}}.theme-piece-dot{background:currentColor;border-radius:9999px;width:6px;height:6px}.theme-piece-dash{background:currentColor;border-radius:9999px;width:10px;height:3px}@media (prefers-reduced-motion:reduce){.theme-panel,.theme-hint,.theme-toast{animation:none}.theme-arrive{animation:.3s ease-out both theme-hint-in}.theme-burst{display:none}}.theme-panel summary{list-style:none}.theme-panel summary::-webkit-details-marker{display:none}.theme-panel details[open]>summary .theme-chevron{transform:rotate(90deg)}@keyframes spin{to{transform:rotate(360deg)}}";
|
|
5743
6772
|
//#endregion
|
|
5744
6773
|
//#region src/ThemeSwitcher.jsx
|
|
5745
6774
|
var CORNERS = {
|
|
@@ -5759,7 +6788,6 @@ var DRAG_THRESHOLD = 5;
|
|
|
5759
6788
|
var HINT_DELAY = 100;
|
|
5760
6789
|
var DOT_INTERVAL = 1500;
|
|
5761
6790
|
var INTRO_DELAY = 900;
|
|
5762
|
-
var BURST_TIME = 1100;
|
|
5763
6791
|
var FOCUSABLE = "a[href], button:not([disabled]), input:not([disabled]), textarea:not([disabled]), select:not([disabled]), summary, [tabindex]:not([tabindex=\"-1\"])";
|
|
5764
6792
|
/** Tag of the element that hosts the switcher's shadow root. The site scan skips it. */
|
|
5765
6793
|
var HOST_TAG = "colorsbymax-root";
|
|
@@ -5788,7 +6816,7 @@ function ThemeSwitcher() {
|
|
|
5788
6816
|
return mount && createPortal(/* @__PURE__ */ jsx(Switcher, {}), mount);
|
|
5789
6817
|
}
|
|
5790
6818
|
function Switcher() {
|
|
5791
|
-
const { issues, storageKey, tokens, position: requested, setLogoColouring, intro, mode, modeSetting, setMode, settingDefaults } = useTheme();
|
|
6819
|
+
const { issues, storageKey, tokens, position: requested, setLogoColouring, setColourStyle, setPaletteDefault, features, intro, mode, modeSetting, setMode, settingDefaults } = useTheme();
|
|
5792
6820
|
const position = CORNERS[requested] ? requested : "bottom-right";
|
|
5793
6821
|
const [open, setOpen] = useState(false);
|
|
5794
6822
|
const [arrived, setArrived] = useState(!intro);
|
|
@@ -5816,6 +6844,8 @@ function Switcher() {
|
|
|
5816
6844
|
}, [burst]);
|
|
5817
6845
|
const [settings, setSettings] = useState(() => loadSettings(storageKey, settingDefaults));
|
|
5818
6846
|
useEffect(() => setLogoColouring(settings.colourLogo), [settings.colourLogo, setLogoColouring]);
|
|
6847
|
+
useEffect(() => setColourStyle(settings.colourStyle), [settings.colourStyle, setColourStyle]);
|
|
6848
|
+
useEffect(() => setPaletteDefault(settings.paletteSize), [settings.paletteSize, setPaletteDefault]);
|
|
5819
6849
|
const [auditOn, setAuditOn] = useState(false);
|
|
5820
6850
|
const [findings, setFindings] = useState([]);
|
|
5821
6851
|
const recheck = useCallback(() => {
|
|
@@ -5945,6 +6975,10 @@ function Switcher() {
|
|
|
5945
6975
|
setOpen(false);
|
|
5946
6976
|
buttonRef.current?.focus();
|
|
5947
6977
|
}, []);
|
|
6978
|
+
const [kept, setKept] = useState(false);
|
|
6979
|
+
useEffect(() => {
|
|
6980
|
+
if (open) setKept(true);
|
|
6981
|
+
}, [open]);
|
|
5948
6982
|
const onDragStart = (e) => {
|
|
5949
6983
|
justDragged.current = false;
|
|
5950
6984
|
hideHint();
|
|
@@ -5997,7 +7031,13 @@ function Switcher() {
|
|
|
5997
7031
|
const settingsApi = {
|
|
5998
7032
|
settings: {
|
|
5999
7033
|
...settings,
|
|
6000
|
-
mode: modeSetting
|
|
7034
|
+
mode: modeSetting,
|
|
7035
|
+
showPicks: settings.showPicks && features.picks,
|
|
7036
|
+
showLibrary: settings.showLibrary && features.library,
|
|
7037
|
+
showCustom: settings.showCustom && features.custom,
|
|
7038
|
+
showOverrides: settings.showOverrides && features.overrides,
|
|
7039
|
+
showImportExport: settings.showImportExport && features.importExport,
|
|
7040
|
+
colourStyle: features.colourStyle ? settings.colourStyle : "colourful"
|
|
6001
7041
|
},
|
|
6002
7042
|
mode,
|
|
6003
7043
|
audit: {
|
|
@@ -6032,7 +7072,7 @@ function Switcher() {
|
|
|
6032
7072
|
const root = panel.getRootNode();
|
|
6033
7073
|
const focused = () => root.activeElement ?? document.activeElement;
|
|
6034
7074
|
const inside = (e, el) => e.composedPath().includes(el);
|
|
6035
|
-
panel.querySelector(FOCUSABLE)?.focus();
|
|
7075
|
+
panel.querySelector(FOCUSABLE)?.focus({ preventScroll: true });
|
|
6036
7076
|
const onKeyDown = (e) => {
|
|
6037
7077
|
if (e.key === "Escape") {
|
|
6038
7078
|
e.preventDefault();
|
|
@@ -6114,15 +7154,15 @@ function Switcher() {
|
|
|
6114
7154
|
})
|
|
6115
7155
|
]
|
|
6116
7156
|
}),
|
|
6117
|
-
open && /* @__PURE__ */ jsxs("div", {
|
|
7157
|
+
(open || kept) && /* @__PURE__ */ jsxs("div", {
|
|
6118
7158
|
ref: panelRef,
|
|
6119
7159
|
id: "theme-panel",
|
|
6120
7160
|
role: "dialog",
|
|
6121
7161
|
"aria-modal": "true",
|
|
6122
7162
|
"aria-labelledby": "theme-panel-title",
|
|
6123
7163
|
style: layout.style,
|
|
6124
|
-
className:
|
|
6125
|
-
children: [/* @__PURE__ */ jsx(ThemePanel, {}), /* @__PURE__ */ jsx(ResizeHandles, {
|
|
7164
|
+
className: `theme-switcher theme-panel fixed z-[60] ${open ? "flex" : "hidden"} flex-col rounded-2xl border border-zinc-200 bg-white text-zinc-900 shadow-2xl`,
|
|
7165
|
+
children: [/* @__PURE__ */ jsx(ThemePanel, { open }), /* @__PURE__ */ jsx(ResizeHandles, {
|
|
6126
7166
|
free: layout.free,
|
|
6127
7167
|
onStart: onResizeStart,
|
|
6128
7168
|
onMove: onResizeMove,
|
|
@@ -6184,59 +7224,6 @@ function CyclingDot({ tokens, animate }) {
|
|
|
6184
7224
|
style: { backgroundColor: still ? tokens.primary : colours[index % colours.length] }
|
|
6185
7225
|
});
|
|
6186
7226
|
}
|
|
6187
|
-
var BURST_KEYS = [
|
|
6188
|
-
"primary",
|
|
6189
|
-
"primary-alt",
|
|
6190
|
-
"data-1",
|
|
6191
|
-
"data-2",
|
|
6192
|
-
"data-3",
|
|
6193
|
-
"data-4",
|
|
6194
|
-
"warning",
|
|
6195
|
-
"data-5"
|
|
6196
|
-
];
|
|
6197
|
-
var BURST_PIECES = Array.from({ length: 12 }, (_, i) => {
|
|
6198
|
-
const angle = (i * 30 + (i % 2 ? 9 : -6)) * (Math.PI / 180);
|
|
6199
|
-
const distance = 30 + i % 3 * 9;
|
|
6200
|
-
return {
|
|
6201
|
-
x: Math.round(Math.cos(angle) * distance),
|
|
6202
|
-
y: Math.round(Math.sin(angle) * distance),
|
|
6203
|
-
r: Math.round(angle * 180 / Math.PI),
|
|
6204
|
-
shape: [
|
|
6205
|
-
"squiggle",
|
|
6206
|
-
"dot",
|
|
6207
|
-
"dash"
|
|
6208
|
-
][i % 3],
|
|
6209
|
-
delay: i % 4 * 25
|
|
6210
|
-
};
|
|
6211
|
-
});
|
|
6212
|
-
function Burst({ tokens }) {
|
|
6213
|
-
return /* @__PURE__ */ jsx("span", {
|
|
6214
|
-
"aria-hidden": "true",
|
|
6215
|
-
className: "theme-burst pointer-events-none absolute inset-0",
|
|
6216
|
-
children: BURST_PIECES.map((p, i) => /* @__PURE__ */ jsx("span", {
|
|
6217
|
-
className: `theme-burst-piece ${p.shape === "squiggle" ? "" : `theme-piece-${p.shape}`}`,
|
|
6218
|
-
style: {
|
|
6219
|
-
"--x": `${p.x}px`,
|
|
6220
|
-
"--y": `${p.y}px`,
|
|
6221
|
-
"--r": `${p.r}deg`,
|
|
6222
|
-
color: tokens[BURST_KEYS[i % BURST_KEYS.length]],
|
|
6223
|
-
animationDelay: `${p.delay}ms`
|
|
6224
|
-
},
|
|
6225
|
-
children: p.shape === "squiggle" && /* @__PURE__ */ jsx("svg", {
|
|
6226
|
-
width: "16",
|
|
6227
|
-
height: "10",
|
|
6228
|
-
viewBox: "0 0 16 10",
|
|
6229
|
-
fill: "none",
|
|
6230
|
-
children: /* @__PURE__ */ jsx("path", {
|
|
6231
|
-
d: "M1 5c1.6-3.6 3.4-3.6 4.6 0s3 3.6 4.6 0 3-3.6 4.4 0",
|
|
6232
|
-
stroke: "currentColor",
|
|
6233
|
-
strokeWidth: "2.2",
|
|
6234
|
-
strokeLinecap: "round"
|
|
6235
|
-
})
|
|
6236
|
-
})
|
|
6237
|
-
}, i))
|
|
6238
|
-
});
|
|
6239
|
-
}
|
|
6240
7227
|
function usePrefersReducedMotion() {
|
|
6241
7228
|
const query = "(prefers-reduced-motion: reduce)";
|
|
6242
7229
|
const [reduce, setReduce] = useState(() => window.matchMedia(query).matches);
|