@lanrenbang/basecoat-ultra 0.1.2
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-cn.md +54 -0
- package/CHANGELOG.md +54 -0
- package/LICENSE +21 -0
- package/README-cn.md +186 -0
- package/README.md +173 -0
- package/dist/css/basecoat.cdn.css +7389 -0
- package/dist/css/basecoat.cdn.min.css +2 -0
- package/dist/css/basecoat.css +1797 -0
- package/dist/css/datepicker.css +382 -0
- package/dist/css/datepicker.min.css +1 -0
- package/dist/css/resizable.css +96 -0
- package/dist/css/resizable.min.css +1 -0
- package/dist/js/accordion.js +20 -0
- package/dist/js/accordion.min.js +13 -0
- package/dist/js/all.js +17 -0
- package/dist/js/all.min.js +17 -0
- package/dist/js/basecoat.js +75 -0
- package/dist/js/basecoat.min.js +56 -0
- package/dist/js/carousel.js +104 -0
- package/dist/js/carousel.min.js +41 -0
- package/dist/js/catppuccin-theme-switcher.js +136 -0
- package/dist/js/catppuccin-theme-switcher.min.js +73 -0
- package/dist/js/command.js +132 -0
- package/dist/js/command.min.js +76 -0
- package/dist/js/datepicker.js +2367 -0
- package/dist/js/datepicker.min.js +1422 -0
- package/dist/js/dialog.js +20 -0
- package/dist/js/dialog.min.js +11 -0
- package/dist/js/dropdown-menu.js +148 -0
- package/dist/js/dropdown-menu.min.js +75 -0
- package/dist/js/input-otp.js +94 -0
- package/dist/js/input-otp.min.js +38 -0
- package/dist/js/lighting.js +80 -0
- package/dist/js/lighting.min.js +44 -0
- package/dist/js/popover.js +72 -0
- package/dist/js/popover.min.js +34 -0
- package/dist/js/resizable.js +534 -0
- package/dist/js/resizable.min.js +284 -0
- package/dist/js/select.js +246 -0
- package/dist/js/select.min.js +131 -0
- package/dist/js/sheet.js +85 -0
- package/dist/js/sheet.min.js +40 -0
- package/dist/js/sidebar.js +87 -0
- package/dist/js/sidebar.min.js +53 -0
- package/dist/js/slider.js +18 -0
- package/dist/js/slider.min.js +10 -0
- package/dist/js/tabs.js +53 -0
- package/dist/js/tabs.min.js +40 -0
- package/dist/js/toast.js +137 -0
- package/dist/js/toast.min.js +83 -0
- package/dist/js/toggle.js +36 -0
- package/dist/js/toggle.min.js +20 -0
- package/dist/theme/catppuccin/index.css +448 -0
- package/dist/theme/catppuccin/index.min.css +1 -0
- package/package.json +46 -0
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
(() => {
|
|
2
|
+
const i = {};
|
|
3
|
+
let r = null;
|
|
4
|
+
const l = (e, o, t) => {
|
|
5
|
+
i[e] = {
|
|
6
|
+
selector: o,
|
|
7
|
+
init: t
|
|
8
|
+
};
|
|
9
|
+
}, c = () => {
|
|
10
|
+
Object.entries(i).forEach(([e, { selector: o, init: t }]) => {
|
|
11
|
+
document.querySelectorAll(o).forEach(t);
|
|
12
|
+
});
|
|
13
|
+
}, a = (e) => {
|
|
14
|
+
e.nodeType === Node.ELEMENT_NODE && Object.entries(i).forEach(([o, { selector: t, init: n }]) => {
|
|
15
|
+
e.matches(t) && n(e), e.querySelectorAll(t).forEach(n);
|
|
16
|
+
});
|
|
17
|
+
}, s = () => {
|
|
18
|
+
if (r) return;
|
|
19
|
+
let e;
|
|
20
|
+
r = new MutationObserver((o) => {
|
|
21
|
+
clearTimeout(e), e = setTimeout(() => {
|
|
22
|
+
o.forEach((t) => {
|
|
23
|
+
t.addedNodes.forEach(a);
|
|
24
|
+
});
|
|
25
|
+
}, 50);
|
|
26
|
+
}), r.observe(document.body, { childList: !0, subtree: !0 });
|
|
27
|
+
}, u = () => {
|
|
28
|
+
r && (r.disconnect(), r = null);
|
|
29
|
+
}, d = (e) => {
|
|
30
|
+
const o = i[e];
|
|
31
|
+
if (!o) {
|
|
32
|
+
console.warn(`Component '${e}' not found in registry`);
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
const t = `data-${e}-initialized`;
|
|
36
|
+
document.querySelectorAll(`[${t}]`).forEach((n) => {
|
|
37
|
+
n.removeAttribute(t);
|
|
38
|
+
}), document.querySelectorAll(o.selector).forEach(o.init);
|
|
39
|
+
}, f = () => {
|
|
40
|
+
Object.entries(i).forEach(([e, { selector: o }]) => {
|
|
41
|
+
const t = `data-${e}-initialized`;
|
|
42
|
+
document.querySelectorAll(`[${t}]`).forEach((n) => {
|
|
43
|
+
n.removeAttribute(t);
|
|
44
|
+
});
|
|
45
|
+
}), c();
|
|
46
|
+
};
|
|
47
|
+
window.basecoat = {
|
|
48
|
+
register: l,
|
|
49
|
+
init: d,
|
|
50
|
+
initAll: f,
|
|
51
|
+
start: s,
|
|
52
|
+
stop: u
|
|
53
|
+
}, document.addEventListener("DOMContentLoaded", () => {
|
|
54
|
+
c(), s();
|
|
55
|
+
});
|
|
56
|
+
})();
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
(() => {
|
|
2
|
+
const initCarousel = (carousel) => {
|
|
3
|
+
const content = carousel.querySelector(".carousel-content");
|
|
4
|
+
const prevBtn = carousel.querySelector(".carousel-previous");
|
|
5
|
+
const nextBtn = carousel.querySelector(".carousel-next");
|
|
6
|
+
const orientation = carousel.dataset.orientation || "horizontal";
|
|
7
|
+
if (!content) return;
|
|
8
|
+
const getScrollAmount = () => {
|
|
9
|
+
const firstItem = content.querySelector(".carousel-item");
|
|
10
|
+
if (!firstItem) return orientation === "vertical" ? content.offsetHeight : content.offsetWidth;
|
|
11
|
+
const style = window.getComputedStyle(firstItem);
|
|
12
|
+
if (orientation === "vertical") {
|
|
13
|
+
const itemHeight = firstItem.offsetHeight;
|
|
14
|
+
const marginTop = parseFloat(style.marginTop);
|
|
15
|
+
const marginBottom = parseFloat(style.marginBottom);
|
|
16
|
+
return itemHeight + marginTop + marginBottom;
|
|
17
|
+
} else {
|
|
18
|
+
const itemWidth = firstItem.offsetWidth;
|
|
19
|
+
const marginLeft = parseFloat(style.marginLeft);
|
|
20
|
+
const marginRight = parseFloat(style.marginRight);
|
|
21
|
+
return itemWidth + marginLeft + marginRight;
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
const scroll = (direction) => {
|
|
25
|
+
const amount = getScrollAmount();
|
|
26
|
+
const value = direction === "next" ? amount : -amount;
|
|
27
|
+
if (orientation === "vertical") {
|
|
28
|
+
content.scrollBy({ top: value, behavior: "smooth" });
|
|
29
|
+
} else {
|
|
30
|
+
content.scrollBy({ left: value, behavior: "smooth" });
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
const updateButtons = () => {
|
|
34
|
+
if (!prevBtn && !nextBtn) return;
|
|
35
|
+
const { scrollLeft, scrollTop, scrollWidth, scrollHeight, clientWidth, clientHeight } = content;
|
|
36
|
+
if (orientation === "vertical") {
|
|
37
|
+
const canScrollPrev = scrollTop > 1;
|
|
38
|
+
const canScrollNext = scrollTop < scrollHeight - clientHeight - 1;
|
|
39
|
+
if (prevBtn) {
|
|
40
|
+
prevBtn.disabled = !canScrollPrev;
|
|
41
|
+
prevBtn.setAttribute("aria-disabled", String(!canScrollPrev));
|
|
42
|
+
}
|
|
43
|
+
if (nextBtn) {
|
|
44
|
+
nextBtn.disabled = !canScrollNext;
|
|
45
|
+
nextBtn.setAttribute("aria-disabled", String(!canScrollNext));
|
|
46
|
+
}
|
|
47
|
+
} else {
|
|
48
|
+
const canScrollPrev = scrollLeft > 1;
|
|
49
|
+
const canScrollNext = scrollLeft < scrollWidth - clientWidth - 1;
|
|
50
|
+
if (prevBtn) {
|
|
51
|
+
prevBtn.disabled = !canScrollPrev;
|
|
52
|
+
prevBtn.setAttribute("aria-disabled", String(!canScrollPrev));
|
|
53
|
+
}
|
|
54
|
+
if (nextBtn) {
|
|
55
|
+
nextBtn.disabled = !canScrollNext;
|
|
56
|
+
nextBtn.setAttribute("aria-disabled", String(!canScrollNext));
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
if (prevBtn) {
|
|
61
|
+
prevBtn.addEventListener("click", () => scroll("prev"));
|
|
62
|
+
}
|
|
63
|
+
if (nextBtn) {
|
|
64
|
+
nextBtn.addEventListener("click", () => scroll("next"));
|
|
65
|
+
}
|
|
66
|
+
let ticking = false;
|
|
67
|
+
content.addEventListener("scroll", () => {
|
|
68
|
+
if (!ticking) {
|
|
69
|
+
window.requestAnimationFrame(() => {
|
|
70
|
+
updateButtons();
|
|
71
|
+
ticking = false;
|
|
72
|
+
});
|
|
73
|
+
ticking = true;
|
|
74
|
+
}
|
|
75
|
+
}, { passive: true });
|
|
76
|
+
carousel.addEventListener("keydown", (e) => {
|
|
77
|
+
if (orientation === "vertical") {
|
|
78
|
+
if (e.key === "ArrowUp") {
|
|
79
|
+
e.preventDefault();
|
|
80
|
+
prevBtn?.click();
|
|
81
|
+
} else if (e.key === "ArrowDown") {
|
|
82
|
+
e.preventDefault();
|
|
83
|
+
nextBtn?.click();
|
|
84
|
+
}
|
|
85
|
+
} else {
|
|
86
|
+
if (e.key === "ArrowLeft") {
|
|
87
|
+
e.preventDefault();
|
|
88
|
+
prevBtn?.click();
|
|
89
|
+
} else if (e.key === "ArrowRight") {
|
|
90
|
+
e.preventDefault();
|
|
91
|
+
nextBtn?.click();
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
const resizeObserver = new ResizeObserver(updateButtons);
|
|
96
|
+
resizeObserver.observe(content);
|
|
97
|
+
updateButtons();
|
|
98
|
+
carousel.dataset.carouselInitialized = true;
|
|
99
|
+
carousel.dispatchEvent(new CustomEvent("basecoat:initialized"));
|
|
100
|
+
};
|
|
101
|
+
if (window.basecoat) {
|
|
102
|
+
window.basecoat.register("carousel", ".carousel:not([data-carousel-initialized])", initCarousel);
|
|
103
|
+
}
|
|
104
|
+
})();
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
(() => {
|
|
2
|
+
const m = (s) => {
|
|
3
|
+
const o = s.querySelector(".carousel-content"), e = s.querySelector(".carousel-previous"), i = s.querySelector(".carousel-next"), a = s.dataset.orientation || "horizontal";
|
|
4
|
+
if (!o) return;
|
|
5
|
+
const b = () => {
|
|
6
|
+
const t = o.querySelector(".carousel-item");
|
|
7
|
+
if (!t) return a === "vertical" ? o.offsetHeight : o.offsetWidth;
|
|
8
|
+
const r = window.getComputedStyle(t);
|
|
9
|
+
if (a === "vertical") {
|
|
10
|
+
const n = t.offsetHeight, l = parseFloat(r.marginTop), c = parseFloat(r.marginBottom);
|
|
11
|
+
return n + l + c;
|
|
12
|
+
} else {
|
|
13
|
+
const n = t.offsetWidth, l = parseFloat(r.marginLeft), c = parseFloat(r.marginRight);
|
|
14
|
+
return n + l + c;
|
|
15
|
+
}
|
|
16
|
+
}, g = (t) => {
|
|
17
|
+
const r = b(), n = t === "next" ? r : -r;
|
|
18
|
+
a === "vertical" ? o.scrollBy({ top: n, behavior: "smooth" }) : o.scrollBy({ left: n, behavior: "smooth" });
|
|
19
|
+
}, u = () => {
|
|
20
|
+
if (!e && !i) return;
|
|
21
|
+
const { scrollLeft: t, scrollTop: r, scrollWidth: n, scrollHeight: l, clientWidth: c, clientHeight: p } = o;
|
|
22
|
+
if (a === "vertical") {
|
|
23
|
+
const d = r > 1, f = r < l - p - 1;
|
|
24
|
+
e && (e.disabled = !d, e.setAttribute("aria-disabled", String(!d))), i && (i.disabled = !f, i.setAttribute("aria-disabled", String(!f)));
|
|
25
|
+
} else {
|
|
26
|
+
const d = t > 1, f = t < n - c - 1;
|
|
27
|
+
e && (e.disabled = !d, e.setAttribute("aria-disabled", String(!d))), i && (i.disabled = !f, i.setAttribute("aria-disabled", String(!f)));
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
e && e.addEventListener("click", () => g("prev")), i && i.addEventListener("click", () => g("next"));
|
|
31
|
+
let v = !1;
|
|
32
|
+
o.addEventListener("scroll", () => {
|
|
33
|
+
v || (window.requestAnimationFrame(() => {
|
|
34
|
+
u(), v = !1;
|
|
35
|
+
}), v = !0);
|
|
36
|
+
}, { passive: !0 }), s.addEventListener("keydown", (t) => {
|
|
37
|
+
a === "vertical" ? t.key === "ArrowUp" ? (t.preventDefault(), e?.click()) : t.key === "ArrowDown" && (t.preventDefault(), i?.click()) : t.key === "ArrowLeft" ? (t.preventDefault(), e?.click()) : t.key === "ArrowRight" && (t.preventDefault(), i?.click());
|
|
38
|
+
}), new ResizeObserver(u).observe(o), u(), s.dataset.carouselInitialized = !0, s.dispatchEvent(new CustomEvent("basecoat:initialized"));
|
|
39
|
+
};
|
|
40
|
+
window.basecoat && window.basecoat.register("carousel", ".carousel:not([data-carousel-initialized])", m);
|
|
41
|
+
})();
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
(() => {
|
|
2
|
+
const THEMES = ["latte", "frappe", "macchiato", "mocha"];
|
|
3
|
+
const DARK_THEMES = ["frappe", "macchiato", "mocha"];
|
|
4
|
+
const ACCENTS = [
|
|
5
|
+
"rosewater",
|
|
6
|
+
"flamingo",
|
|
7
|
+
"pink",
|
|
8
|
+
"mauve",
|
|
9
|
+
"red",
|
|
10
|
+
"maroon",
|
|
11
|
+
"peach",
|
|
12
|
+
"yellow",
|
|
13
|
+
"green",
|
|
14
|
+
"teal",
|
|
15
|
+
"sky",
|
|
16
|
+
"sapphire",
|
|
17
|
+
"blue",
|
|
18
|
+
"lavender"
|
|
19
|
+
];
|
|
20
|
+
function getThemePreviewColors(theme) {
|
|
21
|
+
if (!THEMES.includes(theme)) return {};
|
|
22
|
+
const colors = { background: `var(--ctp-${theme}-base)` };
|
|
23
|
+
ACCENTS.forEach((accent) => {
|
|
24
|
+
colors[accent] = `var(--ctp-${theme}-${accent})`;
|
|
25
|
+
});
|
|
26
|
+
return colors;
|
|
27
|
+
}
|
|
28
|
+
function setTheme(theme, accent) {
|
|
29
|
+
const root = document.documentElement;
|
|
30
|
+
THEMES.forEach((t) => root.classList.remove(`theme-${t}`));
|
|
31
|
+
ACCENTS.forEach((a) => root.classList.remove(`accent-${a}`));
|
|
32
|
+
root.classList.add(`theme-${theme}`);
|
|
33
|
+
root.classList.add(`accent-${accent}`);
|
|
34
|
+
if (DARK_THEMES.includes(theme)) {
|
|
35
|
+
root.classList.add("dark");
|
|
36
|
+
} else {
|
|
37
|
+
root.classList.remove("dark");
|
|
38
|
+
}
|
|
39
|
+
try {
|
|
40
|
+
localStorage.setItem("catppuccin-theme", theme);
|
|
41
|
+
localStorage.setItem("catppuccin-accent", accent);
|
|
42
|
+
} catch (e) {
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
function initTheme() {
|
|
46
|
+
try {
|
|
47
|
+
const savedTheme = localStorage.getItem("catppuccin-theme");
|
|
48
|
+
const savedAccent = localStorage.getItem("catppuccin-accent");
|
|
49
|
+
if (savedTheme && savedAccent) {
|
|
50
|
+
setTheme(savedTheme, savedAccent);
|
|
51
|
+
}
|
|
52
|
+
} catch (e) {
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
initTheme();
|
|
56
|
+
const init = (container) => {
|
|
57
|
+
const flavorGroup = container.querySelector(".theme-flavors");
|
|
58
|
+
const accentGrid = container.querySelector(".theme-accents");
|
|
59
|
+
const resetButton = container.querySelector(".theme-reset");
|
|
60
|
+
let currentFlavor = localStorage.getItem("catppuccin-theme") || "latte";
|
|
61
|
+
if (!THEMES.includes(currentFlavor)) currentFlavor = "latte";
|
|
62
|
+
if (flavorGroup) {
|
|
63
|
+
flavorGroup.innerHTML = "";
|
|
64
|
+
flavorGroup.className = "button-group w-full";
|
|
65
|
+
THEMES.forEach((t) => {
|
|
66
|
+
const btn = document.createElement("button");
|
|
67
|
+
btn.type = "button";
|
|
68
|
+
btn.className = "btn btn-sm capitalize flex-1";
|
|
69
|
+
btn.textContent = t;
|
|
70
|
+
btn.dataset.flavor = t;
|
|
71
|
+
flavorGroup.appendChild(btn);
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
const updateFlavorUI = () => {
|
|
75
|
+
if (!flavorGroup) return;
|
|
76
|
+
const buttons = flavorGroup.querySelectorAll("[data-flavor]");
|
|
77
|
+
buttons.forEach((btn) => {
|
|
78
|
+
if (btn.dataset.flavor === currentFlavor) {
|
|
79
|
+
btn.classList.remove("btn-outline", "btn-ghost");
|
|
80
|
+
btn.classList.add("btn-primary");
|
|
81
|
+
} else {
|
|
82
|
+
btn.classList.remove("btn-primary");
|
|
83
|
+
btn.classList.add("btn-ghost");
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
};
|
|
87
|
+
const renderAccents = () => {
|
|
88
|
+
if (!accentGrid) return;
|
|
89
|
+
accentGrid.innerHTML = "";
|
|
90
|
+
const colors = getThemePreviewColors(currentFlavor);
|
|
91
|
+
accentGrid.className = "theme-accents grid grid-cols-7 gap-3 place-items-center p-4 rounded-xl border border-border/50 mt-4 transition-colors duration-300";
|
|
92
|
+
accentGrid.style.backgroundColor = colors.background;
|
|
93
|
+
ACCENTS.forEach((acc) => {
|
|
94
|
+
const btn = document.createElement("button");
|
|
95
|
+
btn.type = "button";
|
|
96
|
+
btn.className = "size-6 rounded-full border border-border/20 shadow-sm transition-transform hover:scale-110 focus:outline-none focus:ring-2 focus:ring-ring";
|
|
97
|
+
btn.title = acc;
|
|
98
|
+
btn.style.backgroundColor = colors[acc];
|
|
99
|
+
btn.dataset.tooltip = acc;
|
|
100
|
+
btn.dataset.side = "top";
|
|
101
|
+
btn.onclick = () => {
|
|
102
|
+
setTheme(currentFlavor, acc);
|
|
103
|
+
};
|
|
104
|
+
accentGrid.appendChild(btn);
|
|
105
|
+
});
|
|
106
|
+
};
|
|
107
|
+
if (flavorGroup) {
|
|
108
|
+
flavorGroup.addEventListener("click", (e) => {
|
|
109
|
+
const btn = e.target.closest("[data-flavor]");
|
|
110
|
+
if (!btn) return;
|
|
111
|
+
currentFlavor = btn.dataset.flavor;
|
|
112
|
+
updateFlavorUI();
|
|
113
|
+
renderAccents();
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
if (resetButton) {
|
|
117
|
+
resetButton.addEventListener("click", () => {
|
|
118
|
+
const root = document.documentElement;
|
|
119
|
+
THEMES.forEach((t) => root.classList.remove(`theme-${t}`));
|
|
120
|
+
ACCENTS.forEach((a) => root.classList.remove(`accent-${a}`));
|
|
121
|
+
localStorage.removeItem("catppuccin-theme");
|
|
122
|
+
localStorage.removeItem("catppuccin-accent");
|
|
123
|
+
if (DARK_THEMES.includes(currentFlavor)) {
|
|
124
|
+
root.classList.add("dark");
|
|
125
|
+
} else {
|
|
126
|
+
root.classList.remove("dark");
|
|
127
|
+
}
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
updateFlavorUI();
|
|
131
|
+
renderAccents();
|
|
132
|
+
};
|
|
133
|
+
if (window.basecoat) {
|
|
134
|
+
window.basecoat.register("catppuccin-theme-switcher", ".catppuccin-theme-switcher", init);
|
|
135
|
+
}
|
|
136
|
+
})();
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
(() => {
|
|
2
|
+
const l = ["latte", "frappe", "macchiato", "mocha"], d = ["frappe", "macchiato", "mocha"], i = [
|
|
3
|
+
"rosewater",
|
|
4
|
+
"flamingo",
|
|
5
|
+
"pink",
|
|
6
|
+
"mauve",
|
|
7
|
+
"red",
|
|
8
|
+
"maroon",
|
|
9
|
+
"peach",
|
|
10
|
+
"yellow",
|
|
11
|
+
"green",
|
|
12
|
+
"teal",
|
|
13
|
+
"sky",
|
|
14
|
+
"sapphire",
|
|
15
|
+
"blue",
|
|
16
|
+
"lavender"
|
|
17
|
+
];
|
|
18
|
+
function f(c) {
|
|
19
|
+
if (!l.includes(c)) return {};
|
|
20
|
+
const t = { background: `var(--ctp-${c}-base)` };
|
|
21
|
+
return i.forEach((o) => {
|
|
22
|
+
t[o] = `var(--ctp-${c}-${o})`;
|
|
23
|
+
}), t;
|
|
24
|
+
}
|
|
25
|
+
function u(c, t) {
|
|
26
|
+
const o = document.documentElement;
|
|
27
|
+
l.forEach((s) => o.classList.remove(`theme-${s}`)), i.forEach((s) => o.classList.remove(`accent-${s}`)), o.classList.add(`theme-${c}`), o.classList.add(`accent-${t}`), d.includes(c) ? o.classList.add("dark") : o.classList.remove("dark");
|
|
28
|
+
try {
|
|
29
|
+
localStorage.setItem("catppuccin-theme", c), localStorage.setItem("catppuccin-accent", t);
|
|
30
|
+
} catch {
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
function h() {
|
|
34
|
+
try {
|
|
35
|
+
const c = localStorage.getItem("catppuccin-theme"), t = localStorage.getItem("catppuccin-accent");
|
|
36
|
+
c && t && u(c, t);
|
|
37
|
+
} catch {
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
h();
|
|
41
|
+
const v = (c) => {
|
|
42
|
+
const t = c.querySelector(".theme-flavors"), o = c.querySelector(".theme-accents"), s = c.querySelector(".theme-reset");
|
|
43
|
+
let n = localStorage.getItem("catppuccin-theme") || "latte";
|
|
44
|
+
l.includes(n) || (n = "latte"), t && (t.innerHTML = "", t.className = "button-group w-full", l.forEach((a) => {
|
|
45
|
+
const e = document.createElement("button");
|
|
46
|
+
e.type = "button", e.className = "btn btn-sm capitalize flex-1", e.textContent = a, e.dataset.flavor = a, t.appendChild(e);
|
|
47
|
+
}));
|
|
48
|
+
const m = () => {
|
|
49
|
+
if (!t) return;
|
|
50
|
+
t.querySelectorAll("[data-flavor]").forEach((e) => {
|
|
51
|
+
e.dataset.flavor === n ? (e.classList.remove("btn-outline", "btn-ghost"), e.classList.add("btn-primary")) : (e.classList.remove("btn-primary"), e.classList.add("btn-ghost"));
|
|
52
|
+
});
|
|
53
|
+
}, p = () => {
|
|
54
|
+
if (!o) return;
|
|
55
|
+
o.innerHTML = "";
|
|
56
|
+
const a = f(n);
|
|
57
|
+
o.className = "theme-accents grid grid-cols-7 gap-3 place-items-center p-4 rounded-xl border border-border/50 mt-4 transition-colors duration-300", o.style.backgroundColor = a.background, i.forEach((e) => {
|
|
58
|
+
const r = document.createElement("button");
|
|
59
|
+
r.type = "button", r.className = "size-6 rounded-full border border-border/20 shadow-sm transition-transform hover:scale-110 focus:outline-none focus:ring-2 focus:ring-ring", r.title = e, r.style.backgroundColor = a[e], r.dataset.tooltip = e, r.dataset.side = "top", r.onclick = () => {
|
|
60
|
+
u(n, e);
|
|
61
|
+
}, o.appendChild(r);
|
|
62
|
+
});
|
|
63
|
+
};
|
|
64
|
+
t && t.addEventListener("click", (a) => {
|
|
65
|
+
const e = a.target.closest("[data-flavor]");
|
|
66
|
+
e && (n = e.dataset.flavor, m(), p());
|
|
67
|
+
}), s && s.addEventListener("click", () => {
|
|
68
|
+
const a = document.documentElement;
|
|
69
|
+
l.forEach((e) => a.classList.remove(`theme-${e}`)), i.forEach((e) => a.classList.remove(`accent-${e}`)), localStorage.removeItem("catppuccin-theme"), localStorage.removeItem("catppuccin-accent"), d.includes(n) ? a.classList.add("dark") : a.classList.remove("dark");
|
|
70
|
+
}), m(), p();
|
|
71
|
+
};
|
|
72
|
+
window.basecoat && window.basecoat.register("catppuccin-theme-switcher", ".catppuccin-theme-switcher", v);
|
|
73
|
+
})();
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
(() => {
|
|
2
|
+
const initCommand = (container) => {
|
|
3
|
+
const input = container.querySelector("header input");
|
|
4
|
+
const menu = container.querySelector('[role="menu"]');
|
|
5
|
+
if (!input || !menu) {
|
|
6
|
+
const missing = [];
|
|
7
|
+
if (!input) missing.push("input");
|
|
8
|
+
if (!menu) missing.push("menu");
|
|
9
|
+
console.error(`Command component initialization failed. Missing element(s): ${missing.join(", ")}`, container);
|
|
10
|
+
return;
|
|
11
|
+
}
|
|
12
|
+
const allMenuItems = Array.from(menu.querySelectorAll('[role="menuitem"]'));
|
|
13
|
+
const menuItems = allMenuItems.filter(
|
|
14
|
+
(item) => !item.hasAttribute("disabled") && item.getAttribute("aria-disabled") !== "true"
|
|
15
|
+
);
|
|
16
|
+
let visibleMenuItems = [...menuItems];
|
|
17
|
+
let activeIndex = -1;
|
|
18
|
+
const setActiveItem = (index) => {
|
|
19
|
+
if (activeIndex > -1 && menuItems[activeIndex]) {
|
|
20
|
+
menuItems[activeIndex].classList.remove("active");
|
|
21
|
+
}
|
|
22
|
+
activeIndex = index;
|
|
23
|
+
if (activeIndex > -1) {
|
|
24
|
+
const activeItem = menuItems[activeIndex];
|
|
25
|
+
activeItem.classList.add("active");
|
|
26
|
+
if (activeItem.id) {
|
|
27
|
+
input.setAttribute("aria-activedescendant", activeItem.id);
|
|
28
|
+
} else {
|
|
29
|
+
input.removeAttribute("aria-activedescendant");
|
|
30
|
+
}
|
|
31
|
+
} else {
|
|
32
|
+
input.removeAttribute("aria-activedescendant");
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
const filterMenuItems = () => {
|
|
36
|
+
const searchTerm = input.value.trim().toLowerCase();
|
|
37
|
+
setActiveItem(-1);
|
|
38
|
+
visibleMenuItems = [];
|
|
39
|
+
allMenuItems.forEach((item) => {
|
|
40
|
+
if (item.hasAttribute("data-force")) {
|
|
41
|
+
item.setAttribute("aria-hidden", "false");
|
|
42
|
+
if (menuItems.includes(item)) {
|
|
43
|
+
visibleMenuItems.push(item);
|
|
44
|
+
}
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
const itemText = (item.dataset.filter || item.textContent).trim().toLowerCase();
|
|
48
|
+
const keywordList = (item.dataset.keywords || "").toLowerCase().split(/[\s,]+/).filter(Boolean);
|
|
49
|
+
const matchesKeyword = keywordList.some((keyword) => keyword.includes(searchTerm));
|
|
50
|
+
const matches = itemText.includes(searchTerm) || matchesKeyword;
|
|
51
|
+
item.setAttribute("aria-hidden", String(!matches));
|
|
52
|
+
if (matches && menuItems.includes(item)) {
|
|
53
|
+
visibleMenuItems.push(item);
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
if (visibleMenuItems.length > 0) {
|
|
57
|
+
setActiveItem(menuItems.indexOf(visibleMenuItems[0]));
|
|
58
|
+
visibleMenuItems[0].scrollIntoView({ block: "nearest" });
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
input.addEventListener("input", filterMenuItems);
|
|
62
|
+
const handleKeyNavigation = (event) => {
|
|
63
|
+
if (!["ArrowDown", "ArrowUp", "Enter", "Home", "End"].includes(event.key)) {
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
if (event.key === "Enter") {
|
|
67
|
+
event.preventDefault();
|
|
68
|
+
if (activeIndex > -1) {
|
|
69
|
+
menuItems[activeIndex]?.click();
|
|
70
|
+
}
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
if (visibleMenuItems.length === 0) return;
|
|
74
|
+
event.preventDefault();
|
|
75
|
+
const currentVisibleIndex = activeIndex > -1 ? visibleMenuItems.indexOf(menuItems[activeIndex]) : -1;
|
|
76
|
+
let nextVisibleIndex = currentVisibleIndex;
|
|
77
|
+
switch (event.key) {
|
|
78
|
+
case "ArrowDown":
|
|
79
|
+
if (currentVisibleIndex < visibleMenuItems.length - 1) {
|
|
80
|
+
nextVisibleIndex = currentVisibleIndex + 1;
|
|
81
|
+
}
|
|
82
|
+
break;
|
|
83
|
+
case "ArrowUp":
|
|
84
|
+
if (currentVisibleIndex > 0) {
|
|
85
|
+
nextVisibleIndex = currentVisibleIndex - 1;
|
|
86
|
+
} else if (currentVisibleIndex === -1) {
|
|
87
|
+
nextVisibleIndex = 0;
|
|
88
|
+
}
|
|
89
|
+
break;
|
|
90
|
+
case "Home":
|
|
91
|
+
nextVisibleIndex = 0;
|
|
92
|
+
break;
|
|
93
|
+
case "End":
|
|
94
|
+
nextVisibleIndex = visibleMenuItems.length - 1;
|
|
95
|
+
break;
|
|
96
|
+
}
|
|
97
|
+
if (nextVisibleIndex !== currentVisibleIndex) {
|
|
98
|
+
const newActiveItem = visibleMenuItems[nextVisibleIndex];
|
|
99
|
+
setActiveItem(menuItems.indexOf(newActiveItem));
|
|
100
|
+
newActiveItem.scrollIntoView({ block: "nearest", behavior: "smooth" });
|
|
101
|
+
}
|
|
102
|
+
};
|
|
103
|
+
menu.addEventListener("mousemove", (event) => {
|
|
104
|
+
const menuItem = event.target.closest('[role="menuitem"]');
|
|
105
|
+
if (menuItem && visibleMenuItems.includes(menuItem)) {
|
|
106
|
+
const index = menuItems.indexOf(menuItem);
|
|
107
|
+
if (index !== activeIndex) {
|
|
108
|
+
setActiveItem(index);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
});
|
|
112
|
+
menu.addEventListener("click", (event) => {
|
|
113
|
+
const clickedItem = event.target.closest('[role="menuitem"]');
|
|
114
|
+
if (clickedItem && visibleMenuItems.includes(clickedItem)) {
|
|
115
|
+
const dialog = container.closest("dialog.command-dialog");
|
|
116
|
+
if (dialog && !clickedItem.hasAttribute("data-keep-command-open")) {
|
|
117
|
+
dialog.close();
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
});
|
|
121
|
+
input.addEventListener("keydown", handleKeyNavigation);
|
|
122
|
+
if (visibleMenuItems.length > 0) {
|
|
123
|
+
setActiveItem(menuItems.indexOf(visibleMenuItems[0]));
|
|
124
|
+
visibleMenuItems[0].scrollIntoView({ block: "nearest" });
|
|
125
|
+
}
|
|
126
|
+
container.dataset.commandInitialized = true;
|
|
127
|
+
container.dispatchEvent(new CustomEvent("basecoat:initialized"));
|
|
128
|
+
};
|
|
129
|
+
if (window.basecoat) {
|
|
130
|
+
window.basecoat.register("command", ".command:not([data-command-initialized])", initCommand);
|
|
131
|
+
}
|
|
132
|
+
})();
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
(() => {
|
|
2
|
+
const f = (r) => {
|
|
3
|
+
const o = r.querySelector("header input"), c = r.querySelector('[role="menu"]');
|
|
4
|
+
if (!o || !c) {
|
|
5
|
+
const t = [];
|
|
6
|
+
o || t.push("input"), c || t.push("menu"), console.error(`Command component initialization failed. Missing element(s): ${t.join(", ")}`, r);
|
|
7
|
+
return;
|
|
8
|
+
}
|
|
9
|
+
const u = Array.from(c.querySelectorAll('[role="menuitem"]')), s = u.filter(
|
|
10
|
+
(t) => !t.hasAttribute("disabled") && t.getAttribute("aria-disabled") !== "true"
|
|
11
|
+
);
|
|
12
|
+
let i = [...s], a = -1;
|
|
13
|
+
const d = (t) => {
|
|
14
|
+
if (a > -1 && s[a] && s[a].classList.remove("active"), a = t, a > -1) {
|
|
15
|
+
const e = s[a];
|
|
16
|
+
e.classList.add("active"), e.id ? o.setAttribute("aria-activedescendant", e.id) : o.removeAttribute("aria-activedescendant");
|
|
17
|
+
} else
|
|
18
|
+
o.removeAttribute("aria-activedescendant");
|
|
19
|
+
}, b = () => {
|
|
20
|
+
const t = o.value.trim().toLowerCase();
|
|
21
|
+
d(-1), i = [], u.forEach((e) => {
|
|
22
|
+
if (e.hasAttribute("data-force")) {
|
|
23
|
+
e.setAttribute("aria-hidden", "false"), s.includes(e) && i.push(e);
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
const n = (e.dataset.filter || e.textContent).trim().toLowerCase(), w = (e.dataset.keywords || "").toLowerCase().split(/[\s,]+/).filter(Boolean).some((v) => v.includes(t)), m = n.includes(t) || w;
|
|
27
|
+
e.setAttribute("aria-hidden", String(!m)), m && s.includes(e) && i.push(e);
|
|
28
|
+
}), i.length > 0 && (d(s.indexOf(i[0])), i[0].scrollIntoView({ block: "nearest" }));
|
|
29
|
+
};
|
|
30
|
+
o.addEventListener("input", b);
|
|
31
|
+
const h = (t) => {
|
|
32
|
+
if (!["ArrowDown", "ArrowUp", "Enter", "Home", "End"].includes(t.key))
|
|
33
|
+
return;
|
|
34
|
+
if (t.key === "Enter") {
|
|
35
|
+
t.preventDefault(), a > -1 && s[a]?.click();
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
if (i.length === 0) return;
|
|
39
|
+
t.preventDefault();
|
|
40
|
+
const e = a > -1 ? i.indexOf(s[a]) : -1;
|
|
41
|
+
let n = e;
|
|
42
|
+
switch (t.key) {
|
|
43
|
+
case "ArrowDown":
|
|
44
|
+
e < i.length - 1 && (n = e + 1);
|
|
45
|
+
break;
|
|
46
|
+
case "ArrowUp":
|
|
47
|
+
e > 0 ? n = e - 1 : e === -1 && (n = 0);
|
|
48
|
+
break;
|
|
49
|
+
case "Home":
|
|
50
|
+
n = 0;
|
|
51
|
+
break;
|
|
52
|
+
case "End":
|
|
53
|
+
n = i.length - 1;
|
|
54
|
+
break;
|
|
55
|
+
}
|
|
56
|
+
if (n !== e) {
|
|
57
|
+
const l = i[n];
|
|
58
|
+
d(s.indexOf(l)), l.scrollIntoView({ block: "nearest", behavior: "smooth" });
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
c.addEventListener("mousemove", (t) => {
|
|
62
|
+
const e = t.target.closest('[role="menuitem"]');
|
|
63
|
+
if (e && i.includes(e)) {
|
|
64
|
+
const n = s.indexOf(e);
|
|
65
|
+
n !== a && d(n);
|
|
66
|
+
}
|
|
67
|
+
}), c.addEventListener("click", (t) => {
|
|
68
|
+
const e = t.target.closest('[role="menuitem"]');
|
|
69
|
+
if (e && i.includes(e)) {
|
|
70
|
+
const n = r.closest("dialog.command-dialog");
|
|
71
|
+
n && !e.hasAttribute("data-keep-command-open") && n.close();
|
|
72
|
+
}
|
|
73
|
+
}), o.addEventListener("keydown", h), i.length > 0 && (d(s.indexOf(i[0])), i[0].scrollIntoView({ block: "nearest" })), r.dataset.commandInitialized = !0, r.dispatchEvent(new CustomEvent("basecoat:initialized"));
|
|
74
|
+
};
|
|
75
|
+
window.basecoat && window.basecoat.register("command", ".command:not([data-command-initialized])", f);
|
|
76
|
+
})();
|