@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
@@ -0,0 +1,60 @@
1
+ import { writeFileSync, existsSync, mkdirSync, readFileSync } from 'fs';
2
+ import path from 'path';
3
+ import { Index } from '../registry/index';
4
+
5
+ const OUTPUT_DIR = path.join(process.cwd(), '__registry__');
6
+ const OUTPUT_PATH = path.join(OUTPUT_DIR, 'index.ts');
7
+
8
+ async function buildRegistry() {
9
+ if (!existsSync(OUTPUT_DIR)) {
10
+ mkdirSync(OUTPUT_DIR);
11
+ }
12
+
13
+ let indexContent = `// @ts-nocheck
14
+ // This file is autogenerated by scripts/build-registry.ts
15
+ import * as React from "react"
16
+
17
+ export const Index: Record<string, any> = {
18
+ "default": {
19
+ `;
20
+
21
+ Index.forEach((item: any) => {
22
+ const componentPath = item.files[0].replace(/\.tsx?$/, '');
23
+ const sourceFilePath = path.join(process.cwd(), 'registry', item.files[0]);
24
+ const detailsFilePath = path.join(
25
+ process.cwd(),
26
+ 'registry',
27
+ `details/${item.name}.tsx`,
28
+ );
29
+ const hasDetails = existsSync(detailsFilePath);
30
+
31
+ const rawContent = existsSync(sourceFilePath)
32
+ ? readFileSync(sourceFilePath, 'utf8')
33
+ : '';
34
+ const safeContent = rawContent.replace(/`/g, '\\`').replace(/\$/g, '\\$');
35
+ const safeDescription = (item.description || '')
36
+ .replace(/`/g, '\\`')
37
+ .replace(/\$/g, '\\$');
38
+
39
+ indexContent += ` "${item.name}": {
40
+ name: "${item.name}",
41
+ type: "${item.type}",
42
+ component: React.lazy(() => import("../registry/${componentPath}")),
43
+ details: ${hasDetails ? `React.lazy(() => import("../registry/details/${item.name}"))` : 'null'},
44
+ files: ${JSON.stringify(item.files)},
45
+ category: "${item.category || 'undefined'}",
46
+ content: \`${safeContent}\`,
47
+ description: \`${safeDescription}\`,
48
+ install: "${item.install || ''}",
49
+ },
50
+ `;
51
+ });
52
+
53
+ indexContent += ` }
54
+ };`;
55
+
56
+ writeFileSync(OUTPUT_PATH, indexContent);
57
+ console.log('✅ Slash UI Registry updated!');
58
+ }
59
+
60
+ buildRegistry();
@@ -0,0 +1,40 @@
1
+ import fs from "fs-extra";
2
+ import path from "path";
3
+ import chalk from "chalk";
4
+ // Import the Index that YOUR script just generated
5
+ import { Index } from "../../__registry__/index";
6
+
7
+ export const addCommand = async (componentName: string) => {
8
+ try {
9
+ // Access the 'default' key from your generated file
10
+ const component = (Index as any).default[componentName];
11
+
12
+ if (!component) {
13
+ console.error(chalk.red(`\nError: Component "${componentName}" not found in registry.`));
14
+ return;
15
+ }
16
+
17
+ // Determine target directory (e.g., components/ui)
18
+ const targetDir = path.join(process.cwd(), "components", "ui");
19
+ await fs.ensureDir(targetDir);
20
+
21
+ // Use the first filename from your registry item
22
+ const fileName = component.files[0] ? path.basename(component.files[0]) : `${componentName}.tsx`;
23
+ const filePath = path.join(targetDir, fileName);
24
+
25
+ // Write the 'content' string that your build script saved
26
+ await fs.writeFile(filePath, component.content);
27
+
28
+ // --- Premium Success Message ---
29
+ console.log(`\n${chalk.bgCyan.black(" DONE ")} ${chalk.green(`Component ${chalk.bold(componentName)} has been added.`)}`);
30
+ console.log(`${chalk.dim("Location:")} ${chalk.cyan(filePath)}`);
31
+ // -------------------------------
32
+
33
+ if (component.install) {
34
+ console.log(chalk.yellow(`\nNote: This component requires dependencies: `) + chalk.cyan(component.install));
35
+ console.log(chalk.dim(`Run: npm install ${component.install}`));
36
+ }
37
+ } catch (error) {
38
+ console.error(chalk.red("\nFailed to add component:"), error);
39
+ }
40
+ }
@@ -0,0 +1,75 @@
1
+ import fs from 'fs-extra';
2
+ import path from 'path';
3
+ import chalk from 'chalk';
4
+ import prompts from 'prompts';
5
+
6
+ export const initCommand = async () => {
7
+ try {
8
+ console.log(chalk.bold.blue('\n🚀 Initializing Slash UI...\n'));
9
+
10
+ // 1. Ask user for preferred configuration
11
+ const response = await prompts([
12
+ {
13
+ type: 'text',
14
+ name: 'componentsPath',
15
+ message: 'Where would you like to install your components?',
16
+ initial: 'components/ui',
17
+ },
18
+ {
19
+ type: 'confirm',
20
+ name: 'proceed',
21
+ message:
22
+ 'This will create necessary directories and configuration files. Proceed?',
23
+ initial: true,
24
+ },
25
+ ]);
26
+
27
+ if (!response.proceed) {
28
+ console.log(chalk.yellow('Aborted initialization.'));
29
+ return;
30
+ }
31
+
32
+ // 2. Create the components directory
33
+ const targetDir = path.join(process.cwd(), response.componentsPath);
34
+ await fs.ensureDir(targetDir);
35
+ console.log(chalk.green(`✔ Created directory: ${response.componentsPath}`));
36
+
37
+ // 3. Create a components.json for your CLI to remember settings
38
+ const config = {
39
+ style: 'default',
40
+ tailwind: {
41
+ config: 'tailwind.config.js',
42
+ css: 'app/globals.css',
43
+ baseColor: 'zinc',
44
+ },
45
+ paths: {
46
+ components: response.componentsPath,
47
+ utils: 'lib/utils',
48
+ },
49
+ };
50
+
51
+ await fs.writeJSON(path.join(process.cwd(), 'components.json'), config, {
52
+ spaces: 2,
53
+ });
54
+ console.log(chalk.green('✔ Created components.json configuration'));
55
+
56
+ // 4. Check for Tailwind Config
57
+ const tailwindConfigPath = path.join(process.cwd(), 'tailwind.config.ts');
58
+
59
+ if (fs.existsSync(tailwindConfigPath)) {
60
+ let content = fs.readFileSync(tailwindConfigPath, 'utf-8');
61
+
62
+ // Automatically add the components directory to Tailwind's content array
63
+ if (!content.includes(response.componentsPath)) {
64
+ content = content.replace(
65
+ /content: \[([\s\S]*?)\]/,
66
+ `content: [$1, "./${response.componentsPath}/**/*.{ts,tsx}"]`,
67
+ );
68
+ fs.writeFileSync(tailwindConfigPath, content);
69
+ console.log(chalk.dim('✔ Updated tailwind.config.ts content paths.'));
70
+ }
71
+ }
72
+ } catch (error) {
73
+ console.error(chalk.red('\nFailed to initialize project:'), error);
74
+ }
75
+ };
@@ -0,0 +1,44 @@
1
+ import chalk from "chalk";
2
+ import prompts from "prompts";
3
+ import { Index } from "../../__registry__/index";
4
+ import { addCommand } from "./add";
5
+
6
+ export const listCommand = async () => {
7
+ try {
8
+ const registryData = (Index as any).default;
9
+ const components = Object.keys(registryData);
10
+
11
+ if (components.length === 0) {
12
+ console.log(chalk.red("\n✖ No components found. Run 'npm run build:registry' first."));
13
+ return;
14
+ }
15
+
16
+ // 1. Create the interactive menu choices
17
+ const choices = components.map((name) => ({
18
+ title: name,
19
+ value: name,
20
+ description: chalk.dim(registryData[name].category || "ui"),
21
+ }));
22
+
23
+ console.log(chalk.bold.cyan("\n─── Slash UI Explorer ───"));
24
+
25
+ // 2. Launch the autocomplete search menu
26
+ const response = await prompts({
27
+ type: "autocomplete",
28
+ name: "selected",
29
+ message: "Search components",
30
+ choices: choices,
31
+ // This allows filtering as you type
32
+ suggest: (input, choices) =>
33
+ Promise.resolve(choices.filter(i => i.title.toLowerCase().includes(input.toLowerCase()))),
34
+ });
35
+
36
+ // 3. If they select one, run the add command immediately
37
+ if (response.selected) {
38
+ await addCommand(response.selected);
39
+ }
40
+
41
+ } catch (error) {
42
+ console.error(chalk.red("\nFailed to display component list:"), error);
43
+ }
44
+ };
package/src/index.ts ADDED
@@ -0,0 +1,35 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { Command } from 'commander';
4
+ import { addCommand } from './commands/add';
5
+ import { initCommand } from './commands/init';
6
+ import { listCommand } from './commands/list';
7
+
8
+ const program = new Command();
9
+
10
+ program
11
+ .name('slash-ui')
12
+ .description('CLI for Slash UI components')
13
+ .version('1.0.0');
14
+
15
+ // 1. Init
16
+ program
17
+ .command('init')
18
+ .description('Initialize your project for Slash UI')
19
+ .action(initCommand);
20
+
21
+ // 2. List
22
+ program
23
+ .command('list')
24
+ .description('List all available components')
25
+ .action(listCommand);
26
+
27
+ // 3. Add
28
+ program
29
+ .command('add')
30
+ .description('Add a component to your project')
31
+ .argument('<component>', 'the component name to add')
32
+ .action(addCommand);
33
+
34
+ // ONLY ONE PARSE CALL AT THE VERY END
35
+ program.parse();
@@ -0,0 +1,7 @@
1
+ export function getPkgManager() {
2
+ const userAgent = process.env.npm_config_user_agent || "";
3
+ if (userAgent.includes("yarn")) return "yarn";
4
+ if (userAgent.includes("pnpm")) return "pnpm";
5
+ if (userAgent.includes("bun")) return "bun";
6
+ return "npm";
7
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,34 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2017",
4
+ "lib": ["dom", "dom.iterable", "esnext"],
5
+ "allowJs": true,
6
+ "skipLibCheck": true,
7
+ "strict": true,
8
+ "noEmit": true,
9
+ "esModuleInterop": true,
10
+ "module": "esnext",
11
+ "moduleResolution": "bundler",
12
+ "resolveJsonModule": true,
13
+ "isolatedModules": true,
14
+ "jsx": "react-jsx",
15
+ "incremental": true,
16
+ "plugins": [
17
+ {
18
+ "name": "next"
19
+ }
20
+ ],
21
+ "paths": {
22
+ "@/*": ["./*"]
23
+ }
24
+ },
25
+ "include": [
26
+ "next-env.d.ts",
27
+ "**/*.ts",
28
+ "**/*.tsx",
29
+ ".next/types/**/*.ts",
30
+ ".next/dev/types/**/*.ts",
31
+ "**/*.mts"
32
+ ],
33
+ "exclude": ["node_modules"]
34
+ }