flowbite-qwik-cli
Version:
This is a CLI tool to setup flowbite qwik into your project
335 lines (316 loc) • 10.2 kB
JavaScript
#!/usr/bin/env node
'use strict';
const prompts = require('@clack/prompts');
const fs = require('fs');
const promises = require('fs/promises');
const child_process = require('child_process');
const prettier = require('prettier');
const path = require('path');
const identifyMonorepoRoot = require('identify-monorepo-root');
function _interopNamespaceDefault(e) {
const n = Object.create(null, { [Symbol.toStringTag]: { value: 'Module' } });
if (e) {
for (const k in e) {
if (k !== 'default') {
const d = Object.getOwnPropertyDescriptor(e, k);
Object.defineProperty(n, k, d.get ? d : {
enumerable: true,
get: () => e[k]
});
}
}
}
n.default = e;
return Object.freeze(n);
}
const fs__namespace = /*#__PURE__*/_interopNamespaceDefault(fs);
const prettier__namespace = /*#__PURE__*/_interopNamespaceDefault(prettier);
const path__namespace = /*#__PURE__*/_interopNamespaceDefault(path);
async function readJsonFile(path2) {
const file = await promises.readFile(path2, "utf8");
return JSON.parse(file);
}
function detectPackageManager() {
const rootFolder = identifyMonorepoRoot.identifyMonorepoRoot() || "./";
if (fs__namespace.existsSync(path__namespace.resolve(rootFolder, "yarn.lock"))) {
return "yarn";
} else if (fs__namespace.existsSync(path__namespace.resolve(rootFolder, "pnpm-lock.yaml"))) {
return "pnpm";
} else if (fs__namespace.existsSync(path__namespace.resolve(rootFolder, "package-lock.json"))) {
return "npm";
} else {
return "npm";
}
}
async function tailwindInstalledInProject() {
const packageJsonPath = path__namespace.resolve(process.cwd(), "package.json");
if (!fs__namespace.existsSync(packageJsonPath)) {
console.error("package.json not found at:", packageJsonPath);
return false;
}
const packageJson = await readJsonFile("./package.json");
const { dependencies, devDependencies } = packageJson;
return dependencies?.["tailwindcss"] || devDependencies?.["tailwindcss"];
}
function hasCssUtilities() {
const globalCssPath = path__namespace.resolve(process.cwd(), "./src/global.css");
if (!fs__namespace.existsSync(globalCssPath)) {
console.error("global.css not found at:", globalCssPath);
return false;
}
const content = fs__namespace.readFileSync(globalCssPath, "utf8");
return content.includes("tailwindcss");
}
async function detectTailwindCSS() {
return await tailwindInstalledInProject() && hasCssUtilities();
}
async function executeCommand(command, printMessages = true) {
return new Promise((resolve, reject) => {
const cli = child_process.spawn(command, [], { stdio: printMessages ? "inherit" : "ignore", shell: true });
cli.on("close", (code) => {
if (code !== 0) {
reject(`Command ${command} exited with code ${code}`);
} else {
resolve(`Command ${command} completed successfully`);
}
});
});
}
async function runCommand(cmd, packageManager) {
let command;
if (packageManager === "yarn") {
command = `yarn ${cmd}`;
} else if (packageManager === "pnpm") {
command = `pnpm ${cmd}`;
} else {
command = `npm run ${cmd}`;
}
await executeCommand(command);
}
async function installDependency(packageManager, packageName) {
let command;
if (packageManager === "yarn") {
command = `yarn add -D ${packageName}`;
} else if (packageManager === "pnpm") {
command = `pnpm add -D ${packageName}`;
} else {
command = `npm install --save-dev ${packageName}`;
}
await executeCommand(command, false);
}
async function addFlowbiteWrapper(theme, toastPosition, useDarkTheme) {
const rootPath = path__namespace.resolve(process.cwd(), "./src/root.tsx");
if (!fs__namespace.existsSync(rootPath)) {
console.error("root.tsx not found at:", rootPath);
return;
}
const rootContent = fs__namespace.readFileSync(rootPath, "utf8");
if (rootContent.includes("FlowbiteProvider")) {
return;
}
const hasRouterHead = rootContent.includes("<RouterHead />");
const hasRouterOutlet = rootContent.includes("<RouterOutlet />");
if (!hasRouterHead && useDarkTheme) {
prompts.log.error("We did not manage to include the FlowbiteProviderHeader component. Please follow the manual installation steps.");
}
if (!hasRouterOutlet) {
prompts.log.error("We did not manage to include the FlowbiteProvider component. Please follow the manual installation steps.");
return;
}
const content = `
import { FlowbiteProvider ${useDarkTheme ? ", FlowbiteProviderHeader" : ""} } from 'flowbite-qwik';
${rootContent.replace("<RouterHead />", useDarkTheme ? `<FlowbiteProviderHeader /><RouterHead />` : "<RouterHead />").replace("<RouterOutlet />", `<FlowbiteProvider theme="${theme}" toastPosition="${toastPosition}"><RouterOutlet /></FlowbiteProvider>`)}
`;
const prettified = await prettier__namespace.format(content, {
singleQuote: true,
parser: "babel"
});
fs__namespace.writeFileSync(rootPath, prettified);
}
async function addFlowbiteToGlobalCss() {
const globalCssPath = "./src/global.css";
const globalCssContent = fs__namespace.readFileSync(globalCssPath, "utf8");
if (!globalCssContent) {
prompts.log.error("global.css file not found");
return;
}
if (globalCssContent.includes("flowbite/plugin")) return;
const content = await prettier__namespace.format(
`
${globalCssContent}
@plugin 'flowbite/plugin';
@source "../node_modules/flowbite-qwik";
@custom-variant dark (&:where(.dark, .dark *));
@theme {
--color-bgContrast: #fff;
}
@layer theme {
.dark {
--color-bgContrast: #111827;
}
}
@theme {
--animate-from-left: slideFromLeft 0.2s 1;
--animate-from-right: slideFromRight 0.2s 1;
--min-width-screen-lg: 1024px;
--container-8xl: 90rem;
@keyframes slideFromLeft {
0% {
transform: translateX(-100%);
}
100% {
transform: translateX(0);
}
}
@keyframes slideFromRight {
0% {
transform: translateX(100%);
}
100% {
transform: translateX(0);
}
}
--color-green-50: #ecfdf5;
--color-green-100: #d1fae5;
--color-green-200: #a7f3d0;
--color-green-300: #6ee7b7;
--color-green-400: #34d399;
--color-green-500: #10b981;
--color-green-600: #059669;
--color-green-700: #047857;
--color-green-800: #065f46;
--color-green-900: #064e3b;
--color-green-950: oklch(.266 .065 152.934);
--color-pink-50: #fdf2f8;
--color-pink-100: #fce7f3;
--color-pink-200: #fbcfe8;
--color-pink-300: #f9a8d4;
--color-pink-400: #f472b6;
--color-pink-500: #ec4899;
--color-pink-600: #db2777;
--color-pink-700: #be185d;
--color-pink-800: #9d174d;
--color-pink-900: #831843;
--color-purple-50: #f5f3ff;
--color-purple-100: #ede9fe;
--color-purple-200: #ddd6fe;
--color-purple-300: #c4b5fd;
--color-purple-400: #a78bfa;
--color-purple-500: #8b5cf6;
--color-purple-600: #7c3aed;
--color-purple-700: #6d28d9;
--color-purple-800: #5b21b6;
--color-purple-900: #4c1d95;
--color-purple-950: oklch(.291 .149 302.717);
--color-gray-50: #f9fafb;
--color-gray-100: #f3f4f6;
--color-gray-200: #e5e7eb;
--color-gray-300: #d1d5db;
--color-gray-400: #9ca3af;
--color-gray-500: #6b7280;
--color-gray-600: #4b5563;
--color-gray-700: #374151;
--color-gray-800: #1f2937;
--color-gray-900: #111827;
--color-gray-950: oklch(.13 .028 261.692);
--color-blue-50: #eff6ff;
--color-blue-100: #dbeafe;
--color-blue-200: #bfdbfe;
--color-blue-300: #93c5fd;
--color-blue-400: #60a5fa;
--color-blue-500: #3b82f6;
--color-blue-600: #2563eb;
--color-blue-700: #1d4ed8;
--color-blue-800: #1e40af;
--color-blue-900: #1e3a8a;
--color-blue-950: oklch(.282 .091 267.935);
}
@layer base {
*,
::after,
::before,
::backdrop,
::file-selector-button {
border-color: var(--color-gray-200, currentColor);
}
}
.dark {
color-scheme: dark;
background: #111827;
}
.light {
color-scheme: light;
background: #fff;
}`,
{
singleQuote: true,
parser: "css"
}
);
fs__namespace.writeFileSync(globalCssPath, content);
}
async function installFlowbiteQwik() {
const packageManager = detectPackageManager();
const loader = prompts.spinner();
loader.start("Installing flowbite-qwik...");
await installDependency(packageManager, "flowbite-qwik flowbite flowbite-qwik-icons");
loader.stop("Flowbite Qwik installed! 🎉");
const hasTailwindInstalled = await detectTailwindCSS();
if (!hasTailwindInstalled) {
prompts.log.info("Tailwind CSS is not installed in your project. Let's install it!");
await runCommand("qwik add tailwind", packageManager);
}
const colorTheme = await prompts.select({
message: "Choose your color theme",
initialValue: "blue",
options: [
{ value: "blue", label: "Blue" },
{ value: "green", label: "Green" },
{ value: "red", label: "Red" },
{ value: "yellow", label: "Yellow" },
{ value: "purple", label: "Purple" },
{ value: "pink", label: "Pink" }
]
});
const toastPosition = await prompts.select({
message: "Choose your toast position",
initialValue: "top-right",
options: [
{ value: "top-right", label: "Top Right" },
{ value: "top-left", label: "Top Left" },
{ value: "bottom-right", label: "Bottom Right" },
{ value: "bottom-left", label: "Bottom Left" }
]
});
const useDarkTheme = await prompts.confirm({
message: "Do you use dark theme?",
initialValue: true
});
loader.start("Setup flowbite-qwik...");
try {
await addFlowbiteToGlobalCss();
await addFlowbiteWrapper(colorTheme, toastPosition, useDarkTheme);
} catch (error) {
console.log(error);
}
loader.stop("Flowbite Qwik configured! 🎉");
}
function bye() {
prompts.outro("Take care, see you soon! 👋");
process.exit(0);
}
async function init() {
prompts.intro(`Add flowbite-qwik to your project!`);
const proceed = await prompts.confirm({
message: "Do you want to set flowbite integration?",
initialValue: true
});
if (prompts.isCancel(proceed) || !proceed) {
bye();
}
await installFlowbiteQwik();
prompts.outro(`You're all set!`);
}
(async () => {
await init();
})();