uix-ui 0.1.1 → 0.2.0

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
@@ -19,4 +19,12 @@ import { Button } from "@/components/ui/button";
19
19
  Dark mode: `<html data-theme="dark">`. Options: `--overwrite` (add), `--no-install` (print the install command
20
20
  instead of running it), `--registry <url|folder>` (init).
21
21
 
22
+ UIX Pro (marketing blocks, nine visual styles, 210 more themes): set your key, then add them by name.
23
+
24
+ ```bash
25
+ export UIX_LICENSE=<your key>
26
+ npx uix-ui@latest add hero pricing-card skins
27
+ npx uix-ui@latest theme acid-prompt
28
+ ```
29
+
22
30
  Docs, live components and all 42 themes: https://uixdesign.pagestro.com/ui · Source: https://github.com/mdrakibshekh/uix-ui · MIT
package/bin/uix-ui.mjs CHANGED
@@ -15,7 +15,8 @@ const HELP = `uix-ui: UIX components and themes for React + Tailwind v4
15
15
 
16
16
  --overwrite replace files that already exist (add)
17
17
  --no-install don't run the package manager, just print the command
18
- Pro items: set UIX_LICENSE=<your key> and add @uix-pro/<name>.`;
18
+ UIX Pro: set UIX_LICENSE=<your key>, then add Pro items by name (hero, pricing-card, skins…) or switch to a
19
+ Pro theme (npx uix-ui theme acid-prompt). \`list\` shows them all.`;
19
20
 
20
21
  const cwd = process.cwd();
21
22
  const argv = process.argv.slice(2);
@@ -54,28 +55,56 @@ function source(cfg, name) {
54
55
  return { ns, item, url: url.replace('{name}', item), headers: Object.fromEntries(Object.entries(headers).map(([k, v]) => [k, env(v)])) };
55
56
  }
56
57
 
58
+ const PRICING = 'https://uixdesign.pagestro.com/pricing';
59
+ const missing = (src) => Object.assign(new Error(`"${src.item}" is not in the registry (${src.url}).`), { missing: true });
60
+
57
61
  async function load(src) {
58
62
  if (!/^https?:/.test(src.url)) {
59
- if (!existsSync(src.url)) die(`"${src.item}" is not in the registry (${src.url}).`);
63
+ if (!existsSync(src.url)) throw missing(src);
60
64
  return JSON.parse(readFileSync(src.url, 'utf8'));
61
65
  }
62
66
  const res = await fetch(src.url, { headers: src.headers });
63
- if (res.status === 401 || res.status === 403) die(`"${src.item}" is a UIX Pro item. Set UIX_LICENSE to your key (https://uixdesign.pagestro.com/pricing).`);
67
+ if (res.status === 401) die(process.env.UIX_LICENSE ? `UIX_LICENSE is set, but that key wasn't found. Check it in your UIX account (${PRICING}).` : `${src.item.startsWith('theme-') ? `The "${src.item.slice(6)}" theme` : `"${src.item}"`} is part of UIX Pro. Set UIX_LICENSE to your key (${PRICING}).`);
68
+ if (res.status === 403) die(`"${src.item}" needs an active UIX Pro licence; this key's plan has ended (${PRICING}).`);
69
+ if (res.status === 404) throw missing(src);
64
70
  if (!res.ok) die(`"${src.item}" could not be loaded (${res.status} from ${src.url}).`);
65
71
  return res.json();
66
72
  }
67
73
 
74
+ /** The Pro index (names only, no key needed), or null when there is no Pro registry. */
75
+ let proIndex;
76
+ async function loadProIndex(cfg) {
77
+ if (proIndex !== undefined) return proIndex;
78
+ if (!cfg.registries?.['@uix-pro']) return (proIndex = null);
79
+ const ps = source(cfg, '@uix-pro/x');
80
+ return (proIndex = await load({ ...ps, item: 'registry.json', url: ps.url.replace(/\/x\.json$/, '/registry.json'), headers: {} }).catch(() => null));
81
+ }
82
+
83
+ /** A bare name that the free registry doesn't have is looked up in Pro (`hero` → `@uix-pro/hero`). */
84
+ async function loadAny(cfg, src) {
85
+ try { return { src, it: await load(src) }; } catch (e) {
86
+ if (!e.missing || src.ns !== '@uix') throw e;
87
+ const index = await loadProIndex(cfg);
88
+ if (!index?.items.some(i => i.name === src.item)) throw Object.assign(new Error(`"${src.item.replace(/^theme-/, '')}" is not a uix-ui component or theme. See the list: npx uix-ui list`), { missing: true });
89
+ const pro = source(cfg, `@uix-pro/${src.item}`);
90
+ return { src: pro, it: await load(pro) };
91
+ }
92
+ }
93
+
68
94
  /** Loads the items and everything they depend on, dependencies first. */
69
95
  async function resolveAll(cfg, list) {
70
96
  const seen = new Map();
71
97
  const visit = async (name) => {
72
- const src = source(cfg, name);
98
+ let src = source(cfg, name);
73
99
  const key = `${src.ns}/${src.item}`;
74
100
  if (seen.has(key)) return;
75
101
  seen.set(key, null);
76
- const it = await load(src);
102
+ const bare = !name.startsWith('@');
103
+ const got = bare ? await loadAny(cfg, src) : { src, it: await load(src) };
104
+ const it = got.it;
105
+ if (got.src !== src) { seen.delete(key); src = got.src; seen.set(`${src.ns}/${src.item}`, null); }
77
106
  for (const d of it.registryDependencies ?? []) await visit(d.startsWith('@') ? d : `${src.ns}/${d}`);
78
- seen.delete(key); seen.set(key, it);
107
+ seen.delete(`${src.ns}/${src.item}`); seen.set(`${src.ns}/${src.item}`, it);
79
108
  };
80
109
  for (const n of list) await visit(n);
81
110
  return [...seen.values()];
@@ -102,6 +131,20 @@ function place(cfg, items, overwrite) {
102
131
  write(file, code);
103
132
  say(` wrote ${shown}`);
104
133
  }
134
+ for (const it of items) for (const f of it.files) if (/\.css$/.test(f.path) && !/(^|\/)uix\.css$/.test(f.path)) importCss(cfg, target(cfg, f));
135
+ }
136
+
137
+ /** Adds `@import "<file>";` to the app's main CSS, after the theme import (visual styles, backdrops). */
138
+ function importCss(cfg, file) {
139
+ const cssFile = join(cwd, cfg.tailwind?.css ?? 'src/index.css');
140
+ if (!existsSync(cssFile)) return;
141
+ let src = readFileSync(cssFile, 'utf8');
142
+ const imp = `@import "${rel(cssFile, file)}";`;
143
+ if (src.includes(imp)) return;
144
+ const last = [...src.matchAll(/@import [^;\n]+;?/g)].pop(); // after the theme and any earlier style sheets
145
+ src = last ? src.slice(0, last.index + last[0].length) + `\n${imp}` + src.slice(last.index + last[0].length) : `${imp}\n${src}`;
146
+ write(cssFile, src);
147
+ say(` updated ${relative(cwd, cssFile)}`);
105
148
  }
106
149
 
107
150
  function install(items) {
@@ -192,7 +235,12 @@ async function main() {
192
235
  const index = await load({ ...src, item: 'registry.json', url: src.url.replace(/\/r\/x\.json$/, '/registry.json') });
193
236
  const comps = index.items.filter(i => i.type === 'registry:ui' && i.name !== 'icons').map(i => i.name);
194
237
  const themes = index.items.filter(i => i.name.startsWith('theme')).map(i => i.name === 'theme' ? 'uix' : i.name.slice(6));
195
- return say(`Components (${comps.length}): ${comps.join(', ')}\n\nThemes (${themes.length}): ${themes.join(', ')}`);
238
+ say(`Components (${comps.length}): ${comps.join(', ')}\n\nThemes (${themes.length}): ${themes.join(', ')}`);
239
+ const pro = await loadProIndex(cfg);
240
+ if (!pro) return;
241
+ const blocks = pro.items.filter(i => !i.name.startsWith('theme-')).map(i => i.name);
242
+ const proThemes = pro.items.filter(i => i.name.startsWith('theme-')).map(i => i.name.slice(6));
243
+ return say(`\nUIX Pro, with UIX_LICENSE (${PRICING}):\n Blocks and styles (${blocks.length}): ${blocks.join(', ')}\n Themes (${proThemes.length}): ${proThemes.join(', ')}`);
196
244
  }
197
245
  die(`unknown command "${cmd}".\n\n${HELP}`);
198
246
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "uix-ui",
3
- "version": "0.1.1",
3
+ "version": "0.2.0",
4
4
  "description": "Add UIX components and themes to your React + Tailwind app: npx uix-ui init.",
5
5
  "license": "MIT",
6
6
  "type": "module",