alexui 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 +57 -0
- package/components/ActionTable.tsx +307 -0
- package/components/AlertBanner.tsx +124 -0
- package/components/AnimatedAccordion.tsx +95 -0
- package/components/Autocomplete.tsx +144 -0
- package/components/Avatar.tsx +123 -0
- package/components/Badge.tsx +80 -0
- package/components/Breadcrumb.tsx +74 -0
- package/components/Calendar.tsx +340 -0
- package/components/Card3D.tsx +117 -0
- package/components/Carousel3D.tsx +193 -0
- package/components/CascadeSelect.tsx +232 -0
- package/components/ChartShowcase.tsx +700 -0
- package/components/Checkbox.tsx +212 -0
- package/components/ChipsInput.tsx +152 -0
- package/components/CircularKnob.tsx +240 -0
- package/components/CodeVisualizer.tsx +67 -0
- package/components/Collapsible.tsx +72 -0
- package/components/ColorThemeManager.tsx +458 -0
- package/components/CommandMenu.tsx +191 -0
- package/components/ConfirmDialog.tsx +152 -0
- package/components/ContextMenu.tsx +192 -0
- package/components/DashboardLayout.tsx +115 -0
- package/components/DatePicker.tsx +108 -0
- package/components/Divider.tsx +67 -0
- package/components/Dock.tsx +93 -0
- package/components/DragDropLists.tsx +160 -0
- package/components/Drawer.tsx +161 -0
- package/components/DropdownPlus.tsx +304 -0
- package/components/EmptyState.tsx +49 -0
- package/components/ErrorPage.tsx +62 -0
- package/components/FileDropzone.tsx +206 -0
- package/components/ForgotPassword.tsx +137 -0
- package/components/FormField.tsx +81 -0
- package/components/GlassButton.tsx +56 -0
- package/components/GlassCard.tsx +82 -0
- package/components/GlassInput.tsx +96 -0
- package/components/GlassmorphicModal.tsx +108 -0
- package/components/GlowInput.tsx +111 -0
- package/components/GlowSelect.tsx +203 -0
- package/components/GlowTextArea.tsx +105 -0
- package/components/HorizontalTimeline.tsx +121 -0
- package/components/HoverCard.tsx +105 -0
- package/components/ImageLightbox.tsx +259 -0
- package/components/InputGroup.tsx +118 -0
- package/components/InputOTP.tsx +147 -0
- package/components/InteractiveNavbar.tsx +266 -0
- package/components/InteractiveSidebar.tsx +211 -0
- package/components/Kbd.tsx +51 -0
- package/components/LiteYouTube.tsx +118 -0
- package/components/LoaderCollection.tsx +368 -0
- package/components/LoginForm.tsx +192 -0
- package/components/MagneticButton.tsx +101 -0
- package/components/MaskedInput.tsx +79 -0
- package/components/MentionInput.tsx +413 -0
- package/components/MorphingSwitch.tsx +86 -0
- package/components/MultiSelect.tsx +158 -0
- package/components/NumberInput.tsx +203 -0
- package/components/Panel.tsx +104 -0
- package/components/PasswordInput.tsx +203 -0
- package/components/Popover.tsx +91 -0
- package/components/PricingTable.tsx +113 -0
- package/components/ProgressBar.tsx +152 -0
- package/components/RadioButton.tsx +211 -0
- package/components/Rating.tsx +82 -0
- package/components/ResizablePanel.tsx +114 -0
- package/components/ScrollPanel.tsx +103 -0
- package/components/SettingsPage.tsx +154 -0
- package/components/SignupForm.tsx +182 -0
- package/components/Skeleton.tsx +41 -0
- package/components/Slider.tsx +95 -0
- package/components/SlidingTabs.tsx +54 -0
- package/components/SortableList.tsx +91 -0
- package/components/SpeedDial.tsx +134 -0
- package/components/Spinner.tsx +40 -0
- package/components/Stepper.tsx +124 -0
- package/components/TabMenu.tsx +72 -0
- package/components/TableControls.tsx +77 -0
- package/components/TablePagination.tsx +88 -0
- package/components/TextEditor.tsx +329 -0
- package/components/TextReveal.tsx +99 -0
- package/components/ThemeSwitcher.tsx +133 -0
- package/components/TimelineGSAP.tsx +164 -0
- package/components/ToastSystem.tsx +110 -0
- package/components/ToggleButton.tsx +79 -0
- package/components/Tooltip.tsx +121 -0
- package/components/Tree.tsx +138 -0
- package/dist/commands/add.d.ts +7 -0
- package/dist/commands/add.js +110 -0
- package/dist/commands/init.d.ts +5 -0
- package/dist/commands/init.js +76 -0
- package/dist/commands/list.d.ts +1 -0
- package/dist/commands/list.js +32 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +60 -0
- package/dist/registry.d.ts +6 -0
- package/dist/registry.js +38 -0
- package/dist/tui/browse.d.ts +3 -0
- package/dist/tui/browse.js +139 -0
- package/dist/tui/format.d.ts +11 -0
- package/dist/tui/format.js +52 -0
- package/dist/tui/main.d.ts +1 -0
- package/dist/tui/main.js +86 -0
- package/dist/tui/panels.d.ts +9 -0
- package/dist/tui/panels.js +50 -0
- package/dist/tui/theme.d.ts +28 -0
- package/dist/tui/theme.js +76 -0
- package/dist/types.d.ts +28 -0
- package/dist/types.js +1 -0
- package/dist/utils/config.d.ts +6 -0
- package/dist/utils/config.js +24 -0
- package/dist/utils/copy.d.ts +9 -0
- package/dist/utils/copy.js +43 -0
- package/dist/utils/cwd.d.ts +6 -0
- package/dist/utils/cwd.js +30 -0
- package/dist/utils/deps.d.ts +1 -0
- package/dist/utils/deps.js +19 -0
- package/dist/utils/project.d.ts +5 -0
- package/dist/utils/project.js +30 -0
- package/dist/utils/theme.d.ts +1 -0
- package/dist/utils/theme.js +24 -0
- package/package.json +52 -0
- package/registry.json +1133 -0
- package/templates/theme.css +81 -0
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import * as p from '@clack/prompts';
|
|
2
|
+
import pc from 'picocolors';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { getRegistry } from '../registry.js';
|
|
5
|
+
import { configExists, readConfig } from '../utils/config.js';
|
|
6
|
+
import { detectPackageManager } from '../utils/project.js';
|
|
7
|
+
import { icon, renderBanner, renderDivider, shortenPath, statusBadge } from './theme.js';
|
|
8
|
+
export function renderProjectPanel(cwd) {
|
|
9
|
+
const registry = getRegistry();
|
|
10
|
+
const pm = detectPackageManager(cwd);
|
|
11
|
+
const ready = configExists(cwd);
|
|
12
|
+
const lines = [
|
|
13
|
+
statusBadge(ready) + pc.dim(' ') + pc.dim(shortenPath(cwd, 44)),
|
|
14
|
+
'',
|
|
15
|
+
`${icon.project} ${pc.bold('Proyecto')} ${pc.white(shortenPath(cwd))}`,
|
|
16
|
+
`${icon.pm} ${pc.bold('Gestor')} ${pc.cyan(pm)}`,
|
|
17
|
+
`${icon.list} ${pc.bold('Catálogo')} ${pc.dim(`AlexUI ${registry.version} · ${registry.componentCount} componentes`)}`,
|
|
18
|
+
];
|
|
19
|
+
if (ready) {
|
|
20
|
+
const config = readConfig(cwd);
|
|
21
|
+
lines.splice(3, 0, `${icon.folder} ${pc.bold('UI')} ${pc.dim(path.join(cwd, config.componentDir))}`, `${icon.css} ${pc.bold('CSS')} ${pc.dim(path.join(cwd, config.tailwind.css))}`);
|
|
22
|
+
}
|
|
23
|
+
else {
|
|
24
|
+
lines.splice(3, 0, pc.yellow(` ${icon.warn} Sin alexui.json — inicializá el proyecto primero`));
|
|
25
|
+
}
|
|
26
|
+
return lines.join('\n');
|
|
27
|
+
}
|
|
28
|
+
export function printWelcome(cwd) {
|
|
29
|
+
const registry = getRegistry();
|
|
30
|
+
console.log(renderBanner(registry.version, registry.componentCount));
|
|
31
|
+
p.note(renderProjectPanel(cwd), `${icon.logo} Panel de control`);
|
|
32
|
+
}
|
|
33
|
+
export function printProjectPanel(cwd, title = 'Estado actualizado') {
|
|
34
|
+
p.note(renderProjectPanel(cwd), title);
|
|
35
|
+
}
|
|
36
|
+
export function menuOptions(cwd) {
|
|
37
|
+
const registry = getRegistry();
|
|
38
|
+
return [
|
|
39
|
+
{ value: 'init', label: `${icon.init} Inicializar proyecto`, hint: 'alexui.json + tema CSS' },
|
|
40
|
+
{ value: 'add', label: `${icon.add} Agregar componentes`, hint: 'multiselección rápida' },
|
|
41
|
+
{ value: 'browse', label: `${icon.browse} Explorar catálogo`, hint: 'detalle y preview' },
|
|
42
|
+
{ value: 'search', label: `${icon.search} Buscar`, hint: 'id, título o categoría' },
|
|
43
|
+
{ value: 'list', label: `${icon.list} Ver catálogo completo`, hint: `${registry.componentCount} items` },
|
|
44
|
+
{ value: 'chdir', label: `${icon.chdir} Cambiar proyecto`, hint: shortenPath(cwd, 36) },
|
|
45
|
+
{ value: 'exit', label: `${icon.exit} Salir`, hint: 'cerrar TUI' },
|
|
46
|
+
];
|
|
47
|
+
}
|
|
48
|
+
export function sectionHeader(title) {
|
|
49
|
+
console.log(renderDivider(title));
|
|
50
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
export declare const icon: {
|
|
2
|
+
readonly logo: "✦";
|
|
3
|
+
readonly project: "◈";
|
|
4
|
+
readonly folder: "▸";
|
|
5
|
+
readonly css: "◇";
|
|
6
|
+
readonly pm: "⚡";
|
|
7
|
+
readonly init: "⚙";
|
|
8
|
+
readonly add: "+";
|
|
9
|
+
readonly browse: "◉";
|
|
10
|
+
readonly search: "◎";
|
|
11
|
+
readonly list: "≡";
|
|
12
|
+
readonly chdir: "↦";
|
|
13
|
+
readonly exit: "✕";
|
|
14
|
+
readonly complete: "●";
|
|
15
|
+
readonly atomic: "○";
|
|
16
|
+
readonly npm: "▪";
|
|
17
|
+
readonly internal: "↳";
|
|
18
|
+
readonly ok: "✓";
|
|
19
|
+
readonly warn: "!";
|
|
20
|
+
readonly back: "←";
|
|
21
|
+
};
|
|
22
|
+
export declare function categoryIcon(category: string): string;
|
|
23
|
+
export declare function shortenPath(fullPath: string, max?: number): string;
|
|
24
|
+
export declare function renderBanner(version: string, componentCount: number): string;
|
|
25
|
+
export declare function renderDivider(label?: string): string;
|
|
26
|
+
export declare function statusBadge(ready: boolean): string;
|
|
27
|
+
export declare function groupBadge(group: 'completos' | 'individuales'): string;
|
|
28
|
+
export declare function depPills(deps: string[], kind: 'npm' | 'internal'): string;
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import pc from 'picocolors';
|
|
2
|
+
export const icon = {
|
|
3
|
+
logo: '✦',
|
|
4
|
+
project: '◈',
|
|
5
|
+
folder: '▸',
|
|
6
|
+
css: '◇',
|
|
7
|
+
pm: '⚡',
|
|
8
|
+
init: '⚙',
|
|
9
|
+
add: '+',
|
|
10
|
+
browse: '◉',
|
|
11
|
+
search: '◎',
|
|
12
|
+
list: '≡',
|
|
13
|
+
chdir: '↦',
|
|
14
|
+
exit: '✕',
|
|
15
|
+
complete: '●',
|
|
16
|
+
atomic: '○',
|
|
17
|
+
npm: '▪',
|
|
18
|
+
internal: '↳',
|
|
19
|
+
ok: '✓',
|
|
20
|
+
warn: '!',
|
|
21
|
+
back: '←',
|
|
22
|
+
};
|
|
23
|
+
const CATEGORY_ICONS = {
|
|
24
|
+
entradas: '⌨',
|
|
25
|
+
estructura: '▣',
|
|
26
|
+
feedback: '◐',
|
|
27
|
+
multimedia: '▶',
|
|
28
|
+
animaciones: '〜',
|
|
29
|
+
tablas: '▤',
|
|
30
|
+
complejos: '◆',
|
|
31
|
+
};
|
|
32
|
+
export function categoryIcon(category) {
|
|
33
|
+
return CATEGORY_ICONS[category] ?? '·';
|
|
34
|
+
}
|
|
35
|
+
export function shortenPath(fullPath, max = 52) {
|
|
36
|
+
if (fullPath.length <= max)
|
|
37
|
+
return fullPath;
|
|
38
|
+
const normalized = fullPath.replace(/\\/g, '/');
|
|
39
|
+
const parts = normalized.split('/');
|
|
40
|
+
if (parts.length <= 3)
|
|
41
|
+
return `…${normalized.slice(-max + 1)}`;
|
|
42
|
+
return `${parts[0]}/…/${parts.slice(-2).join('/')}`;
|
|
43
|
+
}
|
|
44
|
+
export function renderBanner(version, componentCount) {
|
|
45
|
+
const line = '─'.repeat(36);
|
|
46
|
+
return [
|
|
47
|
+
'',
|
|
48
|
+
pc.magenta(` ${icon.logo} `) + pc.bold(pc.white('AlexUI')) + pc.dim(` v${version}`),
|
|
49
|
+
pc.dim(` ${line}`),
|
|
50
|
+
pc.dim(` ${componentCount} componentes`) + pc.magenta(' · ') + pc.dim('glassmorphic react'),
|
|
51
|
+
'',
|
|
52
|
+
].join('\n');
|
|
53
|
+
}
|
|
54
|
+
export function renderDivider(label) {
|
|
55
|
+
if (!label)
|
|
56
|
+
return pc.dim(' ────────────────────────────────────');
|
|
57
|
+
const pad = Math.max(2, 34 - label.length);
|
|
58
|
+
return pc.dim(` ── ${label} ${'─'.repeat(pad)}`);
|
|
59
|
+
}
|
|
60
|
+
export function statusBadge(ready) {
|
|
61
|
+
return ready
|
|
62
|
+
? pc.bgGreen(pc.black(` ${icon.ok} listo `))
|
|
63
|
+
: pc.bgYellow(pc.black(` ${icon.warn} sin init `));
|
|
64
|
+
}
|
|
65
|
+
export function groupBadge(group) {
|
|
66
|
+
return group === 'completos'
|
|
67
|
+
? pc.bgMagenta(pc.black(` ${icon.complete} completo `))
|
|
68
|
+
: pc.bgBlue(pc.black(` ${icon.atomic} atómico `));
|
|
69
|
+
}
|
|
70
|
+
export function depPills(deps, kind) {
|
|
71
|
+
if (deps.length === 0)
|
|
72
|
+
return pc.dim(' ninguna');
|
|
73
|
+
const color = kind === 'npm' ? pc.cyan : pc.yellow;
|
|
74
|
+
const prefix = kind === 'npm' ? icon.npm : icon.internal;
|
|
75
|
+
return deps.map((d) => color(` ${prefix} ${d} `)).join(pc.dim(' · '));
|
|
76
|
+
}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
export interface AlexUIConfig {
|
|
2
|
+
$schema?: string;
|
|
3
|
+
style: string;
|
|
4
|
+
tailwind: {
|
|
5
|
+
css: string;
|
|
6
|
+
version: string;
|
|
7
|
+
};
|
|
8
|
+
componentDir: string;
|
|
9
|
+
aliases?: {
|
|
10
|
+
components?: string;
|
|
11
|
+
ui?: string;
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
export interface RegistryComponent {
|
|
15
|
+
id: string;
|
|
16
|
+
title: string;
|
|
17
|
+
group: 'completos' | 'individuales';
|
|
18
|
+
category: string;
|
|
19
|
+
description: string;
|
|
20
|
+
file: string;
|
|
21
|
+
npmDependencies: string[];
|
|
22
|
+
internalDependencies: string[];
|
|
23
|
+
}
|
|
24
|
+
export interface RegistryManifest {
|
|
25
|
+
version: string;
|
|
26
|
+
componentCount: number;
|
|
27
|
+
components: RegistryComponent[];
|
|
28
|
+
}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { AlexUIConfig } from '../types.js';
|
|
2
|
+
export declare function getConfigPath(cwd?: string): string;
|
|
3
|
+
export declare function configExists(cwd?: string): boolean;
|
|
4
|
+
export declare function readConfig(cwd?: string): AlexUIConfig;
|
|
5
|
+
export declare function writeConfig(config: AlexUIConfig, cwd?: string): void;
|
|
6
|
+
export declare const DEFAULT_CONFIG: AlexUIConfig;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
const CONFIG_FILE = 'alexui.json';
|
|
4
|
+
export function getConfigPath(cwd = process.cwd()) {
|
|
5
|
+
return path.join(cwd, CONFIG_FILE);
|
|
6
|
+
}
|
|
7
|
+
export function configExists(cwd = process.cwd()) {
|
|
8
|
+
return fs.existsSync(getConfigPath(cwd));
|
|
9
|
+
}
|
|
10
|
+
export function readConfig(cwd = process.cwd()) {
|
|
11
|
+
const raw = fs.readFileSync(getConfigPath(cwd), 'utf8');
|
|
12
|
+
return JSON.parse(raw);
|
|
13
|
+
}
|
|
14
|
+
export function writeConfig(config, cwd = process.cwd()) {
|
|
15
|
+
fs.writeFileSync(getConfigPath(cwd), JSON.stringify(config, null, 2) + '\n', 'utf8');
|
|
16
|
+
}
|
|
17
|
+
export const DEFAULT_CONFIG = {
|
|
18
|
+
style: 'default',
|
|
19
|
+
tailwind: {
|
|
20
|
+
css: 'src/index.css',
|
|
21
|
+
version: '4',
|
|
22
|
+
},
|
|
23
|
+
componentDir: 'src/components/ui',
|
|
24
|
+
};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { RegistryComponent } from '../types.js';
|
|
2
|
+
export interface CopyResult {
|
|
3
|
+
created: string[];
|
|
4
|
+
skipped: string[];
|
|
5
|
+
targetDir: string;
|
|
6
|
+
}
|
|
7
|
+
export declare function copyComponents(components: RegistryComponent[], targetDir: string, overwrite?: boolean): CopyResult;
|
|
8
|
+
export declare function collectNpmDependencies(components: RegistryComponent[]): string[];
|
|
9
|
+
export declare function getMissingDependencies(required: string[], cwd?: string): string[];
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { getComponentsDir } from '../registry.js';
|
|
4
|
+
import { ensureDir } from './project.js';
|
|
5
|
+
export function copyComponents(components, targetDir, overwrite = false) {
|
|
6
|
+
const sourceDir = getComponentsDir();
|
|
7
|
+
ensureDir(targetDir);
|
|
8
|
+
const created = [];
|
|
9
|
+
const skipped = [];
|
|
10
|
+
for (const comp of components) {
|
|
11
|
+
const src = path.join(sourceDir, comp.file);
|
|
12
|
+
const dest = path.join(targetDir, comp.file);
|
|
13
|
+
if (!fs.existsSync(src)) {
|
|
14
|
+
throw new Error(`Componente fuente no encontrado: ${comp.file}`);
|
|
15
|
+
}
|
|
16
|
+
if (fs.existsSync(dest) && !overwrite) {
|
|
17
|
+
skipped.push(comp.file);
|
|
18
|
+
continue;
|
|
19
|
+
}
|
|
20
|
+
fs.copyFileSync(src, dest);
|
|
21
|
+
created.push(comp.file);
|
|
22
|
+
}
|
|
23
|
+
return { created, skipped, targetDir };
|
|
24
|
+
}
|
|
25
|
+
export function collectNpmDependencies(components) {
|
|
26
|
+
const deps = new Set();
|
|
27
|
+
for (const comp of components) {
|
|
28
|
+
for (const dep of comp.npmDependencies)
|
|
29
|
+
deps.add(dep);
|
|
30
|
+
}
|
|
31
|
+
return [...deps].sort();
|
|
32
|
+
}
|
|
33
|
+
export function getMissingDependencies(required, cwd = process.cwd()) {
|
|
34
|
+
const pkgPath = path.join(cwd, 'package.json');
|
|
35
|
+
if (!fs.existsSync(pkgPath))
|
|
36
|
+
return required;
|
|
37
|
+
const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
|
|
38
|
+
const installed = new Set([
|
|
39
|
+
...Object.keys(pkg.dependencies ?? {}),
|
|
40
|
+
...Object.keys(pkg.devDependencies ?? {}),
|
|
41
|
+
]);
|
|
42
|
+
return required.filter((dep) => !installed.has(dep));
|
|
43
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
export function resolveProjectDir(input) {
|
|
4
|
+
const dir = path.resolve(input ?? process.cwd());
|
|
5
|
+
if (!fs.existsSync(dir)) {
|
|
6
|
+
throw new Error(`El directorio no existe: ${dir}`);
|
|
7
|
+
}
|
|
8
|
+
if (!fs.statSync(dir).isDirectory()) {
|
|
9
|
+
throw new Error(`No es un directorio: ${dir}`);
|
|
10
|
+
}
|
|
11
|
+
return dir;
|
|
12
|
+
}
|
|
13
|
+
/** Extrae --cwd / -C de argv antes de que Commander los procese. */
|
|
14
|
+
export function parseCwdFromArgs(args) {
|
|
15
|
+
let cwd = process.cwd();
|
|
16
|
+
const rest = [];
|
|
17
|
+
for (let i = 0; i < args.length; i++) {
|
|
18
|
+
const arg = args[i];
|
|
19
|
+
if ((arg === '--cwd' || arg === '-C') && args[i + 1]) {
|
|
20
|
+
cwd = args[++i];
|
|
21
|
+
continue;
|
|
22
|
+
}
|
|
23
|
+
if (arg.startsWith('--cwd=')) {
|
|
24
|
+
cwd = arg.slice(6);
|
|
25
|
+
continue;
|
|
26
|
+
}
|
|
27
|
+
rest.push(arg);
|
|
28
|
+
}
|
|
29
|
+
return { cwd, rest };
|
|
30
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function installPackages(packages: string[], cwd?: string): boolean;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { spawnSync } from 'node:child_process';
|
|
2
|
+
import { detectPackageManager } from './project.js';
|
|
3
|
+
export function installPackages(packages, cwd = process.cwd()) {
|
|
4
|
+
if (packages.length === 0)
|
|
5
|
+
return true;
|
|
6
|
+
const pm = detectPackageManager(cwd);
|
|
7
|
+
const installArgs = {
|
|
8
|
+
npm: ['install', ...packages],
|
|
9
|
+
pnpm: ['add', ...packages],
|
|
10
|
+
yarn: ['add', ...packages],
|
|
11
|
+
bun: ['add', ...packages],
|
|
12
|
+
};
|
|
13
|
+
const result = spawnSync(pm, installArgs[pm], {
|
|
14
|
+
cwd,
|
|
15
|
+
stdio: 'inherit',
|
|
16
|
+
shell: process.platform === 'win32',
|
|
17
|
+
});
|
|
18
|
+
return result.status === 0;
|
|
19
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export declare function ensureDir(dir: string): void;
|
|
2
|
+
export declare function fileExists(filePath: string): boolean;
|
|
3
|
+
export declare function readPackageJson(cwd?: string): Record<string, unknown> | null;
|
|
4
|
+
export declare function detectPackageManager(cwd?: string): 'npm' | 'pnpm' | 'yarn' | 'bun';
|
|
5
|
+
export declare function hasReactProject(cwd?: string): boolean;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
export function ensureDir(dir) {
|
|
4
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
5
|
+
}
|
|
6
|
+
export function fileExists(filePath) {
|
|
7
|
+
return fs.existsSync(filePath);
|
|
8
|
+
}
|
|
9
|
+
export function readPackageJson(cwd = process.cwd()) {
|
|
10
|
+
const pkgPath = path.join(cwd, 'package.json');
|
|
11
|
+
if (!fs.existsSync(pkgPath))
|
|
12
|
+
return null;
|
|
13
|
+
return JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
|
|
14
|
+
}
|
|
15
|
+
export function detectPackageManager(cwd = process.cwd()) {
|
|
16
|
+
if (fs.existsSync(path.join(cwd, 'bun.lockb')) || fs.existsSync(path.join(cwd, 'bun.lock')))
|
|
17
|
+
return 'bun';
|
|
18
|
+
if (fs.existsSync(path.join(cwd, 'pnpm-lock.yaml')))
|
|
19
|
+
return 'pnpm';
|
|
20
|
+
if (fs.existsSync(path.join(cwd, 'yarn.lock')))
|
|
21
|
+
return 'yarn';
|
|
22
|
+
return 'npm';
|
|
23
|
+
}
|
|
24
|
+
export function hasReactProject(cwd = process.cwd()) {
|
|
25
|
+
const pkg = readPackageJson(cwd);
|
|
26
|
+
if (!pkg)
|
|
27
|
+
return false;
|
|
28
|
+
const deps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
29
|
+
return Boolean(deps.react);
|
|
30
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function applyThemeCss(cssPath: string, cwd?: string): 'created' | 'merged' | 'exists';
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { getTemplatesDir } from '../registry.js';
|
|
4
|
+
import { ensureDir } from './project.js';
|
|
5
|
+
const THEME_MARKER = '/* alexui-theme */';
|
|
6
|
+
export function applyThemeCss(cssPath, cwd = process.cwd()) {
|
|
7
|
+
const fullPath = path.join(cwd, cssPath);
|
|
8
|
+
const templatePath = path.join(getTemplatesDir(), 'theme.css');
|
|
9
|
+
if (!fs.existsSync(templatePath)) {
|
|
10
|
+
throw new Error('Plantilla de tema no encontrada en el paquete CLI');
|
|
11
|
+
}
|
|
12
|
+
const template = fs.readFileSync(templatePath, 'utf8');
|
|
13
|
+
if (!fs.existsSync(fullPath)) {
|
|
14
|
+
ensureDir(path.dirname(fullPath));
|
|
15
|
+
fs.writeFileSync(fullPath, template, 'utf8');
|
|
16
|
+
return 'created';
|
|
17
|
+
}
|
|
18
|
+
const existing = fs.readFileSync(fullPath, 'utf8');
|
|
19
|
+
if (existing.includes(THEME_MARKER) || existing.includes('--color-accent')) {
|
|
20
|
+
return 'exists';
|
|
21
|
+
}
|
|
22
|
+
fs.writeFileSync(fullPath, `${existing.trimEnd()}\n\n${template}\n`, 'utf8');
|
|
23
|
+
return 'merged';
|
|
24
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "alexui",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "CLI para agregar componentes AlexUI by Alexis Jardin a tu proyecto React",
|
|
5
|
+
"author": "Alexis Jardin",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "https://github.com/alexisjardin-js/AlexUI.git",
|
|
10
|
+
"directory": "packages/cli"
|
|
11
|
+
},
|
|
12
|
+
"homepage": "https://github.com/alexisjardin-js/AlexUI#readme",
|
|
13
|
+
"bugs": {
|
|
14
|
+
"url": "https://github.com/alexisjardin-js/AlexUI/issues"
|
|
15
|
+
},
|
|
16
|
+
"keywords": [
|
|
17
|
+
"react",
|
|
18
|
+
"ui",
|
|
19
|
+
"components",
|
|
20
|
+
"glassmorphic",
|
|
21
|
+
"tailwind",
|
|
22
|
+
"cli",
|
|
23
|
+
"shadcn"
|
|
24
|
+
],
|
|
25
|
+
"type": "module",
|
|
26
|
+
"bin": {
|
|
27
|
+
"alexui": "./dist/index.js"
|
|
28
|
+
},
|
|
29
|
+
"files": [
|
|
30
|
+
"dist",
|
|
31
|
+
"registry.json",
|
|
32
|
+
"components",
|
|
33
|
+
"templates"
|
|
34
|
+
],
|
|
35
|
+
"dependencies": {
|
|
36
|
+
"@clack/prompts": "^0.10.1",
|
|
37
|
+
"commander": "^13.1.0",
|
|
38
|
+
"picocolors": "^1.1.1"
|
|
39
|
+
},
|
|
40
|
+
"devDependencies": {
|
|
41
|
+
"@types/node": "^24.12.3",
|
|
42
|
+
"typescript": "~6.0.2"
|
|
43
|
+
},
|
|
44
|
+
"engines": {
|
|
45
|
+
"node": ">=18"
|
|
46
|
+
},
|
|
47
|
+
"scripts": {
|
|
48
|
+
"build": "tsc",
|
|
49
|
+
"prebuild": "node ../../scripts/generate-cli-registry.mjs",
|
|
50
|
+
"dev": "tsc --watch"
|
|
51
|
+
}
|
|
52
|
+
}
|