@salas-ds/cli 0.1.0 → 0.2.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/dist/index.js +253 -86
- package/package.json +4 -5
- package/templates/angular/accordion/accordion-content.component.ts +9 -0
- package/templates/angular/accordion/accordion-item.component.ts +138 -0
- package/templates/angular/accordion/accordion-trigger.component.ts +9 -0
- package/templates/angular/accordion/accordion.component.ts +120 -0
- package/templates/angular/accordion/accordion.module.ts +21 -0
- package/templates/angular/autocomplete/autocomplete.component.ts +707 -0
- package/templates/angular/autocomplete/autocomplete.module.ts +8 -0
- package/templates/angular/avatar/avatar-badge.component.ts +18 -0
- package/templates/angular/avatar/avatar-fallback.component.ts +39 -0
- package/templates/angular/avatar/avatar-group-count.component.ts +46 -0
- package/templates/angular/avatar/avatar-group.component.ts +33 -0
- package/templates/angular/avatar/avatar-image.component.ts +57 -0
- package/templates/angular/avatar/avatar.component.ts +73 -0
- package/templates/angular/avatar/avatar.module.ts +27 -0
- package/templates/angular/badge/badge.component.ts +84 -0
- package/templates/angular/badge/badge.module.ts +9 -0
- package/templates/angular/button/button.component.ts +24 -4
- package/templates/angular/card/card.component.ts +100 -0
- package/templates/angular/card/card.module.ts +8 -0
- package/templates/angular/checkbox/checkbox.component.ts +172 -0
- package/templates/angular/checkbox/checkbox.module.ts +8 -0
- package/templates/angular/datepicker/datepicker.component.ts +660 -0
- package/templates/angular/datepicker/datepicker.module.ts +8 -0
- package/templates/angular/dialog/dialog-content.component.ts +9 -0
- package/templates/angular/dialog/dialog-description.component.ts +17 -0
- package/templates/angular/dialog/dialog-footer.component.ts +17 -0
- package/templates/angular/dialog/dialog-header.component.ts +14 -0
- package/templates/angular/dialog/dialog-title.component.ts +18 -0
- package/templates/angular/dialog/dialog-trigger.component.ts +9 -0
- package/templates/angular/dialog/dialog.component.ts +212 -0
- package/templates/angular/dialog/dialog.module.ts +31 -0
- package/templates/angular/input/input.component.ts +229 -0
- package/templates/angular/input/input.module.ts +8 -0
- package/templates/angular/scroll-area/scroll-area.component.ts +72 -0
- package/templates/angular/scroll-area/scroll-area.module.ts +9 -0
- package/templates/angular/scroll-area/scroll-bar.component.ts +15 -0
- package/templates/angular/select/select.component.ts +292 -0
- package/templates/angular/select/select.module.ts +8 -0
- package/templates/angular/separator/separator.component.ts +63 -0
- package/templates/angular/separator/separator.module.ts +9 -0
- package/templates/angular/sheet/sheet-content.component.ts +13 -0
- package/templates/angular/sheet/sheet-description.component.ts +29 -0
- package/templates/angular/sheet/sheet-footer.component.ts +27 -0
- package/templates/angular/sheet/sheet-header.component.ts +26 -0
- package/templates/angular/sheet/sheet-title.component.ts +31 -0
- package/templates/angular/sheet/sheet-trigger.component.ts +11 -0
- package/templates/angular/sheet/sheet.component.ts +251 -0
- package/templates/angular/sheet/sheet.module.ts +30 -0
- package/templates/angular/sidebar/sidebar-content.component.ts +18 -0
- package/templates/angular/sidebar/sidebar-footer.component.ts +20 -0
- package/templates/angular/sidebar/sidebar-group-content.component.ts +16 -0
- package/templates/angular/sidebar/sidebar-group-label.component.ts +20 -0
- package/templates/angular/sidebar/sidebar-group.component.ts +14 -0
- package/templates/angular/sidebar/sidebar-header.component.ts +20 -0
- package/templates/angular/sidebar/sidebar-inset.component.ts +85 -0
- package/templates/angular/sidebar/sidebar-menu-button.component.ts +75 -0
- package/templates/angular/sidebar/sidebar-menu-item.component.ts +14 -0
- package/templates/angular/sidebar/sidebar-menu.component.ts +19 -0
- package/templates/angular/sidebar/sidebar-provider.component.ts +68 -0
- package/templates/angular/sidebar/sidebar-trigger.component.ts +58 -0
- package/templates/angular/sidebar/sidebar.component.ts +196 -0
- package/templates/angular/sidebar/sidebar.module.ts +48 -0
- package/templates/angular/sidebar/sidebar.service.ts +93 -0
- package/templates/angular/skeleton/skeleton.component.ts +44 -0
- package/templates/angular/skeleton/skeleton.module.ts +8 -0
- package/templates/angular/spinner/spinner.component.ts +75 -0
- package/templates/angular/spinner/spinner.module.ts +8 -0
- package/templates/angular/table/table-body.component.ts +23 -0
- package/templates/angular/table/table-caption.component.ts +29 -0
- package/templates/angular/table/table-cell.component.ts +49 -0
- package/templates/angular/table/table-footer.component.ts +32 -0
- package/templates/angular/table/table-head.component.ts +48 -0
- package/templates/angular/table/table-header.component.ts +28 -0
- package/templates/angular/table/table-row.component.ts +36 -0
- package/templates/angular/table/table.component.ts +35 -0
- package/templates/angular/table/table.module.ts +33 -0
- package/templates/angular/tabs/tabs-content.component.ts +71 -0
- package/templates/angular/tabs/tabs-list.component.ts +70 -0
- package/templates/angular/tabs/tabs-trigger.component.ts +149 -0
- package/templates/angular/tabs/tabs.component.ts +155 -0
- package/templates/angular/tabs/tabs.module.ts +21 -0
- package/templates/angular/textarea/textarea.component.ts +268 -0
- package/templates/angular/textarea/textarea.module.ts +8 -0
- package/templates/angular/toast/toast.module.ts +8 -0
- package/templates/angular/toast/toast.service.ts +104 -0
- package/templates/angular/toast/toaster.component.ts +329 -0
- package/templates/angular/tooltip/tooltip-content.component.ts +43 -0
- package/templates/angular/tooltip/tooltip-trigger.component.ts +13 -0
- package/templates/angular/tooltip/tooltip.component.ts +243 -0
- package/templates/angular/tooltip/tooltip.module.ts +10 -0
package/dist/index.js
CHANGED
|
@@ -5,7 +5,6 @@ import fs2 from 'fs-extra';
|
|
|
5
5
|
import path2 from 'path';
|
|
6
6
|
import { fileURLToPath } from 'url';
|
|
7
7
|
import { glob } from 'glob';
|
|
8
|
-
import inquirer from 'inquirer';
|
|
9
8
|
|
|
10
9
|
// src/index.ts
|
|
11
10
|
|
|
@@ -175,118 +174,286 @@ var THEME_CSS = `/* Salas Design System - Light & Dark theme */
|
|
|
175
174
|
[data-theme="dark"] .salas-autocomplete-loading { color: var(--salas-text-muted); }
|
|
176
175
|
`;
|
|
177
176
|
|
|
177
|
+
// src/utils-template.ts
|
|
178
|
+
var UTILS_TS = `/**
|
|
179
|
+
* Salas Design System - Utility functions
|
|
180
|
+
* Generated by @salas-ds/cli
|
|
181
|
+
*/
|
|
182
|
+
|
|
183
|
+
export const cn = (...classes: (string | undefined | null | false)[]): string => {
|
|
184
|
+
return classes.filter(Boolean).join(' ');
|
|
185
|
+
};
|
|
186
|
+
|
|
187
|
+
export const isEqual = <T>(a: T, b: T): boolean => {
|
|
188
|
+
if (Object.is(a, b)) return true;
|
|
189
|
+
if (typeof a !== 'object' || typeof b !== 'object' || a === null || b === null) {
|
|
190
|
+
return false;
|
|
191
|
+
}
|
|
192
|
+
const keysA = Object.keys(a);
|
|
193
|
+
const keysB = Object.keys(b);
|
|
194
|
+
if (keysA.length !== keysB.length) return false;
|
|
195
|
+
for (const key of keysA) {
|
|
196
|
+
if (!keysB.includes(key)) return false;
|
|
197
|
+
if (!isEqual((a as any)[key], (b as any)[key])) return false;
|
|
198
|
+
}
|
|
199
|
+
return true;
|
|
200
|
+
};
|
|
201
|
+
|
|
202
|
+
export const debounce = <T extends (...args: any[]) => any>(
|
|
203
|
+
func: T,
|
|
204
|
+
wait: number
|
|
205
|
+
): ((...args: Parameters<T>) => void) => {
|
|
206
|
+
let timeout: ReturnType<typeof setTimeout> | null = null;
|
|
207
|
+
return (...args: Parameters<T>) => {
|
|
208
|
+
if (timeout) clearTimeout(timeout);
|
|
209
|
+
timeout = setTimeout(() => func(...args), wait);
|
|
210
|
+
};
|
|
211
|
+
};
|
|
212
|
+
|
|
213
|
+
export const throttle = <T extends (...args: any[]) => any>(
|
|
214
|
+
func: T,
|
|
215
|
+
limit: number
|
|
216
|
+
): ((...args: Parameters<T>) => void) => {
|
|
217
|
+
let inThrottle: boolean;
|
|
218
|
+
return (...args: Parameters<T>) => {
|
|
219
|
+
if (!inThrottle) {
|
|
220
|
+
func(...args);
|
|
221
|
+
inThrottle = true;
|
|
222
|
+
setTimeout(() => (inThrottle = false), limit);
|
|
223
|
+
}
|
|
224
|
+
};
|
|
225
|
+
};
|
|
226
|
+
`;
|
|
227
|
+
|
|
178
228
|
// src/commands/init.ts
|
|
179
|
-
var
|
|
180
|
-
path2.dirname(__filename$1);
|
|
229
|
+
var CONFIG_FILE = "salas-ds.json";
|
|
181
230
|
async function initCommand(options) {
|
|
182
231
|
console.log(chalk2.blue("\u{1F680} Inicializando Salas Design System...\n"));
|
|
183
232
|
const projectRoot = process.cwd();
|
|
184
233
|
const componentsPath = path2.join(projectRoot, options.path);
|
|
185
234
|
try {
|
|
235
|
+
const angularJsonPath = path2.join(projectRoot, "angular.json");
|
|
236
|
+
const isAngular = await fs2.pathExists(angularJsonPath);
|
|
237
|
+
if (!isAngular) {
|
|
238
|
+
console.error(chalk2.red("\u274C Projeto Angular n\xE3o detectado (angular.json n\xE3o encontrado)."));
|
|
239
|
+
console.log(chalk2.gray("Execute este comando na raiz de um projeto Angular."));
|
|
240
|
+
process.exit(1);
|
|
241
|
+
}
|
|
186
242
|
await fs2.ensureDir(componentsPath);
|
|
243
|
+
const config = {
|
|
244
|
+
$schema: "https://salas-ds.dev/schema.json",
|
|
245
|
+
framework: options.framework,
|
|
246
|
+
componentsDir: options.path,
|
|
247
|
+
utils: `${options.path}/utils.ts`,
|
|
248
|
+
styles: `${options.path}/styles.css`
|
|
249
|
+
};
|
|
250
|
+
await fs2.writeJSON(path2.join(projectRoot, CONFIG_FILE), config, { spaces: 2 });
|
|
187
251
|
const cssPath = path2.join(componentsPath, "styles.css");
|
|
188
252
|
await fs2.writeFile(cssPath, THEME_CSS);
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
console.log(chalk2.
|
|
253
|
+
const utilsPath = path2.join(componentsPath, "utils.ts");
|
|
254
|
+
await fs2.writeFile(utilsPath, UTILS_TS);
|
|
255
|
+
console.log(chalk2.green("\u2705 Salas Design System inicializado com sucesso!\n"));
|
|
256
|
+
console.log(chalk2.gray("Arquivos criados:"));
|
|
257
|
+
console.log(chalk2.gray(` ${CONFIG_FILE}`));
|
|
258
|
+
console.log(chalk2.gray(` ${options.path}/styles.css`));
|
|
259
|
+
console.log(chalk2.gray(` ${options.path}/utils.ts
|
|
192
260
|
`));
|
|
193
261
|
console.log(chalk2.blue("\u{1F4A1} Pr\xF3ximos passos:"));
|
|
194
|
-
console.log(chalk2.gray(`
|
|
195
|
-
console.log(chalk2.
|
|
262
|
+
console.log(chalk2.gray(` 1. Importe o CSS no seu styles.css ou angular.json:`));
|
|
263
|
+
console.log(chalk2.white(` @import './${options.path}/styles.css';`));
|
|
264
|
+
console.log(chalk2.gray(`
|
|
265
|
+
2. Adicione componentes:`));
|
|
266
|
+
console.log(chalk2.white(` npx @salas-ds/cli add button`));
|
|
267
|
+
console.log(chalk2.white(` npx @salas-ds/cli add input`));
|
|
268
|
+
console.log(chalk2.white(` npx @salas-ds/cli add --all`));
|
|
269
|
+
console.log(chalk2.gray(`
|
|
270
|
+
3. Componentes dispon\xEDveis:`));
|
|
271
|
+
console.log(chalk2.gray(` accordion, autocomplete, avatar, badge, button, card,`));
|
|
272
|
+
console.log(chalk2.gray(` checkbox, datepicker, dialog, input, scroll-area, select,`));
|
|
273
|
+
console.log(chalk2.gray(` separator, sheet, sidebar, skeleton, spinner, table,`));
|
|
274
|
+
console.log(chalk2.gray(` tabs, textarea, toast, tooltip`));
|
|
196
275
|
} catch (error) {
|
|
197
276
|
console.error(chalk2.red("\u274C Erro ao inicializar:"), error);
|
|
198
277
|
process.exit(1);
|
|
199
278
|
}
|
|
200
279
|
}
|
|
201
|
-
var
|
|
202
|
-
var
|
|
203
|
-
var COMPONENTS = [
|
|
204
|
-
|
|
280
|
+
var __filename$1 = fileURLToPath(import.meta.url);
|
|
281
|
+
var __dirname$1 = path2.dirname(__filename$1);
|
|
282
|
+
var COMPONENTS = [
|
|
283
|
+
"accordion",
|
|
284
|
+
"autocomplete",
|
|
285
|
+
"avatar",
|
|
286
|
+
"badge",
|
|
287
|
+
"button",
|
|
288
|
+
"card",
|
|
289
|
+
"checkbox",
|
|
290
|
+
"datepicker",
|
|
291
|
+
"dialog",
|
|
292
|
+
"input",
|
|
293
|
+
"scroll-area",
|
|
294
|
+
"select",
|
|
295
|
+
"separator",
|
|
296
|
+
"sheet",
|
|
297
|
+
"sidebar",
|
|
298
|
+
"skeleton",
|
|
299
|
+
"spinner",
|
|
300
|
+
"table",
|
|
301
|
+
"tabs",
|
|
302
|
+
"textarea",
|
|
303
|
+
"toast",
|
|
304
|
+
"tooltip"
|
|
305
|
+
];
|
|
306
|
+
var LUCIDE_COMPONENTS = ["autocomplete", "datepicker", "input", "select", "textarea"];
|
|
307
|
+
var CONFIG_FILE2 = "salas-ds.json";
|
|
308
|
+
function toPascalCase(str) {
|
|
309
|
+
return str.split("-").map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join("");
|
|
310
|
+
}
|
|
311
|
+
async function readConfig() {
|
|
312
|
+
const projectRoot = process.cwd();
|
|
313
|
+
const configPath = path2.join(projectRoot, CONFIG_FILE2);
|
|
314
|
+
if (!await fs2.pathExists(configPath)) {
|
|
315
|
+
return null;
|
|
316
|
+
}
|
|
317
|
+
return fs2.readJSON(configPath);
|
|
318
|
+
}
|
|
319
|
+
async function addSingleComponent(componentName, componentsDir, options) {
|
|
320
|
+
const projectRoot = process.cwd();
|
|
321
|
+
const componentPath = path2.join(projectRoot, componentsDir, componentName);
|
|
322
|
+
if (await fs2.pathExists(componentPath)) {
|
|
323
|
+
if (!options.overwrite) {
|
|
324
|
+
console.log(chalk2.yellow(` \u26A0 ${componentName} j\xE1 existe. Use --overwrite para substituir.`));
|
|
325
|
+
return false;
|
|
326
|
+
}
|
|
327
|
+
await fs2.remove(componentPath);
|
|
328
|
+
}
|
|
329
|
+
await fs2.ensureDir(componentPath);
|
|
330
|
+
const templatePath = path2.join(__dirname$1, "..", "templates", "angular", componentName);
|
|
331
|
+
if (!await fs2.pathExists(templatePath)) {
|
|
332
|
+
console.error(chalk2.red(` \u274C Template n\xE3o encontrado para: ${componentName}`));
|
|
333
|
+
return false;
|
|
334
|
+
}
|
|
335
|
+
const templateFiles = await glob("**/*", {
|
|
336
|
+
cwd: templatePath,
|
|
337
|
+
dot: false,
|
|
338
|
+
nodir: true
|
|
339
|
+
});
|
|
340
|
+
for (const file of templateFiles) {
|
|
341
|
+
const srcPath = path2.join(templatePath, file);
|
|
342
|
+
const destPath = path2.join(componentPath, file);
|
|
343
|
+
await fs2.ensureDir(path2.dirname(destPath));
|
|
344
|
+
await fs2.copyFile(srcPath, destPath);
|
|
345
|
+
}
|
|
346
|
+
return true;
|
|
347
|
+
}
|
|
205
348
|
async function addCommand(componentName, options) {
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
);
|
|
210
|
-
console.log(chalk2.gray(`Componentes dispon\xEDveis: ${COMPONENTS.join(", ")}`));
|
|
349
|
+
const config = await readConfig();
|
|
350
|
+
if (!config) {
|
|
351
|
+
console.error(chalk2.red("\u274C Projeto n\xE3o inicializado."));
|
|
352
|
+
console.log(chalk2.gray("Execute primeiro: npx @salas-ds/cli init"));
|
|
211
353
|
process.exit(1);
|
|
212
354
|
}
|
|
213
|
-
|
|
355
|
+
const componentsDir = options.path ?? config.componentsDir;
|
|
356
|
+
const componentsToAdd = [];
|
|
357
|
+
if (options.all) {
|
|
358
|
+
componentsToAdd.push(...COMPONENTS);
|
|
359
|
+
console.log(chalk2.blue(`\u{1F4E6} Adicionando todos os ${COMPONENTS.length} componentes...
|
|
214
360
|
`));
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
default: defaultPath,
|
|
222
|
-
transformer: (input) => input.trim() || defaultPath
|
|
223
|
-
}
|
|
224
|
-
]);
|
|
225
|
-
const basePath = (chosenPath || defaultPath).trim();
|
|
226
|
-
const projectRoot = process.cwd();
|
|
227
|
-
const componentsPath = path2.join(projectRoot, basePath);
|
|
228
|
-
const componentPath = path2.join(componentsPath, componentName);
|
|
229
|
-
try {
|
|
230
|
-
const angularJsonPath = path2.join(projectRoot, "angular.json");
|
|
231
|
-
const isAngular = await fs2.pathExists(angularJsonPath);
|
|
232
|
-
if (!isAngular) {
|
|
233
|
-
console.error(chalk2.red("\u274C Projeto Angular n\xE3o detectado."));
|
|
234
|
-
console.log(chalk2.gray("Execute este comando em um projeto Angular."));
|
|
235
|
-
process.exit(1);
|
|
236
|
-
}
|
|
237
|
-
await fs2.ensureDir(componentPath);
|
|
238
|
-
const templatePath = path2.join(
|
|
239
|
-
__dirname2,
|
|
240
|
-
"..",
|
|
241
|
-
"..",
|
|
242
|
-
"templates",
|
|
243
|
-
"angular",
|
|
244
|
-
componentName
|
|
245
|
-
);
|
|
246
|
-
if (!await fs2.pathExists(templatePath)) {
|
|
247
|
-
console.error(chalk2.red(`\u274C Template n\xE3o encontrado para: ${componentName}`));
|
|
361
|
+
} else if (componentName) {
|
|
362
|
+
if (!COMPONENTS.includes(componentName)) {
|
|
363
|
+
console.error(chalk2.red(`\u274C Componente "${componentName}" n\xE3o encontrado.`));
|
|
364
|
+
console.log(chalk2.gray(`
|
|
365
|
+
Componentes dispon\xEDveis:`));
|
|
366
|
+
console.log(chalk2.gray(` ${COMPONENTS.join(", ")}`));
|
|
248
367
|
process.exit(1);
|
|
249
368
|
}
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
dot: false,
|
|
253
|
-
ignore: ["node_modules/**"]
|
|
254
|
-
});
|
|
255
|
-
for (const file of templateFiles) {
|
|
256
|
-
const srcPath = path2.join(templatePath, file);
|
|
257
|
-
const destPath = path2.join(componentPath, file);
|
|
258
|
-
await fs2.ensureDir(path2.dirname(destPath));
|
|
259
|
-
let content = await fs2.readFile(srcPath, "utf-8");
|
|
260
|
-
content = content.replace(/{{COMPONENT_NAME}}/g, componentName);
|
|
261
|
-
content = content.replace(/{{COMPONENT_CLASS}}/g, toPascalCase(componentName));
|
|
262
|
-
await fs2.writeFile(destPath, content);
|
|
263
|
-
}
|
|
264
|
-
const relativePath = path2.relative(projectRoot, componentPath);
|
|
265
|
-
console.log(chalk2.green(`\u2705 Componente ${componentName} adicionado com sucesso!`));
|
|
266
|
-
console.log(chalk2.gray(` Localiza\xE7\xE3o: ${relativePath}
|
|
369
|
+
componentsToAdd.push(componentName);
|
|
370
|
+
console.log(chalk2.blue(`\u{1F4E6} Adicionando componente: ${componentName}
|
|
267
371
|
`));
|
|
268
|
-
|
|
269
|
-
console.
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
)
|
|
275
|
-
);
|
|
276
|
-
console.log(chalk2.gray(` 2. Use no template:`));
|
|
277
|
-
console.log(chalk2.gray(` <salas-${componentName}></salas-${componentName}>`));
|
|
278
|
-
} catch (error) {
|
|
279
|
-
console.error(chalk2.red("\u274C Erro ao adicionar componente:"), error);
|
|
372
|
+
} else {
|
|
373
|
+
console.error(chalk2.red("\u274C Especifique um componente ou use --all."));
|
|
374
|
+
console.log(chalk2.gray(`
|
|
375
|
+
Exemplos:`));
|
|
376
|
+
console.log(chalk2.gray(` npx @salas-ds/cli add button`));
|
|
377
|
+
console.log(chalk2.gray(` npx @salas-ds/cli add --all`));
|
|
280
378
|
process.exit(1);
|
|
281
379
|
}
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
380
|
+
const added = [];
|
|
381
|
+
const needsLucide = /* @__PURE__ */ new Set();
|
|
382
|
+
for (const name of componentsToAdd) {
|
|
383
|
+
const success = await addSingleComponent(name, componentsDir, options);
|
|
384
|
+
if (success) {
|
|
385
|
+
added.push(name);
|
|
386
|
+
if (LUCIDE_COMPONENTS.includes(name)) {
|
|
387
|
+
needsLucide.add(name);
|
|
388
|
+
}
|
|
389
|
+
console.log(chalk2.green(` \u2713 ${name}`));
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
if (added.length === 0) {
|
|
393
|
+
console.log(chalk2.yellow("\nNenhum componente adicionado."));
|
|
394
|
+
return;
|
|
395
|
+
}
|
|
396
|
+
process.cwd();
|
|
397
|
+
console.log(chalk2.green(`
|
|
398
|
+
\u2705 ${added.length} componente(s) adicionado(s) com sucesso!`));
|
|
399
|
+
console.log(chalk2.gray(` Localiza\xE7\xE3o: ${componentsDir}/
|
|
400
|
+
`));
|
|
401
|
+
if (needsLucide.size > 0) {
|
|
402
|
+
console.log(chalk2.yellow("\u26A0 Os seguintes componentes precisam do lucide-angular:"));
|
|
403
|
+
console.log(chalk2.gray(` ${[...needsLucide].join(", ")}`));
|
|
404
|
+
console.log(chalk2.gray(` Instale com: npm install lucide-angular
|
|
405
|
+
`));
|
|
406
|
+
}
|
|
407
|
+
console.log(chalk2.blue("\u{1F4A1} Como usar:"));
|
|
408
|
+
const example = added[0];
|
|
409
|
+
const exampleClass = `Salas${toPascalCase(example)}Component`;
|
|
410
|
+
const relPath = `./${path2.join(componentsDir, example, example).replace(/\\/g, "/")}`;
|
|
411
|
+
console.log(chalk2.gray(` // Standalone component:`));
|
|
412
|
+
console.log(chalk2.white(` import { ${exampleClass} } from '${relPath}.component';`));
|
|
413
|
+
console.log(chalk2.gray(`
|
|
414
|
+
// Ou via module:`));
|
|
415
|
+
console.log(chalk2.white(` import { Salas${toPascalCase(example)}Module } from '${relPath}.module';`));
|
|
285
416
|
}
|
|
286
417
|
|
|
287
418
|
// src/index.ts
|
|
288
419
|
var program = new Command();
|
|
289
|
-
program.name("salas-ds").description("CLI para adicionar componentes do Salas Design System").version("0.1.0");
|
|
290
|
-
program.command("init").description("Inicializa o Salas Design System no projeto").option("-f, --framework <framework>", "Framework (angular)", "angular").option("-p, --path <path>", "Caminho para componentes", "src/
|
|
291
|
-
program.command("add").description("Adiciona um componente ao projeto").
|
|
420
|
+
program.name("salas-ds").description("CLI para adicionar componentes do Salas Design System ao seu projeto Angular (estilo shadcn)").version("0.1.0");
|
|
421
|
+
program.command("init").description("Inicializa o Salas Design System no projeto").option("-f, --framework <framework>", "Framework (angular)", "angular").option("-p, --path <path>", "Caminho para componentes", "src/components/ui").action(initCommand);
|
|
422
|
+
program.command("add [component]").description("Adiciona um componente ao projeto").option("-p, --path <path>", "Pasta onde os componentes ser\xE3o criados").option("-a, --all", "Adiciona todos os componentes").option("--overwrite", "Sobrescreve componentes existentes").action(addCommand);
|
|
423
|
+
program.command("list").description("Lista todos os componentes dispon\xEDveis").action(() => {
|
|
424
|
+
const components = [
|
|
425
|
+
"accordion",
|
|
426
|
+
"autocomplete",
|
|
427
|
+
"avatar",
|
|
428
|
+
"badge",
|
|
429
|
+
"button",
|
|
430
|
+
"card",
|
|
431
|
+
"checkbox",
|
|
432
|
+
"datepicker",
|
|
433
|
+
"dialog",
|
|
434
|
+
"input",
|
|
435
|
+
"scroll-area",
|
|
436
|
+
"select",
|
|
437
|
+
"separator",
|
|
438
|
+
"sheet",
|
|
439
|
+
"sidebar",
|
|
440
|
+
"skeleton",
|
|
441
|
+
"spinner",
|
|
442
|
+
"table",
|
|
443
|
+
"tabs",
|
|
444
|
+
"textarea",
|
|
445
|
+
"toast",
|
|
446
|
+
"tooltip"
|
|
447
|
+
];
|
|
448
|
+
console.log(chalk2.blue("\n\u{1F4E6} Componentes dispon\xEDveis:\n"));
|
|
449
|
+
for (const c of components) {
|
|
450
|
+
console.log(chalk2.gray(` \u2022 ${c}`));
|
|
451
|
+
}
|
|
452
|
+
console.log(chalk2.gray(`
|
|
453
|
+
Total: ${components.length} componentes`));
|
|
454
|
+
console.log(chalk2.gray(`
|
|
455
|
+
Uso: npx @salas-ds/cli add <componente>`));
|
|
456
|
+
console.log(chalk2.gray(` npx @salas-ds/cli add --all
|
|
457
|
+
`));
|
|
458
|
+
});
|
|
292
459
|
program.parse();
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@salas-ds/cli",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "CLI para adicionar componentes do Salas Design System ao projeto",
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "CLI para adicionar componentes do Salas Design System ao projeto (estilo shadcn)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
7
|
"salas-ds": "./dist/index.js"
|
|
@@ -16,12 +16,10 @@
|
|
|
16
16
|
"chalk": "^5.3.0",
|
|
17
17
|
"fs-extra": "^11.2.0",
|
|
18
18
|
"glob": "^10.3.10",
|
|
19
|
-
"inquirer": "^9.2.12",
|
|
20
19
|
"prettier": "^3.2.0"
|
|
21
20
|
},
|
|
22
21
|
"devDependencies": {
|
|
23
22
|
"@types/fs-extra": "^11.0.4",
|
|
24
|
-
"@types/inquirer": "^9.0.7",
|
|
25
23
|
"@types/node": "^20.11.0",
|
|
26
24
|
"tsup": "^8.0.0",
|
|
27
25
|
"typescript": "~5.5.0"
|
|
@@ -35,7 +33,8 @@
|
|
|
35
33
|
"author": "",
|
|
36
34
|
"license": "MIT",
|
|
37
35
|
"scripts": {
|
|
38
|
-
"
|
|
36
|
+
"generate-templates": "node scripts/generate-templates.mjs",
|
|
37
|
+
"build": "node scripts/generate-templates.mjs && tsup",
|
|
39
38
|
"dev": "tsup --watch",
|
|
40
39
|
"clean": "rm -rf dist"
|
|
41
40
|
}
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import { Component, Input, Output, EventEmitter, ViewEncapsulation } from '@angular/core';
|
|
2
|
+
|
|
3
|
+
@Component({
|
|
4
|
+
selector: 'salas-accordion-item',
|
|
5
|
+
standalone: true,
|
|
6
|
+
imports: [],
|
|
7
|
+
encapsulation: ViewEncapsulation.None,
|
|
8
|
+
template: `
|
|
9
|
+
<div
|
|
10
|
+
class="salas-accordion-item"
|
|
11
|
+
[class.salas-accordion-item--disabled]="disabled"
|
|
12
|
+
>
|
|
13
|
+
<button
|
|
14
|
+
type="button"
|
|
15
|
+
class="salas-accordion-trigger"
|
|
16
|
+
[class.salas-accordion-trigger--open]="open"
|
|
17
|
+
[disabled]="disabled"
|
|
18
|
+
(click)="onTriggerClick()"
|
|
19
|
+
[attr.aria-expanded]="open"
|
|
20
|
+
>
|
|
21
|
+
<ng-content select="salas-accordion-trigger"></ng-content>
|
|
22
|
+
<svg
|
|
23
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
24
|
+
width="16"
|
|
25
|
+
height="16"
|
|
26
|
+
viewBox="0 0 24 24"
|
|
27
|
+
fill="none"
|
|
28
|
+
stroke="currentColor"
|
|
29
|
+
stroke-width="2"
|
|
30
|
+
stroke-linecap="round"
|
|
31
|
+
stroke-linejoin="round"
|
|
32
|
+
class="salas-accordion-trigger-icon"
|
|
33
|
+
[class.salas-accordion-trigger-icon--open]="open"
|
|
34
|
+
>
|
|
35
|
+
<path d="m6 9 6 6 6-6"/>
|
|
36
|
+
</svg>
|
|
37
|
+
</button>
|
|
38
|
+
<div
|
|
39
|
+
class="salas-accordion-content"
|
|
40
|
+
[class.salas-accordion-content--open]="open"
|
|
41
|
+
[attr.aria-hidden]="!open"
|
|
42
|
+
>
|
|
43
|
+
<div class="salas-accordion-content-inner">
|
|
44
|
+
<ng-content select="salas-accordion-content"></ng-content>
|
|
45
|
+
</div>
|
|
46
|
+
</div>
|
|
47
|
+
</div>
|
|
48
|
+
`,
|
|
49
|
+
styles: [`
|
|
50
|
+
.salas-accordion-item {
|
|
51
|
+
border-bottom: 1px solid var(--salas-gray-200);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
.salas-accordion-item:last-child {
|
|
55
|
+
border-bottom: none;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
.salas-accordion-item--disabled {
|
|
59
|
+
opacity: 0.5;
|
|
60
|
+
pointer-events: none;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
:host-context([data-theme="dark"]) .salas-accordion-item {
|
|
64
|
+
border-bottom-color: var(--salas-gray-800);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
.salas-accordion-trigger {
|
|
68
|
+
display: flex;
|
|
69
|
+
align-items: center;
|
|
70
|
+
justify-content: space-between;
|
|
71
|
+
width: 100%;
|
|
72
|
+
padding: 1rem 0;
|
|
73
|
+
font-size: 0.875rem;
|
|
74
|
+
font-weight: 500;
|
|
75
|
+
color: var(--salas-text);
|
|
76
|
+
background: none;
|
|
77
|
+
border: none;
|
|
78
|
+
cursor: pointer;
|
|
79
|
+
transition: color 0.2s;
|
|
80
|
+
text-align: left;
|
|
81
|
+
font-family: inherit;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
.salas-accordion-trigger:hover:not(:disabled) {
|
|
85
|
+
text-decoration: underline;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
.salas-accordion-trigger:disabled {
|
|
89
|
+
cursor: not-allowed;
|
|
90
|
+
opacity: 0.5;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
.salas-accordion-trigger-icon {
|
|
94
|
+
flex-shrink: 0;
|
|
95
|
+
width: 1rem;
|
|
96
|
+
height: 1rem;
|
|
97
|
+
transition: transform 0.2s ease;
|
|
98
|
+
color: var(--salas-text-muted);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
.salas-accordion-trigger-icon--open {
|
|
102
|
+
transform: rotate(180deg);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
.salas-accordion-content {
|
|
106
|
+
overflow: hidden;
|
|
107
|
+
max-height: 0;
|
|
108
|
+
opacity: 0;
|
|
109
|
+
transition: max-height 0.3s ease, opacity 0.2s ease;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
.salas-accordion-content--open {
|
|
113
|
+
max-height: 500px;
|
|
114
|
+
opacity: 1;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
.salas-accordion-content-inner {
|
|
118
|
+
padding-bottom: 1rem;
|
|
119
|
+
color: var(--salas-text-muted);
|
|
120
|
+
font-size: 0.875rem;
|
|
121
|
+
line-height: 1.5;
|
|
122
|
+
}
|
|
123
|
+
`],
|
|
124
|
+
})
|
|
125
|
+
export class SalasAccordionItemComponent {
|
|
126
|
+
@Input() value!: string;
|
|
127
|
+
@Input() disabled = false;
|
|
128
|
+
|
|
129
|
+
open = false;
|
|
130
|
+
|
|
131
|
+
@Output() toggled = new EventEmitter<string>();
|
|
132
|
+
|
|
133
|
+
onTriggerClick(): void {
|
|
134
|
+
if (!this.disabled) {
|
|
135
|
+
this.toggled.emit(this.value);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Component,
|
|
3
|
+
Input,
|
|
4
|
+
Output,
|
|
5
|
+
EventEmitter,
|
|
6
|
+
ContentChildren,
|
|
7
|
+
QueryList,
|
|
8
|
+
AfterContentInit,
|
|
9
|
+
OnDestroy,
|
|
10
|
+
ViewEncapsulation,
|
|
11
|
+
} from '@angular/core';
|
|
12
|
+
import { SalasAccordionItemComponent } from './accordion-item.component';
|
|
13
|
+
|
|
14
|
+
export type AccordionType = 'single' | 'multiple';
|
|
15
|
+
|
|
16
|
+
export interface AccordionProps {
|
|
17
|
+
type?: AccordionType;
|
|
18
|
+
collapsible?: boolean;
|
|
19
|
+
defaultValue?: string | string[];
|
|
20
|
+
value?: string | string[];
|
|
21
|
+
disabled?: boolean;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export interface AccordionItemProps {
|
|
25
|
+
value: string;
|
|
26
|
+
disabled?: boolean;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
@Component({
|
|
31
|
+
selector: 'salas-accordion',
|
|
32
|
+
standalone: true,
|
|
33
|
+
imports: [],
|
|
34
|
+
encapsulation: ViewEncapsulation.None,
|
|
35
|
+
template: `
|
|
36
|
+
<div class="salas-accordion">
|
|
37
|
+
<ng-content></ng-content>
|
|
38
|
+
</div>
|
|
39
|
+
`,
|
|
40
|
+
styles: [`
|
|
41
|
+
.salas-accordion {
|
|
42
|
+
display: flex;
|
|
43
|
+
flex-direction: column;
|
|
44
|
+
}
|
|
45
|
+
`],
|
|
46
|
+
})
|
|
47
|
+
export class SalasAccordionComponent implements AfterContentInit, OnDestroy {
|
|
48
|
+
@Input() type: AccordionType = 'single';
|
|
49
|
+
@Input() collapsible = true;
|
|
50
|
+
@Input() defaultValue?: string | string[];
|
|
51
|
+
@Input() disabled = false;
|
|
52
|
+
|
|
53
|
+
@Output() valueChange = new EventEmitter<string | string[] | undefined>();
|
|
54
|
+
|
|
55
|
+
@ContentChildren(SalasAccordionItemComponent) items!: QueryList<SalasAccordionItemComponent>;
|
|
56
|
+
|
|
57
|
+
private unsubscribes: Array<() => void> = [];
|
|
58
|
+
|
|
59
|
+
ngAfterContentInit(): void {
|
|
60
|
+
this.initItems();
|
|
61
|
+
|
|
62
|
+
this.items.changes.subscribe(() => {
|
|
63
|
+
this.clearSubscriptions();
|
|
64
|
+
this.initItems();
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
ngOnDestroy(): void {
|
|
69
|
+
this.clearSubscriptions();
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
private initItems(): void {
|
|
73
|
+
if (this.defaultValue) {
|
|
74
|
+
const defaults = Array.isArray(this.defaultValue)
|
|
75
|
+
? this.defaultValue
|
|
76
|
+
: [this.defaultValue];
|
|
77
|
+
this.items.forEach((item) => {
|
|
78
|
+
item.open = defaults.includes(item.value);
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
this.items.forEach((item) => {
|
|
83
|
+
const sub = item.toggled.subscribe((value: string) => {
|
|
84
|
+
this.handleToggle(item);
|
|
85
|
+
});
|
|
86
|
+
this.unsubscribes.push(() => sub.unsubscribe());
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
private handleToggle(toggledItem: SalasAccordionItemComponent): void {
|
|
91
|
+
if (this.type === 'single') {
|
|
92
|
+
const wasOpen = toggledItem.open;
|
|
93
|
+
this.items.forEach((item) => {
|
|
94
|
+
item.open = false;
|
|
95
|
+
});
|
|
96
|
+
toggledItem.open = this.collapsible ? !wasOpen : true;
|
|
97
|
+
} else {
|
|
98
|
+
toggledItem.open = !toggledItem.open;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
this.emitValue();
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
private emitValue(): void {
|
|
105
|
+
const openItems = this.items
|
|
106
|
+
.filter((item) => item.open)
|
|
107
|
+
.map((item) => item.value);
|
|
108
|
+
|
|
109
|
+
if (this.type === 'single') {
|
|
110
|
+
this.valueChange.emit(openItems[0] ?? undefined);
|
|
111
|
+
} else {
|
|
112
|
+
this.valueChange.emit(openItems.length > 0 ? openItems : undefined);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
private clearSubscriptions(): void {
|
|
117
|
+
this.unsubscribes.forEach((unsub) => unsub());
|
|
118
|
+
this.unsubscribes = [];
|
|
119
|
+
}
|
|
120
|
+
}
|