@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.
- package/README.md +36 -0
- package/__registry__/index.ts +493 -0
- package/app/(auth)/layout.tsx +18 -0
- package/app/(auth)/login/page.tsx +152 -0
- package/app/(protected)/component/[id]/page.tsx +48 -0
- package/app/(protected)/component/page.tsx +151 -0
- package/app/(protected)/docs/page.tsx +222 -0
- package/app/account/page.tsx +109 -0
- package/app/api/me/route.ts +24 -0
- package/app/globals.css +68 -0
- package/app/icon.png +0 -0
- package/app/layout.tsx +43 -0
- package/app/page.tsx +22 -0
- package/app/pricing/page.tsx +12 -0
- package/bin/intex.ts +19 -0
- package/components/smooth-scroll.tsx +26 -0
- package/components/toast.tsx +101 -0
- package/components/ui/IndustryProof.tsx +159 -0
- package/components/ui/ShowcaseContainer.tsx +497 -0
- package/components/ui/dot-cursor.tsx +108 -0
- package/components/ui/featuredComponents.tsx +126 -0
- package/components/ui/footer.tsx +59 -0
- package/components/ui/hero.tsx +85 -0
- package/components/ui/navbar.tsx +337 -0
- package/components/ui/pricing.tsx +163 -0
- package/eslint.config.mjs +18 -0
- package/hooks/use-component-search.tsx +52 -0
- package/lib/actions/auth.action.ts +88 -0
- package/lib/auth.ts +18 -0
- package/lib/email.ts +46 -0
- package/lib/prisma.ts +14 -0
- package/lib/registry.ts +17 -0
- package/lib/utils.ts +6 -0
- package/middleware/middleware.ts +21 -0
- package/next.config.ts +7 -0
- package/package.json +61 -0
- package/postcss.config.mjs +7 -0
- package/prisma/migrations/20260303172729_init/migration.sql +21 -0
- package/prisma/migrations/migration_lock.toml +3 -0
- package/prisma/schema.prisma +22 -0
- package/prisma.config.ts +14 -0
- package/public/compVideos/neubrutal-button.mp4 +0 -0
- package/public/fonts/BeVietnamPro-ExtraBold.otf +0 -0
- package/public/fonts/CartographCF-Regular.ttf +0 -0
- package/public/fonts/Hoshiko-Satsuki.ttf +0 -0
- package/public/fonts/Switzer-Regular.otf +0 -0
- package/public/images/PricingSlash.svg +58 -0
- package/public/images/slash_1.svg +59 -0
- package/public/images/slash_2.svg +18 -0
- package/public/video/hero_video.mp4 +0 -0
- package/registry/details/buttons/neubrutal-button-details.tsx +146 -0
- package/registry/details/cursor/dot-cursor-details.tsx +11 -0
- package/registry/details/navbar/floating-navbar-details.tsx +11 -0
- package/registry/details/scrollbars/minimal-scrollbar-details.tsx +0 -0
- package/registry/index.ts +35 -0
- package/registry/ui/buttons/neubrutal-button.tsx +33 -0
- package/registry/ui/cursors/dot-cursor.tsx +108 -0
- package/registry/ui/navbars/floating-navbar.tsx +99 -0
- package/registry/ui/scrollbars/minimal-scrollbar.tsx +203 -0
- package/scripts/build-registry.ts +60 -0
- package/src/commands/add.ts +40 -0
- package/src/commands/init.ts +75 -0
- package/src/commands/list.ts +44 -0
- package/src/index.ts +35 -0
- package/src/utils/get-pkg-manager.ts +7 -0
- 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();
|
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
|
+
}
|