@momentumworld/ui-react 0.17.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/dist/chunk-2HQPCV2L.js +895 -0
- package/dist/chunk-2HQPCV2L.js.map +1 -0
- package/dist/form.d.ts +175 -0
- package/dist/form.js +356 -0
- package/dist/form.js.map +1 -0
- package/dist/index.d.ts +2162 -0
- package/dist/index.js +11640 -0
- package/dist/index.js.map +1 -0
- package/dist/input-JCZs61MO.d.ts +24 -0
- package/package.json +90 -0
- package/src/components/form/checkbox-group-field.tsx +101 -0
- package/src/components/form/date-field.tsx +79 -0
- package/src/components/form/date-range-field.tsx +106 -0
- package/src/components/form/form-context.ts +10 -0
- package/src/components/form/form.tsx +54 -0
- package/src/components/form/number-field.tsx +69 -0
- package/src/components/form/select-field.tsx +76 -0
- package/src/components/form/submit-button.tsx +28 -0
- package/src/components/form/text-field.tsx +107 -0
- package/src/components/layout/dashboard-header.tsx +54 -0
- package/src/components/layout/dashboard-panel.tsx +34 -0
- package/src/components/layout/dashboard-topbar.tsx +221 -0
- package/src/components/theme-provider.tsx +403 -0
- package/src/components/ui/accordion.tsx +69 -0
- package/src/components/ui/alert-dialog.tsx +169 -0
- package/src/components/ui/alert.tsx +80 -0
- package/src/components/ui/animated-counter.tsx +109 -0
- package/src/components/ui/animated-theme-toggler.tsx +265 -0
- package/src/components/ui/app-store-buttons.tsx +182 -0
- package/src/components/ui/aspect-ratio.tsx +23 -0
- package/src/components/ui/aurora-orb.tsx +163 -0
- package/src/components/ui/aurora-text.tsx +76 -0
- package/src/components/ui/autocomplete.tsx +296 -0
- package/src/components/ui/avatar-group.tsx +150 -0
- package/src/components/ui/avatar.tsx +285 -0
- package/src/components/ui/badge-group.tsx +160 -0
- package/src/components/ui/badge.tsx +172 -0
- package/src/components/ui/breadcrumb.tsx +112 -0
- package/src/components/ui/button.tsx +77 -0
- package/src/components/ui/calendar.tsx +137 -0
- package/src/components/ui/card.tsx +244 -0
- package/src/components/ui/carousel.tsx +258 -0
- package/src/components/ui/chart.tsx +379 -0
- package/src/components/ui/chat-divider.tsx +67 -0
- package/src/components/ui/chat.tsx +494 -0
- package/src/components/ui/checkbox-group.tsx +16 -0
- package/src/components/ui/checkbox.tsx +82 -0
- package/src/components/ui/collapsible.tsx +45 -0
- package/src/components/ui/color-picker.tsx +389 -0
- package/src/components/ui/combobox.tsx +411 -0
- package/src/components/ui/command.tsx +264 -0
- package/src/components/ui/confetti.tsx +196 -0
- package/src/components/ui/context-menu.tsx +271 -0
- package/src/components/ui/context-meter.tsx +134 -0
- package/src/components/ui/credit-card.tsx +214 -0
- package/src/components/ui/data-table-paged.tsx +163 -0
- package/src/components/ui/date-picker.tsx +154 -0
- package/src/components/ui/dialog.tsx +196 -0
- package/src/components/ui/drawer.tsx +135 -0
- package/src/components/ui/empty.tsx +127 -0
- package/src/components/ui/fab.tsx +45 -0
- package/src/components/ui/featured-icon.tsx +149 -0
- package/src/components/ui/field.tsx +88 -0
- package/src/components/ui/fieldset.tsx +29 -0
- package/src/components/ui/form.tsx +17 -0
- package/src/components/ui/frame.tsx +82 -0
- package/src/components/ui/generic-empty.tsx +142 -0
- package/src/components/ui/group.tsx +97 -0
- package/src/components/ui/help-tip.tsx +94 -0
- package/src/components/ui/horizontal-scroll-fader.tsx +228 -0
- package/src/components/ui/input-group.tsx +102 -0
- package/src/components/ui/input-otp.tsx +96 -0
- package/src/components/ui/input.tsx +66 -0
- package/src/components/ui/item.tsx +198 -0
- package/src/components/ui/kbd.tsx +30 -0
- package/src/components/ui/label.tsx +28 -0
- package/src/components/ui/markdown.tsx +188 -0
- package/src/components/ui/menu.tsx +312 -0
- package/src/components/ui/menubar.tsx +93 -0
- package/src/components/ui/meter.tsx +67 -0
- package/src/components/ui/multi-select.tsx +308 -0
- package/src/components/ui/navigation-menu.tsx +143 -0
- package/src/components/ui/number-field.tsx +160 -0
- package/src/components/ui/pagination-controls.tsx +74 -0
- package/src/components/ui/pagination.tsx +149 -0
- package/src/components/ui/pipeline.tsx +102 -0
- package/src/components/ui/popover.tsx +119 -0
- package/src/components/ui/preview-card.tsx +55 -0
- package/src/components/ui/progress.tsx +289 -0
- package/src/components/ui/qr-code.tsx +150 -0
- package/src/components/ui/radio-group.tsx +103 -0
- package/src/components/ui/resizable.tsx +56 -0
- package/src/components/ui/scroll-area.tsx +90 -0
- package/src/components/ui/scroller.tsx +38 -0
- package/src/components/ui/section-header.tsx +118 -0
- package/src/components/ui/segmented-control.tsx +83 -0
- package/src/components/ui/select.tsx +181 -0
- package/src/components/ui/separator.tsx +23 -0
- package/src/components/ui/sheet.tsx +224 -0
- package/src/components/ui/sidebar.tsx +774 -0
- package/src/components/ui/skeleton.tsx +16 -0
- package/src/components/ui/slider.tsx +108 -0
- package/src/components/ui/smooth-scroll.tsx +206 -0
- package/src/components/ui/social-button.tsx +247 -0
- package/src/components/ui/spinner-on-demand.tsx +32 -0
- package/src/components/ui/spinner.tsx +18 -0
- package/src/components/ui/stat.tsx +187 -0
- package/src/components/ui/stepper.tsx +167 -0
- package/src/components/ui/switch.tsx +56 -0
- package/src/components/ui/table.tsx +126 -0
- package/src/components/ui/tabs.tsx +90 -0
- package/src/components/ui/tag.tsx +242 -0
- package/src/components/ui/target-countdown.tsx +46 -0
- package/src/components/ui/text-editor.tsx +313 -0
- package/src/components/ui/textarea.tsx +51 -0
- package/src/components/ui/thinking-orb.tsx +6 -0
- package/src/components/ui/time-picker.tsx +308 -0
- package/src/components/ui/timeline.tsx +116 -0
- package/src/components/ui/toast.tsx +268 -0
- package/src/components/ui/toggle-group.tsx +101 -0
- package/src/components/ui/toggle.tsx +45 -0
- package/src/components/ui/toolbar.tsx +89 -0
- package/src/components/ui/tooltip.tsx +102 -0
- package/src/components/ui/vertical-scroll-fader.tsx +250 -0
- package/src/components/ui/video-player.tsx +275 -0
- package/src/components/upload/avatar-upload-base.tsx +131 -0
- package/src/components/upload/image-upload-base.tsx +112 -0
- package/src/form.ts +17 -0
- package/src/index.ts +143 -0
- package/src/lib/hooks/use-callback-ref.ts +15 -0
- package/src/lib/hooks/use-first-render.ts +11 -0
- package/src/lib/hooks/use-hover.ts +53 -0
- package/src/lib/hooks/use-is-tab-active.ts +17 -0
- package/src/lib/hooks/use-media-query.ts +164 -0
- package/src/lib/utils/css.ts +6 -0
- package/src/styles.css +329 -0
- package/src/types/helpers.ts +24 -0
- package/src/types/react.d.ts +7 -0
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { useRef } from "react";
|
|
4
|
+
|
|
5
|
+
// biome-ignore lint/suspicious/noExplicitAny: Generic shinanigans
|
|
6
|
+
function useCallbackRef<T extends (...args: Array<any>) => any>(fn: T): T {
|
|
7
|
+
const fnRef = useRef(fn);
|
|
8
|
+
fnRef.current = fn;
|
|
9
|
+
|
|
10
|
+
// biome-ignore lint/suspicious/noExplicitAny: Generic shinanigans
|
|
11
|
+
const ref = useRef((...args: Array<any>) => fnRef.current(...args));
|
|
12
|
+
return ref.current as T;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export default useCallbackRef;
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { useCallback, useRef, useState } from "react";
|
|
4
|
+
|
|
5
|
+
export function useHover<T extends Element>({
|
|
6
|
+
mounted = true,
|
|
7
|
+
}: {
|
|
8
|
+
mounted?: boolean;
|
|
9
|
+
} = {}): readonly [(node: T | null) => void, boolean] {
|
|
10
|
+
const [hovering, setHovering] = useState(false);
|
|
11
|
+
const previousNode = useRef<T | null>(null);
|
|
12
|
+
|
|
13
|
+
const [prevMounted, setPrevMounted] = useState(mounted);
|
|
14
|
+
if (mounted !== prevMounted) {
|
|
15
|
+
setPrevMounted(mounted);
|
|
16
|
+
if (!mounted) {
|
|
17
|
+
setHovering(false);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const handleMouseEnter = useCallback(() => {
|
|
22
|
+
setHovering(true);
|
|
23
|
+
}, []);
|
|
24
|
+
|
|
25
|
+
const handleMouseLeave = useCallback(() => {
|
|
26
|
+
setHovering(false);
|
|
27
|
+
}, []);
|
|
28
|
+
|
|
29
|
+
const customRef = useCallback<React.RefCallback<T>>(
|
|
30
|
+
(node) => {
|
|
31
|
+
if (previousNode.current?.nodeType === Node.ELEMENT_NODE) {
|
|
32
|
+
previousNode.current.removeEventListener(
|
|
33
|
+
"mouseenter",
|
|
34
|
+
handleMouseEnter,
|
|
35
|
+
);
|
|
36
|
+
previousNode.current.removeEventListener(
|
|
37
|
+
"mouseleave",
|
|
38
|
+
handleMouseLeave,
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if (node?.nodeType === Node.ELEMENT_NODE) {
|
|
43
|
+
node.addEventListener("mouseenter", handleMouseEnter);
|
|
44
|
+
node.addEventListener("mouseleave", handleMouseLeave);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
previousNode.current = node;
|
|
48
|
+
},
|
|
49
|
+
[handleMouseEnter, handleMouseLeave],
|
|
50
|
+
);
|
|
51
|
+
|
|
52
|
+
return [customRef, hovering] as const;
|
|
53
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { useSyncExternalStore } from "react";
|
|
4
|
+
|
|
5
|
+
const subscribe = (onVisibilityChange: () => void) => {
|
|
6
|
+
window.addEventListener("visibilitychange", onVisibilityChange);
|
|
7
|
+
return () =>
|
|
8
|
+
window.removeEventListener("visibilitychange", onVisibilityChange);
|
|
9
|
+
};
|
|
10
|
+
const getSnapshot = () => !document.hidden;
|
|
11
|
+
const getServerSnapshot = () => true;
|
|
12
|
+
|
|
13
|
+
function useIsTabActive() {
|
|
14
|
+
return useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export default useIsTabActive;
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { useCallback, useLayoutEffect, useSyncExternalStore } from "react";
|
|
4
|
+
import { create } from "zustand";
|
|
5
|
+
import { useFirstRender } from "./use-first-render";
|
|
6
|
+
|
|
7
|
+
const breakpoints = ["sm", "md", "lg", "xl", "2xl"] as const;
|
|
8
|
+
type Breakpoints = (typeof breakpoints)[number];
|
|
9
|
+
|
|
10
|
+
const useBreakpointsStore = create<
|
|
11
|
+
{
|
|
12
|
+
[breakpoint in Breakpoints as `is${Capitalize<breakpoint>}`]: boolean;
|
|
13
|
+
} & {
|
|
14
|
+
[breakpoint in Breakpoints as `setIs${Capitalize<breakpoint>}`]: (
|
|
15
|
+
value: boolean,
|
|
16
|
+
) => void;
|
|
17
|
+
}
|
|
18
|
+
>((set) => ({
|
|
19
|
+
isSm: false,
|
|
20
|
+
isMd: false,
|
|
21
|
+
isLg: false,
|
|
22
|
+
isXl: false,
|
|
23
|
+
is2xl: false,
|
|
24
|
+
setIsSm: (value: boolean) => set({ isSm: value }),
|
|
25
|
+
setIsMd: (value: boolean) => set({ isMd: value }),
|
|
26
|
+
setIsLg: (value: boolean) => set({ isLg: value }),
|
|
27
|
+
setIsXl: (value: boolean) => set({ isXl: value }),
|
|
28
|
+
setIs2xl: (value: boolean) => set({ is2xl: value }),
|
|
29
|
+
}));
|
|
30
|
+
|
|
31
|
+
const getBreakpointValue = (breakpoint: Breakpoints) =>
|
|
32
|
+
getComputedStyle(document.documentElement).getPropertyValue(
|
|
33
|
+
`--breakpoint-${breakpoint}`,
|
|
34
|
+
);
|
|
35
|
+
|
|
36
|
+
const setters = {
|
|
37
|
+
sm: "setIsSm" as const,
|
|
38
|
+
md: "setIsMd" as const,
|
|
39
|
+
lg: "setIsLg" as const,
|
|
40
|
+
xl: "setIsXl" as const,
|
|
41
|
+
"2xl": "setIs2xl" as const,
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
function useSyncWithStore(breakpoint: Breakpoints) {
|
|
45
|
+
const setBreakpoint = useBreakpointsStore(
|
|
46
|
+
(state) => state[setters[breakpoint]],
|
|
47
|
+
);
|
|
48
|
+
useLayoutEffect(() => {
|
|
49
|
+
const matchMedia = window.matchMedia(
|
|
50
|
+
`(min-width: ${getBreakpointValue(breakpoint)})`,
|
|
51
|
+
);
|
|
52
|
+
matchMedia.addEventListener("change", () => {
|
|
53
|
+
setBreakpoint(matchMedia.matches);
|
|
54
|
+
});
|
|
55
|
+
setBreakpoint(matchMedia.matches);
|
|
56
|
+
return () => {
|
|
57
|
+
matchMedia.removeEventListener("change", () => {
|
|
58
|
+
setBreakpoint(matchMedia.matches);
|
|
59
|
+
});
|
|
60
|
+
};
|
|
61
|
+
}, [breakpoint, setBreakpoint]);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// It could be lazy
|
|
65
|
+
export function useSubscribeBreakpoints() {
|
|
66
|
+
useSyncWithStore("sm");
|
|
67
|
+
useSyncWithStore("md");
|
|
68
|
+
useSyncWithStore("lg");
|
|
69
|
+
useSyncWithStore("xl");
|
|
70
|
+
useSyncWithStore("2xl");
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
interface UseMediaQueryOptions {
|
|
74
|
+
ssr?: boolean;
|
|
75
|
+
defaultSSRValue?: boolean;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export function useMediaQuery(
|
|
79
|
+
query: string,
|
|
80
|
+
{ ssr = false, defaultSSRValue = false }: UseMediaQueryOptions = {},
|
|
81
|
+
) {
|
|
82
|
+
const subscribe = useCallback(
|
|
83
|
+
(callback: (m: MediaQueryListEvent) => void) => {
|
|
84
|
+
const matchMedia = window.matchMedia(query);
|
|
85
|
+
|
|
86
|
+
matchMedia.addEventListener("change", callback);
|
|
87
|
+
return () => {
|
|
88
|
+
matchMedia.removeEventListener("change", callback);
|
|
89
|
+
};
|
|
90
|
+
},
|
|
91
|
+
[query],
|
|
92
|
+
);
|
|
93
|
+
|
|
94
|
+
const getSnapshot = () => window.matchMedia(query).matches;
|
|
95
|
+
|
|
96
|
+
const getServerSnapshot = () => defaultSSRValue;
|
|
97
|
+
|
|
98
|
+
const value = useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);
|
|
99
|
+
const isFirstRender = useFirstRender();
|
|
100
|
+
if (ssr && isFirstRender) {
|
|
101
|
+
return defaultSSRValue;
|
|
102
|
+
}
|
|
103
|
+
return value;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
export function useIsSm({
|
|
107
|
+
ssr = false,
|
|
108
|
+
defaultSSRValue = false,
|
|
109
|
+
}: UseMediaQueryOptions = {}) {
|
|
110
|
+
const isFirstRender = useFirstRender();
|
|
111
|
+
const isSm = useBreakpointsStore((state) => state.isSm);
|
|
112
|
+
if (ssr && isFirstRender) {
|
|
113
|
+
return defaultSSRValue;
|
|
114
|
+
}
|
|
115
|
+
return isSm;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
export function useIsMd({
|
|
119
|
+
ssr = false,
|
|
120
|
+
defaultSSRValue = false,
|
|
121
|
+
}: UseMediaQueryOptions = {}) {
|
|
122
|
+
const isFirstRender = useFirstRender();
|
|
123
|
+
const isMd = useBreakpointsStore((state) => state.isMd);
|
|
124
|
+
if (ssr && isFirstRender) {
|
|
125
|
+
return defaultSSRValue;
|
|
126
|
+
}
|
|
127
|
+
return isMd;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
export function useIsLg({
|
|
131
|
+
ssr = false,
|
|
132
|
+
defaultSSRValue = false,
|
|
133
|
+
}: UseMediaQueryOptions = {}) {
|
|
134
|
+
const isFirstRender = useFirstRender();
|
|
135
|
+
const isLg = useBreakpointsStore((state) => state.isLg);
|
|
136
|
+
if (ssr && isFirstRender) {
|
|
137
|
+
return defaultSSRValue;
|
|
138
|
+
}
|
|
139
|
+
return isLg;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
export function useIsXl({
|
|
143
|
+
ssr = false,
|
|
144
|
+
defaultSSRValue = false,
|
|
145
|
+
}: UseMediaQueryOptions = {}) {
|
|
146
|
+
const isFirstRender = useFirstRender();
|
|
147
|
+
const isXl = useBreakpointsStore((state) => state.isXl);
|
|
148
|
+
if (ssr && isFirstRender) {
|
|
149
|
+
return defaultSSRValue;
|
|
150
|
+
}
|
|
151
|
+
return isXl;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
export function useIs2xl({
|
|
155
|
+
ssr = false,
|
|
156
|
+
defaultSSRValue = false,
|
|
157
|
+
}: UseMediaQueryOptions = {}) {
|
|
158
|
+
const isFirstRender = useFirstRender();
|
|
159
|
+
const is2xl = useBreakpointsStore((state) => state.is2xl);
|
|
160
|
+
if (ssr && isFirstRender) {
|
|
161
|
+
return defaultSSRValue;
|
|
162
|
+
}
|
|
163
|
+
return is2xl;
|
|
164
|
+
}
|
package/src/styles.css
ADDED
|
@@ -0,0 +1,329 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Country Club UI Kit — design system stylesheet (Tailwind CSS v4).
|
|
3
|
+
*
|
|
4
|
+
* Usage (in your app's global CSS):
|
|
5
|
+
*
|
|
6
|
+
* @import "tailwindcss";
|
|
7
|
+
* @import "@countryclub/ui-react/styles.css";
|
|
8
|
+
* @source "../node_modules/@countryclub/ui-react/src";
|
|
9
|
+
*
|
|
10
|
+
* Dark mode is driven by the `data-theme="dark"` attribute on <html>.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
@import "tw-animate-css";
|
|
14
|
+
|
|
15
|
+
@custom-variant dark (&:where([data-theme="dark"], [data-theme="dark"] *));
|
|
16
|
+
|
|
17
|
+
/*
|
|
18
|
+
* Emitted unconditionally (NOT inside @theme) so AuroraText's gradient sweep
|
|
19
|
+
* runs in every consumer — even when their Tailwind build doesn't generate the
|
|
20
|
+
* `animate-aurora` utility from the theme token (keyframes declared inside
|
|
21
|
+
* @theme are dropped unless that utility is scanned/used). AuroraText applies
|
|
22
|
+
* this keyframe via an inline `animation`, so it no longer depends on the
|
|
23
|
+
* utility class existing at all.
|
|
24
|
+
*/
|
|
25
|
+
@keyframes aurora {
|
|
26
|
+
0%,
|
|
27
|
+
100% {
|
|
28
|
+
background-position: 0% 50%;
|
|
29
|
+
}
|
|
30
|
+
50% {
|
|
31
|
+
background-position: 100% 50%;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
@theme inline {
|
|
36
|
+
--animate-skeleton: skeleton 2s -1s infinite linear;
|
|
37
|
+
--animate-qr-scan: qr-scan 2.6s ease-in-out infinite alternate;
|
|
38
|
+
--animate-aurora: aurora 10s ease infinite;
|
|
39
|
+
--color-warning-foreground: var(--warning-foreground);
|
|
40
|
+
--color-warning: var(--warning);
|
|
41
|
+
--color-success-foreground: var(--success-foreground);
|
|
42
|
+
--color-success: var(--success);
|
|
43
|
+
--color-info-foreground: var(--info-foreground);
|
|
44
|
+
--color-info: var(--info);
|
|
45
|
+
--color-destructive-foreground: var(--destructive-foreground);
|
|
46
|
+
--color-sidebar-ring: var(--sidebar-ring);
|
|
47
|
+
--color-sidebar-border: var(--sidebar-border);
|
|
48
|
+
--color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
|
|
49
|
+
--color-sidebar-accent: var(--sidebar-accent);
|
|
50
|
+
--color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
|
|
51
|
+
--color-sidebar-primary: var(--sidebar-primary);
|
|
52
|
+
--color-sidebar-foreground: var(--sidebar-foreground);
|
|
53
|
+
--color-sidebar: var(--sidebar);
|
|
54
|
+
--color-chart-5: var(--chart-5);
|
|
55
|
+
--color-chart-4: var(--chart-4);
|
|
56
|
+
--color-chart-3: var(--chart-3);
|
|
57
|
+
--color-chart-2: var(--chart-2);
|
|
58
|
+
--color-chart-1: var(--chart-1);
|
|
59
|
+
--color-ring: var(--ring);
|
|
60
|
+
--color-input: var(--input);
|
|
61
|
+
--color-border: var(--border);
|
|
62
|
+
--color-destructive: var(--destructive);
|
|
63
|
+
--color-accent-foreground: var(--accent-foreground);
|
|
64
|
+
--color-accent: var(--accent);
|
|
65
|
+
--color-muted-foreground: var(--muted-foreground);
|
|
66
|
+
--color-muted: var(--muted);
|
|
67
|
+
--color-secondary-foreground: var(--secondary-foreground);
|
|
68
|
+
--color-secondary: var(--secondary);
|
|
69
|
+
--color-primary-foreground: var(--primary-foreground);
|
|
70
|
+
--color-primary: var(--primary);
|
|
71
|
+
--color-popover-foreground: var(--popover-foreground);
|
|
72
|
+
--color-popover: var(--popover);
|
|
73
|
+
--color-card-foreground: var(--card-foreground);
|
|
74
|
+
--color-card: var(--card);
|
|
75
|
+
--color-foreground: var(--foreground);
|
|
76
|
+
--color-background: var(--background);
|
|
77
|
+
--color-brand: var(--brand);
|
|
78
|
+
--color-page-bg: var(--color-page-bg);
|
|
79
|
+
--radius-xs: calc(var(--radius) - 8px);
|
|
80
|
+
--radius-sm: calc(var(--radius) - 6px);
|
|
81
|
+
--radius-md: calc(var(--radius) - 4px);
|
|
82
|
+
--radius-lg: calc(var(--radius) - 2px);
|
|
83
|
+
--radius: var(--radius);
|
|
84
|
+
--radius-xl: calc(var(--radius) + 2px);
|
|
85
|
+
--radius-2xl: calc(var(--radius) + 6px);
|
|
86
|
+
--radius-3xl: calc(var(--radius) + 14px);
|
|
87
|
+
--radius-4xl: calc(var(--radius) + 22px);
|
|
88
|
+
@keyframes skeleton {
|
|
89
|
+
to {
|
|
90
|
+
background-position: -200% 0;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
/* The scan band is half the overlay tall with its line at its own center;
|
|
94
|
+
-50% → 150% makes that line sweep exactly edge-to-edge. */
|
|
95
|
+
@keyframes qr-scan {
|
|
96
|
+
from {
|
|
97
|
+
transform: translateY(-50%);
|
|
98
|
+
}
|
|
99
|
+
to {
|
|
100
|
+
transform: translateY(150%);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
/* AuroraText: sweep the oversized gradient back and forth across the glyphs. */
|
|
104
|
+
@keyframes aurora {
|
|
105
|
+
0%,
|
|
106
|
+
100% {
|
|
107
|
+
background-position: 0% 50%;
|
|
108
|
+
}
|
|
109
|
+
50% {
|
|
110
|
+
background-position: 100% 50%;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
--font-sans: "DM Sans", sans-serif;
|
|
114
|
+
--font-serif: "Fraunces", sans-serif;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
@utility text-xl {
|
|
118
|
+
@apply font-serif;
|
|
119
|
+
|
|
120
|
+
&.font-sans {
|
|
121
|
+
@apply font-sans;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
@utility text-2xl {
|
|
126
|
+
@apply font-serif;
|
|
127
|
+
|
|
128
|
+
&.font-sans {
|
|
129
|
+
@apply font-sans;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
@utility text-3xl {
|
|
134
|
+
@apply font-serif;
|
|
135
|
+
|
|
136
|
+
&.font-sans {
|
|
137
|
+
@apply font-sans;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
@utility text-4xl {
|
|
142
|
+
@apply font-serif;
|
|
143
|
+
|
|
144
|
+
&.font-sans {
|
|
145
|
+
@apply font-sans;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
@utility text-5xl {
|
|
150
|
+
@apply font-serif;
|
|
151
|
+
|
|
152
|
+
&.font-sans {
|
|
153
|
+
@apply font-sans;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
@utility text-6xl {
|
|
158
|
+
@apply font-serif;
|
|
159
|
+
|
|
160
|
+
&.font-sans {
|
|
161
|
+
@apply font-sans;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
@utility text-7xl {
|
|
166
|
+
@apply font-serif;
|
|
167
|
+
|
|
168
|
+
&.font-sans {
|
|
169
|
+
@apply font-sans;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
@utility text-8xl {
|
|
174
|
+
@apply font-serif;
|
|
175
|
+
|
|
176
|
+
&.font-sans {
|
|
177
|
+
@apply font-sans;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
@utility text-9xl {
|
|
182
|
+
@apply font-serif;
|
|
183
|
+
|
|
184
|
+
&.font-sans {
|
|
185
|
+
@apply font-sans;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
:root,
|
|
190
|
+
[data-theme="light"] {
|
|
191
|
+
--radius: 0.625rem;
|
|
192
|
+
--accent: rgb(12 10 9 / 0.04);
|
|
193
|
+
--accent-foreground: #120f0e;
|
|
194
|
+
--background: #fffefc;
|
|
195
|
+
--border: rgb(12 10 9 / 0.08);
|
|
196
|
+
--card: #fffefc;
|
|
197
|
+
--card-foreground: #120f0e;
|
|
198
|
+
--destructive: #bf4a37;
|
|
199
|
+
--foreground: #120f0e;
|
|
200
|
+
--info: #4a6fa5;
|
|
201
|
+
--info-foreground: #355280;
|
|
202
|
+
--input: rgb(12 10 9 / 0.1);
|
|
203
|
+
--muted: rgb(12 10 9 / 0.04);
|
|
204
|
+
--muted-foreground: #78716c;
|
|
205
|
+
--popover: #fffefc;
|
|
206
|
+
--popover-foreground: #120f0e;
|
|
207
|
+
--primary: #120f0e;
|
|
208
|
+
--primary-foreground: #fffefc;
|
|
209
|
+
--ring: rgb(12 10 9 / 0.25);
|
|
210
|
+
--secondary: rgb(12 10 9 / 0.04);
|
|
211
|
+
--secondary-foreground: #44403c;
|
|
212
|
+
--success: #3d7a4f;
|
|
213
|
+
--success-foreground: #2d5a3a;
|
|
214
|
+
--warning: #c48a1a;
|
|
215
|
+
--warning-foreground: #92600a;
|
|
216
|
+
--destructive-foreground: #943728;
|
|
217
|
+
--chart-1: #ea580c;
|
|
218
|
+
--chart-2: #0d9488;
|
|
219
|
+
--chart-3: #164e63;
|
|
220
|
+
--chart-4: #fbbf24;
|
|
221
|
+
--chart-5: #f59e0b;
|
|
222
|
+
--sidebar: #f6f4ef;
|
|
223
|
+
--sidebar-foreground: #78716c;
|
|
224
|
+
--sidebar-primary: #92600a;
|
|
225
|
+
--sidebar-primary-foreground: #fffefc;
|
|
226
|
+
--sidebar-accent: rgb(12 10 9 / 0.04);
|
|
227
|
+
--sidebar-accent-foreground: #120f0e;
|
|
228
|
+
--sidebar-border: rgb(12 10 9 / 0.06);
|
|
229
|
+
--sidebar-ring: #d4a84b;
|
|
230
|
+
--brand: #d4a84b;
|
|
231
|
+
--color-page-bg: #f6f4ef;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
[data-theme="dark"] {
|
|
235
|
+
--destructive-foreground: #e8877a;
|
|
236
|
+
--accent: rgb(250 249 246 / 0.04);
|
|
237
|
+
--accent-foreground: #e7e5e4;
|
|
238
|
+
--background: #0c0a09;
|
|
239
|
+
--border: rgb(250 249 246 / 0.06);
|
|
240
|
+
--card: #120f0e;
|
|
241
|
+
--card-foreground: #faf9f6;
|
|
242
|
+
--destructive: #d4644f;
|
|
243
|
+
--foreground: #faf9f6;
|
|
244
|
+
--info: #7ba3d4;
|
|
245
|
+
--info-foreground: #a3c1e8;
|
|
246
|
+
--input: rgb(250 249 246 / 0.08);
|
|
247
|
+
--muted: rgb(250 249 246 / 0.04);
|
|
248
|
+
--muted-foreground: #a8a29e;
|
|
249
|
+
--popover: #120f0e;
|
|
250
|
+
--popover-foreground: #faf9f6;
|
|
251
|
+
--primary: #faf9f6;
|
|
252
|
+
--primary-foreground: #0c0a09;
|
|
253
|
+
--ring: rgb(250 249 246 / 0.25);
|
|
254
|
+
--secondary: rgb(250 249 246 / 0.04);
|
|
255
|
+
--secondary-foreground: #e7e5e4;
|
|
256
|
+
--success: #5aad6b;
|
|
257
|
+
--success-foreground: #7bc98a;
|
|
258
|
+
--warning: #e5b84a;
|
|
259
|
+
--warning-foreground: #f0cc6d;
|
|
260
|
+
--chart-1: #1d4ed8;
|
|
261
|
+
--chart-2: #10b981;
|
|
262
|
+
--chart-3: #f59e0b;
|
|
263
|
+
--chart-4: #a855f7;
|
|
264
|
+
--chart-5: #f43f5e;
|
|
265
|
+
--sidebar: #141110;
|
|
266
|
+
--sidebar-foreground: #a8a29e;
|
|
267
|
+
--sidebar-primary: #d4a84b;
|
|
268
|
+
--sidebar-primary-foreground: #0c0a09;
|
|
269
|
+
--sidebar-accent: rgb(250 249 246 / 0.04);
|
|
270
|
+
--sidebar-accent-foreground: #faf9f6;
|
|
271
|
+
--sidebar-border: rgb(250 249 246 / 0.05);
|
|
272
|
+
--sidebar-ring: #d4a84b;
|
|
273
|
+
--brand: #92600a;
|
|
274
|
+
--color-page-bg: #141110;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
@layer base {
|
|
278
|
+
* {
|
|
279
|
+
@apply border-border outline-ring/50;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
body {
|
|
283
|
+
@apply relative m-0 font-sans text-foreground;
|
|
284
|
+
background-color: var(--color-page-bg);
|
|
285
|
+
-webkit-font-smoothing: antialiased;
|
|
286
|
+
-moz-osx-font-smoothing: grayscale;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
iframe {
|
|
290
|
+
color-scheme: normal;
|
|
291
|
+
@apply rounded-lg outline-border;
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
@layer utilities {
|
|
296
|
+
/* Forces Tailwind to emit the breakpoint variables that
|
|
297
|
+
`useSubscribeBreakpoints` reads at runtime. Do not remove. */
|
|
298
|
+
.__force-breakpoints {
|
|
299
|
+
content: var(--breakpoint-sm) var(--breakpoint-md) var(--breakpoint-lg)
|
|
300
|
+
var(--breakpoint-xl) var(--breakpoint-2xl);
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
/*
|
|
305
|
+
* Animated theme toggle (View Transitions API), used by <AnimatedThemeToggler>.
|
|
306
|
+
* Everything is scoped to `html[data-theme-vt="active"]`, which the component
|
|
307
|
+
* sets only while a toggle is in flight — so any other root view transitions
|
|
308
|
+
* in a consuming app (e.g. route transitions) are left untouched.
|
|
309
|
+
*/
|
|
310
|
+
html[data-theme-vt="active"]::view-transition-old(root),
|
|
311
|
+
html[data-theme-vt="active"]::view-transition-new(root) {
|
|
312
|
+
animation: none;
|
|
313
|
+
mix-blend-mode: normal;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
/*
|
|
317
|
+
* Start the incoming (new theme) snapshot fully clipped at the toggle origin.
|
|
318
|
+
* Without this there's a one-frame flash of the new theme between the
|
|
319
|
+
* pseudo-elements being created and the JS clip-path animation attaching on
|
|
320
|
+
* `transition.ready`. The component sets --theme-vt-x / --theme-vt-y; the WAAPI
|
|
321
|
+
* animation then takes over from this same collapsed origin (no visible seam).
|
|
322
|
+
*/
|
|
323
|
+
html[data-theme-vt="active"]::view-transition-new(root) {
|
|
324
|
+
clip-path: circle(0 at var(--theme-vt-x, 50%) var(--theme-vt-y, 50%));
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
html[data-theme-vt="active"]::view-transition-group(root) {
|
|
328
|
+
animation-duration: var(--theme-toggle-vt-duration, 400ms);
|
|
329
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export type AsChildProps<T extends keyof React.JSX.IntrinsicElements> = {
|
|
2
|
+
asChild?: boolean;
|
|
3
|
+
children?: React.ReactNode;
|
|
4
|
+
} & React.PropsWithoutRef<React.JSX.IntrinsicElements[T]>;
|
|
5
|
+
|
|
6
|
+
export type OmitUnknown<T> = {
|
|
7
|
+
[K in keyof T as unknown extends T[K] ? never : K]: T[K];
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
export type TailOptional<P extends any[]> = P extends [...infer H, infer T]
|
|
11
|
+
? [...H] | [...H, T]
|
|
12
|
+
: never[];
|
|
13
|
+
|
|
14
|
+
export type RequiredSubset<T, K extends keyof T> = Required<Pick<T, K>> &
|
|
15
|
+
Omit<T, K>;
|
|
16
|
+
export type Tail<P extends any[], H extends any[]> = P extends H
|
|
17
|
+
? void
|
|
18
|
+
: P extends [...H, infer T]
|
|
19
|
+
? T
|
|
20
|
+
: void;
|
|
21
|
+
|
|
22
|
+
export type NotNullValues<T> = {
|
|
23
|
+
[K in keyof T]: Exclude<T[K], null>;
|
|
24
|
+
};
|