@ghatak/slash-ui 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. package/README.md +36 -0
  2. package/__registry__/index.ts +493 -0
  3. package/app/(auth)/layout.tsx +18 -0
  4. package/app/(auth)/login/page.tsx +152 -0
  5. package/app/(protected)/component/[id]/page.tsx +48 -0
  6. package/app/(protected)/component/page.tsx +151 -0
  7. package/app/(protected)/docs/page.tsx +222 -0
  8. package/app/account/page.tsx +109 -0
  9. package/app/api/me/route.ts +24 -0
  10. package/app/globals.css +68 -0
  11. package/app/icon.png +0 -0
  12. package/app/layout.tsx +43 -0
  13. package/app/page.tsx +22 -0
  14. package/app/pricing/page.tsx +12 -0
  15. package/bin/intex.ts +19 -0
  16. package/components/smooth-scroll.tsx +26 -0
  17. package/components/toast.tsx +101 -0
  18. package/components/ui/IndustryProof.tsx +159 -0
  19. package/components/ui/ShowcaseContainer.tsx +497 -0
  20. package/components/ui/dot-cursor.tsx +108 -0
  21. package/components/ui/featuredComponents.tsx +126 -0
  22. package/components/ui/footer.tsx +59 -0
  23. package/components/ui/hero.tsx +85 -0
  24. package/components/ui/navbar.tsx +337 -0
  25. package/components/ui/pricing.tsx +163 -0
  26. package/eslint.config.mjs +18 -0
  27. package/hooks/use-component-search.tsx +52 -0
  28. package/lib/actions/auth.action.ts +88 -0
  29. package/lib/auth.ts +18 -0
  30. package/lib/email.ts +46 -0
  31. package/lib/prisma.ts +14 -0
  32. package/lib/registry.ts +17 -0
  33. package/lib/utils.ts +6 -0
  34. package/middleware/middleware.ts +21 -0
  35. package/next.config.ts +7 -0
  36. package/package.json +61 -0
  37. package/postcss.config.mjs +7 -0
  38. package/prisma/migrations/20260303172729_init/migration.sql +21 -0
  39. package/prisma/migrations/migration_lock.toml +3 -0
  40. package/prisma/schema.prisma +22 -0
  41. package/prisma.config.ts +14 -0
  42. package/public/compVideos/neubrutal-button.mp4 +0 -0
  43. package/public/fonts/BeVietnamPro-ExtraBold.otf +0 -0
  44. package/public/fonts/CartographCF-Regular.ttf +0 -0
  45. package/public/fonts/Hoshiko-Satsuki.ttf +0 -0
  46. package/public/fonts/Switzer-Regular.otf +0 -0
  47. package/public/images/PricingSlash.svg +58 -0
  48. package/public/images/slash_1.svg +59 -0
  49. package/public/images/slash_2.svg +18 -0
  50. package/public/video/hero_video.mp4 +0 -0
  51. package/registry/details/buttons/neubrutal-button-details.tsx +146 -0
  52. package/registry/details/cursor/dot-cursor-details.tsx +11 -0
  53. package/registry/details/navbar/floating-navbar-details.tsx +11 -0
  54. package/registry/details/scrollbars/minimal-scrollbar-details.tsx +0 -0
  55. package/registry/index.ts +35 -0
  56. package/registry/ui/buttons/neubrutal-button.tsx +33 -0
  57. package/registry/ui/cursors/dot-cursor.tsx +108 -0
  58. package/registry/ui/navbars/floating-navbar.tsx +99 -0
  59. package/registry/ui/scrollbars/minimal-scrollbar.tsx +203 -0
  60. package/scripts/build-registry.ts +60 -0
  61. package/src/commands/add.ts +40 -0
  62. package/src/commands/init.ts +75 -0
  63. package/src/commands/list.ts +44 -0
  64. package/src/index.ts +35 -0
  65. package/src/utils/get-pkg-manager.ts +7 -0
  66. package/tsconfig.json +34 -0
package/app/page.tsx ADDED
@@ -0,0 +1,22 @@
1
+ import React from 'react';
2
+ import Navbar from '@/components/ui/navbar';
3
+ import Hero from '@/components/ui/hero';
4
+ import Footer from '@/components/ui/footer';
5
+ import FeaturedComponents from '@/components/ui/featuredComponents';
6
+ import Pricing from '@/components/ui/pricing';
7
+ import IndustryProof from '@/components/ui/IndustryProof';
8
+
9
+ const page = () => {
10
+ return (
11
+ <div>
12
+ <Navbar />
13
+ <Hero />
14
+ <FeaturedComponents />
15
+ <IndustryProof />
16
+ <Pricing />
17
+ <Footer />
18
+ </div>
19
+ );
20
+ };
21
+
22
+ export default page;
@@ -0,0 +1,12 @@
1
+ import Navbar from '@/components/ui/navbar'
2
+ import React from 'react'
3
+
4
+ const page = () => {
5
+ return (
6
+ <>
7
+
8
+ </>
9
+ )
10
+ }
11
+
12
+ export default page
package/bin/intex.ts ADDED
@@ -0,0 +1,19 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { Command } from 'commander';
4
+ import { addCommand } from '@/src/commands/add'
5
+
6
+ const program = new Command();
7
+
8
+ program
9
+ .name('slash-ui')
10
+ .description('CLI for Slash-UI component library')
11
+ .version('0.1.0');
12
+
13
+ program
14
+ .command('add')
15
+ .description('Add a component to your project')
16
+ .argument('<component>', 'the component to add')
17
+ .action(addCommand);
18
+
19
+ program.parse();
@@ -0,0 +1,26 @@
1
+ 'use client'
2
+
3
+ import { ReactNode, useEffect } from 'react'
4
+ import Lenis from 'lenis'
5
+
6
+ export default function SmoothScroll({ children }: { children: ReactNode }) {
7
+ useEffect(() => {
8
+ const lenis = new Lenis({
9
+ duration: 1.2,
10
+ smoothWheel: true,
11
+ })
12
+
13
+ function raf(time: number) {
14
+ lenis.raf(time)
15
+ requestAnimationFrame(raf)
16
+ }
17
+
18
+ requestAnimationFrame(raf)
19
+
20
+ return () => {
21
+ lenis.destroy()
22
+ }
23
+ }, [])
24
+
25
+ return <>{children}</>
26
+ }
@@ -0,0 +1,101 @@
1
+ "use client";
2
+
3
+ import { useState, useEffect, useCallback } from "react";
4
+
5
+ interface ToastProps {
6
+ message: string;
7
+ duration?: number;
8
+ onClose?: () => void;
9
+ }
10
+
11
+ export function Toast({ message, duration = 3000, onClose }: ToastProps) {
12
+ const [visible, setVisible] = useState(false);
13
+
14
+ useEffect(() => {
15
+ const enterTimer = setTimeout(() => setVisible(true), 10);
16
+
17
+ const exitTimer = setTimeout(() => {
18
+ setVisible(false);
19
+ setTimeout(() => onClose?.(), 300);
20
+ }, duration);
21
+
22
+ return () => {
23
+ clearTimeout(enterTimer);
24
+ clearTimeout(exitTimer);
25
+ };
26
+ }, [duration, onClose]);
27
+
28
+ return (
29
+ <div
30
+ className="fixed top-6 left-1/2 -translate-x-1/2 z-50 pointer-events-none"
31
+ role="status"
32
+ aria-live="polite"
33
+ >
34
+ <div
35
+ className={`
36
+ inline-flex items-center gap-2.5
37
+ bg-[#1c1c1e] text-[#f5f5f5]
38
+ px-5 py-3 rounded-full
39
+ text-sm font-medium tracking-wide
40
+ shadow-[0_2px_8px_rgba(0,0,0,0.35),0_0_0_1px_rgba(255,255,255,0.06)]
41
+ whitespace-nowrap
42
+ transition-all duration-300 ease-out
43
+ ${visible ? "opacity-100 translate-y-0 scale-100" : "opacity-0 -translate-y-2 scale-95"}
44
+ `}
45
+ >
46
+ <span className="w-[18px] h-[18px] rounded-full bg-white flex items-center justify-center flex-shrink-0">
47
+ <svg width="10" height="10" viewBox="0 0 10 10" fill="none">
48
+ <path
49
+ d="M2 5.5L4 7.5L8 3"
50
+ stroke="white"
51
+ strokeWidth="1.5"
52
+ strokeLinecap="round"
53
+ strokeLinejoin="round"
54
+ />
55
+ </svg>
56
+ </span>
57
+ {message}
58
+ </div>
59
+ </div>
60
+ );
61
+ }
62
+
63
+ // ─── useToast hook ────────────────────────────────────────────────────────────
64
+
65
+ interface ToastState {
66
+ id: number;
67
+ message: string;
68
+ duration?: number;
69
+ }
70
+
71
+ export function useToast() {
72
+ const [toasts, setToasts] = useState<ToastState[]>([]);
73
+
74
+ const showToast = useCallback((message: string, duration = 3000) => {
75
+ const id = Date.now();
76
+ setToasts((prev) => [...prev, { id, message, duration }]);
77
+ }, []);
78
+
79
+ const removeToast = useCallback((id: number) => {
80
+ setToasts((prev) => prev.filter((t) => t.id !== id));
81
+ }, []);
82
+
83
+ const ToastContainer = useCallback(
84
+ () => (
85
+ <>
86
+ {toasts.map((t) => (
87
+ <Toast
88
+ key={t.id}
89
+ message={t.message}
90
+ duration={t.duration}
91
+ onClose={() => removeToast(t.id)}
92
+ />
93
+ ))}
94
+ </>
95
+ ),
96
+ [toasts, removeToast]
97
+ );
98
+
99
+ return { showToast, ToastContainer };
100
+ }
101
+
@@ -0,0 +1,159 @@
1
+ 'use client';
2
+
3
+ import { ChevronRight } from 'lucide-react';
4
+ import { useRef, useState, useEffect } from 'react';
5
+ import Link from 'next/link';
6
+
7
+ interface TechItem {
8
+ name: string;
9
+ icon: string;
10
+ }
11
+
12
+ type MarqueeItem = string | TechItem;
13
+
14
+ const inspirations: string[] = [
15
+ 'Codegrid',
16
+ 'Manu Arora',
17
+ 'Shadcn',
18
+ 'Skiper-Ui',
19
+ ];
20
+
21
+ const techStack: TechItem[] = [
22
+ { name: 'Tailwind CSS', icon: '' },
23
+ { name: 'Next.js', icon: '' },
24
+ { name: 'Motion.dev', icon: '' },
25
+ { name: 'Framer Motion', icon: '' },
26
+ { name: 'GSAP', icon: '' },
27
+ { name: 'TypeScript', icon: '' },
28
+ { name: 'React', icon: '' },
29
+ { name: 'Vercel', icon: '' },
30
+ ];
31
+
32
+ interface ScrollMarqueeProps {
33
+ items: MarqueeItem[];
34
+ speed?: number;
35
+ direction?: 1 | -1;
36
+ }
37
+
38
+ const ScrollMarquee = ({ items, direction = 1 }: ScrollMarqueeProps) => {
39
+ const trackRef = useRef<HTMLDivElement>(null);
40
+ const animRef = useRef<number>(0);
41
+ const posRef = useRef<number>(0);
42
+
43
+ useEffect(() => {
44
+ const track = trackRef.current;
45
+ if (!track) return;
46
+
47
+ const step = () => {
48
+ posRef.current -= direction * 0.5;
49
+ const halfWidth = track.scrollWidth / 2;
50
+ if (direction > 0 && Math.abs(posRef.current) >= halfWidth) {
51
+ posRef.current = 0;
52
+ } else if (direction < 0 && posRef.current >= 0) {
53
+ posRef.current = -halfWidth;
54
+ }
55
+ track.style.transform = `translateX(${posRef.current}px)`;
56
+ animRef.current = requestAnimationFrame(step);
57
+ };
58
+
59
+ animRef.current = requestAnimationFrame(step);
60
+ return () => cancelAnimationFrame(animRef.current);
61
+ }, [direction]);
62
+
63
+ return (
64
+ <div className='overflow-hidden w-full [mask-image:linear-gradient(to_right,transparent,black_10%,black_90%,transparent)]'>
65
+ <div
66
+ ref={trackRef}
67
+ className='flex gap-12 whitespace-nowrap will-change-transform'
68
+ style={{ width: 'max-content' }}
69
+ >
70
+ {[...items, ...items].map((item, i) => (
71
+ <span
72
+ key={i}
73
+ className='inline-flex items-center gap-3 text-base font-medium text-white/75 tracking-widest'
74
+ >
75
+ {typeof item === 'string' ? (
76
+ <>
77
+ <span className='text-white/75 text-[10px]'>◆</span>
78
+ {item}
79
+ </>
80
+ ) : (
81
+ <>
82
+ <span className='text-white/75 text-[13px]'>{item.icon}</span>
83
+ {item.name}
84
+ </>
85
+ )}
86
+ </span>
87
+ ))}
88
+ </div>
89
+ </div>
90
+ );
91
+ };
92
+
93
+ interface DashedDividerProps {
94
+ label: string;
95
+ }
96
+
97
+ const DashedDivider = ({ label }: DashedDividerProps) => (
98
+ <div className='flex items-center gap-4 w-full my-10'>
99
+
100
+ <div className='flex-1 h-px bg-gradient-to-r from-transparent to-white/20' />
101
+ <span className='text-[9px] tracking-[0.2em] text-white/30 font-mono uppercase shrink-0'>
102
+ {label}
103
+ </span>
104
+ <div className='flex-1 h-px bg-gradient-to-l from-transparent to-white/20' />
105
+ </div>
106
+ );
107
+
108
+ export default function IndustryProof() {
109
+ const [visible, setVisible] = useState<boolean>(false);
110
+
111
+ useEffect(() => {
112
+ const t = setTimeout(() => setVisible(true), 100);
113
+ return () => clearTimeout(t);
114
+ }, []);
115
+
116
+ return (
117
+ <section className='relative min-h-screen flex flex-col items-center justify-center px-6 overflow-hidden '>
118
+ {/* 2. Bottom fade-out (Transitions to the next section) */}
119
+ {/* <div className='absolute bottom-0 left-0 right-0 h-74 bg-gradient-to-t from-white/[0.1] to-transparent pointer-events-none' /> */}
120
+
121
+ {/* --- CONTENT --- */}
122
+ <div
123
+ className={`relative z-10 w-full max-w-[860px] transition-all duration-[1000ms] ease-out ${
124
+ visible ? 'opacity-100 translate-y-0' : 'opacity-0 translate-y-4'
125
+ }`}
126
+ >
127
+ <DashedDivider label='Inspired & Legends' />
128
+
129
+ <div className='mb-4'>
130
+ <ScrollMarquee items={inspirations} direction={1} />
131
+ </div>
132
+ <div className='mb-12'>
133
+ <ScrollMarquee items={[...inspirations].reverse()} direction={-1} />
134
+ </div>
135
+
136
+ <DashedDivider label='Tools & Stack' />
137
+
138
+ <div className='mb-4'>
139
+ <ScrollMarquee items={techStack} direction={1} />
140
+ </div>
141
+ <div className='mb-12'>
142
+ <ScrollMarquee items={[...techStack].reverse()} direction={-1} />
143
+ </div>
144
+
145
+ <div className='mt-8 flex justify-center'>
146
+ <Link
147
+ href='/pricing'
148
+ className='relative z-30 h-12 px-6 rounded-lg text-sm text-white transition-all flex items-center gap-2 group'
149
+ >
150
+ Be a part now
151
+ <div className='flex items-center justify-center transition-transform group-hover:translate-x-1'>
152
+ <ChevronRight size={18} />
153
+ </div>
154
+ </Link>
155
+ </div>
156
+ </div>
157
+ </section>
158
+ );
159
+ }