cronus-ui 0.6.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/LICENSE +21 -0
- package/README.md +90 -0
- package/dist/commands/add-page.d.ts +108 -0
- package/dist/commands/add-page.js +642 -0
- package/dist/commands/add.d.ts +9 -0
- package/dist/commands/add.js +114 -0
- package/dist/commands/ai.d.ts +14 -0
- package/dist/commands/ai.js +69 -0
- package/dist/commands/compose.d.ts +82 -0
- package/dist/commands/compose.js +403 -0
- package/dist/commands/diff.d.ts +8 -0
- package/dist/commands/diff.js +55 -0
- package/dist/commands/init.d.ts +9 -0
- package/dist/commands/init.js +53 -0
- package/dist/commands/list.d.ts +7 -0
- package/dist/commands/list.js +28 -0
- package/dist/commands/theme.d.ts +23 -0
- package/dist/commands/theme.js +735 -0
- package/dist/commands/upgrade.d.ts +51 -0
- package/dist/commands/upgrade.js +840 -0
- package/dist/compose/data-slots.d.ts +71 -0
- package/dist/compose/data-slots.js +104 -0
- package/dist/compose/manifest.d.ts +90 -0
- package/dist/compose/manifest.js +224 -0
- package/dist/compose/plan.d.ts +164 -0
- package/dist/compose/plan.js +506 -0
- package/dist/compose/preview.d.ts +10 -0
- package/dist/compose/preview.js +48 -0
- package/dist/compose/reload.d.ts +56 -0
- package/dist/compose/reload.js +138 -0
- package/dist/compose/render.d.ts +123 -0
- package/dist/compose/render.js +404 -0
- package/dist/compose/templates.d.ts +22 -0
- package/dist/compose/templates.js +76 -0
- package/dist/compose.d.ts +10 -0
- package/dist/compose.js +8 -0
- package/dist/config.d.ts +94 -0
- package/dist/config.js +38 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +184 -0
- package/dist/registry.d.ts +59 -0
- package/dist/registry.js +96 -0
- package/dist/utils.d.ts +72 -0
- package/dist/utils.js +186 -0
- package/package.json +68 -0
- package/templates/apps/chat.json +44 -0
- package/templates/apps/finance.json +44 -0
- package/templates/apps/landing-agency.json +31 -0
- package/templates/apps/landing-agents.json +32 -0
- package/templates/apps/landing-broadcast.json +29 -0
- package/templates/apps/landing-care.json +28 -0
- package/templates/apps/landing-coverage.json +23 -0
- package/templates/apps/landing-docs.json +29 -0
- package/templates/apps/landing-glass.json +28 -0
- package/templates/apps/landing-ops.json +29 -0
- package/templates/apps/landing-premium.json +31 -0
- package/templates/apps/landing-secure.json +31 -0
- package/templates/apps/landing-shop.json +27 -0
- package/templates/apps/landing-studio.json +30 -0
- package/templates/apps/landing.json +23 -0
- package/templates/apps/mail.json +44 -0
- package/templates/apps/saas.json +64 -0
- package/templates/apps/store.json +75 -0
package/dist/utils.d.ts
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import type { CronusUIConfig } from "./config.js";
|
|
2
|
+
import type { RegistryItem } from "./registry.js";
|
|
3
|
+
export declare const log: {
|
|
4
|
+
info: (msg: string) => void;
|
|
5
|
+
ok: (msg: string) => void;
|
|
6
|
+
warn: (msg: string) => void;
|
|
7
|
+
err: (msg: string) => void;
|
|
8
|
+
step: (msg: string) => void;
|
|
9
|
+
title: (msg: string) => void;
|
|
10
|
+
};
|
|
11
|
+
export type PackageManager = "bun" | "pnpm" | "yarn" | "npm";
|
|
12
|
+
export declare function detectPackageManager(cwd: string): PackageManager;
|
|
13
|
+
export declare function installArgs(pm: PackageManager, deps: string[]): string[];
|
|
14
|
+
export declare function runInstall(pm: PackageManager, deps: string[], cwd: string): Promise<void>;
|
|
15
|
+
/**
|
|
16
|
+
* Rewrite a component's canonical specifiers to the consumer's aliases:
|
|
17
|
+
* "../lib/cn.js" → `${aliases.lib}/cn`
|
|
18
|
+
* "../lib/demo-store.js" → `${aliases.lib}/demo-store`
|
|
19
|
+
* "./button.js" → `${aliases.ui}/button`
|
|
20
|
+
* The `../lib/<name>.js` rule is generalized (F3) so any shared `registry:lib`
|
|
21
|
+
* a block depends on — `cn`, `demo-store`, `demo-saas`, … — rewrites to the
|
|
22
|
+
* consumer's `lib` alias, not just `cn`. npm imports are left untouched.
|
|
23
|
+
*/
|
|
24
|
+
export declare function rewriteImports(content: string, config: CronusUIConfig): string;
|
|
25
|
+
export declare function targetDir(config: CronusUIConfig, target: "ui" | "lib" | "block"): string;
|
|
26
|
+
export declare function writeFileEnsured(filePath: string, content: string): Promise<void>;
|
|
27
|
+
/**
|
|
28
|
+
* Resolve a registry-supplied `filePath` against `<cwd>/<dir>` while guaranteeing
|
|
29
|
+
* the result stays inside that directory. `filePath` arrives raw from a remote
|
|
30
|
+
* registry, so it is untrusted: reject absolute paths and any `..` traversal that
|
|
31
|
+
* would escape the target root (e.g. "../escape" or "/etc/passwd").
|
|
32
|
+
*
|
|
33
|
+
* Returns the resolved absolute destination; throws a clear Error naming the
|
|
34
|
+
* offending path otherwise.
|
|
35
|
+
*/
|
|
36
|
+
export declare function resolveSafeDest(cwd: string, dir: string, filePath: string): string;
|
|
37
|
+
/** Write all files of a resolved item, applying alias rewrites, return written paths. */
|
|
38
|
+
export declare function writeItemFiles(item: RegistryItem, config: CronusUIConfig, cwd: string, { overwrite }: {
|
|
39
|
+
overwrite: boolean;
|
|
40
|
+
}): Promise<{
|
|
41
|
+
written: string[];
|
|
42
|
+
skipped: string[];
|
|
43
|
+
}>;
|
|
44
|
+
/**
|
|
45
|
+
* Guard a single registry-supplied dependency token before it is handed to the
|
|
46
|
+
* package manager. Dependency strings arrive raw from a remote registry, so a
|
|
47
|
+
* malicious entry like "--registry=http://evil" or "-g" would otherwise be
|
|
48
|
+
* spawned as a package-manager flag (arg injection). Reject anything that is not
|
|
49
|
+
* a plain npm package spec, naming the offending token in the thrown Error.
|
|
50
|
+
*
|
|
51
|
+
* Note the explicit leading-`-` check: a literal `-` is a legal *internal*
|
|
52
|
+
* package-name character (so the name char class permits it), which means the
|
|
53
|
+
* regex alone would accept "-g". We reject a leading dash outright so a spec can
|
|
54
|
+
* never be parsed as a CLI flag.
|
|
55
|
+
*/
|
|
56
|
+
export declare function assertValidDependency(dep: string): void;
|
|
57
|
+
/**
|
|
58
|
+
* Collect + de-duplicate npm deps across resolved items. Every dependency is
|
|
59
|
+
* validated here — the single point all registry deps pass through before the
|
|
60
|
+
* package-manager spawn — so an injected/malformed spec throws before install.
|
|
61
|
+
*/
|
|
62
|
+
export declare function collectDependencies(items: RegistryItem[]): string[];
|
|
63
|
+
/** Levenshtein edit distance between two strings (small inputs: registry names). */
|
|
64
|
+
export declare function levenshtein(a: string, b: string): number;
|
|
65
|
+
/**
|
|
66
|
+
* Find the closest registry name to a (presumably mistyped) `name`. Prefers a
|
|
67
|
+
* substring match, then falls back to the nearest by edit distance, but only
|
|
68
|
+
* when that distance is small enough to be a plausible typo. Returns undefined
|
|
69
|
+
* when nothing is close enough to suggest.
|
|
70
|
+
*/
|
|
71
|
+
export declare function closestName(name: string, candidates: string[]): string | undefined;
|
|
72
|
+
//# sourceMappingURL=utils.d.ts.map
|
package/dist/utils.js
ADDED
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
import { spawn } from "node:child_process";
|
|
2
|
+
import { existsSync } from "node:fs";
|
|
3
|
+
import { mkdir, writeFile } from "node:fs/promises";
|
|
4
|
+
import { dirname, isAbsolute, join, resolve, sep } from "node:path";
|
|
5
|
+
import pc from "picocolors";
|
|
6
|
+
export const log = {
|
|
7
|
+
info: (msg) => console.log(`${pc.cyan("ℹ")} ${msg}`),
|
|
8
|
+
ok: (msg) => console.log(`${pc.green("✔")} ${msg}`),
|
|
9
|
+
warn: (msg) => console.log(`${pc.yellow("⚠")} ${msg}`),
|
|
10
|
+
err: (msg) => console.error(`${pc.red("✖")} ${msg}`),
|
|
11
|
+
step: (msg) => console.log(`${pc.dim("›")} ${msg}`),
|
|
12
|
+
title: (msg) => console.log(`\n${pc.bold(msg)}`),
|
|
13
|
+
};
|
|
14
|
+
export function detectPackageManager(cwd) {
|
|
15
|
+
if (existsSync(join(cwd, "bun.lock")) || existsSync(join(cwd, "bun.lockb")))
|
|
16
|
+
return "bun";
|
|
17
|
+
if (existsSync(join(cwd, "pnpm-lock.yaml")))
|
|
18
|
+
return "pnpm";
|
|
19
|
+
if (existsSync(join(cwd, "yarn.lock")))
|
|
20
|
+
return "yarn";
|
|
21
|
+
return "npm";
|
|
22
|
+
}
|
|
23
|
+
export function installArgs(pm, deps) {
|
|
24
|
+
switch (pm) {
|
|
25
|
+
case "bun":
|
|
26
|
+
return ["add", ...deps];
|
|
27
|
+
case "pnpm":
|
|
28
|
+
return ["add", ...deps];
|
|
29
|
+
case "yarn":
|
|
30
|
+
return ["add", ...deps];
|
|
31
|
+
default:
|
|
32
|
+
return ["install", ...deps];
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
export function runInstall(pm, deps, cwd) {
|
|
36
|
+
return new Promise((resolvePromise, reject) => {
|
|
37
|
+
const child = spawn(pm, installArgs(pm, deps), { cwd, stdio: "inherit" });
|
|
38
|
+
child.on("error", reject);
|
|
39
|
+
child.on("close", (code) => code === 0 ? resolvePromise() : reject(new Error(`${pm} exited with code ${code}`)));
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Rewrite a component's canonical specifiers to the consumer's aliases:
|
|
44
|
+
* "../lib/cn.js" → `${aliases.lib}/cn`
|
|
45
|
+
* "../lib/demo-store.js" → `${aliases.lib}/demo-store`
|
|
46
|
+
* "./button.js" → `${aliases.ui}/button`
|
|
47
|
+
* The `../lib/<name>.js` rule is generalized (F3) so any shared `registry:lib`
|
|
48
|
+
* a block depends on — `cn`, `demo-store`, `demo-saas`, … — rewrites to the
|
|
49
|
+
* consumer's `lib` alias, not just `cn`. npm imports are left untouched.
|
|
50
|
+
*/
|
|
51
|
+
export function rewriteImports(content, config) {
|
|
52
|
+
return content
|
|
53
|
+
.replace(/(["'])\.\.\/lib\/([\w-]+)\.js\1/g, `"${config.aliases.lib}/$2"`)
|
|
54
|
+
.replace(/(["'])\.\/([\w-]+)\.js\1/g, `"${config.aliases.ui}/$2"`);
|
|
55
|
+
}
|
|
56
|
+
export function targetDir(config, target) {
|
|
57
|
+
switch (target) {
|
|
58
|
+
case "ui":
|
|
59
|
+
return config.paths.ui;
|
|
60
|
+
case "block":
|
|
61
|
+
return config.paths.blocks;
|
|
62
|
+
default:
|
|
63
|
+
return config.paths.lib;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
export async function writeFileEnsured(filePath, content) {
|
|
67
|
+
await mkdir(dirname(filePath), { recursive: true });
|
|
68
|
+
await writeFile(filePath, content, "utf8");
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Resolve a registry-supplied `filePath` against `<cwd>/<dir>` while guaranteeing
|
|
72
|
+
* the result stays inside that directory. `filePath` arrives raw from a remote
|
|
73
|
+
* registry, so it is untrusted: reject absolute paths and any `..` traversal that
|
|
74
|
+
* would escape the target root (e.g. "../escape" or "/etc/passwd").
|
|
75
|
+
*
|
|
76
|
+
* Returns the resolved absolute destination; throws a clear Error naming the
|
|
77
|
+
* offending path otherwise.
|
|
78
|
+
*/
|
|
79
|
+
export function resolveSafeDest(cwd, dir, filePath) {
|
|
80
|
+
if (isAbsolute(filePath)) {
|
|
81
|
+
throw new Error(`Refusing to write absolute registry path: ${filePath}`);
|
|
82
|
+
}
|
|
83
|
+
const resolvedRoot = resolve(join(cwd, dir));
|
|
84
|
+
const resolvedDest = resolve(join(cwd, dir, filePath));
|
|
85
|
+
if (resolvedDest !== resolvedRoot && !resolvedDest.startsWith(resolvedRoot + sep)) {
|
|
86
|
+
throw new Error(`Refusing to write registry path outside target directory: ${filePath}`);
|
|
87
|
+
}
|
|
88
|
+
return resolvedDest;
|
|
89
|
+
}
|
|
90
|
+
/** Write all files of a resolved item, applying alias rewrites, return written paths. */
|
|
91
|
+
export async function writeItemFiles(item, config, cwd, { overwrite }) {
|
|
92
|
+
const written = [];
|
|
93
|
+
const skipped = [];
|
|
94
|
+
for (const file of item.files) {
|
|
95
|
+
const dir = targetDir(config, file.target);
|
|
96
|
+
const dest = resolveSafeDest(cwd, dir, file.path);
|
|
97
|
+
if (existsSync(dest) && !overwrite) {
|
|
98
|
+
skipped.push(join(dir, file.path));
|
|
99
|
+
continue;
|
|
100
|
+
}
|
|
101
|
+
await writeFileEnsured(dest, rewriteImports(file.content, config));
|
|
102
|
+
written.push(join(dir, file.path));
|
|
103
|
+
}
|
|
104
|
+
return { written, skipped };
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* A valid npm package spec: an optionally-scoped name with an optional
|
|
108
|
+
* `@version`/range suffix (e.g. "react", "@radix-ui/react-slot", "clsx@^2.1.1").
|
|
109
|
+
* Case-insensitive.
|
|
110
|
+
*/
|
|
111
|
+
const VALID_DEPENDENCY_RE = /^(@[a-z0-9-~][a-z0-9-._~]*\/)?[a-z0-9-~][a-z0-9-._~]*(@[^\s]+)?$/i;
|
|
112
|
+
/**
|
|
113
|
+
* Guard a single registry-supplied dependency token before it is handed to the
|
|
114
|
+
* package manager. Dependency strings arrive raw from a remote registry, so a
|
|
115
|
+
* malicious entry like "--registry=http://evil" or "-g" would otherwise be
|
|
116
|
+
* spawned as a package-manager flag (arg injection). Reject anything that is not
|
|
117
|
+
* a plain npm package spec, naming the offending token in the thrown Error.
|
|
118
|
+
*
|
|
119
|
+
* Note the explicit leading-`-` check: a literal `-` is a legal *internal*
|
|
120
|
+
* package-name character (so the name char class permits it), which means the
|
|
121
|
+
* regex alone would accept "-g". We reject a leading dash outright so a spec can
|
|
122
|
+
* never be parsed as a CLI flag.
|
|
123
|
+
*/
|
|
124
|
+
export function assertValidDependency(dep) {
|
|
125
|
+
if (dep.startsWith("-") || !VALID_DEPENDENCY_RE.test(dep)) {
|
|
126
|
+
throw new Error(`Refusing to install invalid dependency spec from registry: ${dep}`);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Collect + de-duplicate npm deps across resolved items. Every dependency is
|
|
131
|
+
* validated here — the single point all registry deps pass through before the
|
|
132
|
+
* package-manager spawn — so an injected/malformed spec throws before install.
|
|
133
|
+
*/
|
|
134
|
+
export function collectDependencies(items) {
|
|
135
|
+
const set = new Set();
|
|
136
|
+
for (const item of items) {
|
|
137
|
+
for (const dep of item.dependencies) {
|
|
138
|
+
assertValidDependency(dep);
|
|
139
|
+
set.add(dep);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
return [...set].sort();
|
|
143
|
+
}
|
|
144
|
+
/** Levenshtein edit distance between two strings (small inputs: registry names). */
|
|
145
|
+
export function levenshtein(a, b) {
|
|
146
|
+
// Single rolling row of the DP matrix (row 0 = distances against an empty `a`).
|
|
147
|
+
const row = Array.from({ length: b.length + 1 }, (_, j) => j);
|
|
148
|
+
for (let i = 1; i <= a.length; i++) {
|
|
149
|
+
let prevDiag = row[0] ?? 0; // dist[i-1][0]
|
|
150
|
+
row[0] = i;
|
|
151
|
+
for (let j = 1; j <= b.length; j++) {
|
|
152
|
+
const above = row[j] ?? 0; // dist[i-1][j], not yet overwritten
|
|
153
|
+
const cost = a[i - 1] === b[j - 1] ? 0 : 1;
|
|
154
|
+
row[j] = Math.min(above + 1, (row[j - 1] ?? 0) + 1, prevDiag + cost);
|
|
155
|
+
prevDiag = above;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
return row[b.length] ?? 0;
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Find the closest registry name to a (presumably mistyped) `name`. Prefers a
|
|
162
|
+
* substring match, then falls back to the nearest by edit distance, but only
|
|
163
|
+
* when that distance is small enough to be a plausible typo. Returns undefined
|
|
164
|
+
* when nothing is close enough to suggest.
|
|
165
|
+
*/
|
|
166
|
+
export function closestName(name, candidates) {
|
|
167
|
+
if (candidates.length === 0)
|
|
168
|
+
return undefined;
|
|
169
|
+
const needle = name.toLowerCase();
|
|
170
|
+
const substring = candidates.find((c) => c.toLowerCase().includes(needle) || needle.includes(c.toLowerCase()));
|
|
171
|
+
if (substring)
|
|
172
|
+
return substring;
|
|
173
|
+
let best;
|
|
174
|
+
let bestDist = Number.POSITIVE_INFINITY;
|
|
175
|
+
for (const candidate of candidates) {
|
|
176
|
+
const dist = levenshtein(needle, candidate.toLowerCase());
|
|
177
|
+
if (dist < bestDist) {
|
|
178
|
+
bestDist = dist;
|
|
179
|
+
best = candidate;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
// Only suggest when it is a plausible typo (scaled to the name length).
|
|
183
|
+
const threshold = Math.max(2, Math.floor(name.length / 2));
|
|
184
|
+
return best !== undefined && bestDist <= threshold ? best : undefined;
|
|
185
|
+
}
|
|
186
|
+
//# sourceMappingURL=utils.js.map
|
package/package.json
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "cronus-ui",
|
|
3
|
+
"version": "0.6.0",
|
|
4
|
+
"description": "cronus-ui — add Cronus UI components to your project, shadcn-style (copy-paste registry).",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"author": "Cronus",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "git+https://github.com/pedrogbraz/cronus-ui.git",
|
|
11
|
+
"directory": "packages/cli"
|
|
12
|
+
},
|
|
13
|
+
"homepage": "https://aicronus.com",
|
|
14
|
+
"bugs": {
|
|
15
|
+
"url": "https://github.com/pedrogbraz/cronus-ui/issues"
|
|
16
|
+
},
|
|
17
|
+
"keywords": [
|
|
18
|
+
"cronus",
|
|
19
|
+
"components",
|
|
20
|
+
"design-system",
|
|
21
|
+
"registry",
|
|
22
|
+
"shadcn",
|
|
23
|
+
"tailwind",
|
|
24
|
+
"ui"
|
|
25
|
+
],
|
|
26
|
+
"bin": {
|
|
27
|
+
"cronus-ui": "./dist/index.js"
|
|
28
|
+
},
|
|
29
|
+
"files": [
|
|
30
|
+
"dist",
|
|
31
|
+
"templates",
|
|
32
|
+
"LICENSE",
|
|
33
|
+
"README.md",
|
|
34
|
+
"!dist/**/*.map"
|
|
35
|
+
],
|
|
36
|
+
"exports": {
|
|
37
|
+
".": {
|
|
38
|
+
"types": "./dist/index.d.ts",
|
|
39
|
+
"import": "./dist/index.js"
|
|
40
|
+
},
|
|
41
|
+
"./compose": {
|
|
42
|
+
"types": "./dist/compose.d.ts",
|
|
43
|
+
"import": "./dist/compose.js"
|
|
44
|
+
}
|
|
45
|
+
},
|
|
46
|
+
"publishConfig": {
|
|
47
|
+
"access": "public"
|
|
48
|
+
},
|
|
49
|
+
"scripts": {
|
|
50
|
+
"build": "tsc -p tsconfig.json",
|
|
51
|
+
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
52
|
+
"prepublishOnly": "tsc -p tsconfig.json",
|
|
53
|
+
"registry": "bun run scripts/build-registry.ts",
|
|
54
|
+
"registry:check": "bun run scripts/check-registry.ts"
|
|
55
|
+
},
|
|
56
|
+
"dependencies": {
|
|
57
|
+
"@cronus-ui/ai-kit": "0.6.0",
|
|
58
|
+
"commander": "^15.0.0",
|
|
59
|
+
"picocolors": "^1.1.1"
|
|
60
|
+
},
|
|
61
|
+
"devDependencies": {
|
|
62
|
+
"@types/node": "^22.10.0",
|
|
63
|
+
"typescript": "^6.0.3"
|
|
64
|
+
},
|
|
65
|
+
"engines": {
|
|
66
|
+
"node": ">=22.12.0"
|
|
67
|
+
}
|
|
68
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "chat",
|
|
3
|
+
"type": "registry:app",
|
|
4
|
+
"planVersion": 1,
|
|
5
|
+
"manifest": {
|
|
6
|
+
"title": "Chat",
|
|
7
|
+
"description": "A Pro assistant app: chat thread and prompt box under an app shell, plus a replies surface and settings.",
|
|
8
|
+
"chrome": {
|
|
9
|
+
"shell": { "block": "app-shell-chrome" },
|
|
10
|
+
"bare": {}
|
|
11
|
+
},
|
|
12
|
+
"pages": [
|
|
13
|
+
{
|
|
14
|
+
"route": "/login",
|
|
15
|
+
"title": "Sign in",
|
|
16
|
+
"chrome": "bare",
|
|
17
|
+
"blocks": [{ "block": "login", "variant": "split" }]
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
"route": "/",
|
|
21
|
+
"title": "Thread",
|
|
22
|
+
"nav": "Thread",
|
|
23
|
+
"chrome": "shell",
|
|
24
|
+
"blocks": ["chat-thread"]
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
"route": "/new",
|
|
28
|
+
"title": "New",
|
|
29
|
+
"nav": "New",
|
|
30
|
+
"chrome": "shell",
|
|
31
|
+
"blocks": ["prompt-box", "ai-response"]
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
"route": "/settings",
|
|
35
|
+
"title": "Settings",
|
|
36
|
+
"nav": "Settings",
|
|
37
|
+
"chrome": "shell",
|
|
38
|
+
"blocks": ["settings"]
|
|
39
|
+
}
|
|
40
|
+
],
|
|
41
|
+
"extras": { "not-found": "not-found" },
|
|
42
|
+
"defaults": { "theme": "aurora", "mode": "dark", "brand": "__APP_NAME__" }
|
|
43
|
+
}
|
|
44
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "finance",
|
|
3
|
+
"type": "registry:app",
|
|
4
|
+
"planVersion": 1,
|
|
5
|
+
"manifest": {
|
|
6
|
+
"title": "Finance",
|
|
7
|
+
"description": "A Pro money app: payouts and invoices on the home, plus billing, usage, and analytics under an app shell.",
|
|
8
|
+
"chrome": {
|
|
9
|
+
"shell": { "block": "app-shell-chrome" },
|
|
10
|
+
"bare": {}
|
|
11
|
+
},
|
|
12
|
+
"pages": [
|
|
13
|
+
{
|
|
14
|
+
"route": "/login",
|
|
15
|
+
"title": "Sign in",
|
|
16
|
+
"chrome": "bare",
|
|
17
|
+
"blocks": [{ "block": "login", "variant": "split" }]
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
"route": "/",
|
|
21
|
+
"title": "Money",
|
|
22
|
+
"nav": "Money",
|
|
23
|
+
"chrome": "shell",
|
|
24
|
+
"blocks": ["payouts", "invoice"]
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
"route": "/billing",
|
|
28
|
+
"title": "Billing",
|
|
29
|
+
"nav": "Billing",
|
|
30
|
+
"chrome": "shell",
|
|
31
|
+
"blocks": ["billing", "usage-dashboard"]
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
"route": "/analytics",
|
|
35
|
+
"title": "Analytics",
|
|
36
|
+
"nav": "Analytics",
|
|
37
|
+
"chrome": "shell",
|
|
38
|
+
"blocks": ["analytics"]
|
|
39
|
+
}
|
|
40
|
+
],
|
|
41
|
+
"extras": { "not-found": "not-found" },
|
|
42
|
+
"defaults": { "theme": "emerald", "mode": "light", "brand": "__APP_NAME__" }
|
|
43
|
+
}
|
|
44
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "landing-agency",
|
|
3
|
+
"type": "registry:app",
|
|
4
|
+
"planVersion": 1,
|
|
5
|
+
"manifest": {
|
|
6
|
+
"title": "Agency",
|
|
7
|
+
"description": "Studio/agency landing: split hero, logo cloud, about story, services grid, stats, testimonials, and CTA. Midnight, dark.",
|
|
8
|
+
"chrome": {
|
|
9
|
+
"site": { "navbar": "navbar", "footer": "footer" }
|
|
10
|
+
},
|
|
11
|
+
"pages": [
|
|
12
|
+
{
|
|
13
|
+
"route": "/",
|
|
14
|
+
"title": "Home",
|
|
15
|
+
"nav": "Home",
|
|
16
|
+
"chrome": "site",
|
|
17
|
+
"blocks": [
|
|
18
|
+
{ "block": "hero", "variant": "split" },
|
|
19
|
+
"logo-cloud",
|
|
20
|
+
"about",
|
|
21
|
+
"feature-grid",
|
|
22
|
+
"stats",
|
|
23
|
+
"testimonials",
|
|
24
|
+
"cta"
|
|
25
|
+
]
|
|
26
|
+
}
|
|
27
|
+
],
|
|
28
|
+
"extras": { "not-found": "not-found" },
|
|
29
|
+
"defaults": { "theme": "midnight", "mode": "dark", "brand": "__APP_NAME__" }
|
|
30
|
+
}
|
|
31
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "landing-agents",
|
|
3
|
+
"type": "registry:app",
|
|
4
|
+
"planVersion": 1,
|
|
5
|
+
"manifest": {
|
|
6
|
+
"title": "Agents",
|
|
7
|
+
"description": "Automation/agent landing: split hero, marquee logos, bento features, stats, proof, pricing, FAQ, and a banner CTA. Emerald, light.",
|
|
8
|
+
"chrome": {
|
|
9
|
+
"site": { "navbar": "navbar", "footer": "footer" }
|
|
10
|
+
},
|
|
11
|
+
"pages": [
|
|
12
|
+
{
|
|
13
|
+
"route": "/",
|
|
14
|
+
"title": "Home",
|
|
15
|
+
"nav": "Home",
|
|
16
|
+
"chrome": "site",
|
|
17
|
+
"blocks": [
|
|
18
|
+
{ "block": "hero", "variant": "split" },
|
|
19
|
+
{ "block": "logo-cloud", "variant": "marquee" },
|
|
20
|
+
{ "block": "feature-grid", "variant": "bento" },
|
|
21
|
+
"stats",
|
|
22
|
+
"testimonials",
|
|
23
|
+
"pricing",
|
|
24
|
+
"faq",
|
|
25
|
+
{ "block": "cta", "variant": "banner" }
|
|
26
|
+
]
|
|
27
|
+
}
|
|
28
|
+
],
|
|
29
|
+
"extras": { "not-found": "not-found" },
|
|
30
|
+
"defaults": { "theme": "emerald", "mode": "light", "brand": "__APP_NAME__" }
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "landing-broadcast",
|
|
3
|
+
"type": "registry:app",
|
|
4
|
+
"planVersion": 1,
|
|
5
|
+
"manifest": {
|
|
6
|
+
"title": "Broadcast",
|
|
7
|
+
"description": "Studio/show landing: atmospheric hero, marquee logos, feature grid, testimonials, pricing, and footer chrome. Aurora, dark.",
|
|
8
|
+
"chrome": {
|
|
9
|
+
"site": { "navbar": "navbar", "footer": "footer" }
|
|
10
|
+
},
|
|
11
|
+
"pages": [
|
|
12
|
+
{
|
|
13
|
+
"route": "/",
|
|
14
|
+
"title": "Home",
|
|
15
|
+
"nav": "Home",
|
|
16
|
+
"chrome": "site",
|
|
17
|
+
"blocks": [
|
|
18
|
+
{ "block": "hero", "variant": "atmosphere" },
|
|
19
|
+
{ "block": "logo-cloud", "variant": "marquee" },
|
|
20
|
+
"feature-grid",
|
|
21
|
+
"testimonials",
|
|
22
|
+
"pricing"
|
|
23
|
+
]
|
|
24
|
+
}
|
|
25
|
+
],
|
|
26
|
+
"extras": { "not-found": "not-found" },
|
|
27
|
+
"defaults": { "theme": "aurora", "mode": "dark", "brand": "__APP_NAME__" }
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "landing-care",
|
|
3
|
+
"type": "registry:app",
|
|
4
|
+
"planVersion": 1,
|
|
5
|
+
"manifest": {
|
|
6
|
+
"title": "Care",
|
|
7
|
+
"description": "Calm healthcare/conversion landing: waitlist hero, bento features, testimonials, and a contained CTA. Emerald, light.",
|
|
8
|
+
"chrome": {
|
|
9
|
+
"site": { "navbar": "navbar", "footer": "footer" }
|
|
10
|
+
},
|
|
11
|
+
"pages": [
|
|
12
|
+
{
|
|
13
|
+
"route": "/",
|
|
14
|
+
"title": "Home",
|
|
15
|
+
"nav": "Home",
|
|
16
|
+
"chrome": "site",
|
|
17
|
+
"blocks": [
|
|
18
|
+
"waitlist",
|
|
19
|
+
{ "block": "feature-grid", "variant": "bento" },
|
|
20
|
+
"testimonials",
|
|
21
|
+
"cta"
|
|
22
|
+
]
|
|
23
|
+
}
|
|
24
|
+
],
|
|
25
|
+
"extras": { "not-found": "not-found" },
|
|
26
|
+
"defaults": { "theme": "emerald", "mode": "light", "brand": "__APP_NAME__" }
|
|
27
|
+
}
|
|
28
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "landing-coverage",
|
|
3
|
+
"type": "registry:app",
|
|
4
|
+
"planVersion": 1,
|
|
5
|
+
"manifest": {
|
|
6
|
+
"title": "Coverage",
|
|
7
|
+
"description": "Global-services landing: centered hero, stats, testimonial grid, FAQ, and CTA. Sunset, light.",
|
|
8
|
+
"chrome": {
|
|
9
|
+
"site": { "navbar": "navbar", "footer": "footer" }
|
|
10
|
+
},
|
|
11
|
+
"pages": [
|
|
12
|
+
{
|
|
13
|
+
"route": "/",
|
|
14
|
+
"title": "Home",
|
|
15
|
+
"nav": "Home",
|
|
16
|
+
"chrome": "site",
|
|
17
|
+
"blocks": ["hero", "stats", { "block": "testimonials", "variant": "grid" }, "faq", "cta"]
|
|
18
|
+
}
|
|
19
|
+
],
|
|
20
|
+
"extras": { "not-found": "not-found" },
|
|
21
|
+
"defaults": { "theme": "sunset", "mode": "light", "brand": "__APP_NAME__" }
|
|
22
|
+
}
|
|
23
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "landing-docs",
|
|
3
|
+
"type": "registry:app",
|
|
4
|
+
"planVersion": 1,
|
|
5
|
+
"manifest": {
|
|
6
|
+
"title": "Docs product",
|
|
7
|
+
"description": "Developer-tool landing: announcement navbar energy via compact hero, logo cloud, features, integrations, and CTA.",
|
|
8
|
+
"chrome": {
|
|
9
|
+
"site": { "navbar": "navbar", "footer": "footer" }
|
|
10
|
+
},
|
|
11
|
+
"pages": [
|
|
12
|
+
{
|
|
13
|
+
"route": "/",
|
|
14
|
+
"title": "Home",
|
|
15
|
+
"nav": "Home",
|
|
16
|
+
"chrome": "site",
|
|
17
|
+
"blocks": [
|
|
18
|
+
{ "block": "hero", "variant": "compact" },
|
|
19
|
+
"logo-cloud",
|
|
20
|
+
"feature-grid",
|
|
21
|
+
"integrations",
|
|
22
|
+
"cta"
|
|
23
|
+
]
|
|
24
|
+
}
|
|
25
|
+
],
|
|
26
|
+
"extras": { "not-found": "not-found" },
|
|
27
|
+
"defaults": { "theme": "aurora", "mode": "dark", "brand": "__APP_NAME__" }
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "landing-glass",
|
|
3
|
+
"type": "registry:app",
|
|
4
|
+
"planVersion": 1,
|
|
5
|
+
"manifest": {
|
|
6
|
+
"title": "Glass",
|
|
7
|
+
"description": "Glass-dark landing: atmospheric hero, bento features, split FAQ, and a split-visual CTA. Midnight, dark.",
|
|
8
|
+
"chrome": {
|
|
9
|
+
"site": { "navbar": "navbar", "footer": "footer" }
|
|
10
|
+
},
|
|
11
|
+
"pages": [
|
|
12
|
+
{
|
|
13
|
+
"route": "/",
|
|
14
|
+
"title": "Home",
|
|
15
|
+
"nav": "Home",
|
|
16
|
+
"chrome": "site",
|
|
17
|
+
"blocks": [
|
|
18
|
+
{ "block": "hero", "variant": "atmosphere" },
|
|
19
|
+
{ "block": "feature-grid", "variant": "bento" },
|
|
20
|
+
{ "block": "faq", "variant": "split" },
|
|
21
|
+
{ "block": "cta", "variant": "split-visual" }
|
|
22
|
+
]
|
|
23
|
+
}
|
|
24
|
+
],
|
|
25
|
+
"extras": { "not-found": "not-found" },
|
|
26
|
+
"defaults": { "theme": "midnight", "mode": "dark", "brand": "__APP_NAME__" }
|
|
27
|
+
}
|
|
28
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "landing-ops",
|
|
3
|
+
"type": "registry:app",
|
|
4
|
+
"planVersion": 1,
|
|
5
|
+
"manifest": {
|
|
6
|
+
"title": "Ops",
|
|
7
|
+
"description": "Linear-style product landing: split hero with a quality panel, logo cloud, workflow features, integrations, and a full-width CTA.",
|
|
8
|
+
"chrome": {
|
|
9
|
+
"site": { "navbar": "navbar", "footer": "footer" }
|
|
10
|
+
},
|
|
11
|
+
"pages": [
|
|
12
|
+
{
|
|
13
|
+
"route": "/",
|
|
14
|
+
"title": "Home",
|
|
15
|
+
"nav": "Home",
|
|
16
|
+
"chrome": "site",
|
|
17
|
+
"blocks": [
|
|
18
|
+
{ "block": "hero", "variant": "split" },
|
|
19
|
+
"logo-cloud",
|
|
20
|
+
"feature-grid",
|
|
21
|
+
"integrations",
|
|
22
|
+
{ "block": "cta", "variant": "banner" }
|
|
23
|
+
]
|
|
24
|
+
}
|
|
25
|
+
],
|
|
26
|
+
"extras": { "not-found": "not-found" },
|
|
27
|
+
"defaults": { "theme": "aurora", "mode": "dark", "brand": "__APP_NAME__" }
|
|
28
|
+
}
|
|
29
|
+
}
|