aeriui
Version:
A modern, accessible, and highly customizable React UI library built with TypeScript and Tailwind CSS.
336 lines (279 loc) • 9.84 kB
JavaScript
const AERIUI_CSS = `
@import "tailwindcss";
/* AeriUI CSS Vars */
@layer base {
:root {
--background: 95.64% 0.0067 286.27;
--foreground: 13.54% 0.0047 285.76;
--primary: 92.64% 0.0067 286.27;
--primary-foreground: 5% 0.01 250;
--secondary: 87.76% 0.0114 285.5;
--secondary-foreground: 90.79% 0.0054 286.29;
--destructive: 61.22% 0.2082 22.24;
--destructive-foreground: var(--background);
--success: 78.49% 0.2002 153.29;
--success-foreground: var(--foreground);
--warning: 70% 0.22 60;
--warning-foreground: var(--foreground);
--accent: 89.5% 0.0127 279.14;
--accent-foreground: var(--foreground);
--muted: 89.5% 0.0127 279.14;
--muted-foreground: 71.18% 0.0129 286.07;
--border: 87.36% 0.0137 280.05;
--input: 41.6% 0.0183 281.45;
--ring: 56.73% 0.0456 274.26;
--radius-sm: 0.125rem;
--radius: 0.25rem;
}
.dark {
--background: 13.54% 0.0047 285.76;
--foreground: 82.64% 0.0067 286.27;
--primary: 92.64% 0.0067 286.27;
--primary-foreground: 5% 0.01 250;
--secondary: 23.76% 0.0114 285.5;
--secondary-foreground: 90.79% 0.0054 286.29;
--destructive: 61.22% 0.2082 22.24;
--destructive-foreground: var(--foreground);
--success: 78.49% 0.2002 153.29;
--success-foreground: var(--foreground);
--warning: 70% 0.22 60;
--warning-foreground: var(--foreground);
--accent: 29.5% 0.0127 279.14;
--accent-foreground: var(--foreground);
--muted: 29.5% 0.0127 279.14;
--muted-foreground: 60.18% 0.0129 286.07;
--border: 37.36% 0.0137 280.05;
--input: 41.6% 0.0183 281.45;
--ring: 56.73% 0.0456 274.26;
}
}
/* Tailwind v4 Theme Definitions */
@theme {
--color-background: oklch(var(--background));
--color-foreground: oklch(var(--foreground));
--color-primary: oklch(var(--primary));
--color-primary-foreground: oklch(var(--primary-foreground));
--color-secondary: oklch(var(--secondary));
--color-secondary-foreground: oklch(var(--secondary-foreground));
--color-destructive: oklch(var(--destructive));
--color-destructive-foreground: oklch(var(--destructive-foreground));
--color-success: oklch(var(--success));
--color-success-foreground: oklch(var(--success-foreground));
--color-warning: oklch(var(--warning));
--color-warning-foreground: oklch(var(--warning-foreground));
--color-accent: oklch(var(--accent));
--color-accent-foreground: oklch(var(--accent-foreground));
--color-muted: oklch(var(--muted));
--color-muted-foreground: oklch(var(--muted-foreground));
--color-border: oklch(var(--border));
--color-input: oklch(var(--input));
--color-ring: oklch(var(--ring));
}
@layer base {
body {
@apply bg-background text-foreground;
}
}
`;
const inquirer = require("inquirer");
const path = require("path");
const fs = require("fs");
const https = require("https");
const args = process.argv.slice(2);
const command = args[0];
const pkgRoot = process.cwd();
const destDir = path.join(pkgRoot, "src", "app", "components", "ui");
const GITHUB_BASE_URL =
"https://raw.githubusercontent.com/domody/aeriui-pkg/refs/heads/main/src/components/";
const allComponents = [
"Accordion",
"Alert",
"Badge",
"Button",
"Card",
"Checkbox",
"ContextMenu",
"Dropdown",
"Input",
"Modal",
"OptionList",
"Selector",
"Separator",
"Slot",
"Tabs",
"Tooltip",
];
function downloadComponent(componentName) {
const fileUrl = `${GITHUB_BASE_URL}${componentName}.tsx`;
// Load aeriui.json if it exists
const configPath = path.join(projectRoot, "aeriui.json");
let destDirResolved = destDir; // fallback default
if (fs.existsSync(configPath)) {
try {
const configData = JSON.parse(fs.readFileSync(configPath, "utf8"));
if (configData.componentPath) {
destDirResolved = path.join(projectRoot, configData.componentPath);
} else {
console.warn(
"⚠️ Warning: componentPath not found in aeriui.json, using default destination directory."
);
}
} catch (err) {
console.warn(
`⚠️ Warning: Failed to parse aeriui.json, using default destination directory. Error: ${err.message}`
);
}
} else {
console.warn(
"⚠️ Warning: aeriui.json not found, using default destination directory."
);
}
const destFilePath = path.join(destDirResolved, `${componentName}.tsx`);
console.log(`Adding ${componentName}...`);
// Ensure destination folder exists
fs.mkdirSync(destDirResolved, { recursive: true });
https
.get(fileUrl, (res) => {
if (res.statusCode !== 200) {
console.error(
`❌ Failed to download component "${componentName}". Check if it exists.`
);
return;
}
const fileStream = fs.createWriteStream(destFilePath);
res.pipe(fileStream);
fileStream.on("finish", () => {
fileStream.close();
console.log(`✅ Component "${componentName}" added at ${destFilePath}`);
});
})
.on("error", (err) => {
console.error(`❌ Error fetching component: ${err.message}`);
});
}
if (command === "init") {
console.log("Initializing aeriui...\n");
const prompt = inquirer.createPromptModule();
prompt([
{
type: "input",
name: "stylesPath",
message:
"Enter the path for your main styles.css (default: src/app/styles/globals.css):",
default: "src/app/styles/globals.css",
},
{
type: "input",
name: "componentPath",
message:
"Where should AeriUI components be stored? (default: src/app/components/ui)",
default: "src/app/components/ui",
},
{
type: "confirm",
name: "useAlias",
message:
"Would you like to create an alias for AeriUI components? (e.g., @aeriui)",
default: true,
},
{
type: "input",
name: "aliasName",
message: "Enter alias name (default: @aeriui):",
when: (answers) => answers.useAlias,
default: "@aeriui",
},
{
type: "input",
name: "cnPath",
message:
"Enter the path for the `cn.ts` utility (default: src/app/lib/utils/cn.ts):",
default: "src/app/lib/utils/cn.ts",
},
]).then((answers) => {
const projectRoot = process.cwd();
// Create Styles
const stylesFilePath = path.join(projectRoot, answers.stylesPath);
fs.mkdirSync(path.dirname(stylesFilePath), { recursive: true });
let existingContent = "";
if (fs.existsSync(stylesFilePath)) {
existingContent = fs.readFileSync(stylesFilePath, "utf-8");
}
if (!existingContent.includes(AERIUI_CSS.trim())) {
const newContent = existingContent + "\n" + AERIUI_CSS;
fs.writeFileSync(stylesFilePath, newContent, { flag: "w" });
console.log(
`✅ Appended AeriUI CSS variables to existing file at ${answers.stylesPath}`
);
} else {
console.log(
`⚠️ AeriUI CSS variables already present at ${answers.stylesPath}, no changes made.`
);
}
// Create Components Folder
const componentsDir = path.join(projectRoot, answers.componentPath);
fs.mkdirSync(componentsDir, { recursive: true });
console.log(`✅ Components folder created at ${answers.componentPath}`);
// Add custom Alias
if (answers.useAlias) {
const tsconfigPath = path.join(projectRoot, "tsconfig.json");
// Read the existing tsconfig.json
let tsconfig = JSON.parse(fs.readFileSync(tsconfigPath, "utf-8"));
// Ensure compilerOptions exists
tsconfig.compilerOptions = tsconfig.compilerOptions || {};
// Ensure paths exists inside compilerOptions
tsconfig.compilerOptions.paths = tsconfig.compilerOptions.paths || {};
// Add the alias
tsconfig.compilerOptions.paths[answers.aliasName + "/*"] = [
`./${answers.componentPath}/*`,
];
// Write back to tsconfig.json
fs.writeFileSync(tsconfigPath, JSON.stringify(tsconfig, null, 2));
console.log(`✅ Alias "${answers.aliasName}" added to tsconfig.json!`);
}
// cn File path
const cnFilePath = path.join(projectRoot, answers.cnPath);
fs.mkdirSync(path.dirname(cnFilePath), { recursive: true });
fs.writeFileSync(
cnFilePath,
`import { type ClassValue, clsx } from "clsx";
import { twMerge } from "tailwind-merge";
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs));
}`,
{ flag: "w" }
);
console.log(`✅ cn.ts utility created at ${answers.cnPath}`);
// Create aeriui.json file
const aeriuiConfig = {
createdAt: new Date().toISOString(),
description: "AeriUI config file",
stylesPath: answers.stylesPath,
componentPath: answers.componentPath,
cnPath: answers.cnPath,
};
const configPath = path.join(projectRoot, "aeriui.json");
fs.writeFileSync(configPath, JSON.stringify(aeriuiConfig, null, 2));
console.log(`✅ aeriui.json created at ${configPath}`);
console.log("\n🎉 AeriUI has been initialized successfully!");
});
} else if (command === "add" && args[1]) {
const componentName = args[1];
if (componentName === "all" || componentName === "*") {
console.log("Adding all components...\n");
allComponents.forEach(downloadComponent);
} else if (allComponents.includes(componentName)) {
downloadComponent(componentName);
} else {
console.error(`❌ Unknown component "${componentName}".`);
console.log("Available components:");
console.log(allComponents.join(", "));
}
} else {
console.log(`Usage:
npx aeriui@latest init -> Setup the necessary files
npx aeriui@latest add <component> -> Add a specific component
npx aeriui@latest add * -> Add all available componenets
`);
}