@usequark/quark-create-app 1.24.2 → 1.24.3
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/package.json +1 -1
- package/templates/base-project/scripts/check-standards.mjs +43 -0
- package/templates/base-project/scripts/run-tests.mjs +5 -2
- package/templates/ui/src/badge.js +2 -2
- package/templates/ui/src/button.js +1 -1
- package/templates/ui/src/card.js +7 -7
- package/templates/ui/src/checkbox.js +2 -2
- package/templates/ui/src/container.js +1 -1
- package/templates/ui/src/dialog.js +5 -5
- package/templates/ui/src/error-banner.js +1 -1
- package/templates/ui/src/footer.js +9 -9
- package/templates/ui/src/form-field.js +1 -1
- package/templates/ui/src/input.js +2 -2
- package/templates/ui/src/label.js +1 -1
- package/templates/ui/src/lightbox.js +6 -6
- package/templates/ui/src/navbar.js +19 -19
- package/templates/ui/src/password-input.js +1 -1
- package/templates/ui/src/rich-text.js +8 -8
- package/templates/ui/src/select.js +10 -10
- package/templates/ui/src/skeleton.js +1 -1
- package/templates/ui/src/table.js +7 -7
- package/templates/ui/src/textarea.js +1 -1
- package/templates/ui/src/toast.js +3 -3
package/package.json
CHANGED
|
@@ -15,6 +15,38 @@ const tsExtensions = new Set([".ts", ".tsx"]);
|
|
|
15
15
|
const throwNewErrorPattern = /\bthrow new Error\s*\(/;
|
|
16
16
|
const consolePattern = /\bconsole\.(?:log|warn|error|info)\s*\(/;
|
|
17
17
|
|
|
18
|
+
/**
|
|
19
|
+
* Tailwind v4 removed the bare `[--var]` shorthand that v3 accepted. Under v4 a
|
|
20
|
+
* class such as `text-[--navbar-text-muted]` is still a *valid* utility name, so
|
|
21
|
+
* Tailwind emits a rule for it - but the declaration body is the bare token
|
|
22
|
+
* `color: --navbar-text-muted`, which is not a valid CSS value. The browser
|
|
23
|
+
* discards the declaration and the element silently inherits instead.
|
|
24
|
+
*
|
|
25
|
+
* Nothing warns: the build exits 0 and the rule is present in the stylesheet, so
|
|
26
|
+
* the breakage is only visible by rendering both themes and reading computed
|
|
27
|
+
* styles. In light mode `body` sets no colour and the inherited default happens
|
|
28
|
+
* to be black, which reads as "working".
|
|
29
|
+
*
|
|
30
|
+
* The v4 forms are `text-(--navbar-text-muted)` or, when the utility namespace
|
|
31
|
+
* would be ambiguous (e.g. `text-` shared between colour and font-size),
|
|
32
|
+
* `text-[color:var(--navbar-text-muted)]`.
|
|
33
|
+
*
|
|
34
|
+
* The pattern matches the *shape* of the v3 shorthand rather than an
|
|
35
|
+
* enumerated list of utilities. An earlier version listed the colour, border and
|
|
36
|
+
* radius families explicitly, which was a false economy: the same mistake is
|
|
37
|
+
* equally reachable through `w-[--panel-width]`, `leading-[--line-height]` or
|
|
38
|
+
* `p-[--gutter]`, and any list has to be extended every time someone reaches
|
|
39
|
+
* for a family it omits.
|
|
40
|
+
*
|
|
41
|
+
* The `-` immediately before `[` is what separates this from ordinary
|
|
42
|
+
* JavaScript. `rows[--i]` (decrement-then-index) and `obj[key--1]` have no
|
|
43
|
+
* hyphen there and do not match. The one shape that is indistinguishable from a
|
|
44
|
+
* real class is `<ident>-[--ident]`, which would require JavaScript that
|
|
45
|
+
* subtracts from a decrement expression - it does not occur in this codebase.
|
|
46
|
+
*/
|
|
47
|
+
const tailwindV3VarPattern =
|
|
48
|
+
/(?:^|[\s"'`(])(?:[a-z][a-z0-9-]*:)*[a-z][a-z0-9-]*-\[--[a-zA-Z][a-zA-Z0-9-]*\]/;
|
|
49
|
+
|
|
18
50
|
const consoleAllowlist = [
|
|
19
51
|
/^packages\/config\/src\/validate-env\.js$/,
|
|
20
52
|
/^packages\/core\/src\/testing\//,
|
|
@@ -159,6 +191,17 @@ async function main() {
|
|
|
159
191
|
}
|
|
160
192
|
}
|
|
161
193
|
|
|
194
|
+
if (isSourceFile(relativePath)) {
|
|
195
|
+
for (const lineNumber of findMatchingLines(
|
|
196
|
+
content,
|
|
197
|
+
tailwindV3VarPattern,
|
|
198
|
+
)) {
|
|
199
|
+
violations.push(
|
|
200
|
+
`${relativePath}:${lineNumber}: Tailwind v4 ignores the v3 \`[--var]\` shorthand - the utility is emitted with an invalid value and silently does nothing. Use \`utility-(--var)\`, or \`utility-[color:var(--var)]\` when the namespace is ambiguous.`,
|
|
201
|
+
);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
162
205
|
if (
|
|
163
206
|
isSourceFile(relativePath) &&
|
|
164
207
|
!isTestFile(relativePath) &&
|
|
@@ -50,8 +50,11 @@ function collectTests(targetPath) {
|
|
|
50
50
|
const files = roots.flatMap((rootPath) => collectTests(path.resolve(rootPath)));
|
|
51
51
|
|
|
52
52
|
if (files.length === 0) {
|
|
53
|
-
|
|
54
|
-
|
|
53
|
+
// An empty suite is not a failure. `node --test` exits 0 when it matches no
|
|
54
|
+
// files, so exiting 1 here made a freshly scaffolded project fail its own
|
|
55
|
+
// `pnpm test` and therefore its pre-push hook.
|
|
56
|
+
console.log(`No test files found in: ${roots.join(", ")} - nothing to run.`);
|
|
57
|
+
process.exit(0);
|
|
55
58
|
}
|
|
56
59
|
|
|
57
60
|
const result = spawnSync(
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
|
|
3
3
|
const base =
|
|
4
|
-
"inline-flex items-center justify-center border font-medium bg-
|
|
4
|
+
"inline-flex items-center justify-center border font-medium bg-(--badge-bg) border-(--badge-border) text-(--badge-text)";
|
|
5
5
|
|
|
6
6
|
export function Badge({ variant = "default", className = "", ...props }) {
|
|
7
|
-
const cls = `${base} rounded-
|
|
7
|
+
const cls = `${base} rounded-(--radius-default) ${className}`.trim();
|
|
8
8
|
return React.createElement("span", {
|
|
9
9
|
"data-badge-variant": variant,
|
|
10
10
|
className: cls,
|
|
@@ -6,7 +6,7 @@ const base =
|
|
|
6
6
|
"inline-flex items-center justify-center font-medium tracking-wide transition-all duration-200 linear cursor-pointer focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-1 disabled:opacity-40 disabled:cursor-not-allowed active:opacity-80";
|
|
7
7
|
|
|
8
8
|
const variantCls =
|
|
9
|
-
"bg-
|
|
9
|
+
"bg-(--btn-bg) border border-(--btn-border) text-(--btn-text) rounded-(--btn-radius) hover:brightness-[var(--btn-hover-brightness)] hover:shadow-[var(--btn-hover-shadow)] hover:bg-[var(--btn-hover-bg)] hover:text-[var(--btn-hover-text)] hover:opacity-[var(--btn-hover-opacity)] focus-visible:ring-[var(--btn-ring)]";
|
|
10
10
|
|
|
11
11
|
const sizes = {
|
|
12
12
|
sm: "h-8 px-3 text-sm",
|
package/templates/ui/src/card.js
CHANGED
|
@@ -4,19 +4,19 @@ import { ChevronDown } from "lucide-react";
|
|
|
4
4
|
import React, { useState } from "react";
|
|
5
5
|
|
|
6
6
|
const cardCls =
|
|
7
|
-
"border border-
|
|
7
|
+
"border border-(--card-border) bg-(--card-bg) transition-colors duration-200 linear";
|
|
8
8
|
|
|
9
9
|
const headerCls = "flex flex-col space-y-1.5 p-6";
|
|
10
10
|
|
|
11
11
|
const titleCls =
|
|
12
|
-
"text-lg font-bold leading-none tracking-tight text-
|
|
12
|
+
"text-lg font-bold leading-none tracking-tight text-(--card-title-text)";
|
|
13
13
|
|
|
14
14
|
const contentCls = "p-6 pt-0";
|
|
15
15
|
|
|
16
16
|
const footerCls = "flex items-center p-6 pt-0";
|
|
17
17
|
|
|
18
18
|
const collapsibleTriggerCls =
|
|
19
|
-
"flex w-full cursor-pointer items-center justify-between p-6 text-
|
|
19
|
+
"flex w-full cursor-pointer items-center justify-between p-6 text-(--card-title-text) transition-colors duration-200 hover:bg-(--card-trigger-hover-bg) focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--card-trigger-ring)]";
|
|
20
20
|
|
|
21
21
|
function CollapsibleCard({
|
|
22
22
|
className = "",
|
|
@@ -31,7 +31,7 @@ function CollapsibleCard({
|
|
|
31
31
|
"div",
|
|
32
32
|
{
|
|
33
33
|
className:
|
|
34
|
-
`${cardCls} h-fit self-start rounded-
|
|
34
|
+
`${cardCls} h-fit self-start rounded-(--radius-default) ${className}`.trim(),
|
|
35
35
|
...props,
|
|
36
36
|
},
|
|
37
37
|
React.createElement(
|
|
@@ -51,7 +51,7 @@ function CollapsibleCard({
|
|
|
51
51
|
"span",
|
|
52
52
|
{
|
|
53
53
|
"aria-hidden": "true",
|
|
54
|
-
className: `pointer-events-none ml-3 shrink-0 text-
|
|
54
|
+
className: `pointer-events-none ml-3 shrink-0 text-(--card-text-muted) transition-transform duration-300 ease-[cubic-bezier(0.4,0,0.2,1)] ${isOpen ? "rotate-180" : "rotate-0"}`,
|
|
55
55
|
},
|
|
56
56
|
React.createElement(ChevronDown, { size: 16 }),
|
|
57
57
|
),
|
|
@@ -59,7 +59,7 @@ function CollapsibleCard({
|
|
|
59
59
|
React.createElement(
|
|
60
60
|
"div",
|
|
61
61
|
{
|
|
62
|
-
className: `border-t border-
|
|
62
|
+
className: `border-t border-(--card-border) text-(--card-text-muted) grid transition-[grid-template-rows,opacity,transform] duration-300 ease-[cubic-bezier(0.4,0,0.2,1)] motion-reduce:transition-none ${isOpen ? "translate-y-0 opacity-100" : "-translate-y-2 opacity-0"}`,
|
|
63
63
|
style: { gridTemplateRows: isOpen ? "1fr" : "0fr" },
|
|
64
64
|
},
|
|
65
65
|
React.createElement(
|
|
@@ -92,7 +92,7 @@ export function Card({
|
|
|
92
92
|
return React.createElement(
|
|
93
93
|
"div",
|
|
94
94
|
{
|
|
95
|
-
className: `${cardCls} rounded-
|
|
95
|
+
className: `${cardCls} rounded-(--radius-default) ${className}`.trim(),
|
|
96
96
|
...props,
|
|
97
97
|
},
|
|
98
98
|
children,
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
|
|
3
3
|
const inputCls =
|
|
4
|
-
"h-4 w-4 rounded border-
|
|
4
|
+
"h-4 w-4 rounded border-(--checkbox-border) bg-(--checkbox-bg) accent-(--checkbox-accent) transition-colors cursor-pointer focus-visible:ring-2 focus-visible:ring-[var(--checkbox-ring)] disabled:cursor-not-allowed disabled:opacity-[var(--checkbox-disabled-opacity)]";
|
|
5
5
|
|
|
6
|
-
const labelCls = "text-sm text-
|
|
6
|
+
const labelCls = "text-sm text-(--checkbox-label-text) select-none";
|
|
7
7
|
|
|
8
8
|
export function Checkbox({ id, label, className = "", ...props }) {
|
|
9
9
|
return React.createElement(
|
|
@@ -5,7 +5,7 @@ export function Container({ className = "", children, ...props }) {
|
|
|
5
5
|
"section",
|
|
6
6
|
{
|
|
7
7
|
className:
|
|
8
|
-
`relative overflow-hidden rounded-
|
|
8
|
+
`relative overflow-hidden rounded-(--radius-default) border border-(--container-border) bg-(--container-bg) ${className}`.trim(),
|
|
9
9
|
...props,
|
|
10
10
|
},
|
|
11
11
|
children,
|
|
@@ -28,18 +28,18 @@ import React, {
|
|
|
28
28
|
*/
|
|
29
29
|
|
|
30
30
|
const dialogCls =
|
|
31
|
-
"backdrop:bg-[var(--dialog-backdrop)] border border-
|
|
31
|
+
"backdrop:bg-[var(--dialog-backdrop)] border border-(--dialog-border) bg-(--dialog-bg) p-0 w-full max-w-lg rounded-(--radius-default)";
|
|
32
32
|
|
|
33
33
|
const headerCls =
|
|
34
|
-
"flex items-center justify-between border-b border-
|
|
34
|
+
"flex items-center justify-between border-b border-(--dialog-border) px-5 py-4";
|
|
35
35
|
|
|
36
36
|
const titleCls =
|
|
37
|
-
"text-base font-bold tracking-tight text-
|
|
37
|
+
"text-base font-bold tracking-tight text-(--dialog-title-text)";
|
|
38
38
|
|
|
39
39
|
const closeCls =
|
|
40
|
-
"flex h-8 w-8 cursor-pointer items-center justify-center text-lg text-
|
|
40
|
+
"flex h-8 w-8 cursor-pointer items-center justify-center text-lg text-(--dialog-text-muted) transition-colors duration-200 linear hover:text-(--dialog-title-text) hover:bg-(--dialog-close-hover-bg) active:bg-(--dialog-close-hover-bg) focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--dialog-close-ring)] rounded-(--radius-default)";
|
|
41
41
|
|
|
42
|
-
const bodyCls = "px-5 py-4 text-
|
|
42
|
+
const bodyCls = "px-5 py-4 text-(--dialog-text-muted)";
|
|
43
43
|
|
|
44
44
|
export function Dialog({ open, onClose, title, children, className = "" }) {
|
|
45
45
|
const ref = useRef(null);
|
|
@@ -8,7 +8,7 @@ export function ErrorBanner({ message, className = "" }) {
|
|
|
8
8
|
role: "alert",
|
|
9
9
|
"aria-live": "polite",
|
|
10
10
|
className:
|
|
11
|
-
`mb-4 border border-
|
|
11
|
+
`mb-4 border border-(--error-border) bg-(--error-bg) px-3 py-2 text-sm text-(--error-text) rounded-(--radius-default) ${className}`.trim(),
|
|
12
12
|
},
|
|
13
13
|
message,
|
|
14
14
|
);
|
|
@@ -1,24 +1,24 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
|
|
3
|
-
const footerCls = "border-t border-
|
|
3
|
+
const footerCls = "border-t border-(--footer-border) bg-(--footer-bg)";
|
|
4
4
|
const containerCls = "mx-auto";
|
|
5
5
|
const topGridCls =
|
|
6
6
|
"grid gap-8 sm:gap-10 md:grid-cols-2 lg:grid-cols-[minmax(0,1.45fr)_minmax(0,1fr)_minmax(0,1fr)_minmax(0,1fr)]";
|
|
7
7
|
const brandRowCls = "flex items-center gap-3";
|
|
8
8
|
const markCls =
|
|
9
|
-
"flex shrink-0 items-center justify-center rounded-2xl bg-
|
|
9
|
+
"flex shrink-0 items-center justify-center rounded-2xl bg-(--footer-mark-bg) font-bold text-(--footer-mark-text)";
|
|
10
10
|
const brandNameCls =
|
|
11
|
-
"text-2xl font-bold tracking-tight text-
|
|
12
|
-
const brandTextCls = "max-w-md text-sm leading-7 text-
|
|
11
|
+
"text-2xl font-bold tracking-tight text-(--footer-text) sm:text-3xl";
|
|
12
|
+
const brandTextCls = "max-w-md text-sm leading-7 text-(--footer-text-muted)";
|
|
13
13
|
const ctaCls =
|
|
14
|
-
"inline-flex w-full items-center justify-center rounded-full border border-
|
|
15
|
-
const columnTitleCls = "mb-4 font-semibold text-
|
|
14
|
+
"inline-flex w-full items-center justify-center rounded-full border border-(--footer-cta-border) font-semibold text-(--footer-mark-text) transition-colors hover:bg-(--footer-cta-hover-bg) sm:w-auto";
|
|
15
|
+
const columnTitleCls = "mb-4 font-semibold text-(--footer-text-faint)";
|
|
16
16
|
const columnListCls = "space-y-2.5";
|
|
17
17
|
const linkCls =
|
|
18
|
-
"break-words text-
|
|
19
|
-
const textItemCls = "break-words text-
|
|
18
|
+
"break-words text-(--footer-text-muted) transition-colors hover:text-(--footer-link-hover)";
|
|
19
|
+
const textItemCls = "break-words text-(--footer-text-muted)";
|
|
20
20
|
const bottomBarCls =
|
|
21
|
-
"mt-8 border-t border-
|
|
21
|
+
"mt-8 border-t border-(--footer-border) pt-5 flex flex-col gap-3 text-sm text-(--footer-text-faint) sm:mt-10 sm:pt-6 lg:flex-row lg:items-center lg:justify-between";
|
|
22
22
|
const legalCls = "flex flex-wrap items-center gap-2 sm:gap-3";
|
|
23
23
|
const sepCls = "text-[var(--footer-sep)]";
|
|
24
24
|
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
|
|
3
3
|
const base =
|
|
4
|
-
"block h-10 w-full border border-
|
|
4
|
+
"block h-10 w-full border border-(--input-border) bg-(--input-bg) px-3 text-sm text-(--input-text) placeholder:text-(--input-placeholder) transition-colors duration-200 linear hover:border-(--input-border-hover) focus-visible:border-(--input-border-focus) focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--input-ring-focus)] disabled:opacity-(--input-disabled-opacity) disabled:cursor-not-allowed";
|
|
5
5
|
|
|
6
6
|
export function Input({ className = "", ...props }) {
|
|
7
7
|
return React.createElement("input", {
|
|
8
|
-
className: `${base} rounded-
|
|
8
|
+
className: `${base} rounded-(--radius-default) ${className}`.trim(),
|
|
9
9
|
...props,
|
|
10
10
|
});
|
|
11
11
|
}
|
|
@@ -3,16 +3,16 @@ import { ChevronLeft, ChevronRight, X } from "lucide-react";
|
|
|
3
3
|
import React, { useEffect, useRef, useState } from "react";
|
|
4
4
|
|
|
5
5
|
const BACKDROP_CLS =
|
|
6
|
-
"absolute inset-0 z-0 bg-
|
|
6
|
+
"absolute inset-0 z-0 bg-(--lightbox-backdrop) px-3 py-4 transition-opacity duration-200 ease-out sm:px-6 sm:py-8 cursor-pointer";
|
|
7
7
|
const DIALOG_CLS =
|
|
8
8
|
"relative z-10 mx-auto flex h-full w-full max-w-6xl flex-col p-3 transition-all duration-200 ease-out sm:p-5";
|
|
9
9
|
const NAV_BTN_CLS =
|
|
10
|
-
"inline-flex items-center gap-1.5 rounded-
|
|
10
|
+
"inline-flex items-center gap-1.5 rounded-(--radius-default) border border-(--lightbox-btn-border) px-3 py-1.5 text-sm font-medium text-(--lightbox-btn-text) transition-colors duration-200 hover:bg-(--lightbox-btn-hover-bg) focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--lightbox-btn-ring)] cursor-pointer";
|
|
11
11
|
const CLOSE_BTN_CLS =
|
|
12
|
-
"rounded-
|
|
12
|
+
"rounded-(--radius-default) border border-(--lightbox-btn-border) font-medium text-(--lightbox-btn-text) transition-colors duration-200 hover:bg-(--lightbox-btn-hover-bg) focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--lightbox-btn-ring)] flex items-center cursor-pointer";
|
|
13
13
|
|
|
14
14
|
const IMG_CLS =
|
|
15
|
-
"max-h-[72vh] w-auto max-w-full rounded-
|
|
15
|
+
"max-h-[72vh] w-auto max-w-full rounded-(--radius-default) object-contain transition-all duration-200 ease-out";
|
|
16
16
|
|
|
17
17
|
export function Lightbox({
|
|
18
18
|
src,
|
|
@@ -129,7 +129,7 @@ export function Lightbox({
|
|
|
129
129
|
"p",
|
|
130
130
|
{
|
|
131
131
|
key: "caption",
|
|
132
|
-
className: "mt-3 text-sm leading-6 text-
|
|
132
|
+
className: "mt-3 text-sm leading-6 text-(--lightbox-caption-text)",
|
|
133
133
|
},
|
|
134
134
|
caption,
|
|
135
135
|
),
|
|
@@ -169,7 +169,7 @@ export function Lightbox({
|
|
|
169
169
|
"p",
|
|
170
170
|
{
|
|
171
171
|
key: "counter",
|
|
172
|
-
className: "text-center text-
|
|
172
|
+
className: "text-center text-(--lightbox-counter-text)",
|
|
173
173
|
style: {
|
|
174
174
|
minWidth: "var(--lightbox-counter-min-width)",
|
|
175
175
|
fontSize: "var(--lightbox-counter-font-size)",
|
|
@@ -2,47 +2,47 @@
|
|
|
2
2
|
import React, { useEffect, useMemo, useRef, useState } from "react";
|
|
3
3
|
|
|
4
4
|
const shellCls =
|
|
5
|
-
"relative w-full border-b border-
|
|
5
|
+
"relative w-full border-b border-(--navbar-border) bg-(--navbar-bg) shadow-[var(--navbar-inset-shadow)] backdrop-blur";
|
|
6
6
|
const mobileShellCls =
|
|
7
|
-
"relative w-full border-b border-
|
|
7
|
+
"relative w-full border-b border-(--navbar-border) bg-(--navbar-mobile-bg) shadow-[var(--navbar-inset-shadow)]";
|
|
8
8
|
const mobileShellOpenCls =
|
|
9
|
-
"relative w-full border-b border-transparent bg-
|
|
9
|
+
"relative w-full border-b border-transparent bg-(--navbar-mobile-bg) shadow-[var(--navbar-inset-shadow)]";
|
|
10
10
|
const containerCls = "mx-auto w-full px-4 sm:px-6 lg:px-8";
|
|
11
11
|
const desktopInnerCls = "flex h-[4.5rem] items-center justify-center gap-6";
|
|
12
12
|
const leftZoneCls = "flex items-center mr-auto";
|
|
13
13
|
const rightZoneCls = "flex items-center justify-end ml-auto";
|
|
14
14
|
const logoCls =
|
|
15
|
-
"inline-flex items-center gap-2.5 rounded-
|
|
15
|
+
"inline-flex items-center gap-2.5 rounded-(--radius-default) px-1.5 py-1 font-semibold tracking-wide text-(--navbar-text) transition-colors hover:text-(--navbar-logo-hover)";
|
|
16
16
|
const markCls =
|
|
17
|
-
"inline-flex h-8 w-8 items-center justify-center rounded-
|
|
17
|
+
"inline-flex h-8 w-8 items-center justify-center rounded-(--radius-default) border border-(--navbar-mark-border) bg-(--navbar-mark-bg) font-bold text-(--navbar-mark-text)";
|
|
18
18
|
const centerNavCls = "flex min-w-0 justify-center";
|
|
19
19
|
const desktopListCls = "flex items-center gap-3";
|
|
20
20
|
const desktopLinkCls =
|
|
21
|
-
"inline-flex h-10 items-center rounded-
|
|
21
|
+
"inline-flex h-10 items-center rounded-(--radius-default) px-3.5 font-medium text-(--navbar-text-muted) transition-colors hover:bg-(--navbar-hover-bg) hover:text-(--navbar-hover-text)";
|
|
22
22
|
|
|
23
23
|
const desktopDropdownWrapCls =
|
|
24
|
-
"group inline-flex cursor-pointer items-center rounded-
|
|
24
|
+
"group inline-flex cursor-pointer items-center rounded-(--radius-default) transition-colors hover:bg-(--navbar-hover-bg)";
|
|
25
25
|
const desktopDropdownLinkCls =
|
|
26
|
-
"flex items-center font-medium text-
|
|
26
|
+
"flex items-center font-medium text-(--navbar-text-muted) transition-colors group-hover:text-(--navbar-hover-text)";
|
|
27
27
|
const desktopDropdownChevronCls =
|
|
28
|
-
"flex items-center px-2 pt-1 text-
|
|
28
|
+
"flex items-center px-2 pt-1 text-(--navbar-text-muted) transition-colors group-hover:text-(--navbar-hover-text) focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--navbar-ring)] rounded-r-(--radius-default)";
|
|
29
29
|
const actionCls =
|
|
30
|
-
"inline-flex h-11 items-center justify-center whitespace-nowrap rounded-
|
|
30
|
+
"inline-flex h-11 items-center justify-center whitespace-nowrap rounded-(--radius-default) border border-(--navbar-action-border) bg-(--navbar-action-bg) px-5 font-semibold text-(--navbar-action-text) transition-colors hover:border-(--navbar-action-hover-border) hover:bg-(--navbar-action-hover-bg) focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--navbar-ring)]";
|
|
31
31
|
|
|
32
32
|
const mobileInnerCls = "flex h-14 items-center justify-between gap-4";
|
|
33
33
|
const mobileToggleCls =
|
|
34
|
-
"inline-flex h-10 w-10 items-center justify-center rounded-
|
|
34
|
+
"inline-flex h-10 w-10 items-center justify-center rounded-(--radius-default) text-(--navbar-text-muted) transition-colors hover:text-(--navbar-hover-text) focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--navbar-ring)]";
|
|
35
35
|
const mobilePanelWrapCls =
|
|
36
36
|
"absolute inset-x-0 top-full z-[80] overflow-y-auto overscroll-contain [touch-action:pan-y] [-webkit-overflow-scrolling:touch] origin-top";
|
|
37
37
|
const mobilePanelCls =
|
|
38
|
-
"border-y border-
|
|
38
|
+
"border-y border-(--navbar-border) bg-(--navbar-mobile-panel-bg) will-change-transform transition-all duration-300 ease-out";
|
|
39
39
|
const mobileLinkCls =
|
|
40
|
-
"flex min-h-12 w-full items-center justify-between px-4 text-left font-medium text-
|
|
40
|
+
"flex min-h-12 w-full items-center justify-between px-4 text-left font-medium text-(--navbar-text-muted) transition-colors hover:bg-(--navbar-hover-bg) hover:text-(--navbar-hover-text)";
|
|
41
41
|
const mobileSubLinkCls =
|
|
42
|
-
"block px-6 py-2 text-
|
|
42
|
+
"block px-6 py-2 text-(--navbar-text-muted) transition-colors hover:bg-(--navbar-hover-bg) hover:text-(--navbar-hover-text)";
|
|
43
43
|
const mobileActionWrapCls = "px-3 pb-3 pt-2";
|
|
44
44
|
const mobileActionCls =
|
|
45
|
-
"inline-flex h-10 w-full items-center justify-center rounded-
|
|
45
|
+
"inline-flex h-10 w-full items-center justify-center rounded-(--radius-default) border border-(--navbar-action-border) bg-(--navbar-action-bg) px-4 font-semibold text-(--navbar-action-text) transition-colors hover:border-(--navbar-action-hover-border) hover:bg-(--navbar-action-hover-bg) focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--navbar-ring)]";
|
|
46
46
|
|
|
47
47
|
const DEFAULT_LINKS = [
|
|
48
48
|
{ label: "Home", href: "#" },
|
|
@@ -239,7 +239,7 @@ export function Navbar({
|
|
|
239
239
|
"a",
|
|
240
240
|
{
|
|
241
241
|
href: link.href ?? "#",
|
|
242
|
-
className: `${desktopDropdownLinkCls} rounded-l-
|
|
242
|
+
className: `${desktopDropdownLinkCls} rounded-l-(--radius-default) px-3.5 py-2`,
|
|
243
243
|
},
|
|
244
244
|
link.label,
|
|
245
245
|
),
|
|
@@ -262,7 +262,7 @@ export function Navbar({
|
|
|
262
262
|
{
|
|
263
263
|
role: "menu",
|
|
264
264
|
className:
|
|
265
|
-
"absolute left-0 top-[calc(100%+0.6rem)] z-40 w-48 rounded-
|
|
265
|
+
"absolute left-0 top-[calc(100%+0.6rem)] z-40 w-48 rounded-(--radius-default) border border-(--navbar-border) bg-(--navbar-dropdown-bg) shadow-[var(--navbar-dropdown-shadow)]",
|
|
266
266
|
},
|
|
267
267
|
...(link.items ?? []).map((item, itemIndex) =>
|
|
268
268
|
React.createElement(
|
|
@@ -272,7 +272,7 @@ export function Navbar({
|
|
|
272
272
|
href: item.href ?? "#",
|
|
273
273
|
role: "menuitem",
|
|
274
274
|
className:
|
|
275
|
-
"block rounded-
|
|
275
|
+
"block rounded-(--radius-default) px-3.5 py-2.5 text-base text-(--navbar-text-muted) transition-colors hover:bg-(--navbar-hover-bg) hover:text-(--navbar-hover-text)",
|
|
276
276
|
onClick: () => setOpenIndex(null),
|
|
277
277
|
},
|
|
278
278
|
item.label,
|
|
@@ -476,7 +476,7 @@ export function MobileNavbar({
|
|
|
476
476
|
},
|
|
477
477
|
React.createElement(
|
|
478
478
|
"ul",
|
|
479
|
-
{ className: "divide-y divide-
|
|
479
|
+
{ className: "divide-y divide-(--navbar-divide-border)" },
|
|
480
480
|
...navLinks.map((link, index) => {
|
|
481
481
|
if (!hasSubItems(link)) {
|
|
482
482
|
return React.createElement(
|
|
@@ -23,7 +23,7 @@ export function PasswordInput({ className = "", ...props }) {
|
|
|
23
23
|
onClick: () => setVisible((v) => !v),
|
|
24
24
|
"aria-label": visible ? "Hide password" : "Show password",
|
|
25
25
|
className:
|
|
26
|
-
"absolute right-2.5 top-1/2 -translate-y-1/2 text-
|
|
26
|
+
"absolute right-2.5 top-1/2 -translate-y-1/2 text-(--input-icon) hover:text-(--input-icon-hover) transition-colors",
|
|
27
27
|
},
|
|
28
28
|
React.createElement(Icon, { size: 16, "aria-hidden": true }),
|
|
29
29
|
),
|
|
@@ -27,24 +27,24 @@ import { Input } from "./input.js";
|
|
|
27
27
|
*/
|
|
28
28
|
|
|
29
29
|
const wrapperCls =
|
|
30
|
-
"rounded-
|
|
30
|
+
"rounded-(--radius-default) border border-(--richtext-border) bg-(--richtext-bg) text-sm text-(--richtext-text) transition-colors duration-200 focus-within:border-(--richtext-border-focus) focus-within:ring-2 focus-within:ring-[var(--richtext-ring)] overflow-hidden";
|
|
31
31
|
|
|
32
32
|
const toolbarCls =
|
|
33
|
-
"flex flex-wrap items-center border-b border-
|
|
33
|
+
"flex flex-wrap items-center border-b border-(--richtext-border) bg-(--richtext-toolbar-bg)";
|
|
34
34
|
|
|
35
35
|
const btnBase =
|
|
36
|
-
"inline-flex items-center justify-center rounded-
|
|
36
|
+
"inline-flex items-center justify-center rounded-(--radius-default) text-(--richtext-btn-text) transition-colors cursor-pointer hover:bg-(--richtext-btn-hover-bg) hover:text-(--richtext-btn-hover-text) disabled:opacity-30 disabled:cursor-not-allowed";
|
|
37
37
|
|
|
38
38
|
const btnActive =
|
|
39
|
-
"bg-
|
|
39
|
+
"bg-(--richtext-btn-active-bg) text-(--richtext-btn-active-text)";
|
|
40
40
|
|
|
41
|
-
const separatorCls = "bg-
|
|
41
|
+
const separatorCls = "bg-(--richtext-separator)";
|
|
42
42
|
|
|
43
43
|
const editorCls =
|
|
44
|
-
"outline-none px-3 py-2 overflow-y-auto prose-sm [&_h1]:text-xl [&_h1]:font-bold [&_h1]:mt-4 [&_h1]:mb-2 [&_h2]:text-lg [&_h2]:font-semibold [&_h2]:mt-3 [&_h2]:mb-1.5 [&_h3]:text-base [&_h3]:font-semibold [&_h3]:mt-2 [&_h3]:mb-1 [&_ul]:list-disc [&_ul]:pl-5 [&_ul]:my-2 [&_ol]:list-decimal [&_ol]:pl-5 [&_ol]:my-2 [&_li]:my-0.5 [&_a]:text-
|
|
44
|
+
"outline-none px-3 py-2 overflow-y-auto prose-sm [&_h1]:text-xl [&_h1]:font-bold [&_h1]:mt-4 [&_h1]:mb-2 [&_h2]:text-lg [&_h2]:font-semibold [&_h2]:mt-3 [&_h2]:mb-1.5 [&_h3]:text-base [&_h3]:font-semibold [&_h3]:mt-2 [&_h3]:mb-1 [&_ul]:list-disc [&_ul]:pl-5 [&_ul]:my-2 [&_ol]:list-decimal [&_ol]:pl-5 [&_ol]:my-2 [&_li]:my-0.5 [&_a]:text-(--richtext-link) [&_a]:underline [&_blockquote]:border-l-2 [&_blockquote]:border-(--richtext-blockquote-border) [&_blockquote]:pl-3 [&_blockquote]:italic [&_blockquote]:text-(--richtext-blockquote-text) [&_blockquote]:my-2 [&_code]:bg-(--richtext-code-bg) [&_code]:px-1 [&_code]:py-0.5 [&_code]:rounded [&_code]:text-xs [&_code]:font-mono";
|
|
45
45
|
|
|
46
46
|
const placeholderCls =
|
|
47
|
-
"before:content-[attr(data-placeholder)] before:text-
|
|
47
|
+
"before:content-[attr(data-placeholder)] before:text-(--richtext-placeholder) before:pointer-events-none before:absolute before:left-3 before:top-2";
|
|
48
48
|
|
|
49
49
|
const TOOLBAR_ITEMS = [
|
|
50
50
|
{ command: "bold", icon: "B", title: "Bold", style: "font-bold" },
|
|
@@ -433,7 +433,7 @@ export function RichText({
|
|
|
433
433
|
linkError
|
|
434
434
|
? React.createElement(
|
|
435
435
|
"p",
|
|
436
|
-
{ className: "mt-1.5 text-xs text-
|
|
436
|
+
{ className: "mt-1.5 text-xs text-(--color-danger)" },
|
|
437
437
|
linkError,
|
|
438
438
|
)
|
|
439
439
|
: null,
|
|
@@ -10,19 +10,19 @@ import React, {
|
|
|
10
10
|
} from "react";
|
|
11
11
|
|
|
12
12
|
const triggerCls =
|
|
13
|
-
"flex h-10 w-full items-center justify-between rounded-
|
|
13
|
+
"flex h-10 w-full items-center justify-between rounded-(--radius-default) border border-(--select-border) bg-(--select-bg) px-3 text-sm text-(--select-text) shadow-sm transition-all duration-200 cursor-pointer hover:border-(--select-border-hover) focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--select-ring)] disabled:cursor-not-allowed disabled:opacity-50";
|
|
14
14
|
|
|
15
15
|
const panelCls =
|
|
16
|
-
"absolute z-30 max-h-60 w-full overflow-auto rounded-
|
|
16
|
+
"absolute z-30 max-h-60 w-full overflow-auto rounded-(--radius-default) border border-(--select-border) bg-(--select-panel-bg) shadow-xl origin-top transition-all duration-200 ease-out";
|
|
17
17
|
|
|
18
18
|
const optionBaseCls =
|
|
19
|
-
"flex w-full items-center justify-between rounded-
|
|
19
|
+
"flex w-full items-center justify-between rounded-(--radius-default) px-2.5 py-2 text-left text-sm transition-colors duration-150";
|
|
20
20
|
|
|
21
21
|
const optionIdleCls =
|
|
22
|
-
"cursor-pointer text-
|
|
22
|
+
"cursor-pointer text-(--select-text) hover:bg-(--select-option-hover-bg) hover:text-(--select-option-hover-text)";
|
|
23
23
|
|
|
24
24
|
const optionActiveCls =
|
|
25
|
-
"bg-
|
|
25
|
+
"bg-(--select-option-active-bg) text-(--select-option-active-text)";
|
|
26
26
|
|
|
27
27
|
function normalizeValue(value) {
|
|
28
28
|
if (value === undefined || value === null) return "";
|
|
@@ -249,8 +249,8 @@ export function Select({
|
|
|
249
249
|
"span",
|
|
250
250
|
{
|
|
251
251
|
className: selectedOption
|
|
252
|
-
? "text-
|
|
253
|
-
: "text-
|
|
252
|
+
? "text-(--select-text)"
|
|
253
|
+
: "text-(--select-text-faint)",
|
|
254
254
|
},
|
|
255
255
|
selectedOption?.label ??
|
|
256
256
|
(options.length === 0 ? "No options" : placeholder),
|
|
@@ -260,7 +260,7 @@ export function Select({
|
|
|
260
260
|
{
|
|
261
261
|
"aria-hidden": "true",
|
|
262
262
|
className:
|
|
263
|
-
`ml-2 text-
|
|
263
|
+
`ml-2 text-(--select-text-faint) transition-transform duration-200 ease-in-out ${open ? "rotate-180" : "rotate-0"}`.trim(),
|
|
264
264
|
},
|
|
265
265
|
React.createElement(ChevronDown, { size: 16 }),
|
|
266
266
|
),
|
|
@@ -276,7 +276,7 @@ export function Select({
|
|
|
276
276
|
options.length === 0
|
|
277
277
|
? React.createElement(
|
|
278
278
|
"p",
|
|
279
|
-
{ className: "px-2.5 py-2 text-sm text-
|
|
279
|
+
{ className: "px-2.5 py-2 text-sm text-(--select-text-faint)" },
|
|
280
280
|
"No options",
|
|
281
281
|
)
|
|
282
282
|
: options.map((option) => {
|
|
@@ -305,7 +305,7 @@ export function Select({
|
|
|
305
305
|
"span",
|
|
306
306
|
{
|
|
307
307
|
"aria-hidden": "true",
|
|
308
|
-
className: "text-
|
|
308
|
+
className: "text-(--select-option-active-text)",
|
|
309
309
|
},
|
|
310
310
|
React.createElement(Check, { size: 16 }),
|
|
311
311
|
)
|
|
@@ -2,11 +2,11 @@ import { ChevronDown, ChevronsUpDown, ChevronUp } from "lucide-react";
|
|
|
2
2
|
import React from "react";
|
|
3
3
|
|
|
4
4
|
const wrapperCls =
|
|
5
|
-
"w-full overflow-auto rounded-
|
|
5
|
+
"w-full overflow-auto rounded-(--radius-default) border border-(--table-border) bg-(--table-bg)";
|
|
6
6
|
|
|
7
7
|
const tableCls = "w-full caption-bottom text-sm";
|
|
8
8
|
|
|
9
|
-
const headerCls = "border-b border-
|
|
9
|
+
const headerCls = "border-b border-(--table-border) bg-(--table-header-bg)";
|
|
10
10
|
|
|
11
11
|
const bodyCls = "[&_tr:last-child]:border-0";
|
|
12
12
|
|
|
@@ -14,15 +14,15 @@ const rowCls =
|
|
|
14
14
|
"border-b border-[var(--table-border)] transition-colors hover:bg-[var(--table-row-hover-bg)] active:bg-[var(--table-row-active-bg)]";
|
|
15
15
|
|
|
16
16
|
const headCls =
|
|
17
|
-
"h-11 text-left align-middle font-medium text-
|
|
17
|
+
"h-11 text-left align-middle font-medium text-(--table-head-text)";
|
|
18
18
|
|
|
19
|
-
const cellCls = "align-middle text-
|
|
19
|
+
const cellCls = "align-middle text-(--table-cell-text)";
|
|
20
20
|
|
|
21
21
|
const sortButtonCls =
|
|
22
|
-
"group inline-flex w-full items-center justify-between gap-2 text-left outline-none focus-visible:ring-2 focus-visible:ring-[var(--table-ring)] rounded-
|
|
22
|
+
"group inline-flex w-full items-center justify-between gap-2 text-left outline-none focus-visible:ring-2 focus-visible:ring-[var(--table-ring)] rounded-(--radius-default)";
|
|
23
23
|
|
|
24
24
|
const sortIconCls =
|
|
25
|
-
"text-
|
|
25
|
+
"text-(--table-sort-icon) transition-colors group-hover:text-(--table-sort-icon-hover)";
|
|
26
26
|
|
|
27
27
|
function toAriaSort(direction) {
|
|
28
28
|
if (direction === "asc") return "ascending";
|
|
@@ -148,7 +148,7 @@ export function TableHead({
|
|
|
148
148
|
{
|
|
149
149
|
"aria-hidden": "true",
|
|
150
150
|
className:
|
|
151
|
-
`${sortIconCls} ${direction !== "none" ? "text-
|
|
151
|
+
`${sortIconCls} ${direction !== "none" ? "text-(--table-sort-active)" : ""}`.trim(),
|
|
152
152
|
},
|
|
153
153
|
sortIndicator(direction),
|
|
154
154
|
),
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
|
|
3
3
|
const base =
|
|
4
|
-
"block w-full rounded-
|
|
4
|
+
"block w-full rounded-(--radius-default) border border-(--input-border) bg-(--input-bg) px-3 py-2 text-sm text-(--input-text) placeholder:text-(--input-placeholder) transition-colors duration-200 hover:border-(--input-border-hover) focus-visible:border-(--input-border-focus) focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--input-ring-focus)] disabled:opacity-(--input-disabled-opacity) disabled:cursor-not-allowed resize-y";
|
|
5
5
|
|
|
6
6
|
export function Textarea({ className = "", ...props }) {
|
|
7
7
|
return React.createElement("textarea", {
|
|
@@ -21,7 +21,7 @@ export function Toast({
|
|
|
21
21
|
const [shouldRender, setShouldRender] = useState(visible);
|
|
22
22
|
|
|
23
23
|
const variantCls =
|
|
24
|
-
"bg-
|
|
24
|
+
"bg-(--toast-bg) border-(--toast-border) text-(--toast-text) shadow-[var(--toast-shadow)]";
|
|
25
25
|
|
|
26
26
|
const remainingRef = useRef(duration);
|
|
27
27
|
const startRef = useRef(null);
|
|
@@ -98,7 +98,7 @@ export function Toast({
|
|
|
98
98
|
"data-toast-variant": variant,
|
|
99
99
|
onMouseEnter: () => setHovered(true),
|
|
100
100
|
onMouseLeave: () => setHovered(false),
|
|
101
|
-
className: `fixed bottom-4 right-4 z-50 flex items-center gap-3 rounded-
|
|
101
|
+
className: `fixed bottom-4 right-4 z-50 flex items-center gap-3 rounded-(--radius-default) px-4 py-3 text-sm transition-colors duration-200 ${variantCls}`,
|
|
102
102
|
style: animStyle,
|
|
103
103
|
},
|
|
104
104
|
React.createElement("span", null, message),
|
|
@@ -116,7 +116,7 @@ export function Toast({
|
|
|
116
116
|
"aria-label": "Dismiss notification",
|
|
117
117
|
onClick: onClose,
|
|
118
118
|
className:
|
|
119
|
-
"flex h-6 w-6 cursor-pointer items-center justify-center rounded-
|
|
119
|
+
"flex h-6 w-6 cursor-pointer items-center justify-center rounded-(--radius-default) text-base leading-none opacity-80 transition-all hover:bg-black/10 dark:hover:bg-white/10 hover:opacity-100 active:bg-black/20 dark:active:bg-white/20 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/60",
|
|
120
120
|
},
|
|
121
121
|
React.createElement(
|
|
122
122
|
"svg",
|