mirror of
https://github.com/hunvreus/basecoat.git
synced 2026-11-11 04:38:18 +00:00
Working on new packages structure
This commit is contained in:
+5
-6
@@ -2,11 +2,10 @@
|
||||
!.gitignore
|
||||
!.eleventy.js
|
||||
|
||||
/node_modules
|
||||
/_site
|
||||
|
||||
_site/
|
||||
node_modules/
|
||||
packages/cli/dist/
|
||||
packages/css/dist/
|
||||
|
||||
# Logs
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
npm-debug.log*
|
||||
@@ -364,6 +364,9 @@
|
||||
.block {
|
||||
display: block;
|
||||
}
|
||||
.contents {
|
||||
display: contents;
|
||||
}
|
||||
.flex {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
+8
-6
@@ -1,9 +1,10 @@
|
||||
{
|
||||
"name": "basecoat-ui",
|
||||
"version": "0.1.0",
|
||||
"name": "basecoat",
|
||||
"version": "0.0.1",
|
||||
"description": "shadcn/ui for the rest of us",
|
||||
"author": "hunvreus",
|
||||
"type": "module",
|
||||
"private": true,
|
||||
"workspaces": [
|
||||
"packages/*"
|
||||
],
|
||||
@@ -42,10 +43,11 @@
|
||||
},
|
||||
"homepage": "https://github.com/hunvreus/basecoat#readme",
|
||||
"scripts": {
|
||||
"css:dev": "tailwindcss -i ./docs/css/styles.css -o ./docs/src/assets/styles.css --watch",
|
||||
"eleventy:serve": "eleventy --serve",
|
||||
"dev": "concurrently \"npm:css:dev\" \"npm:eleventy:serve\"",
|
||||
"build": "tailwindcss -i ./docs/css/styles.css -o ./docs/src/assets/styles.css --minify && eleventy"
|
||||
"build": "node ./scripts/build.js",
|
||||
"docs:build": "tailwindcss -i ./docs/css/styles.css -o ./docs/src/assets/styles.css --minify && eleventy",
|
||||
"docs:dev:css": "tailwindcss -i ./docs/css/styles.css -o ./docs/src/assets/styles.css --watch",
|
||||
"docs:dev:eleventy": "eleventy --serve",
|
||||
"docs:dev": "concurrently \"npm:docs:dev:css\" \"npm:docs:dev:eleventy\""
|
||||
},
|
||||
"devDependencies": {
|
||||
"@11ty/eleventy": "^3.0.0",
|
||||
|
||||
+104
-103
@@ -1,24 +1,23 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
console.log('CLI starting...');
|
||||
|
||||
import { Command } from 'commander';
|
||||
import inquirer from 'inquirer';
|
||||
import fs from 'fs-extra';
|
||||
import path from 'path';
|
||||
|
||||
console.log('Imports loaded');
|
||||
import { fileURLToPath } from 'url';
|
||||
|
||||
const program = new Command();
|
||||
|
||||
// Attempt to read version from the CLI's own package.json
|
||||
let packageVersion = 'unknown';
|
||||
try {
|
||||
const cliScriptDir = path.dirname(new URL(import.meta.url).pathname);
|
||||
const packageJsonPath = path.resolve(cliScriptDir, 'package.json');
|
||||
const cliScriptRunningDir = path.dirname(fileURLToPath(import.meta.url)); // .../packages/cli/dist
|
||||
const cliPackageRootDir = path.resolve(cliScriptRunningDir, '..'); // .../packages/cli
|
||||
const packageJsonPath = path.join(cliPackageRootDir, 'package.json');
|
||||
const packageJsonContent = fs.readFileSync(packageJsonPath, 'utf8');
|
||||
packageVersion = JSON.parse(packageJsonContent).version;
|
||||
} catch (error) {
|
||||
console.warn('Could not read package version:', error.message);
|
||||
console.warn('Could not read CLI package version:', error.message);
|
||||
}
|
||||
|
||||
const DEFAULT_CONFIG = {
|
||||
@@ -26,28 +25,28 @@ const DEFAULT_CONFIG = {
|
||||
templateDest: './components/basecoat',
|
||||
scriptDest: './static/js/basecoat'
|
||||
};
|
||||
let config = { ...DEFAULT_CONFIG };
|
||||
let config = { ...DEFAULT_CONFIG }; // User-specific config, potentially updated by prompts
|
||||
|
||||
// Discovers available components from the CLI's bundled assets.
|
||||
async function getAvailableComponents() {
|
||||
try {
|
||||
const packageRoot = path.resolve(path.dirname(new URL(import.meta.url).pathname), '..', '..');
|
||||
console.log('Package root:', packageRoot);
|
||||
const jsSourceDir = path.join(packageRoot, 'src', 'js');
|
||||
console.log('JS source dir:', jsSourceDir);
|
||||
const cliScriptRunningDir = path.dirname(fileURLToPath(import.meta.url));
|
||||
const assetsDir = path.resolve(cliScriptRunningDir, 'assets');
|
||||
const jsSourceDir = path.join(assetsDir, 'js');
|
||||
|
||||
const jsFiles = await fs.readdir(jsSourceDir);
|
||||
console.log('Found JS files:', jsFiles);
|
||||
|
||||
return jsFiles
|
||||
.filter(file => file.endsWith('.js'))
|
||||
.map(file => path.basename(file, '.js'));
|
||||
} catch (error) {
|
||||
console.error("Error reading component source directories:", error);
|
||||
console.error("Error reading component source directories from CLI assets:", error);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
// Ensures necessary configuration (template engine, destination paths) is set, prompting the user if needed.
|
||||
async function ensureConfiguration() {
|
||||
console.log('\nChecking configuration...');
|
||||
|
||||
if (!config.templateEngine) {
|
||||
const engineChoice = await inquirer.prompt([
|
||||
{
|
||||
@@ -60,113 +59,61 @@ async function ensureConfiguration() {
|
||||
config.templateEngine = engineChoice.engine;
|
||||
}
|
||||
|
||||
const pathChoices = await inquirer.prompt([
|
||||
{
|
||||
type: 'input',
|
||||
name: 'templateDest',
|
||||
message: 'Where should template files be placed?',
|
||||
default: './',
|
||||
},
|
||||
{
|
||||
type: 'input',
|
||||
name: 'scriptDest',
|
||||
message: 'Where should script files be placed?',
|
||||
default: './',
|
||||
}
|
||||
]);
|
||||
config.templateDest = pathChoices.templateDest;
|
||||
config.scriptDest = pathChoices.scriptDest;
|
||||
const pathPrompts = [];
|
||||
if (!config.templateDest || config.templateDest === DEFAULT_CONFIG.templateDest) {
|
||||
pathPrompts.push({
|
||||
type: 'input',
|
||||
name: 'templateDest',
|
||||
message: 'Where should template files be placed?',
|
||||
default: DEFAULT_CONFIG.templateDest,
|
||||
});
|
||||
}
|
||||
if (!config.scriptDest || config.scriptDest === DEFAULT_CONFIG.scriptDest) {
|
||||
pathPrompts.push({
|
||||
type: 'input',
|
||||
name: 'scriptDest',
|
||||
message: 'Where should script files be placed?',
|
||||
default: DEFAULT_CONFIG.scriptDest,
|
||||
});
|
||||
}
|
||||
|
||||
console.log(`Configuration set: Engine=${config.templateEngine}, Templates=${config.templateDest}, Scripts=${config.scriptDest}`);
|
||||
if (pathPrompts.length > 0) {
|
||||
const pathChoices = await inquirer.prompt(pathPrompts);
|
||||
if (pathChoices.templateDest) config.templateDest = pathChoices.templateDest;
|
||||
if (pathChoices.scriptDest) config.scriptDest = pathChoices.scriptDest;
|
||||
}
|
||||
}
|
||||
|
||||
console.log('Basecoat CLI');
|
||||
|
||||
program
|
||||
.name('basecoat')
|
||||
.description('Add Basecoat components to your project')
|
||||
.version(packageVersion)
|
||||
.command('add')
|
||||
.description('Add one or more components to your project')
|
||||
.argument('[components...]', 'Names of components to add')
|
||||
.action(async (componentsArg) => {
|
||||
let componentsToAdd = componentsArg;
|
||||
try {
|
||||
if (!componentsToAdd || componentsToAdd.length === 0) {
|
||||
const availableComponents = await getAvailableComponents();
|
||||
if (availableComponents.length === 0) {
|
||||
console.error('Error: Could not find any components.');
|
||||
return;
|
||||
}
|
||||
|
||||
const answers = await inquirer.prompt([
|
||||
{
|
||||
type: 'checkbox',
|
||||
name: 'selectedComponents',
|
||||
message: 'Which component(s) would you like to add?',
|
||||
choices: availableComponents,
|
||||
validate: (input) => input.length > 0 ? true : 'Please select at least one component.'
|
||||
}
|
||||
]);
|
||||
|
||||
componentsToAdd = answers.selectedComponents;
|
||||
}
|
||||
|
||||
if (!componentsToAdd || componentsToAdd.length === 0) {
|
||||
console.log('No components selected. Exiting.');
|
||||
return;
|
||||
}
|
||||
|
||||
console.log(`Attempting to add: ${componentsToAdd.join(', ')}`);
|
||||
|
||||
await ensureConfiguration();
|
||||
|
||||
for (const componentName of componentsToAdd) {
|
||||
await addComponent(componentName);
|
||||
}
|
||||
|
||||
console.log('\nComponent addition process finished.');
|
||||
} catch (error) {
|
||||
if (error.isTtyError || error.constructor.name === 'ExitPromptError') {
|
||||
console.log('\nOperation cancelled.');
|
||||
} else {
|
||||
console.error('\nAn unexpected error occurred:', error);
|
||||
}
|
||||
process.exit(1);
|
||||
}
|
||||
});
|
||||
|
||||
// Copies a component's template and script files to the user's project.
|
||||
async function addComponent(componentName) {
|
||||
console.log(`\nProcessing component: ${componentName}...`);
|
||||
|
||||
// 1. Determine source paths (relative to package root)
|
||||
const cliScriptDir = path.dirname(new URL(import.meta.url).pathname);
|
||||
const packageRoot = path.resolve(cliScriptDir, '..', '..');
|
||||
const cliScriptRunningDir = path.dirname(fileURLToPath(import.meta.url));
|
||||
const assetsDir = path.resolve(cliScriptRunningDir, 'assets');
|
||||
const templateExt = config.templateEngine === 'jinja' ? '.html.jinja' : '.njk';
|
||||
const templateSource = path.join(packageRoot, 'src', config.templateEngine, `${componentName}${templateExt}`);
|
||||
const scriptSource = path.join(packageRoot, 'src', 'js', `${componentName}.js`);
|
||||
|
||||
const templateSource = path.join(assetsDir, config.templateEngine, `${componentName}${templateExt}`);
|
||||
const scriptSource = path.join(assetsDir, 'js', `${componentName}.js`);
|
||||
|
||||
// 2. Determine destination paths (relative to user's current working directory)
|
||||
const templateDestPath = path.resolve(process.cwd(), config.templateDest, `${componentName}${templateExt}`);
|
||||
const scriptDestPath = path.resolve(process.cwd(), config.scriptDest, `${componentName}.js`);
|
||||
|
||||
try {
|
||||
// 3. Check if source files exist
|
||||
const templateExists = await fs.pathExists(templateSource);
|
||||
const scriptExists = await fs.pathExists(scriptSource);
|
||||
|
||||
if (!templateExists || !scriptExists) {
|
||||
console.error(` Error: Source files for component '${componentName}' not found. Searched:`);
|
||||
if (!templateExists) console.error(` - ${templateSource}`);
|
||||
if (!scriptExists) console.error(` - ${scriptSource}`);
|
||||
return; // Skip this component
|
||||
if (!templateExists) {
|
||||
console.error(` Error: Template file for component '${componentName}' not found in CLI assets. Searched: ${templateSource}`);
|
||||
// Optionally, list available template engines or files for that component if helpful
|
||||
}
|
||||
if (!scriptExists) {
|
||||
console.error(` Error: Script file for component '${componentName}' not found in CLI assets. Searched: ${scriptSource}`);
|
||||
}
|
||||
if (!templateExists || !scriptExists) return; // Skip this component if sources are missing
|
||||
|
||||
// 4. Ensure destination directories exist
|
||||
await fs.ensureDir(path.dirname(templateDestPath));
|
||||
await fs.ensureDir(path.dirname(scriptDestPath));
|
||||
|
||||
// 5. Copy files
|
||||
await fs.copyFile(templateSource, templateDestPath);
|
||||
console.log(` -> Copied template to: ${templateDestPath}`);
|
||||
await fs.copyFile(scriptSource, scriptDestPath);
|
||||
@@ -177,4 +124,58 @@ async function addComponent(componentName) {
|
||||
}
|
||||
}
|
||||
|
||||
// Setup main CLI program
|
||||
program
|
||||
.name('basecoat')
|
||||
.description('Add Basecoat components to your project')
|
||||
.version(packageVersion);
|
||||
|
||||
// Define the 'add' command
|
||||
program
|
||||
.command('add')
|
||||
.description('Add one or more Basecoat components to your project')
|
||||
.argument('[components...]', 'Names of components to add (e.g., dialog select)')
|
||||
.action(async (componentsArg) => {
|
||||
let componentsToAdd = componentsArg;
|
||||
try {
|
||||
if (!componentsToAdd || componentsToAdd.length === 0) {
|
||||
const availableComponents = await getAvailableComponents();
|
||||
if (availableComponents.length === 0) {
|
||||
console.error('Error: No components available in the CLI. Build might be corrupted.');
|
||||
return;
|
||||
}
|
||||
const answers = await inquirer.prompt([
|
||||
{
|
||||
type: 'checkbox',
|
||||
name: 'selectedComponents',
|
||||
message: 'Which component(s) would you like to add?',
|
||||
choices: availableComponents,
|
||||
validate: (input) => input.length > 0 ? true : 'Please select at least one component.'
|
||||
}
|
||||
]);
|
||||
componentsToAdd = answers.selectedComponents;
|
||||
}
|
||||
|
||||
if (!componentsToAdd || componentsToAdd.length === 0) {
|
||||
console.log('No components selected. Exiting.');
|
||||
return;
|
||||
}
|
||||
|
||||
await ensureConfiguration(); // Confirm/gather destination paths
|
||||
|
||||
for (const componentName of componentsToAdd) {
|
||||
await addComponent(componentName);
|
||||
}
|
||||
console.log('\nComponent addition process finished.');
|
||||
|
||||
} catch (error) {
|
||||
if (error.isTtyError || error.constructor?.name === 'ExitPromptError') { // Handle inquirer cancellation
|
||||
console.log('\nOperation cancelled by user.');
|
||||
} else {
|
||||
console.error('\nAn unexpected error occurred during the add command:', error);
|
||||
}
|
||||
process.exit(1); // Exit with error code for unexpected errors
|
||||
}
|
||||
});
|
||||
|
||||
program.parse(process.argv);
|
||||
@@ -1,14 +1,45 @@
|
||||
{
|
||||
"name": "@hunvreus/basecoat-cli",
|
||||
"name": "basecoat-cli",
|
||||
"version": "0.1.0",
|
||||
"description": "CLI for Basecoat UI components",
|
||||
"description": "Add Basecoat components to your project",
|
||||
"author": "hunvreus",
|
||||
"license": "MIT",
|
||||
"type": "module",
|
||||
"bin": {
|
||||
"basecoat": "./index.js"
|
||||
"basecoat": "./dist/index.js"
|
||||
},
|
||||
"files": [
|
||||
"dist/"
|
||||
],
|
||||
"dependencies": {
|
||||
"commander": "^13.1.0",
|
||||
"inquirer": "^12.6.0",
|
||||
"fs-extra": "^11.3.0"
|
||||
}
|
||||
"fs-extra": "^11.3.0",
|
||||
"inquirer": "^12.6.0"
|
||||
},
|
||||
"keywords": [
|
||||
"cli",
|
||||
"components",
|
||||
"component library",
|
||||
"component system",
|
||||
"ui",
|
||||
"ui kit",
|
||||
"shadcn",
|
||||
"shadcn/ui",
|
||||
"tailwind",
|
||||
"tailwindcss",
|
||||
"css",
|
||||
"html",
|
||||
"jinja",
|
||||
"nunjucks",
|
||||
"alpinejs"
|
||||
],
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/hunvreus/basecoat.git",
|
||||
"directory": "packages/cli"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/hunvreus/basecoat/issues"
|
||||
},
|
||||
"homepage": "https://basecoatui.com/installation#install-cli"
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
{
|
||||
"name": "basecoat-css",
|
||||
"version": "0.1.0",
|
||||
"description": "CSS for Basecoat UI components",
|
||||
"author": {
|
||||
"name": "hunvreus",
|
||||
"url": "https://x.com/hunvreus"
|
||||
},
|
||||
"license": "MIT",
|
||||
"main": "dist/basecoat.css",
|
||||
"style": "dist/basecoat.css",
|
||||
"files": [
|
||||
"dist/"
|
||||
],
|
||||
"keywords": [
|
||||
"components",
|
||||
"component library",
|
||||
"component system",
|
||||
"ui",
|
||||
"ui kit",
|
||||
"shadcn",
|
||||
"shadcn/ui",
|
||||
"tailwind",
|
||||
"tailwindcss",
|
||||
"css",
|
||||
"html",
|
||||
"jinja",
|
||||
"nunjucks",
|
||||
"alpinejs"
|
||||
],
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/hunvreus/basecoat.git",
|
||||
"directory": "packages/css"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/hunvreus/basecoat/issues"
|
||||
},
|
||||
"homepage": "https://basecoatui.com/installation#install-css"
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
import fs from 'fs/promises';
|
||||
import path from 'path';
|
||||
import { fileURLToPath } from 'url';
|
||||
|
||||
// Resolve project root, assuming this script is in <project_root>/scripts/
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = path.dirname(__filename);
|
||||
const projectRoot = path.resolve(__dirname, '..');
|
||||
|
||||
// Ensures a directory exists. If it doesn't, it's created recursively.
|
||||
async function ensureDir(dirPath) {
|
||||
try {
|
||||
await fs.access(dirPath);
|
||||
} catch (error) {
|
||||
if (error.code === 'ENOENT') {
|
||||
await fs.mkdir(dirPath, { recursive: true });
|
||||
} else {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Cleans a directory by removing all its contents (files and subdirectories).
|
||||
async function cleanDir(directory) {
|
||||
try {
|
||||
await fs.access(directory);
|
||||
const entries = await fs.readdir(directory, { withFileTypes: true });
|
||||
for (const entry of entries) {
|
||||
const entryPath = path.join(directory, entry.name);
|
||||
if (entry.isDirectory()) {
|
||||
await fs.rm(entryPath, { recursive: true, force: true });
|
||||
} else {
|
||||
await fs.unlink(entryPath);
|
||||
}
|
||||
}
|
||||
console.log(`Cleaned directory: ${directory}`);
|
||||
} catch (error) {
|
||||
if (error.code === 'ENOENT') {
|
||||
console.log(`Directory not found, no need to clean: ${directory}`);
|
||||
} else {
|
||||
console.error(`Error cleaning directory ${directory}:`, error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Recursively copies a directory.
|
||||
async function copyDirRecursive(src, dest) {
|
||||
await ensureDir(dest);
|
||||
const entries = await fs.readdir(src, { withFileTypes: true });
|
||||
for (let entry of entries) {
|
||||
const srcPath = path.join(src, entry.name);
|
||||
const destPath = path.join(dest, entry.name);
|
||||
if (entry.isDirectory()) {
|
||||
await copyDirRecursive(srcPath, destPath);
|
||||
} else {
|
||||
await fs.copyFile(srcPath, destPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Main build function to prepare packages for publishing.
|
||||
async function build() {
|
||||
console.log('Starting build process...');
|
||||
|
||||
// Define all necessary paths
|
||||
const cliPackageDir = path.join(projectRoot, 'packages', 'cli');
|
||||
const cliDistDir = path.join(cliPackageDir, 'dist');
|
||||
const cliDistAssetsDir = path.join(cliDistDir, 'assets');
|
||||
|
||||
const cssPackageDir = path.join(projectRoot, 'packages', 'css');
|
||||
const cssDistDir = path.join(cssPackageDir, 'dist');
|
||||
|
||||
const srcDir = path.join(projectRoot, 'src');
|
||||
const srcCssDir = path.join(srcDir, 'css');
|
||||
const srcJsDir = path.join(srcDir, 'js');
|
||||
const srcNunjucksDir = path.join(srcDir, 'nunjucks');
|
||||
const srcJinjaDir = path.join(srcDir, 'jinja');
|
||||
|
||||
// Clean previous build artifacts
|
||||
console.log('Cleaning distribution directories...');
|
||||
await cleanDir(cliDistDir);
|
||||
await cleanDir(cssDistDir);
|
||||
|
||||
// Build CLI package
|
||||
console.log('Building CLI package...');
|
||||
await ensureDir(cliDistDir); // Ensure base dist dir exists
|
||||
await ensureDir(cliDistAssetsDir); // Ensure assets dir within dist exists
|
||||
|
||||
await fs.copyFile(path.join(cliPackageDir, 'index.js'), path.join(cliDistDir, 'index.js'));
|
||||
console.log(`Copied CLI index.js to ${cliDistDir}`);
|
||||
|
||||
await copyDirRecursive(srcJsDir, path.join(cliDistAssetsDir, 'js'));
|
||||
console.log(`Copied JS assets to ${path.join(cliDistAssetsDir, 'js')}`);
|
||||
await copyDirRecursive(srcNunjucksDir, path.join(cliDistAssetsDir, 'nunjucks'));
|
||||
console.log(`Copied Nunjucks assets to ${path.join(cliDistAssetsDir, 'nunjucks')}`);
|
||||
await copyDirRecursive(srcJinjaDir, path.join(cliDistAssetsDir, 'jinja'));
|
||||
console.log(`Copied Jinja assets to ${path.join(cliDistAssetsDir, 'jinja')}`);
|
||||
|
||||
// Build CSS package
|
||||
console.log('Building CSS package...');
|
||||
await ensureDir(cssDistDir); // Ensure dist dir exists for css package
|
||||
await fs.copyFile(path.join(srcCssDir, 'basecoat.css'), path.join(cssDistDir, 'basecoat.css'));
|
||||
console.log(`Copied basecoat.css to ${cssDistDir}`);
|
||||
|
||||
console.log('Build process finished successfully!');
|
||||
}
|
||||
|
||||
build().catch(error => {
|
||||
console.error('Build failed:', error);
|
||||
process.exit(1);
|
||||
});
|
||||
Reference in New Issue
Block a user