ciderui 0.1.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/README.md +106 -0
- package/js/carousel.js +77 -0
- package/js/combobox.js +125 -0
- package/js/command.js +91 -0
- package/js/context-menu.js +49 -0
- package/js/dialog.js +18 -0
- package/js/dropdown-menu.js +39 -0
- package/js/otp.js +92 -0
- package/js/popover.js +35 -0
- package/js/select.js +56 -0
- package/js/sheet.js +17 -0
- package/js/tabs.js +34 -0
- package/js/toast.js +60 -0
- package/js/toggle.js +26 -0
- package/package.json +53 -0
- package/src/css/ciderui.cdn.css +11 -0
- package/src/css/ciderui.css +324 -0
- package/src/css/components/accordion.css +31 -0
- package/src/css/components/alert.css +18 -0
- package/src/css/components/aspect-ratio.css +7 -0
- package/src/css/components/avatar.css +17 -0
- package/src/css/components/badge.css +20 -0
- package/src/css/components/breadcrumb.css +16 -0
- package/src/css/components/button-group.css +20 -0
- package/src/css/components/button.css +59 -0
- package/src/css/components/card.css +37 -0
- package/src/css/components/carousel.css +60 -0
- package/src/css/components/checkbox.css +16 -0
- package/src/css/components/collapsible.css +25 -0
- package/src/css/components/combobox.css +69 -0
- package/src/css/components/command.css +64 -0
- package/src/css/components/context-menu.css +28 -0
- package/src/css/components/dialog.css +23 -0
- package/src/css/components/drawer.css +69 -0
- package/src/css/components/dropdown-menu.css +28 -0
- package/src/css/components/empty.css +12 -0
- package/src/css/components/field.css +7 -0
- package/src/css/components/file-tree.css +53 -0
- package/src/css/components/form-controls.css +57 -0
- package/src/css/components/form.css +15 -0
- package/src/css/components/hover-card.css +25 -0
- package/src/css/components/input-group.css +48 -0
- package/src/css/components/input-otp.css +22 -0
- package/src/css/components/item.css +43 -0
- package/src/css/components/kbd.css +7 -0
- package/src/css/components/label.css +4 -0
- package/src/css/components/pagination.css +15 -0
- package/src/css/components/popover.css +19 -0
- package/src/css/components/progress.css +18 -0
- package/src/css/components/radio.css +13 -0
- package/src/css/components/scroll-area.css +24 -0
- package/src/css/components/separator.css +19 -0
- package/src/css/components/sheet.css +46 -0
- package/src/css/components/sidebar.css +32 -0
- package/src/css/components/skeleton.css +9 -0
- package/src/css/components/slider.css +48 -0
- package/src/css/components/spinner.css +12 -0
- package/src/css/components/switch.css +28 -0
- package/src/css/components/table.css +39 -0
- package/src/css/components/tabs.css +44 -0
- package/src/css/components/theme-switcher.css +17 -0
- package/src/css/components/toast.css +22 -0
- package/src/css/components/toggle.css +34 -0
- package/src/css/components/tooltip.css +66 -0
- package/src/css/components/typography.css +84 -0
package/js/sheet.js
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
// Sheet — ciderui
|
|
2
|
+
// Uses native <dialog> element. Adds backdrop-click-to-close.
|
|
3
|
+
function init() {
|
|
4
|
+
document.querySelectorAll("dialog.sheet").forEach((sheet) => {
|
|
5
|
+
sheet.addEventListener("click", (e) => {
|
|
6
|
+
if (e.target === sheet) {
|
|
7
|
+
sheet.close();
|
|
8
|
+
}
|
|
9
|
+
});
|
|
10
|
+
});
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
if (document.readyState === "loading") {
|
|
14
|
+
document.addEventListener("DOMContentLoaded", init);
|
|
15
|
+
} else {
|
|
16
|
+
init();
|
|
17
|
+
}
|
package/js/tabs.js
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
// Tabs — ciderui
|
|
2
|
+
function init() {
|
|
3
|
+
document.querySelectorAll("[data-tabs]").forEach((tabGroup) => {
|
|
4
|
+
const buttons = tabGroup.querySelectorAll("[data-tab]");
|
|
5
|
+
const panels = tabGroup.querySelectorAll("[data-tab-panel]");
|
|
6
|
+
|
|
7
|
+
buttons.forEach((btn) => {
|
|
8
|
+
btn.addEventListener("click", () => {
|
|
9
|
+
const target = btn.getAttribute("data-tab");
|
|
10
|
+
|
|
11
|
+
// Deactivate all
|
|
12
|
+
buttons.forEach((b) => b.removeAttribute("data-active"));
|
|
13
|
+
|
|
14
|
+
// Activate clicked
|
|
15
|
+
btn.setAttribute("data-active", "");
|
|
16
|
+
|
|
17
|
+
// Show/hide panels
|
|
18
|
+
panels.forEach((p) => {
|
|
19
|
+
if (p.getAttribute("data-tab-panel") === target) {
|
|
20
|
+
p.setAttribute("data-active", "");
|
|
21
|
+
} else {
|
|
22
|
+
p.removeAttribute("data-active");
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
});
|
|
26
|
+
});
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
if (document.readyState === "loading") {
|
|
31
|
+
document.addEventListener("DOMContentLoaded", init);
|
|
32
|
+
} else {
|
|
33
|
+
init();
|
|
34
|
+
}
|
package/js/toast.js
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
// Toast — ciderui
|
|
2
|
+
function showToast(title, message, type = "success") {
|
|
3
|
+
const container =
|
|
4
|
+
document.getElementById("toast-container") || createToastContainer();
|
|
5
|
+
|
|
6
|
+
const iconsSVG = {
|
|
7
|
+
success:
|
|
8
|
+
'<svg class="mt-0.5 size-5 shrink-0 text-success" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"/></svg>',
|
|
9
|
+
error:
|
|
10
|
+
'<svg class="mt-0.5 size-5 shrink-0 text-destructive" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" d="M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"/></svg>',
|
|
11
|
+
info: '<svg class="mt-0.5 size-5 shrink-0 text-primary" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"/></svg>',
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
const toast = document.createElement("div");
|
|
15
|
+
toast.className = "toast";
|
|
16
|
+
toast.setAttribute("role", "status");
|
|
17
|
+
toast.setAttribute("aria-live", "polite");
|
|
18
|
+
|
|
19
|
+
// Icon
|
|
20
|
+
const iconWrapper = document.createElement("template");
|
|
21
|
+
iconWrapper.innerHTML = iconsSVG[type] || iconsSVG.success;
|
|
22
|
+
toast.appendChild(iconWrapper.content);
|
|
23
|
+
|
|
24
|
+
// Content
|
|
25
|
+
const content = document.createElement("div");
|
|
26
|
+
content.className = "flex-1";
|
|
27
|
+
const titleEl = document.createElement("p");
|
|
28
|
+
titleEl.className = "toast-title";
|
|
29
|
+
titleEl.textContent = title;
|
|
30
|
+
const messageEl = document.createElement("p");
|
|
31
|
+
messageEl.className = "toast-message";
|
|
32
|
+
messageEl.textContent = message;
|
|
33
|
+
content.appendChild(titleEl);
|
|
34
|
+
content.appendChild(messageEl);
|
|
35
|
+
toast.appendChild(content);
|
|
36
|
+
|
|
37
|
+
// Close button
|
|
38
|
+
const closeBtn = document.createElement("button");
|
|
39
|
+
closeBtn.className = "toast-close";
|
|
40
|
+
closeBtn.setAttribute("aria-label", "Close");
|
|
41
|
+
closeBtn.innerHTML = '<svg class="size-4" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" d="M6 18L18 6M6 6l12 12"/></svg>';
|
|
42
|
+
closeBtn.addEventListener("click", () => toast.remove());
|
|
43
|
+
toast.appendChild(closeBtn);
|
|
44
|
+
|
|
45
|
+
container.appendChild(toast);
|
|
46
|
+
|
|
47
|
+
// Auto-remove after 4 seconds
|
|
48
|
+
setTimeout(() => {
|
|
49
|
+
toast.style.animation = "slideDown 0.2s ease-in forwards";
|
|
50
|
+
setTimeout(() => toast.remove(), 200);
|
|
51
|
+
}, 4000);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function createToastContainer() {
|
|
55
|
+
const container = document.createElement("div");
|
|
56
|
+
container.id = "toast-container";
|
|
57
|
+
container.className = "toast-container";
|
|
58
|
+
document.body.appendChild(container);
|
|
59
|
+
return container;
|
|
60
|
+
}
|
package/js/toggle.js
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
// Toggle — ciderui
|
|
2
|
+
document.addEventListener("click", (e) => {
|
|
3
|
+
const toggle = e.target.closest(".toggle");
|
|
4
|
+
if (!toggle || toggle.disabled) return;
|
|
5
|
+
|
|
6
|
+
// If inside a toggle-group, handle single-select
|
|
7
|
+
const group = toggle.closest(".toggle-group");
|
|
8
|
+
if (group && !group.hasAttribute("data-multiple")) {
|
|
9
|
+
group.querySelectorAll(".toggle").forEach((t) => {
|
|
10
|
+
t.removeAttribute("data-active");
|
|
11
|
+
t.setAttribute("aria-pressed", "false");
|
|
12
|
+
});
|
|
13
|
+
toggle.setAttribute("data-active", "");
|
|
14
|
+
toggle.setAttribute("aria-pressed", "true");
|
|
15
|
+
} else {
|
|
16
|
+
// Standalone toggle or multi-select group
|
|
17
|
+
const isActive = toggle.hasAttribute("data-active");
|
|
18
|
+
if (isActive) {
|
|
19
|
+
toggle.removeAttribute("data-active");
|
|
20
|
+
toggle.setAttribute("aria-pressed", "false");
|
|
21
|
+
} else {
|
|
22
|
+
toggle.setAttribute("data-active", "");
|
|
23
|
+
toggle.setAttribute("aria-pressed", "true");
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
});
|
package/package.json
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "ciderui",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Apple-aesthetic UI components as a Tailwind CSS plugin",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"author": "newlix",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "https://github.com/newlix/ciderui"
|
|
10
|
+
},
|
|
11
|
+
"keywords": [
|
|
12
|
+
"tailwindcss",
|
|
13
|
+
"tailwind",
|
|
14
|
+
"css",
|
|
15
|
+
"components",
|
|
16
|
+
"apple",
|
|
17
|
+
"cider",
|
|
18
|
+
"ui"
|
|
19
|
+
],
|
|
20
|
+
"type": "module",
|
|
21
|
+
"exports": {
|
|
22
|
+
".": "./src/css/ciderui.css",
|
|
23
|
+
"./cdn": "./src/css/ciderui.cdn.css",
|
|
24
|
+
"./carousel.js": "./js/carousel.js",
|
|
25
|
+
"./combobox.js": "./js/combobox.js",
|
|
26
|
+
"./command.js": "./js/command.js",
|
|
27
|
+
"./context-menu.js": "./js/context-menu.js",
|
|
28
|
+
"./dialog.js": "./js/dialog.js",
|
|
29
|
+
"./dropdown-menu.js": "./js/dropdown-menu.js",
|
|
30
|
+
"./otp.js": "./js/otp.js",
|
|
31
|
+
"./popover.js": "./js/popover.js",
|
|
32
|
+
"./select.js": "./js/select.js",
|
|
33
|
+
"./sheet.js": "./js/sheet.js",
|
|
34
|
+
"./tabs.js": "./js/tabs.js",
|
|
35
|
+
"./toast.js": "./js/toast.js",
|
|
36
|
+
"./toggle.js": "./js/toggle.js"
|
|
37
|
+
},
|
|
38
|
+
"files": [
|
|
39
|
+
"src/css/",
|
|
40
|
+
"js/"
|
|
41
|
+
],
|
|
42
|
+
"scripts": {
|
|
43
|
+
"build": "tailwindcss -i src/css/ciderui.cdn.css -o dist/ciderui.cdn.css && tailwindcss -i src/css/ciderui.cdn.css -o dist/ciderui.cdn.min.css --minify",
|
|
44
|
+
"dev": "concurrently \"tailwindcss -i docs/docs.css -o docs/docs.built.css --watch\" \"npx serve -l tcp://0.0.0.0:3000\"",
|
|
45
|
+
"test": "npx playwright test",
|
|
46
|
+
"test:ui": "npx playwright test --ui"
|
|
47
|
+
},
|
|
48
|
+
"devDependencies": {
|
|
49
|
+
"@playwright/test": "latest",
|
|
50
|
+
"@tailwindcss/cli": "^4.2.1",
|
|
51
|
+
"concurrently": "latest"
|
|
52
|
+
}
|
|
53
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* ciderui — CDN variant (includes Tailwind CSS)
|
|
3
|
+
*
|
|
4
|
+
* Usage:
|
|
5
|
+
* <link rel="stylesheet" href="path/to/ciderui.cdn.css" />
|
|
6
|
+
*
|
|
7
|
+
* This file includes Tailwind CSS + ciderui in one bundle.
|
|
8
|
+
* source(none) ensures Tailwind only generates classes used in ciderui.css.
|
|
9
|
+
*/
|
|
10
|
+
@import "tailwindcss" source(none);
|
|
11
|
+
@import "./ciderui.css";
|
|
@@ -0,0 +1,324 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* ciderui — Apple-aesthetic UI components as a Tailwind CSS plugin
|
|
3
|
+
* https://github.com/newlix/ciderui
|
|
4
|
+
*
|
|
5
|
+
* Usage:
|
|
6
|
+
* @import "tailwindcss";
|
|
7
|
+
* @import "ciderui";
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
/* ─── Dark mode variant ─── */
|
|
11
|
+
@custom-variant dark (&:is(.dark *));
|
|
12
|
+
|
|
13
|
+
/* ─── CSS Variables ─── */
|
|
14
|
+
:root {
|
|
15
|
+
--primary: oklch(0.563 0.193 256.16); /* Apple Blue #0071E3 rgb(0,113,227) */
|
|
16
|
+
--primary-hover: oklch(0.522 0.177 255.84); /* #0066CC rgb(0,102,204) */
|
|
17
|
+
--primary-active: oklch(0.480 0.165 256.16); /* darker press state */
|
|
18
|
+
--primary-foreground: #fff;
|
|
19
|
+
|
|
20
|
+
--background: #fff;
|
|
21
|
+
--foreground: oklch(0.232 0.004 285.99); /* #1D1D1F Apple body text */
|
|
22
|
+
|
|
23
|
+
--card: #fff;
|
|
24
|
+
--card-foreground: oklch(0.232 0.004 285.99);
|
|
25
|
+
|
|
26
|
+
--secondary: oklch(0.971 0.003 285.66); /* #F5F5F7 Apple secondary bg */
|
|
27
|
+
--secondary-hover: oklch(0.930 0.005 286.02);
|
|
28
|
+
--secondary-foreground: oklch(0.232 0.004 285.99);
|
|
29
|
+
|
|
30
|
+
--muted: oklch(0.971 0.003 285.66);
|
|
31
|
+
--muted-foreground: oklch(0.540 0.008 286.01); /* #6E6E73 Apple muted text */
|
|
32
|
+
|
|
33
|
+
--accent: oklch(0.971 0.003 285.66);
|
|
34
|
+
--accent-foreground: oklch(0.232 0.004 285.99);
|
|
35
|
+
|
|
36
|
+
--border: oklch(0.862 0.007 286.02 / 0.6); /* #D1D1D6 Apple border */
|
|
37
|
+
--border-solid: oklch(0.862 0.007 286.02 / 0.8);
|
|
38
|
+
--input: oklch(0.862 0.007 286.02 / 0.8);
|
|
39
|
+
|
|
40
|
+
--ring: oklch(0.563 0.193 256.16 / 0.1);
|
|
41
|
+
|
|
42
|
+
--destructive: oklch(0.577 0.245 27.33); /* red-500 */
|
|
43
|
+
--destructive-hover: oklch(0.535 0.241 27.33); /* red-600 */
|
|
44
|
+
--destructive-active: oklch(0.494 0.226 27.33);/* red-700 */
|
|
45
|
+
--destructive-foreground: #fff;
|
|
46
|
+
|
|
47
|
+
--success: oklch(0.596 0.172 145.18); /* green-500 */
|
|
48
|
+
--success-bg: oklch(0.962 0.044 156.74); /* green-50 */
|
|
49
|
+
--success-text: oklch(0.408 0.132 145.18); /* green-700 */
|
|
50
|
+
--success-border: oklch(0.905 0.093 156.74 / 0.6); /* green-200/60 */
|
|
51
|
+
|
|
52
|
+
--warning: oklch(0.666 0.179 58.32); /* amber-600 */
|
|
53
|
+
--warning-bg: oklch(0.987 0.046 85.80); /* amber-50 */
|
|
54
|
+
--warning-text: oklch(0.461 0.147 58.32); /* amber-700 */
|
|
55
|
+
--warning-border: oklch(0.924 0.112 85.80 / 0.6); /* amber-200/60 */
|
|
56
|
+
|
|
57
|
+
--info: oklch(0.563 0.193 256.16); /* same as primary */
|
|
58
|
+
--info-bg: oklch(0.563 0.193 256.16 / 0.05);
|
|
59
|
+
--info-text: oklch(0.563 0.193 256.16);
|
|
60
|
+
--info-border: oklch(0.563 0.193 256.16 / 0.2);
|
|
61
|
+
|
|
62
|
+
--input-border: oklch(0.800 0.007 286.02); /* Apple input border */
|
|
63
|
+
--input-border-hover: oklch(0.580 0.010 286.01); /* Darker on hover */
|
|
64
|
+
|
|
65
|
+
--apple-press-scale: 0.98;
|
|
66
|
+
--apple-spring: cubic-bezier(0.2, 0.8, 0.2, 1);
|
|
67
|
+
--apple-ease: cubic-bezier(0.25, 0.1, 0.25, 1);
|
|
68
|
+
|
|
69
|
+
/* Surface overlays — auto-switch in dark mode */
|
|
70
|
+
--surface-1: oklch(0 0 0 / 0.02); /* table header, zebra stripe */
|
|
71
|
+
--surface-2: oklch(0 0 0 / 0.03); /* hover backgrounds */
|
|
72
|
+
--surface-3: oklch(0 0 0 / 0.04); /* icon bg, kbd bg, toggle group */
|
|
73
|
+
--surface-4: oklch(0 0 0 / 0.06); /* active state, segmented control bg */
|
|
74
|
+
--surface-5: oklch(0 0 0 / 0.1); /* slider track */
|
|
75
|
+
--surface-6: oklch(0 0 0 / 0.12); /* scrollbar */
|
|
76
|
+
--surface-7: oklch(0 0 0 / 0.2); /* scrollbar hover, handle */
|
|
77
|
+
--panel-border: oklch(0 0 0 / 0.06); /* section dividers in panels */
|
|
78
|
+
--panel-ring: 0 0 0 1px oklch(0 0 0 / 0.04); /* card/table shadow outline */
|
|
79
|
+
--float-ring: 0 0 0 1px oklch(0 0 0 / 0.06); /* dropdown/popover/toast outline */
|
|
80
|
+
--glass-blur: blur(20px) saturate(1.5);
|
|
81
|
+
--glass-bg: oklch(from var(--card) l c h / 0.85);
|
|
82
|
+
--glass-bg-opaque: oklch(from var(--card) l c h / 0.9);
|
|
83
|
+
--backdrop-bg: oklch(0 0 0 / 0.35);
|
|
84
|
+
|
|
85
|
+
--radius: 0.75rem; /* 12px */
|
|
86
|
+
--radius-sm: 0.5rem; /* 8px */
|
|
87
|
+
--radius-lg: 1rem; /* 16px */
|
|
88
|
+
--radius-xl: 1.375rem; /* 22px */
|
|
89
|
+
|
|
90
|
+
--shadow-sm: 0 1px 2px oklch(0 0 0 / 0.04), 0 1px 3px oklch(0 0 0 / 0.03);
|
|
91
|
+
--shadow: 0 2px 8px oklch(0 0 0 / 0.06), 0 1px 2px oklch(0 0 0 / 0.04);
|
|
92
|
+
--shadow-md: 0 4px 16px oklch(0 0 0 / 0.08), 0 2px 4px oklch(0 0 0 / 0.04);
|
|
93
|
+
--shadow-lg: 0 8px 32px oklch(0 0 0 / 0.1), 0 2px 8px oklch(0 0 0 / 0.05);
|
|
94
|
+
--shadow-xl: 0 16px 48px oklch(0 0 0 / 0.12), 0 4px 16px oklch(0 0 0 / 0.06);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
.dark {
|
|
98
|
+
--primary: oklch(0.669 0.181 251.85); /* #2997FF Apple blue on dark bg */
|
|
99
|
+
--primary-hover: oklch(0.620 0.185 253.00);
|
|
100
|
+
--primary-active: oklch(0.570 0.188 254.00);
|
|
101
|
+
|
|
102
|
+
--background: oklch(0.000 0 0); /* #000 Apple dark bg */
|
|
103
|
+
--foreground: oklch(0.971 0.003 285.66); /* #F5F5F7 Apple dark text */
|
|
104
|
+
|
|
105
|
+
--card: oklch(0.160 0.004 285.99); /* #1C1C1E Apple dark card */
|
|
106
|
+
--card-foreground: oklch(0.971 0.003 285.66);
|
|
107
|
+
|
|
108
|
+
--secondary: oklch(0.232 0.004 285.99); /* #2C2C2E Apple dark secondary */
|
|
109
|
+
--secondary-hover: oklch(0.320 0.004 285.99);
|
|
110
|
+
--secondary-foreground: oklch(0.971 0.003 285.66);
|
|
111
|
+
|
|
112
|
+
--muted: oklch(0.232 0.004 285.99);
|
|
113
|
+
--muted-foreground: oklch(0.630 0.006 286.01); /* #98989D Apple dark muted */
|
|
114
|
+
|
|
115
|
+
--accent: oklch(0.232 0.004 285.99);
|
|
116
|
+
--accent-foreground: oklch(0.971 0.003 285.66);
|
|
117
|
+
|
|
118
|
+
--border: oklch(0.290 0.004 285.99); /* #3A3A3C Apple dark border */
|
|
119
|
+
--border-solid: oklch(0.350 0.004 285.99); /* #48484A */
|
|
120
|
+
--input: oklch(0.350 0.004 285.99);
|
|
121
|
+
|
|
122
|
+
--input-border: oklch(0.350 0.004 285.99); /* #48484A */
|
|
123
|
+
--input-border-hover: oklch(0.420 0.004 285.99); /* Lighter on hover */
|
|
124
|
+
|
|
125
|
+
--ring: oklch(0.669 0.181 251.85 / 0.2);
|
|
126
|
+
|
|
127
|
+
--info: oklch(0.669 0.181 251.85);
|
|
128
|
+
--info-bg: oklch(0.669 0.181 251.85 / 0.05);
|
|
129
|
+
--info-text: oklch(0.669 0.181 251.85);
|
|
130
|
+
--info-border: oklch(0.669 0.181 251.85 / 0.2);
|
|
131
|
+
|
|
132
|
+
--success-bg: oklch(0.596 0.172 145.18 / 0.05);
|
|
133
|
+
--success-text: oklch(0.792 0.155 145.18); /* green-400 */
|
|
134
|
+
--success-border: oklch(0.596 0.172 145.18 / 0.2);
|
|
135
|
+
|
|
136
|
+
--warning-bg: oklch(0.666 0.179 58.32 / 0.05);
|
|
137
|
+
--warning-text: oklch(0.828 0.143 58.32); /* amber-400 */
|
|
138
|
+
--warning-border: oklch(0.666 0.179 58.32 / 0.2);
|
|
139
|
+
|
|
140
|
+
--shadow-sm: 0 1px 3px oklch(1 0 0 / 0.08), 0 1px 2px oklch(1 0 0 / 0.04);
|
|
141
|
+
--shadow: 0 2px 8px oklch(0 0 0 / 0.2), 0 1px 3px oklch(0 0 0 / 0.15);
|
|
142
|
+
--shadow-md: 0 4px 16px oklch(0 0 0 / 0.25), 0 2px 4px oklch(0 0 0 / 0.15);
|
|
143
|
+
--shadow-lg: 0 8px 32px oklch(0 0 0 / 0.3), 0 2px 8px oklch(0 0 0 / 0.2);
|
|
144
|
+
--shadow-xl: 0 16px 48px oklch(0 0 0 / 0.35), 0 4px 16px oklch(0 0 0 / 0.2);
|
|
145
|
+
|
|
146
|
+
--surface-1: oklch(1 0 0 / 0.03);
|
|
147
|
+
--surface-2: oklch(1 0 0 / 0.05);
|
|
148
|
+
--surface-3: oklch(1 0 0 / 0.06);
|
|
149
|
+
--surface-4: oklch(1 0 0 / 0.08);
|
|
150
|
+
--surface-5: oklch(1 0 0 / 0.12);
|
|
151
|
+
--surface-6: oklch(1 0 0 / 0.12);
|
|
152
|
+
--surface-7: oklch(1 0 0 / 0.2);
|
|
153
|
+
--panel-border: oklch(1 0 0 / 0.08);
|
|
154
|
+
--panel-ring: 0 0 0 1px oklch(1 0 0 / 0.06);
|
|
155
|
+
--float-ring: 0 0 0 1px oklch(1 0 0 / 0.08);
|
|
156
|
+
--glass-bg: oklch(from var(--card) l c h / 0.8);
|
|
157
|
+
--glass-bg-opaque: oklch(from var(--card) l c h / 0.85);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/* ─── Theme tokens (make vars available to Tailwind) ─── */
|
|
161
|
+
@theme {
|
|
162
|
+
--color-primary: var(--primary);
|
|
163
|
+
--color-primary-hover: var(--primary-hover);
|
|
164
|
+
--color-primary-active: var(--primary-active);
|
|
165
|
+
--color-primary-foreground: var(--primary-foreground);
|
|
166
|
+
--color-background: var(--background);
|
|
167
|
+
--color-foreground: var(--foreground);
|
|
168
|
+
--color-card: var(--card);
|
|
169
|
+
--color-card-foreground: var(--card-foreground);
|
|
170
|
+
--color-secondary: var(--secondary);
|
|
171
|
+
--color-secondary-hover: var(--secondary-hover);
|
|
172
|
+
--color-secondary-foreground: var(--secondary-foreground);
|
|
173
|
+
--color-muted: var(--muted);
|
|
174
|
+
--color-muted-foreground: var(--muted-foreground);
|
|
175
|
+
--color-accent: var(--accent);
|
|
176
|
+
--color-accent-foreground: var(--accent-foreground);
|
|
177
|
+
--color-border: var(--border);
|
|
178
|
+
--color-input: var(--input);
|
|
179
|
+
--color-ring: var(--ring);
|
|
180
|
+
--color-destructive: var(--destructive);
|
|
181
|
+
--color-destructive-hover: var(--destructive-hover);
|
|
182
|
+
--color-destructive-active: var(--destructive-active);
|
|
183
|
+
--color-destructive-foreground: var(--destructive-foreground);
|
|
184
|
+
--color-success: var(--success);
|
|
185
|
+
--color-success-bg: var(--success-bg);
|
|
186
|
+
--color-success-text: var(--success-text);
|
|
187
|
+
--color-success-border: var(--success-border);
|
|
188
|
+
--color-warning: var(--warning);
|
|
189
|
+
--color-warning-bg: var(--warning-bg);
|
|
190
|
+
--color-warning-text: var(--warning-text);
|
|
191
|
+
--color-warning-border: var(--warning-border);
|
|
192
|
+
--color-info: var(--info);
|
|
193
|
+
--color-info-bg: var(--info-bg);
|
|
194
|
+
--color-info-text: var(--info-text);
|
|
195
|
+
--color-info-border: var(--info-border);
|
|
196
|
+
--radius: var(--radius);
|
|
197
|
+
--radius-sm: var(--radius-sm);
|
|
198
|
+
--radius-lg: var(--radius-lg);
|
|
199
|
+
--radius-xl: var(--radius-xl);
|
|
200
|
+
--shadow-sm: var(--shadow-sm);
|
|
201
|
+
--shadow: var(--shadow);
|
|
202
|
+
--shadow-md: var(--shadow-md);
|
|
203
|
+
--shadow-lg: var(--shadow-lg);
|
|
204
|
+
--shadow-xl: var(--shadow-xl);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/* ─── Base ─── */
|
|
208
|
+
@layer base {
|
|
209
|
+
body {
|
|
210
|
+
@apply bg-background text-foreground antialiased;
|
|
211
|
+
font-family: -apple-system, BlinkMacSystemFont, "SF Pro Text", "SF Pro Display", system-ui, sans-serif;
|
|
212
|
+
-webkit-font-smoothing: antialiased;
|
|
213
|
+
-moz-osx-font-smoothing: grayscale;
|
|
214
|
+
letter-spacing: -0.01em;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
*,
|
|
218
|
+
*::before,
|
|
219
|
+
*::after {
|
|
220
|
+
@apply border-border;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
@keyframes slideUp {
|
|
224
|
+
from { opacity: 0; transform: translateY(8px); }
|
|
225
|
+
to { opacity: 1; transform: translateY(0); }
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
@keyframes slideDown {
|
|
229
|
+
from { opacity: 1; transform: translateY(0); }
|
|
230
|
+
to { opacity: 0; transform: translateY(8px); }
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
@keyframes dialogShow {
|
|
234
|
+
from { opacity: 0; transform: scale(0.95); }
|
|
235
|
+
to { opacity: 1; transform: scale(1); }
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
@keyframes indeterminate {
|
|
239
|
+
0% { transform: translateX(-100%); }
|
|
240
|
+
100% { transform: translateX(400%); }
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
@keyframes sheetSlideInRight {
|
|
244
|
+
from { transform: translateX(100%); }
|
|
245
|
+
to { transform: translateX(0); }
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
@keyframes sheetSlideInLeft {
|
|
249
|
+
from { transform: translateX(-100%); }
|
|
250
|
+
to { transform: translateX(0); }
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
@keyframes sheetSlideInBottom {
|
|
254
|
+
from { transform: translateY(100%); }
|
|
255
|
+
to { transform: translateY(0); }
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
@keyframes sheetSlideInTop {
|
|
259
|
+
from { transform: translateY(-100%); }
|
|
260
|
+
to { transform: translateY(0); }
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
/* Reduced motion — disable animations/transitions for users who prefer it */
|
|
264
|
+
@media (prefers-reduced-motion: reduce) {
|
|
265
|
+
*, *::before, *::after {
|
|
266
|
+
animation-duration: 0.01ms !important;
|
|
267
|
+
animation-iteration-count: 1 !important;
|
|
268
|
+
transition-duration: 0.01ms !important;
|
|
269
|
+
scroll-behavior: auto !important;
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
/* ─── Components ─── */
|
|
275
|
+
@layer components {
|
|
276
|
+
@import "./components/button.css";
|
|
277
|
+
@import "./components/badge.css";
|
|
278
|
+
@import "./components/card.css";
|
|
279
|
+
@import "./components/alert.css";
|
|
280
|
+
@import "./components/form-controls.css";
|
|
281
|
+
@import "./components/checkbox.css";
|
|
282
|
+
@import "./components/radio.css";
|
|
283
|
+
@import "./components/switch.css";
|
|
284
|
+
@import "./components/label.css";
|
|
285
|
+
@import "./components/field.css";
|
|
286
|
+
@import "./components/dialog.css";
|
|
287
|
+
@import "./components/dropdown-menu.css";
|
|
288
|
+
@import "./components/tabs.css";
|
|
289
|
+
@import "./components/table.css";
|
|
290
|
+
@import "./components/accordion.css";
|
|
291
|
+
@import "./components/avatar.css";
|
|
292
|
+
@import "./components/breadcrumb.css";
|
|
293
|
+
@import "./components/button-group.css";
|
|
294
|
+
@import "./components/kbd.css";
|
|
295
|
+
@import "./components/pagination.css";
|
|
296
|
+
@import "./components/progress.css";
|
|
297
|
+
@import "./components/skeleton.css";
|
|
298
|
+
@import "./components/slider.css";
|
|
299
|
+
@import "./components/spinner.css";
|
|
300
|
+
@import "./components/toast.css";
|
|
301
|
+
@import "./components/tooltip.css";
|
|
302
|
+
@import "./components/separator.css";
|
|
303
|
+
@import "./components/input-group.css";
|
|
304
|
+
@import "./components/item.css";
|
|
305
|
+
@import "./components/form.css";
|
|
306
|
+
@import "./components/sidebar.css";
|
|
307
|
+
@import "./components/theme-switcher.css";
|
|
308
|
+
@import "./components/command.css";
|
|
309
|
+
@import "./components/combobox.css";
|
|
310
|
+
@import "./components/empty.css";
|
|
311
|
+
@import "./components/collapsible.css";
|
|
312
|
+
@import "./components/file-tree.css";
|
|
313
|
+
@import "./components/sheet.css";
|
|
314
|
+
@import "./components/popover.css";
|
|
315
|
+
@import "./components/toggle.css";
|
|
316
|
+
@import "./components/aspect-ratio.css";
|
|
317
|
+
@import "./components/typography.css";
|
|
318
|
+
@import "./components/scroll-area.css";
|
|
319
|
+
@import "./components/hover-card.css";
|
|
320
|
+
@import "./components/drawer.css";
|
|
321
|
+
@import "./components/input-otp.css";
|
|
322
|
+
@import "./components/context-menu.css";
|
|
323
|
+
@import "./components/carousel.css";
|
|
324
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/* ========== ACCORDION ========== */
|
|
2
|
+
.accordion {
|
|
3
|
+
@apply rounded-2xl bg-card;
|
|
4
|
+
box-shadow: var(--shadow-sm), var(--panel-ring);
|
|
5
|
+
& details + details {
|
|
6
|
+
border-top: 1px solid var(--panel-border);
|
|
7
|
+
}
|
|
8
|
+
& summary {
|
|
9
|
+
@apply flex cursor-pointer items-center justify-between px-5 py-4 text-[13px] font-medium text-foreground;
|
|
10
|
+
transition: background-color 0.15s var(--apple-ease);
|
|
11
|
+
&:hover { background: var(--surface-1); }
|
|
12
|
+
&:focus-visible { outline: 3px solid oklch(from var(--primary) l c h / 0.3); outline-offset: -3px; }
|
|
13
|
+
&::-webkit-details-marker { display: none; }
|
|
14
|
+
& svg:last-child {
|
|
15
|
+
@apply size-4 shrink-0 text-muted-foreground;
|
|
16
|
+
transition: transform 0.25s var(--apple-spring);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
& details:first-child > summary {
|
|
20
|
+
@apply rounded-t-2xl;
|
|
21
|
+
}
|
|
22
|
+
& details:last-child:not([open]) > summary {
|
|
23
|
+
@apply rounded-b-2xl;
|
|
24
|
+
}
|
|
25
|
+
& details[open] > summary svg:last-child {
|
|
26
|
+
transform: rotate(180deg);
|
|
27
|
+
}
|
|
28
|
+
& details > div, & details > p {
|
|
29
|
+
@apply px-5 pb-4 text-[13px] text-muted-foreground;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/* ========== ALERT ========== */
|
|
2
|
+
.alert,
|
|
3
|
+
.alert-info,
|
|
4
|
+
.alert-success,
|
|
5
|
+
.alert-warning,
|
|
6
|
+
.alert-destructive {
|
|
7
|
+
@apply flex gap-3 rounded-xl p-4;
|
|
8
|
+
background: var(--card);
|
|
9
|
+
box-shadow: var(--shadow-sm), var(--panel-ring);
|
|
10
|
+
& svg:first-child { @apply mt-0.5 size-5 shrink-0; color: var(--muted-foreground); }
|
|
11
|
+
& p:first-child, & p:first-of-type { @apply text-[13px] font-medium text-foreground; }
|
|
12
|
+
& p:last-child:not(:first-child) { @apply mt-0.5 text-[13px] text-muted-foreground; }
|
|
13
|
+
}
|
|
14
|
+
/* Only the icon carries semantic color */
|
|
15
|
+
.alert-info { & svg:first-child { color: var(--primary); } }
|
|
16
|
+
.alert-success { & svg:first-child { color: var(--success); } }
|
|
17
|
+
.alert-warning { & svg:first-child { color: var(--warning); } }
|
|
18
|
+
.alert-destructive { & svg:first-child { color: var(--destructive); } }
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/* ========== AVATAR ========== */
|
|
2
|
+
.avatar {
|
|
3
|
+
@apply inline-flex size-10 items-center justify-center rounded-full text-[13px] font-semibold;
|
|
4
|
+
/* Default fallback styling */
|
|
5
|
+
@apply bg-secondary text-muted-foreground;
|
|
6
|
+
& img {
|
|
7
|
+
@apply size-full rounded-full object-cover;
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
.avatar-sm { @apply size-8 text-xs; }
|
|
11
|
+
.avatar-lg { @apply size-14 text-[17px]; }
|
|
12
|
+
.avatar-group {
|
|
13
|
+
@apply flex -space-x-2;
|
|
14
|
+
& .avatar {
|
|
15
|
+
@apply ring-2 ring-background;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/* ========== BADGE ========== */
|
|
2
|
+
.badge,
|
|
3
|
+
.badge-primary,
|
|
4
|
+
.badge-secondary,
|
|
5
|
+
.badge-success,
|
|
6
|
+
.badge-warning,
|
|
7
|
+
.badge-destructive,
|
|
8
|
+
.badge-outline {
|
|
9
|
+
@apply inline-flex items-center gap-1 rounded-full px-2 py-[2px] text-[11px] font-medium bg-secondary text-secondary-foreground;
|
|
10
|
+
letter-spacing: 0;
|
|
11
|
+
}
|
|
12
|
+
/* Only text carries semantic color */
|
|
13
|
+
.badge-primary { @apply text-primary; }
|
|
14
|
+
.badge-success { color: var(--success); }
|
|
15
|
+
.badge-warning { color: var(--warning); }
|
|
16
|
+
.badge-destructive { @apply text-destructive; }
|
|
17
|
+
.badge-outline {
|
|
18
|
+
@apply bg-transparent;
|
|
19
|
+
box-shadow: inset 0 0 0 1px var(--border-solid);
|
|
20
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/* ========== BREADCRUMB ========== */
|
|
2
|
+
.breadcrumb {
|
|
3
|
+
@apply flex items-center gap-1.5 text-[13px];
|
|
4
|
+
& a {
|
|
5
|
+
@apply text-muted-foreground transition-colors;
|
|
6
|
+
&:hover { @apply text-foreground; }
|
|
7
|
+
&:focus-visible { outline: 3px solid oklch(from var(--primary) l c h / 0.3); outline-offset: 2px; border-radius: 4px; }
|
|
8
|
+
}
|
|
9
|
+
& svg { @apply size-3.5 text-muted-foreground; opacity: 0.6; }
|
|
10
|
+
& span:last-child, & [aria-current] {
|
|
11
|
+
@apply font-medium text-foreground;
|
|
12
|
+
}
|
|
13
|
+
& .breadcrumb-separator {
|
|
14
|
+
@apply text-muted-foreground; opacity: 0.6;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/* ========== BUTTON GROUP ========== */
|
|
2
|
+
.button-group {
|
|
3
|
+
@apply inline-flex rounded-[12px] bg-card;
|
|
4
|
+
box-shadow: 0 0 0 1px var(--panel-border), var(--shadow-sm);
|
|
5
|
+
& button, & a {
|
|
6
|
+
@apply inline-flex items-center justify-center bg-transparent px-4 py-2.5 text-[13px] font-medium text-foreground;
|
|
7
|
+
transition: all 0.15s var(--apple-ease);
|
|
8
|
+
&:hover { background: var(--surface-2); }
|
|
9
|
+
&:focus-visible { outline: 3px solid oklch(from var(--primary) l c h / 0.3); outline-offset: -3px; }
|
|
10
|
+
&:first-child { @apply rounded-l-[12px]; }
|
|
11
|
+
&:last-child { @apply rounded-r-[12px]; }
|
|
12
|
+
&:not(:first-child) {
|
|
13
|
+
border-left: 1px solid var(--panel-border);
|
|
14
|
+
}
|
|
15
|
+
&[data-active] {
|
|
16
|
+
@apply bg-primary text-primary-foreground;
|
|
17
|
+
&:hover { @apply bg-primary-hover; }
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|