@arronqzy/ui 0.0.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/.eslintrc.cjs +10 -0
- package/.turbo/turbo-lint.log +4 -0
- package/components.json +20 -0
- package/dist/styles.css +3105 -0
- package/index.ts +7 -0
- package/package.json +76 -0
- package/postcss.config.cjs +7 -0
- package/scripts/sync-shadcn.mjs +144 -0
- package/src/hooks/use-toast.ts +194 -0
- package/src/lib/overlay-z-index.ts +8 -0
- package/src/lib/utils.ts +7 -0
- package/src/styles.css +89 -0
- package/src/theme-provider.tsx +36 -0
- package/src/ui/accordion.tsx +58 -0
- package/src/ui/alert-dialog.tsx +149 -0
- package/src/ui/alert.tsx +59 -0
- package/src/ui/aspect-ratio.tsx +7 -0
- package/src/ui/avatar.tsx +50 -0
- package/src/ui/badge.tsx +36 -0
- package/src/ui/breadcrumb.tsx +115 -0
- package/src/ui/button.tsx +56 -0
- package/src/ui/calendar.tsx +213 -0
- package/src/ui/card.tsx +79 -0
- package/src/ui/carousel.tsx +262 -0
- package/src/ui/chart.tsx +403 -0
- package/src/ui/checkbox.tsx +30 -0
- package/src/ui/collapsible.tsx +11 -0
- package/src/ui/command.tsx +153 -0
- package/src/ui/context-menu.tsx +200 -0
- package/src/ui/dialog.tsx +130 -0
- package/src/ui/drawer.tsx +124 -0
- package/src/ui/dropdown-menu.tsx +200 -0
- package/src/ui/empty.tsx +50 -0
- package/src/ui/form.tsx +178 -0
- package/src/ui/hover-card.tsx +29 -0
- package/src/ui/index.ts +50 -0
- package/src/ui/input-otp.tsx +71 -0
- package/src/ui/input.tsx +22 -0
- package/src/ui/label.tsx +26 -0
- package/src/ui/menubar.tsx +256 -0
- package/src/ui/navigation-menu.tsx +128 -0
- package/src/ui/pagination.tsx +117 -0
- package/src/ui/popover.tsx +31 -0
- package/src/ui/progress.tsx +28 -0
- package/src/ui/radio-group.tsx +44 -0
- package/src/ui/resizable.tsx +46 -0
- package/src/ui/scroll-area.tsx +48 -0
- package/src/ui/select.tsx +160 -0
- package/src/ui/separator.tsx +31 -0
- package/src/ui/sheet.tsx +146 -0
- package/src/ui/skeleton.tsx +15 -0
- package/src/ui/slider.tsx +28 -0
- package/src/ui/sonner.tsx +45 -0
- package/src/ui/switch.tsx +29 -0
- package/src/ui/table.tsx +117 -0
- package/src/ui/tabs.tsx +55 -0
- package/src/ui/textarea.tsx +22 -0
- package/src/ui/toast.tsx +129 -0
- package/src/ui/toaster.tsx +35 -0
- package/src/ui/toggle-group.tsx +61 -0
- package/src/ui/toggle.tsx +45 -0
- package/src/ui/tooltip.tsx +32 -0
- package/tailwind.config.ts +8 -0
- package/tsconfig.json +5 -0
package/index.ts
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@arronqzy/ui",
|
|
3
|
+
"version": "0.0.0",
|
|
4
|
+
"exports": {
|
|
5
|
+
".": "./index.ts",
|
|
6
|
+
"./counter": "./components/counter.ts",
|
|
7
|
+
"./header": "./components/header.ts",
|
|
8
|
+
"./setup-counter": "./utils/counter.ts",
|
|
9
|
+
"./styles.css": "./dist/styles.css"
|
|
10
|
+
},
|
|
11
|
+
"license": "MIT",
|
|
12
|
+
"dependencies": {
|
|
13
|
+
"@hookform/resolvers": "^5.2.1",
|
|
14
|
+
"@radix-ui/react-accordion": "^1.2.12",
|
|
15
|
+
"@radix-ui/react-alert-dialog": "^1.1.15",
|
|
16
|
+
"@radix-ui/react-aspect-ratio": "^1.1.7",
|
|
17
|
+
"@radix-ui/react-avatar": "^1.1.10",
|
|
18
|
+
"@radix-ui/react-checkbox": "^1.3.2",
|
|
19
|
+
"@radix-ui/react-collapsible": "^1.1.12",
|
|
20
|
+
"@radix-ui/react-context-menu": "^2.2.15",
|
|
21
|
+
"@radix-ui/react-dialog": "^1.1.15",
|
|
22
|
+
"@radix-ui/react-dropdown-menu": "^2.1.15",
|
|
23
|
+
"@radix-ui/react-hover-card": "^1.1.15",
|
|
24
|
+
"@radix-ui/react-label": "^2.1.7",
|
|
25
|
+
"@radix-ui/react-menubar": "^1.1.15",
|
|
26
|
+
"@radix-ui/react-navigation-menu": "^1.2.14",
|
|
27
|
+
"@radix-ui/react-popover": "^1.1.15",
|
|
28
|
+
"@radix-ui/react-progress": "^1.1.7",
|
|
29
|
+
"@radix-ui/react-radio-group": "^1.3.7",
|
|
30
|
+
"@radix-ui/react-scroll-area": "^1.2.10",
|
|
31
|
+
"@radix-ui/react-select": "^2.2.5",
|
|
32
|
+
"@radix-ui/react-separator": "^1.1.7",
|
|
33
|
+
"@radix-ui/react-slider": "^1.3.5",
|
|
34
|
+
"@radix-ui/react-slot": "^1.2.3",
|
|
35
|
+
"@radix-ui/react-switch": "^1.2.5",
|
|
36
|
+
"@radix-ui/react-tabs": "^1.1.12",
|
|
37
|
+
"@radix-ui/react-toast": "^1.2.15",
|
|
38
|
+
"@radix-ui/react-toggle": "^1.1.9",
|
|
39
|
+
"@radix-ui/react-toggle-group": "^1.1.10",
|
|
40
|
+
"@radix-ui/react-tooltip": "^1.2.8",
|
|
41
|
+
"class-variance-authority": "^0.7.1",
|
|
42
|
+
"clsx": "^2.1.1",
|
|
43
|
+
"cmdk": "^1.1.1",
|
|
44
|
+
"date-fns": "^4.1.0",
|
|
45
|
+
"embla-carousel-react": "^8.6.0",
|
|
46
|
+
"input-otp": "^1.4.2",
|
|
47
|
+
"lucide-react": "^0.545.0",
|
|
48
|
+
"next-themes": "^0.4.6",
|
|
49
|
+
"react-day-picker": "^9.9.0",
|
|
50
|
+
"react": "^19",
|
|
51
|
+
"react-dom": "^19",
|
|
52
|
+
"react-hook-form": "^7.63.0",
|
|
53
|
+
"react-resizable-panels": "^3.0.5",
|
|
54
|
+
"recharts": "^3.2.1",
|
|
55
|
+
"sonner": "^2.0.7",
|
|
56
|
+
"tailwind-merge": "^2.5.5",
|
|
57
|
+
"vaul": "^1.1.2",
|
|
58
|
+
"zod": "^4.1.9"
|
|
59
|
+
},
|
|
60
|
+
"devDependencies": {
|
|
61
|
+
"@types/react": "^19.0.1",
|
|
62
|
+
"@types/react-dom": "^19.0.2",
|
|
63
|
+
"eslint": "^8.57.0",
|
|
64
|
+
"typescript": "^5.5.4",
|
|
65
|
+
"@arronqzy/eslint-config": "0.0.0",
|
|
66
|
+
"@arronqzy/typescript-config": "0.0.0",
|
|
67
|
+
"@arronqzy/tailwind": "0.0.1"
|
|
68
|
+
},
|
|
69
|
+
"scripts": {
|
|
70
|
+
"lint": "eslint \"**/*.{ts,tsx}\"",
|
|
71
|
+
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
72
|
+
"build:css": "arronqzy-tailwind -c tailwind.config.ts -i ./src/styles.css -o ./dist/styles.css",
|
|
73
|
+
"dev:css": "arronqzy-tailwind -c tailwind.config.ts -i ./src/styles.css -o ./dist/styles.css --watch",
|
|
74
|
+
"build": "pnpm run lint && pnpm run typecheck && pnpm run build:css"
|
|
75
|
+
}
|
|
76
|
+
}
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import fs from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
|
|
4
|
+
const REGISTRY_BASE = "https://ui.shadcn.com/r/styles/default";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* 说明:
|
|
8
|
+
* - 不使用 `shadcn add`,避免触发 pnpm 安装依赖(你当前 node_modules 权限有残留会失败)
|
|
9
|
+
* - 直接从 shadcn registry 拉取组件源码并写入 packages/ui/src/components/ui
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
const componentNames = [
|
|
13
|
+
"accordion",
|
|
14
|
+
"alert",
|
|
15
|
+
"alert-dialog",
|
|
16
|
+
"aspect-ratio",
|
|
17
|
+
"avatar",
|
|
18
|
+
"badge",
|
|
19
|
+
"breadcrumb",
|
|
20
|
+
"button",
|
|
21
|
+
"calendar",
|
|
22
|
+
"card",
|
|
23
|
+
"carousel",
|
|
24
|
+
"chart",
|
|
25
|
+
"checkbox",
|
|
26
|
+
"collapsible",
|
|
27
|
+
"command",
|
|
28
|
+
"context-menu",
|
|
29
|
+
"dialog",
|
|
30
|
+
"drawer",
|
|
31
|
+
"dropdown-menu",
|
|
32
|
+
"form",
|
|
33
|
+
"hover-card",
|
|
34
|
+
"input",
|
|
35
|
+
"input-otp",
|
|
36
|
+
"label",
|
|
37
|
+
"menubar",
|
|
38
|
+
"navigation-menu",
|
|
39
|
+
"pagination",
|
|
40
|
+
"popover",
|
|
41
|
+
"progress",
|
|
42
|
+
"radio-group",
|
|
43
|
+
"resizable",
|
|
44
|
+
"scroll-area",
|
|
45
|
+
"select",
|
|
46
|
+
"separator",
|
|
47
|
+
"sheet",
|
|
48
|
+
"skeleton",
|
|
49
|
+
"slider",
|
|
50
|
+
"sonner",
|
|
51
|
+
"switch",
|
|
52
|
+
"table",
|
|
53
|
+
"tabs",
|
|
54
|
+
"textarea",
|
|
55
|
+
"toast",
|
|
56
|
+
"toggle",
|
|
57
|
+
"toggle-group",
|
|
58
|
+
"tooltip",
|
|
59
|
+
// 注意:registry 里 `combobox.json` 缺失,会导致 add --all 失败;这里故意不包含 combobox
|
|
60
|
+
];
|
|
61
|
+
|
|
62
|
+
function isObject(v) {
|
|
63
|
+
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function normalizeEol(s) {
|
|
67
|
+
return s.replace(/\r\n/g, "\n");
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
async function writeFileEnsured(filePath, content) {
|
|
71
|
+
await fs.mkdir(path.dirname(filePath), { recursive: true });
|
|
72
|
+
await fs.writeFile(filePath, content, "utf8");
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
async function fetchJson(url) {
|
|
76
|
+
const res = await fetch(url);
|
|
77
|
+
if (!res.ok) {
|
|
78
|
+
const msg = await res.text().catch(() => "");
|
|
79
|
+
const err = new Error(`Fetch failed ${res.status} ${url}\n${msg}`);
|
|
80
|
+
err.status = res.status;
|
|
81
|
+
throw err;
|
|
82
|
+
}
|
|
83
|
+
return await res.json();
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function mapRegistryPathToLocal(filePath) {
|
|
87
|
+
// registry 通常是 `components/ui/*.tsx`、`lib/utils.ts` 等
|
|
88
|
+
// 我们把它统一落到 `packages/ui/src/` 下面,避免污染根目录结构
|
|
89
|
+
if (filePath.startsWith("components/")) return path.join("src", filePath);
|
|
90
|
+
if (filePath.startsWith("lib/")) return path.join("src", filePath);
|
|
91
|
+
return path.join("src", filePath);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
async function main() {
|
|
95
|
+
const root = path.resolve(process.cwd(), "packages/ui");
|
|
96
|
+
const written = new Set();
|
|
97
|
+
const exportedUiModules = new Set();
|
|
98
|
+
|
|
99
|
+
for (const name of componentNames) {
|
|
100
|
+
const url = `${REGISTRY_BASE}/${name}.json`;
|
|
101
|
+
try {
|
|
102
|
+
const item = await fetchJson(url);
|
|
103
|
+
if (!isObject(item) || !Array.isArray(item.files)) {
|
|
104
|
+
throw new Error(`Invalid registry item shape for ${name}`);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
for (const f of item.files) {
|
|
108
|
+
if (!f?.path || typeof f.path !== "string" || typeof f.content !== "string") continue;
|
|
109
|
+
const rel = mapRegistryPathToLocal(f.path);
|
|
110
|
+
const abs = path.join(root, rel);
|
|
111
|
+
await writeFileEnsured(abs, normalizeEol(f.content));
|
|
112
|
+
written.add(rel);
|
|
113
|
+
|
|
114
|
+
if (rel.startsWith("src/components/ui/") && rel.endsWith(".tsx")) {
|
|
115
|
+
const mod = "./" + path.basename(rel, ".tsx");
|
|
116
|
+
exportedUiModules.add(mod);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
// eslint-disable-next-line no-console
|
|
120
|
+
console.log(`synced: ${name}`);
|
|
121
|
+
} catch (e) {
|
|
122
|
+
// eslint-disable-next-line no-console
|
|
123
|
+
console.warn(`skip: ${name} (${e?.status ?? "err"})`);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// 生成 ui barrel:src/components/ui/index.ts
|
|
128
|
+
const uiIndexPath = path.join(root, "src/components/ui/index.ts");
|
|
129
|
+
const exports = Array.from(exportedUiModules)
|
|
130
|
+
.sort()
|
|
131
|
+
.map((m) => `export * from "${m}";`)
|
|
132
|
+
.join("\n");
|
|
133
|
+
await writeFileEnsured(uiIndexPath, exports + "\n");
|
|
134
|
+
|
|
135
|
+
// eslint-disable-next-line no-console
|
|
136
|
+
console.log(`done. files: ${written.size}`);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
main().catch((e) => {
|
|
140
|
+
// eslint-disable-next-line no-console
|
|
141
|
+
console.error(e);
|
|
142
|
+
process.exit(1);
|
|
143
|
+
});
|
|
144
|
+
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
"use client"
|
|
2
|
+
|
|
3
|
+
// Inspired by react-hot-toast library
|
|
4
|
+
import * as React from "react"
|
|
5
|
+
|
|
6
|
+
import type {
|
|
7
|
+
ToastActionElement,
|
|
8
|
+
ToastProps,
|
|
9
|
+
} from "../ui/toast.tsx"
|
|
10
|
+
|
|
11
|
+
const TOAST_LIMIT = 1
|
|
12
|
+
const TOAST_REMOVE_DELAY = 1000000
|
|
13
|
+
|
|
14
|
+
type ToasterToast = ToastProps & {
|
|
15
|
+
id: string
|
|
16
|
+
title?: React.ReactNode
|
|
17
|
+
description?: React.ReactNode
|
|
18
|
+
action?: ToastActionElement
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const actionTypes = {
|
|
22
|
+
ADD_TOAST: "ADD_TOAST",
|
|
23
|
+
UPDATE_TOAST: "UPDATE_TOAST",
|
|
24
|
+
DISMISS_TOAST: "DISMISS_TOAST",
|
|
25
|
+
REMOVE_TOAST: "REMOVE_TOAST",
|
|
26
|
+
} as const
|
|
27
|
+
|
|
28
|
+
let count = 0
|
|
29
|
+
|
|
30
|
+
function genId() {
|
|
31
|
+
count = (count + 1) % Number.MAX_SAFE_INTEGER
|
|
32
|
+
return count.toString()
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
type ActionType = typeof actionTypes
|
|
36
|
+
|
|
37
|
+
type Action =
|
|
38
|
+
| {
|
|
39
|
+
type: ActionType["ADD_TOAST"]
|
|
40
|
+
toast: ToasterToast
|
|
41
|
+
}
|
|
42
|
+
| {
|
|
43
|
+
type: ActionType["UPDATE_TOAST"]
|
|
44
|
+
toast: Partial<ToasterToast>
|
|
45
|
+
}
|
|
46
|
+
| {
|
|
47
|
+
type: ActionType["DISMISS_TOAST"]
|
|
48
|
+
toastId?: ToasterToast["id"]
|
|
49
|
+
}
|
|
50
|
+
| {
|
|
51
|
+
type: ActionType["REMOVE_TOAST"]
|
|
52
|
+
toastId?: ToasterToast["id"]
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
interface State {
|
|
56
|
+
toasts: ToasterToast[]
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const toastTimeouts = new Map<string, ReturnType<typeof setTimeout>>()
|
|
60
|
+
|
|
61
|
+
const addToRemoveQueue = (toastId: string) => {
|
|
62
|
+
if (toastTimeouts.has(toastId)) {
|
|
63
|
+
return
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const timeout = setTimeout(() => {
|
|
67
|
+
toastTimeouts.delete(toastId)
|
|
68
|
+
dispatch({
|
|
69
|
+
type: "REMOVE_TOAST",
|
|
70
|
+
toastId: toastId,
|
|
71
|
+
})
|
|
72
|
+
}, TOAST_REMOVE_DELAY)
|
|
73
|
+
|
|
74
|
+
toastTimeouts.set(toastId, timeout)
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export const reducer = (state: State, action: Action): State => {
|
|
78
|
+
switch (action.type) {
|
|
79
|
+
case "ADD_TOAST":
|
|
80
|
+
return {
|
|
81
|
+
...state,
|
|
82
|
+
toasts: [action.toast, ...state.toasts].slice(0, TOAST_LIMIT),
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
case "UPDATE_TOAST":
|
|
86
|
+
return {
|
|
87
|
+
...state,
|
|
88
|
+
toasts: state.toasts.map((t) =>
|
|
89
|
+
t.id === action.toast.id ? { ...t, ...action.toast } : t
|
|
90
|
+
),
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
case "DISMISS_TOAST": {
|
|
94
|
+
const { toastId } = action
|
|
95
|
+
|
|
96
|
+
// ! Side effects ! - This could be extracted into a dismissToast() action,
|
|
97
|
+
// but I'll keep it here for simplicity
|
|
98
|
+
if (toastId) {
|
|
99
|
+
addToRemoveQueue(toastId)
|
|
100
|
+
} else {
|
|
101
|
+
state.toasts.forEach((toast) => {
|
|
102
|
+
addToRemoveQueue(toast.id)
|
|
103
|
+
})
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
return {
|
|
107
|
+
...state,
|
|
108
|
+
toasts: state.toasts.map((t) =>
|
|
109
|
+
t.id === toastId || toastId === undefined
|
|
110
|
+
? {
|
|
111
|
+
...t,
|
|
112
|
+
open: false,
|
|
113
|
+
}
|
|
114
|
+
: t
|
|
115
|
+
),
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
case "REMOVE_TOAST":
|
|
119
|
+
if (action.toastId === undefined) {
|
|
120
|
+
return {
|
|
121
|
+
...state,
|
|
122
|
+
toasts: [],
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
return {
|
|
126
|
+
...state,
|
|
127
|
+
toasts: state.toasts.filter((t) => t.id !== action.toastId),
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
const listeners: Array<(state: State) => void> = []
|
|
133
|
+
|
|
134
|
+
let memoryState: State = { toasts: [] }
|
|
135
|
+
|
|
136
|
+
function dispatch(action: Action) {
|
|
137
|
+
memoryState = reducer(memoryState, action)
|
|
138
|
+
listeners.forEach((listener) => {
|
|
139
|
+
listener(memoryState)
|
|
140
|
+
})
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
type Toast = Omit<ToasterToast, "id">
|
|
144
|
+
|
|
145
|
+
function toast({ ...props }: Toast) {
|
|
146
|
+
const id = genId()
|
|
147
|
+
|
|
148
|
+
const update = (props: ToasterToast) =>
|
|
149
|
+
dispatch({
|
|
150
|
+
type: "UPDATE_TOAST",
|
|
151
|
+
toast: { ...props, id },
|
|
152
|
+
})
|
|
153
|
+
const dismiss = () => dispatch({ type: "DISMISS_TOAST", toastId: id })
|
|
154
|
+
|
|
155
|
+
dispatch({
|
|
156
|
+
type: "ADD_TOAST",
|
|
157
|
+
toast: {
|
|
158
|
+
...props,
|
|
159
|
+
id,
|
|
160
|
+
open: true,
|
|
161
|
+
onOpenChange: (open) => {
|
|
162
|
+
if (!open) dismiss()
|
|
163
|
+
},
|
|
164
|
+
},
|
|
165
|
+
})
|
|
166
|
+
|
|
167
|
+
return {
|
|
168
|
+
id: id,
|
|
169
|
+
dismiss,
|
|
170
|
+
update,
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
function useToast() {
|
|
175
|
+
const [state, setState] = React.useState<State>(memoryState)
|
|
176
|
+
|
|
177
|
+
React.useEffect(() => {
|
|
178
|
+
listeners.push(setState)
|
|
179
|
+
return () => {
|
|
180
|
+
const index = listeners.indexOf(setState)
|
|
181
|
+
if (index > -1) {
|
|
182
|
+
listeners.splice(index, 1)
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
}, [state])
|
|
186
|
+
|
|
187
|
+
return {
|
|
188
|
+
...state,
|
|
189
|
+
toast,
|
|
190
|
+
dismiss: (toastId?: string) => dispatch({ type: "DISMISS_TOAST", toastId }),
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
export { useToast, toast }
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { CSSProperties } from "react";
|
|
2
|
+
|
|
3
|
+
/** 弹窗层级:高于画布 Ruler(999)、工具栏(1200)、Menubar(10100) 等 */
|
|
4
|
+
export const MODAL_Z_INDEX = 20000;
|
|
5
|
+
export const MODAL_CONTENT_Z_INDEX = 20001;
|
|
6
|
+
|
|
7
|
+
export const modalOverlayStyle: CSSProperties = { zIndex: MODAL_Z_INDEX };
|
|
8
|
+
export const modalContentStyle: CSSProperties = { zIndex: MODAL_CONTENT_Z_INDEX };
|
package/src/lib/utils.ts
ADDED
package/src/styles.css
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
@tailwind base;
|
|
2
|
+
@tailwind components;
|
|
3
|
+
@tailwind utilities;
|
|
4
|
+
|
|
5
|
+
@layer base {
|
|
6
|
+
:root {
|
|
7
|
+
--background: 0 0% 100%;
|
|
8
|
+
--foreground: 222.2 84% 4.9%;
|
|
9
|
+
|
|
10
|
+
--card: 0 0% 100%;
|
|
11
|
+
--card-foreground: 222.2 84% 4.9%;
|
|
12
|
+
|
|
13
|
+
--popover: 0 0% 100%;
|
|
14
|
+
--popover-foreground: 222.2 84% 4.9%;
|
|
15
|
+
|
|
16
|
+
--primary: 222.2 47.4% 11.2%;
|
|
17
|
+
--primary-foreground: 210 40% 98%;
|
|
18
|
+
|
|
19
|
+
--secondary: 210 40% 96.1%;
|
|
20
|
+
--secondary-foreground: 222.2 47.4% 11.2%;
|
|
21
|
+
|
|
22
|
+
--muted: 210 40% 96.1%;
|
|
23
|
+
--muted-foreground: 215.4 16.3% 46.9%;
|
|
24
|
+
|
|
25
|
+
--accent: 210 40% 96.1%;
|
|
26
|
+
--accent-foreground: 222.2 47.4% 11.2%;
|
|
27
|
+
|
|
28
|
+
--destructive: 0 84.2% 60.2%;
|
|
29
|
+
--destructive-foreground: 210 40% 98%;
|
|
30
|
+
|
|
31
|
+
--border: 214.3 31.8% 91.4%;
|
|
32
|
+
--input: 214.3 31.8% 91.4%;
|
|
33
|
+
--ring: 222.2 84% 4.9%;
|
|
34
|
+
|
|
35
|
+
--radius: 0.5rem;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
.dark {
|
|
39
|
+
--background: 222.2 84% 4.9%;
|
|
40
|
+
--foreground: 210 40% 98%;
|
|
41
|
+
|
|
42
|
+
--card: 222.2 84% 4.9%;
|
|
43
|
+
--card-foreground: 210 40% 98%;
|
|
44
|
+
|
|
45
|
+
--popover: 222.2 84% 4.9%;
|
|
46
|
+
--popover-foreground: 210 40% 98%;
|
|
47
|
+
|
|
48
|
+
--primary: 210 40% 98%;
|
|
49
|
+
--primary-foreground: 222.2 47.4% 11.2%;
|
|
50
|
+
|
|
51
|
+
--secondary: 217.2 32.6% 17.5%;
|
|
52
|
+
--secondary-foreground: 210 40% 98%;
|
|
53
|
+
|
|
54
|
+
--muted: 217.2 32.6% 17.5%;
|
|
55
|
+
--muted-foreground: 215 20.2% 65.1%;
|
|
56
|
+
|
|
57
|
+
--accent: 217.2 32.6% 17.5%;
|
|
58
|
+
--accent-foreground: 210 40% 98%;
|
|
59
|
+
|
|
60
|
+
--destructive: 0 62.8% 30.6%;
|
|
61
|
+
--destructive-foreground: 210 40% 98%;
|
|
62
|
+
|
|
63
|
+
--border: 217.2 32.6% 17.5%;
|
|
64
|
+
--input: 217.2 32.6% 17.5%;
|
|
65
|
+
--ring: 212.7 26.8% 83.9%;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
* {
|
|
69
|
+
@apply border-border;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
body {
|
|
73
|
+
@apply bg-background text-foreground;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/* 弹窗蒙层全屏覆盖,层级高于画布 Ruler / 工具栏 */
|
|
78
|
+
[data-radix-dialog-overlay],
|
|
79
|
+
[data-radix-alert-dialog-overlay],
|
|
80
|
+
[data-vaul-overlay] {
|
|
81
|
+
z-index: 20000 !important;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
[data-radix-dialog-content],
|
|
85
|
+
[data-radix-alert-dialog-content],
|
|
86
|
+
[data-vaul-drawer-wrapper] {
|
|
87
|
+
z-index: 20001 !important;
|
|
88
|
+
}
|
|
89
|
+
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import { ThemeProvider as NextThemesProvider } from "next-themes";
|
|
5
|
+
import type { ThemeProviderProps } from "next-themes";
|
|
6
|
+
|
|
7
|
+
export type AppTheme = "light" | "dark";
|
|
8
|
+
|
|
9
|
+
export type ArronqzyThemeProviderProps = Omit<
|
|
10
|
+
ThemeProviderProps,
|
|
11
|
+
"attribute" | "defaultTheme" | "enableSystem"
|
|
12
|
+
> & {
|
|
13
|
+
defaultTheme?: AppTheme;
|
|
14
|
+
enableSystem?: boolean;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export function ThemeProvider({
|
|
18
|
+
children,
|
|
19
|
+
defaultTheme = "dark",
|
|
20
|
+
enableSystem = true,
|
|
21
|
+
...props
|
|
22
|
+
}: ArronqzyThemeProviderProps) {
|
|
23
|
+
return (
|
|
24
|
+
<NextThemesProvider
|
|
25
|
+
attribute="class"
|
|
26
|
+
defaultTheme={defaultTheme}
|
|
27
|
+
enableSystem={enableSystem}
|
|
28
|
+
{...props}
|
|
29
|
+
>
|
|
30
|
+
{children}
|
|
31
|
+
</NextThemesProvider>
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export { useTheme } from "next-themes";
|
|
36
|
+
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"use client"
|
|
2
|
+
|
|
3
|
+
import * as React from "react"
|
|
4
|
+
import * as AccordionPrimitive from "@radix-ui/react-accordion"
|
|
5
|
+
import { ChevronDown } from "lucide-react"
|
|
6
|
+
|
|
7
|
+
import { cn } from "../lib/utils"
|
|
8
|
+
|
|
9
|
+
const Accordion = AccordionPrimitive.Root
|
|
10
|
+
|
|
11
|
+
const AccordionItem = React.forwardRef<
|
|
12
|
+
React.ElementRef<typeof AccordionPrimitive.Item>,
|
|
13
|
+
React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Item>
|
|
14
|
+
>(({ className, ...props }, ref) => (
|
|
15
|
+
<AccordionPrimitive.Item
|
|
16
|
+
ref={ref}
|
|
17
|
+
className={cn("border-b", className)}
|
|
18
|
+
{...props}
|
|
19
|
+
/>
|
|
20
|
+
))
|
|
21
|
+
AccordionItem.displayName = "AccordionItem"
|
|
22
|
+
|
|
23
|
+
const AccordionTrigger = React.forwardRef<
|
|
24
|
+
React.ElementRef<typeof AccordionPrimitive.Trigger>,
|
|
25
|
+
React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Trigger>
|
|
26
|
+
>(({ className, children, ...props }, ref) => (
|
|
27
|
+
<AccordionPrimitive.Header className="flex">
|
|
28
|
+
<AccordionPrimitive.Trigger
|
|
29
|
+
ref={ref}
|
|
30
|
+
className={cn(
|
|
31
|
+
"flex flex-1 items-center justify-between py-4 font-medium transition-all hover:underline [&[data-state=open]>svg]:rotate-180",
|
|
32
|
+
className
|
|
33
|
+
)}
|
|
34
|
+
{...props}
|
|
35
|
+
>
|
|
36
|
+
{children}
|
|
37
|
+
<ChevronDown className="h-4 w-4 shrink-0 transition-transform duration-200" />
|
|
38
|
+
</AccordionPrimitive.Trigger>
|
|
39
|
+
</AccordionPrimitive.Header>
|
|
40
|
+
))
|
|
41
|
+
AccordionTrigger.displayName = AccordionPrimitive.Trigger.displayName
|
|
42
|
+
|
|
43
|
+
const AccordionContent = React.forwardRef<
|
|
44
|
+
React.ElementRef<typeof AccordionPrimitive.Content>,
|
|
45
|
+
React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Content>
|
|
46
|
+
>(({ className, children, ...props }, ref) => (
|
|
47
|
+
<AccordionPrimitive.Content
|
|
48
|
+
ref={ref}
|
|
49
|
+
className="overflow-hidden text-sm transition-all data-[state=closed]:animate-accordion-up data-[state=open]:animate-accordion-down"
|
|
50
|
+
{...props}
|
|
51
|
+
>
|
|
52
|
+
<div className={cn("pb-4 pt-0", className)}>{children}</div>
|
|
53
|
+
</AccordionPrimitive.Content>
|
|
54
|
+
))
|
|
55
|
+
|
|
56
|
+
AccordionContent.displayName = AccordionPrimitive.Content.displayName
|
|
57
|
+
|
|
58
|
+
export { Accordion, AccordionItem, AccordionTrigger, AccordionContent }
|