UNPKG

@feedinbox/cli

Version:

CLI tool for installing FeedInbox components into your project

335 lines (317 loc) 11.8 kB
// src/commands/add.ts import path3 from "path"; import fs3 from "fs-extra"; import chalk2 from "chalk"; import inquirer from "inquirer"; // src/utils/registry.ts async function getTemplateRegistry() { return { "react-vanilla": { name: "React + Vanilla CSS", description: "Clean React components with vanilla CSS styling", dependencies: { "@feedinbox/sdk": "^1.0.0" }, devDependencies: { "@types/react": "^19.0.0", "@types/react-dom": "^19.0.0" }, files: [ "FeedbackWidget.tsx", "NewsletterWidget.tsx", "ContactWidget.tsx", "index.ts", "styles/index.css", "styles/feedback-widget.css", "styles/newsletter-widget.css", "styles/contact-widget.css" ] }, "react-tailwind": { name: "React + Tailwind CSS", description: "React components styled with Tailwind CSS utilities", dependencies: { "@feedinbox/sdk": "^1.0.0" }, devDependencies: { "@types/react": "^19.0.0", "@types/react-dom": "^19.0.0", "tailwindcss": "^3.4.0" }, files: [ "FeedbackWidget.tsx", "NewsletterWidget.tsx", "ContactWidget.tsx", "index.ts" ] }, "react-shadcn": { name: "React + shadcn/ui", description: "React components using shadcn/ui component library", dependencies: { "@feedinbox/sdk": "^1.0.0" }, devDependencies: { "@types/react": "^19.0.0", "@types/react-dom": "^19.0.0" }, files: [ "FeedbackWidget.tsx", "NewsletterWidget.tsx", "ContactWidget.tsx", "index.ts", "ui/button.tsx", "ui/input.tsx", "ui/textarea.tsx", "ui/dialog.tsx", "ui/checkbox.tsx", "ui/radio-group.tsx" ] } }; } // src/utils/template.ts import path from "path"; import fs from "fs-extra"; import { fileURLToPath } from "url"; var __filename = fileURLToPath(import.meta.url); var __dirname = path.dirname(__filename); async function copyTemplate(templateType, targetDir) { const templateDir = path.join(__dirname, "../../templates", templateType); if (!await fs.pathExists(templateDir)) { throw new Error(`Template directory not found: ${templateType}`); } await fs.copy(templateDir, targetDir, { overwrite: true, filter: (src) => { return !src.includes(".git") && !src.includes("node_modules"); } }); console.log(`\u{1F4C1} Template files copied from ${templateType}`); } // src/utils/package.ts import path2 from "path"; import fs2 from "fs-extra"; import chalk from "chalk"; async function updatePackageJson(dependencies, devDependencies) { const packageJsonPath = path2.join(process.cwd(), "package.json"); if (!await fs2.pathExists(packageJsonPath)) { console.log(chalk.yellow("\u26A0\uFE0F No package.json found. You may need to run npm init first.")); return; } const packageJson = await fs2.readJson(packageJsonPath); if (Object.keys(dependencies).length > 0) { packageJson.dependencies = packageJson.dependencies || {}; Object.assign(packageJson.dependencies, dependencies); console.log(chalk.blue("\u{1F4E6} Added dependencies:"), Object.keys(dependencies).join(", ")); } if (Object.keys(devDependencies).length > 0) { packageJson.devDependencies = packageJson.devDependencies || {}; Object.assign(packageJson.devDependencies, devDependencies); console.log(chalk.blue("\u{1F527} Added dev dependencies:"), Object.keys(devDependencies).join(", ")); } await fs2.writeJson(packageJsonPath, packageJson, { spaces: 2 }); console.log(chalk.green("\u2705 package.json updated")); console.log(chalk.yellow("\u{1F4A1} Run npm install to install new dependencies")); } // src/commands/add.ts async function addComponents(type, options) { const validTypes = ["react-vanilla", "react-tailwind", "react-shadcn"]; if (!validTypes.includes(type)) { throw new Error(`Invalid component type: ${type}. Valid types: ${validTypes.join(", ")}`); } const targetDir = path3.resolve(process.cwd(), options.dir); if (await fs3.pathExists(targetDir)) { const files = await fs3.readdir(targetDir); if (files.length > 0 && !options.force) { if (!options.yes) { const { confirm } = await inquirer.prompt([ { type: "confirm", name: "confirm", message: `Directory ${options.dir} already exists and contains files. Continue?`, default: false } ]); if (!confirm) { console.log(chalk2.yellow("Installation cancelled.")); return; } } } } console.log(chalk2.blue(`\u{1F4E6} Installing ${type} components...`)); const registry = await getTemplateRegistry(); const template = registry[type]; if (!template) { throw new Error(`Template not found for type: ${type}`); } await fs3.ensureDir(targetDir); console.log(chalk2.blue("\u{1F4C4} Copying component files...")); await copyTemplate(type, targetDir); console.log(chalk2.blue("\u{1F4CB} Updating dependencies...")); await updatePackageJson(template.dependencies, template.devDependencies); await createComponentReadme(type, targetDir); console.log(chalk2.green(`\u2705 ${type} components installed to ${options.dir}`)); showNextSteps(type); } async function createComponentReadme(type, targetDir) { const readmeContent = `# FeedInbox Components This directory contains FeedInbox ${type} components installed via the CLI. ## Usage \`\`\`typescript import { FeedbackWidget, NewsletterWidget, ContactWidget } from './' import { FeedInboxSDK } from '@feedinbox/sdk' // Initialize SDK const feedinbox = new FeedInboxSDK({ apiKey: 'fb_your_api_key' }) // Use components <FeedbackWidget apiKey="fb_your_api_key" onSuccess={(response) => console.log(response)} onError={(error) => console.error(error)} /> \`\`\` ## Customization These components are copied into your project, so you can: - Modify styling and behavior - Add your own props and features - Customize the UI to match your design system - Update dependencies as needed ## Components Included - **FeedbackWidget**: Collect user feedback with priority levels - **NewsletterWidget**: Newsletter subscription with consent management - **ContactWidget**: Contact form with validation ## Documentation Visit https://feedinbox.com/docs for complete documentation. `; await fs3.writeFile(path3.join(targetDir, "README.md"), readmeContent); } function showNextSteps(type) { console.log(chalk2.yellow("\n\u{1F4D6} Next steps:")); console.log("1. Install the SDK if not already installed:"); console.log(chalk2.cyan(" npm install @feedinbox/sdk")); if (type === "react-tailwind") { console.log("2. Make sure Tailwind CSS is configured in your project"); console.log("3. Import and use the components"); } else if (type === "react-shadcn") { console.log("2. Make sure shadcn/ui is configured in your project"); console.log("3. Install required shadcn components if not already installed"); console.log("4. Import and use the components"); } else { console.log("2. Import the CSS file in your app:"); console.log(chalk2.cyan(' import "./components/feedinbox/styles.css"')); console.log("3. Import and use the components"); } console.log("4. Configure your API key and start collecting feedback!"); } // src/commands/init.ts import path4 from "path"; import fs4 from "fs-extra"; import chalk3 from "chalk"; import inquirer2 from "inquirer"; async function initConfig() { const configPath = path4.join(process.cwd(), "feedinbox.config.json"); if (await fs4.pathExists(configPath)) { const { overwrite } = await inquirer2.prompt([ { type: "confirm", name: "overwrite", message: "FeedInbox config already exists. Overwrite?", default: false } ]); if (!overwrite) { console.log(chalk3.yellow("Configuration unchanged.")); return; } } const answers = await inquirer2.prompt([ { type: "input", name: "apiKey", message: "Enter your FeedInbox API key:", validate: (input) => { if (!input) return "API key is required"; if (!input.startsWith("fb_")) return 'API key must start with "fb_"'; return true; } }, { type: "input", name: "apiUrl", message: "Enter your API URL (optional):", default: "https://api.feedinbox.com" }, { type: "input", name: "workspaceId", message: "Enter your workspace ID (optional):" } ]); const config = { apiKey: answers.apiKey, apiUrl: answers.apiUrl, workspaceId: answers.workspaceId || void 0, version: "1.0.0", createdAt: (/* @__PURE__ */ new Date()).toISOString() }; await fs4.writeJson(configPath, config, { spaces: 2 }); console.log(chalk3.green("\u2705 Configuration saved to feedinbox.config.json")); console.log(chalk3.yellow("\u26A0\uFE0F Make sure to add feedinbox.config.json to your .gitignore")); } // src/commands/list.ts import chalk4 from "chalk"; function listTemplates() { console.log(chalk4.blue("\n\u{1F4CB} Available FeedInbox component types:\n")); console.log(chalk4.green("react-vanilla")); console.log(" React components with vanilla CSS"); console.log(" \u2022 Clean, customizable styling"); console.log(" \u2022 No external CSS framework required"); console.log(" \u2022 Perfect for custom design systems\n"); console.log(chalk4.green("react-tailwind")); console.log(" React components with Tailwind CSS"); console.log(" \u2022 Utility-first CSS approach"); console.log(" \u2022 Requires Tailwind CSS in your project"); console.log(" \u2022 Highly customizable with utilities\n"); console.log(chalk4.green("react-shadcn")); console.log(" React components with shadcn/ui"); console.log(" \u2022 Modern component library"); console.log(" \u2022 Requires shadcn/ui setup"); console.log(" \u2022 Beautiful, accessible components\n"); console.log(chalk4.yellow("Usage:")); console.log(" npx @feedinbox/cli add react-vanilla"); console.log(" npx @feedinbox/cli add react-tailwind"); console.log(" npx @feedinbox/cli add react-shadcn\n"); } // src/utils/project.ts import path5 from "path"; import fs5 from "fs-extra"; import chalk5 from "chalk"; async function validateProject() { var _a, _b, _c, _d, _e; const cwd = process.cwd(); const packageJsonPath = path5.join(cwd, "package.json"); if (!await fs5.pathExists(packageJsonPath)) { throw new Error("No package.json found. Please run this command in a Node.js project directory."); } const packageJson = await fs5.readJson(packageJsonPath); const hasReact = ((_a = packageJson.dependencies) == null ? void 0 : _a.react) || ((_b = packageJson.devDependencies) == null ? void 0 : _b.react) || ((_c = packageJson.peerDependencies) == null ? void 0 : _c.react); if (!hasReact) { console.log(chalk5.yellow("\u26A0\uFE0F React not detected in dependencies. Make sure this is a React project.")); } const hasTypeScript = ((_d = packageJson.dependencies) == null ? void 0 : _d.typescript) || ((_e = packageJson.devDependencies) == null ? void 0 : _e.typescript) || await fs5.pathExists(path5.join(cwd, "tsconfig.json")); if (!hasTypeScript) { console.log(chalk5.yellow("\u26A0\uFE0F TypeScript not detected. FeedInbox components are written in TypeScript.")); } console.log(chalk5.green("\u2705 Project validation passed")); } export { addComponents, getTemplateRegistry, initConfig, listTemplates, validateProject }; //# sourceMappingURL=index.mjs.map