@lanrenbang/basecoat-ultra 0.1.6 → 0.2.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/{LICENSE → LICENSE.md} +2 -2
- package/README.md +77 -144
- package/dist/css/basecoat.cdn.css +134 -1726
- package/dist/css/basecoat.cdn.min.css +1 -1
- package/dist/css/basecoat.css +34 -24
- package/dist/css/datepicker.css +277 -1080
- package/dist/css/datepicker.min.css +2 -1
- package/dist/css/resizable.css +39 -60
- package/dist/css/resizable.min.css +1 -1
- package/dist/js/all.js +1 -0
- package/dist/js/all.min.js +1 -0
- package/dist/js/basecoat.js +6 -4
- package/dist/js/basecoat.min.js +12 -12
- package/dist/js/carousel.js +8 -0
- package/dist/js/carousel.min.js +24 -17
- package/dist/js/catppuccin-theme-switcher.js +41 -6
- package/dist/js/catppuccin-theme-switcher.min.js +62 -47
- package/dist/js/datepicker.js +211 -46
- package/dist/js/datepicker.min.js +566 -423
- package/dist/js/input-otp.js +69 -79
- package/dist/js/input-otp.min.js +30 -35
- package/dist/js/pagination.js +107 -0
- package/dist/js/pagination.min.js +43 -0
- package/dist/js/resizable.js +35 -46
- package/dist/js/resizable.min.js +180 -182
- package/dist/js/sheet.js +28 -26
- package/dist/js/sheet.min.js +34 -34
- package/dist/js/toast.js +17 -35
- package/dist/js/toast.min.js +35 -56
- package/dist/js/toggle.js +5 -0
- package/dist/js/toggle.min.js +15 -10
- package/package.json +28 -13
- package/CHANGELOG-cn.md +0 -54
- package/CHANGELOG.md +0 -54
- package/README-cn.md +0 -199
package/dist/js/toast.js
CHANGED
|
@@ -83,48 +83,30 @@
|
|
|
83
83
|
element.addEventListener("transitionend", () => element.remove(), { once: true });
|
|
84
84
|
}
|
|
85
85
|
function createToast(config) {
|
|
86
|
-
const {
|
|
87
|
-
category = "info",
|
|
88
|
-
title,
|
|
89
|
-
description,
|
|
90
|
-
action,
|
|
91
|
-
cancel,
|
|
92
|
-
duration,
|
|
93
|
-
icon
|
|
94
|
-
} = config;
|
|
86
|
+
const { category = "info", title, description, action, cancel, duration, icon } = config;
|
|
95
87
|
const iconHtml = icon || category && ICONS[category] || "";
|
|
96
|
-
const titleHtml = title ?
|
|
97
|
-
const descriptionHtml = description ?
|
|
98
|
-
const actionHtml = action?.href ?
|
|
99
|
-
const cancelHtml = cancel ?
|
|
100
|
-
const footerHtml = actionHtml || cancelHtml ?
|
|
101
|
-
const html =
|
|
102
|
-
<div
|
|
103
|
-
class="toast"
|
|
104
|
-
role="${category === "error" ? "alert" : "status"}"
|
|
105
|
-
aria-atomic="true"
|
|
106
|
-
${category ? `data-category="${category}"` : ""}
|
|
107
|
-
${duration !== void 0 ? `data-duration="${duration}"` : ""}
|
|
108
|
-
>
|
|
109
|
-
<div class="toast-content">
|
|
110
|
-
${iconHtml}
|
|
111
|
-
<section>
|
|
112
|
-
${titleHtml}
|
|
113
|
-
${descriptionHtml}
|
|
114
|
-
</section>
|
|
115
|
-
${footerHtml}
|
|
116
|
-
</div>
|
|
117
|
-
</div>
|
|
118
|
-
</div>
|
|
119
|
-
`;
|
|
88
|
+
const titleHtml = title ? "<h2>" + title + "</h2>" : "";
|
|
89
|
+
const descriptionHtml = description ? "<p>" + description + "</p>" : "";
|
|
90
|
+
const actionHtml = action?.href ? '<a href="' + action.href + '" class="btn" data-toast-action>' + action.label + "</a>" : action?.onclick ? '<button type="button" class="btn" data-toast-action onclick="' + action.onclick + '">' + action.label + "</button>" : "";
|
|
91
|
+
const cancelHtml = cancel ? '<button type="button" class="btn-outline h-6 text-xs px-2.5 rounded-sm" data-toast-cancel onclick="' + (cancel?.onclick || "") + '">' + cancel.label + "</button>" : "";
|
|
92
|
+
const footerHtml = actionHtml || cancelHtml ? "<footer>" + actionHtml + cancelHtml + "</footer>" : "";
|
|
93
|
+
const html = '<div class="toast" role="' + (category === "error" ? "alert" : "status") + '" aria-atomic="true"' + (category ? ' data-category="' + category + '"' : "") + (duration !== void 0 ? ' data-duration="' + duration + '"' : "") + '><div class="toast-content">' + iconHtml + "<section>" + titleHtml + descriptionHtml + "</section>" + footerHtml + "</div></div>";
|
|
120
94
|
const template = document.createElement("template");
|
|
121
95
|
template.innerHTML = html.trim();
|
|
122
96
|
return template.content.firstChild;
|
|
123
97
|
}
|
|
124
98
|
document.addEventListener("basecoat:toast", (event) => {
|
|
125
99
|
if (!toaster) {
|
|
126
|
-
|
|
127
|
-
|
|
100
|
+
const existingToaster = document.getElementById("toaster") || document.querySelector(".toaster");
|
|
101
|
+
if (existingToaster) {
|
|
102
|
+
initToaster(existingToaster);
|
|
103
|
+
} else {
|
|
104
|
+
const newToaster = document.createElement("section");
|
|
105
|
+
newToaster.id = "toaster";
|
|
106
|
+
newToaster.className = "toaster";
|
|
107
|
+
document.body.appendChild(newToaster);
|
|
108
|
+
initToaster(newToaster);
|
|
109
|
+
}
|
|
128
110
|
}
|
|
129
111
|
const config = event.detail?.config || {};
|
|
130
112
|
const toastElement = createToast(config);
|
package/dist/js/toast.min.js
CHANGED
|
@@ -1,83 +1,62 @@
|
|
|
1
1
|
(() => {
|
|
2
|
-
let
|
|
3
|
-
const
|
|
4
|
-
let
|
|
5
|
-
const
|
|
2
|
+
let i;
|
|
3
|
+
const s = /* @__PURE__ */ new WeakMap();
|
|
4
|
+
let r = !1;
|
|
5
|
+
const w = {
|
|
6
6
|
success: '<svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><path d="m9 12 2 2 4-4"/></svg>',
|
|
7
7
|
error: '<svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><path d="m15 9-6 6"/><path d="m9 9 6 6"/></svg>',
|
|
8
8
|
info: '<svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><path d="M12 16v-4"/><path d="M12 8h.01"/></svg>',
|
|
9
9
|
warning: '<svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3"/><path d="M12 9v4"/><path d="M12 17h.01"/></svg>'
|
|
10
10
|
};
|
|
11
|
-
function
|
|
12
|
-
t.dataset.toasterInitialized || (
|
|
13
|
-
const
|
|
14
|
-
(
|
|
15
|
-
}),
|
|
11
|
+
function d(t) {
|
|
12
|
+
t.dataset.toasterInitialized || (i = t, i.addEventListener("mouseenter", p), i.addEventListener("mouseleave", v), i.addEventListener("click", (e) => {
|
|
13
|
+
const n = e.target.closest(".toast footer a"), o = e.target.closest(".toast footer button");
|
|
14
|
+
(n || o) && c(e.target.closest(".toast"));
|
|
15
|
+
}), i.querySelectorAll(".toast:not([data-toast-initialized])").forEach(u), i.dataset.toasterInitialized = "true", i.dispatchEvent(new CustomEvent("basecoat:initialized")));
|
|
16
16
|
}
|
|
17
|
-
function
|
|
17
|
+
function u(t) {
|
|
18
18
|
if (t.dataset.toastInitialized) return;
|
|
19
|
-
const e = parseInt(t.dataset.duration),
|
|
20
|
-
remainingTime:
|
|
19
|
+
const e = parseInt(t.dataset.duration), n = e !== -1 ? e || (t.dataset.category === "error" ? 5e3 : 3e3) : -1, o = {
|
|
20
|
+
remainingTime: n,
|
|
21
21
|
timeoutId: null,
|
|
22
22
|
startTime: null
|
|
23
23
|
};
|
|
24
|
-
|
|
24
|
+
n !== -1 && (r ? o.timeoutId = null : (o.startTime = Date.now(), o.timeoutId = setTimeout(() => c(t), n))), s.set(t, o), t.dataset.toastInitialized = "true";
|
|
25
25
|
}
|
|
26
26
|
function p() {
|
|
27
|
-
|
|
28
|
-
if (!
|
|
29
|
-
const e =
|
|
27
|
+
r || (r = !0, i.querySelectorAll('.toast:not([aria-hidden="true"])').forEach((t) => {
|
|
28
|
+
if (!s.has(t)) return;
|
|
29
|
+
const e = s.get(t);
|
|
30
30
|
e.timeoutId && (clearTimeout(e.timeoutId), e.timeoutId = null, e.remainingTime -= Date.now() - e.startTime);
|
|
31
31
|
}));
|
|
32
32
|
}
|
|
33
33
|
function v() {
|
|
34
|
-
|
|
35
|
-
if (!
|
|
36
|
-
const e =
|
|
34
|
+
r && (r = !1, i.querySelectorAll('.toast:not([aria-hidden="true"])').forEach((t) => {
|
|
35
|
+
if (!s.has(t)) return;
|
|
36
|
+
const e = s.get(t);
|
|
37
37
|
e.remainingTime !== -1 && !e.timeoutId && (e.remainingTime > 0 ? (e.startTime = Date.now(), e.timeoutId = setTimeout(() => c(t), e.remainingTime)) : c(t));
|
|
38
38
|
}));
|
|
39
39
|
}
|
|
40
40
|
function c(t) {
|
|
41
|
-
if (!
|
|
42
|
-
const e =
|
|
43
|
-
clearTimeout(e.timeoutId),
|
|
41
|
+
if (!s.has(t)) return;
|
|
42
|
+
const e = s.get(t);
|
|
43
|
+
clearTimeout(e.timeoutId), s.delete(t), t.contains(document.activeElement) && document.activeElement.blur(), t.setAttribute("aria-hidden", "true"), t.addEventListener("transitionend", () => t.remove(), { once: !0 });
|
|
44
44
|
}
|
|
45
45
|
function k(t) {
|
|
46
|
-
const {
|
|
47
|
-
|
|
48
|
-
title: i,
|
|
49
|
-
description: a,
|
|
50
|
-
action: r,
|
|
51
|
-
cancel: d,
|
|
52
|
-
duration: u,
|
|
53
|
-
icon: b
|
|
54
|
-
} = t, T = b || e && g[e] || "", $ = i ? `<h2>${i}</h2>` : "", I = a ? `<p>${a}</p>` : "", h = r?.href ? `<a href="${r.href}" class="btn" data-toast-action>${r.label}</a>` : r?.onclick ? `<button type="button" class="btn" data-toast-action onclick="${r.onclick}">${r.label}</button>` : "", m = d ? `<button type="button" class="btn-outline h-6 text-xs px-2.5 rounded-sm" data-toast-cancel onclick="${d?.onclick}">${d.label}</button>` : "", x = h || m ? `<footer>${h}${m}</footer>` : "", E = `
|
|
55
|
-
<div
|
|
56
|
-
class="toast"
|
|
57
|
-
role="${e === "error" ? "alert" : "status"}"
|
|
58
|
-
aria-atomic="true"
|
|
59
|
-
${e ? `data-category="${e}"` : ""}
|
|
60
|
-
${u !== void 0 ? `data-duration="${u}"` : ""}
|
|
61
|
-
>
|
|
62
|
-
<div class="toast-content">
|
|
63
|
-
${T}
|
|
64
|
-
<section>
|
|
65
|
-
${$}
|
|
66
|
-
${I}
|
|
67
|
-
</section>
|
|
68
|
-
${x}
|
|
69
|
-
</div>
|
|
70
|
-
</div>
|
|
71
|
-
</div>
|
|
72
|
-
`, f = document.createElement("template");
|
|
73
|
-
return f.innerHTML = E.trim(), f.content.firstChild;
|
|
46
|
+
const { category: e = "info", title: n, description: o, action: a, cancel: l, duration: h, icon: T } = t, b = T || e && w[e] || "", I = n ? "<h2>" + n + "</h2>" : "", x = o ? "<p>" + o + "</p>" : "", m = a?.href ? '<a href="' + a.href + '" class="btn" data-toast-action>' + a.label + "</a>" : a?.onclick ? '<button type="button" class="btn" data-toast-action onclick="' + a.onclick + '">' + a.label + "</button>" : "", f = l ? '<button type="button" class="btn-outline h-6 text-xs px-2.5 rounded-sm" data-toast-cancel onclick="' + (l?.onclick || "") + '">' + l.label + "</button>" : "", E = m || f ? "<footer>" + m + f + "</footer>" : "", y = '<div class="toast" role="' + (e === "error" ? "alert" : "status") + '" aria-atomic="true"' + (e ? ' data-category="' + e + '"' : "") + (h !== void 0 ? ' data-duration="' + h + '"' : "") + '><div class="toast-content">' + b + "<section>" + I + x + "</section>" + E + "</div></div>", g = document.createElement("template");
|
|
47
|
+
return g.innerHTML = y.trim(), g.content.firstChild;
|
|
74
48
|
}
|
|
75
49
|
document.addEventListener("basecoat:toast", (t) => {
|
|
76
|
-
if (!
|
|
77
|
-
|
|
78
|
-
|
|
50
|
+
if (!i) {
|
|
51
|
+
const o = document.getElementById("toaster") || document.querySelector(".toaster");
|
|
52
|
+
if (o)
|
|
53
|
+
d(o);
|
|
54
|
+
else {
|
|
55
|
+
const a = document.createElement("section");
|
|
56
|
+
a.id = "toaster", a.className = "toaster", document.body.appendChild(a), d(a);
|
|
57
|
+
}
|
|
79
58
|
}
|
|
80
|
-
const e = t.detail?.config || {},
|
|
81
|
-
|
|
82
|
-
}), window.basecoat && (window.basecoat.register("toaster", "#toaster:not([data-toaster-initialized])",
|
|
59
|
+
const e = t.detail?.config || {}, n = k(e);
|
|
60
|
+
i.appendChild(n);
|
|
61
|
+
}), window.basecoat && (window.basecoat.register("toaster", "#toaster:not([data-toaster-initialized])", d), window.basecoat.register("toast", ".toast:not([data-toast-initialized])", u));
|
|
83
62
|
})();
|
package/dist/js/toggle.js
CHANGED
|
@@ -26,6 +26,11 @@
|
|
|
26
26
|
} else {
|
|
27
27
|
toggle.setAttribute("aria-pressed", !isPressed);
|
|
28
28
|
}
|
|
29
|
+
const selected = Array.from(group.querySelectorAll('.toggle[aria-pressed="true"]')).map((t) => t.dataset.value || t.innerText.trim());
|
|
30
|
+
group.dispatchEvent(new CustomEvent("change", {
|
|
31
|
+
bubbles: true,
|
|
32
|
+
detail: { value: type === "single" ? selected[0] || null : selected }
|
|
33
|
+
}));
|
|
29
34
|
});
|
|
30
35
|
group.dataset.toggleGroupInitialized = true;
|
|
31
36
|
};
|
package/dist/js/toggle.min.js
CHANGED
|
@@ -2,19 +2,24 @@
|
|
|
2
2
|
const d = (e) => {
|
|
3
3
|
e.addEventListener("click", (s) => {
|
|
4
4
|
if (e.disabled || e.getAttribute("aria-disabled") === "true") return;
|
|
5
|
-
const
|
|
6
|
-
e.setAttribute("aria-pressed", !
|
|
5
|
+
const r = e.getAttribute("aria-pressed") === "true";
|
|
6
|
+
e.setAttribute("aria-pressed", !r);
|
|
7
7
|
}), e.dataset.toggleInitialized = !0;
|
|
8
|
-
},
|
|
8
|
+
}, n = (e) => {
|
|
9
9
|
const s = e.dataset.type || "single";
|
|
10
|
-
e.addEventListener("click", (
|
|
11
|
-
const t =
|
|
10
|
+
e.addEventListener("click", (r) => {
|
|
11
|
+
const t = r.target.closest(".toggle");
|
|
12
12
|
if (!t || !e.contains(t) || t.disabled || t.getAttribute("aria-disabled") === "true") return;
|
|
13
|
-
const
|
|
14
|
-
s === "single" ?
|
|
15
|
-
|
|
16
|
-
}), t.setAttribute("aria-pressed", "true")) : t.setAttribute("aria-pressed", !
|
|
13
|
+
const a = t.getAttribute("aria-pressed") === "true";
|
|
14
|
+
s === "single" ? a ? t.setAttribute("aria-pressed", "false") : (e.querySelectorAll(".toggle").forEach((i) => {
|
|
15
|
+
i !== t && i.setAttribute("aria-pressed", "false");
|
|
16
|
+
}), t.setAttribute("aria-pressed", "true")) : t.setAttribute("aria-pressed", !a);
|
|
17
|
+
const l = Array.from(e.querySelectorAll('.toggle[aria-pressed="true"]')).map((i) => i.dataset.value || i.innerText.trim());
|
|
18
|
+
e.dispatchEvent(new CustomEvent("change", {
|
|
19
|
+
bubbles: !0,
|
|
20
|
+
detail: { value: s === "single" ? l[0] || null : l }
|
|
21
|
+
}));
|
|
17
22
|
}), e.dataset.toggleGroupInitialized = !0;
|
|
18
23
|
};
|
|
19
|
-
window.basecoat && (window.basecoat.register("toggle", ".toggle:not(.toggle-group .toggle):not([data-toggle-initialized])", d), window.basecoat.register("toggle-group", ".toggle-group:not([data-toggle-group-initialized])",
|
|
24
|
+
window.basecoat && (window.basecoat.register("toggle", ".toggle:not(.toggle-group .toggle):not([data-toggle-initialized])", d), window.basecoat.register("toggle-group", ".toggle-group:not([data-toggle-group-initialized])", n));
|
|
20
25
|
})();
|
package/package.json
CHANGED
|
@@ -1,16 +1,33 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lanrenbang/basecoat-ultra",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Basecoat UI - Ultra edition. A Tailwind-first component library.",
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "Basecoat UI - Ultra edition. A Tailwind-first component library for any web stack.",
|
|
5
5
|
"type": "module",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"author": "Lanrenbang",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "git+https://github.com/Lanrenbang/basecoat-ultra.git",
|
|
11
|
+
"directory": "packages/ultra"
|
|
12
|
+
},
|
|
13
|
+
"homepage": "https://lanrenbang.github.io/basecoat-ultra",
|
|
14
|
+
"bugs": {
|
|
15
|
+
"url": "https://github.com/Lanrenbang/basecoat-ultra/issues"
|
|
16
|
+
},
|
|
17
|
+
"keywords": [
|
|
18
|
+
"tailwind",
|
|
19
|
+
"ui",
|
|
20
|
+
"components",
|
|
21
|
+
"css",
|
|
22
|
+
"basecoat",
|
|
23
|
+
"shadcn",
|
|
24
|
+
"catppuccin"
|
|
25
|
+
],
|
|
6
26
|
"main": "./dist/js/all.js",
|
|
7
27
|
"style": "./dist/css/basecoat.css",
|
|
8
28
|
"files": [
|
|
9
29
|
"dist",
|
|
10
30
|
"README.md",
|
|
11
|
-
"README-cn.md",
|
|
12
|
-
"CHANGELOG.md",
|
|
13
|
-
"CHANGELOG-cn.md",
|
|
14
31
|
"LICENSE.md"
|
|
15
32
|
],
|
|
16
33
|
"exports": {
|
|
@@ -39,23 +56,21 @@
|
|
|
39
56
|
"./slider": "./dist/js/slider.js",
|
|
40
57
|
"./tabs": "./dist/js/tabs.js",
|
|
41
58
|
"./toast": "./dist/js/toast.js",
|
|
42
|
-
"./toggle": "./dist/js/toggle.js"
|
|
59
|
+
"./toggle": "./dist/js/toggle.js",
|
|
60
|
+
"./utils/*": "./dist/js/utils/*.js"
|
|
43
61
|
},
|
|
44
62
|
"scripts": {
|
|
45
|
-
"dev": "vite",
|
|
46
63
|
"build": "vite build && vite build --mode minify && bun run build.ts",
|
|
47
|
-
"
|
|
48
|
-
"
|
|
49
|
-
"
|
|
50
|
-
"
|
|
51
|
-
"check": "bun run build.ts check"
|
|
64
|
+
"upstream:diff": "bun run scripts/upstream-diff.ts analyze",
|
|
65
|
+
"upstream:sync": "bun run scripts/upstream-diff.ts sync",
|
|
66
|
+
"upstream:css": "bun run scripts/upstream-diff.ts css",
|
|
67
|
+
"upstream:js": "bun run scripts/upstream-diff.ts js"
|
|
52
68
|
},
|
|
53
69
|
"dependencies": {
|
|
54
70
|
"flatpickr": "^4.6.13",
|
|
55
71
|
"split.js": "^1.6.5"
|
|
56
72
|
},
|
|
57
73
|
"devDependencies": {
|
|
58
|
-
"@lanrenbang/basecoat-ultra": "^0.1.5",
|
|
59
74
|
"@tailwindcss/cli": "^4.1.18",
|
|
60
75
|
"@tailwindcss/vite": "^4.1.18",
|
|
61
76
|
"@types/bun": "latest",
|
package/CHANGELOG-cn.md
DELETED
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
# Basecoat Ultra 更新日志 (Changelog)
|
|
2
|
-
|
|
3
|
-
[English](./CHANGELOG.md) | **中文**
|
|
4
|
-
|
|
5
|
-
本文档记录了 `basecoat-ultra` 相对于上游 Basecoat 的所有主要变更。
|
|
6
|
-
|
|
7
|
-
## 🚀 核心架构与构建 (Architecture & Build)
|
|
8
|
-
|
|
9
|
-
* **模块化重构**: 将原版单体 `basecoat.css` 拆分为 `src/css/parts/` 下的独立模块,便于维护和按需引用。
|
|
10
|
-
* **Tailwind v4 适配**: 修复了在 CSS 中使用复杂 `@apply` 选择器(如 `[&_svg:not(...)]`)时的转义与语法错误,改用原生 CSS 嵌套写法。
|
|
11
|
-
* **依赖精简**: 移除了 Nunjucks/Jinja 模板支持,专注于 HTML/JS 组件实现。
|
|
12
|
-
|
|
13
|
-
## ✨ 组件改进 (Component Improvements)
|
|
14
|
-
|
|
15
|
-
### 核心组件修复
|
|
16
|
-
* **Button**:
|
|
17
|
-
* 修复 Ghost/Link 变体在某些上下文中的背景残留问题。
|
|
18
|
-
* 增强 Outline 变体的文字对比度。
|
|
19
|
-
* **Dialog**:
|
|
20
|
-
* 重构动画曲线,引入 `cubic-bezier` 回弹效果。
|
|
21
|
-
* 优化居中定位逻辑。
|
|
22
|
-
* **Dropdown Menu**:
|
|
23
|
-
* 修复初始化时的可见性闪烁问题(确保初始 `aria-hidden="true"`)。
|
|
24
|
-
* 支持更灵活的 DOM 结构(直接在 popover 内容上定义 `role="menu"`)。
|
|
25
|
-
* **Sidebar**:
|
|
26
|
-
* 优化 `aria-current` 自动高亮逻辑,自动忽略 `href="#"` 空链接。
|
|
27
|
-
* **Form Elements**:
|
|
28
|
-
* 修复 Checkbox/Radio/Switch/Sidebar 中 `content` 属性转义符丢失导致的构建错误。
|
|
29
|
-
* 调整 Select 和 Checkbox 图标颜色 (`oklch`) 以提升对比度。
|
|
30
|
-
* Range 滑块增加 hover 阴影与手型光标。
|
|
31
|
-
|
|
32
|
-
### 新增自定义组件 (New Components)
|
|
33
|
-
* **Accordion**: 上游仅做文档演示,本项目已将其标准化封装为正式组件。基于 `<details>`/`<summary>` 的纯 CSS 动画手风琴。
|
|
34
|
-
* **Sheet**: 侧边抽屉组件,支持从屏幕边缘滑出。
|
|
35
|
-
* **Carousel**: 基础轮播图组件。
|
|
36
|
-
* **Input OTP**: 验证码/一次性密码输入组件。
|
|
37
|
-
* **Toggle / Toggle Group**: 独立的开关与开关组组件。
|
|
38
|
-
|
|
39
|
-
### 外部集成 (External Integrations)
|
|
40
|
-
* **Date Picker**: 集成 `flatpickr`,并提供深度定制的主题样式。
|
|
41
|
-
* **Resizable**: 集成 `split.js`,提供可拖拽布局支持。
|
|
42
|
-
|
|
43
|
-
## 🎨 视觉与主题 (Visuals & Theming)
|
|
44
|
-
|
|
45
|
-
* **Catppuccin 主题**:
|
|
46
|
-
* 完整集成 Latte, Frappé, Macchiato, Mocha 四款主题。
|
|
47
|
-
* 提供配套的 `Theme Switcher` 逻辑 (`src/js/catppuccin-theme-switcher.js`)。
|
|
48
|
-
* **Neumorphism 扩展**:
|
|
49
|
-
* 新增 `lighting.js`: 实现基于鼠标位置的全局拟态光照效果(灵感来源于 `puikinsh/login-forms`)。
|
|
50
|
-
* 支持 CSS 3D Transform 翻转效果。
|
|
51
|
-
|
|
52
|
-
---
|
|
53
|
-
|
|
54
|
-
*注意:以上变更基于与 Basecoat 原版 (`references/basecoat`) 的对比。*
|
package/CHANGELOG.md
DELETED
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
# Basecoat Ultra Changelog
|
|
2
|
-
|
|
3
|
-
**English** | [中文](./CHANGELOG-cn.md)
|
|
4
|
-
|
|
5
|
-
This document records all major changes in `basecoat-ultra` relative to the upstream Basecoat.
|
|
6
|
-
|
|
7
|
-
## 🚀 Architecture & Build
|
|
8
|
-
|
|
9
|
-
* **Modular Refactoring**: Split the monolithic `basecoat.css` into independent modules under `src/css/parts/` for easier maintenance and on-demand usage.
|
|
10
|
-
* **Tailwind v4 Adaptation**: Fixed escaping and syntax errors when using complex `@apply` selectors (e.g., `[&_svg:not(...)]`) in CSS, replacing them with native CSS nesting syntax.
|
|
11
|
-
* **Dependency Slimming**: Removed Nunjucks/Jinja template support to focus on HTML/JS component implementation.
|
|
12
|
-
|
|
13
|
-
## ✨ Component Improvements
|
|
14
|
-
|
|
15
|
-
### Core Fixes
|
|
16
|
-
* **Button**:
|
|
17
|
-
* Fixed background residue issues for Ghost/Link variants in specific contexts.
|
|
18
|
-
* Enhanced text contrast for Outline variants.
|
|
19
|
-
* **Dialog**:
|
|
20
|
-
* Refactored animation curves, introducing `cubic-bezier` bounce effects.
|
|
21
|
-
* Optimized centering logic.
|
|
22
|
-
* **Dropdown Menu**:
|
|
23
|
-
* Fixed visibility flicker on initialization (ensured initial `aria-hidden="true"`).
|
|
24
|
-
* Supported more flexible DOM structures (defining `role="menu"` directly on popover content).
|
|
25
|
-
* **Sidebar**:
|
|
26
|
-
* Optimized `aria-current` auto-highlighting logic to ignore `href="#"` empty links.
|
|
27
|
-
* **Form Elements**:
|
|
28
|
-
* Fixed build errors caused by missing escape characters in `content` properties for Checkbox/Radio/Switch/Sidebar.
|
|
29
|
-
* Adjusted Select and Checkbox icon colors (`oklch`) to improve contrast.
|
|
30
|
-
* Added hover shadows and pointer cursor to Range sliders.
|
|
31
|
-
|
|
32
|
-
### New Custom Components
|
|
33
|
-
* **Accordion**: Standardized and internalized (upstream only had it as a demo). Pure CSS animation based on `<details>`/`<summary>`.
|
|
34
|
-
* **Sheet**: Side drawer component supporting slide-in from screen edges.
|
|
35
|
-
* **Carousel**: Basic carousel component.
|
|
36
|
-
* **Input OTP**: Verification code/One-Time Password input component.
|
|
37
|
-
* **Toggle / Toggle Group**: Independent toggle and toggle group components.
|
|
38
|
-
|
|
39
|
-
### External Integrations
|
|
40
|
-
* **Date Picker**: Integrated `flatpickr` with deeply customized theme styles.
|
|
41
|
-
* **Resizable**: Integrated `split.js` providing draggable layout support.
|
|
42
|
-
|
|
43
|
-
## 🎨 Visuals & Theming
|
|
44
|
-
|
|
45
|
-
* **Catppuccin Themes**:
|
|
46
|
-
* Fully integrated Latte, Frappé, Macchiato, and Mocha themes.
|
|
47
|
-
* Provided matching `Theme Switcher` logic (`src/js/catppuccin-theme-switcher.js`).
|
|
48
|
-
* **Neumorphism Extension**:
|
|
49
|
-
* Added `lighting.js`: Implements global neumorphic lighting effects based on mouse position (Inspired by `puikinsh/login-forms`).
|
|
50
|
-
* Supported CSS 3D Transform flip effects.
|
|
51
|
-
|
|
52
|
-
---
|
|
53
|
-
|
|
54
|
-
*Note: The above changes are based on comparison with the original Basecoat (`references/basecoat`).*
|
package/README-cn.md
DELETED
|
@@ -1,199 +0,0 @@
|
|
|
1
|
-
# Basecoat Ultra
|
|
2
|
-
|
|
3
|
-
**中文** | [English](./README.md)
|
|
4
|
-
|
|
5
|
-
Basecoat 是一套基于 Tailwind CSS 构建的组件库。它旨在用于任何传统的 Web 技术栈。
|
|
6
|
-
Basecoat 将 shadcn/ui 的设计魔法带到了传统 Web 开发中:无需 React。
|
|
7
|
-
|
|
8
|
-
**Basecoat Ultra** 是基于 [Basecoat](https://basecoatui.com) 的增强版 UI 库。它保留了“Tailwind 优先、框架无关”的核心理念,同时提供了针对现代审美和轻量级需求的深度定制。我们移除了对 Nunjucks/Jinja 的原生支持,转而专注于提供更丰富的交互组件、开箱即用的主题系统以及精细的视觉增强。
|
|
9
|
-
|
|
10
|
-
## ✨ 特性
|
|
11
|
-
|
|
12
|
-
### 🛠️ 核心改进
|
|
13
|
-
我们对 Basecoat 核心进行了大量细节打磨和错误修复(详见 CHANGELOG),包括但不限于:
|
|
14
|
-
- **CSS 模块化**:将单体 CSS 重构为模块化结构,支持按需加载。
|
|
15
|
-
- **构建修复**:解决了 Tailwind v4 中复杂选择器的转义问题。
|
|
16
|
-
- **组件优化**:
|
|
17
|
-
- `Button`:修复了特定背景下 Ghost/Link 变体的显示问题。
|
|
18
|
-
- `Dialog`:引入了更自然的缩放和回弹动画。
|
|
19
|
-
- `Dropdown Menu`:修复了初始化时的闪烁问题。
|
|
20
|
-
- `Sidebar`:智能识别并高亮当前页面的逻辑。
|
|
21
|
-
|
|
22
|
-
### 🧩 新增组件
|
|
23
|
-
引入了一系列受 shadcn/ui 启发的高频组件,完全独立于 React/Vue:
|
|
24
|
-
- **Accordion (手风琴)**:原版仅存在于演示中,现已标准化并内置。基于原生 `<details>`,零 JS 动画。
|
|
25
|
-
- **Sheet (侧边栏/抽屉)**:优雅的侧滑面板。
|
|
26
|
-
- **Carousel (轮播)**:轻量级轮播组件。
|
|
27
|
-
- **Input OTP (验证码输入)**:专用的单次密码输入框。
|
|
28
|
-
- **Toggle Group (切换组)**:类似 Radio Group 的按钮式交互。
|
|
29
|
-
- **Toggle (切换按钮)**:独立的切换按钮样式。
|
|
30
|
-
|
|
31
|
-
### 🔌 外部集成
|
|
32
|
-
集成了优秀的第三方库以填补纯 CSS/Vanilla JS 的空白(需单独引入):
|
|
33
|
-
- **Date Picker (日期选择器)**:基于 [Flatpickr](https://flatpickr.js.org/) 的深度定制版,完美适配主题。
|
|
34
|
-
- **Resizable (拖拽分割)**:基于 [Split.js](https://split.js.org/) 的可拖拽分割面板。
|
|
35
|
-
|
|
36
|
-
### 🎨 视觉增强
|
|
37
|
-
- **Catppuccin 主题**:内置支持完整的 [Catppuccin](https://github.com/catppuccin/catppuccin) 配色方案 (Latte, Frappé, Macchiato, Mocha)。
|
|
38
|
-
- **拟态设计 (Neumorphism) 扩展**:
|
|
39
|
-
- **全局光照系统**:独特的小鼠跟随光照效果 (`lighting.js`),赋予 `.neu-panel`、`.neu-btn` 元素拟态质感。
|
|
40
|
-
- **3D 翻转**:支持基于 CSS 3D Transform 的卡片翻转效果。
|
|
41
|
-
|
|
42
|
-
## 📦 安装
|
|
43
|
-
|
|
44
|
-
推荐使用 `bun`,当然也支持 `npm` 或 `pnpm`:
|
|
45
|
-
|
|
46
|
-
```bash
|
|
47
|
-
bun add @lanrenbang/basecoat-ultra
|
|
48
|
-
# 或
|
|
49
|
-
npm install @lanrenbang/basecoat-ultra
|
|
50
|
-
```
|
|
51
|
-
|
|
52
|
-
## 🚀 配置 (构建工具)
|
|
53
|
-
|
|
54
|
-
如果您使用 Vite、Webpack 等构建工具,并已配置 Tailwind CSS v4,请按照以下步骤操作。
|
|
55
|
-
|
|
56
|
-
### 1. 引入 CSS
|
|
57
|
-
|
|
58
|
-
在您的 CSS 入口文件(例如 `style.css`)中引入。
|
|
59
|
-
|
|
60
|
-
**注意**:请引入不带编译的源码版本,让您的 Tailwind 配置来处理样式。切勿引入 `.cdn.css` 版本。
|
|
61
|
-
|
|
62
|
-
```css
|
|
63
|
-
@import "tailwindcss";
|
|
64
|
-
|
|
65
|
-
/* 1. Basecoat 核心样式 (必须) */
|
|
66
|
-
@import "@lanrenbang/basecoat-ultra";
|
|
67
|
-
|
|
68
|
-
/* 2. 外部扩展组件样式 (可选,仅当您使用这些组件时必须显式引入) */
|
|
69
|
-
@import "@lanrenbang/basecoat-ultra/datepicker.css";
|
|
70
|
-
@import "@lanrenbang/basecoat-ultra/resizable.css";
|
|
71
|
-
|
|
72
|
-
/* 3. 主题样式 (可选,必须显式引入) */
|
|
73
|
-
/* 我们提供了一套 Catppuccin 主题,您也可以参考源码实现自己的主题 */
|
|
74
|
-
@import "@lanrenbang/basecoat-ultra/theme/catppuccin";
|
|
75
|
-
```
|
|
76
|
-
|
|
77
|
-
### 2. 引入 JavaScript
|
|
78
|
-
|
|
79
|
-
在您的应用入口文件(例如 `main.js` 或 `app.ts`)中引入。
|
|
80
|
-
|
|
81
|
-
**方式一:全量引入 (推荐)**
|
|
82
|
-
包含核心逻辑及大部分常用组件(不含 Datepicker/Resizable)。
|
|
83
|
-
|
|
84
|
-
```javascript
|
|
85
|
-
import '@lanrenbang/basecoat-ultra/all';
|
|
86
|
-
```
|
|
87
|
-
|
|
88
|
-
**方式二:特定组件引入**
|
|
89
|
-
```javascript
|
|
90
|
-
// 1. 先引入核心
|
|
91
|
-
import '@lanrenbang/basecoat-ultra/basecoat';
|
|
92
|
-
|
|
93
|
-
// 2. 再引入具体组件
|
|
94
|
-
import '@lanrenbang/basecoat-ultra/tabs';
|
|
95
|
-
import '@lanrenbang/basecoat-ultra/select';
|
|
96
|
-
import '@lanrenbang/basecoat-ultra/popover';
|
|
97
|
-
```
|
|
98
|
-
|
|
99
|
-
**外部扩展组件 (必须单独引入)**
|
|
100
|
-
无论使用哪种方式,以下组件因为体积较大或依赖外部库,**不会**包含在默认入口中,必须显式引入:
|
|
101
|
-
|
|
102
|
-
```javascript
|
|
103
|
-
import '@lanrenbang/basecoat-ultra/datepicker'; // 基于 flatpickr
|
|
104
|
-
import '@lanrenbang/basecoat-ultra/resizable'; // 基于 split.js
|
|
105
|
-
```
|
|
106
|
-
|
|
107
|
-
---
|
|
108
|
-
|
|
109
|
-
## 🌐 CDN 用法 (无构建工具)
|
|
110
|
-
|
|
111
|
-
如果您不使用打包工具,可以直接通过 CDN (jsDelivr) 引入。这里我们使用编译好的 `.cdn.css` 版本(已包含 Tailwind 样式)。
|
|
112
|
-
|
|
113
|
-
### CSS
|
|
114
|
-
|
|
115
|
-
```html
|
|
116
|
-
<!-- Basecoat 核心 (包含 Tailwind 样式) -->
|
|
117
|
-
<link href="https://cdn.jsdelivr.net/npm/@lanrenbang/basecoat-ultra@latest/dist/css/basecoat.cdn.min.css" rel="stylesheet">
|
|
118
|
-
|
|
119
|
-
<!-- 外部扩展 (可选) -->
|
|
120
|
-
<link href="https://cdn.jsdelivr.net/npm/@lanrenbang/basecoat-ultra@latest/dist/css/datepicker.min.css" rel="stylesheet">
|
|
121
|
-
<link href="https://cdn.jsdelivr.net/npm/@lanrenbang/basecoat-ultra@latest/dist/css/resizable.min.css" rel="stylesheet">
|
|
122
|
-
|
|
123
|
-
<!-- 主题 (可选) -->
|
|
124
|
-
<link href="https://cdn.jsdelivr.net/npm/@lanrenbang/basecoat-ultra@latest/dist/theme/catppuccin/index.min.css" rel="stylesheet">
|
|
125
|
-
```
|
|
126
|
-
|
|
127
|
-
### JavaScript
|
|
128
|
-
|
|
129
|
-
```html
|
|
130
|
-
<!-- 核心与常用组件 -->
|
|
131
|
-
<script src="https://cdn.jsdelivr.net/npm/@lanrenbang/basecoat-ultra@latest/dist/js/all.min.js" defer></script>
|
|
132
|
-
|
|
133
|
-
<!-- 外部扩展 (可选) -->
|
|
134
|
-
<script src="https://cdn.jsdelivr.net/npm/@lanrenbang/basecoat-ultra@latest/dist/js/datepicker.min.js" defer></script>
|
|
135
|
-
<script src="https://cdn.jsdelivr.net/npm/@lanrenbang/basecoat-ultra@latest/dist/js/resizable.min.js" defer></script>
|
|
136
|
-
```
|
|
137
|
-
|
|
138
|
-
## 🛠️ 开发指南
|
|
139
|
-
|
|
140
|
-
本项目使用 [Bun](https://bun.sh) 作为包管理器和运行时,使用 [Vite](https://vitejs.dev) 进行构建。
|
|
141
|
-
|
|
142
|
-
### 启动项目
|
|
143
|
-
|
|
144
|
-
```bash
|
|
145
|
-
# 1. 克隆项目
|
|
146
|
-
git clone https://github.com/your-username/basecoat-ultra.git
|
|
147
|
-
cd basecoat-ultra
|
|
148
|
-
|
|
149
|
-
# 2. 安装依赖
|
|
150
|
-
bun install
|
|
151
|
-
|
|
152
|
-
# 3. 启动开发服务器
|
|
153
|
-
bun run dev
|
|
154
|
-
```
|
|
155
|
-
|
|
156
|
-
### 防闪烁脚本 (Anti-flash)
|
|
157
|
-
|
|
158
|
-
为了防止在使用 Catppuccin 主题切换器时刷新页面出现闪烁 (FOUC),请将以下脚本放在 HTML `<head>` 标签的顶部:
|
|
159
|
-
|
|
160
|
-
```html
|
|
161
|
-
<script>
|
|
162
|
-
(function() {
|
|
163
|
-
try {
|
|
164
|
-
const t = localStorage.getItem('catppuccin-theme');
|
|
165
|
-
const a = localStorage.getItem('catppuccin-accent');
|
|
166
|
-
const m = localStorage.getItem('basecoat-mode');
|
|
167
|
-
const r = document.documentElement;
|
|
168
|
-
// 优先使用主题配置
|
|
169
|
-
if (t && a) {
|
|
170
|
-
r.classList.add(`theme-${t}`, `accent-${a}`);
|
|
171
|
-
if(['frappe','macchiato','mocha'].includes(t)) r.classList.add('dark');
|
|
172
|
-
} else if (m) {
|
|
173
|
-
// 仅夜间/日间模式偏好
|
|
174
|
-
r.classList.toggle('dark', m === 'dark');
|
|
175
|
-
} else {
|
|
176
|
-
// 跟随系统
|
|
177
|
-
r.classList.toggle('dark', window.matchMedia('(prefers-color-scheme: dark)').matches);
|
|
178
|
-
}
|
|
179
|
-
} catch(e) {}
|
|
180
|
-
})();
|
|
181
|
-
</script>
|
|
182
|
-
```
|
|
183
|
-
|
|
184
|
-
## ❤️ 致谢
|
|
185
|
-
|
|
186
|
-
本项目站在巨人的肩膀上:
|
|
187
|
-
|
|
188
|
-
* **[Basecoat](https://basecoatui.com)**: 原作者 [hunvreus](https://github.com/hunvreus)。大部分基础代码归原作者所有。
|
|
189
|
-
* **[Catppuccin](https://github.com/catppuccin/palette)**: 提供了精美的配色方案。
|
|
190
|
-
* **[puikinsh/login-forms](https://github.com/puikinsh/login-forms/tree/main/forms/neumorphism)**: 拟态光照和 3D 效果的灵感来源。
|
|
191
|
-
* **[Flatpickr](https://flatpickr.js.org/)** & **[Split.js](https://split.js.org/)**: 优秀的第三方库支持。
|
|
192
|
-
|
|
193
|
-
## 通过捐赠支持我
|
|
194
|
-
[](https://buymeacoffee.com/bobbynona) [](https://ko-fi.com/bobbynona) [](https://github.com/Lanrenbang/.github/blob/5b06b0b2d0b8e4ce532c1c37c72115dd98d7d849/custom/USDT-TRC20.md) [](https://github.com/Lanrenbang/.github/blob/5b06b0b2d0b8e4ce532c1c37c72115dd98d7d849/custom/Litecoin.md)
|
|
195
|
-
|
|
196
|
-
## 📄 许可证
|
|
197
|
-
|
|
198
|
-
本项目基于 [MIT License](LICENSE.md) 开源。
|
|
199
|
-
原 Basecoat 内容版权归 hunvreus 所有。
|