@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,324 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import React, { useEffect, useRef, useState } from "react";
|
|
4
|
+
import { renderToString } from "react-dom/server";
|
|
5
|
+
|
|
6
|
+
interface Icon {
|
|
7
|
+
x: number;
|
|
8
|
+
y: number;
|
|
9
|
+
z: number;
|
|
10
|
+
scale: number;
|
|
11
|
+
opacity: number;
|
|
12
|
+
id: number;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
interface IconCloudProps {
|
|
16
|
+
icons?: React.ReactNode[];
|
|
17
|
+
images?: string[];
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function easeOutCubic(t: number): number {
|
|
21
|
+
return 1 - Math.pow(1 - t, 3);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function IconCloud({ icons, images }: IconCloudProps) {
|
|
25
|
+
const canvasRef = useRef<HTMLCanvasElement>(null);
|
|
26
|
+
const [iconPositions, setIconPositions] = useState<Icon[]>([]);
|
|
27
|
+
const [rotation, setRotation] = useState({ x: 0, y: 0 });
|
|
28
|
+
const [isDragging, setIsDragging] = useState(false);
|
|
29
|
+
const [lastMousePos, setLastMousePos] = useState({ x: 0, y: 0 });
|
|
30
|
+
const [mousePos, setMousePos] = useState({ x: 0, y: 0 });
|
|
31
|
+
const [targetRotation, setTargetRotation] = useState<{
|
|
32
|
+
x: number;
|
|
33
|
+
y: number;
|
|
34
|
+
startX: number;
|
|
35
|
+
startY: number;
|
|
36
|
+
distance: number;
|
|
37
|
+
startTime: number;
|
|
38
|
+
duration: number;
|
|
39
|
+
} | null>(null);
|
|
40
|
+
const animationFrameRef = useRef<number>();
|
|
41
|
+
const rotationRef = useRef(rotation);
|
|
42
|
+
const iconCanvasesRef = useRef<HTMLCanvasElement[]>([]);
|
|
43
|
+
const imagesLoadedRef = useRef<boolean[]>([]);
|
|
44
|
+
|
|
45
|
+
// Create icon canvases once when icons/images change
|
|
46
|
+
useEffect(() => {
|
|
47
|
+
if (!icons && !images) return;
|
|
48
|
+
|
|
49
|
+
const items = icons || images || [];
|
|
50
|
+
imagesLoadedRef.current = new Array(items.length).fill(false);
|
|
51
|
+
|
|
52
|
+
const newIconCanvases = items.map((item, index) => {
|
|
53
|
+
const offscreen = document.createElement("canvas");
|
|
54
|
+
offscreen.width = 40;
|
|
55
|
+
offscreen.height = 40;
|
|
56
|
+
const offCtx = offscreen.getContext("2d");
|
|
57
|
+
|
|
58
|
+
if (offCtx) {
|
|
59
|
+
if (images) {
|
|
60
|
+
// Handle image URLs directly
|
|
61
|
+
const img = new Image();
|
|
62
|
+
img.crossOrigin = "anonymous";
|
|
63
|
+
img.src = items[index] as string;
|
|
64
|
+
img.onload = () => {
|
|
65
|
+
offCtx.clearRect(0, 0, offscreen.width, offscreen.height);
|
|
66
|
+
|
|
67
|
+
// Create circular clipping path
|
|
68
|
+
offCtx.beginPath();
|
|
69
|
+
offCtx.arc(20, 20, 20, 0, Math.PI * 2);
|
|
70
|
+
offCtx.closePath();
|
|
71
|
+
offCtx.clip();
|
|
72
|
+
|
|
73
|
+
// Draw the image
|
|
74
|
+
offCtx.drawImage(img, 0, 0, 40, 40);
|
|
75
|
+
|
|
76
|
+
imagesLoadedRef.current[index] = true;
|
|
77
|
+
};
|
|
78
|
+
} else {
|
|
79
|
+
// Handle SVG icons
|
|
80
|
+
offCtx.scale(0.4, 0.4);
|
|
81
|
+
const svgString = renderToString(item as React.ReactElement);
|
|
82
|
+
const img = new Image();
|
|
83
|
+
img.src = "data:image/svg+xml;base64," + btoa(svgString);
|
|
84
|
+
img.onload = () => {
|
|
85
|
+
offCtx.clearRect(0, 0, offscreen.width, offscreen.height);
|
|
86
|
+
offCtx.drawImage(img, 0, 0);
|
|
87
|
+
imagesLoadedRef.current[index] = true;
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
return offscreen;
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
iconCanvasesRef.current = newIconCanvases;
|
|
95
|
+
}, [icons, images]);
|
|
96
|
+
|
|
97
|
+
// Generate initial icon positions on a sphere
|
|
98
|
+
useEffect(() => {
|
|
99
|
+
const items = icons || images || [];
|
|
100
|
+
const newIcons: Icon[] = [];
|
|
101
|
+
const numIcons = items.length || 20;
|
|
102
|
+
|
|
103
|
+
// Fibonacci sphere parameters
|
|
104
|
+
const offset = 2 / numIcons;
|
|
105
|
+
const increment = Math.PI * (3 - Math.sqrt(5));
|
|
106
|
+
|
|
107
|
+
for (let i = 0; i < numIcons; i++) {
|
|
108
|
+
const y = i * offset - 1 + offset / 2;
|
|
109
|
+
const r = Math.sqrt(1 - y * y);
|
|
110
|
+
const phi = i * increment;
|
|
111
|
+
|
|
112
|
+
const x = Math.cos(phi) * r;
|
|
113
|
+
const z = Math.sin(phi) * r;
|
|
114
|
+
|
|
115
|
+
newIcons.push({
|
|
116
|
+
x: x * 100,
|
|
117
|
+
y: y * 100,
|
|
118
|
+
z: z * 100,
|
|
119
|
+
scale: 1,
|
|
120
|
+
opacity: 1,
|
|
121
|
+
id: i,
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
setIconPositions(newIcons);
|
|
125
|
+
}, [icons, images]);
|
|
126
|
+
|
|
127
|
+
// Handle mouse events
|
|
128
|
+
const handleMouseDown = (e: React.MouseEvent<HTMLCanvasElement>) => {
|
|
129
|
+
const rect = canvasRef.current?.getBoundingClientRect();
|
|
130
|
+
if (!rect || !canvasRef.current) return;
|
|
131
|
+
|
|
132
|
+
const x = e.clientX - rect.left;
|
|
133
|
+
const y = e.clientY - rect.top;
|
|
134
|
+
|
|
135
|
+
const ctx = canvasRef.current.getContext("2d");
|
|
136
|
+
if (!ctx) return;
|
|
137
|
+
|
|
138
|
+
iconPositions.forEach((icon) => {
|
|
139
|
+
const cosX = Math.cos(rotationRef.current.x);
|
|
140
|
+
const sinX = Math.sin(rotationRef.current.x);
|
|
141
|
+
const cosY = Math.cos(rotationRef.current.y);
|
|
142
|
+
const sinY = Math.sin(rotationRef.current.y);
|
|
143
|
+
|
|
144
|
+
const rotatedX = icon.x * cosY - icon.z * sinY;
|
|
145
|
+
const rotatedZ = icon.x * sinY + icon.z * cosY;
|
|
146
|
+
const rotatedY = icon.y * cosX + rotatedZ * sinX;
|
|
147
|
+
|
|
148
|
+
const screenX = canvasRef.current!.width / 2 + rotatedX;
|
|
149
|
+
const screenY = canvasRef.current!.height / 2 + rotatedY;
|
|
150
|
+
|
|
151
|
+
const scale = (rotatedZ + 200) / 300;
|
|
152
|
+
const radius = 20 * scale;
|
|
153
|
+
const dx = x - screenX;
|
|
154
|
+
const dy = y - screenY;
|
|
155
|
+
|
|
156
|
+
if (dx * dx + dy * dy < radius * radius) {
|
|
157
|
+
const targetX = -Math.atan2(
|
|
158
|
+
icon.y,
|
|
159
|
+
Math.sqrt(icon.x * icon.x + icon.z * icon.z),
|
|
160
|
+
);
|
|
161
|
+
const targetY = Math.atan2(icon.x, icon.z);
|
|
162
|
+
|
|
163
|
+
const currentX = rotationRef.current.x;
|
|
164
|
+
const currentY = rotationRef.current.y;
|
|
165
|
+
const distance = Math.sqrt(
|
|
166
|
+
Math.pow(targetX - currentX, 2) + Math.pow(targetY - currentY, 2),
|
|
167
|
+
);
|
|
168
|
+
|
|
169
|
+
const duration = Math.min(2000, Math.max(800, distance * 1000));
|
|
170
|
+
|
|
171
|
+
setTargetRotation({
|
|
172
|
+
x: targetX,
|
|
173
|
+
y: targetY,
|
|
174
|
+
startX: currentX,
|
|
175
|
+
startY: currentY,
|
|
176
|
+
distance,
|
|
177
|
+
startTime: performance.now(),
|
|
178
|
+
duration,
|
|
179
|
+
});
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
setIsDragging(true);
|
|
185
|
+
setLastMousePos({ x: e.clientX, y: e.clientY });
|
|
186
|
+
};
|
|
187
|
+
|
|
188
|
+
const handleMouseMove = (e: React.MouseEvent<HTMLCanvasElement>) => {
|
|
189
|
+
const rect = canvasRef.current?.getBoundingClientRect();
|
|
190
|
+
if (rect) {
|
|
191
|
+
const x = e.clientX - rect.left;
|
|
192
|
+
const y = e.clientY - rect.top;
|
|
193
|
+
setMousePos({ x, y });
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
if (isDragging) {
|
|
197
|
+
const deltaX = e.clientX - lastMousePos.x;
|
|
198
|
+
const deltaY = e.clientY - lastMousePos.y;
|
|
199
|
+
|
|
200
|
+
rotationRef.current = {
|
|
201
|
+
x: rotationRef.current.x + deltaY * 0.002,
|
|
202
|
+
y: rotationRef.current.y + deltaX * 0.002,
|
|
203
|
+
};
|
|
204
|
+
|
|
205
|
+
setLastMousePos({ x: e.clientX, y: e.clientY });
|
|
206
|
+
}
|
|
207
|
+
};
|
|
208
|
+
|
|
209
|
+
const handleMouseUp = () => {
|
|
210
|
+
setIsDragging(false);
|
|
211
|
+
};
|
|
212
|
+
|
|
213
|
+
// Animation and rendering
|
|
214
|
+
useEffect(() => {
|
|
215
|
+
const canvas = canvasRef.current;
|
|
216
|
+
const ctx = canvas?.getContext("2d");
|
|
217
|
+
if (!canvas || !ctx) return;
|
|
218
|
+
|
|
219
|
+
const animate = () => {
|
|
220
|
+
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
|
221
|
+
|
|
222
|
+
const centerX = canvas.width / 2;
|
|
223
|
+
const centerY = canvas.height / 2;
|
|
224
|
+
const maxDistance = Math.sqrt(centerX * centerX + centerY * centerY);
|
|
225
|
+
const dx = mousePos.x - centerX;
|
|
226
|
+
const dy = mousePos.y - centerY;
|
|
227
|
+
const distance = Math.sqrt(dx * dx + dy * dy);
|
|
228
|
+
const speed = 0.003 + (distance / maxDistance) * 0.01;
|
|
229
|
+
|
|
230
|
+
if (targetRotation) {
|
|
231
|
+
const elapsed = performance.now() - targetRotation.startTime;
|
|
232
|
+
const progress = Math.min(1, elapsed / targetRotation.duration);
|
|
233
|
+
const easedProgress = easeOutCubic(progress);
|
|
234
|
+
|
|
235
|
+
rotationRef.current = {
|
|
236
|
+
x:
|
|
237
|
+
targetRotation.startX +
|
|
238
|
+
(targetRotation.x - targetRotation.startX) * easedProgress,
|
|
239
|
+
y:
|
|
240
|
+
targetRotation.startY +
|
|
241
|
+
(targetRotation.y - targetRotation.startY) * easedProgress,
|
|
242
|
+
};
|
|
243
|
+
|
|
244
|
+
if (progress >= 1) {
|
|
245
|
+
setTargetRotation(null);
|
|
246
|
+
}
|
|
247
|
+
} else if (!isDragging) {
|
|
248
|
+
rotationRef.current = {
|
|
249
|
+
x: rotationRef.current.x + (dy / canvas.height) * speed,
|
|
250
|
+
y: rotationRef.current.y + (dx / canvas.width) * speed,
|
|
251
|
+
};
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
iconPositions.forEach((icon, index) => {
|
|
255
|
+
const cosX = Math.cos(rotationRef.current.x);
|
|
256
|
+
const sinX = Math.sin(rotationRef.current.x);
|
|
257
|
+
const cosY = Math.cos(rotationRef.current.y);
|
|
258
|
+
const sinY = Math.sin(rotationRef.current.y);
|
|
259
|
+
|
|
260
|
+
const rotatedX = icon.x * cosY - icon.z * sinY;
|
|
261
|
+
const rotatedZ = icon.x * sinY + icon.z * cosY;
|
|
262
|
+
const rotatedY = icon.y * cosX + rotatedZ * sinX;
|
|
263
|
+
|
|
264
|
+
const scale = (rotatedZ + 200) / 300;
|
|
265
|
+
const opacity = Math.max(0.2, Math.min(1, (rotatedZ + 150) / 200));
|
|
266
|
+
|
|
267
|
+
ctx.save();
|
|
268
|
+
ctx.translate(
|
|
269
|
+
canvas.width / 2 + rotatedX,
|
|
270
|
+
canvas.height / 2 + rotatedY,
|
|
271
|
+
);
|
|
272
|
+
ctx.scale(scale, scale);
|
|
273
|
+
ctx.globalAlpha = opacity;
|
|
274
|
+
|
|
275
|
+
if (icons || images) {
|
|
276
|
+
// Only try to render icons/images if they exist
|
|
277
|
+
if (
|
|
278
|
+
iconCanvasesRef.current[index] &&
|
|
279
|
+
imagesLoadedRef.current[index]
|
|
280
|
+
) {
|
|
281
|
+
ctx.drawImage(iconCanvasesRef.current[index], -20, -20, 40, 40);
|
|
282
|
+
}
|
|
283
|
+
} else {
|
|
284
|
+
// Show numbered circles if no icons/images are provided
|
|
285
|
+
ctx.beginPath();
|
|
286
|
+
ctx.arc(0, 0, 20, 0, Math.PI * 2);
|
|
287
|
+
ctx.fillStyle = "#4444ff";
|
|
288
|
+
ctx.fill();
|
|
289
|
+
ctx.fillStyle = "white";
|
|
290
|
+
ctx.textAlign = "center";
|
|
291
|
+
ctx.textBaseline = "middle";
|
|
292
|
+
ctx.font = "16px Arial";
|
|
293
|
+
ctx.fillText(`${icon.id + 1}`, 0, 0);
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
ctx.restore();
|
|
297
|
+
});
|
|
298
|
+
animationFrameRef.current = requestAnimationFrame(animate);
|
|
299
|
+
};
|
|
300
|
+
|
|
301
|
+
animate();
|
|
302
|
+
|
|
303
|
+
return () => {
|
|
304
|
+
if (animationFrameRef.current) {
|
|
305
|
+
cancelAnimationFrame(animationFrameRef.current);
|
|
306
|
+
}
|
|
307
|
+
};
|
|
308
|
+
}, [icons, images, iconPositions, isDragging, mousePos, targetRotation]);
|
|
309
|
+
|
|
310
|
+
return (
|
|
311
|
+
<canvas
|
|
312
|
+
ref={canvasRef}
|
|
313
|
+
width={400}
|
|
314
|
+
height={400}
|
|
315
|
+
onMouseDown={handleMouseDown}
|
|
316
|
+
onMouseMove={handleMouseMove}
|
|
317
|
+
onMouseUp={handleMouseUp}
|
|
318
|
+
onMouseLeave={handleMouseUp}
|
|
319
|
+
className="rounded-full"
|
|
320
|
+
aria-label="Interactive 3D Icon Cloud"
|
|
321
|
+
role="img"
|
|
322
|
+
/>
|
|
323
|
+
);
|
|
324
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import * as React from "react"
|
|
2
|
+
|
|
3
|
+
import { cn } from "@/lib/utils"
|
|
4
|
+
|
|
5
|
+
export interface InputProps
|
|
6
|
+
extends React.InputHTMLAttributes<HTMLInputElement> {}
|
|
7
|
+
|
|
8
|
+
const Input = React.forwardRef<HTMLInputElement, InputProps>(
|
|
9
|
+
({ className, type, ...props }, ref) => {
|
|
10
|
+
return (
|
|
11
|
+
<input
|
|
12
|
+
type={type}
|
|
13
|
+
className={cn(
|
|
14
|
+
"flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
|
|
15
|
+
className
|
|
16
|
+
)}
|
|
17
|
+
ref={ref}
|
|
18
|
+
{...props}
|
|
19
|
+
/>
|
|
20
|
+
)
|
|
21
|
+
}
|
|
22
|
+
)
|
|
23
|
+
Input.displayName = "Input"
|
|
24
|
+
|
|
25
|
+
export { Input }
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { ArrowRight } from "lucide-react";
|
|
3
|
+
import { cn } from "@/lib/utils";
|
|
4
|
+
|
|
5
|
+
interface InteractiveHoverButtonProps
|
|
6
|
+
extends React.ButtonHTMLAttributes<HTMLButtonElement> {}
|
|
7
|
+
|
|
8
|
+
export const InteractiveHoverButton = React.forwardRef<
|
|
9
|
+
HTMLButtonElement,
|
|
10
|
+
InteractiveHoverButtonProps
|
|
11
|
+
>(({ children, className, ...props }, ref) => {
|
|
12
|
+
return (
|
|
13
|
+
<button
|
|
14
|
+
ref={ref}
|
|
15
|
+
className={cn(
|
|
16
|
+
"group relative w-auto cursor-pointer overflow-hidden rounded-full border bg-background p-2 px-6 text-center font-semibold",
|
|
17
|
+
className,
|
|
18
|
+
)}
|
|
19
|
+
{...props}
|
|
20
|
+
>
|
|
21
|
+
<div className="flex items-center gap-2">
|
|
22
|
+
<div className="h-2 w-2 rounded-full bg-primary transition-all duration-300 group-hover:scale-[100.8]"></div>
|
|
23
|
+
<span className="inline-block transition-all duration-300 group-hover:translate-x-12 group-hover:opacity-0">
|
|
24
|
+
{children}
|
|
25
|
+
</span>
|
|
26
|
+
</div>
|
|
27
|
+
<div className="absolute top-0 z-10 flex h-full w-full translate-x-12 items-center justify-center gap-2 text-primary-foreground opacity-0 transition-all duration-300 group-hover:-translate-x-5 group-hover:opacity-100">
|
|
28
|
+
<span>{children}</span>
|
|
29
|
+
<ArrowRight className="w-4 h-4" />
|
|
30
|
+
</div>
|
|
31
|
+
</button>
|
|
32
|
+
);
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
InteractiveHoverButton.displayName = "InteractiveHoverButton";
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"use client"
|
|
2
|
+
|
|
3
|
+
import * as React from "react"
|
|
4
|
+
import * as PopoverPrimitive from "@radix-ui/react-popover"
|
|
5
|
+
|
|
6
|
+
import { cn } from "@/lib/utils"
|
|
7
|
+
|
|
8
|
+
const Popover = PopoverPrimitive.Root
|
|
9
|
+
|
|
10
|
+
const PopoverTrigger = PopoverPrimitive.Trigger
|
|
11
|
+
|
|
12
|
+
const PopoverAnchor = PopoverPrimitive.Anchor
|
|
13
|
+
|
|
14
|
+
const PopoverContent = React.forwardRef<
|
|
15
|
+
React.ElementRef<typeof PopoverPrimitive.Content>,
|
|
16
|
+
React.ComponentPropsWithoutRef<typeof PopoverPrimitive.Content>
|
|
17
|
+
>(({ className, align = "center", sideOffset = 4, ...props }, ref) => (
|
|
18
|
+
<PopoverPrimitive.Portal>
|
|
19
|
+
<PopoverPrimitive.Content
|
|
20
|
+
ref={ref}
|
|
21
|
+
align={align}
|
|
22
|
+
sideOffset={sideOffset}
|
|
23
|
+
className={cn(
|
|
24
|
+
"z-50 w-72 rounded-md border bg-popover p-4 text-popover-foreground shadow-md outline-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
|
|
25
|
+
className
|
|
26
|
+
)}
|
|
27
|
+
{...props}
|
|
28
|
+
/>
|
|
29
|
+
</PopoverPrimitive.Portal>
|
|
30
|
+
))
|
|
31
|
+
PopoverContent.displayName = PopoverPrimitive.Content.displayName
|
|
32
|
+
|
|
33
|
+
export { Popover, PopoverTrigger, PopoverContent, PopoverAnchor }
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"use client"
|
|
2
|
+
|
|
3
|
+
import * as React from "react"
|
|
4
|
+
import * as ScrollAreaPrimitive from "@radix-ui/react-scroll-area"
|
|
5
|
+
|
|
6
|
+
import { cn } from "@/lib/utils"
|
|
7
|
+
|
|
8
|
+
const ScrollArea = React.forwardRef<
|
|
9
|
+
React.ElementRef<typeof ScrollAreaPrimitive.Root>,
|
|
10
|
+
React.ComponentPropsWithoutRef<typeof ScrollAreaPrimitive.Root>
|
|
11
|
+
>(({ className, children, ...props }, ref) => (
|
|
12
|
+
<ScrollAreaPrimitive.Root
|
|
13
|
+
ref={ref}
|
|
14
|
+
className={cn("relative overflow-hidden", className)}
|
|
15
|
+
{...props}
|
|
16
|
+
>
|
|
17
|
+
<ScrollAreaPrimitive.Viewport className="h-full w-full rounded-[inherit]">
|
|
18
|
+
{children}
|
|
19
|
+
</ScrollAreaPrimitive.Viewport>
|
|
20
|
+
<ScrollBar />
|
|
21
|
+
<ScrollAreaPrimitive.Corner />
|
|
22
|
+
</ScrollAreaPrimitive.Root>
|
|
23
|
+
))
|
|
24
|
+
ScrollArea.displayName = ScrollAreaPrimitive.Root.displayName
|
|
25
|
+
|
|
26
|
+
const ScrollBar = React.forwardRef<
|
|
27
|
+
React.ElementRef<typeof ScrollAreaPrimitive.ScrollAreaScrollbar>,
|
|
28
|
+
React.ComponentPropsWithoutRef<typeof ScrollAreaPrimitive.ScrollAreaScrollbar>
|
|
29
|
+
>(({ className, orientation = "vertical", ...props }, ref) => (
|
|
30
|
+
<ScrollAreaPrimitive.ScrollAreaScrollbar
|
|
31
|
+
ref={ref}
|
|
32
|
+
orientation={orientation}
|
|
33
|
+
className={cn(
|
|
34
|
+
"flex touch-none select-none transition-colors",
|
|
35
|
+
orientation === "vertical" &&
|
|
36
|
+
"h-full w-2.5 border-l border-l-transparent p-[1px]",
|
|
37
|
+
orientation === "horizontal" &&
|
|
38
|
+
"h-2.5 flex-col border-t border-t-transparent p-[1px]",
|
|
39
|
+
className
|
|
40
|
+
)}
|
|
41
|
+
{...props}
|
|
42
|
+
>
|
|
43
|
+
<ScrollAreaPrimitive.ScrollAreaThumb className="relative flex-1 rounded-full bg-border" />
|
|
44
|
+
</ScrollAreaPrimitive.ScrollAreaScrollbar>
|
|
45
|
+
))
|
|
46
|
+
ScrollBar.displayName = ScrollAreaPrimitive.ScrollAreaScrollbar.displayName
|
|
47
|
+
|
|
48
|
+
export { ScrollArea, ScrollBar }
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import * as SeparatorPrimitive from "@radix-ui/react-separator";
|
|
5
|
+
import { cn } from "@/lib/utils";
|
|
6
|
+
|
|
7
|
+
const Separator = React.forwardRef<
|
|
8
|
+
React.ElementRef<typeof SeparatorPrimitive.Root>,
|
|
9
|
+
React.ComponentPropsWithoutRef<typeof SeparatorPrimitive.Root>
|
|
10
|
+
>(
|
|
11
|
+
(
|
|
12
|
+
{ className, orientation = "horizontal", decorative = true, ...props },
|
|
13
|
+
ref
|
|
14
|
+
) => (
|
|
15
|
+
<SeparatorPrimitive.Root
|
|
16
|
+
ref={ref}
|
|
17
|
+
decorative={decorative}
|
|
18
|
+
orientation={orientation}
|
|
19
|
+
className={cn(
|
|
20
|
+
"shrink-0 bg-border",
|
|
21
|
+
orientation === "horizontal" ? "h-[1px] w-full" : "h-full w-[1px]",
|
|
22
|
+
className
|
|
23
|
+
)}
|
|
24
|
+
{...props}
|
|
25
|
+
/>
|
|
26
|
+
)
|
|
27
|
+
);
|
|
28
|
+
Separator.displayName = SeparatorPrimitive.Root.displayName;
|
|
29
|
+
|
|
30
|
+
export { Separator };
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import * as SheetPrimitive from "@radix-ui/react-dialog";
|
|
5
|
+
import { cva, type VariantProps } from "class-variance-authority";
|
|
6
|
+
import { X } from "lucide-react";
|
|
7
|
+
|
|
8
|
+
import { cn } from "@/lib/utils";
|
|
9
|
+
|
|
10
|
+
const Sheet = SheetPrimitive.Root;
|
|
11
|
+
|
|
12
|
+
const SheetTrigger = SheetPrimitive.Trigger;
|
|
13
|
+
|
|
14
|
+
const SheetClose = SheetPrimitive.Close;
|
|
15
|
+
|
|
16
|
+
const SheetPortal = SheetPrimitive.Portal;
|
|
17
|
+
|
|
18
|
+
const SheetOverlay = React.forwardRef<
|
|
19
|
+
React.ElementRef<typeof SheetPrimitive.Overlay>,
|
|
20
|
+
React.ComponentPropsWithoutRef<typeof SheetPrimitive.Overlay>
|
|
21
|
+
>(({ className, ...props }, ref) => (
|
|
22
|
+
<SheetPrimitive.Overlay
|
|
23
|
+
className={cn(
|
|
24
|
+
"fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
|
|
25
|
+
className
|
|
26
|
+
)}
|
|
27
|
+
{...props}
|
|
28
|
+
ref={ref}
|
|
29
|
+
/>
|
|
30
|
+
));
|
|
31
|
+
SheetOverlay.displayName = SheetPrimitive.Overlay.displayName;
|
|
32
|
+
|
|
33
|
+
const sheetVariants = cva(
|
|
34
|
+
"fixed z-50 gap-4 bg-background p-6 shadow-lg transition ease-in-out data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:duration-300 data-[state=open]:duration-500",
|
|
35
|
+
{
|
|
36
|
+
variants: {
|
|
37
|
+
side: {
|
|
38
|
+
top: "inset-x-0 top-0 border-b data-[state=closed]:slide-out-to-top data-[state=open]:slide-in-from-top",
|
|
39
|
+
bottom:
|
|
40
|
+
"inset-x-0 bottom-0 border-t data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom",
|
|
41
|
+
left: "inset-y-0 left-0 h-full w-3/4 border-r data-[state=closed]:slide-out-to-left data-[state=open]:slide-in-from-left sm:max-w-sm",
|
|
42
|
+
right:
|
|
43
|
+
"inset-y-0 right-0 h-full w-3/4 border-l data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right sm:max-w-sm",
|
|
44
|
+
},
|
|
45
|
+
},
|
|
46
|
+
defaultVariants: {
|
|
47
|
+
side: "right",
|
|
48
|
+
},
|
|
49
|
+
}
|
|
50
|
+
);
|
|
51
|
+
|
|
52
|
+
interface SheetContentProps
|
|
53
|
+
extends React.ComponentPropsWithoutRef<typeof SheetPrimitive.Content>,
|
|
54
|
+
VariantProps<typeof sheetVariants> {}
|
|
55
|
+
|
|
56
|
+
const SheetContent = React.forwardRef<
|
|
57
|
+
React.ElementRef<typeof SheetPrimitive.Content>,
|
|
58
|
+
SheetContentProps
|
|
59
|
+
>(({ side = "right", className, children, ...props }, ref) => (
|
|
60
|
+
<SheetPortal>
|
|
61
|
+
<SheetOverlay />
|
|
62
|
+
<SheetPrimitive.Content
|
|
63
|
+
ref={ref}
|
|
64
|
+
className={cn(sheetVariants({ side }), className)}
|
|
65
|
+
{...props}
|
|
66
|
+
>
|
|
67
|
+
{children}
|
|
68
|
+
<SheetPrimitive.Close className="absolute right-4 top-7 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-secondary">
|
|
69
|
+
<X className="h-4 w-4" />
|
|
70
|
+
<span className="sr-only">Close</span>
|
|
71
|
+
</SheetPrimitive.Close>
|
|
72
|
+
</SheetPrimitive.Content>
|
|
73
|
+
</SheetPortal>
|
|
74
|
+
));
|
|
75
|
+
SheetContent.displayName = SheetPrimitive.Content.displayName;
|
|
76
|
+
|
|
77
|
+
const SheetHeader = ({
|
|
78
|
+
className,
|
|
79
|
+
...props
|
|
80
|
+
}: React.HTMLAttributes<HTMLDivElement>) => (
|
|
81
|
+
<div
|
|
82
|
+
className={cn(
|
|
83
|
+
"flex flex-col space-y-2 text-center sm:text-left",
|
|
84
|
+
className
|
|
85
|
+
)}
|
|
86
|
+
{...props}
|
|
87
|
+
/>
|
|
88
|
+
);
|
|
89
|
+
SheetHeader.displayName = "SheetHeader";
|
|
90
|
+
|
|
91
|
+
const SheetFooter = ({
|
|
92
|
+
className,
|
|
93
|
+
...props
|
|
94
|
+
}: React.HTMLAttributes<HTMLDivElement>) => (
|
|
95
|
+
<div
|
|
96
|
+
className={cn(
|
|
97
|
+
"flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2",
|
|
98
|
+
className
|
|
99
|
+
)}
|
|
100
|
+
{...props}
|
|
101
|
+
/>
|
|
102
|
+
);
|
|
103
|
+
SheetFooter.displayName = "SheetFooter";
|
|
104
|
+
|
|
105
|
+
const SheetTitle = React.forwardRef<
|
|
106
|
+
React.ElementRef<typeof SheetPrimitive.Title>,
|
|
107
|
+
React.ComponentPropsWithoutRef<typeof SheetPrimitive.Title>
|
|
108
|
+
>(({ className, ...props }, ref) => (
|
|
109
|
+
<SheetPrimitive.Title
|
|
110
|
+
ref={ref}
|
|
111
|
+
className={cn("text-lg font-semibold text-foreground", className)}
|
|
112
|
+
{...props}
|
|
113
|
+
/>
|
|
114
|
+
));
|
|
115
|
+
SheetTitle.displayName = SheetPrimitive.Title.displayName;
|
|
116
|
+
|
|
117
|
+
const SheetDescription = React.forwardRef<
|
|
118
|
+
React.ElementRef<typeof SheetPrimitive.Description>,
|
|
119
|
+
React.ComponentPropsWithoutRef<typeof SheetPrimitive.Description>
|
|
120
|
+
>(({ className, ...props }, ref) => (
|
|
121
|
+
<SheetPrimitive.Description
|
|
122
|
+
ref={ref}
|
|
123
|
+
className={cn("text-sm text-muted-foreground", className)}
|
|
124
|
+
{...props}
|
|
125
|
+
/>
|
|
126
|
+
));
|
|
127
|
+
SheetDescription.displayName = SheetPrimitive.Description.displayName;
|
|
128
|
+
|
|
129
|
+
export {
|
|
130
|
+
Sheet,
|
|
131
|
+
SheetPortal,
|
|
132
|
+
SheetOverlay,
|
|
133
|
+
SheetTrigger,
|
|
134
|
+
SheetClose,
|
|
135
|
+
SheetContent,
|
|
136
|
+
SheetHeader,
|
|
137
|
+
SheetFooter,
|
|
138
|
+
SheetTitle,
|
|
139
|
+
SheetDescription,
|
|
140
|
+
};
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
|
|
5
|
+
import { cn } from "@/lib/utils";
|
|
6
|
+
|
|
7
|
+
interface ShineBorderProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
8
|
+
/**
|
|
9
|
+
* Width of the border in pixels
|
|
10
|
+
* @default 1
|
|
11
|
+
*/
|
|
12
|
+
borderWidth?: number;
|
|
13
|
+
/**
|
|
14
|
+
* Duration of the animation in seconds
|
|
15
|
+
* @default 14
|
|
16
|
+
*/
|
|
17
|
+
duration?: number;
|
|
18
|
+
/**
|
|
19
|
+
* Color of the border, can be a single color or an array of colors
|
|
20
|
+
* @default "#000000"
|
|
21
|
+
*/
|
|
22
|
+
shineColor?: string | string[];
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Shine Border
|
|
27
|
+
*
|
|
28
|
+
* An animated background border effect component with configurable properties.
|
|
29
|
+
*/
|
|
30
|
+
export function ShineBorder({
|
|
31
|
+
borderWidth = 1,
|
|
32
|
+
duration = 14,
|
|
33
|
+
shineColor = "#000000",
|
|
34
|
+
className,
|
|
35
|
+
style,
|
|
36
|
+
...props
|
|
37
|
+
}: ShineBorderProps) {
|
|
38
|
+
return (
|
|
39
|
+
<div
|
|
40
|
+
style={
|
|
41
|
+
{
|
|
42
|
+
"--border-width": `${borderWidth}px`,
|
|
43
|
+
"--duration": `${duration}s`,
|
|
44
|
+
backgroundImage: `radial-gradient(transparent,transparent, ${
|
|
45
|
+
Array.isArray(shineColor) ? shineColor.join(",") : shineColor
|
|
46
|
+
},transparent,transparent)`,
|
|
47
|
+
backgroundSize: "300% 300%",
|
|
48
|
+
mask: `linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0)`,
|
|
49
|
+
WebkitMask: `linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0)`,
|
|
50
|
+
WebkitMaskComposite: "xor",
|
|
51
|
+
maskComposite: "exclude",
|
|
52
|
+
padding: "var(--border-width)",
|
|
53
|
+
...style,
|
|
54
|
+
} as React.CSSProperties
|
|
55
|
+
}
|
|
56
|
+
className={cn(
|
|
57
|
+
"pointer-events-none absolute inset-0 size-full rounded-[inherit] will-change-[background-position] motion-safe:animate-shine",
|
|
58
|
+
className,
|
|
59
|
+
)}
|
|
60
|
+
{...props}
|
|
61
|
+
/>
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
export default ShineBorder;
|