prepare basecoat 1.0 migration

This commit is contained in:
Ronan Berder
2026-06-03 23:08:41 +08:00
parent 7e7d509e90
commit c1cf01da45
125 changed files with 2346 additions and 1169 deletions
+26
View File
@@ -1,10 +1,22 @@
import { spawn } from 'child_process';
import { execFile } from 'child_process';
import { cp, mkdir } from 'fs/promises';
import { promisify } from 'util';
import { generateCssEntrypoints } from './generate-css-entrypoints.js';
const execFilePromise = promisify(execFile);
const styles = ['vega', 'nova', 'maia', 'lyra', 'mira', 'luma', 'sera', 'rhea'];
const watch = process.argv.includes('--watch');
const fontFiles = [
'geist-sans-latin-400-normal.woff2',
'geist-sans-latin-500-normal.woff2',
'geist-sans-latin-600-normal.woff2',
'geist-sans-latin-700-normal.woff2',
'geist-mono-latin-400-normal.woff2',
'geist-mono-latin-500-normal.woff2',
'geist-mono-latin-600-normal.woff2',
'geist-mono-latin-700-normal.woff2',
];
function tailwindArgs(input, output) {
const args = ['tailwindcss', '-i', input, '-o', output];
@@ -13,6 +25,20 @@ function tailwindArgs(input, output) {
return args;
}
async function copyDocsAssets() {
await mkdir('./docs/src/assets/js', { recursive: true });
await cp('./node_modules/htmx.org/dist/htmx.min.js', './docs/src/assets/js/htmx.min.js');
await mkdir('./docs/src/assets/fonts/geist', { recursive: true });
for (const file of fontFiles) {
const packageName = file.startsWith('geist-sans') ? 'geist-sans' : 'geist-mono';
await cp(`./node_modules/@fontsource/${packageName}/files/${file}`, `./docs/src/assets/fonts/geist/${file}`);
}
}
await copyDocsAssets();
await generateCssEntrypoints();
if (watch) {
const children = styles.map((style) => {
const child = spawn('npx', tailwindArgs(`./docs/css/styles-${style}.css`, `./docs/src/assets/styles-${style}.css`), {
+6 -1
View File
@@ -3,6 +3,7 @@ import path from 'path';
import { fileURLToPath } from 'url';
import { exec } from 'child_process';
import { promisify } from 'util';
import { generateCssEntrypoints } from './generate-css-entrypoints.js';
const execPromise = promisify(exec);
@@ -66,6 +67,7 @@ async function copyDirRecursive(src, dest) {
// Main build function to prepare packages for publishing.
async function build() {
console.log('Starting build process...');
await generateCssEntrypoints();
// Define all necessary paths
const cliPackageDir = path.join(projectRoot, 'packages', 'cli');
@@ -152,6 +154,9 @@ async function build() {
const styles = ['vega', 'nova', 'maia', 'lyra', 'mira', 'luma', 'sera', 'rhea'];
await fs.copyFile(path.join(srcCssDir, 'basecoat.css'), path.join(cssDistDir, 'basecoat.css'));
await fs.copyFile(path.join(srcCssDir, 'basecoat.all.css'), path.join(cssDistDir, 'basecoat.all.css'));
await fs.copyFile(path.join(srcCssDir, 'basecoat-base.css'), path.join(cssDistDir, 'basecoat-base.css'));
await fs.copyFile(path.join(srcCssDir, 'basecoat-base.cdn.css'), path.join(cssDistDir, 'basecoat-base.cdn.css'));
await fs.copyFile(path.join(srcCssDir, 'basecoat-components.css'), path.join(cssDistDir, 'basecoat-components.css'));
for (const style of styles) {
await fs.copyFile(path.join(srcCssDir, `basecoat-${style}.css`), path.join(cssDistDir, `basecoat-${style}.css`));
await fs.copyFile(path.join(srcCssDir, `basecoat-${style}.cdn.css`), path.join(cssDistDir, `basecoat-${style}.cdn.css`));
@@ -170,7 +175,7 @@ async function build() {
console.log(`Copied split CSS folders to ${cssDistDir}`);
// Create Tailwind CSS builds for the CSS package.
const cdnEntries = ['basecoat.cdn.css', ...styles.map((style) => `basecoat-${style}.cdn.css`)];
const cdnEntries = ['basecoat.cdn.css', 'basecoat-base.cdn.css', ...styles.map((style) => `basecoat-${style}.cdn.css`)];
for (const entry of cdnEntries) {
const cdnCssSrc = path.join(srcCssDir, entry);
const baseName = path.basename(entry, '.css');
+100
View File
@@ -0,0 +1,100 @@
import fs from 'fs/promises';
import path from 'path';
const styles = ['vega', 'nova', 'maia', 'lyra', 'mira', 'luma', 'sera', 'rhea'];
const excludedComponents = new Set(['form']);
// Keep cascade stable for components whose selectors intentionally compose.
const componentOrder = [
'alert',
'badge',
'button',
'button-group',
'card',
'collapsible',
'command',
'combobox',
'dialog',
'dropdown-menu',
'empty',
'field',
'checkbox',
'input',
'input-group',
'item',
'kbd',
'label',
'native-select',
'popover',
'radio',
'range',
'select',
'sidebar',
'skeleton',
'switch',
'table',
'tabs',
'textarea',
'toast',
'tooltip',
];
async function existingComponentNames(cssDir) {
const componentDir = path.join(cssDir, 'components');
const files = await fs.readdir(componentDir);
const names = files
.filter((file) => file.endsWith('.css'))
.map((file) => path.basename(file, '.css'))
.filter((name) => !excludedComponents.has(name));
const known = componentOrder.filter((name) => names.includes(name));
const extra = names.filter((name) => !componentOrder.includes(name)).sort();
return [...known, ...extra];
}
function componentImports(names) {
return [
'/* Components */',
...names.map((name) => `@import "./components/${name}.css";`),
].join('\n');
}
async function writeIfChanged(filePath, content) {
let current = null;
try {
current = await fs.readFile(filePath, 'utf8');
} catch (error) {
if (error.code !== 'ENOENT') throw error;
}
if (current !== content) await fs.writeFile(filePath, content);
}
export async function generateCssEntrypoints({ cssDir = path.resolve('src/css') } = {}) {
const components = await existingComponentNames(cssDir);
const componentsCss = `${componentImports(components)}\n`;
const baseCss = `@import "./base/base.css";\n@import "./basecoat-components.css";\n`;
await writeIfChanged(path.join(cssDir, 'basecoat-components.css'), componentsCss);
await writeIfChanged(path.join(cssDir, 'basecoat-base.css'), baseCss);
await writeIfChanged(path.join(cssDir, 'basecoat-base.cdn.css'), '@import "tailwindcss" source(none);\n@import "./basecoat-base.css";\n');
for (const style of styles) {
await writeIfChanged(
path.join(cssDir, `basecoat-${style}.css`),
`@import "./basecoat-base.css";\n@import "./styles/style-${style}.css";\n`,
);
await writeIfChanged(
path.join(cssDir, `basecoat-${style}.cdn.css`),
`@import "tailwindcss" source(none);\n@import "./basecoat-${style}.css";\n`,
);
}
await writeIfChanged(path.join(cssDir, 'basecoat.css'), '@import "./basecoat-vega.css";\n');
await writeIfChanged(path.join(cssDir, 'basecoat.all.css'), '@import "./basecoat.css";\n');
await writeIfChanged(path.join(cssDir, 'basecoat.cdn.css'), '@import "tailwindcss" source(none);\n@import "./basecoat.css";\n');
return { components, styles };
}
if (import.meta.url === `file://${process.argv[1]}`) {
await generateCssEntrypoints();
}