rahman-resources 0.1.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 ADDED
@@ -0,0 +1,77 @@
1
+ # rahman-resources
2
+
3
+ Template installer for the [Rahman Resources kitab](https://github.com/rahmanef63/resource-site).
4
+
5
+ ## Usage
6
+
7
+ ```bash
8
+ npx rahman-resources add <template> [target-dir]
9
+ pnpm dlx rahman-resources add <template> [target-dir]
10
+ ```
11
+
12
+ ### List templates
13
+
14
+ ```bash
15
+ npx rahman-resources list
16
+ ```
17
+
18
+ ### Inspect a template
19
+
20
+ ```bash
21
+ npx rahman-resources info personal-brand-os
22
+ ```
23
+
24
+ ### Install into a project
25
+
26
+ ```bash
27
+ # new project
28
+ mkdir my-app && cd my-app && pnpm init
29
+ npx rahman-resources add personal-brand-os .
30
+
31
+ # existing project
32
+ cd existing-app
33
+ npx rahman-resources add personal-brand-os .
34
+ ```
35
+
36
+ The CLI:
37
+
38
+ 1. Pulls only the folders listed for that template (via [`tiged`](https://github.com/tiged/tiged)) — no full clone.
39
+ 2. Detects your package manager (`pnpm` / `yarn` / `bun` / `npm`) and installs the template's npm dependencies.
40
+ 3. Prints the agent recipe: what to wire next.
41
+
42
+ ## What's included
43
+
44
+ Every template ships:
45
+
46
+ - The page route(s) under `app/`
47
+ - The slice components under `components/templates/<slug>/`
48
+ - A drop-in Convex backend slice under `convex/templates/<slug>/` (where applicable)
49
+
50
+ Schema files are written to `convex/templates/<slug>/schema.ts` — merge into your existing `convex/schema.ts` or move it up.
51
+
52
+ ## Templates (current)
53
+
54
+ Run `npx rahman-resources list` to see the live catalog. Highlights:
55
+
56
+ | Slug | Category | What |
57
+ |---|---|---|
58
+ | `personal-brand-os` | website-template | Public site + admin dashboard for solo brand |
59
+ | `dashboard-three-column` | dashboard | Resizable left/main/right with drawer fallback |
60
+ | `dashboard-mobile-dock` | dashboard | Native-feel mobile dock + desktop sidebar |
61
+ | `cms-public-storefront` | cms | E-commerce / blog storefront |
62
+ | `landing-*` | marketing | Hero/bento/masonry/kinetic landings |
63
+
64
+ ## Updating the manifest
65
+
66
+ The manifest is generated from `site/lib/content/layouts.ts`. To regenerate:
67
+
68
+ ```bash
69
+ cd packages/cli
70
+ node scripts/gen-manifest.mjs
71
+ ```
72
+
73
+ `prepublishOnly` runs this automatically before `npm publish`.
74
+
75
+ ## License
76
+
77
+ MIT
package/bin/cli.js ADDED
@@ -0,0 +1,171 @@
1
+ #!/usr/bin/env node
2
+ // rahman-resources — template installer for the Rahman kitab.
3
+ // Usage:
4
+ // npx rahman-resources add <template> [target-dir]
5
+ // npx rahman-resources list
6
+ // npx rahman-resources info <template>
7
+
8
+ import { createRequire } from "node:module";
9
+ import { spawn } from "node:child_process";
10
+ import { existsSync } from "node:fs";
11
+ import path from "node:path";
12
+ import { fileURLToPath } from "node:url";
13
+
14
+ import kleur from "kleur";
15
+ import tiged from "tiged";
16
+
17
+ const require = createRequire(import.meta.url);
18
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
19
+ const manifest = require(path.join(__dirname, "../lib/manifest.json"));
20
+
21
+ const REPO = "rahmanef63/resource-site";
22
+ const BRANCH = "main";
23
+
24
+ const [, , cmd, ...rest] = process.argv;
25
+
26
+ main().catch((err) => {
27
+ console.error(kleur.red("✖"), err.message ?? err);
28
+ process.exit(1);
29
+ });
30
+
31
+ async function main() {
32
+ switch (cmd) {
33
+ case "add":
34
+ return runAdd(rest);
35
+ case "list":
36
+ case "ls":
37
+ return runList();
38
+ case "info":
39
+ return runInfo(rest);
40
+ case undefined:
41
+ case "-h":
42
+ case "--help":
43
+ case "help":
44
+ return printHelp();
45
+ default:
46
+ console.error(kleur.red(`Unknown command: ${cmd}`));
47
+ printHelp();
48
+ process.exit(1);
49
+ }
50
+ }
51
+
52
+ function printHelp() {
53
+ console.log(`
54
+ ${kleur.bold("rahman-resources")} — install templates from the Rahman kitab
55
+
56
+ ${kleur.bold("Usage:")}
57
+ npx rahman-resources add <template> [target-dir]
58
+ npx rahman-resources list
59
+ npx rahman-resources info <template>
60
+
61
+ ${kleur.bold("Examples:")}
62
+ npx rahman-resources add personal-brand-os my-app
63
+ pnpm dlx rahman-resources add personal-brand-os .
64
+ `);
65
+ }
66
+
67
+ function runList() {
68
+ console.log(kleur.bold("\nAvailable templates:\n"));
69
+ for (const t of manifest.templates) {
70
+ console.log(
71
+ ` ${kleur.cyan(t.slug.padEnd(28))} ${kleur.dim(t.category.padEnd(18))} ${t.title}`,
72
+ );
73
+ }
74
+ console.log(`\n${manifest.templates.length} total. Run ${kleur.cyan("info <slug>")} for detail.\n`);
75
+ }
76
+
77
+ function runInfo([slug]) {
78
+ if (!slug) throw new Error("Usage: rahman-resources info <template>");
79
+ const t = manifest.templates.find((x) => x.slug === slug);
80
+ if (!t) throw new Error(`Template not found: ${slug}. Run 'list' to see all.`);
81
+ console.log(`
82
+ ${kleur.bold(t.title)} ${kleur.dim(`[${t.category}]`)}
83
+
84
+ ${t.description}
85
+
86
+ ${kleur.bold("Pulls:")}
87
+ ${t.pullPaths.map((p) => ` · ${p}`).join("\n")}
88
+
89
+ ${kleur.bold("Dependencies:")}
90
+ ${(t.dependencies ?? []).map((d) => ` · ${d}`).join("\n") || " (none beyond base)"}
91
+
92
+ ${kleur.dim(`Page: https://github.com/${REPO}/tree/${BRANCH}/${t.repoPath}`)}
93
+ `);
94
+ }
95
+
96
+ async function runAdd([slug, targetArg = "."]) {
97
+ if (!slug) {
98
+ console.error(kleur.red("Missing template slug."));
99
+ printHelp();
100
+ process.exit(1);
101
+ }
102
+ const t = manifest.templates.find((x) => x.slug === slug);
103
+ if (!t) {
104
+ throw new Error(
105
+ `Template "${slug}" not found. Run ${kleur.cyan("npx rahman-resources list")} to see available templates.`,
106
+ );
107
+ }
108
+ const target = path.resolve(process.cwd(), targetArg);
109
+
110
+ console.log(kleur.bold(`\n→ Installing ${kleur.cyan(t.title)} into ${kleur.dim(target)}\n`));
111
+ for (const p of t.pullPaths) {
112
+ const dest = path.join(target, p);
113
+ process.stdout.write(` pulling ${kleur.dim(p)} ... `);
114
+ await pull(p, dest);
115
+ console.log(kleur.green("ok"));
116
+ }
117
+
118
+ if (t.dependencies?.length) {
119
+ const pm = detectPM(target);
120
+ console.log(kleur.bold(`\n→ Installing dependencies via ${kleur.cyan(pm)}\n`));
121
+ if (!hasPackageJson(target)) {
122
+ console.log(
123
+ kleur.yellow(` ${target}/package.json not found — skipping install.`),
124
+ );
125
+ console.log(kleur.dim(` Run later: cd ${targetArg} && ${pm} add ${t.dependencies.join(" ")}`));
126
+ } else {
127
+ await runInstall(pm, t.dependencies, target);
128
+ }
129
+ }
130
+
131
+ console.log(`\n${kleur.green("✓")} Done. ${kleur.bold(t.title)} installed.`);
132
+ if (t.agentRecipe) {
133
+ console.log(`\n${kleur.bold("Next:")}\n${indent(t.agentRecipe, 2)}\n`);
134
+ }
135
+ }
136
+
137
+ async function pull(repoPath, dest) {
138
+ const emitter = tiged(`${REPO}/${repoPath}#${BRANCH}`, {
139
+ cache: false,
140
+ force: true,
141
+ verbose: false,
142
+ });
143
+ await emitter.clone(dest);
144
+ }
145
+
146
+ function detectPM(target) {
147
+ if (existsSync(path.join(target, "pnpm-lock.yaml"))) return "pnpm";
148
+ if (existsSync(path.join(target, "yarn.lock"))) return "yarn";
149
+ if (existsSync(path.join(target, "bun.lockb"))) return "bun";
150
+ return "npm";
151
+ }
152
+
153
+ function hasPackageJson(target) {
154
+ return existsSync(path.join(target, "package.json"));
155
+ }
156
+
157
+ function runInstall(pm, deps, cwd) {
158
+ const args = pm === "npm" ? ["install", ...deps] : ["add", ...deps];
159
+ return new Promise((resolve, reject) => {
160
+ const ps = spawn(pm, args, { cwd, stdio: "inherit", shell: true });
161
+ ps.on("error", reject);
162
+ ps.on("exit", (code) =>
163
+ code === 0 ? resolve() : reject(new Error(`${pm} ${args[0]} exited ${code}`)),
164
+ );
165
+ });
166
+ }
167
+
168
+ function indent(s, n) {
169
+ const pad = " ".repeat(n);
170
+ return s.split("\n").map((l) => pad + l).join("\n");
171
+ }
@@ -0,0 +1,235 @@
1
+ {
2
+ "generatedAt": "2026-05-03T14:23:54.502Z",
3
+ "repo": "rahmanef63/resource-site",
4
+ "branch": "main",
5
+ "templates": [
6
+ {
7
+ "slug": "personal-brand-os",
8
+ "title": "Personal Brand OS",
9
+ "category": "website-template",
10
+ "description": "Full-app personal site — public landing (hero, blog, portfolio, services, resources, contact) + admin dashboard (posts, leads, chatbot, comments). Inspired by saudivisuals.com + cescadesigns. Fill-in-the-blank with lorem ipsum.",
11
+ "source": "saudivisuals.com + cescadesigns",
12
+ "repoPath": "app/preview/personal-brand-os",
13
+ "pullPaths": [
14
+ "app/preview/personal-brand-os",
15
+ "components/templates/personal-brand",
16
+ "convex/templates/personal-brand-os"
17
+ ],
18
+ "files": [
19
+ "app/preview/personal-brand-os/public/layout.tsx",
20
+ "app/preview/personal-brand-os/public/page.tsx",
21
+ "app/preview/personal-brand-os/public/blog/page.tsx",
22
+ "app/preview/personal-brand-os/public/blog/[slug]/page.tsx",
23
+ "app/preview/personal-brand-os/public/portfolio/page.tsx",
24
+ "app/preview/personal-brand-os/public/portfolio/[slug]/page.tsx",
25
+ "app/preview/personal-brand-os/public/services/page.tsx",
26
+ "app/preview/personal-brand-os/public/resources/page.tsx",
27
+ "app/preview/personal-brand-os/public/contact/page.tsx",
28
+ "app/preview/personal-brand-os/public/about/page.tsx",
29
+ "app/preview/personal-brand-os/admin/layout.tsx",
30
+ "app/preview/personal-brand-os/admin/page.tsx",
31
+ "app/preview/personal-brand-os/admin/posts/page.tsx",
32
+ "app/preview/personal-brand-os/admin/posts/new/page.tsx",
33
+ "app/preview/personal-brand-os/admin/posts/[id]/page.tsx",
34
+ "app/preview/personal-brand-os/admin/portfolio/page.tsx",
35
+ "app/preview/personal-brand-os/admin/leads/page.tsx",
36
+ "app/preview/personal-brand-os/admin/comments/page.tsx",
37
+ "app/preview/personal-brand-os/admin/chatbot/page.tsx",
38
+ "components/templates/personal-brand/shared/types.ts",
39
+ "components/templates/personal-brand/shared/store.tsx",
40
+ "components/templates/personal-brand/shared/seed.ts",
41
+ "components/templates/personal-brand/shared/ui/site-nav.tsx",
42
+ "components/templates/personal-brand/shared/ui/site-footer.tsx",
43
+ "components/templates/personal-brand/shared/ui/chat-fab.tsx",
44
+ "components/templates/personal-brand/slices/admin/shell/admin-sidebar.tsx",
45
+ "components/templates/personal-brand/slices/admin/shell/admin-topbar.tsx",
46
+ "convex/templates/personal-brand-os/schema.ts",
47
+ "convex/templates/personal-brand-os/posts.ts",
48
+ "convex/templates/personal-brand-os/portfolio.ts",
49
+ "convex/templates/personal-brand-os/services.ts",
50
+ "convex/templates/personal-brand-os/resources.ts",
51
+ "convex/templates/personal-brand-os/leads.ts",
52
+ "convex/templates/personal-brand-os/comments.ts",
53
+ "convex/templates/personal-brand-os/subscribers.ts",
54
+ "convex/templates/personal-brand-os/chat.ts",
55
+ "convex/templates/personal-brand-os/README.md"
56
+ ],
57
+ "dependencies": [
58
+ "next@^16",
59
+ "react@^19",
60
+ "react-dom@^19",
61
+ "lucide-react",
62
+ "@tabler/icons-react",
63
+ "sonner",
64
+ "next-themes",
65
+ "tailwindcss@^4",
66
+ "convex",
67
+ "@convex-dev/auth"
68
+ ],
69
+ "agentRecipe": "Personal Brand OS = full-app template (public + admin). Copy sections from app/preview/personal-brand-os/public/page.tsx into app/(public)/sections/. Copy admin shell from app/preview/personal-brand-os/admin/page.tsx into app/(admin)/. Wire posts/portfolio/leads/chatbot/comments to Convex per docs/templates/T1-personal-brand-os.md schema. Replace lorem ipsum with real content via the CMS module.",
70
+ "tags": [
71
+ "template",
72
+ "personal-brand",
73
+ "blog",
74
+ "portfolio",
75
+ "admin",
76
+ "saas"
77
+ ]
78
+ },
79
+ {
80
+ "slug": "landing-hero-carousel",
81
+ "title": "Landing — Hero Carousel",
82
+ "category": "marketing",
83
+ "description": "Full-width image carousel hero with auto-fade + dot indicators. Originally CMS-driven via Convex. Best for visual brands.",
84
+ "source": "cescadesigns",
85
+ "repoPath": "cookbook/layouts/landing-hero-carousel",
86
+ "pullPaths": [
87
+ "cookbook/layouts/landing-hero-carousel"
88
+ ],
89
+ "files": [],
90
+ "dependencies": [],
91
+ "agentRecipe": "Mount the HeroSection from cookbook/layouts/landing-hero-carousel as the hero of the marketing route group. Provide image array via props or wire to Convex api.heroImages.list.",
92
+ "tags": [
93
+ "marketing",
94
+ "carousel",
95
+ "image",
96
+ "cms"
97
+ ]
98
+ },
99
+ {
100
+ "slug": "landing-asymmetric-masonry",
101
+ "title": "Landing — Asymmetric Masonry",
102
+ "category": "marketing",
103
+ "description": "8-slot repeating asymmetric grid. Intersection-observer staggered scroll-reveal. Lifted from rahmanef.com portfolio.",
104
+ "source": "rahmanef.com",
105
+ "repoPath": "cookbook/layouts/landing-asymmetric-masonry",
106
+ "pullPaths": [
107
+ "cookbook/layouts/landing-asymmetric-masonry"
108
+ ],
109
+ "files": [],
110
+ "dependencies": [],
111
+ "agentRecipe": "Use PortfolioGrid for case-study or portfolio pages. Items array shape: { id, title, cover, href, category }. The 8-slot pattern repeats; supply at least 8 items for the layout to bloom.",
112
+ "tags": [
113
+ "marketing",
114
+ "portfolio",
115
+ "masonry",
116
+ "scroll-reveal"
117
+ ]
118
+ },
119
+ {
120
+ "slug": "landing-bento",
121
+ "title": "Landing — Bento Grid",
122
+ "category": "marketing",
123
+ "description": "Feature-grid marketing landing. Compose Card + Magnetic + KineticHeading. Modern SaaS feel.",
124
+ "source": "synthesized",
125
+ "repoPath": "cookbook/layouts/landing-bento",
126
+ "pullPaths": [
127
+ "cookbook/layouts/landing-bento"
128
+ ],
129
+ "files": [],
130
+ "dependencies": [],
131
+ "agentRecipe": "Compose a 3-column CSS grid with explicit area assignments per feature. Mix Card sizes (1x1, 1x2, 2x1, 2x2) for visual rhythm.",
132
+ "tags": [
133
+ "marketing",
134
+ "bento",
135
+ "features"
136
+ ]
137
+ },
138
+ {
139
+ "slug": "landing-kinetic-text",
140
+ "title": "Landing — Kinetic Text",
141
+ "category": "marketing",
142
+ "description": "Brand-forward landing. Letter-stagger headings + magnetic CTAs + marquee strips. Motion-heavy.",
143
+ "source": "rahmanef.com",
144
+ "repoPath": "cookbook/layouts/landing-kinetic-text",
145
+ "pullPaths": [
146
+ "cookbook/layouts/landing-kinetic-text"
147
+ ],
148
+ "files": [],
149
+ "dependencies": [],
150
+ "agentRecipe": "Use motion primitives marquee, kinetic-heading, magnetic from components/motion (already imported into the kitab from rahmanef.com). All respect prefers-reduced-motion automatically.",
151
+ "tags": [
152
+ "marketing",
153
+ "motion",
154
+ "type"
155
+ ]
156
+ },
157
+ {
158
+ "slug": "dashboard-three-column",
159
+ "title": "Dashboard — Three Column",
160
+ "category": "dashboard",
161
+ "description": "Kitab flagship. Left tree / main / right inspector. Resizable, collapsible, mobile drawer fallback. Used by Database, Tasks, Contacts.",
162
+ "source": "kitab-core",
163
+ "repoPath": "cookbook/layouts/dashboard-three-column",
164
+ "pullPaths": [
165
+ "cookbook/layouts/dashboard-three-column"
166
+ ],
167
+ "files": [],
168
+ "dependencies": [],
169
+ "agentRecipe": "Mount inside app/dashboard/<slice>/page.tsx. Wrap with the kitab's <ThreeColumnLayout>. Slot in slice-specific sidebars and inspectors. Mobile auto-collapses to drawers.",
170
+ "tags": [
171
+ "dashboard",
172
+ "three-column",
173
+ "resizable",
174
+ "responsive"
175
+ ]
176
+ },
177
+ {
178
+ "slug": "dashboard-ide",
179
+ "title": "Dashboard — IDE",
180
+ "category": "dashboard",
181
+ "description": "Activity bar + tabs + editor + bottom panel. Editor-first apps (notion, code, doc tools).",
182
+ "source": "synthesized",
183
+ "repoPath": "cookbook/layouts/dashboard-ide",
184
+ "pullPaths": [
185
+ "cookbook/layouts/dashboard-ide"
186
+ ],
187
+ "files": [],
188
+ "dependencies": [],
189
+ "agentRecipe": "Compose grid: 48px activity bar + tabs row + editor/inspector flex row + bottom console. Wire activity bar items to dispatch into tabs/inspector store.",
190
+ "tags": [
191
+ "dashboard",
192
+ "ide",
193
+ "editor"
194
+ ]
195
+ },
196
+ {
197
+ "slug": "dashboard-mobile-dock",
198
+ "title": "Dashboard — Mobile Dock",
199
+ "category": "dashboard",
200
+ "description": "Mobile-first auth app. MobileTopBar + content + MobileDashboardDock bottom nav. Native-app feel on mobile, sidebar on desktop.",
201
+ "source": "kitab-core",
202
+ "repoPath": "cookbook/layouts/dashboard-mobile-dock",
203
+ "pullPaths": [
204
+ "cookbook/layouts/dashboard-mobile-dock"
205
+ ],
206
+ "files": [],
207
+ "dependencies": [],
208
+ "agentRecipe": "Use ResponsiveDashboardShell which branches desktop (sidebar) vs mobile (dock). Customize MobileDashboardDock items and MobileTopBar workspace switcher to your domain.",
209
+ "tags": [
210
+ "dashboard",
211
+ "mobile",
212
+ "pwa"
213
+ ]
214
+ },
215
+ {
216
+ "slug": "cms-public-storefront",
217
+ "title": "CMS — Public Storefront",
218
+ "category": "cms",
219
+ "description": "E-commerce / blog public storefront. Convex read-only. Cart context + currency selector + i18n.",
220
+ "source": "kitab-core cms-lite",
221
+ "repoPath": "cookbook/layouts/cms-public-storefront",
222
+ "pullPaths": [
223
+ "cookbook/layouts/cms-public-storefront"
224
+ ],
225
+ "files": [],
226
+ "dependencies": [],
227
+ "agentRecipe": "Port kitab-core slices/cms-lite/ into your project's app/(cms)/ route group. Fetch products/pages from Convex via api.cmsLite.* queries.",
228
+ "tags": [
229
+ "cms",
230
+ "ecommerce",
231
+ "storefront"
232
+ ]
233
+ }
234
+ ]
235
+ }
package/package.json ADDED
@@ -0,0 +1,41 @@
1
+ {
2
+ "name": "rahman-resources",
3
+ "version": "0.1.0",
4
+ "description": "Template installer for Rahman Resources kitab — npx rahman-resources add <template> <target>",
5
+ "type": "module",
6
+ "license": "MIT",
7
+ "author": "Rahman <casadezian@gmail.com>",
8
+ "homepage": "https://github.com/rahmanef63/resource-site",
9
+ "repository": {
10
+ "type": "git",
11
+ "url": "git+https://github.com/rahmanef63/resource-site.git",
12
+ "directory": "packages/cli"
13
+ },
14
+ "bin": {
15
+ "rahman-resources": "bin/cli.js"
16
+ },
17
+ "files": [
18
+ "bin",
19
+ "lib",
20
+ "README.md"
21
+ ],
22
+ "engines": {
23
+ "node": ">=18"
24
+ },
25
+ "scripts": {
26
+ "gen": "node scripts/gen-manifest.mjs",
27
+ "prepublishOnly": "node scripts/gen-manifest.mjs"
28
+ },
29
+ "dependencies": {
30
+ "kleur": "^4.1.5",
31
+ "tiged": "^2.12.7"
32
+ },
33
+ "keywords": [
34
+ "rahman",
35
+ "kitab",
36
+ "template",
37
+ "installer",
38
+ "nextjs",
39
+ "convex"
40
+ ]
41
+ }