@docubook/create 1.9.0 → 1.11.2
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 +1 -3
- package/package.json +7 -7
- package/src/cli/program.js +32 -0
- package/src/cli/promptHandler.js +73 -0
- package/src/dist/LICENSE +21 -0
- package/src/dist/README.md +37 -0
- package/src/dist/app/docs/[[...slug]]/page.tsx +105 -0
- package/src/dist/app/docs/layout.tsx +16 -0
- package/src/dist/app/error.tsx +44 -0
- package/src/dist/app/layout.tsx +96 -0
- package/src/dist/app/not-found.tsx +19 -0
- package/src/dist/app/page.tsx +96 -0
- package/src/dist/components/GithubStart.tsx +44 -0
- package/src/dist/components/Sponsor.tsx +69 -0
- package/src/dist/components/anchor.tsx +84 -0
- package/src/dist/components/contexts/theme-provider.tsx +9 -0
- package/src/dist/components/docs-breadcrumb.tsx +47 -0
- package/src/dist/components/docs-menu.tsx +45 -0
- package/src/dist/components/edit-on-github.tsx +33 -0
- package/src/dist/components/footer.tsx +85 -0
- package/src/dist/components/leftbar.tsx +95 -0
- package/src/dist/components/markdown/AccordionMdx.tsx +47 -0
- package/src/dist/components/markdown/ButtonMdx.tsx +52 -0
- package/src/dist/components/markdown/CardGroupMdx.tsx +28 -0
- package/src/dist/components/markdown/CardMdx.tsx +41 -0
- package/src/dist/components/markdown/CopyMdx.tsx +33 -0
- package/src/dist/components/markdown/ImageMdx.tsx +25 -0
- package/src/dist/components/markdown/KeyboardMdx.tsx +102 -0
- package/src/dist/components/markdown/LinkMdx.tsx +14 -0
- package/src/dist/components/markdown/NoteMdx.tsx +52 -0
- package/src/dist/components/markdown/OutletMdx.tsx +29 -0
- package/src/dist/components/markdown/PreMdx.tsx +19 -0
- package/src/dist/components/markdown/ReleaseMdx.tsx +109 -0
- package/src/dist/components/markdown/StepperMdx.tsx +41 -0
- package/src/dist/components/markdown/TooltipsMdx.tsx +28 -0
- package/src/dist/components/markdown/YoutubeMdx.tsx +22 -0
- package/src/dist/components/markdown/mdx-provider.tsx +29 -0
- package/src/dist/components/mob-toc.tsx +128 -0
- package/src/dist/components/navbar.tsx +87 -0
- package/src/dist/components/pagination.tsx +49 -0
- package/src/dist/components/scroll-to-top.tsx +86 -0
- package/src/dist/components/search.tsx +214 -0
- package/src/dist/components/sublink.tsx +133 -0
- package/src/dist/components/theme-toggle.tsx +71 -0
- package/src/dist/components/toc-observer.tsx +264 -0
- package/src/dist/components/toc.tsx +27 -0
- package/src/dist/components/typography.tsx +9 -0
- package/src/dist/components/ui/accordion.tsx +58 -0
- package/src/dist/components/ui/animated-shiny-text.tsx +40 -0
- package/src/dist/components/ui/aurora.tsx +45 -0
- package/src/dist/components/ui/avatar.tsx +50 -0
- package/src/dist/components/ui/badge.tsx +37 -0
- package/src/dist/components/ui/breadcrumb.tsx +115 -0
- package/src/dist/components/ui/button.tsx +57 -0
- package/src/dist/components/ui/card.tsx +76 -0
- package/src/dist/components/ui/collapsible.tsx +11 -0
- package/src/dist/components/ui/command.tsx +153 -0
- package/src/dist/components/ui/dialog.tsx +124 -0
- package/src/dist/components/ui/dropdown-menu.tsx +200 -0
- package/src/dist/components/ui/icon-cloud.tsx +324 -0
- package/src/dist/components/ui/input.tsx +25 -0
- package/src/dist/components/ui/interactive-hover-button.tsx +35 -0
- package/src/dist/components/ui/popover.tsx +33 -0
- package/src/dist/components/ui/scroll-area.tsx +48 -0
- package/src/dist/components/ui/separator.tsx +30 -0
- package/src/dist/components/ui/sheet.tsx +140 -0
- package/src/dist/components/ui/shine-border.tsx +64 -0
- package/src/dist/components/ui/skeleton.tsx +15 -0
- package/src/dist/components/ui/sonner.tsx +31 -0
- package/src/dist/components/ui/table.tsx +117 -0
- package/src/dist/components/ui/tabs.tsx +55 -0
- package/src/dist/components/ui/toggle-group.tsx +61 -0
- package/src/dist/components/ui/toggle.tsx +46 -0
- package/src/dist/components.json +17 -0
- package/src/dist/contents/docs/getting-started/changelog/index.mdx +512 -0
- package/src/dist/contents/docs/getting-started/components/accordion/index.mdx +72 -0
- package/src/dist/contents/docs/getting-started/components/button/index.mdx +42 -0
- package/src/dist/contents/docs/getting-started/components/card/index.mdx +70 -0
- package/src/dist/contents/docs/getting-started/components/card-group/index.mdx +49 -0
- package/src/dist/contents/docs/getting-started/components/code-block/index.mdx +41 -0
- package/src/dist/contents/docs/getting-started/components/custom/index.mdx +38 -0
- package/src/dist/contents/docs/getting-started/components/image/index.mdx +37 -0
- package/src/dist/contents/docs/getting-started/components/index.mdx +9 -0
- package/src/dist/contents/docs/getting-started/components/keyboard/index.mdx +117 -0
- package/src/dist/contents/docs/getting-started/components/link/index.mdx +34 -0
- package/src/dist/contents/docs/getting-started/components/note/index.mdx +46 -0
- package/src/dist/contents/docs/getting-started/components/release-note/index.mdx +130 -0
- package/src/dist/contents/docs/getting-started/components/stepper/index.mdx +47 -0
- package/src/dist/contents/docs/getting-started/components/tabs/index.mdx +70 -0
- package/src/dist/contents/docs/getting-started/components/tooltips/index.mdx +22 -0
- package/src/dist/contents/docs/getting-started/components/youtube/index.mdx +21 -0
- package/src/dist/contents/docs/getting-started/customize/index.mdx +94 -0
- package/src/dist/contents/docs/getting-started/installation/index.mdx +84 -0
- package/src/dist/contents/docs/getting-started/introduction/index.mdx +50 -0
- package/src/dist/contents/docs/getting-started/project-structure/index.mdx +87 -0
- package/src/dist/contents/docs/getting-started/quick-start-guide/index.mdx +127 -0
- package/src/dist/docu.json +100 -0
- package/src/dist/hooks/index.ts +2 -0
- package/src/dist/hooks/useActiveSection.ts +68 -0
- package/src/dist/hooks/useScrollPosition.ts +28 -0
- package/src/dist/lib/markdown.ts +244 -0
- package/src/dist/lib/routes-config.ts +28 -0
- package/src/dist/lib/toc.ts +9 -0
- package/src/dist/lib/utils.ts +80 -0
- package/src/dist/next-env.d.ts +5 -0
- package/src/dist/next.config.mjs +14 -0
- package/src/dist/package.json +58 -0
- package/src/dist/postcss.config.js +6 -0
- package/src/dist/public/favicon.ico +0 -0
- package/src/dist/public/images/docu.svg +6 -0
- package/src/dist/public/images/example-img.png +0 -0
- package/src/dist/public/images/img-playground.png +0 -0
- package/src/dist/public/images/new-editor.png +0 -0
- package/src/dist/public/images/og-image.png +0 -0
- package/src/dist/public/images/release-note.png +0 -0
- package/src/dist/public/images/snippet.png +0 -0
- package/src/dist/public/images/vercel.png +0 -0
- package/src/dist/public/images/view-changelog.png +0 -0
- package/src/dist/styles/editor.css +57 -0
- package/src/dist/styles/globals.css +156 -0
- package/src/dist/styles/syntax.css +100 -0
- package/src/dist/tailwind.config.ts +112 -0
- package/src/dist/tsconfig.json +26 -0
- package/src/index.js +19 -0
- package/src/installer/projectInstaller.js +125 -0
- package/src/utils/display.js +83 -0
- package/src/utils/logger.js +11 -0
- package/src/utils/packageManager.js +54 -0
- package/create.js +0 -223
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { getDocsTocs } from "@/lib/markdown";
|
|
4
|
+
import clsx from "clsx";
|
|
5
|
+
import Link from "next/link";
|
|
6
|
+
import { useState, useRef, useEffect, useCallback } from "react";
|
|
7
|
+
import { motion } from "framer-motion";
|
|
8
|
+
import { ScrollToTop } from "./scroll-to-top";
|
|
9
|
+
import { TocItem } from "@/lib/toc";
|
|
10
|
+
|
|
11
|
+
interface TocObserverProps {
|
|
12
|
+
data: TocItem[];
|
|
13
|
+
activeId?: string | null;
|
|
14
|
+
onActiveIdChange?: (id: string | null) => void;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export default function TocObserver({
|
|
18
|
+
data,
|
|
19
|
+
activeId: externalActiveId,
|
|
20
|
+
onActiveIdChange
|
|
21
|
+
}: TocObserverProps) {
|
|
22
|
+
const [internalActiveId, setInternalActiveId] = useState<string | null>(null);
|
|
23
|
+
const observer = useRef<IntersectionObserver | null>(null);
|
|
24
|
+
const [clickedId, setClickedId] = useState<string | null>(null);
|
|
25
|
+
const itemRefs = useRef<Map<string, HTMLAnchorElement>>(new Map());
|
|
26
|
+
|
|
27
|
+
// Use external activeId if provided, otherwise use internal state
|
|
28
|
+
const activeId = externalActiveId !== undefined ? externalActiveId : internalActiveId;
|
|
29
|
+
const setActiveId = onActiveIdChange || setInternalActiveId;
|
|
30
|
+
|
|
31
|
+
// Handle intersection observer for auto-highlighting
|
|
32
|
+
useEffect(() => {
|
|
33
|
+
const handleIntersect = (entries: IntersectionObserverEntry[]) => {
|
|
34
|
+
const visibleEntries = entries.filter(entry => entry.isIntersecting);
|
|
35
|
+
|
|
36
|
+
// Find the most recently scrolled-into-view element
|
|
37
|
+
const mostVisibleEntry = visibleEntries.reduce((prev, current) => {
|
|
38
|
+
// Prefer the entry that's more visible or higher on the page
|
|
39
|
+
const prevRatio = prev?.intersectionRatio || 0;
|
|
40
|
+
const currentRatio = current.intersectionRatio;
|
|
41
|
+
|
|
42
|
+
if (currentRatio > prevRatio) return current;
|
|
43
|
+
if (currentRatio === prevRatio &&
|
|
44
|
+
current.boundingClientRect.top < prev.boundingClientRect.top) {
|
|
45
|
+
return current;
|
|
46
|
+
}
|
|
47
|
+
return prev;
|
|
48
|
+
}, visibleEntries[0]);
|
|
49
|
+
|
|
50
|
+
if (mostVisibleEntry && !clickedId) {
|
|
51
|
+
const newActiveId = mostVisibleEntry.target.id;
|
|
52
|
+
if (newActiveId !== activeId) {
|
|
53
|
+
setActiveId(newActiveId);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
observer.current = new IntersectionObserver(handleIntersect, {
|
|
59
|
+
root: null,
|
|
60
|
+
rootMargin: "-20% 0px -70% 0px", // Adjusted margins for better section detection
|
|
61
|
+
threshold: [0, 0.1, 0.5, 0.9, 1], // Multiple thresholds for better accuracy
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
const elements = data.map((item) =>
|
|
65
|
+
document.getElementById(item.href.slice(1))
|
|
66
|
+
);
|
|
67
|
+
|
|
68
|
+
elements.forEach((el) => {
|
|
69
|
+
if (el && observer.current) {
|
|
70
|
+
observer.current.observe(el);
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
// Set initial active ID if none is set
|
|
75
|
+
if (!activeId && elements[0]) {
|
|
76
|
+
setActiveId(elements[0].id);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return () => {
|
|
80
|
+
if (observer.current) {
|
|
81
|
+
elements.forEach((el) => {
|
|
82
|
+
if (el) {
|
|
83
|
+
observer.current!.unobserve(el);
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
}, [data, clickedId, activeId, setActiveId]);
|
|
89
|
+
|
|
90
|
+
const handleLinkClick = useCallback((id: string) => {
|
|
91
|
+
setClickedId(id);
|
|
92
|
+
setActiveId(id);
|
|
93
|
+
|
|
94
|
+
// Reset the clicked state after a delay to allow for smooth scrolling
|
|
95
|
+
const timer = setTimeout(() => {
|
|
96
|
+
setClickedId(null);
|
|
97
|
+
}, 1000);
|
|
98
|
+
|
|
99
|
+
return () => clearTimeout(timer);
|
|
100
|
+
}, [setActiveId]);
|
|
101
|
+
|
|
102
|
+
// Function to check if an item has children
|
|
103
|
+
const hasChildren = (currentId: string, currentLevel: number) => {
|
|
104
|
+
const currentIndex = data.findIndex(item => item.href.slice(1) === currentId);
|
|
105
|
+
if (currentIndex === -1 || currentIndex === data.length - 1) return false;
|
|
106
|
+
|
|
107
|
+
const nextItem = data[currentIndex + 1];
|
|
108
|
+
return nextItem.level > currentLevel;
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
// Calculate scroll progress for the active section
|
|
112
|
+
const [scrollProgress, setScrollProgress] = useState(0);
|
|
113
|
+
const [activeSectionIndex, setActiveSectionIndex] = useState(0);
|
|
114
|
+
|
|
115
|
+
useEffect(() => {
|
|
116
|
+
const handleScroll = () => {
|
|
117
|
+
if (!activeId) return;
|
|
118
|
+
|
|
119
|
+
const activeElement = document.getElementById(activeId);
|
|
120
|
+
if (!activeElement) return;
|
|
121
|
+
|
|
122
|
+
const rect = activeElement.getBoundingClientRect();
|
|
123
|
+
const windowHeight = window.innerHeight;
|
|
124
|
+
const elementTop = rect.top;
|
|
125
|
+
const elementHeight = rect.height;
|
|
126
|
+
|
|
127
|
+
// Calculate how much of the element is visible
|
|
128
|
+
let progress = 0;
|
|
129
|
+
if (elementTop < windowHeight) {
|
|
130
|
+
progress = Math.min(1, (windowHeight - elementTop) / (windowHeight + elementHeight));
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
setScrollProgress(progress);
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
window.addEventListener('scroll', handleScroll, { passive: true });
|
|
137
|
+
return () => window.removeEventListener('scroll', handleScroll);
|
|
138
|
+
}, [activeId]);
|
|
139
|
+
|
|
140
|
+
// Update active section index when activeId changes
|
|
141
|
+
useEffect(() => {
|
|
142
|
+
if (activeId) {
|
|
143
|
+
const index = data.findIndex(item => item.href.slice(1) === activeId);
|
|
144
|
+
if (index !== -1) {
|
|
145
|
+
setActiveSectionIndex(index);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}, [activeId, data]);
|
|
149
|
+
|
|
150
|
+
return (
|
|
151
|
+
<div className="relative">
|
|
152
|
+
<div className="relative text-sm text-stone-600 dark:text-stone-400">
|
|
153
|
+
<div className="flex flex-col gap-0">
|
|
154
|
+
{data.map(({ href, level, text }, index) => {
|
|
155
|
+
const id = href.slice(1);
|
|
156
|
+
const isActive = activeId === id;
|
|
157
|
+
const indent = level > 1 ? (level - 1) * 20 : 0;
|
|
158
|
+
const isParent = hasChildren(id, level);
|
|
159
|
+
const isLastInLevel = index === data.length - 1 || data[index + 1].level <= level;
|
|
160
|
+
|
|
161
|
+
return (
|
|
162
|
+
<div key={href} className="relative">
|
|
163
|
+
{/* Simple L-shaped connector */}
|
|
164
|
+
{level > 1 && (
|
|
165
|
+
<div
|
|
166
|
+
className={clsx("absolute top-0 h-full w-6", {
|
|
167
|
+
"left-[6px]": indent === 20, // Level 2
|
|
168
|
+
"left-[22px]": indent === 40, // Level 3
|
|
169
|
+
"left-[38px]": indent === 60, // Level 4
|
|
170
|
+
})}
|
|
171
|
+
>
|
|
172
|
+
{/* Vertical line */}
|
|
173
|
+
<div className={clsx(
|
|
174
|
+
"absolute left-0 top-0 h-full w-px",
|
|
175
|
+
isActive ? "bg-primary/20" : "bg-stone-300 dark:bg-stone-600"
|
|
176
|
+
)}>
|
|
177
|
+
{isActive && (
|
|
178
|
+
<motion.div
|
|
179
|
+
className="absolute left-0 top-0 w-full h-full bg-primary origin-top"
|
|
180
|
+
initial={{ scaleY: 0 }}
|
|
181
|
+
animate={{ scaleY: scrollProgress }}
|
|
182
|
+
transition={{ duration: 0.3 }}
|
|
183
|
+
/>
|
|
184
|
+
)}
|
|
185
|
+
</div>
|
|
186
|
+
|
|
187
|
+
{/* Horizontal line */}
|
|
188
|
+
<div className={clsx(
|
|
189
|
+
"absolute left-0 top-1/2 h-px w-6",
|
|
190
|
+
isActive ? "bg-primary/20" : "bg-stone-300 dark:bg-stone-600"
|
|
191
|
+
)}>
|
|
192
|
+
{isActive && (
|
|
193
|
+
<motion.div
|
|
194
|
+
className="absolute left-0 top-0 h-full w-full bg-primary origin-left"
|
|
195
|
+
initial={{ scaleX: 0 }}
|
|
196
|
+
animate={{ scaleX: scrollProgress }}
|
|
197
|
+
transition={{ duration: 0.3, delay: 0.1 }}
|
|
198
|
+
/>
|
|
199
|
+
)}
|
|
200
|
+
</div>
|
|
201
|
+
</div>
|
|
202
|
+
)}
|
|
203
|
+
|
|
204
|
+
<Link
|
|
205
|
+
href={href}
|
|
206
|
+
onClick={() => handleLinkClick(id)}
|
|
207
|
+
className={clsx(
|
|
208
|
+
"relative flex items-center py-2 transition-colors",
|
|
209
|
+
{
|
|
210
|
+
"text-primary dark:text-primary-400 font-medium": isActive,
|
|
211
|
+
"text-stone-600 dark:text-stone-400 hover:text-stone-900 dark:hover:text-stone-200": !isActive,
|
|
212
|
+
}
|
|
213
|
+
)}
|
|
214
|
+
style={{
|
|
215
|
+
paddingLeft: `${indent}px`,
|
|
216
|
+
marginLeft: level > 1 ? '12px' : '0',
|
|
217
|
+
}}
|
|
218
|
+
ref={(el) => {
|
|
219
|
+
const map = itemRefs.current;
|
|
220
|
+
if (el) {
|
|
221
|
+
map.set(id, el);
|
|
222
|
+
} else {
|
|
223
|
+
map.delete(id);
|
|
224
|
+
}
|
|
225
|
+
}}
|
|
226
|
+
>
|
|
227
|
+
{/* Circle indicator */}
|
|
228
|
+
<div className="relative w-4 h-4 flex items-center justify-center flex-shrink-0">
|
|
229
|
+
<div className={clsx(
|
|
230
|
+
"w-1.5 h-1.5 rounded-full transition-all duration-300 relative z-10",
|
|
231
|
+
{
|
|
232
|
+
"bg-primary scale-100": isActive,
|
|
233
|
+
"bg-stone-300 dark:bg-stone-600 scale-75 group-hover:scale-100 group-hover:bg-primary/50": !isActive,
|
|
234
|
+
}
|
|
235
|
+
)}>
|
|
236
|
+
{isActive && (
|
|
237
|
+
<motion.div
|
|
238
|
+
className="absolute inset-0 rounded-full bg-primary/20"
|
|
239
|
+
initial={{ scale: 1 }}
|
|
240
|
+
animate={{ scale: 1.8 }}
|
|
241
|
+
transition={{
|
|
242
|
+
duration: 2,
|
|
243
|
+
repeat: Infinity,
|
|
244
|
+
repeatType: "reverse"
|
|
245
|
+
}}
|
|
246
|
+
/>
|
|
247
|
+
)}
|
|
248
|
+
</div>
|
|
249
|
+
</div>
|
|
250
|
+
|
|
251
|
+
<span className="truncate text-sm">
|
|
252
|
+
{text}
|
|
253
|
+
</span>
|
|
254
|
+
</Link>
|
|
255
|
+
</div>
|
|
256
|
+
);
|
|
257
|
+
})}
|
|
258
|
+
</div>
|
|
259
|
+
</div>
|
|
260
|
+
{/* Add scroll to top link at the bottom of TOC */}
|
|
261
|
+
<ScrollToTop className="mt-6" />
|
|
262
|
+
</div>
|
|
263
|
+
);
|
|
264
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { getDocsTocs } from "@/lib/markdown";
|
|
2
|
+
import TocObserver from "./toc-observer";
|
|
3
|
+
import { ScrollArea } from "@/components/ui/scroll-area";
|
|
4
|
+
import { ListIcon } from "lucide-react";
|
|
5
|
+
import Sponsor from "./Sponsor";
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
export default async function Toc({ path }: { path: string }) {
|
|
9
|
+
const tocs = await getDocsTocs(path);
|
|
10
|
+
|
|
11
|
+
return (
|
|
12
|
+
<div className="lg:flex hidden toc flex-[1.5] min-w-[238px] py-5 sticky top-16 h-[calc(100vh-4rem)]">
|
|
13
|
+
<div className="flex flex-col h-full w-full px-2 gap-2 mb-auto">
|
|
14
|
+
<div className="flex items-center gap-2">
|
|
15
|
+
<ListIcon className="w-4 h-4" />
|
|
16
|
+
<h3 className="font-medium text-sm">On this page</h3>
|
|
17
|
+
</div>
|
|
18
|
+
<div className="flex-shrink-0 min-h-0 max-h-[calc(70vh-4rem)]">
|
|
19
|
+
<ScrollArea className="h-full">
|
|
20
|
+
<TocObserver data={tocs} />
|
|
21
|
+
</ScrollArea>
|
|
22
|
+
</div>
|
|
23
|
+
<Sponsor />
|
|
24
|
+
</div>
|
|
25
|
+
</div>
|
|
26
|
+
);
|
|
27
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { PropsWithChildren } from "react";
|
|
2
|
+
|
|
3
|
+
export function Typography({ children }: PropsWithChildren) {
|
|
4
|
+
return (
|
|
5
|
+
<div className="prose prose-zinc dark:prose-invert prose-code:font-code dark:prose-code:bg-stone-900/25 prose-code:bg-stone-50 prose-pre:bg-background prose-headings:scroll-m-20 w-[85vw] sm:w-full sm:mx-auto prose-code:text-sm prose-code:leading-6 dark:prose-code:text-white prose-code:text-stone-800 prose-code:p-1 prose-code:rounded-md prose-code:border pt-2 !min-w-full prose-img:rounded-md prose-img:border prose-code:before:content-none prose-code:after:content-none prose-code:px-1.5 prose-code:overflow-x-auto !max-w-[500px] prose-img:my-3 prose-h2:my-4 prose-h2:mt-8">
|
|
6
|
+
{children}
|
|
7
|
+
</div>
|
|
8
|
+
);
|
|
9
|
+
}
|
|
@@ -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 }
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { CSSProperties, FC, ReactNode } from "react";
|
|
2
|
+
|
|
3
|
+
import { cn } from "@/lib/utils";
|
|
4
|
+
|
|
5
|
+
interface AnimatedShinyTextProps {
|
|
6
|
+
children: ReactNode;
|
|
7
|
+
className?: string;
|
|
8
|
+
shimmerWidth?: number;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const AnimatedShinyText: FC<AnimatedShinyTextProps> = ({
|
|
12
|
+
children,
|
|
13
|
+
className,
|
|
14
|
+
shimmerWidth = 100,
|
|
15
|
+
}) => {
|
|
16
|
+
return (
|
|
17
|
+
<p
|
|
18
|
+
style={
|
|
19
|
+
{
|
|
20
|
+
"--shiny-width": `${shimmerWidth}px`,
|
|
21
|
+
} as CSSProperties
|
|
22
|
+
}
|
|
23
|
+
className={cn(
|
|
24
|
+
"mx-auto max-w-md text-neutral-600/70 dark:text-neutral-400/70",
|
|
25
|
+
|
|
26
|
+
// Shine effect
|
|
27
|
+
"animate-shiny-text bg-clip-text bg-no-repeat [background-position:0_0] [background-size:var(--shiny-width)_100%] [transition:background-position_1s_cubic-bezier(.6,.6,0,1)_infinite]",
|
|
28
|
+
|
|
29
|
+
// Shine gradient
|
|
30
|
+
"bg-gradient-to-r from-transparent via-black/80 via-50% to-transparent dark:via-white/80",
|
|
31
|
+
|
|
32
|
+
className,
|
|
33
|
+
)}
|
|
34
|
+
>
|
|
35
|
+
{children}
|
|
36
|
+
</p>
|
|
37
|
+
);
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
export default AnimatedShinyText;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import React, { memo } from "react";
|
|
4
|
+
|
|
5
|
+
interface AuroraTextProps {
|
|
6
|
+
children: React.ReactNode;
|
|
7
|
+
className?: string;
|
|
8
|
+
colors?: string[];
|
|
9
|
+
speed?: number;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export const AuroraText = memo(
|
|
13
|
+
({
|
|
14
|
+
children,
|
|
15
|
+
className = "",
|
|
16
|
+
colors = ["#FF0080", "#7928CA", "#0070F3", "#38bdf8"],
|
|
17
|
+
speed = 1,
|
|
18
|
+
}: AuroraTextProps) => {
|
|
19
|
+
const gradientStyle = {
|
|
20
|
+
backgroundImage: `linear-gradient(135deg, ${colors.join(", ")}, ${
|
|
21
|
+
colors[0]
|
|
22
|
+
})`,
|
|
23
|
+
WebkitBackgroundClip: "text",
|
|
24
|
+
WebkitTextFillColor: "transparent",
|
|
25
|
+
animationDuration: `${10 / speed}s`,
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
return (
|
|
29
|
+
<span className={`relative inline-block ${className}`}>
|
|
30
|
+
<span className="sr-only">{children}</span>
|
|
31
|
+
<span
|
|
32
|
+
className="relative animate-aurora bg-[length:200%_auto] bg-clip-text text-transparent"
|
|
33
|
+
style={gradientStyle}
|
|
34
|
+
aria-hidden="true"
|
|
35
|
+
>
|
|
36
|
+
{children}
|
|
37
|
+
</span>
|
|
38
|
+
</span>
|
|
39
|
+
);
|
|
40
|
+
},
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
AuroraText.displayName = "AuroraText";
|
|
44
|
+
|
|
45
|
+
export default AuroraText;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"use client"
|
|
2
|
+
|
|
3
|
+
import * as React from "react"
|
|
4
|
+
import * as AvatarPrimitive from "@radix-ui/react-avatar"
|
|
5
|
+
|
|
6
|
+
import { cn } from "@/lib/utils"
|
|
7
|
+
|
|
8
|
+
const Avatar = React.forwardRef<
|
|
9
|
+
React.ElementRef<typeof AvatarPrimitive.Root>,
|
|
10
|
+
React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Root>
|
|
11
|
+
>(({ className, ...props }, ref) => (
|
|
12
|
+
<AvatarPrimitive.Root
|
|
13
|
+
ref={ref}
|
|
14
|
+
className={cn(
|
|
15
|
+
"relative flex h-10 w-10 shrink-0 overflow-hidden rounded-full",
|
|
16
|
+
className
|
|
17
|
+
)}
|
|
18
|
+
{...props}
|
|
19
|
+
/>
|
|
20
|
+
))
|
|
21
|
+
Avatar.displayName = AvatarPrimitive.Root.displayName
|
|
22
|
+
|
|
23
|
+
const AvatarImage = React.forwardRef<
|
|
24
|
+
React.ElementRef<typeof AvatarPrimitive.Image>,
|
|
25
|
+
React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Image>
|
|
26
|
+
>(({ className, ...props }, ref) => (
|
|
27
|
+
<AvatarPrimitive.Image
|
|
28
|
+
ref={ref}
|
|
29
|
+
className={cn("aspect-square h-full w-full", className)}
|
|
30
|
+
{...props}
|
|
31
|
+
/>
|
|
32
|
+
))
|
|
33
|
+
AvatarImage.displayName = AvatarPrimitive.Image.displayName
|
|
34
|
+
|
|
35
|
+
const AvatarFallback = React.forwardRef<
|
|
36
|
+
React.ElementRef<typeof AvatarPrimitive.Fallback>,
|
|
37
|
+
React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Fallback>
|
|
38
|
+
>(({ className, ...props }, ref) => (
|
|
39
|
+
<AvatarPrimitive.Fallback
|
|
40
|
+
ref={ref}
|
|
41
|
+
className={cn(
|
|
42
|
+
"flex h-full w-full items-center justify-center rounded-full bg-muted",
|
|
43
|
+
className
|
|
44
|
+
)}
|
|
45
|
+
{...props}
|
|
46
|
+
/>
|
|
47
|
+
))
|
|
48
|
+
AvatarFallback.displayName = AvatarPrimitive.Fallback.displayName
|
|
49
|
+
|
|
50
|
+
export { Avatar, AvatarImage, AvatarFallback }
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import { cva, type VariantProps } from "class-variance-authority";
|
|
5
|
+
import { cn } from "@/lib/utils";
|
|
6
|
+
|
|
7
|
+
const badgeVariants = cva(
|
|
8
|
+
"inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2",
|
|
9
|
+
{
|
|
10
|
+
variants: {
|
|
11
|
+
variant: {
|
|
12
|
+
default:
|
|
13
|
+
"border-transparent bg-primary text-primary-foreground hover:bg-primary/80",
|
|
14
|
+
secondary:
|
|
15
|
+
"border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80",
|
|
16
|
+
destructive:
|
|
17
|
+
"border-transparent bg-destructive text-destructive-foreground hover:bg-destructive/80",
|
|
18
|
+
outline: "text-foreground",
|
|
19
|
+
},
|
|
20
|
+
},
|
|
21
|
+
defaultVariants: {
|
|
22
|
+
variant: "default",
|
|
23
|
+
},
|
|
24
|
+
}
|
|
25
|
+
);
|
|
26
|
+
|
|
27
|
+
export interface BadgeProps
|
|
28
|
+
extends React.HTMLAttributes<HTMLDivElement>,
|
|
29
|
+
VariantProps<typeof badgeVariants> {}
|
|
30
|
+
|
|
31
|
+
function Badge({ className, variant, ...props }: BadgeProps) {
|
|
32
|
+
return (
|
|
33
|
+
<div className={cn(badgeVariants({ variant }), className)} {...props} />
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export { Badge, badgeVariants };
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import * as React from "react"
|
|
2
|
+
import { Slot } from "@radix-ui/react-slot"
|
|
3
|
+
import { ChevronRight, MoreHorizontal } from "lucide-react"
|
|
4
|
+
|
|
5
|
+
import { cn } from "@/lib/utils"
|
|
6
|
+
|
|
7
|
+
const Breadcrumb = React.forwardRef<
|
|
8
|
+
HTMLElement,
|
|
9
|
+
React.ComponentPropsWithoutRef<"nav"> & {
|
|
10
|
+
separator?: React.ReactNode
|
|
11
|
+
}
|
|
12
|
+
>(({ ...props }, ref) => <nav ref={ref} aria-label="breadcrumb" {...props} />)
|
|
13
|
+
Breadcrumb.displayName = "Breadcrumb"
|
|
14
|
+
|
|
15
|
+
const BreadcrumbList = React.forwardRef<
|
|
16
|
+
HTMLOListElement,
|
|
17
|
+
React.ComponentPropsWithoutRef<"ol">
|
|
18
|
+
>(({ className, ...props }, ref) => (
|
|
19
|
+
<ol
|
|
20
|
+
ref={ref}
|
|
21
|
+
className={cn(
|
|
22
|
+
"flex flex-wrap items-center gap-1.5 break-words text-sm text-muted-foreground sm:gap-2.5",
|
|
23
|
+
className
|
|
24
|
+
)}
|
|
25
|
+
{...props}
|
|
26
|
+
/>
|
|
27
|
+
))
|
|
28
|
+
BreadcrumbList.displayName = "BreadcrumbList"
|
|
29
|
+
|
|
30
|
+
const BreadcrumbItem = React.forwardRef<
|
|
31
|
+
HTMLLIElement,
|
|
32
|
+
React.ComponentPropsWithoutRef<"li">
|
|
33
|
+
>(({ className, ...props }, ref) => (
|
|
34
|
+
<li
|
|
35
|
+
ref={ref}
|
|
36
|
+
className={cn("inline-flex items-center gap-1.5", className)}
|
|
37
|
+
{...props}
|
|
38
|
+
/>
|
|
39
|
+
))
|
|
40
|
+
BreadcrumbItem.displayName = "BreadcrumbItem"
|
|
41
|
+
|
|
42
|
+
const BreadcrumbLink = React.forwardRef<
|
|
43
|
+
HTMLAnchorElement,
|
|
44
|
+
React.ComponentPropsWithoutRef<"a"> & {
|
|
45
|
+
asChild?: boolean
|
|
46
|
+
}
|
|
47
|
+
>(({ asChild, className, ...props }, ref) => {
|
|
48
|
+
const Comp = asChild ? Slot : "a"
|
|
49
|
+
|
|
50
|
+
return (
|
|
51
|
+
<Comp
|
|
52
|
+
ref={ref}
|
|
53
|
+
className={cn("transition-colors hover:text-foreground", className)}
|
|
54
|
+
{...props}
|
|
55
|
+
/>
|
|
56
|
+
)
|
|
57
|
+
})
|
|
58
|
+
BreadcrumbLink.displayName = "BreadcrumbLink"
|
|
59
|
+
|
|
60
|
+
const BreadcrumbPage = React.forwardRef<
|
|
61
|
+
HTMLSpanElement,
|
|
62
|
+
React.ComponentPropsWithoutRef<"span">
|
|
63
|
+
>(({ className, ...props }, ref) => (
|
|
64
|
+
<span
|
|
65
|
+
ref={ref}
|
|
66
|
+
role="link"
|
|
67
|
+
aria-disabled="true"
|
|
68
|
+
aria-current="page"
|
|
69
|
+
className={cn("font-normal text-foreground", className)}
|
|
70
|
+
{...props}
|
|
71
|
+
/>
|
|
72
|
+
))
|
|
73
|
+
BreadcrumbPage.displayName = "BreadcrumbPage"
|
|
74
|
+
|
|
75
|
+
const BreadcrumbSeparator = ({
|
|
76
|
+
children,
|
|
77
|
+
className,
|
|
78
|
+
...props
|
|
79
|
+
}: React.ComponentProps<"li">) => (
|
|
80
|
+
<li
|
|
81
|
+
role="presentation"
|
|
82
|
+
aria-hidden="true"
|
|
83
|
+
className={cn("[&>svg]:size-3.5", className)}
|
|
84
|
+
{...props}
|
|
85
|
+
>
|
|
86
|
+
{children ?? <ChevronRight />}
|
|
87
|
+
</li>
|
|
88
|
+
)
|
|
89
|
+
BreadcrumbSeparator.displayName = "BreadcrumbSeparator"
|
|
90
|
+
|
|
91
|
+
const BreadcrumbEllipsis = ({
|
|
92
|
+
className,
|
|
93
|
+
...props
|
|
94
|
+
}: React.ComponentProps<"span">) => (
|
|
95
|
+
<span
|
|
96
|
+
role="presentation"
|
|
97
|
+
aria-hidden="true"
|
|
98
|
+
className={cn("flex h-9 w-9 items-center justify-center", className)}
|
|
99
|
+
{...props}
|
|
100
|
+
>
|
|
101
|
+
<MoreHorizontal className="h-4 w-4" />
|
|
102
|
+
<span className="sr-only">More</span>
|
|
103
|
+
</span>
|
|
104
|
+
)
|
|
105
|
+
BreadcrumbEllipsis.displayName = "BreadcrumbElipssis"
|
|
106
|
+
|
|
107
|
+
export {
|
|
108
|
+
Breadcrumb,
|
|
109
|
+
BreadcrumbList,
|
|
110
|
+
BreadcrumbItem,
|
|
111
|
+
BreadcrumbLink,
|
|
112
|
+
BreadcrumbPage,
|
|
113
|
+
BreadcrumbSeparator,
|
|
114
|
+
BreadcrumbEllipsis,
|
|
115
|
+
}
|