phpxui 0.1.2 → 0.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,46 +1,48 @@
1
- # **phpxui‑cli** — Instant PHPXUI Component Generator 🚀
1
+ # **phpxui‑cli** — Instant PHPXUI Component Generator 🚀
2
2
 
3
- > **Generate fully‑typed PHPXUI components for Prisma PHP right from the terminal.**
4
- > ⚡ **Single component**  `npx phpxui add Alert`   |   🌌 **Whole library**  `npx phpxui add --all`
3
+ > **Generate fully‑typed PHPXUI components for Prisma PHP right from the terminal.**
4
+ > ⚡ **Add one** `npx phpxui add Alert` | 🌌 **Add all** `npx phpxui add --all` | 🔁 **Update installed** → `npx phpxui update`
5
5
 
6
6
  ---
7
7
 
8
- ## ✨ Features
8
+ ## ✨ Features
9
9
 
10
- | Feature | Details |
11
- | --------------------- | ------------------------------------------------------------------------------------------------------------ |
12
- | **Bulk install** | `--all` downloads every component in one shot. |
13
- | **Ready‑to‑use code** | Each file already contains the `$class` merge logic and `{$attributes}` placeholder for **Wave** reactivity. |
14
- | **Clean paths** | Files are written under `src/Lib/PHPXUI/FancyName.php` with OS‑agnostic separators. |
15
- | **Friendly output** | Clear green / red summary with relative paths only. |
16
- | **Automatic icons** | Core **PPIcons** (`x`, `chevron‑down`, `chevron‑right`) are installed on the very first run. |
10
+ | Feature | Details |
11
+ | ---------------------- | ---------------------------------------------------------------------------------------------------------------- |
12
+ | **Bulk install** | `--all` downloads every component in one shot. |
13
+ | **Update in place** | `update` scans your `outputDir` and re‑downloads every installed component (overwrite). |
14
+ | **Ready‑to‑use code** | Each file already contains the `$class` merge logic and `{$attributes}` placeholder for **Wave** reactivity. |
15
+ | **Clean paths** | Files are written under `src/Lib/PHPXUI/FancyName.php` with OS‑agnostic separators. |
16
+ | **Friendly output** | Clear green / red summary with relative paths only. |
17
+ | **Automatic icons** | Core **PPIcons** (`x`, `chevron‑down`, `chevron‑right`, etc.) are installed on the very first run. |
18
+ | **Tailwind bootstrap** | Ensures `tw-animate-css` and (on first run / missing file) writes `src/app/globals.css` for a sensible baseline. |
17
19
 
18
20
  ---
19
21
 
20
- ## 📦 Installation
22
+ ## 📦 Installation
21
23
 
22
24
  ```bash
23
25
  # Global
24
26
  npm install -g phpxui
25
27
 
26
- # Or as a dev‑dependency
28
+ # Or as a dev‑dependency
27
29
  npm install -D phpxui
28
30
  ```
29
31
 
30
- > Requires **Node 18+** and a Prisma PHP project (PHP 8.2+).
32
+ > Requires **Node 18+** and a Prisma PHP project (PHP 8.2+).
31
33
 
32
34
  ---
33
35
 
34
- ## 🚀 Quick Start
36
+ ## 🚀 Quick Start
35
37
 
36
38
  ```bash
37
- # Add a single component
39
+ # Add a single component
38
40
  npx phpxui add Alert
39
41
 
40
- # Add multiple components at once
42
+ # Add multiple components at once
41
43
  npx phpxui add Alert Dialog Badge
42
44
 
43
- # Add the entire component set
45
+ # Add the entire component set
44
46
  npx phpxui add --all
45
47
  ```
46
48
 
@@ -68,11 +70,13 @@ class Alert extends PHPX
68
70
  {
69
71
  public function render(): string
70
72
  {
71
- $attributes = $this->getAttributes();
72
73
  $class = $this->getMergeClasses();
74
+ $attributes = $this->getAttributes([
75
+ 'class' => $class,
76
+ ]);
73
77
 
74
78
  return <<<HTML
75
- <div {$attributes} class="alert {$class}">
79
+ <div {$attributes}>
76
80
  {$this->children}
77
81
  </div>
78
82
  HTML;
@@ -82,19 +86,93 @@ class Alert extends PHPX
82
86
 
83
87
  ---
84
88
 
85
- ## 🔧 CLI Options
89
+ ## 🔁 Updating Components
86
90
 
87
- | Flag / Argument | Description |
88
- | --------------- | -------------------------------------------------------- |
89
- | `<component …>` | One or more component names separated by space or comma. |
90
- | `--all` | Download the full catalogue in one request. |
91
- | `--force` | Overwrite existing files. |
91
+ ### Update everything you already installed
92
+
93
+ ```bash
94
+ npx phpxui update
95
+ ```
96
+
97
+ What it does:
98
+
99
+ - Reads your `phpxui.json` (creates it if missing)
100
+ - Resolves your `outputDir` (default: `src/Lib/PHPXUI`)
101
+ - Scans that folder for `*.php` files (e.g. `Alert.php`, `Dialog.php`)
102
+ - Re-downloads each matching component from the PHPXUI catalogue
103
+ - **Overwrites files automatically** (no `--force` required)
104
+
105
+ If you have no generated components yet, it will report:
106
+
107
+ - `⚠ No components found to update.`
108
+
109
+ ### Update a single component (targeted)
110
+
111
+ If you only want to refresh one component, use `add` with `--force`:
112
+
113
+ ```bash
114
+ npx phpxui add Alert --force
115
+ ```
116
+
117
+ ---
118
+
119
+ ## 🔧 CLI Usage and Options
120
+
121
+ ```bash
122
+ phpxui <command> [--all] [--force] <component…>
123
+ ```
124
+
125
+ ### Commands
126
+
127
+ | Command | Purpose |
128
+ | -------- | ---------------------------------------------------------------------------- |
129
+ | `add` | Generate one or more components by name, or the full catalogue with `--all`. |
130
+ | `update` | Update **all installed** components found in `outputDir` (overwrites). |
131
+
132
+ ### Flags / Arguments
133
+
134
+ | Flag / Argument | Description |
135
+ | --------------- | ---------------------------------------------------------------------------- |
136
+ | `<component …>` | One or more component names separated by space (or comma). Applies to `add`. |
137
+ | `--all` | Download the full catalogue in one request. Applies to `add`. |
138
+ | `--force` | Overwrite existing files. Applies to `add`. |
92
139
 
93
140
  > **Note:** The CLI automatically installs a default set of core icons (such as `x`, `chevron-down`, `chevron-right`) on first use. Extra icons are not yet selectable via `phpxui` directly.
94
141
 
95
142
  ---
96
143
 
97
- ## 🎨 Using Additional Icons
144
+ ## 🧩 Configuration (phpxui.json)
145
+
146
+ On first run, **phpxui‑cli** creates a `phpxui.json` in your project root. The most important fields are:
147
+
148
+ - `outputDir`: where PHPXUI components are written (default: `src/Lib/PHPXUI`)
149
+ - `psr4`: mapping hints for components and icons
150
+ - `iconsInstalled`: internal flag to avoid reinstalling the default icon set
151
+ - `tailwind.css`: where the base CSS should live (default: `src/app/globals.css`)
152
+
153
+ Example:
154
+
155
+ ```json
156
+ {
157
+ "outputDir": "src/Lib/PHPXUI",
158
+ "iconsInstalled": false,
159
+ "tailwind": {
160
+ "css": "src/app/globals.css",
161
+ "baseColor": "neutral",
162
+ "cssVariables": true,
163
+ "prefix": ""
164
+ },
165
+ "psr4": {
166
+ "Components": "src/Lib/PHPXUI/",
167
+ "Icons": "src/Lib/PPIcons/"
168
+ },
169
+ "iconLibrary": "ppicons"
170
+ }
171
+ ```
172
+
173
+ ---
174
+
175
+ ## 🎨 Using Additional Icons
98
176
 
99
177
  Need more icons? Use the **PPIcons** CLI directly:
100
178
 
@@ -102,35 +180,35 @@ Need more icons? Use the **PPIcons** CLI directly:
102
180
  npx ppicons add menu chevron-left arrow-right
103
181
  ```
104
182
 
105
- This will place the requested icons under `src/Lib/PPIcons` with full PHPXUI typings.
106
- Browse the complete icon catalogue and usage docs at **[https://ppicons.tsnc.tech/](https://ppicons.tsnc.tech/)**.
183
+ This will place the requested icons under `src/Lib/PPIcons` with full PHPXUI typings.
184
+ Browse the complete icon catalogue and usage docs at **https://ppicons.tsnc.tech/**.
107
185
 
108
186
  ---
109
187
 
110
- ## 📚 Documentation
188
+ ## 📚 Documentation
111
189
 
112
- Full guides and examples live at the [PHPXUI documentation site](https://phpxui.tsnc.tech/).
190
+ Full guides and examples live at the PHPXUI documentation site: **https://phpxui.tsnc.tech/**
113
191
 
114
192
  ---
115
193
 
116
- ## 💡 Contributing
194
+ ## 💡 Contributing
117
195
 
118
196
  We welcome contributions to improve **phpxui‑cli**. If you have ideas, find bugs, or want to add features, open an issue or submit a pull request.
119
197
 
120
198
  ---
121
199
 
122
- ## 📄 License
200
+ ## 📄 License
123
201
 
124
202
  `phpxui‑cli` is released under the MIT License. See `LICENSE` for details.
125
203
 
126
204
  ---
127
205
 
128
- ## 👤 Author
206
+ ## 👤 Author
129
207
 
130
- This project is developed and maintained by **TheSteelNinjaCode**, continuously pushing the boundaries of PHP development.
208
+ This project is developed and maintained by **The Steel Ninja Code**, continuously pushing the boundaries of PHP development.
131
209
 
132
210
  ---
133
211
 
134
- ## 📧 Contact
212
+ ## 📧 Contact
135
213
 
136
214
  Questions or feedback? Reach us at [thesteelninjacode@gmail.com](mailto:thesteelninjacode@gmail.com) — we’d love to hear from you!
@@ -1,25 +1 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.installIcons = installIcons;
7
- const child_process_1 = require("child_process");
8
- const chalk_1 = __importDefault(require("chalk"));
9
- const load_config_1 = require("../utils/load-config");
10
- async function installIcons(iconList, config) {
11
- try {
12
- console.log(chalk_1.default.blue("📦 Installing ppicons CLI..."));
13
- (0, child_process_1.execSync)("npm install -g ppicons", { stdio: "inherit" });
14
- const args = iconList.join(" ");
15
- console.log(chalk_1.default.blue(`✨ Installing default icons: ${args}`));
16
- (0, child_process_1.execSync)(`npx ppicons add ${args}`, { stdio: "inherit" });
17
- console.log(chalk_1.default.green("✔ Icons installed in src/Lib/PPIcons"));
18
- config.iconsInstalled = true;
19
- (0, load_config_1.savePhpXUIConfig)(config); // ⬅️ persist change
20
- }
21
- catch (err) {
22
- console.error(chalk_1.default.red("✖ Failed to install icons:"), err.message);
23
- process.exit(1);
24
- }
25
- }
1
+ import{execSync}from"child_process";import chalk from"chalk";import{savePhpXUIConfig}from"../utils/load-config.js";export async function installIcons(o,n){try{console.log(chalk.blue("📦 Installing ppicons CLI...")),execSync("npm install -g ppicons",{stdio:"inherit"});const c=o.join(" ");console.log(chalk.blue(`✨ Installing default icons: ${c}`)),execSync(`npx ppicons add ${c}`,{stdio:"inherit"}),console.log(chalk.green("✔ Icons installed in src/Lib/PPIcons")),n.iconsInstalled=!0,savePhpXUIConfig(n)}catch(o){console.error(chalk.red("✖ Failed to install icons:"),o.message),process.exit(1)}}
@@ -1,27 +1 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.copyTailwindCss = copyTailwindCss;
7
- const fs_extra_1 = __importDefault(require("fs-extra"));
8
- const path_1 = __importDefault(require("path"));
9
- /**
10
- * Copy dist/css/tailwind.css into src/app/css/tailwind.css.
11
- *
12
- * @param force Overwrite even if the target exists.
13
- * @returns true → file was copied / overwritten
14
- * false → skipped (already exists and !force)
15
- */
16
- function copyTailwindCss(force = false) {
17
- // Path to the CSS bundled with the CLI
18
- const source = path_1.default.resolve(__dirname, "../css/globals.css");
19
- // Path inside the user’s project
20
- const target = path_1.default.resolve(process.cwd(), "src/app/globals.css");
21
- if (!force && fs_extra_1.default.existsSync(target)) {
22
- return false; // skip quietly
23
- }
24
- fs_extra_1.default.ensureDirSync(path_1.default.dirname(target));
25
- fs_extra_1.default.copyFileSync(source, target);
26
- return true;
27
- }
1
+ import fs from"fs-extra";import path from"path";import{fileURLToPath}from"url";const __filename=fileURLToPath(import.meta.url),__dirname=path.dirname(__filename);export function copyTailwindCss(s=!1){const e=path.resolve(__dirname,"../css/globals.css"),r=path.resolve(process.cwd(),"src/app/globals.css");return!(!s&&fs.existsSync(r))&&(fs.ensureDirSync(path.dirname(r)),fs.copyFileSync(e,r),!0)}
@@ -1,32 +1 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.ensurePackageInstalled = ensurePackageInstalled;
7
- const fs_extra_1 = __importDefault(require("fs-extra"));
8
- const child_process_1 = require("child_process");
9
- /**
10
- * Ensures a package is present in dependencies/devDependencies.
11
- * Installs it with `npm i -D <pkg>` if missing.
12
- *
13
- * @param pkg Package name, e.g. "tw-animate-css"
14
- * @param quiet If true, suppress install output.
15
- * @returns true → package was installed now
16
- * false → package already present
17
- */
18
- function ensurePackageInstalled(pkg, quiet = false) {
19
- const pkgJsonPath = "package.json";
20
- if (!fs_extra_1.default.existsSync(pkgJsonPath))
21
- return false;
22
- const pkgJson = fs_extra_1.default.readJsonSync(pkgJsonPath);
23
- const hasIt = (pkgJson.dependencies && pkgJson.dependencies[pkg]) ||
24
- (pkgJson.devDependencies && pkgJson.devDependencies[pkg]);
25
- if (hasIt)
26
- return false;
27
- const cmd = `npm i -D ${pkg}`;
28
- if (!quiet)
29
- console.log(`⬇ Installing missing package: ${pkg} …`);
30
- (0, child_process_1.execSync)(cmd, { stdio: quiet ? "ignore" : "inherit" });
31
- return true;
32
- }
1
+ import fs from"fs-extra";import{execSync}from"child_process";export function ensurePackageInstalled(e,n=!1){const s="package.json";if(!fs.existsSync(s))return!1;const c=fs.readJsonSync(s);if(c.dependencies&&c.dependencies[e]||c.devDependencies&&c.devDependencies[e])return!1;const i=`npm i -D ${e}`;return n||console.log(`⬇ Installing missing package: ${e} …`),execSync(i,{stdio:n?"ignore":"inherit"}),!0}
@@ -1,27 +1 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.generateComponent = generateComponent;
7
- const node_fetch_1 = __importDefault(require("node-fetch"));
8
- const write_component_1 = require("./write-component");
9
- const path_1 = __importDefault(require("path"));
10
- const SINGLE_URL = "https://phpxui.tsnc.tech/cli";
11
- async function generateComponent(componentName, targetDir, force = false) {
12
- const url = `${SINGLE_URL}?component=${encodeURIComponent(componentName)}`;
13
- const res = await (0, node_fetch_1.default)(url);
14
- if (!res.ok) {
15
- throw new Error(`Could not fetch "${componentName}": ${res.status} – ${url}`);
16
- }
17
- // El endpoint puede devolver un objeto (uno) o un array (muchos)
18
- const json = await res.json();
19
- const components = Array.isArray(json) ? json : [json];
20
- const writtenPaths = [];
21
- for (const cmp of components) {
22
- // Cada objeto contiene { name, content }
23
- const filePath = await (0, write_component_1.writeComponent)(cmp, targetDir, force);
24
- writtenPaths.push(path_1.default.relative(process.cwd(), filePath));
25
- }
26
- return writtenPaths;
27
- }
1
+ import fetch from"node-fetch";import{writeComponent}from"./write-component.js";import path from"path";const SINGLE_URL="https://phpxui.tsnc.tech/cli";export async function generateComponent(t,o,n=!1){const e=`${SINGLE_URL}?component=${encodeURIComponent(t)}`,r=await fetch(e);if(!r.ok)throw new Error(`Could not fetch "${t}": ${r.status} – ${e}`);const c=await r.json(),p=Array.isArray(c)?c:[c],s=[];for(const t of p){const e=await writeComponent(t,o,n);s.push(path.relative(process.cwd(),e))}return s}
@@ -1,42 +1 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.generateAllComponents = generateAllComponents;
7
- const node_fetch_1 = __importDefault(require("node-fetch"));
8
- const write_component_1 = require("./write-component");
9
- /** Endpoint that returns every PHPXUI component */
10
- const BULK_URL = "https://phpxui.tsnc.tech/cli?component=all";
11
- /**
12
- * Download all components and write them to disk.
13
- *
14
- * @param targetDir Destination folder (e.g. "./src/Lib/PHPXUI")
15
- * @param force Overwrite if file exists (default: false)
16
- */
17
- async function generateAllComponents(targetDir, force = false) {
18
- const res = await (0, node_fetch_1.default)(BULK_URL);
19
- if (!res.ok) {
20
- throw new Error(`Could not fetch component list: ${res.status} – ${BULK_URL}`);
21
- }
22
- // Backend returns [{ name, content }]
23
- const components = (await res.json());
24
- console.log(`➡ Received ${components.length} components. Generating…`);
25
- const ok = [];
26
- const fail = [];
27
- /* Small concurrency queue to avoid hammering the FS */
28
- const BATCH = 10;
29
- let queue = [];
30
- for (const cmp of components) {
31
- const job = (0, write_component_1.writeComponent)(cmp, targetDir, force)
32
- .then((file) => ok.push(file))
33
- .catch((e) => fail.push(`${cmp.name}: ${e.message}`));
34
- queue.push(job);
35
- if (queue.length >= BATCH) {
36
- await Promise.allSettled(queue);
37
- queue = [];
38
- }
39
- }
40
- await Promise.allSettled(queue);
41
- return { ok, fail };
42
- }
1
+ import fetch from"node-fetch";import{writeComponent}from"./write-component.js";const BULK_URL="https://phpxui.tsnc.tech/cli?component=all";export async function generateAllComponents(t,e=!1){const o=await fetch(BULK_URL);if(!o.ok)throw new Error(`Could not fetch component list: ${o.status} – ${BULK_URL}`);const n=await o.json();console.log(`➡ Received ${n.length} components. Generating…`);const s=[],c=[];let a=[];for(const o of n){const n=writeComponent(o,t,e).then(t=>s.push(t)).catch(t=>c.push(`${o.name}: ${t.message}`));a.push(n),a.length>=10&&(await Promise.allSettled(a),a=[])}return await Promise.allSettled(a),{ok:s,fail:c}}
@@ -1,26 +1 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.writeComponent = writeComponent;
7
- const fs_extra_1 = __importDefault(require("fs-extra"));
8
- const path_1 = __importDefault(require("path"));
9
- /**
10
- * Writes a PHPXUI component file to disk.
11
- *
12
- * @param componentJson { name: string; content: string }
13
- * @param targetDir Destination folder
14
- * @param force Overwrite if file exists
15
- * @returns Path of the written file
16
- */
17
- async function writeComponent(componentJson, targetDir, force = false) {
18
- const filePath = path_1.default.join(targetDir, `${componentJson.name}.php`);
19
- if (!force && (await fs_extra_1.default.pathExists(filePath))) {
20
- // Skip quietly
21
- return filePath;
22
- }
23
- await fs_extra_1.default.ensureDir(path_1.default.dirname(filePath));
24
- await fs_extra_1.default.writeFile(filePath, componentJson.content, "utf8");
25
- return filePath;
26
- }
1
+ import fs from"fs-extra";import path from"path";export async function writeComponent(t,a,i=!1){const n=path.join(a,`${t.name}.php`);return!i&&await fs.pathExists(n)||(await fs.ensureDir(path.dirname(n)),await fs.writeFile(n,t.content,"utf8")),n}
package/dist/index.js CHANGED
@@ -1,121 +1,2 @@
1
1
  #!/usr/bin/env node
2
- "use strict";
3
- var __importDefault = (this && this.__importDefault) || function (mod) {
4
- return (mod && mod.__esModule) ? mod : { "default": mod };
5
- };
6
- Object.defineProperty(exports, "__esModule", { value: true });
7
- const prompts_1 = __importDefault(require("prompts"));
8
- const chalk_1 = __importDefault(require("chalk"));
9
- const path_1 = __importDefault(require("path"));
10
- const php_component_1 = require("./generators/php-component");
11
- const php_components_bulk_1 = require("./generators/php-components-bulk");
12
- const ensure_package_1 = require("./generators/ensure-package");
13
- const copy_tailwind_1 = require("./generators/copy-tailwind");
14
- const load_config_1 = require("./utils/load-config");
15
- const icons_1 = require("./commands/icons");
16
- const CORE_COMPONENTS = ["Slot", "Portal"];
17
- (async () => {
18
- const args = process.argv.slice(2);
19
- const [command, ...rest] = args;
20
- if (command !== "add") {
21
- console.log(chalk_1.default.blue("Usage: phpxui add [--all] [--force] <component…>"));
22
- process.exit(0);
23
- }
24
- const flags = { all: false, force: false };
25
- const names = [];
26
- for (let i = 0; i < rest.length; i++) {
27
- const tok = rest[i];
28
- switch (tok) {
29
- case "--all":
30
- flags.all = true;
31
- break;
32
- case "--force":
33
- flags.force = true;
34
- break;
35
- default:
36
- names.push(tok);
37
- }
38
- }
39
- /* 2) Load config + detect first run */
40
- const { config, isFirstRun } = (0, load_config_1.loadPhpXUIConfig)();
41
- if (!config.iconsInstalled) {
42
- await (0, icons_1.installIcons)([
43
- "chevron-down",
44
- "x",
45
- "chevron-right",
46
- "ellipsis",
47
- "chevron-left",
48
- "arrow-left",
49
- "arrow-right",
50
- "check",
51
- "chevrons-up-down",
52
- "search",
53
- "circle",
54
- "calendar",
55
- "minus",
56
- "chevron-up",
57
- "panel-left",
58
- ], config);
59
- }
60
- /* 3) Housekeeping */
61
- (0, ensure_package_1.ensurePackageInstalled)("tw-animate-css");
62
- // Tailwind base CSS: only forced on first run
63
- const cssUpdated = (0, copy_tailwind_1.copyTailwindCss)(isFirstRun /* ignore flags.force here */);
64
- if (cssUpdated) {
65
- const relCss = path_1.default
66
- .relative(process.cwd(), "src/app/globals.css")
67
- .replace(/\\/g, "/");
68
- console.log(chalk_1.default.green(isFirstRun
69
- ? `✔ Installed base Tailwind CSS → ${relCss}`
70
- : `✔ Added Tailwind CSS (missing) → ${relCss}`));
71
- }
72
- /* 4) Resolve output directory */
73
- const targetDir = path_1.default.resolve(config.outputDir || "src/Lib/PHPXUI");
74
- try {
75
- // Overwrite policy
76
- const componentForce = isFirstRun || flags.force;
77
- /* 5) Bulk mode */
78
- if (flags.all) {
79
- const { ok, fail } = await (0, php_components_bulk_1.generateAllComponents)(targetDir, componentForce);
80
- console.log(chalk_1.default.green(`\n✔ Generated ${ok.length} components in ${path_1.default.relative(process.cwd(), targetDir)}`));
81
- if (fail.length) {
82
- console.log(chalk_1.default.red(`✖ ${fail.length} failures:`));
83
- fail.forEach((m) => console.log(" •", m));
84
- }
85
- process.exit(fail.length ? 1 : 0);
86
- }
87
- /* 6) Interactive prompt if no names given */
88
- if (names.length === 0) {
89
- const { componentList } = await (0, prompts_1.default)({
90
- type: "text",
91
- name: "componentList",
92
- message: "Which components do you want to add? (space- or comma-separated)",
93
- validate: (v) => (v.trim() ? true : "Enter at least one name"),
94
- });
95
- names.push(...componentList.split(/[\s,]+/));
96
- }
97
- /* 6.5) Ensure core components first on first-run (unless --all) */
98
- if (isFirstRun && !flags.all) {
99
- for (const core of CORE_COMPONENTS) {
100
- const hasCore = names.some((n) => n.toLowerCase() === core.toLowerCase());
101
- if (!hasCore) {
102
- // Put each core at the front in the declared order:
103
- names.unshift(core);
104
- }
105
- }
106
- }
107
- /* 7) Generate each requested component */
108
- for (const name of names) {
109
- const saved = await (0, php_component_1.generateComponent)(name, targetDir, componentForce);
110
- const paths = Array.isArray(saved) ? saved : [saved];
111
- for (const abs of paths) {
112
- const rel = path_1.default.relative(process.cwd(), abs).replace(/\\/g, "/");
113
- console.log(chalk_1.default.green(`✔ ${name} → ${rel}`));
114
- }
115
- }
116
- }
117
- catch (err) {
118
- console.error(chalk_1.default.red("✖ Error:"), err.message);
119
- process.exit(1);
120
- }
121
- })();
2
+ import prompts from"prompts";import chalk from"chalk";import path from"path";import{generateComponent}from"./generators/php-component.js";import{generateAllComponents}from"./generators/php-components-bulk.js";import{ensurePackageInstalled}from"./generators/ensure-package.js";import{copyTailwindCss}from"./generators/copy-tailwind.js";import{loadPhpXUIConfig}from"./utils/load-config.js";import{installIcons}from"./commands/icons.js";import{getInstalledComponents}from"./utils/scan-installed.js";const CORE_COMPONENTS=["Slot","Portal"];(async()=>{const o=process.argv.slice(2),[e,...s]=o;"add"!==e&&"update"!==e&&(console.log(chalk.blue("Usage: phpxui <add|update> [--all] [--force] <component…>")),process.exit(0));const t={all:!1,force:!1},n=[];for(let o=0;o<s.length;o++){const e=s[o];switch(e){case"--all":t.all=!0;break;case"--force":t.force=!0;break;default:n.push(e)}}const{config:a,isFirstRun:l}=loadPhpXUIConfig();a.iconsInstalled||await installIcons(["chevron-down","x","chevron-right","ellipsis","chevron-left","arrow-left","arrow-right","check","chevrons-up-down","search","circle","calendar","minus","chevron-up","panel-left"],a),ensurePackageInstalled("tw-animate-css");if(copyTailwindCss(l)){const o=path.relative(process.cwd(),"src/app/globals.css").replace(/\\/g,"/");console.log(chalk.green(l?`✔ Installed base Tailwind CSS → ${o}`:`✔ Added Tailwind CSS (missing) → ${o}`))}const r=path.resolve(a.outputDir||"src/Lib/PHPXUI");try{if("update"===e){console.log(chalk.blue(`🔎 Scanning for installed components in ${a.outputDir}...`));const o=getInstalledComponents(r);0===o.length&&(console.log(chalk.yellow("⚠ No components found to update.")),process.exit(0)),console.log(chalk.blue(`✨ Found ${o.length} components. Updating...`));const e=[],s=[];for(const t of o)try{const o=await generateComponent(t,r,!0);(Array.isArray(o)?o:[o]).forEach(o=>e.push(path.basename(o))),console.log(chalk.green(`✔ Updated ${t}`))}catch(o){s.push(`${t}: ${o.message}`),console.log(chalk.red(`✖ Failed to update ${t}`))}console.log(chalk.green(`\n✔ Successfully updated ${e.length} components.`)),s.length>0&&(console.log(chalk.red(`✖ ${s.length} failures:`)),s.forEach(o=>console.log(` - ${o}`))),process.exit(0)}const o=l||t.force;if(t.all){const{fail:e}=await generateAllComponents(r,o);process.exit(e.length?1:0)}if(0===n.length){const{componentList:o}=await prompts({type:"text",name:"componentList",message:"Which components do you want to add? (space- or comma-separated)",validate:o=>!!o.trim()||"Enter at least one name"});n.push(...o.split(/[\s,]+/))}if(l&&!t.all)for(const o of CORE_COMPONENTS){n.some(e=>e.toLowerCase()===o.toLowerCase())||n.unshift(o)}for(const e of n){const s=await generateComponent(e,r,o),t=Array.isArray(s)?s:[s];for(const o of t){const s=path.relative(process.cwd(),o).replace(/\\/g,"/");console.log(chalk.green(`✔ ${e} → ${s}`))}}}catch(o){console.error(chalk.red("✖ Error:"),o.message),process.exit(1)}})();
@@ -1,41 +1 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.loadPhpXUIConfig = loadPhpXUIConfig;
7
- exports.savePhpXUIConfig = savePhpXUIConfig;
8
- const fs_1 = __importDefault(require("fs"));
9
- const path_1 = __importDefault(require("path"));
10
- const defaultConfig = {
11
- style: "new-york",
12
- force: false,
13
- outputDir: "src/Lib/PHPXUI",
14
- iconsInstalled: false,
15
- tailwind: {
16
- css: "src/app/globals.css",
17
- baseColor: "neutral",
18
- cssVariables: true,
19
- prefix: "",
20
- },
21
- psr4: {
22
- Components: "src/Lib/PHPXUI/",
23
- Icons: "src/Lib/PPIcons/",
24
- },
25
- iconLibrary: "ppicons",
26
- };
27
- // ⬇️ CHANGED: return { config, isFirstRun }
28
- function loadPhpXUIConfig() {
29
- const configPath = path_1.default.resolve("phpxui.json");
30
- const existed = fs_1.default.existsSync(configPath);
31
- if (!existed) {
32
- fs_1.default.writeFileSync(configPath, JSON.stringify(defaultConfig, null, 2));
33
- console.log("📦 Created default phpxui.json");
34
- }
35
- const content = fs_1.default.readFileSync(configPath, "utf-8");
36
- return { config: JSON.parse(content), isFirstRun: !existed };
37
- }
38
- function savePhpXUIConfig(config) {
39
- const configPath = path_1.default.resolve("phpxui.json");
40
- fs_1.default.writeFileSync(configPath, JSON.stringify(config, null, 2));
41
- }
1
+ import fs from"fs";import path from"path";const defaultConfig={style:"new-york",force:!1,outputDir:"src/Lib/PHPXUI",iconsInstalled:!1,tailwind:{css:"src/app/globals.css",baseColor:"neutral",cssVariables:!0,prefix:""},psr4:{Components:"src/Lib/PHPXUI/",Icons:"src/Lib/PPIcons/"},iconLibrary:"ppicons"};export function loadPhpXUIConfig(){const s=path.resolve("phpxui.json"),o=fs.existsSync(s);o||(fs.writeFileSync(s,JSON.stringify(defaultConfig,null,2)),console.log("📦 Created default phpxui.json"));const n=fs.readFileSync(s,"utf-8");return{config:JSON.parse(n),isFirstRun:!o}}export function savePhpXUIConfig(s){const o=path.resolve("phpxui.json");fs.writeFileSync(o,JSON.stringify(s,null,2))}
@@ -0,0 +1 @@
1
+ import fs from"fs-extra";import path from"path";export function getInstalledComponents(t){if(!fs.existsSync(t))return[];return fs.readdirSync(t).filter(t=>t.endsWith(".php")).map(t=>path.basename(t,".php"))}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "phpxui",
3
- "version": "0.1.2",
3
+ "version": "0.1.4",
4
4
  "description": "A package for generating Prisma PHP components with a CLI interface.",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -23,7 +23,7 @@
23
23
  ],
24
24
  "author": "Jefferson Abraham Omier <thesteelninjacode@gmail.com>",
25
25
  "license": "MIT",
26
- "type": "commonjs",
26
+ "type": "module",
27
27
  "devDependencies": {
28
28
  "@types/fs-extra": "^11.0.4",
29
29
  "@types/node": "^24.0.13",