colorsbymax 0.3.2 → 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 -89
- package/README.md +482 -476
- package/dist/{ThemeSwitcher-BlWfKjRg.js → ThemeSwitcher-DB_-2YB8.js} +1306 -261
- 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,
|
|
@@ -2878,19 +3541,214 @@ function removePreview() {
|
|
|
2878
3541
|
for (const el of document.querySelectorAll(`[${PREVIEW}]`)) el.remove();
|
|
2879
3542
|
}
|
|
2880
3543
|
//#endregion
|
|
2881
|
-
//#region src/
|
|
2882
|
-
var
|
|
2883
|
-
"
|
|
2884
|
-
"
|
|
2885
|
-
"
|
|
2886
|
-
|
|
2887
|
-
|
|
2888
|
-
|
|
2889
|
-
|
|
2890
|
-
|
|
2891
|
-
|
|
2892
|
-
|
|
3544
|
+
//#region src/logoMark.jsx
|
|
3545
|
+
var BARS = [
|
|
3546
|
+
"M57.13,163.05H0C28.34,108.7,56.67,54.35,85.01,0h55.44c-27.77,54.35-55.55,108.7-83.32,163.05Z",
|
|
3547
|
+
"M134.89,163.05h-57.13C106.1,108.7,134.43,54.35,162.77,0h55.44c-27.77,54.35-55.55,108.7-83.32,163.05Z",
|
|
3548
|
+
"M212.65,163.05h-57.13C183.86,108.7,212.19,54.35,240.53,0h55.44c-27.77,54.35-55.55,108.7-83.32,163.05Z"
|
|
3549
|
+
];
|
|
3550
|
+
var MIN_CONTRAST = 3;
|
|
3551
|
+
var hue = (hex) => rgbToHsl(hexToRgb(hex))[0];
|
|
3552
|
+
var hueGap = (a, b) => {
|
|
3553
|
+
const d = Math.abs(hue(a) - hue(b));
|
|
3554
|
+
return Math.min(d, 360 - d);
|
|
3555
|
+
};
|
|
3556
|
+
/** The three bars' colours for a theme. */
|
|
3557
|
+
function logoColours(tokens) {
|
|
3558
|
+
const [a, b] = [tokens["primary-alt"], tokens.primary];
|
|
3559
|
+
const apart = (x) => Math.min(hueGap(x, a), hueGap(x, b));
|
|
3560
|
+
let c = tokens["data-3"];
|
|
3561
|
+
for (let n = 1; n <= 8; n++) if (apart(tokens[`data-${n}`]) > apart(c)) c = tokens[`data-${n}`];
|
|
3562
|
+
return [
|
|
3563
|
+
a,
|
|
3564
|
+
b,
|
|
3565
|
+
c
|
|
3566
|
+
];
|
|
3567
|
+
}
|
|
3568
|
+
/** Moves a colour towards black (on light) or white (on dark) until it reads on `background`. */
|
|
3569
|
+
function standOut(hex, background) {
|
|
3570
|
+
const target = contrastRatio(background, "#000000") > contrastRatio(background, "#ffffff") ? "#000000" : "#ffffff";
|
|
3571
|
+
for (let t = 0; t <= 1; t += .05) {
|
|
3572
|
+
const out = mix(target, hex, t);
|
|
3573
|
+
if (contrastRatio(out, background) >= MIN_CONTRAST) return out;
|
|
3574
|
+
}
|
|
3575
|
+
return target;
|
|
3576
|
+
}
|
|
3577
|
+
/** @param {{ tokens: Record<string, string>, background: string, className?: string }} props */
|
|
3578
|
+
function LogoMark({ tokens, background, className = "" }) {
|
|
3579
|
+
const colours = logoColours(tokens).map((c) => standOut(c, background));
|
|
3580
|
+
return /* @__PURE__ */ jsx("svg", {
|
|
3581
|
+
viewBox: "0 0 296 163.05",
|
|
3582
|
+
className,
|
|
3583
|
+
"aria-hidden": "true",
|
|
3584
|
+
children: BARS.map((d, i) => /* @__PURE__ */ jsx("path", {
|
|
3585
|
+
d,
|
|
3586
|
+
fill: colours[i]
|
|
3587
|
+
}, i))
|
|
3588
|
+
});
|
|
3589
|
+
}
|
|
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
|
+
]
|
|
2893
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
|
|
3750
|
+
//#region src/ThemePanel.jsx
|
|
3751
|
+
var PANEL_DARK = "#18181b";
|
|
2894
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";
|
|
2895
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";
|
|
2896
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";
|
|
@@ -2924,7 +3782,12 @@ function useSavedToYours() {
|
|
|
2924
3782
|
});
|
|
2925
3783
|
};
|
|
2926
3784
|
}
|
|
2927
|
-
|
|
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 }) {
|
|
2928
3791
|
const theme = useTheme();
|
|
2929
3792
|
const { settings, mode, audit, update } = useSettings();
|
|
2930
3793
|
const overrideCount = Object.keys(theme.state.overrides).length;
|
|
@@ -2933,6 +3796,11 @@ function ThemePanel() {
|
|
|
2933
3796
|
const rootRef = useRef(null);
|
|
2934
3797
|
const [toasts, setToasts] = useState([]);
|
|
2935
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]);
|
|
2936
3804
|
const toast = useCallback((text, action) => setToasts((list) => [...list.slice(-2), {
|
|
2937
3805
|
id: ++toastSeq,
|
|
2938
3806
|
text,
|
|
@@ -2975,22 +3843,32 @@ function ThemePanel() {
|
|
|
2975
3843
|
value: panelApi,
|
|
2976
3844
|
children: [/* @__PURE__ */ jsxs("div", {
|
|
2977
3845
|
ref: rootRef,
|
|
3846
|
+
onScroll: (e) => {
|
|
3847
|
+
if (open) scrollTop.current = e.currentTarget.scrollTop;
|
|
3848
|
+
},
|
|
2978
3849
|
className: "theme-scroll @container flex min-h-0 flex-1 flex-col overflow-y-auto overscroll-contain rounded-[inherit]",
|
|
2979
3850
|
children: [
|
|
2980
3851
|
/* @__PURE__ */ jsxs("header", {
|
|
2981
|
-
className: "sticky top-0 z-10 flex items-
|
|
2982
|
-
children: [/* @__PURE__ */ jsxs("div", {
|
|
2983
|
-
|
|
2984
|
-
|
|
2985
|
-
|
|
2986
|
-
|
|
2987
|
-
|
|
2988
|
-
})
|
|
2989
|
-
|
|
2990
|
-
|
|
2991
|
-
|
|
2992
|
-
|
|
2993
|
-
|
|
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",
|
|
3853
|
+
children: [/* @__PURE__ */ jsxs("div", {
|
|
3854
|
+
className: "flex w-full shrink-0 items-center justify-center gap-2 @min-[520px]:w-auto @min-[520px]:justify-start",
|
|
3855
|
+
children: [/* @__PURE__ */ jsx(LogoMark, {
|
|
3856
|
+
tokens: theme.tokens,
|
|
3857
|
+
background: mode === "dark" ? PANEL_DARK : "#ffffff",
|
|
3858
|
+
className: "h-7 w-auto shrink-0"
|
|
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: "™"
|
|
3865
|
+
})]
|
|
3866
|
+
}), /* @__PURE__ */ jsx("p", {
|
|
3867
|
+
className: "text-[11px] text-zinc-500",
|
|
3868
|
+
children: "by mrmaxdesigns"
|
|
3869
|
+
})] })]
|
|
3870
|
+
}), /* @__PURE__ */ jsxs("div", {
|
|
3871
|
+
className: "flex w-full items-center justify-center gap-1 @min-[520px]:ml-auto @min-[520px]:w-auto",
|
|
2994
3872
|
children: [
|
|
2995
3873
|
/* @__PURE__ */ jsx("div", {
|
|
2996
3874
|
role: "radiogroup",
|
|
@@ -3013,7 +3891,7 @@ function ThemePanel() {
|
|
|
3013
3891
|
}, id);
|
|
3014
3892
|
})
|
|
3015
3893
|
}),
|
|
3016
|
-
/* @__PURE__ */ jsxs("button", {
|
|
3894
|
+
theme.features.addToSite && /* @__PURE__ */ jsxs("button", {
|
|
3017
3895
|
type: "button",
|
|
3018
3896
|
onClick: (e) => view === "mode-toggle" ? setView("main") : showView("mode-toggle", e.currentTarget),
|
|
3019
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"}`,
|
|
@@ -3028,7 +3906,7 @@ function ThemePanel() {
|
|
|
3028
3906
|
children: "Add to site"
|
|
3029
3907
|
})]
|
|
3030
3908
|
}),
|
|
3031
|
-
/* @__PURE__ */ jsxs("button", {
|
|
3909
|
+
theme.features.audit && /* @__PURE__ */ jsxs("button", {
|
|
3032
3910
|
type: "button",
|
|
3033
3911
|
onClick: audit.toggle,
|
|
3034
3912
|
className: `${btn} px-2 ${audit.on ? "border-zinc-900 bg-zinc-100" : "border-transparent"}`,
|
|
@@ -3065,7 +3943,6 @@ function ThemePanel() {
|
|
|
3065
3943
|
children: [
|
|
3066
3944
|
/* @__PURE__ */ jsx(Section, {
|
|
3067
3945
|
title: "Preset themes",
|
|
3068
|
-
defaultOpen: true,
|
|
3069
3946
|
children: /* @__PURE__ */ jsx(PresetGrid, {})
|
|
3070
3947
|
}),
|
|
3071
3948
|
settings.showCustom && /* @__PURE__ */ jsx(Section, {
|
|
@@ -3365,8 +4242,9 @@ var FINISH_OPTIONS = [
|
|
|
3365
4242
|
* here only, or remove colorsbymax, each with code and a prompt for an AI editor. Cancel goes back.
|
|
3366
4243
|
*/
|
|
3367
4244
|
function FinishView({ onBack }) {
|
|
3368
|
-
const { tokens, active, recolouring } = useTheme();
|
|
3369
|
-
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;
|
|
3370
4248
|
const [choice, setChoice] = useState("keep");
|
|
3371
4249
|
const [kind, setKind] = useState(() => document.querySelector("[data-colorsbymax=\"auto\"]") ? "auto" : "provider");
|
|
3372
4250
|
const headingRef = useRef(null);
|
|
@@ -3613,6 +4491,7 @@ var MODES = [
|
|
|
3613
4491
|
/** The visitor's preferences for the panel and colour button. */
|
|
3614
4492
|
function SettingsView({ onBack }) {
|
|
3615
4493
|
const { settings, update, reset, resetButton } = useSettings();
|
|
4494
|
+
const { active, features } = useTheme();
|
|
3616
4495
|
const { toast } = usePanel();
|
|
3617
4496
|
const headingRef = useRef(null);
|
|
3618
4497
|
useEffect(() => headingRef.current?.focus(), []);
|
|
@@ -3669,6 +4548,40 @@ function SettingsView({ onBack }) {
|
|
|
3669
4548
|
})
|
|
3670
4549
|
]
|
|
3671
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
|
+
}),
|
|
3672
4585
|
/* @__PURE__ */ jsxs("fieldset", {
|
|
3673
4586
|
className: "space-y-1.5",
|
|
3674
4587
|
children: [
|
|
@@ -3711,29 +4624,29 @@ function SettingsView({ onBack }) {
|
|
|
3711
4624
|
className: "mb-1 text-[11px] font-semibold uppercase tracking-wide text-zinc-600",
|
|
3712
4625
|
children: "Show"
|
|
3713
4626
|
}),
|
|
3714
|
-
/* @__PURE__ */ jsx(Toggle, {
|
|
4627
|
+
features.picks && /* @__PURE__ */ jsx(Toggle, {
|
|
3715
4628
|
checked: settings.showPicks,
|
|
3716
4629
|
onChange: (v) => update({ showPicks: v }),
|
|
3717
4630
|
label: "Max’s picks",
|
|
3718
4631
|
note: "Hand-tuned colorsbymax themes"
|
|
3719
4632
|
}),
|
|
3720
|
-
/* @__PURE__ */ jsx(Toggle, {
|
|
4633
|
+
features.library && /* @__PURE__ */ jsx(Toggle, {
|
|
3721
4634
|
checked: settings.showLibrary,
|
|
3722
4635
|
onChange: (v) => update({ showLibrary: v }),
|
|
3723
4636
|
label: "Theme library",
|
|
3724
4637
|
note: "Hundreds of themes in categories, with search"
|
|
3725
4638
|
}),
|
|
3726
|
-
/* @__PURE__ */ jsx(Toggle, {
|
|
4639
|
+
features.custom && /* @__PURE__ */ jsx(Toggle, {
|
|
3727
4640
|
checked: settings.showCustom,
|
|
3728
4641
|
onChange: (v) => update({ showCustom: v }),
|
|
3729
4642
|
label: "Custom palettes"
|
|
3730
4643
|
}),
|
|
3731
|
-
/* @__PURE__ */ jsx(Toggle, {
|
|
4644
|
+
features.overrides && /* @__PURE__ */ jsx(Toggle, {
|
|
3732
4645
|
checked: settings.showOverrides,
|
|
3733
4646
|
onChange: (v) => update({ showOverrides: v }),
|
|
3734
4647
|
label: "Override a single colour"
|
|
3735
4648
|
}),
|
|
3736
|
-
/* @__PURE__ */ jsx(Toggle, {
|
|
4649
|
+
features.importExport && /* @__PURE__ */ jsx(Toggle, {
|
|
3737
4650
|
checked: settings.showImportExport,
|
|
3738
4651
|
onChange: (v) => update({ showImportExport: v }),
|
|
3739
4652
|
label: "Import / export"
|
|
@@ -3951,20 +4864,78 @@ function IssuesLink() {
|
|
|
3951
4864
|
]
|
|
3952
4865
|
});
|
|
3953
4866
|
}
|
|
3954
|
-
|
|
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 }) {
|
|
3955
4869
|
return /* @__PURE__ */ jsx("div", {
|
|
3956
4870
|
className: "flex overflow-hidden rounded-md border border-zinc-200",
|
|
3957
4871
|
"aria-hidden": "true",
|
|
3958
|
-
children:
|
|
4872
|
+
children: paletteKeys(tokens, count).map((key) => /* @__PURE__ */ jsx("span", {
|
|
3959
4873
|
className: "h-5 flex-1",
|
|
3960
4874
|
style: { background: tokens[key] }
|
|
3961
4875
|
}, key))
|
|
3962
4876
|
});
|
|
3963
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
|
+
}
|
|
3964
4925
|
var PAGE_SIZE = 24;
|
|
3965
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
|
+
}];
|
|
3966
4936
|
function PresetGrid() {
|
|
3967
|
-
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();
|
|
3968
4939
|
const { settings, mode, update } = useSettings();
|
|
3969
4940
|
const categoriesId = useId();
|
|
3970
4941
|
const [loaded, setLoaded] = useState(null);
|
|
@@ -3993,6 +4964,8 @@ function PresetGrid() {
|
|
|
3993
4964
|
if (scrollToThemes.current && themesRef.current) {
|
|
3994
4965
|
scrollToThemes.current = false;
|
|
3995
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`;
|
|
3996
4969
|
themesRef.current.scrollIntoView({
|
|
3997
4970
|
block: "start",
|
|
3998
4971
|
behavior: still ? "auto" : "smooth"
|
|
@@ -4067,7 +5040,9 @@ function PresetGrid() {
|
|
|
4067
5040
|
else list = (library?.themes ?? []).filter((t) => t.tags.includes(category));
|
|
4068
5041
|
if (q) {
|
|
4069
5042
|
const labels = Object.fromEntries((library?.categories ?? []).map((c) => [c.id, c.label.toLowerCase()]));
|
|
4070
|
-
|
|
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)) : []];
|
|
4071
5046
|
}
|
|
4072
5047
|
return list;
|
|
4073
5048
|
}, [
|
|
@@ -4093,14 +5068,20 @@ function PresetGrid() {
|
|
|
4093
5068
|
};
|
|
4094
5069
|
const pick = (t) => selectTheme(t.id, t);
|
|
4095
5070
|
const surprise = () => {
|
|
4096
|
-
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;
|
|
4097
5074
|
pick(inMode(pool[Math.floor(Math.random() * pool.length)], mode));
|
|
5075
|
+
surpriseBurst.celebrate();
|
|
4098
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;
|
|
4099
5080
|
return /* @__PURE__ */ jsxs("div", {
|
|
4100
5081
|
ref: wrapRef,
|
|
4101
5082
|
className: "space-y-3",
|
|
4102
5083
|
children: [
|
|
4103
|
-
/* @__PURE__ */ jsx(ScanCard, {}),
|
|
5084
|
+
features.scan && /* @__PURE__ */ jsx(ScanCard, {}),
|
|
4104
5085
|
/* @__PURE__ */ jsxs("p", {
|
|
4105
5086
|
className: "text-xs text-zinc-600",
|
|
4106
5087
|
children: ["Current theme: ", /* @__PURE__ */ jsx("strong", {
|
|
@@ -4108,6 +5089,31 @@ function PresetGrid() {
|
|
|
4108
5089
|
children: active.name
|
|
4109
5090
|
})]
|
|
4110
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
|
+
}),
|
|
4111
5117
|
overrideCount > 0 && /* @__PURE__ */ jsxs("p", {
|
|
4112
5118
|
className: "flex items-center justify-between gap-2 rounded-lg bg-zinc-100 px-3 py-2 text-xs text-zinc-700",
|
|
4113
5119
|
children: [
|
|
@@ -4126,38 +5132,94 @@ function PresetGrid() {
|
|
|
4126
5132
|
})
|
|
4127
5133
|
]
|
|
4128
5134
|
}),
|
|
4129
|
-
/* @__PURE__ */ jsxs("div", {
|
|
5135
|
+
(features.search || features.surprise) && /* @__PURE__ */ jsxs("div", {
|
|
4130
5136
|
className: "flex gap-2",
|
|
4131
|
-
children: [
|
|
4132
|
-
|
|
4133
|
-
|
|
4134
|
-
|
|
4135
|
-
|
|
4136
|
-
|
|
4137
|
-
|
|
4138
|
-
|
|
4139
|
-
|
|
4140
|
-
|
|
4141
|
-
|
|
4142
|
-
value
|
|
4143
|
-
|
|
4144
|
-
|
|
4145
|
-
|
|
4146
|
-
|
|
4147
|
-
}
|
|
4148
|
-
|
|
4149
|
-
|
|
4150
|
-
|
|
4151
|
-
|
|
4152
|
-
disabled: !library && needsLibrary,
|
|
4153
|
-
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, {
|
|
4154
5158
|
className: "w-3.5 h-3.5",
|
|
4155
5159
|
"aria-hidden": "true"
|
|
4156
|
-
}),
|
|
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);
|
|
4157
5219
|
})
|
|
4158
|
-
]
|
|
5220
|
+
})]
|
|
4159
5221
|
}),
|
|
4160
|
-
/* @__PURE__ */ jsx("div", {
|
|
5222
|
+
!q && /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("div", {
|
|
4161
5223
|
role: "group",
|
|
4162
5224
|
"aria-label": "Your groups",
|
|
4163
5225
|
"data-groups": true,
|
|
@@ -4168,77 +5230,87 @@ function PresetGrid() {
|
|
|
4168
5230
|
type: "button",
|
|
4169
5231
|
"aria-pressed": on,
|
|
4170
5232
|
"data-tip": `${g.description} (${g.count} ${g.count === 1 ? "theme" : "themes"})`,
|
|
4171
|
-
onClick: () => choose(g.id),
|
|
4172
|
-
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"}`,
|
|
4173
5235
|
children: [
|
|
4174
5236
|
/* @__PURE__ */ jsx(g.Icon, {
|
|
4175
5237
|
className: "w-4 h-4 shrink-0",
|
|
4176
5238
|
"aria-hidden": "true"
|
|
4177
5239
|
}),
|
|
4178
5240
|
/* @__PURE__ */ jsx("span", {
|
|
4179
|
-
className: "max-w-full truncate",
|
|
5241
|
+
className: "max-w-full text-center break-words @min-[460px]:truncate @min-[460px]:text-left",
|
|
4180
5242
|
children: g.label
|
|
4181
5243
|
}),
|
|
4182
5244
|
/* @__PURE__ */ jsx("span", {
|
|
4183
|
-
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"}`,
|
|
4184
5246
|
children: g.count
|
|
4185
5247
|
})
|
|
4186
5248
|
]
|
|
4187
5249
|
}, g.id);
|
|
4188
5250
|
})
|
|
4189
|
-
}),
|
|
4190
|
-
|
|
4191
|
-
|
|
4192
|
-
"
|
|
4193
|
-
|
|
4194
|
-
|
|
4195
|
-
|
|
4196
|
-
|
|
4197
|
-
|
|
4198
|
-
|
|
4199
|
-
|
|
4200
|
-
|
|
4201
|
-
|
|
4202
|
-
|
|
4203
|
-
|
|
4204
|
-
|
|
4205
|
-
|
|
4206
|
-
|
|
4207
|
-
|
|
4208
|
-
|
|
4209
|
-
|
|
4210
|
-
|
|
4211
|
-
|
|
4212
|
-
|
|
4213
|
-
|
|
4214
|
-
|
|
4215
|
-
|
|
4216
|
-
|
|
4217
|
-
className: "grid grid-cols-2 @min-[380px]:grid-cols-3 gap-2",
|
|
4218
|
-
children: categories.map((c) => {
|
|
4219
|
-
const on = !q && category === c.id;
|
|
4220
|
-
return /* @__PURE__ */ jsxs("button", {
|
|
4221
|
-
type: "button",
|
|
4222
|
-
"aria-pressed": on,
|
|
4223
|
-
"data-tip": c.description,
|
|
4224
|
-
onClick: () => choose(c.id, { scroll: true }),
|
|
4225
|
-
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"}`,
|
|
4226
|
-
children: [
|
|
4227
|
-
on && /* @__PURE__ */ jsx(Check, {
|
|
4228
|
-
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"}`,
|
|
4229
5279
|
"aria-hidden": "true"
|
|
4230
|
-
})
|
|
4231
|
-
|
|
4232
|
-
|
|
4233
|
-
|
|
4234
|
-
|
|
4235
|
-
|
|
4236
|
-
|
|
4237
|
-
|
|
4238
|
-
|
|
4239
|
-
|
|
4240
|
-
|
|
4241
|
-
|
|
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
|
+
})]
|
|
4242
5314
|
})] }),
|
|
4243
5315
|
/* @__PURE__ */ jsx("div", {
|
|
4244
5316
|
ref: themesRef,
|
|
@@ -4264,7 +5336,7 @@ function PresetGrid() {
|
|
|
4264
5336
|
"”."
|
|
4265
5337
|
]
|
|
4266
5338
|
}) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
4267
|
-
/* @__PURE__ */ jsxs("p", {
|
|
5339
|
+
!q && /* @__PURE__ */ jsxs("p", {
|
|
4268
5340
|
className: "sr-only",
|
|
4269
5341
|
role: "status",
|
|
4270
5342
|
children: [visible.length, " themes"]
|
|
@@ -4383,58 +5455,73 @@ function ScanCard() {
|
|
|
4383
5455
|
});
|
|
4384
5456
|
}
|
|
4385
5457
|
function ThemeCard({ theme: t, isActive, onSelect }) {
|
|
4386
|
-
const { issues } = useTheme();
|
|
5458
|
+
const { issues, coloursOf, setThemeColours, features } = useTheme();
|
|
5459
|
+
const colours = coloursOf(t.id);
|
|
4387
5460
|
const showContrast = useContext(ContrastNav);
|
|
4388
5461
|
const stored = useMemo(() => t.library && !t.derived ? 0 : checkTheme(t.tokens).length, [t]);
|
|
4389
5462
|
const count = isActive ? issues.length : stored;
|
|
4390
5463
|
return /* @__PURE__ */ jsxs("div", {
|
|
4391
5464
|
className: "relative",
|
|
4392
|
-
children: [
|
|
4393
|
-
|
|
4394
|
-
|
|
4395
|
-
|
|
4396
|
-
|
|
4397
|
-
|
|
4398
|
-
|
|
4399
|
-
|
|
4400
|
-
|
|
4401
|
-
|
|
4402
|
-
|
|
4403
|
-
|
|
4404
|
-
|
|
4405
|
-
|
|
4406
|
-
|
|
4407
|
-
|
|
4408
|
-
|
|
4409
|
-
|
|
4410
|
-
|
|
4411
|
-
|
|
4412
|
-
|
|
4413
|
-
|
|
4414
|
-
|
|
4415
|
-
|
|
4416
|
-
|
|
4417
|
-
|
|
4418
|
-
|
|
4419
|
-
|
|
4420
|
-
|
|
4421
|
-
|
|
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`
|
|
4422
5522
|
})
|
|
4423
|
-
|
|
4424
|
-
|
|
4425
|
-
type: "button",
|
|
4426
|
-
onClick: (e) => {
|
|
4427
|
-
if (!isActive) onSelect();
|
|
4428
|
-
showContrast(e.currentTarget);
|
|
4429
|
-
},
|
|
4430
|
-
"aria-label": `${t.name} has ${count} contrast ${count === 1 ? "problem" : "problems"}. Review and fix`,
|
|
4431
|
-
"data-tip": "Contrast problems: review and fix",
|
|
4432
|
-
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",
|
|
4433
|
-
children: [/* @__PURE__ */ jsx(AlertTriangle, {
|
|
4434
|
-
className: "w-3 h-3",
|
|
4435
|
-
"aria-hidden": "true"
|
|
4436
|
-
}), count]
|
|
4437
|
-
})]
|
|
5523
|
+
})
|
|
5524
|
+
]
|
|
4438
5525
|
});
|
|
4439
5526
|
}
|
|
4440
5527
|
function CustomPalettes() {
|
|
@@ -5681,7 +6768,7 @@ function AuditBar({ anchorRect, open, hiddenCount, themeIssues, onRecheck, onClo
|
|
|
5681
6768
|
}
|
|
5682
6769
|
//#endregion
|
|
5683
6770
|
//#region src/panel-css.generated.js
|
|
5684
|
-
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-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)}}";
|
|
5685
6772
|
//#endregion
|
|
5686
6773
|
//#region src/ThemeSwitcher.jsx
|
|
5687
6774
|
var CORNERS = {
|
|
@@ -5701,7 +6788,6 @@ var DRAG_THRESHOLD = 5;
|
|
|
5701
6788
|
var HINT_DELAY = 100;
|
|
5702
6789
|
var DOT_INTERVAL = 1500;
|
|
5703
6790
|
var INTRO_DELAY = 900;
|
|
5704
|
-
var BURST_TIME = 1100;
|
|
5705
6791
|
var FOCUSABLE = "a[href], button:not([disabled]), input:not([disabled]), textarea:not([disabled]), select:not([disabled]), summary, [tabindex]:not([tabindex=\"-1\"])";
|
|
5706
6792
|
/** Tag of the element that hosts the switcher's shadow root. The site scan skips it. */
|
|
5707
6793
|
var HOST_TAG = "colorsbymax-root";
|
|
@@ -5730,7 +6816,7 @@ function ThemeSwitcher() {
|
|
|
5730
6816
|
return mount && createPortal(/* @__PURE__ */ jsx(Switcher, {}), mount);
|
|
5731
6817
|
}
|
|
5732
6818
|
function Switcher() {
|
|
5733
|
-
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();
|
|
5734
6820
|
const position = CORNERS[requested] ? requested : "bottom-right";
|
|
5735
6821
|
const [open, setOpen] = useState(false);
|
|
5736
6822
|
const [arrived, setArrived] = useState(!intro);
|
|
@@ -5758,6 +6844,8 @@ function Switcher() {
|
|
|
5758
6844
|
}, [burst]);
|
|
5759
6845
|
const [settings, setSettings] = useState(() => loadSettings(storageKey, settingDefaults));
|
|
5760
6846
|
useEffect(() => setLogoColouring(settings.colourLogo), [settings.colourLogo, setLogoColouring]);
|
|
6847
|
+
useEffect(() => setColourStyle(settings.colourStyle), [settings.colourStyle, setColourStyle]);
|
|
6848
|
+
useEffect(() => setPaletteDefault(settings.paletteSize), [settings.paletteSize, setPaletteDefault]);
|
|
5761
6849
|
const [auditOn, setAuditOn] = useState(false);
|
|
5762
6850
|
const [findings, setFindings] = useState([]);
|
|
5763
6851
|
const recheck = useCallback(() => {
|
|
@@ -5887,6 +6975,10 @@ function Switcher() {
|
|
|
5887
6975
|
setOpen(false);
|
|
5888
6976
|
buttonRef.current?.focus();
|
|
5889
6977
|
}, []);
|
|
6978
|
+
const [kept, setKept] = useState(false);
|
|
6979
|
+
useEffect(() => {
|
|
6980
|
+
if (open) setKept(true);
|
|
6981
|
+
}, [open]);
|
|
5890
6982
|
const onDragStart = (e) => {
|
|
5891
6983
|
justDragged.current = false;
|
|
5892
6984
|
hideHint();
|
|
@@ -5939,7 +7031,13 @@ function Switcher() {
|
|
|
5939
7031
|
const settingsApi = {
|
|
5940
7032
|
settings: {
|
|
5941
7033
|
...settings,
|
|
5942
|
-
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"
|
|
5943
7041
|
},
|
|
5944
7042
|
mode,
|
|
5945
7043
|
audit: {
|
|
@@ -5974,7 +7072,7 @@ function Switcher() {
|
|
|
5974
7072
|
const root = panel.getRootNode();
|
|
5975
7073
|
const focused = () => root.activeElement ?? document.activeElement;
|
|
5976
7074
|
const inside = (e, el) => e.composedPath().includes(el);
|
|
5977
|
-
panel.querySelector(FOCUSABLE)?.focus();
|
|
7075
|
+
panel.querySelector(FOCUSABLE)?.focus({ preventScroll: true });
|
|
5978
7076
|
const onKeyDown = (e) => {
|
|
5979
7077
|
if (e.key === "Escape") {
|
|
5980
7078
|
e.preventDefault();
|
|
@@ -6056,15 +7154,15 @@ function Switcher() {
|
|
|
6056
7154
|
})
|
|
6057
7155
|
]
|
|
6058
7156
|
}),
|
|
6059
|
-
open && /* @__PURE__ */ jsxs("div", {
|
|
7157
|
+
(open || kept) && /* @__PURE__ */ jsxs("div", {
|
|
6060
7158
|
ref: panelRef,
|
|
6061
7159
|
id: "theme-panel",
|
|
6062
7160
|
role: "dialog",
|
|
6063
7161
|
"aria-modal": "true",
|
|
6064
7162
|
"aria-labelledby": "theme-panel-title",
|
|
6065
7163
|
style: layout.style,
|
|
6066
|
-
className:
|
|
6067
|
-
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, {
|
|
6068
7166
|
free: layout.free,
|
|
6069
7167
|
onStart: onResizeStart,
|
|
6070
7168
|
onMove: onResizeMove,
|
|
@@ -6126,59 +7224,6 @@ function CyclingDot({ tokens, animate }) {
|
|
|
6126
7224
|
style: { backgroundColor: still ? tokens.primary : colours[index % colours.length] }
|
|
6127
7225
|
});
|
|
6128
7226
|
}
|
|
6129
|
-
var BURST_KEYS = [
|
|
6130
|
-
"primary",
|
|
6131
|
-
"primary-alt",
|
|
6132
|
-
"data-1",
|
|
6133
|
-
"data-2",
|
|
6134
|
-
"data-3",
|
|
6135
|
-
"data-4",
|
|
6136
|
-
"warning",
|
|
6137
|
-
"data-5"
|
|
6138
|
-
];
|
|
6139
|
-
var BURST_PIECES = Array.from({ length: 12 }, (_, i) => {
|
|
6140
|
-
const angle = (i * 30 + (i % 2 ? 9 : -6)) * (Math.PI / 180);
|
|
6141
|
-
const distance = 30 + i % 3 * 9;
|
|
6142
|
-
return {
|
|
6143
|
-
x: Math.round(Math.cos(angle) * distance),
|
|
6144
|
-
y: Math.round(Math.sin(angle) * distance),
|
|
6145
|
-
r: Math.round(angle * 180 / Math.PI),
|
|
6146
|
-
shape: [
|
|
6147
|
-
"squiggle",
|
|
6148
|
-
"dot",
|
|
6149
|
-
"dash"
|
|
6150
|
-
][i % 3],
|
|
6151
|
-
delay: i % 4 * 25
|
|
6152
|
-
};
|
|
6153
|
-
});
|
|
6154
|
-
function Burst({ tokens }) {
|
|
6155
|
-
return /* @__PURE__ */ jsx("span", {
|
|
6156
|
-
"aria-hidden": "true",
|
|
6157
|
-
className: "theme-burst pointer-events-none absolute inset-0",
|
|
6158
|
-
children: BURST_PIECES.map((p, i) => /* @__PURE__ */ jsx("span", {
|
|
6159
|
-
className: `theme-burst-piece ${p.shape === "squiggle" ? "" : `theme-piece-${p.shape}`}`,
|
|
6160
|
-
style: {
|
|
6161
|
-
"--x": `${p.x}px`,
|
|
6162
|
-
"--y": `${p.y}px`,
|
|
6163
|
-
"--r": `${p.r}deg`,
|
|
6164
|
-
color: tokens[BURST_KEYS[i % BURST_KEYS.length]],
|
|
6165
|
-
animationDelay: `${p.delay}ms`
|
|
6166
|
-
},
|
|
6167
|
-
children: p.shape === "squiggle" && /* @__PURE__ */ jsx("svg", {
|
|
6168
|
-
width: "16",
|
|
6169
|
-
height: "10",
|
|
6170
|
-
viewBox: "0 0 16 10",
|
|
6171
|
-
fill: "none",
|
|
6172
|
-
children: /* @__PURE__ */ jsx("path", {
|
|
6173
|
-
d: "M1 5c1.6-3.6 3.4-3.6 4.6 0s3 3.6 4.6 0 3-3.6 4.4 0",
|
|
6174
|
-
stroke: "currentColor",
|
|
6175
|
-
strokeWidth: "2.2",
|
|
6176
|
-
strokeLinecap: "round"
|
|
6177
|
-
})
|
|
6178
|
-
})
|
|
6179
|
-
}, i))
|
|
6180
|
-
});
|
|
6181
|
-
}
|
|
6182
7227
|
function usePrefersReducedMotion() {
|
|
6183
7228
|
const query = "(prefers-reduced-motion: reduce)";
|
|
6184
7229
|
const [reduce, setReduce] = useState(() => window.matchMedia(query).matches);
|