ar-saas 0.2.0 → 0.3.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/LICENSE +21 -0
- package/README.md +133 -25
- package/dist/cli.js +33 -1
- package/dist/generator.js +12 -3
- package/package.json +7 -3
- package/templates/frontend/package.json +21 -13
- package/templates/frontend/pnpm-lock.yaml +5012 -0
- package/templates/frontend/pnpm-workspace.yaml +3 -0
- package/templates/frontend/src/app/(auth)/register/page.tsx +49 -7
- package/templates/frontend/src/app/(dashboard)/billing/page.tsx +111 -0
- package/templates/frontend/src/app/(dashboard)/dashboard/page.tsx +81 -12
- package/templates/frontend/src/app/(dashboard)/layout.tsx +11 -32
- package/templates/frontend/src/app/(dashboard)/profile/page.tsx +226 -0
- package/templates/frontend/src/app/(dashboard)/settings/page.tsx +156 -0
- package/templates/frontend/src/app/(dashboard)/team/page.tsx +178 -0
- package/templates/frontend/src/app/(legal)/privacy/page.tsx +127 -0
- package/templates/frontend/src/app/(legal)/terms/page.tsx +118 -0
- package/templates/frontend/src/app/page.tsx +43 -3
- package/templates/frontend/src/app/setup/page.tsx +1 -4
- package/templates/frontend/src/components/dashboard/header.tsx +89 -0
- package/templates/frontend/src/components/dashboard/sidebar.tsx +71 -0
- package/templates/frontend/src/components/dashboard/stat-card.tsx +34 -0
- package/templates/frontend/src/components/landing/faq.tsx +39 -0
- package/templates/frontend/src/components/landing/features.tsx +54 -0
- package/templates/frontend/src/components/landing/footer.tsx +76 -0
- package/templates/frontend/src/components/landing/hero.tsx +72 -0
- package/templates/frontend/src/components/landing/navbar.tsx +78 -0
- package/templates/frontend/src/components/landing/pricing.tsx +90 -0
- package/templates/frontend/src/components/ui/accordion.tsx +52 -0
- package/templates/frontend/src/components/ui/avatar.tsx +46 -0
- package/templates/frontend/src/components/ui/badge.tsx +30 -0
- package/templates/frontend/src/components/ui/checkbox.tsx +27 -0
- package/templates/frontend/src/components/ui/dialog.tsx +100 -0
- package/templates/frontend/src/components/ui/dropdown-menu.tsx +173 -0
- package/templates/frontend/src/components/ui/separator.tsx +25 -0
- package/templates/frontend/src/components/ui/skeleton.tsx +7 -0
- package/templates/frontend/src/components/ui/switch.tsx +28 -0
- package/templates/frontend/src/components/ui/tabs.tsx +54 -0
- package/templates/frontend/src/components/ui/textarea.tsx +20 -0
- package/templates/frontend/src/config/site.ts +197 -0
- package/dist/license.js +0 -71
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
2
|
+
// Archivo de configuración central del SaaS.
|
|
3
|
+
// Editá este archivo para personalizar textos, links y contenido de toda la app.
|
|
4
|
+
// Los valores con __PLACEHOLDER__ son reemplazados automáticamente por el CLI.
|
|
5
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
6
|
+
|
|
7
|
+
export const siteConfig = {
|
|
8
|
+
// ── Identidad ──────────────────────────────────────────────────────────────
|
|
9
|
+
name: '__SITE_NAME__',
|
|
10
|
+
tagline: '__SITE_TAGLINE__',
|
|
11
|
+
description: '__SITE_DESCRIPTION__',
|
|
12
|
+
url: 'https://tu-dominio.com',
|
|
13
|
+
supportEmail: '__SUPPORT_EMAIL__',
|
|
14
|
+
|
|
15
|
+
// ── Navegación pública (landing) ───────────────────────────────────────────
|
|
16
|
+
nav: {
|
|
17
|
+
links: [
|
|
18
|
+
{ label: 'Funcionalidades', href: '#features' },
|
|
19
|
+
{ label: 'Precios', href: '#pricing' },
|
|
20
|
+
{ label: 'FAQ', href: '#faq' },
|
|
21
|
+
],
|
|
22
|
+
},
|
|
23
|
+
|
|
24
|
+
// ── Hero ───────────────────────────────────────────────────────────────────
|
|
25
|
+
hero: {
|
|
26
|
+
headline: '__SITE_NAME__',
|
|
27
|
+
subheadline: '__SITE_TAGLINE__',
|
|
28
|
+
description: '__SITE_DESCRIPTION__',
|
|
29
|
+
cta: { label: 'Empezar gratis', href: '/register' },
|
|
30
|
+
ctaSecondary: { label: 'Ver funcionalidades', href: '#features' },
|
|
31
|
+
},
|
|
32
|
+
|
|
33
|
+
// ── Funcionalidades ────────────────────────────────────────────────────────
|
|
34
|
+
features: [
|
|
35
|
+
{
|
|
36
|
+
icon: 'Zap',
|
|
37
|
+
title: 'Rápido y confiable',
|
|
38
|
+
description: 'Infraestructura diseñada para escalar con tu negocio sin fricciones.',
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
icon: 'Shield',
|
|
42
|
+
title: 'Seguridad primero',
|
|
43
|
+
description: 'Autenticación robusta, tokens JWT y encriptación en toda la plataforma.',
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
icon: 'BarChart3',
|
|
47
|
+
title: 'Analytics en tiempo real',
|
|
48
|
+
description: 'Tomá decisiones basadas en datos con métricas actualizadas al instante.',
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
icon: 'Users',
|
|
52
|
+
title: 'Trabajo en equipo',
|
|
53
|
+
description: 'Invitá colaboradores y gestioná permisos de forma simple y segura.',
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
icon: 'Globe',
|
|
57
|
+
title: 'Multi-workspace',
|
|
58
|
+
description: 'Administrá múltiples proyectos o clientes desde una sola cuenta.',
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
icon: 'Headphones',
|
|
62
|
+
title: 'Soporte dedicado',
|
|
63
|
+
description: 'Estamos disponibles para ayudarte a resolver cualquier duda.',
|
|
64
|
+
},
|
|
65
|
+
],
|
|
66
|
+
|
|
67
|
+
// ── Precios ────────────────────────────────────────────────────────────────
|
|
68
|
+
pricing: [
|
|
69
|
+
{
|
|
70
|
+
name: 'Free',
|
|
71
|
+
price: '$0',
|
|
72
|
+
period: '/mes',
|
|
73
|
+
description: 'Para empezar y explorar la plataforma.',
|
|
74
|
+
features: [
|
|
75
|
+
'1 workspace',
|
|
76
|
+
'Hasta 3 usuarios',
|
|
77
|
+
'5 GB de almacenamiento',
|
|
78
|
+
'Soporte por email',
|
|
79
|
+
],
|
|
80
|
+
cta: 'Empezar gratis',
|
|
81
|
+
href: '/register',
|
|
82
|
+
highlight: false,
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
name: 'Pro',
|
|
86
|
+
price: '$29',
|
|
87
|
+
period: '/mes',
|
|
88
|
+
description: 'Para equipos que necesitan más poder.',
|
|
89
|
+
features: [
|
|
90
|
+
'Workspaces ilimitados',
|
|
91
|
+
'Usuarios ilimitados',
|
|
92
|
+
'50 GB de almacenamiento',
|
|
93
|
+
'Analytics avanzados',
|
|
94
|
+
'Soporte prioritario',
|
|
95
|
+
'Integraciones premium',
|
|
96
|
+
],
|
|
97
|
+
cta: 'Comenzar prueba gratis',
|
|
98
|
+
href: '/register',
|
|
99
|
+
highlight: true,
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
name: 'Enterprise',
|
|
103
|
+
price: 'A consultar',
|
|
104
|
+
period: '',
|
|
105
|
+
description: 'Soluciones a medida para grandes organizaciones.',
|
|
106
|
+
features: [
|
|
107
|
+
'Todo lo de Pro',
|
|
108
|
+
'SLA garantizado',
|
|
109
|
+
'Onboarding dedicado',
|
|
110
|
+
'SSO y SAML',
|
|
111
|
+
'Auditoría y compliance',
|
|
112
|
+
'Contrato personalizado',
|
|
113
|
+
],
|
|
114
|
+
cta: 'Hablar con ventas',
|
|
115
|
+
href: 'mailto:__SUPPORT_EMAIL__',
|
|
116
|
+
highlight: false,
|
|
117
|
+
},
|
|
118
|
+
],
|
|
119
|
+
|
|
120
|
+
// ── FAQ ────────────────────────────────────────────────────────────────────
|
|
121
|
+
faq: [
|
|
122
|
+
{
|
|
123
|
+
question: '¿Puedo cambiar de plan en cualquier momento?',
|
|
124
|
+
answer:
|
|
125
|
+
'Sí, podés upgradear o downgradear tu plan cuando quieras. Los cambios se aplican al próximo ciclo de facturación.',
|
|
126
|
+
},
|
|
127
|
+
{
|
|
128
|
+
question: '¿Qué métodos de pago aceptan?',
|
|
129
|
+
answer:
|
|
130
|
+
'Aceptamos tarjetas de crédito y débito (Visa, Mastercard, Amex) y transferencias bancarias para planes Enterprise.',
|
|
131
|
+
},
|
|
132
|
+
{
|
|
133
|
+
question: '¿Hay un período de prueba gratuito?',
|
|
134
|
+
answer:
|
|
135
|
+
'El plan Free está disponible sin límite de tiempo. Los planes pagos incluyen 14 días de prueba sin necesidad de tarjeta.',
|
|
136
|
+
},
|
|
137
|
+
{
|
|
138
|
+
question: '¿Cómo es la seguridad de mis datos?',
|
|
139
|
+
answer:
|
|
140
|
+
'Todos los datos se almacenan encriptados en reposo y en tránsito. Cumplimos con los estándares de seguridad más exigentes.',
|
|
141
|
+
},
|
|
142
|
+
{
|
|
143
|
+
question: '¿Puedo cancelar en cualquier momento?',
|
|
144
|
+
answer:
|
|
145
|
+
'Sí, sin penalidades ni cargos adicionales. Si cancelás, seguís teniendo acceso hasta el fin del período pagado.',
|
|
146
|
+
},
|
|
147
|
+
{
|
|
148
|
+
question: '¿Tienen soporte en español?',
|
|
149
|
+
answer: 'Sí, todo nuestro soporte es en español. Respondemos dentro de las 24 horas hábiles.',
|
|
150
|
+
},
|
|
151
|
+
],
|
|
152
|
+
|
|
153
|
+
// ── Footer ─────────────────────────────────────────────────────────────────
|
|
154
|
+
footer: {
|
|
155
|
+
columns: [
|
|
156
|
+
{
|
|
157
|
+
title: 'Producto',
|
|
158
|
+
links: [
|
|
159
|
+
{ label: 'Funcionalidades', href: '#features' },
|
|
160
|
+
{ label: 'Precios', href: '#pricing' },
|
|
161
|
+
{ label: 'FAQ', href: '#faq' },
|
|
162
|
+
{ label: 'Changelog', href: '#' },
|
|
163
|
+
],
|
|
164
|
+
},
|
|
165
|
+
{
|
|
166
|
+
title: 'Legal',
|
|
167
|
+
links: [
|
|
168
|
+
{ label: 'Términos y condiciones', href: '/terms' },
|
|
169
|
+
{ label: 'Política de privacidad', href: '/privacy' },
|
|
170
|
+
],
|
|
171
|
+
},
|
|
172
|
+
{
|
|
173
|
+
title: 'Soporte',
|
|
174
|
+
links: [
|
|
175
|
+
{ label: 'Contacto', href: 'mailto:__SUPPORT_EMAIL__' },
|
|
176
|
+
{ label: 'Documentación', href: '#' },
|
|
177
|
+
{ label: 'Estado del servicio', href: '#' },
|
|
178
|
+
],
|
|
179
|
+
},
|
|
180
|
+
],
|
|
181
|
+
social: {
|
|
182
|
+
twitter: '',
|
|
183
|
+
github: '',
|
|
184
|
+
linkedin: '',
|
|
185
|
+
},
|
|
186
|
+
copyright: '© 2024 __SITE_NAME__. Todos los derechos reservados.',
|
|
187
|
+
},
|
|
188
|
+
|
|
189
|
+
// ── Legal ──────────────────────────────────────────────────────────────────
|
|
190
|
+
legal: {
|
|
191
|
+
companyName: '__SITE_NAME__',
|
|
192
|
+
email: '__SUPPORT_EMAIL__',
|
|
193
|
+
lastUpdated: '1 de enero de 2024',
|
|
194
|
+
},
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
export type SiteConfig = typeof siteConfig
|
package/dist/license.js
DELETED
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.validateLicense = validateLicense;
|
|
7
|
-
const fs_1 = __importDefault(require("fs"));
|
|
8
|
-
const path_1 = __importDefault(require("path"));
|
|
9
|
-
const os_1 = __importDefault(require("os"));
|
|
10
|
-
const CACHE_DIR = path_1.default.join(os_1.default.homedir(), '.ar-saas');
|
|
11
|
-
const CACHE_FILE = path_1.default.join(CACHE_DIR, 'license');
|
|
12
|
-
const LICENSE_API = 'https://api.create-saas-ar.dev/licenses/validate';
|
|
13
|
-
const LICENSE_REGEX = /^CSAR-[A-Z0-9]{4}-[A-Z0-9]{4}-[A-Z0-9]{4}$/;
|
|
14
|
-
async function validateLicense(license) {
|
|
15
|
-
const normalized = license.trim().toUpperCase();
|
|
16
|
-
if (!LICENSE_REGEX.test(normalized)) {
|
|
17
|
-
return {
|
|
18
|
-
valid: false,
|
|
19
|
-
error: 'Formato inválido. La licencia debe tener el formato CSAR-XXXX-XXXX-XXXX',
|
|
20
|
-
};
|
|
21
|
-
}
|
|
22
|
-
const cached = readCache();
|
|
23
|
-
if (cached === normalized) {
|
|
24
|
-
return { valid: true };
|
|
25
|
-
}
|
|
26
|
-
try {
|
|
27
|
-
const controller = new AbortController();
|
|
28
|
-
const timeout = setTimeout(() => controller.abort(), 5000);
|
|
29
|
-
const response = await fetch(LICENSE_API, {
|
|
30
|
-
method: 'POST',
|
|
31
|
-
headers: { 'Content-Type': 'application/json' },
|
|
32
|
-
body: JSON.stringify({ license: normalized }),
|
|
33
|
-
signal: controller.signal,
|
|
34
|
-
});
|
|
35
|
-
clearTimeout(timeout);
|
|
36
|
-
if (!response.ok) {
|
|
37
|
-
return { valid: false, error: 'Licencia inválida o expirada' };
|
|
38
|
-
}
|
|
39
|
-
const data = (await response.json());
|
|
40
|
-
if (data.valid) {
|
|
41
|
-
writeCache(normalized);
|
|
42
|
-
return { valid: true };
|
|
43
|
-
}
|
|
44
|
-
return { valid: false, error: 'Licencia inválida o expirada' };
|
|
45
|
-
}
|
|
46
|
-
catch {
|
|
47
|
-
// Fail open: si la API no está disponible, aceptar la licencia
|
|
48
|
-
writeCache(normalized);
|
|
49
|
-
return { valid: true };
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
function readCache() {
|
|
53
|
-
try {
|
|
54
|
-
if (fs_1.default.existsSync(CACHE_FILE)) {
|
|
55
|
-
return fs_1.default.readFileSync(CACHE_FILE, 'utf-8').trim();
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
catch {
|
|
59
|
-
// ignore
|
|
60
|
-
}
|
|
61
|
-
return null;
|
|
62
|
-
}
|
|
63
|
-
function writeCache(license) {
|
|
64
|
-
try {
|
|
65
|
-
fs_1.default.mkdirSync(CACHE_DIR, { recursive: true });
|
|
66
|
-
fs_1.default.writeFileSync(CACHE_FILE, license, 'utf-8');
|
|
67
|
-
}
|
|
68
|
-
catch {
|
|
69
|
-
// ignore — no bloquear al usuario si no se puede escribir la caché
|
|
70
|
-
}
|
|
71
|
-
}
|