slashh-ui 1.3.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 +36 -0
- package/dist/__registry__/index.d.ts +1 -0
- package/dist/__registry__/index.js +492 -0
- package/dist/app/(auth)/layout.d.ts +5 -0
- package/dist/app/(auth)/layout.js +8 -0
- package/dist/app/(auth)/login/page.d.ts +1 -0
- package/dist/app/(auth)/login/page.js +45 -0
- package/dist/app/(protected)/component/[id]/page.d.ts +5 -0
- package/dist/app/(protected)/component/[id]/page.js +13 -0
- package/dist/app/(protected)/component/page.d.ts +2 -0
- package/dist/app/(protected)/component/page.js +26 -0
- package/dist/app/(protected)/docs/page.d.ts +2 -0
- package/dist/app/(protected)/docs/page.js +43 -0
- package/dist/app/account/page.d.ts +1 -0
- package/dist/app/account/page.js +38 -0
- package/dist/app/api/me/route.d.ts +8 -0
- package/dist/app/api/me/route.js +20 -0
- package/dist/app/layout.d.ts +6 -0
- package/dist/app/layout.js +21 -0
- package/dist/app/page.d.ts +2 -0
- package/dist/app/page.js +11 -0
- package/dist/app/pricing/page.d.ts +2 -0
- package/dist/app/pricing/page.js +5 -0
- package/dist/bin/index.d.ts +2 -0
- package/dist/bin/index.js +27 -0
- package/dist/components/smooth-scroll.d.ts +4 -0
- package/dist/components/smooth-scroll.js +21 -0
- package/dist/components/toast.d.ts +11 -0
- package/dist/components/toast.js +39 -0
- package/dist/components/ui/IndustryProof.d.ts +1 -0
- package/dist/components/ui/IndustryProof.js +55 -0
- package/dist/components/ui/ShowcaseContainer.d.ts +8 -0
- package/dist/components/ui/ShowcaseContainer.js +139 -0
- package/dist/components/ui/dot-cursor.d.ts +2 -0
- package/dist/components/ui/dot-cursor.js +70 -0
- package/dist/components/ui/featuredComponents.d.ts +2 -0
- package/dist/components/ui/featuredComponents.js +14 -0
- package/dist/components/ui/footer.d.ts +2 -0
- package/dist/components/ui/footer.js +5 -0
- package/dist/components/ui/hero.d.ts +3 -0
- package/dist/components/ui/hero.js +21 -0
- package/dist/components/ui/navbar.d.ts +3 -0
- package/dist/components/ui/navbar.js +102 -0
- package/dist/components/ui/pricing.d.ts +2 -0
- package/dist/components/ui/pricing.js +26 -0
- package/dist/hooks/use-component-search.d.ts +5 -0
- package/dist/hooks/use-component-search.js +37 -0
- package/dist/lib/actions/auth.action.d.ts +8 -0
- package/dist/lib/actions/auth.action.js +66 -0
- package/dist/lib/auth.d.ts +1 -0
- package/dist/lib/auth.js +15 -0
- package/dist/lib/email.d.ts +1 -0
- package/dist/lib/email.js +42 -0
- package/dist/lib/prisma.d.ts +2 -0
- package/dist/lib/prisma.js +8 -0
- package/dist/lib/registry.d.ts +1 -0
- package/dist/lib/registry.js +16 -0
- package/dist/lib/utils.d.ts +2 -0
- package/dist/lib/utils.js +5 -0
- package/dist/middleware/middleware.d.ts +5 -0
- package/dist/middleware/middleware.js +19 -0
- package/dist/next.config.d.ts +3 -0
- package/dist/next.config.js +4 -0
- package/dist/prisma.config.d.ts +3 -0
- package/dist/prisma.config.js +13 -0
- package/dist/registry/details/buttons/neubrutal-button-details.d.ts +2 -0
- package/dist/registry/details/buttons/neubrutal-button-details.js +25 -0
- package/dist/registry/details/cursor/dot-cursor-details.d.ts +2 -0
- package/dist/registry/details/cursor/dot-cursor-details.js +5 -0
- package/dist/registry/details/navbar/floating-navbar-details.d.ts +2 -0
- package/dist/registry/details/navbar/floating-navbar-details.js +5 -0
- package/dist/registry/details/scrollbars/minimal-scrollbar-details.d.ts +0 -0
- package/dist/registry/details/scrollbars/minimal-scrollbar-details.js +1 -0
- package/dist/registry/index.d.ts +7 -0
- package/dist/registry/index.js +31 -0
- package/dist/registry/ui/buttons/neubrutal-button.d.ts +6 -0
- package/dist/registry/ui/buttons/neubrutal-button.js +18 -0
- package/dist/registry/ui/cursors/dot-cursor.d.ts +2 -0
- package/dist/registry/ui/cursors/dot-cursor.js +70 -0
- package/dist/registry/ui/navbars/floating-navbar.d.ts +2 -0
- package/dist/registry/ui/navbars/floating-navbar.js +35 -0
- package/dist/registry/ui/scrollbars/minimal-scrollbar.d.ts +2 -0
- package/dist/registry/ui/scrollbars/minimal-scrollbar.js +171 -0
- package/dist/scripts/build-registry.d.ts +1 -0
- package/dist/scripts/build-registry.js +47 -0
- package/dist/src/commands/add.d.ts +1 -0
- package/dist/src/commands/add.js +64 -0
- package/dist/src/commands/init.d.ts +1 -0
- package/dist/src/commands/init.js +88 -0
- package/dist/src/commands/list.d.ts +1 -0
- package/dist/src/commands/list.js +37 -0
- package/dist/src/index.d.ts +2 -0
- package/dist/src/index.js +28 -0
- package/dist/src/utils/get-pkg-manager.d.ts +1 -0
- package/dist/src/utils/get-pkg-manager.js +10 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/package.json +71 -0
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import Link from 'next/link';
|
|
4
|
+
import { ChevronRight } from 'lucide-react';
|
|
5
|
+
import { Index } from "@/__registry__";
|
|
6
|
+
const ComponentCard = ({ title, videoSrc, children, span = '', bg = 'bg-[#161616]', }) => {
|
|
7
|
+
return (_jsxs("div", { className: `group relative flex flex-col justify-between rounded-3xl ${bg} border border-white/5 p-1 hover:border-white/20 transition-all duration-500 h-full cursor-pointer ${span}`, children: [_jsx("div", { className: 'relative flex-grow overflow-hidden rounded-[22px] bg-[#0A0A0A] flex items-center justify-center min-h-[140px] border border-white/[0.03]', children: videoSrc ? (_jsx("video", { src: videoSrc, autoPlay: true, loop: true, muted: true, playsInline: true, className: "absolute inset-0 w-full h-full object-cover opacity-100 scale-100" })) : (_jsx("div", { className: "relative z-10 w-full h-full flex items-center justify-center", children: children })) }), _jsx("div", { className: 'px-4 py-3 flex justify-between items-center bg-transparent relative z-10', children: _jsx("h3", { className: 'text-[13px] font-medium text-zinc-400 group-hover:text-white transition-colors', children: title }) })] }));
|
|
8
|
+
};
|
|
9
|
+
const FeaturedComponents = () => {
|
|
10
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
11
|
+
const getComp = (name) => { var _a; return (_a = Index["default"]) === null || _a === void 0 ? void 0 : _a[name]; };
|
|
12
|
+
return (_jsx("div", { className: 'min-h-screen w-full p-8 text-white mt-10', children: _jsxs("div", { className: 'max-w-7xl mx-auto', children: [_jsxs("div", { className: 'grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4 auto-rows-[220px]', children: [_jsx(Link, { href: `/component/`, children: _jsx(ComponentCard, { title: "", videoSrc: (_a = getComp("reveal")) === null || _a === void 0 ? void 0 : _a.video }) }), _jsx(Link, { href: `/component/floating-navbar`, className: "lg:col-span-2", children: _jsx(ComponentCard, { title: "Floating Navbar", videoSrc: (_b = getComp("navbar")) === null || _b === void 0 ? void 0 : _b.video }) }), _jsx(Link, { href: `/component/minimal-scrollbar`, className: "lg:row-span-3", children: _jsx(ComponentCard, { title: "Minimal Scrollbar", videoSrc: (_c = getComp("minimal-scrollbar")) === null || _c === void 0 ? void 0 : _c.video }) }), _jsx(Link, { href: `/component/dot-cursor`, className: "lg:col-span-2 lg:row-span-2", children: _jsx(ComponentCard, { title: "Custom Cursor" }) }), _jsx(Link, { href: `/component/`, children: _jsx(ComponentCard, { title: "", videoSrc: (_d = getComp("details")) === null || _d === void 0 ? void 0 : _d.video }) }), _jsx(Link, { href: `/component/neubrutal-button`, children: _jsx(ComponentCard, { title: "Neubrutal Button", videoSrc: ((_e = getComp("neubrutal-button")) === null || _e === void 0 ? void 0 : _e.video) || "/compVideos/neubrutal-button.mp4" }) }), _jsx(Link, { href: `/component/`, className: "lg:col-span-3", children: _jsx(ComponentCard, { title: "", videoSrc: (_f = getComp("creative-grid")) === null || _f === void 0 ? void 0 : _f.video }) }), _jsx(Link, { href: `/component/`, children: _jsx(ComponentCard, { title: "", videoSrc: (_g = getComp("feedback")) === null || _g === void 0 ? void 0 : _g.video, children: _jsx("div", { className: "text-2xl font-bold opacity-50 transition-opacity", children: "?" }) }) })] }), _jsx("div", { className: 'mt-8 flex justify-center', children: _jsxs(Link, { href: '/component', className: 'relative z-30 h-12 px-6 rounded-lg text-sm text-white transition-all flex items-center gap-2 group', children: ["Explore All Components", _jsx("div", { className: 'flex items-center justify-center transition-transform group-hover:translate-x-1', children: _jsx(ChevronRight, { size: 18 }) })] }) })] }) }));
|
|
13
|
+
};
|
|
14
|
+
export default FeaturedComponents;
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
const Footer = () => {
|
|
3
|
+
return (_jsxs("footer", { className: ' text-white border-neutral-800 overflow-hidden relative', children: [_jsx("div", { className: 'w-full', children: _jsx("img", { src: '/images/slash_1.svg', alt: 'Slash Logo', className: 'w-full h-auto object-cover block ' }) }), _jsxs("div", { className: 'relative max-w-7xl mx-auto pt-20 pb-40 px-4 sm:px-6 lg:px-8 overflow-hidden', children: [_jsx("div", { className: "absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 w-[500px] h-[300px] bg-zinc-800/20 blur-[120px] rounded-full -z-10 pointer-events-none" }), _jsxs("div", { className: "relative z-10 overflow-hidden text-center", children: [_jsxs("h1", { className: 'text-center text-4xl md:text-6xl font-switzer capitalize font-bold tracking-tighter leading-tight text-neutral-100 overflow-hidden', children: ["Start slashing your UI ", _jsx("br", {}), "development with ", _jsx("span", { className: 'italic font-hoshiko text-red-500 tracking-wider px-5', children: "Slash/Ui" }), " today!"] }), _jsx("div", { className: "flex justify-center mt-10 overflow-x-hidden", children: _jsxs("button", { className: 'group relative px-15 py-4 tracking-widest overflow-hidden border text-white hover:text-black font-hoshiko rounded-full font-semibold transition-all duration-300 hover:bg-red-500 hover:scale-105 active:scale-95 cursor-pointer flex items-center gap-2', children: ["Slash Now", _jsx("span", { className: "transition-transform duration-300 group-hover:translate-x-1" })] }) })] })] }), _jsx("div", { className: 'py-8 border-t border-neutral-900', children: _jsxs("div", { className: "max-w-7xl mx-auto px-6 flex flex-col md:flex-row justify-between items-center gap-4", children: [_jsx("p", { className: 'text-sm font-cartographCF text-neutral-500 capitalize', children: "\u00A9 2026 Slash/Ui. All Rights Reserved." }), _jsxs("h1", { className: 'text-sm font-cartographCF text-neutral-500', children: ["Designed and Developed by", ' ', _jsx("a", { className: 'italic text-neutral-300 hover:text-white transition-colors duration-300 border-b border-neutral-700 hover:border-white', href: 'https://x.com/rahulll_parihar', target: '_blank', rel: 'noopener noreferrer', children: "@Rahul" })] })] }) })] }));
|
|
4
|
+
};
|
|
5
|
+
export default Footer;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useState } from 'react';
|
|
4
|
+
import Link from 'next/link';
|
|
5
|
+
import { ChevronRight, Terminal, Copy, Check } from 'lucide-react';
|
|
6
|
+
const Hero = () => {
|
|
7
|
+
const [copied, setCopied] = useState(false);
|
|
8
|
+
const installCommand = 'npx slash-ui@latest init';
|
|
9
|
+
const handleCopy = async () => {
|
|
10
|
+
try {
|
|
11
|
+
await navigator.clipboard.writeText(installCommand);
|
|
12
|
+
setCopied(true);
|
|
13
|
+
setTimeout(() => setCopied(false), 2000);
|
|
14
|
+
}
|
|
15
|
+
catch (err) {
|
|
16
|
+
console.error('Failed to copy text: ', err);
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
return (_jsxs("section", { className: 'relative min-h-screen w-full flex flex-col items-center justify-center overflow-hidden ', children: [_jsxs("video", { autoPlay: true, muted: true, loop: true, playsInline: true, className: 'absolute inset-0 z-0 h-full w-full object-cover mix-blend-screen grayscale-100', children: [_jsx("source", { src: '/video/hero_video.mp4', type: 'video/mp4' }), "Your browser does not support the video tag."] }), _jsxs("div", { className: 'relative z-10 container mx-auto px-6 flex mt-40 flex-col items-center', children: [_jsxs("h1", { className: 'max-w-4xl text-center text-3xl font-beVietnamPro tracking-tight md:text-5xl lg:text-8xl text-white', children: ["SLASH/UI ", _jsx("br", {}), _jsx("span", { className: 'font-sans italic text-6xl md:text-8xl text-zinc-200', children: "components" })] }), _jsx("p", { className: 'mt-8 max-w-2xl text-center font-cartographCF text-zinc-400 leading-relaxed md:text-sm', children: "A collection of accessible, high-performance components built with React and Tailwind. Stop styling from scratch and start building." }), _jsxs("div", { className: 'mt-10 flex flex-col items-center gap-4 sm:flex-row font-cartographCF', children: [_jsxs(Link, { href: '/component', className: 'h-14 px-8 rounded-xl text-sm bg-white text-black font-bold hover:bg-zinc-200 transition-all flex items-center gap-4 group', children: ["Explore Components", _jsx(ChevronRight, { size: 18, className: 'transition-transform group-hover:translate-x-1' })] }), _jsxs("div", { onClick: handleCopy, className: 'group flex h-14 items-center gap-3 rounded-xl border border-white/10 bg-black/50 backdrop-blur-md px-5 hover:bg-white/10 transition-all cursor-pointer', children: [_jsx(Terminal, { size: 16, className: 'text-zinc-500' }), _jsx("code", { className: 'text-sm text-zinc-300 font-mono', children: installCommand }), _jsx("div", { className: 'ml-2 border-l border-white/10 pl-4', children: copied ? (_jsx(Check, { size: 16, className: 'text-green-400' })) : (_jsx(Copy, { size: 16, className: 'text-zinc-600 group-hover:text-white' })) })] })] })] })] }));
|
|
20
|
+
};
|
|
21
|
+
export default Hero;
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
|
+
import React, { useState, useEffect } from 'react';
|
|
4
|
+
import Link from 'next/link';
|
|
5
|
+
import { Command } from 'lucide-react';
|
|
6
|
+
import { motion, AnimatePresence } from 'framer-motion';
|
|
7
|
+
import { useSearch } from '@/hooks/use-component-search';
|
|
8
|
+
import { Slant as Hamburger } from 'hamburger-react';
|
|
9
|
+
import { logout } from '@/lib/actions/auth.action';
|
|
10
|
+
const Navbar = () => {
|
|
11
|
+
const { searchQuery, setSearchQuery, filteredItems, staticPages } = useSearch();
|
|
12
|
+
const [mounted, setMounted] = useState(false);
|
|
13
|
+
const [isSearchOpen, setIsSearchOpen] = useState(false);
|
|
14
|
+
const [isMenuOpen, setIsMenuOpen] = useState(false);
|
|
15
|
+
const [selectedIndex, setSelectedIndex] = useState(0);
|
|
16
|
+
const [userEmail, setUserEmail] = useState(null);
|
|
17
|
+
const [authLoaded, setAuthLoaded] = useState(false);
|
|
18
|
+
useEffect(() => {
|
|
19
|
+
async function getUser() {
|
|
20
|
+
var _a;
|
|
21
|
+
const res = await fetch('/api/me', {
|
|
22
|
+
credentials: 'include',
|
|
23
|
+
cache: 'no-store',
|
|
24
|
+
});
|
|
25
|
+
const data = await res.json();
|
|
26
|
+
setUserEmail(((_a = data.user) === null || _a === void 0 ? void 0 : _a.email) || null);
|
|
27
|
+
setAuthLoaded(true);
|
|
28
|
+
}
|
|
29
|
+
getUser();
|
|
30
|
+
}, []);
|
|
31
|
+
useEffect(() => {
|
|
32
|
+
setMounted(true);
|
|
33
|
+
const handleKeyDown = (e) => {
|
|
34
|
+
if ((e.metaKey || e.ctrlKey) && e.key === 'k') {
|
|
35
|
+
e.preventDefault();
|
|
36
|
+
setIsSearchOpen((prev) => !prev);
|
|
37
|
+
setIsMenuOpen(false);
|
|
38
|
+
}
|
|
39
|
+
if (!isSearchOpen)
|
|
40
|
+
return;
|
|
41
|
+
if (e.key === 'Escape') {
|
|
42
|
+
setIsSearchOpen(false);
|
|
43
|
+
setSearchQuery('');
|
|
44
|
+
}
|
|
45
|
+
if (e.key === 'ArrowDown') {
|
|
46
|
+
e.preventDefault();
|
|
47
|
+
setSelectedIndex((prev) => (prev + 1) % filteredItems.length);
|
|
48
|
+
}
|
|
49
|
+
else if (e.key === 'ArrowUp') {
|
|
50
|
+
e.preventDefault();
|
|
51
|
+
setSelectedIndex((prev) => (prev - 1 + filteredItems.length) % filteredItems.length);
|
|
52
|
+
}
|
|
53
|
+
else if (e.key === 'Enter') {
|
|
54
|
+
const selected = filteredItems[selectedIndex];
|
|
55
|
+
if (selected) {
|
|
56
|
+
window.location.href = selected.path;
|
|
57
|
+
setIsSearchOpen(false);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
window.addEventListener('keydown', handleKeyDown);
|
|
62
|
+
return () => window.removeEventListener('keydown', handleKeyDown);
|
|
63
|
+
}, [isSearchOpen, filteredItems, selectedIndex, setSearchQuery]);
|
|
64
|
+
useEffect(() => {
|
|
65
|
+
setSelectedIndex(0);
|
|
66
|
+
}, [searchQuery]);
|
|
67
|
+
useEffect(() => {
|
|
68
|
+
document.body.style.overflow = isMenuOpen ? 'hidden' : '';
|
|
69
|
+
return () => {
|
|
70
|
+
document.body.style.overflow = '';
|
|
71
|
+
};
|
|
72
|
+
}, [isMenuOpen]);
|
|
73
|
+
const menuLinks = React.useMemo(() => {
|
|
74
|
+
return [
|
|
75
|
+
{ label: 'Quick Start', path: '/docs', tag: 'Guide' },
|
|
76
|
+
{ label: 'Pricing', path: '/pricing', tag: 'Free' },
|
|
77
|
+
{ label: 'Components', path: '/component', tag: '105+' },
|
|
78
|
+
{ label: 'Get Support', path: '/support', tag: null },
|
|
79
|
+
...(authLoaded
|
|
80
|
+
? userEmail
|
|
81
|
+
? [
|
|
82
|
+
{ label: 'Account', path: '/account', tag: userEmail },
|
|
83
|
+
{ label: 'Logout', path: '#logout', tag: null },
|
|
84
|
+
]
|
|
85
|
+
: [{ label: 'Login', path: '/login', tag: null }]
|
|
86
|
+
: []),
|
|
87
|
+
];
|
|
88
|
+
}, [userEmail, authLoaded]);
|
|
89
|
+
return (_jsxs(_Fragment, { children: [_jsx("nav", { className: 'fixed top-0 left-0 w-full z-[100] flex justify-center pt-4 px-6 pointer-events-none', children: _jsxs("div", { className: 'flex items-center justify-between px-6 h-14 w-full max-w-[860px] bg-zinc-900/80 backdrop-blur-3xl border border-zinc-800 rounded-2xl pointer-events-auto', children: [_jsxs("div", { className: 'flex items-center gap-8', children: [_jsx(Link, { href: '/', className: 'font-bold text-white text-lg', children: "Slash/Ui" }), _jsxs("div", { className: 'hidden md:flex items-center gap-6 text-sm font-medium text-zinc-400', children: [_jsx(Link, { href: '/docs', className: 'hover:text-white transition-colors', children: "Docs" }), _jsx(Link, { href: '/component', className: 'hover:text-white transition-colors', children: "Components" })] })] }), _jsxs("div", { className: 'flex items-center gap-2', children: [_jsx("button", { onClick: () => {
|
|
90
|
+
setIsSearchOpen(true);
|
|
91
|
+
setIsMenuOpen(false);
|
|
92
|
+
}, className: 'flex items-center justify-center w-9 h-9 rounded-lg bg-zinc-800 hover:bg-zinc-700 text-zinc-400 hover:text-white transition-all cursor-pointer', "aria-label": 'Open search', children: _jsx(Command, { size: 16 }) }), _jsx("button", { onClick: () => {
|
|
93
|
+
setIsMenuOpen((v) => !v);
|
|
94
|
+
setIsSearchOpen(false);
|
|
95
|
+
}, className: 'flex items-center justify-center w-9 h-9 rounded-lg bg-zinc-800 hover:bg-zinc-700 text-zinc-400 hover:text-white transition-all cursor-pointer', "aria-label": 'Open menu', children: _jsx(AnimatePresence, { mode: 'wait', initial: false, children: isMenuOpen ? (_jsx(motion.span, { children: _jsx(Hamburger, { size: 16, toggled: isMenuOpen }) }, 'close')) : (_jsx(motion.span, { children: _jsx(Hamburger, { size: 16, toggled: isMenuOpen, toggle: () => { } }) }, 'open')) }) })] })] }) }), _jsx(AnimatePresence, { children: isMenuOpen && (_jsxs(_Fragment, { children: [_jsx(motion.div, { initial: { opacity: 0 }, animate: { opacity: 1 }, exit: { opacity: 0 }, transition: { duration: 0.3 }, onClick: () => setIsMenuOpen(false), className: 'fixed inset-0 z-[150] backdrop-blur-md' }), _jsxs(motion.div, { initial: { opacity: 0, scale: 1.1 }, animate: { opacity: 1, scale: 1 }, exit: { opacity: 0, scale: 1.1 }, transition: { type: 'spring', damping: 25, stiffness: 200 }, className: 'fixed inset-0 z-[160] flex flex-col justify-center items-center bg-transparent pointer-events-none', children: [_jsx("nav", { className: 'flex flex-col items-center justify-center w-full max-w-4xl pointer-events-auto', children: menuLinks.map((link, i) => (_jsx(motion.div, { initial: { opacity: 0, y: 20 }, animate: { opacity: 1, y: 0 }, transition: { delay: i * 0.05, duration: 0.4 }, className: 'w-full', children: link.label === 'Logout' ? (_jsx("form", { action: logout, className: 'w-full', children: _jsxs("button", { type: 'submit', onClick: () => setIsMenuOpen(false), className: 'group flex flex-col items-center py-2 w-full cursor-pointer', children: [_jsx("span", { className: 'text-6xl md:text-7xl font-black uppercase tracking-tighter leading-[0.85] text-white transition-transform duration-300 group-hover:scale-105', children: "Logout" }), link.tag && (_jsx("span", { className: 'text-[10px] mt-2 opacity-50 tracking-widest', children: link.tag }))] }) })) : (_jsxs(Link, { href: link.path, onClick: () => setIsMenuOpen(false), className: 'group flex flex-col items-center py-2', children: [_jsx("span", { className: 'text-6xl md:text-7xl font-black uppercase tracking-tighter leading-[0.85] text-white transition-transform duration-300 group-hover:scale-105', children: link.label }), link.tag && (_jsx("span", { className: 'text-[10px] mt-2 opacity-50 tracking-widest', children: link.tag }))] })) }, link.label))) }), _jsxs("div", { className: 'absolute bottom-10 w-full flex justify-between px-10 text-md font-bold text-zinc-500 uppercase pointer-events-auto', children: [_jsx(Link, { href: '/privacy-policy', className: 'hover:text-white transition-all duration-500', children: "Privacy Policy" }), _jsx(Link, { href: '/terms-of-service', className: 'hover:text-white transition-all duration-500', children: "Terms of Service" })] })] })] })) }), _jsx(AnimatePresence, { children: isSearchOpen && (_jsxs("div", { className: 'fixed inset-0 z-[200] flex items-start justify-center pt-[18vh] px-4', children: [_jsx(motion.div, { initial: { opacity: 0 }, animate: { opacity: 1 }, exit: { opacity: 0 }, onClick: () => setIsSearchOpen(false), className: 'absolute inset-0 bg-black/60 backdrop-blur-sm' }), _jsxs(motion.div, { initial: { opacity: 0, scale: 0.95, y: -20 }, animate: { opacity: 1, scale: 1, y: 0 }, exit: { opacity: 0, scale: 0.95, y: -20 }, className: 'relative w-full max-w-[600px] bg-zinc-950 border border-zinc-800 rounded-xl shadow-2xl overflow-hidden', children: [_jsxs("div", { className: 'flex items-center px-4 border-b border-zinc-800', children: [_jsx(Command, { className: 'text-zinc-500', size: 18 }), _jsx("input", { autoFocus: true, value: searchQuery, onChange: (e) => setSearchQuery(e.target.value), placeholder: 'Search components or pages...', className: 'w-full h-14 bg-transparent border-none outline-none px-4 text-white text-sm placeholder:text-zinc-600' })] }), _jsx("div", { className: 'max-h-[400px] overflow-y-auto p-2 custom-scrollbar', children: searchQuery.length > 0 ? (_jsxs("div", { className: 'p-2', children: [_jsx("p", { className: 'px-3 py-2 text-[10px] font-semibold text-zinc-500 uppercase tracking-wider', children: "Results" }), filteredItems.length > 0 ? (filteredItems.map((item) => (_jsxs(Link, { href: item.path, onClick: () => {
|
|
96
|
+
setIsSearchOpen(false);
|
|
97
|
+
setSearchQuery('');
|
|
98
|
+
}, className: 'flex items-center justify-between px-3 py-2.5 rounded-lg hover:bg-white/5 transition-all group', children: [_jsxs("div", { className: 'flex items-center gap-3', children: [_jsx(item.icon, { size: 16, className: 'text-zinc-500 group-hover:text-white' }), _jsx("span", { className: 'text-sm text-zinc-300 group-hover:text-white', children: item.label })] }), _jsx("span", { className: 'text-[10px] opacity-50 uppercase tracking-widest', children: item.category })] }, item.path)))) : (_jsx("p", { className: 'px-3 py-4 text-sm text-zinc-600', children: "No results found..." }))] })) : (['Pages', 'Get Started'].map((cat) => (_jsxs("div", { className: 'mb-2', children: [_jsx("p", { className: 'px-3 py-2 text-[10px] font-semibold text-zinc-500 uppercase tracking-wider', children: cat }), staticPages
|
|
99
|
+
.filter((p) => p.category === cat)
|
|
100
|
+
.map((p) => (_jsxs(Link, { href: p.path, onClick: () => setIsSearchOpen(false), className: 'flex items-center gap-3 px-3 py-2.5 rounded-lg hover:bg-white/5 transition-all group', children: [_jsx("div", { className: 'text-zinc-500 group-hover:text-white', children: _jsx(p.icon, { size: 16 }) }), _jsx("span", { className: 'text-sm text-zinc-300 group-hover:text-white', children: p.label })] }, p.label)))] }, cat)))) }), _jsxs("div", { className: 'px-4 py-3 border-t border-zinc-800 bg-zinc-900/30 flex justify-between items-center text-[10px] text-zinc-500 font-medium', children: [_jsxs("div", { className: 'flex gap-3', children: [_jsxs("span", { className: 'flex items-center gap-1', children: [_jsx(Command, { size: 10 }), " to select"] }), _jsx("span", { className: 'flex items-center gap-1', children: "Enter to open" })] }), _jsx("span", { children: "ESC to close" })] })] })] })) })] }));
|
|
101
|
+
};
|
|
102
|
+
export default Navbar;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import Link from 'next/link';
|
|
4
|
+
import { Check, Zap } from 'lucide-react';
|
|
5
|
+
const PricingCard = ({ tier, price, description, features, href, isHighlighted = false, }) => {
|
|
6
|
+
return (_jsxs("div", { className: `relative flex flex-col p-8 rounded-3xl border transition-all duration-500 overflow-hidden h-full ${isHighlighted
|
|
7
|
+
? 'border-white bg-neutral-900 shadow-[0_0_50px_-12px_rgba(255,255,255,0.2)]'
|
|
8
|
+
: 'border-white/10 bg-neutral-900 text-zinc-400'}`, children: [isHighlighted && (_jsxs(_Fragment, { children: [_jsx("div", { className: 'absolute -top-[20%] -right-[20%] w-[70%] h-[70%] bg-white/10 blur-[100px] pointer-events-none' }), _jsx("div", { className: 'absolute inset-0 pointer-events-none z-0', children: _jsx("img", { src: '/images/PricingSlash.svg', alt: '', className: 'w-full h-full object-cover scale-150 rotate-[-5deg] opacity-90' }) }), _jsx("div", { className: 'absolute inset-0 rounded-3xl border border-white/20 animate-pulse pointer-events-none' })] })), _jsxs("div", { className: `relative flex flex-col h-full ${isHighlighted ? 'z-10 mix-blend-difference' : 'z-10'}`, children: [_jsxs("div", { className: 'mb-8', children: [_jsx("h3", { className: `text-xs uppercase font-mono tracking-widest ${isHighlighted ? 'text-white' : 'text-zinc-500'}`, children: tier }), _jsx("p", { className: `text-sm mt-3 font-medium leading-relaxed ${isHighlighted ? 'text-white' : 'text-zinc-400'}`, children: description })] }), _jsxs("div", { className: 'mb-8 flex items-baseline gap-1', children: [_jsx("span", { className: `text-6xl font-black tracking-tighter ${isHighlighted ? 'text-white' : 'text-zinc-100'}`, children: price }), _jsx("span", { className: 'text-zinc-500 text-[10px] uppercase tracking-widest ml-2', children: "Lifetime Access" })] }), _jsx("div", { className: 'space-y-4 mb-10 flex-grow', children: features.map((feature, index) => (_jsxs("div", { className: 'flex items-center gap-3 text-[13px] font-cartographCF', children: [_jsx(Check, { size: 14, className: isHighlighted ? 'text-white' : 'text-zinc-600' }), _jsx("span", { className: isHighlighted ? 'text-white' : 'text-zinc-500', children: feature })] }, index))) }), _jsx("div", { className: 'relative z-20', children: _jsxs(Link, { href: 'https://app.archway.finance/payment-requests/HDGAY/public', className: `w-full py-4 rounded-xl font-beVietnamPro text-xs transition-all duration-500 flex items-center justify-center cursor-pointer ${isHighlighted
|
|
9
|
+
? 'bg-white text-black hover:shadow-[0_0_20px_rgba(255,255,255,0.4)] hover:bg-zinc-100'
|
|
10
|
+
: 'bg-transparent text-white border border-white/20 hover:border-white/60'}`, children: ["Select ", tier] }) })] })] }));
|
|
11
|
+
};
|
|
12
|
+
const Pricing = () => {
|
|
13
|
+
return (_jsx("section", { className: 'w-full py-32 px-8 ', children: _jsxs("div", { className: 'max-w-4xl mx-auto', children: [_jsxs("div", { className: 'flex flex-col items-center text-center mb-20', children: [_jsxs("div", { className: 'flex items-center gap-2 px-3 py-1 rounded-full border border-white/10 bg-zinc-950 mb-6', children: [_jsx(Zap, { size: 12, className: 'text-white' }), _jsx("span", { className: 'text-[10px] font-bold text-zinc-400 uppercase tracking-widest', children: "Pricing Plans" })] }), _jsx("h2", { className: 'text-5xl font-black text-white uppercase tracking-tighter mb-6', children: "Unlock the Full Library" }), _jsx("p", { className: 'text-zinc-500 text-sm max-w-lg leading-relaxed', children: "Professional-grade UI components for Next.js and Tailwind. Choose the pack that fits your scale." })] }), _jsxs("div", { className: 'grid grid-cols-1 md:grid-cols-2 gap-6 items-stretch', children: [_jsx(PricingCard, { tier: 'Standard', price: '$50', href: 'https://app.archway.finance/payment-requests/HDGAY/public', description: 'Perfect for individual projects and hobbyists.', features: [
|
|
14
|
+
'30+ Open Source Components',
|
|
15
|
+
'React / Tailwind Templates',
|
|
16
|
+
'Community Support',
|
|
17
|
+
'Lifetime Access',
|
|
18
|
+
] }), _jsx(PricingCard, { tier: 'Premium', isHighlighted: true, price: '$129', href: 'https://app.archway.finance/payment-requests/HDGAY/public', description: 'Full access for professionals and agency work.', features: [
|
|
19
|
+
'100+ Premium Components',
|
|
20
|
+
'Agency/Commercial License',
|
|
21
|
+
'Priority Feature Requests',
|
|
22
|
+
'Figma Design Files',
|
|
23
|
+
'Private Discord Access',
|
|
24
|
+
] })] })] }) }));
|
|
25
|
+
};
|
|
26
|
+
export default Pricing;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import { createContext, useContext, useState, useMemo } from 'react';
|
|
4
|
+
import { Home, Box } from 'lucide-react';
|
|
5
|
+
import { Index } from '@/__registry__';
|
|
6
|
+
const SearchContext = createContext(undefined);
|
|
7
|
+
export function SearchProvider({ children }) {
|
|
8
|
+
const [searchQuery, setSearchQuery] = useState('');
|
|
9
|
+
const staticPages = useMemo(() => [
|
|
10
|
+
{ icon: Home, label: 'Home', category: 'Pages', path: '/' },
|
|
11
|
+
], []);
|
|
12
|
+
const componentsList = useMemo(() => {
|
|
13
|
+
return Object.values(Index['default'] || {}).map((comp) => ({
|
|
14
|
+
icon: Box,
|
|
15
|
+
label: comp.name,
|
|
16
|
+
category: 'Components',
|
|
17
|
+
path: `/component/${comp.name}`,
|
|
18
|
+
}));
|
|
19
|
+
}, []);
|
|
20
|
+
const allItems = useMemo(() => [...staticPages, ...componentsList], [staticPages, componentsList]);
|
|
21
|
+
const filteredItems = useMemo(() => {
|
|
22
|
+
return allItems.filter((item) => item.label.toLowerCase().includes(searchQuery.toLowerCase()));
|
|
23
|
+
}, [searchQuery, allItems]);
|
|
24
|
+
return (_jsx(SearchContext.Provider, { value: {
|
|
25
|
+
searchQuery,
|
|
26
|
+
setSearchQuery,
|
|
27
|
+
filteredItems,
|
|
28
|
+
staticPages,
|
|
29
|
+
totalComponents: componentsList.length,
|
|
30
|
+
}, children: children }));
|
|
31
|
+
}
|
|
32
|
+
export const useSearch = () => {
|
|
33
|
+
const context = useContext(SearchContext);
|
|
34
|
+
if (!context)
|
|
35
|
+
throw new Error('useSearch must be used within a SearchProvider');
|
|
36
|
+
return context;
|
|
37
|
+
};
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
'use server';
|
|
2
|
+
import bcrypt from 'bcryptjs';
|
|
3
|
+
import jwt from 'jsonwebtoken';
|
|
4
|
+
import { prisma } from '@/lib/prisma';
|
|
5
|
+
import { randomInt } from 'crypto';
|
|
6
|
+
import { sendOtpEmail } from '../email';
|
|
7
|
+
import { cookies } from 'next/headers';
|
|
8
|
+
import { redirect } from 'next/navigation';
|
|
9
|
+
export async function sendOtp(formData) {
|
|
10
|
+
const email = formData.get('email');
|
|
11
|
+
const rawOtp = randomInt(100000, 999999).toString();
|
|
12
|
+
const hashedOtp = await bcrypt.hash(rawOtp, 10);
|
|
13
|
+
await prisma.otp.create({
|
|
14
|
+
data: {
|
|
15
|
+
email,
|
|
16
|
+
code: hashedOtp,
|
|
17
|
+
expiresAt: new Date(Date.now() + 5 * 60 * 1000),
|
|
18
|
+
},
|
|
19
|
+
});
|
|
20
|
+
await sendOtpEmail(email, rawOtp);
|
|
21
|
+
return { success: true };
|
|
22
|
+
}
|
|
23
|
+
export async function verifyOtp(formData) {
|
|
24
|
+
const email = formData.get('email');
|
|
25
|
+
const otp = formData.get('otp');
|
|
26
|
+
try {
|
|
27
|
+
const record = await prisma.otp.findFirst({
|
|
28
|
+
where: {
|
|
29
|
+
email,
|
|
30
|
+
expiresAt: { gt: new Date() },
|
|
31
|
+
},
|
|
32
|
+
orderBy: { createdAt: 'desc' },
|
|
33
|
+
});
|
|
34
|
+
if (!record) {
|
|
35
|
+
return { success: false, message: 'OTP expired' };
|
|
36
|
+
}
|
|
37
|
+
const valid = await bcrypt.compare(otp, record.code);
|
|
38
|
+
if (!valid) {
|
|
39
|
+
return { success: false, message: 'Invalid OTP' };
|
|
40
|
+
}
|
|
41
|
+
await prisma.otp.deleteMany({ where: { email } });
|
|
42
|
+
let user = await prisma.user.findUnique({ where: { email } });
|
|
43
|
+
if (!user) {
|
|
44
|
+
user = await prisma.user.create({ data: { email } });
|
|
45
|
+
}
|
|
46
|
+
const token = jwt.sign({ email: user.email, id: user.id }, process.env.JWT_SECRET, { expiresIn: '7d' });
|
|
47
|
+
const cookieStore = await cookies();
|
|
48
|
+
cookieStore.set('access_token', token, {
|
|
49
|
+
httpOnly: true,
|
|
50
|
+
secure: process.env.NODE_ENV === 'production',
|
|
51
|
+
sameSite: 'lax',
|
|
52
|
+
path: '/',
|
|
53
|
+
maxAge: 60 * 60 * 24 * 7,
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
catch (err) {
|
|
57
|
+
console.error(err);
|
|
58
|
+
return { success: false, message: 'Server error' };
|
|
59
|
+
}
|
|
60
|
+
redirect('/account');
|
|
61
|
+
}
|
|
62
|
+
export async function logout() {
|
|
63
|
+
const cookieStore = await cookies();
|
|
64
|
+
cookieStore.delete('access_token');
|
|
65
|
+
redirect('/');
|
|
66
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function getCurrentUserEmail(): Promise<string | null>;
|
package/dist/lib/auth.js
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { cookies } from "next/headers";
|
|
2
|
+
import jwt from "jsonwebtoken";
|
|
3
|
+
export async function getCurrentUserEmail() {
|
|
4
|
+
var _a;
|
|
5
|
+
const token = (_a = (await cookies()).get("access_token")) === null || _a === void 0 ? void 0 : _a.value;
|
|
6
|
+
if (!token)
|
|
7
|
+
return null;
|
|
8
|
+
try {
|
|
9
|
+
const decoded = jwt.verify(token, process.env.JWT_SECRET);
|
|
10
|
+
return decoded.email;
|
|
11
|
+
}
|
|
12
|
+
catch (_b) {
|
|
13
|
+
return null;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function sendOtpEmail(email: string, otp: string): Promise<import("nodemailer/lib/smtp-transport").SentMessageInfo>;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import nodemailer from 'nodemailer';
|
|
2
|
+
export async function sendOtpEmail(email, otp) {
|
|
3
|
+
const transporter = nodemailer.createTransport({
|
|
4
|
+
service: 'gmail',
|
|
5
|
+
auth: {
|
|
6
|
+
user: process.env.EMAIL_USER,
|
|
7
|
+
pass: process.env.EMAIL_APP_PASSWORD,
|
|
8
|
+
},
|
|
9
|
+
});
|
|
10
|
+
const response = await transporter.sendMail({
|
|
11
|
+
from: `"Slash/UI" <${process.env.EMAIL_USER}>`,
|
|
12
|
+
to: email,
|
|
13
|
+
subject: 'Your verification code',
|
|
14
|
+
html: `
|
|
15
|
+
<div style="font-family: 'Helvetica Neue', Helvetica, sans-serif; max-width: 600px; margin: 0 auto; padding: 40px 20px; color: #1a1a1a;">
|
|
16
|
+
<div style="margin-bottom: 32px;">
|
|
17
|
+
<div style="display: flex; align-items: center; gap: 8px; font-weight: 600; letter-spacing: -0.02em;">
|
|
18
|
+
<span>SLASH/UI</span>
|
|
19
|
+
</div>
|
|
20
|
+
</div>
|
|
21
|
+
|
|
22
|
+
<h2 style="font-size: 24px; font-weight: 600; margin-bottom: 8px; color: #000;">Your verification code</h2>
|
|
23
|
+
<p style="font-size: 16px; color: #666; margin-bottom: 32px;">Use the one-time code below to continue.</p>
|
|
24
|
+
|
|
25
|
+
<div style="background-color: #f7f7f7; border-radius: 12px; padding: 24px; text-align: center; margin-bottom: 32px;">
|
|
26
|
+
<span style="font-size: 32px; font-weight: 500; letter-spacing: 12px; color: #000; font-family: monospace;">${otp}</span>
|
|
27
|
+
</div>
|
|
28
|
+
|
|
29
|
+
<p style="font-size: 14px; color: #888; line-height: 1.5; margin-bottom: 24px;">
|
|
30
|
+
This code will expire in 5 minutes and can only be used once.<br />
|
|
31
|
+
For your security, do not share this code with anyone.
|
|
32
|
+
</p>
|
|
33
|
+
|
|
34
|
+
<div style="font-size: 14px; color: #666;">
|
|
35
|
+
Have fun,<br />
|
|
36
|
+
<strong style="color: #000;">The Slash/UI Team</strong>
|
|
37
|
+
</div>
|
|
38
|
+
</div>
|
|
39
|
+
`,
|
|
40
|
+
});
|
|
41
|
+
return response;
|
|
42
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
var _a;
|
|
2
|
+
import { PrismaClient } from "@prisma/client";
|
|
3
|
+
const globalForPrisma = global;
|
|
4
|
+
export const prisma = (_a = globalForPrisma.prisma) !== null && _a !== void 0 ? _a : new PrismaClient({
|
|
5
|
+
log: ["query"],
|
|
6
|
+
});
|
|
7
|
+
if (process.env.NODE_ENV !== "production")
|
|
8
|
+
globalForPrisma.prisma = prisma;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function getComponentSource(filePaths: string[] | undefined): Promise<string | undefined>;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
'use server';
|
|
2
|
+
import fs from 'fs/promises';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
export async function getComponentSource(filePaths) {
|
|
5
|
+
if (!filePaths || filePaths.length === 0)
|
|
6
|
+
return;
|
|
7
|
+
try {
|
|
8
|
+
const fullPath = path.join(process.cwd(), filePaths[0]);
|
|
9
|
+
const source = await fs.readFile(fullPath, 'utf-8');
|
|
10
|
+
return source;
|
|
11
|
+
}
|
|
12
|
+
catch (error) {
|
|
13
|
+
console.error('Failed to read source code:', error);
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { NextResponse } from 'next/server';
|
|
2
|
+
import jwt from 'jsonwebtoken';
|
|
3
|
+
export function middleware(req) {
|
|
4
|
+
var _a;
|
|
5
|
+
const token = (_a = req.cookies.get('access_token')) === null || _a === void 0 ? void 0 : _a.value;
|
|
6
|
+
if (!token) {
|
|
7
|
+
return NextResponse.redirect(new URL('/login', req.url));
|
|
8
|
+
}
|
|
9
|
+
try {
|
|
10
|
+
jwt.verify(token, process.env.JWT_SECRET);
|
|
11
|
+
return NextResponse.next();
|
|
12
|
+
}
|
|
13
|
+
catch (_b) {
|
|
14
|
+
return NextResponse.redirect(new URL('/login', req.url));
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
export const config = {
|
|
18
|
+
matcher: ['/account/:path*', '/docs/:path*', '/components/:path*'],
|
|
19
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
// This file was generated by Prisma, and assumes you have installed the following:
|
|
2
|
+
// npm install --save-dev prisma dotenv
|
|
3
|
+
import "dotenv/config";
|
|
4
|
+
import { defineConfig } from "prisma/config";
|
|
5
|
+
export default defineConfig({
|
|
6
|
+
schema: "prisma/schema.prisma",
|
|
7
|
+
migrations: {
|
|
8
|
+
path: "prisma/migrations",
|
|
9
|
+
},
|
|
10
|
+
datasource: {
|
|
11
|
+
url: process.env["DATABASE_URL"],
|
|
12
|
+
},
|
|
13
|
+
});
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useState } from 'react';
|
|
4
|
+
import { MousePointer2, Zap, Copy, Check, ShieldCheck, } from 'lucide-react';
|
|
5
|
+
const NeubrutalButtonDetails = () => {
|
|
6
|
+
const [copied, setCopied] = useState(false);
|
|
7
|
+
const [activeTab, setActiveTab] = useState(null);
|
|
8
|
+
const command = 'npx slash-ui@latest add neubrutal-button';
|
|
9
|
+
const handleCopyCommand = () => {
|
|
10
|
+
navigator.clipboard.writeText(command);
|
|
11
|
+
setCopied(true);
|
|
12
|
+
setTimeout(() => setCopied(false), 2000);
|
|
13
|
+
};
|
|
14
|
+
const copyDependency = (pkg) => {
|
|
15
|
+
navigator.clipboard.writeText(`npm install ${pkg}`);
|
|
16
|
+
setActiveTab(pkg);
|
|
17
|
+
setTimeout(() => setActiveTab(null), 2000);
|
|
18
|
+
};
|
|
19
|
+
return (_jsxs("div", { className: 'flex flex-col gap-16 py-8 animate-in fade-in slide-in-from-bottom-4 duration-1000', children: [_jsxs("section", { children: [_jsx("h4", { className: 'text-sm uppercase text-zinc-600 mb-6 font-mono tracking-widest', children: "Description" }), _jsx("p", { className: 'text-zinc-400 text-lg leading-relaxed max-w-2xl font-medium', children: "A high-performance 3D button built with Framer Motion. It features tactile depth, dynamic shadow scaling, and smooth state transitions." })] }), _jsxs("section", { children: [_jsx("h4", { className: 'text-sm uppercase text-zinc-600 mb-4 font-mono tracking-widest', children: "Dependencies" }), _jsxs("div", { className: 'flex items-center gap-3', children: [_jsxs("button", { onClick: () => copyDependency('framer-motion'), className: "flex items-center gap-2 px-3 py-1.5 rounded-full bg-zinc-950 border border-white/5 hover:border-white/20 transition-all active:scale-95", children: [activeTab === 'framer-motion' ? (_jsx(Check, { size: 12, className: "text-white" })) : (_jsx("svg", { width: '12', height: '12', viewBox: '0 0 24 24', fill: 'currentColor', className: "text-white", children: _jsx("path", { d: 'M0 0l12 12L24 0H0zm0 12l12 12V12H0z' }) })), _jsx("span", { className: "text-[11px] font-mono text-white", children: activeTab === 'framer-motion' ? 'Copied!' : 'framer-motion' })] }), _jsxs("button", { onClick: () => copyDependency('lucide-react'), className: "flex items-center gap-2 px-3 py-1.5 rounded-full bg-zinc-950 border border-white/5 hover:border-white/20 transition-all active:scale-95", children: [activeTab === 'lucide-react' ? (_jsx(Check, { size: 12, className: "text-white" })) : (_jsxs("svg", { xmlns: 'http://www.w3.org/2000/svg', width: '12', height: '12', viewBox: '0 0 24 24', fill: 'none', stroke: 'currentColor', strokeWidth: '2', children: [_jsx("path", { d: 'M14 12C14 9.79086 12.2091 8 10 8C7.79086 8 6 9.79086 6 12C6 16.4183 9.58172 20 14 20C18.4183 20 22 16.4183 22 12C22 8.446 20.455 5.25285 18 3.05557', stroke: '#fff' }), _jsx("path", { d: 'M10 12C10 14.2091 11.7909 16 14 16C16.2091 16 18 14.2091 18 12C18 7.58172 14.4183 4 10 4C5.58172 4 2 7.58172 2 12C2 15.5841 3.57127 18.8012 6.06253 21', stroke: '#fff' })] })), _jsx("span", { className: "text-[11px] font-mono text-white", children: activeTab === 'lucide-react' ? 'Copied!' : 'lucide-react' })] })] })] }), _jsxs("section", { children: [_jsx("h4", { className: 'text-sm uppercase text-zinc-600 mb-6 font-mono tracking-widest', children: "Interaction" }), _jsxs("div", { className: 'space-y-4', children: [_jsxs("div", { className: 'flex items-center gap-4 group', children: [_jsx("div", { className: 'p-2 rounded-lg bg-white/5 text-zinc-500 group-hover:text-white transition-colors', children: _jsx(MousePointer2, { size: 16 }) }), _jsx("span", { className: 'text-sm font-medium text-zinc-400', children: "Realistic 3D depth on click" })] }), _jsxs("div", { className: 'flex items-center gap-4 group', children: [_jsx("div", { className: 'p-2 rounded-lg bg-white/5 text-zinc-500 group-hover:text-white transition-colors', children: _jsx(Zap, { size: 16 }) }), _jsx("span", { className: 'text-sm font-medium text-zinc-400', children: "Smooth hover effects" })] })] })] }), _jsxs("section", { children: [_jsx("h4", { className: 'text-sm uppercase text-zinc-600 mb-6 font-mono tracking-widest', children: "Installation" }), _jsxs("div", { onClick: handleCopyCommand, className: 'group relative flex items-center justify-between p-5 rounded-2xl bg-black border border-white/10 hover:border-white/20 transition-all cursor-pointer active:scale-[0.99]', children: [_jsxs("code", { className: 'text-xs font-cartographCF text-zinc-300', children: [_jsx("span", { className: 'text-zinc-500', children: "npx" }), " slash-ui@latest add ", _jsx("span", { className: 'text-white', children: "neubrutal-button" })] }), _jsx("div", { className: 'p-2 hover:bg-white/5 rounded-lg text-zinc-500 group-hover:text-white transition-colors', children: copied ? _jsx(Check, { size: 14, className: "text-white" }) : _jsx(Copy, { size: 14 }) })] })] }), _jsxs("section", { children: [_jsx("h4", { className: 'text-sm uppercase text-zinc-600 mb-6 font-mono tracking-widest', children: "Props" }), _jsx("div", { className: 'w-full border-t border-white/5', children: [
|
|
20
|
+
{ prop: 'children', desc: 'Button label or content' },
|
|
21
|
+
{ prop: 'onClick', desc: 'Click handler function' },
|
|
22
|
+
{ prop: 'className', desc: 'Additional Tailwind classes' },
|
|
23
|
+
].map((item, i) => (_jsxs("div", { className: 'flex py-4 border-b border-white/5 text-[13px] group', children: [_jsx("span", { className: 'w-1/3 font-mono font-bold text-white', children: item.prop }), _jsx("span", { className: 'w-2/3 text-zinc-500 font-medium group-hover:text-zinc-400 transition-colors', children: item.desc })] }, i))) })] }), _jsxs("footer", { className: 'pt-8 border-t border-white/5', children: [_jsxs("div", { className: 'flex items-center gap-2 text-zinc-600 text-[11px] font-bold uppercase tracking-widest font-mono', children: [_jsx(ShieldCheck, { size: 14 }), _jsx("span", { children: "License" })] }), _jsx("p", { className: 'mt-4 text-xs text-zinc-500 leading-relaxed font-medium', children: "Free for all projects." })] })] }));
|
|
24
|
+
};
|
|
25
|
+
export default NeubrutalButtonDetails;
|
|
File without changes
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";
|