Fixed Some Bugs
This commit is contained in:
@@ -27,6 +27,8 @@ const {
|
|||||||
{ key: "sunset", label: "Sunset" },
|
{ key: "sunset", label: "Sunset" },
|
||||||
{ key: "grape", label: "Grape" },
|
{ key: "grape", label: "Grape" },
|
||||||
{ key: "slate", label: "Slate" },
|
{ key: "slate", label: "Slate" },
|
||||||
|
{ key: "gray", label: "Gray" },
|
||||||
|
{ key: "neutral", label: "Neutral" },
|
||||||
{ key: "mint", label: "Mint" },
|
{ key: "mint", label: "Mint" },
|
||||||
{ key: "amber", label: "Amber" },
|
{ key: "amber", label: "Amber" },
|
||||||
{ key: "crimson", label: "Crimson" },
|
{ key: "crimson", label: "Crimson" },
|
||||||
|
|||||||
+110
-88
@@ -197,13 +197,18 @@ const id = `dd-${Math.random().toString(36).slice(2)}`;
|
|||||||
|
|
||||||
const side = sideOf(pref);
|
const side = sideOf(pref);
|
||||||
const align = alignOf(pref);
|
const align = alignOf(pref);
|
||||||
|
|
||||||
|
const AR = showArrow && arrowEl ? 8 : 0; // arrow size
|
||||||
|
const SAFE = Math.max(shiftPadding, 8); // viewport padding
|
||||||
|
const GAP = offset + AR; // desired gap + arrow
|
||||||
|
|
||||||
let x = 0,
|
let x = 0,
|
||||||
y = 0;
|
y = 0;
|
||||||
|
|
||||||
if (side === "bottom") y = t.bottom + offset;
|
if (side === "bottom") y = t.bottom + GAP;
|
||||||
else if (side === "top") y = t.top - p.height - offset;
|
else if (side === "top") y = t.top - p.height - GAP;
|
||||||
else if (side === "right") x = t.right + offset;
|
else if (side === "right") x = t.right + GAP;
|
||||||
else if (side === "left") x = t.left - p.width - offset;
|
else if (side === "left") x = t.left - p.width - GAP;
|
||||||
|
|
||||||
if (side === "top" || side === "bottom") {
|
if (side === "top" || side === "bottom") {
|
||||||
if (align === "start") x = t.left;
|
if (align === "start") x = t.left;
|
||||||
@@ -215,116 +220,99 @@ const id = `dd-${Math.random().toString(36).slice(2)}`;
|
|||||||
else y = t.top + (t.height - p.height) / 2;
|
else y = t.top + (t.height - p.height) / 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
const pad = shiftPadding;
|
// Clamp into viewport
|
||||||
x = Math.max(pad, Math.min(x, vw - p.width - pad));
|
x = Math.max(SAFE, Math.min(x, vw - p.width - SAFE));
|
||||||
y = Math.max(pad, Math.min(y, vh - p.height - pad));
|
y = Math.max(SAFE, Math.min(y, vh - p.height - SAFE));
|
||||||
return { x, y }; // no Math.round
|
|
||||||
}
|
|
||||||
|
|
||||||
function positionPanel() {
|
// Return overflow score (lower is better)
|
||||||
if (!open) return;
|
const over =
|
||||||
if (matchTriggerWidth) {
|
Math.max(0, SAFE - x) +
|
||||||
const w = Math.max(192, trigger.getBoundingClientRect().width);
|
Math.max(0, SAFE - y) +
|
||||||
panel.style.minWidth = `${w}px`;
|
Math.max(0, x + p.width - (vw - SAFE)) +
|
||||||
}
|
Math.max(0, y + p.height - (vh - SAFE));
|
||||||
const best = smartPosition();
|
|
||||||
panel.style.left = `${best.x}px`;
|
|
||||||
panel.style.top = `${best.y}px`;
|
|
||||||
|
|
||||||
const side = sideOf(best.cand),
|
return { x: Math.round(x), y: Math.round(y), over };
|
||||||
align = alignOf(best.cand);
|
|
||||||
setOriginFor(side, align);
|
|
||||||
panel.dataset.side = side;
|
|
||||||
|
|
||||||
if (showArrow && arrowEl) {
|
|
||||||
Object.assign(arrowEl.style, {
|
|
||||||
left: "",
|
|
||||||
top: "",
|
|
||||||
right: "",
|
|
||||||
bottom: "",
|
|
||||||
});
|
|
||||||
const t = trigger.getBoundingClientRect();
|
|
||||||
const p = panel.getBoundingClientRect();
|
|
||||||
const aw = arrowEl.getBoundingClientRect().width;
|
|
||||||
const ah = arrowEl.getBoundingClientRect().height;
|
|
||||||
const AR = 7;
|
|
||||||
|
|
||||||
if (side === "bottom") {
|
|
||||||
arrowEl.style.top = `${-AR}px`;
|
|
||||||
const cx = t.left + t.width / 2;
|
|
||||||
arrowEl.style.left = `${cx - p.left - aw / 2}px`;
|
|
||||||
} else if (side === "top") {
|
|
||||||
arrowEl.style.bottom = `${-AR}px`;
|
|
||||||
const cx = t.left + t.width / 2;
|
|
||||||
arrowEl.style.left = `${cx - p.left - aw / 2}px`;
|
|
||||||
} else if (side === "right") {
|
|
||||||
arrowEl.style.left = `${-AR}px`;
|
|
||||||
const cy = t.top + t.height / 2;
|
|
||||||
arrowEl.style.top = `${cy - p.top - ah / 2}px`;
|
|
||||||
} else if (side === "left") {
|
|
||||||
arrowEl.style.right = `${-AR}px`;
|
|
||||||
const cy = t.top + t.height / 2;
|
|
||||||
arrowEl.style.top = `${cy - p.top - ah / 2}px`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function smartPosition() {
|
function smartPosition() {
|
||||||
const s = sideOf(placement),
|
const s = sideOf(placement);
|
||||||
a = alignOf(placement);
|
const a = alignOf(placement);
|
||||||
const flips = {
|
|
||||||
|
const flipSide = {
|
||||||
top: "bottom",
|
top: "bottom",
|
||||||
bottom: "top",
|
bottom: "top",
|
||||||
left: "right",
|
left: "right",
|
||||||
right: "left",
|
right: "left",
|
||||||
};
|
}[s];
|
||||||
const candidates = [placement, `${flips[s]}${a ? `-${a}` : ""}`];
|
|
||||||
if (s === "top" || s === "bottom")
|
|
||||||
candidates.push(
|
|
||||||
`left-${a || "start"}`,
|
|
||||||
`right-${a || "start"}`,
|
|
||||||
);
|
|
||||||
else
|
|
||||||
candidates.push(
|
|
||||||
`top-${a || "start"}`,
|
|
||||||
`bottom-${a || "start"}`,
|
|
||||||
);
|
|
||||||
|
|
||||||
const vw = document.documentElement.clientWidth;
|
// Try: requested → side flipped → align flipped → both flipped → orthogonal sides
|
||||||
const vh = document.documentElement.clientHeight;
|
const aligns = a
|
||||||
|
? [a, a === "start" ? "end" : "start", "center"]
|
||||||
|
: ["center", "start", "end"];
|
||||||
|
const candidates = [];
|
||||||
|
|
||||||
|
aligns.forEach((al) =>
|
||||||
|
candidates.push(`${s}${al === "center" ? "" : "-" + al}`),
|
||||||
|
);
|
||||||
|
aligns.forEach((al) =>
|
||||||
|
candidates.push(
|
||||||
|
`${flipSide}${al === "center" ? "" : "-" + al}`,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (s === "top" || s === "bottom") {
|
||||||
|
aligns.forEach((al) =>
|
||||||
|
candidates.push(`left-${al === "center" ? "start" : al}`),
|
||||||
|
);
|
||||||
|
aligns.forEach((al) =>
|
||||||
|
candidates.push(`right-${al === "center" ? "start" : al}`),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
aligns.forEach((al) =>
|
||||||
|
candidates.push(`top-${al === "center" ? "start" : al}`),
|
||||||
|
);
|
||||||
|
aligns.forEach((al) =>
|
||||||
|
candidates.push(`bottom-${al === "center" ? "start" : al}`),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
let best = null;
|
let best = null;
|
||||||
for (const cand of candidates) {
|
for (const cand of candidates) {
|
||||||
const pos = placeOnce(cand);
|
const pos = placeOnce(cand);
|
||||||
const p = panel.getBoundingClientRect();
|
if (!best || pos.over < best.over) best = { cand, ...pos };
|
||||||
const w = p.width,
|
if (pos.over === 0) break; // perfect fit
|
||||||
h = p.height;
|
|
||||||
const over =
|
|
||||||
Math.max(0, -pos.x) +
|
|
||||||
Math.max(0, -pos.y) +
|
|
||||||
Math.max(0, pos.x + w - vw) +
|
|
||||||
Math.max(0, pos.y + h - vh);
|
|
||||||
if (!best || over < best.score)
|
|
||||||
best = { cand, ...pos, score: over };
|
|
||||||
}
|
}
|
||||||
return best;
|
return best;
|
||||||
}
|
}
|
||||||
|
|
||||||
function positionPanel() {
|
function positionPanel() {
|
||||||
if (!open) return;
|
if (!open) return;
|
||||||
|
|
||||||
|
// Constrain size so the panel never forces overflow
|
||||||
|
const vw = document.documentElement.clientWidth;
|
||||||
|
const vh = document.documentElement.clientHeight;
|
||||||
|
const PAD = Math.max(shiftPadding, 8);
|
||||||
|
|
||||||
|
// Optional: match trigger width
|
||||||
if (matchTriggerWidth) {
|
if (matchTriggerWidth) {
|
||||||
const w = Math.max(192, trigger.getBoundingClientRect().width);
|
const w = Math.max(192, trigger.getBoundingClientRect().width);
|
||||||
panel.style.minWidth = `${Math.round(w)}px`;
|
panel.style.minWidth = `${Math.round(w)}px`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
panel.style.maxWidth = `${vw - PAD * 2}px`;
|
||||||
|
panel.style.maxHeight = `${vh - PAD * 2}px`;
|
||||||
|
panel.style.overflow = "auto"; // scroll when needed
|
||||||
|
|
||||||
const best = smartPosition();
|
const best = smartPosition();
|
||||||
panel.style.left = best.x + "px";
|
panel.style.left = best.x + "px";
|
||||||
panel.style.top = best.y + "px";
|
panel.style.top = best.y + "px";
|
||||||
|
|
||||||
const side = sideOf(best.cand),
|
const side = sideOf(best.cand);
|
||||||
align = alignOf(best.cand);
|
const align = alignOf(best.cand);
|
||||||
setOriginFor(side, align);
|
setOriginFor(side, align);
|
||||||
panel.dataset.side = side;
|
panel.dataset.side = side;
|
||||||
|
|
||||||
|
// Arrow
|
||||||
if (showArrow && arrowEl) {
|
if (showArrow && arrowEl) {
|
||||||
Object.assign(arrowEl.style, {
|
Object.assign(arrowEl.style, {
|
||||||
left: "",
|
left: "",
|
||||||
@@ -336,26 +324,60 @@ const id = `dd-${Math.random().toString(36).slice(2)}`;
|
|||||||
const p = panel.getBoundingClientRect();
|
const p = panel.getBoundingClientRect();
|
||||||
const aw = arrowEl.getBoundingClientRect().width;
|
const aw = arrowEl.getBoundingClientRect().width;
|
||||||
const ah = arrowEl.getBoundingClientRect().height;
|
const ah = arrowEl.getBoundingClientRect().height;
|
||||||
const AR = 7;
|
const AR = 8;
|
||||||
|
|
||||||
if (side === "bottom") {
|
if (side === "bottom") {
|
||||||
arrowEl.style.top = -AR + "px";
|
arrowEl.style.top = -AR + "px";
|
||||||
const cx = t.left + t.width / 2;
|
const cx = t.left + t.width / 2;
|
||||||
arrowEl.style.left =
|
arrowEl.style.left =
|
||||||
Math.round(cx - p.left - aw / 2) + "px";
|
Math.round(
|
||||||
|
Math.max(
|
||||||
|
PAD,
|
||||||
|
Math.min(
|
||||||
|
cx - p.left - aw / 2,
|
||||||
|
p.width - PAD - aw,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
) + "px";
|
||||||
} else if (side === "top") {
|
} else if (side === "top") {
|
||||||
arrowEl.style.bottom = -AR + "px";
|
arrowEl.style.bottom = -AR + "px";
|
||||||
const cx = t.left + t.width / 2;
|
const cx = t.left + t.width / 2;
|
||||||
arrowEl.style.left =
|
arrowEl.style.left =
|
||||||
Math.round(cx - p.left - aw / 2) + "px";
|
Math.round(
|
||||||
|
Math.max(
|
||||||
|
PAD,
|
||||||
|
Math.min(
|
||||||
|
cx - p.left - aw / 2,
|
||||||
|
p.width - PAD - aw,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
) + "px";
|
||||||
} else if (side === "right") {
|
} else if (side === "right") {
|
||||||
arrowEl.style.left = -AR + "px";
|
arrowEl.style.left = -AR + "px";
|
||||||
const cy = t.top + t.height / 2;
|
const cy = t.top + t.height / 2;
|
||||||
arrowEl.style.top = Math.round(cy - p.top - ah / 2) + "px";
|
arrowEl.style.top =
|
||||||
|
Math.round(
|
||||||
|
Math.max(
|
||||||
|
PAD,
|
||||||
|
Math.min(
|
||||||
|
cy - p.top - ah / 2,
|
||||||
|
p.height - PAD - ah,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
) + "px";
|
||||||
} else if (side === "left") {
|
} else if (side === "left") {
|
||||||
arrowEl.style.right = -AR + "px";
|
arrowEl.style.right = -AR + "px";
|
||||||
const cy = t.top + t.height / 2;
|
const cy = t.top + t.height / 2;
|
||||||
arrowEl.style.top = Math.round(cy - p.top - ah / 2) + "px";
|
arrowEl.style.top =
|
||||||
|
Math.round(
|
||||||
|
Math.max(
|
||||||
|
PAD,
|
||||||
|
Math.min(
|
||||||
|
cy - p.top - ah / 2,
|
||||||
|
p.height - PAD - ah,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
) + "px";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ const descId = p.description ? `${fieldId}-desc` : undefined;
|
|||||||
const errId = `${fieldId}-err`;
|
const errId = `${fieldId}-err`;
|
||||||
|
|
||||||
const inputBase = cva(
|
const inputBase = cva(
|
||||||
"wr:py-2.5 wr:sm:py-3 wr:px-4 wr:block wr:w-full wr:border-gray-200 wr:rounded-lg wr:sm:text-sm wr:focus:border-blue-500 wr:focus:ring-blue-500 wr:disabled:opacity-50 wr:disabled:pointer-events-none wr:dark:bg-neutral-900 wr:dark:border-neutral-700 wr:dark:text-neutral-400 wr:dark:placeholder-neutral-500 wr:dark:focus:ring-neutral-600",
|
"wr:py-2.5 wr:sm:py-3 wr:px-4 wr:block wr:w-full wr:border-border wr:rounded-lg wr:sm:text-sm wr:focus:border-border wr:focus:ring-blue-500 wr:disabled:opacity-50 wr:disabled:pointer-events-none wr:dark:bg-input wr:dark:border-border wr:dark:text-neutral-400 wr:dark:placeholder-neutral-500 wr:dark:focus:ring-neutral-600",
|
||||||
{
|
{
|
||||||
variants: {
|
variants: {
|
||||||
size: {
|
size: {
|
||||||
@@ -68,7 +68,7 @@ const inputBase = cva(
|
|||||||
);
|
);
|
||||||
|
|
||||||
const selectBase = cva(
|
const selectBase = cva(
|
||||||
"wr:py-3 wr:px-4 wr:pe-9 wr:block wr:w-full wr:border-gray-200 wr:rounded-lg wr:text-sm wr:focus:border-blue-500 wr:focus:ring-blue-500 wr:disabled:opacity-50 wr:disabled:pointer-events-none wr:dark:bg-neutral-900 wr:dark:border-neutral-700 wr:dark:text-neutral-400 wr:dark:placeholder-neutral-500 wr:dark:focus:ring-neutral-600",
|
"wr:py-3 wr:px-4 wr:pe-9 wr:block wr:w-full wr:border-border wr:rounded-lg wr:text-sm wr:focus:border-border wr:focus:ring-blue-500 wr:disabled:opacity-50 wr:disabled:pointer-events-none wr:dark:bg-input wr:dark:border-border wr:dark:text-neutral-400 wr:dark:placeholder-neutral-500 wr:dark:focus:ring-neutral-600",
|
||||||
{
|
{
|
||||||
variants: {
|
variants: {
|
||||||
size: {
|
size: {
|
||||||
@@ -90,7 +90,7 @@ const helpCls = "wr:mt-2 wr:text-sm wr:text-gray-500 wr:dark:text-neutral-500";
|
|||||||
const errCls = "wr:text-sm wr:text-red-600 wr:mt-2";
|
const errCls = "wr:text-sm wr:text-red-600 wr:mt-2";
|
||||||
const groupCls = "wr:relative wr:flex wr:items-stretch";
|
const groupCls = "wr:relative wr:flex wr:items-stretch";
|
||||||
const addonBase =
|
const addonBase =
|
||||||
"wr:px-4 wr:inline-flex wr:items-center wr:min-w-fit wr:rounded-md wr:border wr:border-gray-200 wr:bg-gray-50 wr:text-sm wr:text-gray-500 wr:dark:bg-neutral-700 wr:dark:border-neutral-700 wr:dark:text-neutral-400";
|
"wr:px-4 wr:inline-flex wr:items-center wr:min-w-fit wr:rounded-md wr:border wr:border-border wr:bg-gray-200 wr:text-sm wr:text-gray-500 wr:dark:bg-card wr:dark:border-border wr:dark:text-neutral-400";
|
||||||
const controlWrap = "wr:relative";
|
const controlWrap = "wr:relative";
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -220,7 +220,7 @@ const controlWrap = "wr:relative";
|
|||||||
name={p.name}
|
name={p.name}
|
||||||
type={(p.kind as any) ?? "text"}
|
type={(p.kind as any) ?? "text"}
|
||||||
class={cn(
|
class={cn(
|
||||||
"wr:block wr:w-full wr:border wr:border-gray-200 wr:shadow-sm wr:rounded-lg wr:text-sm wr:focus:z-10 wr:focus:border-blue-500 wr:focus:ring-blue-500 wr:disabled:opacity-50 wr:disabled:pointer-events-none wr:dark:bg-neutral-900 wr:dark:border-neutral-700 wr:dark:text-neutral-400 wr:file:bg-gray-50 wr:file:border-0 wr:file:me-4 wr:file:py-3 wr:file:px-4 wr:dark:file:bg-neutral-700 wr:dark:file:text-neutral-400",
|
"wr:block wr:w-full wr:border wr:border-border wr:shadow-sm wr:rounded-lg wr:text-sm wr:focus:z-10 wr:focus:border-border wr:focus:ring-blue-500 wr:disabled:opacity-50 wr:disabled:pointer-events-none wr:dark:bg-input wr:dark:border-border wr:dark:text-neutral-400 wr:file:bg-gray-50 wr:file:border-0 wr:file:me-4 wr:file:py-3 wr:file:px-4 wr:dark:file:bg-input wr:dark:file:text-neutral-400",
|
||||||
p.prefixText && "wr:rounded-l-none",
|
p.prefixText && "wr:rounded-l-none",
|
||||||
p.suffixText && "wr:rounded-r-none",
|
p.suffixText && "wr:rounded-r-none",
|
||||||
p.error &&
|
p.error &&
|
||||||
@@ -281,7 +281,7 @@ const controlWrap = "wr:relative";
|
|||||||
.join(" ") || undefined
|
.join(" ") || undefined
|
||||||
}
|
}
|
||||||
class={cn(
|
class={cn(
|
||||||
"wr:py-2.5 wr:sm:py-3 wr:px-4 wr:block wr:w-full wr:border-gray-200 wr:rounded-lg wr:sm:text-sm wr:focus:border-blue-500 wr:focus:ring-blue-500 wr:disabled:opacity-50 wr:disabled:pointer-events-none wr:dark:bg-neutral-900 wr:dark:border-neutral-700 wr:dark:text-neutral-400 wr:dark:placeholder-neutral-500 wr:dark:focus:ring-neutral-600",
|
"wr:py-2.5 wr:sm:py-3 wr:px-4 wr:block wr:w-full wr:border-border wr:rounded-lg wr:sm:text-sm wr:focus:border-border wr:focus:ring-blue-500 wr:disabled:opacity-50 wr:disabled:pointer-events-none wr:dark:bg-input wr:dark:border-border wr:dark:text-neutral-400 wr:dark:placeholder-neutral-500 wr:dark:focus:ring-neutral-600",
|
||||||
p.size === "sm"
|
p.size === "sm"
|
||||||
? "wr:text-sm wr:p-3"
|
? "wr:text-sm wr:p-3"
|
||||||
: p.size === "lg"
|
: p.size === "lg"
|
||||||
@@ -352,7 +352,7 @@ const controlWrap = "wr:relative";
|
|||||||
id={fieldId}
|
id={fieldId}
|
||||||
name={p.name}
|
name={p.name}
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
class="wr:shrink-0 wr:mt-0.5 wr:border-gray-200 wr:rounded-sm wr:text-blue-600 wr:focus:ring-blue-500 wr:checked:border-blue-500 wr:disabled:opacity-50 wr:disabled:pointer-events-none wr:dark:bg-neutral-800 wr:dark:border-neutral-700 wr:dark:checked:bg-blue-500 wr:dark:checked:border-blue-500 wr:dark:focus:ring-offset-gray-800"
|
class="wr:shrink-0 wr:mt-0.5 wr:border-border wr:rounded-sm wr:text-blue-600 wr:focus:ring-blue-500 wr:checked:border-border wr:disabled:opacity-50 wr:disabled:pointer-events-none wr:dark:bg-input wr:dark:border-border wr:dark:checked:bg-blue-500 wr:dark:checked:border-border wr:dark:focus:ring-offset-gray-800"
|
||||||
checked={!!p.value}
|
checked={!!p.value}
|
||||||
disabled={p.disabled}
|
disabled={p.disabled}
|
||||||
data-control
|
data-control
|
||||||
@@ -395,7 +395,7 @@ const controlWrap = "wr:relative";
|
|||||||
name={p.name}
|
name={p.name}
|
||||||
value={opt.value}
|
value={opt.value}
|
||||||
checked={String(p.value) === opt.value}
|
checked={String(p.value) === opt.value}
|
||||||
class="wr:shrink-0 wr:mt-0.5 wr:border-gray-200 wr:rounded-full wr:text-blue-600 wr:focus:ring-blue-500 wr:checked:border-blue-500 wr:disabled:opacity-50 wr:disabled:pointer-events-none wr:dark:bg-neutral-800 wr:dark:border-neutral-700 wr:dark:checked:bg-blue-500 wr:dark:checked:border-blue-500 wr:dark:focus:ring-offset-gray-800"
|
class="wr:shrink-0 wr:mt-0.5 wr:border-border wr:rounded-full wr:text-blue-600 wr:focus:ring-blue-500 wr:checked:border-border wr:disabled:opacity-50 wr:disabled:pointer-events-none wr:dark:bg-input wr:dark:border-border wr:dark:checked:bg-blue-500 wr:dark:checked:border-border wr:dark:focus:ring-offset-gray-800"
|
||||||
disabled={opt.disabled || p.disabled}
|
disabled={opt.disabled || p.disabled}
|
||||||
data-control
|
data-control
|
||||||
/>
|
/>
|
||||||
@@ -422,8 +422,8 @@ const controlWrap = "wr:relative";
|
|||||||
disabled={p.disabled}
|
disabled={p.disabled}
|
||||||
data-control
|
data-control
|
||||||
/>
|
/>
|
||||||
<span class="wr:absolute wr:inset-0 wr:bg-gray-200 wr:rounded-full wr:transition-colors wr:duration-200 wr:ease-in-out wr:peer-checked:bg-blue-600 wr:dark:bg-neutral-700 wr:dark:peer-checked:bg-blue-500 wr:peer-disabled:opacity-50 wr:peer-disabled:pointer-events-none" />
|
<span class="wr:absolute wr:inset-0 wr:bg-gray-200 wr:rounded-full wr:transition-colors wr:duration-200 wr:ease-in-out wr:peer-checked:bg-blue-600 wr:dark:bg-input wr:dark:peer-checked:bg-blue-500 wr:peer-disabled:opacity-50 wr:peer-disabled:pointer-events-none" />
|
||||||
<span class="wr:absolute wr:top-1/2 wr:start-0.5 wr:-translate-y-1/2 wr:size-5 wr:bg-white wr:rounded-full wr:shadow-xs wr:transition-transform wr:duration-200 wr:ease-in-out wr:peer-checked:translate-x-full wr:dark:bg-neutral-400 wr:dark:peer-checked:bg-white" />
|
<span class="wr:absolute wr:top-1/2 wr:start-0.5 wr:-translate-y-1/2 wr:size-5 wr:bg-white wr:rounded-full wr:shadow-xs wr:transition-transform wr:duration-200 wr:ease-in-out wr:peer-checked:translate-x-full wr:dark:bg-white wr:dark:peer-checked:bg-white" />
|
||||||
</label>
|
</label>
|
||||||
{p.label && (
|
{p.label && (
|
||||||
<label
|
<label
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ const sizeCls =
|
|||||||
const controlCls =
|
const controlCls =
|
||||||
"wr:py-2.5 wr:sm:py-3 wr:px-4 wr:block wr:w-full wr:border-gray-200 wr:rounded-lg wr:sm:text-sm " +
|
"wr:py-2.5 wr:sm:py-3 wr:px-4 wr:block wr:w-full wr:border-gray-200 wr:rounded-lg wr:sm:text-sm " +
|
||||||
"wr:focus:border-blue-500 wr:focus:ring-blue-500 wr:disabled:opacity-50 wr:disabled:pointer-events-none " +
|
"wr:focus:border-blue-500 wr:focus:ring-blue-500 wr:disabled:opacity-50 wr:disabled:pointer-events-none " +
|
||||||
"wr:dark:bg-neutral-900 wr:dark:border-neutral-700 wr:dark:text-neutral-400 wr:dark:placeholder-neutral-500 wr:dark:focus:ring-neutral-600";
|
"wr:dark:bg-input wr:dark:border-border wr:dark:text-neutral-400 wr:dark:placeholder-neutral-500 wr:dark:focus:ring-neutral-600";
|
||||||
|
|
||||||
const chipBase =
|
const chipBase =
|
||||||
"wr:inline-flex wr:items-center wr:gap-1 wr:rounded-full wr:px-2 wr:py-0.5 wr:text-xs wr:bg-muted wr:text-foreground";
|
"wr:inline-flex wr:items-center wr:gap-1 wr:rounded-full wr:px-2 wr:py-0.5 wr:text-xs wr:bg-muted wr:text-foreground";
|
||||||
@@ -133,7 +133,7 @@ const displayMode = p.display ?? "text";
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
class="wr:absolute wr:border-border wr:bg-popover wr:text-popover-foreground wr:shadow-lg wr:hidden wr:mt-2 wr:z-50 wr:w-full wr:max-h-72 wr:p-1 wr:space-y-0.5 wr:bg-white wr:border wr:border-gray-200 wr:rounded-lg wr:overflow-hidden wr:overflow-y-auto wr:[&::-webkit-scrollbar]:w-2 wr:[&::-webkit-scrollbar-thumb]:rounded-full wr:[&::-webkit-scrollbar-track]:bg-gray-100 wr:[&::-webkit-scrollbar-thumb]:bg-gray-300 wr:dark:[&::-webkit-scrollbar-track]:bg-neutral-700 wr:dark:[&::-webkit-scrollbar-thumb]:bg-neutral-500 wr:dark:bg-neutral-900 wr:dark:border-neutral-700"
|
class="wr:absolute wr:text-popover-foreground wr:shadow-lg wr:hidden wr:mt-2 wr:z-50 wr:w-full wr:max-h-96 wr:p-1 wr:space-y-0.5 wr:bg-white wr:border wr:border-gray-200 wr:rounded-lg wr:overflow-hidden wr:overflow-y-auto wr:[&::-webkit-scrollbar]:w-2 wr:[&::-webkit-scrollbar-thumb]:rounded-full wr:[&::-webkit-scrollbar-track]:bg-gray-100 wr:[&::-webkit-scrollbar-thumb]:bg-gray-300 wr:dark:[&::-webkit-scrollbar-track]:bg-input wr:dark:[&::-webkit-scrollbar-thumb]:bg-input wr:dark:bg-input wr:dark:border-border"
|
||||||
id={`${containerId}-panel`}
|
id={`${containerId}-panel`}
|
||||||
>
|
>
|
||||||
{
|
{
|
||||||
@@ -147,7 +147,7 @@ const displayMode = p.display ?? "text";
|
|||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
class={cn(
|
class={cn(
|
||||||
"wr:py-2.5 wr:sm:py-3 wr:px-4 wr:block wr:w-full wr:border-gray-200 wr:rounded-lg wr:sm:text-sm wr:focus:border-blue-500 wr:focus:ring-blue-500 wr:disabled:opacity-50 wr:disabled:pointer-events-none wr:dark:bg-neutral-900 wr:dark:border-neutral-700 wr:dark:text-neutral-400 wr:dark:placeholder-neutral-500 wr:dark:focus:ring-neutral-600",
|
"wr:py-2.5 wr:sm:py-3 wr:px-4 wr:block wr:w-full wr:border-gray-200 wr:rounded-lg wr:sm:text-sm wr:focus:border-blue-500 wr:focus:ring-blue-500 wr:disabled:opacity-50 wr:disabled:pointer-events-none wr:dark:bg-input wr:dark:border-neutral-400 wr:dark:text-neutral-400 wr:dark:placeholder-neutral-400 wr:dark:focus:ring-neutral-400",
|
||||||
"wr:h-9 wr:pl-8 wr:pr-2 wr:text-sm",
|
"wr:h-9 wr:pl-8 wr:pr-2 wr:text-sm",
|
||||||
)}
|
)}
|
||||||
placeholder="Search…"
|
placeholder="Search…"
|
||||||
@@ -226,7 +226,7 @@ const displayMode = p.display ?? "text";
|
|||||||
p.description && (
|
p.description && (
|
||||||
<p
|
<p
|
||||||
id={descId}
|
id={descId}
|
||||||
class="wr:mt-2 wr:text-sm wr:text-gray-500 wr:dark:text-neutral-500"
|
class="wr:mt-2 wr:text-sm wr:text-gray-500 wr:dark:text-input"
|
||||||
>
|
>
|
||||||
{p.description}
|
{p.description}
|
||||||
</p>
|
</p>
|
||||||
|
|||||||
+115
-155
@@ -1,198 +1,158 @@
|
|||||||
---
|
---
|
||||||
import type { HTMLAttributes } from "astro/types";
|
import type { HTMLAttributes } from "astro/types";
|
||||||
|
import Dropdown from "./Dropdown.astro";
|
||||||
import { Icon } from "astro-icon/components";
|
import { Icon } from "astro-icon/components";
|
||||||
|
|
||||||
interface Props extends HTMLAttributes<"div"> {
|
interface Props extends HTMLAttributes<"div"> {
|
||||||
storageKey?: string;
|
storageKey?: string;
|
||||||
rootSelector?: string; // where to toggle theme, e.g. "html"
|
rootSelector?: string;
|
||||||
compact?: boolean; // smaller trigger button
|
compact?: boolean;
|
||||||
darkBgClass?: string[]; // non–pure-black dark background class
|
showLabel?: boolean;
|
||||||
lightBgClass?: string[]; // light background class
|
darkBgClass?: string[];
|
||||||
rootExtraClass?: string; // always-on root class (optional)
|
lightBgClass?: string[];
|
||||||
showLabel?: boolean; // show text next to icon in trigger
|
rootExtraClass?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const {
|
const {
|
||||||
storageKey = "wr-theme",
|
storageKey = "wr-theme",
|
||||||
rootSelector = "html",
|
rootSelector = "html",
|
||||||
compact = false,
|
compact = false,
|
||||||
darkBgClass = ["wr-theme-dark-soft"],
|
|
||||||
lightBgClass = ["wr-theme-light"],
|
|
||||||
rootExtraClass = "",
|
|
||||||
showLabel = false,
|
showLabel = false,
|
||||||
|
darkBgClass = [],
|
||||||
|
lightBgClass = [],
|
||||||
|
rootExtraClass = "",
|
||||||
class: className,
|
class: className,
|
||||||
...rest
|
...rest
|
||||||
}: Props = Astro.props;
|
}: Props = Astro.props;
|
||||||
|
|
||||||
const iconBtn =
|
const containerId = `ts-${Math.random().toString(36).slice(2)}`;
|
||||||
"wr:py-3 wr:px-4 wr:inline-flex wr:items-center wr:gap-x-2 wr:text-sm wr:font-medium wr:rounded-lg wr:border wr:border-gray-200 wr:bg-white wr:text-gray-800 wr:shadow-2xs wr:hover:bg-gray-50 wr:focus:outline-hidden wr:focus:bg-gray-50 wr:disabled:opacity-50 wr:disabled:pointer-events-none wr:dark:bg-neutral-800 wr:dark:border-neutral-700 wr:dark:text-white wr:dark:hover:bg-neutral-700 wr:dark:focus:bg-neutral-700";
|
const icon = "wr:size-4";
|
||||||
|
|
||||||
const menuBtn =
|
|
||||||
"wr:py-3 wr:px-4 wr:inline-flex wr:items-center wr:gap-x-2 wr:text-sm wr:font-medium wr:rounded-lg wr:border wr:border-gray-200 wr:bg-white wr:text-gray-800 wr:shadow-2xs wr:hover:bg-gray-50 wr:focus:outline-hidden wr:focus:bg-gray-50 wr:disabled:opacity-50 wr:disabled:pointer-events-none wr:dark:bg-neutral-800 wr:dark:border-neutral-700 wr:dark:text-white wr:dark:hover:bg-neutral-700 wr:dark:focus:bg-neutral-700";
|
|
||||||
|
|
||||||
const item =
|
const item =
|
||||||
"wr:flex wr:items-center wr:gap-3 wr:w-full wr:px-3 wr:py-2.5 wr:rounded-lg wr:text-sm wr:hover:bg-muted/70 wr:transition wr:duration-150";
|
"wr:flex wr:items-center wr:gap-3 wr:w-full wr:px-3 wr:py-2.5 wr:rounded-lg wr:text-sm wr:hover:bg-muted/70 wr:transition wr:duration-150";
|
||||||
|
|
||||||
const icon = "wr:size-4";
|
|
||||||
const checkBase = "wr:size-4 wr:opacity-0 wr:scale-90 wr:transition";
|
const checkBase = "wr:size-4 wr:opacity-0 wr:scale-90 wr:transition";
|
||||||
const containerId = `ts-${Math.random().toString(36).slice(2)}`;
|
|
||||||
---
|
---
|
||||||
|
|
||||||
<div id={containerId} class={["wr:relative", className].join(" ")} {...rest}>
|
<div id={containerId} class={["wr:inline-flex", className].join(" ")} data-compact={compact ? "1" : ""} {...rest}>
|
||||||
<!-- Trigger: icon-only by default; set showLabel=true to include text -->
|
<Dropdown openOn="click" placement="bottom-end" offset={10} shiftPadding={10} showArrow={true} closeOnSelect={true}>
|
||||||
<button
|
<span slot="trigger" class="wr:inline-flex wr:items-center wr:gap-2">
|
||||||
type="button"
|
<span data-current-icon="light" class="wr:inline">
|
||||||
class={showLabel ? menuBtn : [iconBtn, compact && "wr:h-8 wr:w-8"].filter(Boolean).join(" ")}
|
<Icon name="mdi:weather-sunny" class={icon} />
|
||||||
data-menu-trigger
|
</span>
|
||||||
aria-haspopup="menu"
|
<span data-current-icon="dark" class="wr:hidden">
|
||||||
aria-expanded="false"
|
<Icon name="mdi:weather-night" class={icon} />
|
||||||
title="Theme"
|
</span>
|
||||||
>
|
<span data-current-icon="system" class="wr:hidden">
|
||||||
<span class="wr:inline-flex wr:items-center wr:gap-2">
|
<Icon name="mdi:laptop" class={icon} />
|
||||||
<span data-current-icon="light" class="wr:inline"><Icon name="mdi:weather-sunny" class={icon} /></span>
|
</span>
|
||||||
<span data-current-icon="dark" class="wr:hidden"><Icon name="mdi:weather-night" class={icon} /></span>
|
|
||||||
<span data-current-icon="system" class="wr:hidden"><Icon name="mdi:laptop" class={icon} /></span>
|
|
||||||
{showLabel && <span data-current-label class="wr:text-sm wr:font-medium">System</span>}
|
{showLabel && <span data-current-label class="wr:text-sm wr:font-medium">System</span>}
|
||||||
|
<svg data-dd-chev class="wr:size-4 wr:opacity-70 wr:transition-transform wr:duration-150" viewBox="0 0 24 24" fill="none">
|
||||||
|
<path d="M7 10l5 5 5-5" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
|
||||||
|
</svg>
|
||||||
</span>
|
</span>
|
||||||
{showLabel && <Icon name="mdi:chevron-down" class="wr:size-4 wr:opacity-70" />}
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<!-- Dropdown -->
|
<!-- Note: each item carries data-owner={containerId} so we can find it after portal -->
|
||||||
<div
|
<button type="button" role="menuitemradio" aria-checked="false" class={item} data-dd-item data-set-theme="light" data-owner={containerId}>
|
||||||
class="wr:absolute wr:right-0 wr:z-50 wr:w-56 wr:border-border wr:bg-popover/90 wr:backdrop-blur-md wr:text-popover-foreground wr:p-1.5 wr:origin-top-right wr:scale-95 wr:duration-150 wr:ease-out wr:transition-[opacity,margin] wr:border wr:border-gray-100 wr:duration wr:hs-dropdown-open:opacity-100 wr:opacity-0 wr:hidden wr:min-w-60 wr:bg-white wr:shadow-md wr:rounded-lg wr:mt-2 wr:dark:bg-neutral-800 wr:dark:border wr:dark:border-neutral-700 wr:dark:divide-neutral-700 wr:after:h-4 wr:after:absolute wr:after:-bottom-4 wr:after:start-0 wr:after:w-full wr:before:h-4 wr:before:absolute wr:before:-top-4 wr:before:start-0 wr:before:w-full"
|
|
||||||
role="menu"
|
|
||||||
aria-label="Theme"
|
|
||||||
data-menu-panel
|
|
||||||
>
|
|
||||||
<button type="button" role="menuitemradio" aria-checked="false" class={item} data-set-theme="light">
|
|
||||||
<Icon name="mdi:weather-sunny" class={icon} />
|
<Icon name="mdi:weather-sunny" class={icon} />
|
||||||
<div class="wr:flex-1 wr:font-medium">Light</div>
|
<div class="wr:flex-1 wr:font-medium">Light</div>
|
||||||
<Icon name="mdi:check" class={checkBase} data-check />
|
<Icon name="mdi:check" class={checkBase} data-check />
|
||||||
</button>
|
</button>
|
||||||
<button type="button" role="menuitemradio" aria-checked="false" class={item} data-set-theme="dark">
|
|
||||||
|
<button type="button" role="menuitemradio" aria-checked="false" class={item} data-dd-item data-set-theme="dark" data-owner={containerId}>
|
||||||
<Icon name="mdi:weather-night" class={icon} />
|
<Icon name="mdi:weather-night" class={icon} />
|
||||||
<div class="wr:flex-1 wr:font-medium">Dark</div>
|
<div class="wr:flex-1 wr:font-medium">Dark</div>
|
||||||
<Icon name="mdi:check" class={checkBase} data-check />
|
<Icon name="mdi:check" class={checkBase} data-check />
|
||||||
</button>
|
</button>
|
||||||
<button type="button" role="menuitemradio" aria-checked="true" class={item} data-set-theme="system">
|
|
||||||
|
<button type="button" role="menuitemradio" aria-checked="true" class={item} data-dd-item data-set-theme="system" data-owner={containerId}>
|
||||||
<Icon name="mdi:laptop" class={icon} />
|
<Icon name="mdi:laptop" class={icon} />
|
||||||
<div class="wr:flex-1 wr:font-medium">System</div>
|
<div class="wr:flex-1 wr:font-medium">System</div>
|
||||||
<Icon name="mdi:check" class={checkBase} data-check />
|
<Icon name="mdi:check" class={checkBase} data-check />
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</Dropdown>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script is:inline define:vars={{ containerId, storageKey, rootSelector, darkBgClass, lightBgClass, rootExtraClass }}>
|
|
||||||
(() => {
|
|
||||||
const host = document.getElementById(containerId);
|
|
||||||
if (!host) return;
|
|
||||||
|
|
||||||
const root = rootSelector === "html"
|
|
||||||
? document.documentElement
|
|
||||||
: document.querySelector(rootSelector) || document.documentElement;
|
|
||||||
|
|
||||||
const mql = window.matchMedia("(prefers-color-scheme: dark)");
|
|
||||||
let lastThemeClasses = [];
|
|
||||||
|
|
||||||
function setRootClasses(list) {
|
|
||||||
lastThemeClasses.forEach(c => c && root.classList.remove(c));
|
|
||||||
list.filter(Boolean).forEach(c => root.classList.add(c));
|
|
||||||
lastThemeClasses = list.filter(Boolean);
|
|
||||||
}
|
|
||||||
|
|
||||||
function reflectUI(mode) {
|
|
||||||
// Trigger icon + optional label
|
|
||||||
const trig = host.querySelector("[data-menu-trigger]");
|
|
||||||
if (trig) {
|
|
||||||
const labelSpan = trig.querySelector("[data-current-label]");
|
|
||||||
if (labelSpan) labelSpan.textContent = mode[0].toUpperCase() + mode.slice(1);
|
|
||||||
trig.querySelectorAll("[data-current-icon]").forEach(el => {
|
|
||||||
const is = el.getAttribute("data-current-icon") === mode;
|
|
||||||
el.classList.toggle("wr:hidden", !is);
|
|
||||||
el.classList.toggle("wr:inline", is);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Menu radios & checks
|
|
||||||
const panel = host.querySelector("[data-menu-panel]");
|
|
||||||
if (panel) {
|
|
||||||
panel.querySelectorAll("[role='menuitemradio']").forEach(item => {
|
|
||||||
const active = item.getAttribute("data-set-theme") === mode;
|
|
||||||
item.setAttribute("aria-checked", active ? "true" : "false");
|
|
||||||
item.classList.toggle("wr:bg-muted/60", active);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function openMenu(open) {
|
|
||||||
const trigger = host.querySelector("[data-menu-trigger]");
|
|
||||||
const panel = host.querySelector("[data-menu-panel]");
|
|
||||||
trigger?.setAttribute("aria-expanded", open ? "true" : "false");
|
|
||||||
if (!panel) return;
|
|
||||||
if (open) {
|
|
||||||
panel.classList.remove("wr:hidden");
|
|
||||||
requestAnimationFrame(() => {
|
|
||||||
panel.classList.remove("wr:scale-95","wr:opacity-0");
|
|
||||||
panel.classList.add("wr:scale-100","wr:opacity-100");
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
panel.classList.add("wr:scale-95","wr:opacity-0");
|
|
||||||
setTimeout(() => panel.classList.add("wr:hidden"), 150);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function apply(mode) {
|
|
||||||
const resolved = mode === "system" ? (mql.matches ? "dark" : "light") : mode;
|
|
||||||
root.classList.toggle("dark", resolved === "dark");
|
|
||||||
root.setAttribute("data-theme", resolved);
|
|
||||||
document.documentElement.style.colorScheme = resolved;
|
|
||||||
setRootClasses([rootExtraClass, ...(resolved === "dark" ? darkBgClass : lightBgClass)]);
|
|
||||||
localStorage.setItem(storageKey, mode);
|
|
||||||
reflectUI(mode);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Init
|
|
||||||
const saved = (localStorage.getItem(storageKey) ) || "system";
|
|
||||||
apply(saved);
|
|
||||||
|
|
||||||
// react to system changes when mode=system
|
|
||||||
mql.addEventListener?.("change", () => {
|
|
||||||
if ((localStorage.getItem(storageKey) ) === "system") apply("system");
|
|
||||||
});
|
|
||||||
|
|
||||||
// Events (scoped to this component)
|
|
||||||
host.addEventListener("click", (e) => {
|
|
||||||
const trigger = (e.target )?.closest?.("[data-menu-trigger]");
|
|
||||||
if (trigger && host.contains(trigger)) {
|
|
||||||
const expanded = trigger.getAttribute("aria-expanded") === "true";
|
|
||||||
openMenu(!expanded);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const choose = (e.target )?.closest?.("[data-set-theme]");
|
|
||||||
if (choose && host.contains(choose)) {
|
|
||||||
apply(choose.getAttribute("data-set-theme") );
|
|
||||||
openMenu(false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Close on outside click
|
|
||||||
document.addEventListener("click", (e) => {
|
|
||||||
if (!host.contains(e.target )) openMenu(false);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Esc to close
|
|
||||||
document.addEventListener("keydown", (e) => {
|
|
||||||
if (e.key === "Escape") openMenu(false);
|
|
||||||
});
|
|
||||||
})();
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style is:inline>
|
<style is:inline>
|
||||||
/* Check icon ONLY on active item */
|
/* Compact trigger tweak without touching Dropdown source */
|
||||||
#{containerId} [role="menuitemradio"][aria-checked="true"] [data-check] {
|
#{containerId}[data-compact="1"] [data-dd-trigger]{
|
||||||
|
height: 2.25rem;
|
||||||
|
padding-left: .5rem;
|
||||||
|
padding-right: .5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Show check icon ONLY on active */
|
||||||
|
#{containerId} [role="menuitemradio"][aria-checked="true"] [data-check]{
|
||||||
opacity: 1 !important;
|
opacity: 1 !important;
|
||||||
transform: scale(1) !important;
|
transform: scale(1) !important;
|
||||||
}
|
}
|
||||||
</style>
|
|
||||||
|
/* Subtle active row styling */
|
||||||
|
#{containerId} [role="menuitemradio"][aria-checked="true"]{
|
||||||
|
background-color: color-mix(in hsl, hsl(var(--muted)) 70%, transparent);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<script is:inline define:vars={{ containerId, storageKey, rootSelector, darkBgClass, lightBgClass, rootExtraClass }}>
|
||||||
|
(() => {
|
||||||
|
const host = document.getElementById(containerId);
|
||||||
|
if (!host) return;
|
||||||
|
|
||||||
|
const root = rootSelector === "html"
|
||||||
|
? document.documentElement
|
||||||
|
: document.querySelector(rootSelector) || document.documentElement;
|
||||||
|
|
||||||
|
const mql = window.matchMedia("(prefers-color-scheme: dark)");
|
||||||
|
let lastThemeClasses = [];
|
||||||
|
const itemSelector = `[data-set-theme][data-owner="${containerId}"]`;
|
||||||
|
|
||||||
|
function setRootClasses(list) {
|
||||||
|
lastThemeClasses.forEach(c => c && root.classList.remove(c));
|
||||||
|
list.filter(Boolean).forEach(c => root.classList.add(c));
|
||||||
|
lastThemeClasses = list.filter(Boolean);
|
||||||
|
}
|
||||||
|
|
||||||
|
function reflectUI(mode) {
|
||||||
|
const label = host.querySelector("[data-current-label]");
|
||||||
|
if (label) label.textContent = mode[0].toUpperCase() + mode.slice(1);
|
||||||
|
|
||||||
|
host.querySelectorAll("[data-current-icon]").forEach(el => {
|
||||||
|
const on = el.getAttribute("data-current-icon") === mode;
|
||||||
|
el.classList.toggle("wr:hidden", !on);
|
||||||
|
el.classList.toggle("wr:inline", on);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Items are portaled; query document by owner
|
||||||
|
document.querySelectorAll(itemSelector).forEach((el) => {
|
||||||
|
const active = el.getAttribute("data-set-theme") === mode;
|
||||||
|
el.setAttribute("aria-checked", active ? "true" : "false");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function apply(mode) {
|
||||||
|
const resolved = mode === "system" ? (mql.matches ? "dark" : "light") : mode;
|
||||||
|
root.classList.toggle("dark", resolved === "dark");
|
||||||
|
root.setAttribute("data-theme", resolved);
|
||||||
|
document.documentElement.style.colorScheme = resolved;
|
||||||
|
|
||||||
|
setRootClasses([rootExtraClass, ...(resolved === "dark" ? darkBgClass : lightBgClass)]);
|
||||||
|
|
||||||
|
localStorage.setItem(storageKey, mode);
|
||||||
|
reflectUI(mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Init
|
||||||
|
const saved = (localStorage.getItem(storageKey)) || "system";
|
||||||
|
apply(saved);
|
||||||
|
|
||||||
|
// React to system changes when mode=system
|
||||||
|
mql.addEventListener?.("change", () => {
|
||||||
|
if ((localStorage.getItem(storageKey)) === "system") apply("system");
|
||||||
|
});
|
||||||
|
|
||||||
|
// Listen globally because panel is portaled outside host
|
||||||
|
document.addEventListener("click", (e) => {
|
||||||
|
const btn = (e.target)?.closest?.(itemSelector);
|
||||||
|
if (!btn) return;
|
||||||
|
apply(btn.getAttribute("data-set-theme"));
|
||||||
|
});
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ const attributes = Astro.props;
|
|||||||
</head>
|
</head>
|
||||||
<body
|
<body
|
||||||
class={cn(
|
class={cn(
|
||||||
"bg-white dark:bg-neutral-700 text-black dark:text-white",
|
"wr:bg-white wr:dark:bg-background wr:text-black wr:dark:text-white",
|
||||||
attributes.class,
|
attributes.class,
|
||||||
)}
|
)}
|
||||||
{...attributes}
|
{...attributes}
|
||||||
|
|||||||
@@ -0,0 +1,48 @@
|
|||||||
|
---
|
||||||
|
import ColorSwitcher from "../components/ColorSwitcher.astro";
|
||||||
|
import ThemeSwitcher from "../components/ThemeSwitcher.astro";
|
||||||
|
import Base from "./Base.astro";
|
||||||
|
---
|
||||||
|
|
||||||
|
<Base>
|
||||||
|
<div class="wr:flex wr:items-center wr:gap-3 wr:pb-3 wr:p-4">
|
||||||
|
<ThemeSwitcher
|
||||||
|
darkBgClass={["wr:dark:bg-neutral-500", "wr:text-white"]}
|
||||||
|
lightBgClass={["wr:bg-white", "wr:text-black"]}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<ColorSwitcher ui="menu" />
|
||||||
|
</div>
|
||||||
|
<div class="wr:flex-1 wr:flex">
|
||||||
|
<div class="wr:w-1/6 wr:p-4 wr:space-y-3">
|
||||||
|
<h1 class="text-xl font-bold">Component List</h1>
|
||||||
|
<ul class="list-outside list-decimal">
|
||||||
|
<li class="list-item">
|
||||||
|
<a href="/icons">Icons</a>
|
||||||
|
</li>
|
||||||
|
<li class="list-item">
|
||||||
|
<a href="/buttons">Buttons</a>
|
||||||
|
</li>
|
||||||
|
<li class="list-item">
|
||||||
|
<a href="/forms">Forms</a>
|
||||||
|
</li>
|
||||||
|
<li class="list-item">
|
||||||
|
<a href="/forms1">Forms 1</a>
|
||||||
|
</li>
|
||||||
|
<li class="list-item">
|
||||||
|
<a href="/forms2">Forms 2</a>
|
||||||
|
</li>
|
||||||
|
<li class="list-item">
|
||||||
|
<a href="/theme">Theme</a>
|
||||||
|
</li>
|
||||||
|
<li class="list-item">
|
||||||
|
<a href="/dropdown">Dropdown</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="wr:w-5/6 wr:p-4">
|
||||||
|
<slot />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Base>
|
||||||
+4
-14
@@ -1,22 +1,12 @@
|
|||||||
---
|
---
|
||||||
import Base from "../layouts/Base.astro";
|
import ComponentLayout from "../layouts/ComponentLayout.astro";
|
||||||
import Button from "../components/Button.astro";
|
import Button from "../components/Button.astro";
|
||||||
import ThemeSwitcher from "../components/ThemeSwitcher.astro";
|
|
||||||
import ColorSwitcher from "../components/ColorSwitcher.astro";
|
|
||||||
---
|
---
|
||||||
|
|
||||||
<Base>
|
<ComponentLayout>
|
||||||
<ThemeSwitcher
|
|
||||||
ui="select"
|
|
||||||
darkBgClass={["wr:dark:bg-neutral-700", "wr:text-white"]}
|
|
||||||
lightBgClass={["wr:bg-white", "wr:text-black"]}
|
|
||||||
rootExtraClass=""
|
|
||||||
/>
|
|
||||||
<ColorSwitcher />
|
|
||||||
|
|
||||||
<div class="wr:p-4">
|
<div class="wr:p-4">
|
||||||
<Button
|
<Button
|
||||||
variant="outline"
|
variant="solid"
|
||||||
icon="lets-icons:check-ring-duotone-line"
|
icon="lets-icons:check-ring-duotone-line"
|
||||||
color="primary"
|
color="primary"
|
||||||
size="md"
|
size="md"
|
||||||
@@ -24,4 +14,4 @@ import ColorSwitcher from "../components/ColorSwitcher.astro";
|
|||||||
Submit
|
Submit
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</Base>
|
</ComponentLayout>
|
||||||
|
|||||||
@@ -1,21 +1,12 @@
|
|||||||
---
|
---
|
||||||
import Base from "../layouts/Base.astro";
|
import ComponentLayout from "../layouts/ComponentLayout.astro";
|
||||||
import Dropdown from "../components/Dropdown.astro";
|
import Dropdown from "../components/Dropdown.astro";
|
||||||
import ThemeSwitcher from "../components/ThemeSwitcher.astro";
|
|
||||||
import ColorSwitcher from "../components/ColorSwitcher.astro";
|
|
||||||
---
|
---
|
||||||
|
|
||||||
<Base>
|
<ComponentLayout>
|
||||||
<div
|
<div
|
||||||
class="wrnx wr:flex wr:items-center wr:flex-col wr:gap-4 wr:w-full wr:h-screen"
|
class="wrnx wr:flex wr:items-center wr:flex-col wr:gap-4 wr:w-full wr:h-screen"
|
||||||
>
|
>
|
||||||
<ThemeSwitcher
|
|
||||||
darkBgClass={["wr:dark:bg-neutral-500", "wr:text-white"]}
|
|
||||||
lightBgClass={["wr:bg-white", "wr:text-black"]}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<ColorSwitcher ui="menu" />
|
|
||||||
|
|
||||||
<Dropdown placement="bottom">
|
<Dropdown placement="bottom">
|
||||||
<div slot="trigger" class="wr:inline-flex wr:items-center wr:gap-2">
|
<div slot="trigger" class="wr:inline-flex wr:items-center wr:gap-2">
|
||||||
Actions
|
Actions
|
||||||
@@ -56,7 +47,7 @@ import ColorSwitcher from "../components/ColorSwitcher.astro";
|
|||||||
</div>
|
</div>
|
||||||
</Dropdown>
|
</Dropdown>
|
||||||
</div>
|
</div>
|
||||||
</Base>
|
</ComponentLayout>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
const alerthere = document.getElementById("alertHere");
|
const alerthere = document.getElementById("alertHere");
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
---
|
---
|
||||||
import Form from "../components/Form.astro";
|
import Form from "../components/Form.astro";
|
||||||
import Field from "../components/Field.astro";
|
import Field from "../components/Field.astro";
|
||||||
import Base from "../layouts/Base.astro";
|
import ComponentLayout from "../layouts/ComponentLayout.astro";
|
||||||
---
|
---
|
||||||
|
|
||||||
<Base class="wr:p-4">
|
<ComponentLayout class="wr:p-4">
|
||||||
<Form
|
<Form
|
||||||
title="Create Project"
|
title="Create Project"
|
||||||
description="Fields marked * are required."
|
description="Fields marked * are required."
|
||||||
@@ -69,7 +69,7 @@ import Base from "../layouts/Base.astro";
|
|||||||
class="wr:sm:col-span-2"
|
class="wr:sm:col-span-2"
|
||||||
/>
|
/>
|
||||||
</Form>
|
</Form>
|
||||||
</Base>
|
</ComponentLayout>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
---
|
---
|
||||||
import Form from "../components/Form.astro";
|
import Form from "../components/Form.astro";
|
||||||
import Field from "../components/Field.astro";
|
import Field from "../components/Field.astro";
|
||||||
import Base from "../layouts/Base.astro";
|
import ComponentLayout from "../layouts/ComponentLayout.astro";
|
||||||
---
|
---
|
||||||
|
|
||||||
<Base class="wr:p-4">
|
<ComponentLayout class="wr:p-4">
|
||||||
<Form
|
<Form
|
||||||
title="Account Settings"
|
title="Account Settings"
|
||||||
description="Basic profile & auth fields. * indicates required."
|
description="Basic profile & auth fields. * indicates required."
|
||||||
@@ -74,7 +74,7 @@ import Base from "../layouts/Base.astro";
|
|||||||
class="wr:sm:col-span-2"
|
class="wr:sm:col-span-2"
|
||||||
/>
|
/>
|
||||||
</Form>
|
</Form>
|
||||||
</Base>
|
</ComponentLayout>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|||||||
@@ -2,10 +2,10 @@
|
|||||||
import Field from "../components/Field.astro";
|
import Field from "../components/Field.astro";
|
||||||
import Form from "../components/Form.astro";
|
import Form from "../components/Form.astro";
|
||||||
import MultiSelect from "../components/MultiSelect.astro";
|
import MultiSelect from "../components/MultiSelect.astro";
|
||||||
import Base from "../layouts/Base.astro";
|
import ComponentLayout from "../layouts/ComponentLayout.astro";
|
||||||
---
|
---
|
||||||
|
|
||||||
<Base class="wr:p-4">
|
<ComponentLayout class="wr:p-4">
|
||||||
<Form
|
<Form
|
||||||
title="Job Application"
|
title="Job Application"
|
||||||
description="Tell us about yourself. Fields marked * are required."
|
description="Tell us about yourself. Fields marked * are required."
|
||||||
@@ -155,7 +155,7 @@ import Base from "../layouts/Base.astro";
|
|||||||
class="wr:sm:col-span-2"
|
class="wr:sm:col-span-2"
|
||||||
/>
|
/>
|
||||||
</Form>
|
</Form>
|
||||||
</Base>
|
</ComponentLayout>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
---
|
---
|
||||||
import { Icon } from "astro-icon/components";
|
import { Icon } from "astro-icon/components";
|
||||||
import Base from "../layouts/Base.astro";
|
import ComponentLayout from "../layouts/ComponentLayout.astro";
|
||||||
---
|
---
|
||||||
|
|
||||||
<Base>
|
<ComponentLayout>
|
||||||
<Icon name="lets-icons:chart-alt-duotone-line" size="xl" />
|
<Icon name="lets-icons:chart-alt-duotone-line" size="xl" />
|
||||||
</Base>
|
</ComponentLayout>
|
||||||
|
|||||||
+11
-11
@@ -1,23 +1,23 @@
|
|||||||
---
|
---
|
||||||
import ThemeSwitcher from "../components/ThemeSwitcher.astro";
|
|
||||||
import ColorSwitcher from "../components/ColorSwitcher.astro";
|
import ColorSwitcher from "../components/ColorSwitcher.astro";
|
||||||
import Base from "../layouts/Base.astro";
|
import ThemeSwitcher from "../components/ThemeSwitcher.astro";
|
||||||
|
import ComponentLayout from "../layouts/ComponentLayout.astro";
|
||||||
---
|
---
|
||||||
|
|
||||||
<Base>
|
<ComponentLayout>
|
||||||
<div
|
<div
|
||||||
class="wrnx wr:flex wr:items-center wr:flex-col wr:gap-4 wr:w-full wr:h-screen"
|
class="wrnx wr:flex wr:items-center wr:flex-col wr:gap-4 wr:w-full wr:h-screen"
|
||||||
>
|
>
|
||||||
<!-- Icon-only trigger (default) -->
|
<div class="wr:flex wr:items-center wr:gap-3 wr:pb-3 wr:p-4">
|
||||||
<ThemeSwitcher
|
<ThemeSwitcher
|
||||||
darkBgClass={["wr:dark:bg-neutral-500", "wr:text-white"]}
|
darkBgClass={["wr:dark:bg-neutral-500", "wr:text-white"]}
|
||||||
lightBgClass={["wr:bg-white", "wr:text-black"]}
|
lightBgClass={["wr:bg-white", "wr:text-black"]}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<ColorSwitcher ui="menu" trigger="dot" />
|
|
||||||
|
|
||||||
|
<ColorSwitcher ui="menu" />
|
||||||
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<h1 class="wr:text-primary">Test Heading</h1>
|
<h1 class="wr:text-primary">Test Heading</h1>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Base>
|
</ComponentLayout>
|
||||||
|
|||||||
@@ -33,4 +33,14 @@
|
|||||||
--color-danger-foreground: hsl(var(--danger-foreground));
|
--color-danger-foreground: hsl(var(--danger-foreground));
|
||||||
--color-neutral: hsl(var(--neutral));
|
--color-neutral: hsl(var(--neutral));
|
||||||
--color-neutral-foreground: hsl(var(--neutral-foreground));
|
--color-neutral-foreground: hsl(var(--neutral-foreground));
|
||||||
|
--color-background: hsl(var(--background));
|
||||||
|
--color-foreground: hsl(var(--foreground));
|
||||||
|
--color-card: hsl(var(--card));
|
||||||
|
--color-card-foreground: hsl(var(--card-foreground));
|
||||||
|
--color-popover: hsl(var(--popover));
|
||||||
|
--color-popover-foreground: hsl(var(--popover-foreground));
|
||||||
|
--color-muted: hsl(var(--muted));
|
||||||
|
--color-muted-foreground: hsl(var(--muted-foreground));
|
||||||
|
--color-border: hsl(var(--border));
|
||||||
|
--color-input: hsl(var(--input));
|
||||||
}
|
}
|
||||||
@@ -20,6 +20,17 @@
|
|||||||
--neutral-foreground: 210 40% 98%;
|
--neutral-foreground: 210 40% 98%;
|
||||||
--link: 221 83% 53%;
|
--link: 221 83% 53%;
|
||||||
--link-visited: 262 83% 58%;
|
--link-visited: 262 83% 58%;
|
||||||
|
--background: 0 0% 100%;
|
||||||
|
--foreground: 222 47% 11%;
|
||||||
|
--card: 0 0% 100%;
|
||||||
|
--card-foreground: 222 47% 11%;
|
||||||
|
--popover: 0 0% 100%;
|
||||||
|
--popover-foreground: 222 47% 11%;
|
||||||
|
--muted: 220 14% 96%;
|
||||||
|
--muted-foreground: 215 16% 46%;
|
||||||
|
--border: 214 31% 91%;
|
||||||
|
--input: 214 31% 91%;
|
||||||
|
--ring: 221 83% 53%;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---------- Brand palettes (swap only role colors) ---------- */
|
/* ---------- Brand palettes (swap only role colors) ---------- */
|
||||||
@@ -210,4 +221,213 @@
|
|||||||
--danger-foreground: 0 0% 100%;
|
--danger-foreground: 0 0% 100%;
|
||||||
--neutral: 215 16% 47%;
|
--neutral: 215 16% 47%;
|
||||||
--neutral-foreground: 210 40% 98%;
|
--neutral-foreground: 210 40% 98%;
|
||||||
|
}
|
||||||
|
[data-color="neutral"] {
|
||||||
|
--primary: 215 16% 47%;
|
||||||
|
--primary-foreground: 210 40% 98%;
|
||||||
|
--secondary: 220 14% 34%;
|
||||||
|
--secondary-foreground: 210 40% 98%;
|
||||||
|
--tertiary: 220 10% 60%;
|
||||||
|
--tertiary-foreground: 222 47% 10%;
|
||||||
|
--accent: 216 12% 52%;
|
||||||
|
--accent-foreground: 210 40% 98%;
|
||||||
|
--info: 201 96% 48%;
|
||||||
|
--success: 142 71% 45%;
|
||||||
|
--success-foreground: 144 60% 98%;
|
||||||
|
--warning: 38 92% 50%;
|
||||||
|
--warning-foreground: 26 83% 15%;
|
||||||
|
--danger: 0 84% 60%;
|
||||||
|
--danger-foreground: 0 0% 100%;
|
||||||
|
--neutral: 215 16% 47%;
|
||||||
|
--neutral-foreground: 210 40% 98%;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-color="gray"] {
|
||||||
|
--primary: 220 9% 46%;
|
||||||
|
--primary-foreground: 210 40% 98%;
|
||||||
|
--secondary: 220 7% 38%;
|
||||||
|
--secondary-foreground: 210 40% 98%;
|
||||||
|
--tertiary: 220 10% 60%;
|
||||||
|
--tertiary-foreground: 222 47% 10%;
|
||||||
|
--accent: 220 12% 52%;
|
||||||
|
--accent-foreground: 210 40% 98%;
|
||||||
|
--info: 201 96% 48%;
|
||||||
|
--success: 142 71% 45%;
|
||||||
|
--success-foreground: 144 60% 98%;
|
||||||
|
--warning: 38 92% 50%;
|
||||||
|
--warning-foreground: 26 83% 15%;
|
||||||
|
--danger: 0 84% 60%;
|
||||||
|
--danger-foreground: 0 0% 100%;
|
||||||
|
--neutral: 220 10% 40%;
|
||||||
|
--neutral-foreground: 210 40% 98%;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* =======================
|
||||||
|
Dark surfaces baseline
|
||||||
|
======================= */
|
||||||
|
:root.dark {
|
||||||
|
color-scheme: dark;
|
||||||
|
--background: 222 14% 12%;
|
||||||
|
--foreground: 210 40% 96%;
|
||||||
|
--card: 222 12% 14%;
|
||||||
|
--card-foreground: 210 40% 96%;
|
||||||
|
--popover: 222 12% 14%;
|
||||||
|
--popover-foreground: 210 40% 96%;
|
||||||
|
--muted: 220 10% 18%;
|
||||||
|
--muted-foreground: 215 20% 72%;
|
||||||
|
--border: 220 12% 22%;
|
||||||
|
--input: 220 12% 22%;
|
||||||
|
--ring: 217 91% 60%;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* =======================
|
||||||
|
Dark platters (surface-only)
|
||||||
|
======================= */
|
||||||
|
|
||||||
|
/* gray */
|
||||||
|
:root.dark[data-color="ocean"] {
|
||||||
|
--background: 201 20% 13%;
|
||||||
|
--foreground: 210 40% 96%;
|
||||||
|
--card: 201 18% 15%;
|
||||||
|
--card-foreground: 210 40% 96%;
|
||||||
|
--popover: 201 18% 15%;
|
||||||
|
--popover-foreground: 210 40% 96%;
|
||||||
|
--muted: 201 16% 20%;
|
||||||
|
--muted-foreground: 200 20% 78%;
|
||||||
|
--border: 201 16% 24%;
|
||||||
|
--input: 201 16% 24%;
|
||||||
|
}
|
||||||
|
|
||||||
|
:root.dark[data-color="forest"] {
|
||||||
|
--background: 150 16% 12%;
|
||||||
|
--foreground: 160 30% 96%;
|
||||||
|
--card: 150 14% 14%;
|
||||||
|
--card-foreground: 160 30% 96%;
|
||||||
|
--popover: 150 14% 14%;
|
||||||
|
--popover-foreground: 160 30% 96%;
|
||||||
|
--muted: 150 12% 19%;
|
||||||
|
--muted-foreground: 150 16% 78%;
|
||||||
|
--border: 150 12% 23%;
|
||||||
|
--input: 150 12% 23%;
|
||||||
|
}
|
||||||
|
|
||||||
|
:root.dark[data-color="sunset"] {
|
||||||
|
--background: 18 20% 12%;
|
||||||
|
--foreground: 24 30% 96%;
|
||||||
|
--card: 18 18% 14%;
|
||||||
|
--card-foreground: 24 30% 96%;
|
||||||
|
--popover: 18 18% 14%;
|
||||||
|
--popover-foreground: 24 30% 96%;
|
||||||
|
--muted: 18 16% 20%;
|
||||||
|
--muted-foreground: 20 20% 80%;
|
||||||
|
--border: 18 16% 24%;
|
||||||
|
--input: 18 16% 24%;
|
||||||
|
}
|
||||||
|
|
||||||
|
:root.dark[data-color="grape"] {
|
||||||
|
--background: 275 22% 13%;
|
||||||
|
--foreground: 0 0% 98%;
|
||||||
|
--card: 275 20% 15%;
|
||||||
|
--card-foreground: 0 0% 98%;
|
||||||
|
--popover: 275 20% 15%;
|
||||||
|
--popover-foreground: 0 0% 98%;
|
||||||
|
--muted: 275 18% 21%;
|
||||||
|
--muted-foreground: 275 14% 78%;
|
||||||
|
--border: 275 16% 25%;
|
||||||
|
--input: 275 16% 25%;
|
||||||
|
}
|
||||||
|
|
||||||
|
:root.dark[data-color="slate"] {
|
||||||
|
--background: 220 12% 12%;
|
||||||
|
--foreground: 210 40% 96%;
|
||||||
|
--card: 220 11% 14%;
|
||||||
|
--card-foreground: 210 40% 96%;
|
||||||
|
--popover: 220 11% 14%;
|
||||||
|
--popover-foreground: 210 40% 96%;
|
||||||
|
--muted: 220 8% 20%;
|
||||||
|
--muted-foreground: 215 18% 74%;
|
||||||
|
--border: 220 10% 24%;
|
||||||
|
--input: 220 10% 24%;
|
||||||
|
}
|
||||||
|
|
||||||
|
:root.dark[data-color="indigo"] {
|
||||||
|
--background: 238 22% 14%;
|
||||||
|
--foreground: 210 40% 96%;
|
||||||
|
--card: 238 20% 16%;
|
||||||
|
--card-foreground: 210 40% 96%;
|
||||||
|
--popover: 238 20% 16%;
|
||||||
|
--popover-foreground: 210 40% 96%;
|
||||||
|
--muted: 238 18% 22%;
|
||||||
|
--muted-foreground: 220 25% 80%;
|
||||||
|
--border: 238 18% 26%;
|
||||||
|
--input: 238 18% 26%;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Aliases for the remaining brands */
|
||||||
|
:root.dark[data-color="mint"] {
|
||||||
|
/* use forest surfaces */
|
||||||
|
--background: 150 16% 12%;
|
||||||
|
--foreground: 160 30% 96%;
|
||||||
|
--card: 150 14% 14%;
|
||||||
|
--card-foreground: 160 30% 96%;
|
||||||
|
--popover: 150 14% 14%;
|
||||||
|
--popover-foreground: 160 30% 96%;
|
||||||
|
--muted: 150 12% 19%;
|
||||||
|
--muted-foreground: 150 16% 78%;
|
||||||
|
--border: 150 12% 23%;
|
||||||
|
--input: 150 12% 23%;
|
||||||
|
}
|
||||||
|
|
||||||
|
:root.dark[data-color="amber"] {
|
||||||
|
/* use sunset surfaces */
|
||||||
|
--background: 18 20% 12%;
|
||||||
|
--foreground: 24 30% 96%;
|
||||||
|
--card: 18 18% 14%;
|
||||||
|
--card-foreground: 24 30% 96%;
|
||||||
|
--popover: 18 18% 14%;
|
||||||
|
--popover-foreground: 24 30% 96%;
|
||||||
|
--muted: 18 16% 20%;
|
||||||
|
--muted-foreground: 20 20% 80%;
|
||||||
|
--border: 18 16% 24%;
|
||||||
|
--input: 18 16% 24%;
|
||||||
|
}
|
||||||
|
|
||||||
|
:root.dark[data-color="crimson"] {
|
||||||
|
/* use gray baseline surfaces */
|
||||||
|
--background: 222 14% 12%;
|
||||||
|
--foreground: 210 40% 96%;
|
||||||
|
--card: 222 12% 14%;
|
||||||
|
--card-foreground: 210 40% 96%;
|
||||||
|
--popover: 222 12% 14%;
|
||||||
|
--popover-foreground: 210 40% 96%;
|
||||||
|
--muted: 220 10% 18%;
|
||||||
|
--muted-foreground: 215 20% 72%;
|
||||||
|
--border: 220 12% 22%;
|
||||||
|
--input: 220 12% 22%;
|
||||||
|
}
|
||||||
|
|
||||||
|
:root.dark[data-color="neutral"] {
|
||||||
|
--background: 220 12% 12%;
|
||||||
|
--foreground: 210 40% 96%;
|
||||||
|
--card: 220 11% 14%;
|
||||||
|
--card-foreground: 210 40% 96%;
|
||||||
|
--popover: 220 11% 14%;
|
||||||
|
--popover-foreground: 210 40% 96%;
|
||||||
|
--muted: 220 8% 20%;
|
||||||
|
--muted-foreground: 215 18% 74%;
|
||||||
|
--border: 220 10% 24%;
|
||||||
|
--input: 220 10% 24%;
|
||||||
|
}
|
||||||
|
|
||||||
|
:root.dark[data-color="gray"] {
|
||||||
|
--background: 220 10% 12%;
|
||||||
|
--foreground: 210 40% 96%;
|
||||||
|
--card: 220 9% 14%;
|
||||||
|
--card-foreground: 210 40% 96%;
|
||||||
|
--popover: 220 9% 14%;
|
||||||
|
--popover-foreground: 210 40% 96%;
|
||||||
|
--muted: 220 8% 19%;
|
||||||
|
--muted-foreground: 215 18% 74%;
|
||||||
|
--border: 220 9% 23%;
|
||||||
|
--input: 220 9% 23%;
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user