rahman-resources 1.14.2 → 1.16.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/lib/manifest.json CHANGED
@@ -3,13 +3,30 @@
3
3
  "repo": "rahmanef63/resource-site",
4
4
  "branch": "main",
5
5
  "aliases": {
6
- "blog-section": "landing-sections",
7
- "faq-section": "landing-sections",
8
- "portfolio-section": "landing-sections",
9
- "changelog-feed": "landing-sections",
10
- "feature-grid": "landing-sections",
11
- "testimonials-grid": "landing-sections",
12
- "pricing-page": "landing-sections"
6
+ "blog-section": "sections",
7
+ "faq-section": "sections",
8
+ "portfolio-section": "sections",
9
+ "changelog-feed": "sections",
10
+ "feature-grid": "sections",
11
+ "testimonials-grid": "sections",
12
+ "pricing-page": "sections",
13
+ "files": "file-upload",
14
+ "onboarding-wizard": "site-setup-wizard",
15
+ "media-studio": "design-studio",
16
+ "loading-states": "feedback-states",
17
+ "empty-states": "feedback-states",
18
+ "resume": "profile",
19
+ "about-profile": "profile",
20
+ "settings-page": "settings",
21
+ "shell-settings": "settings",
22
+ "doku-payment": "payment",
23
+ "midtrans-payment": "payment",
24
+ "landing-sections": "sections",
25
+ "notion-shell": "notion-ui",
26
+ "notion-database": "notion-ui",
27
+ "notion-sidebar": "notion-ui",
28
+ "notion": "notion-app",
29
+ "admin-console": "admin"
13
30
  },
14
31
  "layouts": [],
15
32
  "recipes": [],
@@ -121,6 +138,112 @@
121
138
  "ui"
122
139
  ]
123
140
  },
141
+ {
142
+ "slug": "booking",
143
+ "title": "Booking — session request form + owner inbox",
144
+ "category": "os",
145
+ "description": "One app that is BOTH a public 'book a session' request form AND the owner's triage inbox — it flips to show the inbox when the viewer can manage. Visitors submit name/email/topic (+ optional preferred time / note); the owner sees pending requests with Confirm / Decline. The backend is INJECTED via a small BookingAdapter (submit/list/setStatus/canManage): point configureBooking at your store, or keep the bundled in-memory mock so it renders fully interactive — form + inbox — with zero backend.",
146
+ "source": "rahmanef63/os-vps",
147
+ "install": "npx rahman-resources add booking",
148
+ "npmPackages": [],
149
+ "exampleCode": "\"use client\";\nimport { Booking } from \"@/features/booking\";\n\nexport default function BookingDemo() {\n // Unwired -> in-memory mock; configureBooking for a real backend.\n return <div className=\"h-dvh w-full\"><Booking /></div>;\n}",
150
+ "agentRecipe": "Stack: Next 16 + React 19 + Tailwind 4 + shadcn/ui. A booking request form + owner inbox. Fully client-side; backend optional.\n\nSTEP 1 — Install. `npx rr add booking`. Ensure `@/features/booking` resolves and Tailwind scans the slice folder.\n\nSTEP 2 — Deps. npm: `lucide-react`. shadcn: `npx shadcn@latest add button input textarea scroll-area`.\n\nSTEP 3 — Mount. `<Booking />` in a height-bearing box — unwired it runs on an in-memory mock store (form + inbox both live). Or register `bookingApp` in an appshell manifest.\n\nSTEP 4 — Real backend. `configureBooking({ mode:\"live\", submit, list, setStatus, canManage })` — submit takes { name, email, topic, preferredTime?, note? }; list returns rows with { id, status, createdAt }; omit list/canManage for a write-only public form.",
151
+ "tags": [
152
+ "booking",
153
+ "contact",
154
+ "form",
155
+ "inbox",
156
+ "lead",
157
+ "scheduling",
158
+ "ui"
159
+ ]
160
+ },
161
+ {
162
+ "slug": "html-studio",
163
+ "title": "HTML Studio — sandboxed HTML/CSS/JS editor with live preview",
164
+ "category": "os",
165
+ "description": "A tiny web-page studio: write HTML / CSS / JS and see it render LIVE in a sandboxed iframe (srcdoc + sandbox=allow-scripts WITHOUT allow-same-origin, so user code runs in an opaque origin and cannot read the host) — then Save to a shareable /p/<slug>. Code / Split / Preview view toggle, a device-width preview (responsive / tablet / phone), a saved-pages rail, and public/private visibility. The backend is INJECTED via a small HtmlStudioAdapter (save/load/list/remove): point configureHtmlStudio at your store, or keep the bundled in-memory mock so the editor + live preview + saved list are fully interactive with zero backend.",
166
+ "source": "rahmanef63/os-vps",
167
+ "install": "npx rahman-resources add html-studio",
168
+ "npmPackages": [],
169
+ "exampleCode": "\"use client\";\nimport { HtmlStudio } from \"@/features/html-studio\";\n\nexport default function HtmlStudioDemo() {\n // Unwired -> in-memory mock; configureHtmlStudio for a real backend.\n return <div className=\"h-dvh w-full\"><HtmlStudio /></div>;\n}",
170
+ "agentRecipe": "Stack: Next 16 + React 19 + Tailwind 4 + shadcn/ui. A sandboxed HTML/CSS/JS studio: editor + live iframe preview + saved pages. Fully client-side; backend optional.\n\nSTEP 1 — Install. `npx rr add html-studio`. Ensure `@/features/html-studio` resolves and Tailwind scans the slice folder.\n\nSTEP 2 — Deps. npm: `lucide-react`. shadcn: `npx shadcn@latest add button input textarea scroll-area`.\n\nSTEP 3 — Mount. `<HtmlStudio />` in a height-bearing box — unwired it runs on an in-memory mock (editor + live sandboxed preview + saved list all live). Pass `payload={{ slug }}` to open a page, or register `htmlStudioApp` in an appshell manifest.\n\nSTEP 4 — Real backend. `configureHtmlStudio({ mode:\"live\", save, load, list, remove })` — save takes { slug?, title, html, visibility } and returns { slug }; load(slug) -> SavedPage | null; omit save for a read-only sandbox or list to hide the saved rail. KEEP the iframe sandbox without allow-same-origin — it is the security boundary.",
171
+ "tags": [
172
+ "html",
173
+ "editor",
174
+ "sandbox",
175
+ "iframe",
176
+ "preview",
177
+ "playground",
178
+ "code",
179
+ "ui"
180
+ ]
181
+ },
182
+ {
183
+ "slug": "resources-launcher-admin",
184
+ "title": "Resources Admin — curated icon-launcher CRUD",
185
+ "category": "os",
186
+ "description": "An owner-gated admin app for a curated icon-launcher: add / edit / remove / reorder links (label, lucide icon NAME, url, group, order) that open in a new tab. The backend is INJECTED via a small ResourcesAdapter (list/upsert/remove/canManage): point configureResources at your store, or keep the bundled in-memory mock so the whole CRUD — including reorder — is interactive with zero backend. Icons are stored as lucide NAME strings and resolved client-side, so the same data drives a public launcher surface.",
187
+ "source": "rahmanef63/os-vps",
188
+ "install": "npx rahman-resources add resources-launcher-admin",
189
+ "npmPackages": [],
190
+ "exampleCode": "\"use client\";\nimport { ResourcesAdmin } from \"@/features/resources-launcher-admin\";\n\nexport default function ResourcesAdminDemo() {\n // Unwired -> in-memory mock; configureResources for a real backend.\n return <div className=\"h-dvh w-full\"><ResourcesAdmin /></div>;\n}",
191
+ "agentRecipe": "Stack: Next 16 + React 19 + Tailwind 4 + shadcn/ui. A curated icon-launcher admin (CRUD + reorder). Fully client-side; backend optional.\n\nSTEP 1 — Install. `npx rr add resources-launcher-admin`. Ensure `@/features/resources-launcher-admin` resolves and Tailwind scans the slice folder.\n\nSTEP 2 — Deps. npm: `lucide-react`. shadcn: `npx shadcn@latest add button input label scroll-area native-select`.\n\nSTEP 3 — Mount. `<ResourcesAdmin />` in a height-bearing box — unwired it runs on an in-memory mock store (add / edit / remove / reorder all live). Or register `resourcesAdminApp` in an appshell manifest.\n\nSTEP 4 — Real backend. `configureResources({ mode:\"live\", list, upsert, remove, canManage })` — list returns rows { id, label, icon, url, group, order }; upsert takes the same minus id to insert (pass id to patch); canManage gates the editor + reorder. Icons are lucide NAME strings resolved via resolveIcon.",
192
+ "tags": [
193
+ "launcher",
194
+ "links",
195
+ "bookmarks",
196
+ "admin",
197
+ "crud",
198
+ "icons",
199
+ "ui"
200
+ ]
201
+ },
202
+ {
203
+ "slug": "profile",
204
+ "title": "Profile — CV + identity card",
205
+ "category": "os",
206
+ "description": "One owner's identity in two co-located variants, behind one slug. resume: a clean one-column résumé / CV — name, roles, location, contacts, summary, skills, experience (role · org · period + bullets), projects — rendered by <Resume /> off a configureResume() seam, with a Print / PDF button. card: an \"About This Mac\"-style identity card — avatar / monogram, name, roles, outbound links, FAQ accordion — rendered by <AboutProfile /> off a configureAbout() seam. Both render a populated placeholder unwired (zero backend). Install one surface with `npx rr add profile resume|card`, or both with `npx rr add profile`.",
207
+ "source": "rahmanef63/os-vps",
208
+ "install": "npx rahman-resources add profile",
209
+ "npmPackages": [],
210
+ "exampleCode": "\"use client\";\nimport { Resume, AboutProfile } from \"@/features/profile\";\n\nexport default function ProfileDemo() {\n // Unwired -> generic placeholders; configureResume(cv) / configureAbout(card) for real data.\n return (\n <div className=\"grid h-dvh grid-cols-2 gap-4\">\n <Resume />\n <AboutProfile />\n </div>\n );\n}",
211
+ "agentRecipe": "Stack: Next 16 + React 19 + Tailwind 4 + shadcn/ui. Two identity renderers driven by injected data. Fully client-side; no backend required.\n\nSTEP 1 — Install. `npx rr add profile` for both, or `npx rr add profile resume` / `card` for one. Ensure `@/features/profile` resolves and Tailwind scans the slice folder.\n\nSTEP 2 — Deps. npm: `lucide-react`. shadcn: `npx shadcn@latest add button scroll-area avatar`.\n\nSTEP 3 — Mount. `<Resume />` (CV) or `<AboutProfile />` (card) in a height-bearing box — unwired each renders a generic placeholder. Or register `resumeApp` / `aboutProfileApp` in an appshell manifest.\n\nSTEP 4 — Real data. `configureResume(profile)` with a ResumeProfile { name, roles[], location, summary, contacts[], skills[], experience[], projects[] }, and/or `configureAbout(card)` with { name, roles[], description, links[], faq[] }, once at boot from Convex / a CMS / a JSON file. Resume's \"Print / PDF\" button calls window.print() against a print-friendly layout.",
212
+ "tags": [
213
+ "resume",
214
+ "cv",
215
+ "profile",
216
+ "portfolio",
217
+ "about",
218
+ "identity",
219
+ "bio",
220
+ "card",
221
+ "links",
222
+ "faq",
223
+ "print",
224
+ "ui"
225
+ ]
226
+ },
227
+ {
228
+ "slug": "start-here",
229
+ "title": "Start Here — guided OS onboarding tour",
230
+ "category": "os",
231
+ "description": "A guided 'Start Here' tour that lays the OS out as a path of stages, each stage opening real apps from the LIVE registry — drift-proof, it reads the injected app catalog instead of a hardcoded list, so adding an app surfaces it automatically (in a stage if listed, else a final 'Everything else' bucket). The catalog, the open(id) callback, and the stage journey are INJECTED via a small StartHereAdapter (apps / open / stages): point configureStartHere at your live app registry + window opener, or keep the bundled in-memory mock (a few generic apps + 3 stages) so the welcome tour renders fully alive with zero host.",
232
+ "source": "rahmanef63/os-vps",
233
+ "install": "npx rahman-resources add start-here",
234
+ "npmPackages": [],
235
+ "exampleCode": "\"use client\";\nimport { StartHere } from \"@/features/start-here\";\n\nexport default function StartHereDemo() {\n // Unwired -> in-memory mock catalog; configureStartHere for the live registry.\n return <div className=\"h-dvh w-full\"><StartHere /></div>;\n}",
236
+ "agentRecipe": "Stack: Next 16 + React 19 + Tailwind 4 + shadcn/ui. A guided onboarding tour that renders your live app catalog as a path of stages. Fully client-side; the catalog is injected.\n\nSTEP 1 — Install. `npx rr add start-here`. Ensure `@/features/start-here` resolves and Tailwind scans the slice folder.\n\nSTEP 2 — Deps. npm: `lucide-react`. shadcn: `npx shadcn@latest add button scroll-area`.\n\nSTEP 3 — Mount. `<StartHere />` in a height-bearing box — unwired it reads an in-memory mock catalog (generic apps + 3 stages) so the tour is fully alive. Or register `startHereApp` in an appshell manifest.\n\nSTEP 4 — Real catalog. `configureStartHere({ mode:\"live\", apps, open, stages })` — apps is your live registry as [{ id, title, icon, description? }]; open(id) launches the real app/window; stages is [{ title, blurb, appIds }] (apps not placed fall into a final \"Everything else\" stage). Drift-proof: read the registry, never hardcode the list.",
237
+ "tags": [
238
+ "onboarding",
239
+ "tour",
240
+ "welcome",
241
+ "launcher",
242
+ "guide",
243
+ "os",
244
+ "ui"
245
+ ]
246
+ },
124
247
  {
125
248
  "slug": "os-terminal",
126
249
  "title": "Terminal — shell emulator with live passthrough + PTY seam",
@@ -267,45 +390,27 @@
267
390
  ]
268
391
  },
269
392
  {
270
- "slug": "doku-payment",
271
- "title": "DOKU — Indonesia Payment",
393
+ "slug": "payment",
394
+ "title": "Payment — Indonesia PSP (DOKU · Midtrans)",
272
395
  "category": "integrations",
273
- "description": "Pembayaran lokal Indonesia via DOKU Checkout (hosted) + Direct (VA / QRIS / e-Wallet / PayLater / Minimarket / Kartu). HMAC-signed REST + signature-verified webhook + idempotent retries. Sibling slice to midtrans-payment dengan paymentOrders schema yang dishare.",
396
+ "description": "Indonesia payment providers behind one slug + ONE shared Convex backend (convex/features/payment discriminates on a provider column: paymentOrders + paymentWebhookEvents, unprefixed). Two frontend variants: doku — DOKU Hosted Checkout + Direct (VA / QRIS / e-Wallet / PayLater), HMAC-SHA256 signed REST, signature-verified webhook, idempotent retries, dependency-free, server-side env only. midtrans Snap hosted-modal checkout + orders history (needs npm midtrans-client + a NEXT_PUBLIC_MIDTRANS_CLIENT_KEY). Install one with `npx rr add payment doku|midtrans`, or both. A future stripe variant is reserved in the schema's provider union.",
274
397
  "source": "rahmanef63/resource-site",
275
398
  "docsUrl": "https://sandbox.doku.com/integration",
276
399
  "install": "",
277
400
  "npmPackages": [],
278
401
  "exampleCode": "",
279
- "agentRecipe": "Run `npx rr add doku-payment`. DOKU dual-mode: Checkout (hosted, all channels) atau Direct (single channel, returns VA/QRIS/deeplink). Webhook di /webhooks/doku verify HMAC-SHA256 (canonical: Client-Id + Request-Id + Request-Timestamp + Request-Target + Digest). Idempotency by request_id index. Server-only no NEXT_PUBLIC_*. Sandbox default (api-sandbox.doku.com); flip DOKU_IS_PRODUCTION=true for live.",
402
+ "agentRecipe": "Run `npx rr add payment` for both providers, or `npx rr add payment doku` / `midtrans`. Either variant copies the shared convex/features/payment backend. doku: Checkout (hosted) or Direct (single channel VA/QRIS/deeplink); webhook /webhooks/doku verifies HMAC-SHA256; server-only, no NEXT_PUBLIC_*. midtrans: Snap.js + window.snap.pay(token); webhook verifies signature_key; needs NEXT_PUBLIC_MIDTRANS_CLIENT_KEY. Both patch paymentOrders by orderId; sandbox by default.",
280
403
  "tags": [
281
404
  "payment",
282
- "doku",
405
+ "checkout",
283
406
  "indonesia",
407
+ "doku",
408
+ "midtrans",
409
+ "snap",
284
410
  "qris",
285
411
  "virtual-account",
286
412
  "ewallet",
287
- "checkout"
288
- ]
289
- },
290
- {
291
- "slug": "midtrans-payment",
292
- "title": "Midtrans — Indonesia Payment",
293
- "category": "integrations",
294
- "description": "Pembayaran lokal Indonesia via Midtrans Snap (BCA, Mandiri, BRI, e-wallet GoPay/OVO/Dana, QRIS). Webhook untuk konfirmasi. Provider-isolated under components/providers/midtrans + actions/midtrans so Doku/Stripe land as siblings.",
295
- "source": "rahmanef63/resource-site",
296
- "docsUrl": "https://docs.midtrans.com",
297
- "install": "npm i midtrans-client",
298
- "npmPackages": [
299
- "midtrans-client"
300
- ],
301
- "exampleCode": "",
302
- "agentRecipe": "Run `npx rr add midtrans-payment`. Midtrans Snap untuk pembayaran instant. Webhook ke Convex HTTP action /api/midtrans-callback untuk update order status. Ingat: PPN 11% sudah included di amount, jangan double-count.",
303
- "tags": [
304
- "payment",
305
- "midtrans",
306
- "indonesia",
307
- "qris",
308
- "snap"
413
+ "psp"
309
414
  ]
310
415
  },
311
416
  {
@@ -824,20 +929,24 @@
824
929
  },
825
930
  {
826
931
  "slug": "admin",
827
- "title": "Admin — Generic Shell",
932
+ "title": "Admin — generic shell + composed console",
828
933
  "category": "infra",
829
- "description": "HEADLESS admin scaffoldno chrome of its own; pair with dashboard-shell for app chrome. Per-instance admin landing scaffold + portable nav-from-registry factory. Consumer supplies a SliceRegistryAdapter (each slice declares its own admin.activity[]) + queryTable reader; the slice's buildAdminStats(opts) emits the { counts, unreadMessages, activity } shape Convex's admin.stats query returns. Pulled UP from rahmanef.com (Wave N+3.1, commit b542389) domain literals dropped at the kitab boundary. Gated by requireAdmin on Convex side; superadmin email gate via SUPER_ADMIN_EMAIL env.",
934
+ "description": "Access-gated admin surfaces behind one slug, in two variants each pulls ONLY its own convex backend (per-variant convex gating). shell: a HEADLESS minimal generic admin shell — a titled landing region + a portable buildAdminStats(opts) nav-from-registry factory (consumer supplies a SliceRegistryAdapter + queryTable reader) over convex/features/admin; superadmin gate via SUPER_ADMIN_EMAIL. console: the composed admin panel distilled from ~15 project admin panels — a gated two-column shell (AdminConsole) over a 26-section registry (ADMIN_CONSOLE_SECTIONS: observability / identity / ai / content / commerce / config) that mounts OTHER rr slices via a consumer-supplied `components` map (users→user-management, roles→rbac-roles, ai→ai-admin, tenants→platform-admin) plus 5 owned gap sections (Analytics, Audit-log, Nav config, SEO health, Leads/CRM) over convex/features/admin_console (ac_leads + ac_nav_items); gate injected, PLATFORM_ADMIN_EMAILS allowlist. Install one with `npx rr add admin shell|console`, or both with `npx rr add admin`. NOT the multi-tenant control plane that's the separate `platform-admin` slice (the console's `tenants` section provider).",
830
935
  "source": "rahmanef63/resource-site",
831
936
  "install": "npx rahman-resources add admin",
832
937
  "npmPackages": [],
833
938
  "exampleCode": "",
834
- "agentRecipe": "Run `rr add admin`. Wire <AdminPage labels={...} /> at /admin and call buildAdminStats({ sliceRegistry, queryTable }) inside convex/features/admin/query.ts sliceRegistry.entries flat-maps each feature's admin.activity[] declarations. Set SUPER_ADMIN_EMAIL via `npx convex env set` to lock down /admin to one address.",
939
+ "agentRecipe": "Run `npx rr add admin` for both, or `npx rr add admin shell` / `console` for one — each variant pulls only its own convex backend. shell: mount <AdminPage labels={...} /> + call buildAdminStats({ sliceRegistry, queryTable }) in convex/features/admin/query.ts; lock down with SUPER_ADMIN_EMAIL. console: mount <AdminConsole access={useAdminAccess()} components={{ users: <UsersPanel/>, ... }} /> — owned sections (analytics/audit-log/nav-config/seo-health/leads) render as-is, map each reuse section id to the panel from the peer slice you installed; compose adminConsoleTables into convex/schema.ts and front ac_leads.create with rate-limit; gate via PLATFORM_ADMIN_EMAILS.",
835
940
  "tags": [
836
941
  "infra",
837
942
  "admin",
943
+ "console",
838
944
  "shell",
839
- "crud",
840
- "nav-from-registry"
945
+ "dashboard",
946
+ "composition",
947
+ "rbac",
948
+ "access-gate",
949
+ "registry"
841
950
  ]
842
951
  },
843
952
  {
@@ -911,6 +1020,47 @@
911
1020
  "metadata-generator"
912
1021
  ]
913
1022
  },
1023
+ {
1024
+ "slug": "publisher-clean-html",
1025
+ "title": "Publisher — clean HTML",
1026
+ "category": "content",
1027
+ "description": "A pure render-to-clean-HTML engine harvested from the Instatic CMS publisher, decoupled from its host caching / loops / visual-components / Layer-C islands. publishPage(tree, registry, options) walks a generic node tree bottom-up: render children, escape every prop by its schema-declared control type (url -> safe-URL, richtext -> DOMPurify, svg -> SVG profile, else HTML-escape), dedup CSS by moduleId (~60-80% shrink), splice author classes + inline styles onto each rendered root, then assemble <!DOCTYPE> + reset + framework + module CSS + a deterministic (sorted) CSP plan. Bring your own ModuleRegistry (each module is a pure render(props, children) -> { html, css? }). Security spine: HTML escape + safe-URL, CSS-value guard (expression()/{}/</), </style RAWTEXT neutraliser, and an injectable DOMPurify seam (configureRichtextSanitizer) that fails closed — without a runtime, richtext strips all tags and SVG returns empty. Stateless, env-free, ZERO npm deps, no Convex. Ships a PublishPreview iframe-srcdoc pane. A Wave-1 leaf of the feature-harvest ULTRAPLAN; a dependency of the planned visual-page-canvas.",
1028
+ "source": "rahman-resources",
1029
+ "install": "npx rahman-resources add publisher-clean-html",
1030
+ "npmPackages": [],
1031
+ "exampleCode": "",
1032
+ "agentRecipe": "Run `npx rr add publisher-clean-html`. Build a registry: createModuleRegistry([{ id: 'base.body', render: (_p, kids) => ({ html: kids.join('') }) }, { id: 'demo.h', schema: { text: { type: 'text' } }, render: (p) => ({ html: `<h1>${p.text}</h1>`, css: 'h1{font-size:1.5rem}' }) }]). Tree = { rootNodeId, nodes: { [id]: { id, moduleId, props?, children?, classIds?, inlineStyles?, hidden? } } }. const { html } = publishPage(tree, registry, { title, cssEmission: 'inline' }). Preview: <PublishPreview html={html} />. Enable rich HTML/SVG by calling configureRichtextSanitizer(DOMPurify) once — without it, richtext/svg props fail closed (strip/empty). Props escape by schema control type, not key name.",
1033
+ "tags": [
1034
+ "content",
1035
+ "publisher",
1036
+ "html",
1037
+ "static-export",
1038
+ "sanitization",
1039
+ "csp",
1040
+ "css-dedup",
1041
+ "render"
1042
+ ]
1043
+ },
1044
+ {
1045
+ "slug": "content-loops",
1046
+ "title": "Content Loops",
1047
+ "category": "content",
1048
+ "description": "A data-source-driven repeater harvested from the Instatic CMS base.loop engine, decoupled from its publisher / page-tree / entryStack machinery into a plain React slice. Register pluggable LoopEntitySource backends (each declares display fields + an async fetch returning { items, totalItems }); drop <ContentLoop source|sourceId filters orderBy variants={[A, B]} /> to render one component per item, round-robining items across variants so alternating / featured layouts need no per-item branching. Ships a namespaced source registry (ids must be 'ns.name', so consumer sources can't shadow each other), createMockLoopSource for env-free previews + tests, and none/infinite pagination via useLoopPagination (a shadcn Load more button accumulates pageSize chunks). LoopItem.fields is a generic resolved-value bag — variants read item.fields.title directly, no second lookup. UI-only: no Convex tables shipped; point a source's fetch at Convex/REST when you have a backend. First slice of the feature-harvest ULTRAPLAN (docs/feature-harvest) and a dependency of the planned site-templates-engine + visual-page-canvas.",
1049
+ "source": "rahman-resources",
1050
+ "install": "npx rahman-resources add content-loops",
1051
+ "npmPackages": [],
1052
+ "exampleCode": "",
1053
+ "agentRecipe": "Run `npx rr add content-loops`. Env-free demo: createMockLoopSource() then <ContentLoop source={s} pagination='infinite' pageSize={6} variants={[CardA, CardB]} /> — variants round-robin (item i -> variants[i % n]). Real source: implement LoopEntitySource { id: 'blog.posts' (namespaced 'ns.name'), fields, async fetch({ filters, orderBy, direction, limit, offset }) returns { items, totalItems } }, call loopSourceRegistry.registerOrReplace(source), then <ContentLoop sourceId='blog.posts' variants={[...]} />. item.fields holds RESOLVED values — resolve media/author inside fetch.",
1054
+ "tags": [
1055
+ "content",
1056
+ "loop",
1057
+ "repeater",
1058
+ "list",
1059
+ "data-source",
1060
+ "pagination",
1061
+ "variants"
1062
+ ]
1063
+ },
914
1064
  {
915
1065
  "slug": "markdown",
916
1066
  "title": "Markdown — page container with CRUD tabs + diagrams",
@@ -936,15 +1086,15 @@
936
1086
  ]
937
1087
  },
938
1088
  {
939
- "slug": "notion",
940
- "title": "Notion — Block Editor",
1089
+ "slug": "notion-app",
1090
+ "title": "Notion App — Block Editor",
941
1091
  "category": "content",
942
1092
  "description": "Nested vertical slice (slice-of-slices) housing the full notion-page-clone block editor. Mount <PageEditor pageId/> inside <EditorAdapterProvider adapter/> — with `{}` it is a working plain-text/markdown block editor (slash menu, markdown triggers `# - > [] etc.`, dnd-kit drag with column layouts, per-block toolbar with turn-into/color/duplicate, per-block undo, paste-markdown import); host capabilities light up per optional adapter: data (block+page CRUD), selection (multi-select), comments (per-block popover), ai (Ask-AI panel), database (render + picker), mention (@-typeahead), page (nav/uploads/covers). Cluster-private shared layer under @notion/* — vendored block/page/database model, uid, inline markdown, page→md/html export. Pure convex block helpers (_blocks/_blockOps, unit-tested) ship in convex/features/notion. Same markdown grammar as the standalone `markdown` slice (blocksToMarkdown/markdownToBlocks bridge).",
943
1093
  "source": "notion-page-clone",
944
- "install": "npx rahman-resources add notion",
1094
+ "install": "npx rahman-resources add notion-app",
945
1095
  "npmPackages": [],
946
1096
  "exampleCode": "",
947
- "agentRecipe": "Run `npx rr add notion`. Wire the `@notion/*` path alias to `./slices/notion/*` in tsconfig. Minimal mount: `<EditorAdapterProvider adapter={{ data }}><PageEditor pageId={id}/></EditorAdapterProvider>` where `data` implements EditorDataAdapter (block+page CRUD over your store — see lib/dataAdapter.ts; a localStorage reference impl lives in the rr preview). Add capabilities incrementally: `selection` for multi-select, `comments` for per-block threads, `database.renderDatabase` to mount your database renderer inside database blocks, `mention.search` for @-typeahead, `page.navigateToPage`/`uploadFile` for nav + media. Convex hosts: copy convex/features/notion (_blocks/_blockOps are pure, unit-tested array ops) and keep handlers thin.",
1097
+ "agentRecipe": "Run `npx rr add notion-app`. Wire the `@notion/*` path alias to `./slices/notion-app/*` in tsconfig. Minimal mount: `<EditorAdapterProvider adapter={{ data }}><PageEditor pageId={id}/></EditorAdapterProvider>` where `data` implements EditorDataAdapter (block+page CRUD over your store — see lib/dataAdapter.ts; a localStorage reference impl lives in the rr preview). Add capabilities incrementally: `selection` for multi-select, `comments` for per-block threads, `database.renderDatabase` to mount your database renderer inside database blocks, `mention.search` for @-typeahead, `page.navigateToPage`/`uploadFile` for nav + media. Convex hosts: copy convex/features/notion (_blocks/_blockOps are pure, unit-tested array ops) and keep handlers thin.",
948
1098
  "tags": [
949
1099
  "content",
950
1100
  "notion",
@@ -957,15 +1107,15 @@
957
1107
  ]
958
1108
  },
959
1109
  {
960
- "slug": "landing-sections",
961
- "title": "Landing Sections",
1110
+ "slug": "sections",
1111
+ "title": "Sections — composable marketing/landing sections",
962
1112
  "category": "content",
963
1113
  "description": "Canonical landing-page composition slice — replaces the former standalone hero / cta / pricing-page / faq-section / feature-grid / testimonials-grid / blog-section / portfolio-section / changelog-feed slices (all merged here as `kind` variants in v0.2.0). Ships a pure reducer (v0.4.0: LANDING_UPSERT auto-shifts sibling `order` to keep positions unique; LANDING_DELETE closes the gap) + LandingProvider store adapter + admin LandingView/LandingEditorView built on the shared CRUD primitives, plus a per-section LandingSectionShell (background image + custom Tailwind className overlay + scroll-reveal). NEW in v0.4.0: a `sections/` library of config-driven public renderers (StatsSection, TestimonialsSection, FaqSection, PricingSection, NewsletterSection, CustomSection) that read `LandingSection.config` JSON merged over template defaults — content stays dashboard-controlled without per-template renderer code; plus `parse-config` helpers (parseConfigBadge/parseConfigField) and `sections/config` guards (parseConfigObject, cfg*). Sections carry { kind, order, title, subtitle, enabled, imageUrl, imageRatio, bgImageUrl, className, config (JSON) } with up/down reorder arrows. Lifted from the _templates fleet `_shared/landing` (2026-06-11) — the 8 standalone templates ship a byte-similar copy; this rr slice is the SSOT. Used by all 7 rr website templates.",
964
1114
  "source": "rahman-resources (lifted from _templates fleet)",
965
- "install": "npx rahman-resources add landing-sections",
1115
+ "install": "npx rahman-resources add sections",
966
1116
  "npmPackages": [],
967
1117
  "exampleCode": "",
968
- "agentRecipe": "Run `npx rr add landing-sections`. Fold `landingReducer` into your root reducer (cases LANDING_UPSERT + LANDING_DELETE), seed State.landingSections with `defaultLandingSections()`, wrap your StoreProvider with `<LandingProvider value={adapter}/>` where adapter maps {items, publicBase, adminBase, create, update, remove} from your dispatch. Mount `<LandingView/>` at `/admin/landing` and `<LandingEditorView id={params.id}/>` at `/admin/landing/[id]`. In HomePage iterate `state.landingSections.filter(s => s.enabled).sort((a,b) => a.order - b.order)` and render each inside `<LandingSectionShell section={s}>`; for stats/testimonials/pricing/faq/newsletter/custom kinds drop in the shipped `<StatsSection/>` etc. (they read `section.config` JSON over your template defaults), or map the remaining kinds (hero/features/blog/etc.) to your own renderer. Use `parseConfigBadge(section.config)` for a section badge. Requires the template-base shared surface that ships in every rr website template: `@/components/templates/_shared/motion` (Reveal/Stagger/CountUp/Marquee/useInView — the motion-kit primitives), `@/components/templates/_shared/ui/section-head`, and `@/components/templates/_shared/crud/*`. Sections also use shadcn accordion/card/carousel + embla-carousel-autoplay.",
1118
+ "agentRecipe": "Run `npx rr add sections`. Fold `landingReducer` into your root reducer (cases LANDING_UPSERT + LANDING_DELETE), seed State.landingSections with `defaultLandingSections()`, wrap your StoreProvider with `<LandingProvider value={adapter}/>` where adapter maps {items, publicBase, adminBase, create, update, remove} from your dispatch. Mount `<LandingView/>` at `/admin/landing` and `<LandingEditorView id={params.id}/>` at `/admin/landing/[id]`. In HomePage iterate `state.landingSections.filter(s => s.enabled).sort((a,b) => a.order - b.order)` and render each inside `<LandingSectionShell section={s}>`; for stats/testimonials/pricing/faq/newsletter/custom kinds drop in the shipped `<StatsSection/>` etc. (they read `section.config` JSON over your template defaults), or map the remaining kinds (hero/features/blog/etc.) to your own renderer. Use `parseConfigBadge(section.config)` for a section badge. Requires the template-base shared surface that ships in every rr website template: `@/components/templates/_shared/motion` (Reveal/Stagger/CountUp/Marquee/useInView — the motion-kit primitives), `@/components/templates/_shared/ui/section-head`, and `@/components/templates/_shared/crud/*`. Sections also use shadcn accordion/card/carousel + embla-carousel-autoplay.",
969
1119
  "tags": [
970
1120
  "admin",
971
1121
  "landing",
@@ -1042,15 +1192,15 @@
1042
1192
  ]
1043
1193
  },
1044
1194
  {
1045
- "slug": "onboarding-wizard",
1046
- "title": "Onboarding Wizard — first-run site setup",
1195
+ "slug": "site-setup-wizard",
1196
+ "title": "Site Setup Wizard — first-run site setup",
1047
1197
  "category": "ui",
1048
1198
  "description": "Post-claim onboarding wizard for clone-to-own templates, graduated from the headless template surface (2026-06-06). Multi-step card flow (Identitas / Branding / Konten / Selesai) that stores ALL site config in the host backend via a props-driven save callback — a non-coder configures their site with zero code. Branding step ships a readable shadcn Select theme-preset picker (color swatches per preset + grouped headers + live preview callback — replaces the white-on-white native select), brand color quick-chips, light/dark/system default mode, logo/favicon upload via injected ImageField, and optional Analytics ID. Identity step hints invalid email format. 'Lewati setup' marks onboarded without fields and reverts any browsed-but-unsaved preset. Props-driven (R3): no convex/react import — host wires settings.upsert / seed.seedSample / setup.status into props; pairs naturally with the theme-presets slice (registry + tweakcnSwatches + previewTweakcnPreset) but works with any theme system or none.",
1049
1199
  "source": "personal-brand-os",
1050
- "install": "npx rahman-resources add onboarding-wizard",
1200
+ "install": "npx rahman-resources add site-setup-wizard",
1051
1201
  "npmPackages": [],
1052
1202
  "exampleCode": "",
1053
- "agentRecipe": "Run `npx rr add onboarding-wizard`. Show from your admin gate when `setup.status().onboarded === false`: `<OnboardingWizard onDone={...} save={(f) => settingsUpsert(f)} seedSample={() => seedSample({})} seeded={status?.seeded} ImageField={ImageField} presetOptions={presets} onPresetPreview={(n) => preview(n)} />`. `save` receives Partial<OnboardingFields> + `markOnboarded: true` — back it with a `settings.upsert` mutation that patches only provided fields. Theme bridge (optional): with the theme-presets slice installed build `presetOptions` from `groupTweakcnPresets(registry.items)` + `tweakcnSwatches(p)` and pass `useThemePreset().preview` as `onPresetPreview` — the picker then live-previews while the user browses and `Lewati setup` reverts via `onPresetPreview(null)`. Omit `presetOptions` to hide the picker entirely; omit `ImageField` to hide logo/favicon upload. Full wiring recipe in the slice's HOST-SETUP.md.",
1203
+ "agentRecipe": "Run `npx rr add site-setup-wizard`. Show from your admin gate when `setup.status().onboarded === false`: `<OnboardingWizard onDone={...} save={(f) => settingsUpsert(f)} seedSample={() => seedSample({})} seeded={status?.seeded} ImageField={ImageField} presetOptions={presets} onPresetPreview={(n) => preview(n)} />`. `save` receives Partial<OnboardingFields> + `markOnboarded: true` — back it with a `settings.upsert` mutation that patches only provided fields. Theme bridge (optional): with the theme-presets slice installed build `presetOptions` from `groupTweakcnPresets(registry.items)` + `tweakcnSwatches(p)` and pass `useThemePreset().preview` as `onPresetPreview` — the picker then live-previews while the user browses and `Lewati setup` reverts via `onPresetPreview(null)`. Omit `presetOptions` to hide the picker entirely; omit `ImageField` to hide logo/favicon upload. Full wiring recipe in the slice's HOST-SETUP.md.",
1054
1204
  "tags": [
1055
1205
  "ui",
1056
1206
  "onboarding",
@@ -1064,15 +1214,15 @@
1064
1214
  ]
1065
1215
  },
1066
1216
  {
1067
- "slug": "files",
1068
- "title": "Files — pluggable upload + URL resolver with storage-adapter contract",
1217
+ "slug": "file-upload",
1218
+ "title": "File Upload — pluggable upload + URL resolver with storage-adapter contract",
1069
1219
  "category": "data",
1070
1220
  "description": "Host-pluggable file upload + URL resolution. Ships <FileUploadButton>, <FileChip>, useFileUpload(), useFileUrl() — all reading from a FilesAdapter the host wires via <FilesAdapterProvider>. Bundled localStorage demo adapter stores blobs as data URLs (small files only). Drop in your own adapter for Convex / S3 / GCS / R2. The slice itself has zero backend coupling, proving the storage-adapter pattern for the rest of the open-silong blocked-pending-adapter wave (cover, workspace-io, templates, …).",
1071
1221
  "source": "notion-page-clone",
1072
- "install": "npx rahman-resources add files",
1222
+ "install": "npx rahman-resources add file-upload",
1073
1223
  "npmPackages": [],
1074
1224
  "exampleCode": "",
1075
- "agentRecipe": "Run `npx rr add files`. Wrap your tree with `<FilesAdapterProvider adapter={...}>` — pass `useLocalStorageFilesAdapter()` for a quick demo or implement `FilesAdapter` (upload + remove + useUrl) against your backend. Then drop `<FileUploadButton onUploaded={...}>` anywhere; pair with `<FileChip fileRef={...}>` for rendered chips. Hooks: `useFileUpload()` returns `{upload, uploading, progress, removeFromStorage}`; `useFileUrl(storageId)` resolves to a fetchable URL (Convex adapter uses useQuery for live invalidation; demo reads localStorage synchronously). To wire S3: implement the FilesAdapter interface with presigned URLs + DELETE; the slice doesn't care which backend you pick.",
1225
+ "agentRecipe": "Run `npx rr add file-upload`. Wrap your tree with `<FilesAdapterProvider adapter={...}>` — pass `useLocalStorageFilesAdapter()` for a quick demo or implement `FilesAdapter` (upload + remove + useUrl) against your backend. Then drop `<FileUploadButton onUploaded={...}>` anywhere; pair with `<FileChip fileRef={...}>` for rendered chips. Hooks: `useFileUpload()` returns `{upload, uploading, progress, removeFromStorage}`; `useFileUrl(storageId)` resolves to a fetchable URL (Convex adapter uses useQuery for live invalidation; demo reads localStorage synchronously). To wire S3: implement the FilesAdapter interface with presigned URLs + DELETE; the slice doesn't care which backend you pick.",
1076
1226
  "tags": [
1077
1227
  "data",
1078
1228
  "upload",
@@ -1106,15 +1256,15 @@
1106
1256
  ]
1107
1257
  },
1108
1258
  {
1109
- "slug": "notion-database",
1110
- "title": "Notion Database",
1259
+ "slug": "notion-ui",
1260
+ "title": "Notion UI — page editor · database · sidebar primitives",
1111
1261
  "category": "ui",
1112
- "description": "Drop-in Notion-style database surface. 11 views (table, board, list, gallery, calendar, feed, chart, dashboard, form, map, timeline), 18 property/cell types, and a per-type column-header config menu (number format, date ranges, select, relation, rollup, formula) plus filter / sort / group / calculate, row peek, row multi-select, table cell selection + drag-to-fill (click a cell, drag the handle to copy down merged from the former database-cell-selection slice in v0.16), and CSV + JSON import-export. Pure and props-driven — the host owns the data and dispatches change callbacks. Domain types live in notion-shell (install it as the peer). Full release history in CHANGELOG.md.",
1113
- "source": "open-silong",
1114
- "install": "npx rahman-resources add notion-database",
1262
+ "description": "The pure, props-driven Notion-clone primitives suite behind one slug, over one shared domain-type model (Block / Page / Property / Database / DbView …). page: the page + block editor (NotionPage / NotionHeader / NotionBlock, SlashMenu, block renderers, inline-markdown decorator, built-in code (highlight.js) + equation (KaTeX)). database: a drop-in 11-view database (table/board/list/gallery/calendar/feed/chart/dashboard/form/map/timeline, 18 property/cell types, per-type column config, filter/sort/group/calculate, row peek + multi-select, cell drag-fill, formula engine, CSV/JSON import-export). sidebar: a standalone tree-nav sidebar (dnd reorder + reparent with depth projection, inline rename, per-row icon picker). All stateless + callback-CRUD — the host owns the data. Install one surface with `npx rr add notion-ui page|database|sidebar`, or all with `npx rr add notion-ui`; the shared/ domain type model is copied for every variant. NOT the full Notion app — that's the separate `notion` slice (adapter + Convex backed).",
1263
+ "source": "notion-page-clone",
1264
+ "install": "npx rahman-resources add notion-ui",
1115
1265
  "npmPackages": [],
1116
1266
  "exampleCode": "",
1117
- "agentRecipe": "**Controlled component.** `<NotionDatabase />` renders the whole surface — 11 views (table, board, list, gallery, calendar, feed, chart, dashboard, form, map, timeline), 18 cell types, filter / sort / group / calculate, row peek + multi-select, table cell drag-fill, CSV / JSON import-export. It is 100% props-driven: it owns NO data state — you hold `db` + `rows` and persist every change callback. The view tab strip scrolls horizontally and the card clips to its border, so it stays inside any container width.\n\n**1. Install** — `npx rr add notion-database`. Cascades the `notion-shell` peer (the domain types live there). Components import from `@/features/notion-database`; types from `@/features/notion-shell`.\n\n**2. Minimal wire-up** — keep `db: Database` + `rows: Page[]` in your store (a Convex query result or `useState`) and pass change handlers:\n```tsx\nimport { NotionDatabase } from '@/features/notion-database';\n\n<NotionDatabase\n db={db}\n rows={rows}\n onRowAdd={addRow}\n onRowUpdate={(rowId, propId, value) => setValue(rowId, propId, value)}\n onRowRemove={removeRow}\n onPropertyAdd={addProperty}\n onViewActivate={setActiveView}\n onViewAdd={addView}\n onViewConfigChange={(viewId, patch) => patchView(viewId, patch)}\n/>\n```\nOmit any callback and that affordance goes read-only; pass `readOnly` to freeze everything at once.\n\n**3. Data shape** — `Database = { id, name, properties: Property[], views: DatabaseViewConfig[], activeViewId }`; each row `Page = { id, title, rowProps: Record<propId, PropertyValue> }`. For `relation` / `rollup` cells also pass `pages` + `databases`; for `person` / `created_by` cells pass `userLookup(id)`.\n\n**4. Import / export** — mount `<DatabaseIOActions db={db} rows={rows} onImport={handleImport} />` in your toolbar: CSV/JSON in (with schema-diff), CSV/JSON + live-schema templates out. New columns arrive with a `tempId` — map it to your real backend id before writing their `rowProps`.\n\n**5. Backend (optional)** — the UI is store-agnostic. For Convex persistence copy `template-base/database-silong/convex/` (handlers → `convex/`, schema fragment merges into `convex/schema.ts`). Pick `_shared/minimal/` (single-user, noop authz) or `_shared/full/` (`@convex-dev/auth` + workspaces). See CONVEX-BACKEND.md.\n\n**Just one view?** Import it directly — `import { TableView } from '@/features/notion-database'` — and feed it `rows` + `renderCell` + `renderColumnHeader`.",
1267
+ "agentRecipe": "**Controlled component.** `<NotionDatabase />` renders the whole surface — 11 views (table, board, list, gallery, calendar, feed, chart, dashboard, form, map, timeline), 18 cell types, filter / sort / group / calculate, row peek + multi-select, table cell drag-fill, CSV / JSON import-export. It is 100% props-driven: it owns NO data state — you hold `db` + `rows` and persist every change callback. The view tab strip scrolls horizontally and the card clips to its border, so it stays inside any container width.\n\n**1. Install** — `npx rr add notion-ui database`. Cascades the `notion-shell` peer (the domain types live there). Components import from `@/features/notion-ui`; types from `@/features/notion-ui`.\n\n**2. Minimal wire-up** — keep `db: Database` + `rows: Page[]` in your store (a Convex query result or `useState`) and pass change handlers:\n```tsx\nimport { NotionDatabase } from '@/features/notion-ui';\n\n<NotionDatabase\n db={db}\n rows={rows}\n onRowAdd={addRow}\n onRowUpdate={(rowId, propId, value) => setValue(rowId, propId, value)}\n onRowRemove={removeRow}\n onPropertyAdd={addProperty}\n onViewActivate={setActiveView}\n onViewAdd={addView}\n onViewConfigChange={(viewId, patch) => patchView(viewId, patch)}\n/>\n```\nOmit any callback and that affordance goes read-only; pass `readOnly` to freeze everything at once.\n\n**3. Data shape** — `Database = { id, name, properties: Property[], views: DatabaseViewConfig[], activeViewId }`; each row `Page = { id, title, rowProps: Record<propId, PropertyValue> }`. For `relation` / `rollup` cells also pass `pages` + `databases`; for `person` / `created_by` cells pass `userLookup(id)`.\n\n**4. Import / export** — mount `<DatabaseIOActions db={db} rows={rows} onImport={handleImport} />` in your toolbar: CSV/JSON in (with schema-diff), CSV/JSON + live-schema templates out. New columns arrive with a `tempId` — map it to your real backend id before writing their `rowProps`.\n\n**5. Backend (optional)** — the UI is store-agnostic. For Convex persistence copy `template-base/database-silong/convex/` (handlers → `convex/`, schema fragment merges into `convex/schema.ts`). Pick `_shared/minimal/` (single-user, noop authz) or `_shared/full/` (`@convex-dev/auth` + workspaces). See CONVEX-BACKEND.md.\n\n**Just one view?** Import it directly — `import { TableView } from '@/features/notion-ui'` — and feed it `rows` + `renderCell` + `renderColumnHeader`.",
1118
1268
  "tags": [
1119
1269
  "ui",
1120
1270
  "notion",
@@ -1180,67 +1330,6 @@
1180
1330
  "dialog"
1181
1331
  ]
1182
1332
  },
1183
- {
1184
- "slug": "notion-sidebar",
1185
- "title": "Notion Sidebar — tree nav + page CRUD (rename · drag · icon picker)",
1186
- "category": "ui",
1187
- "description": "Standalone Notion-style tree-nav sidebar with full page CRUD, lifted out of notion-shell so it is reusable on its own. Props-driven + fully decoupled — owns its own lightweight NotionSidebarPage type (id / title / icon / parentId), imports no other slice. Capabilities: click a row to open; DOUBLE-CLICK a title to rename inline; drag the grip to reorder AND reparent (a @dnd-kit sortable tree with horizontal-offset depth projection); collapse/expand subtrees; hover a row for +subpage / delete. Optional per-row icon PICKER — wire `renderIconPicker` + `onIconChange` (e.g. @/features/icon-picker's IconPickerPopover) so clicking a row icon opens the picker. The host owns the data and dispatches onSelect / onCreate / onRename / onDelete / onMove / onIconChange. Compose with notion-shell (page editor) + notion-database (embedded DBs) for the full Notion-clone OS — see the notion-page-clone-os template.",
1188
- "source": "notion-page-clone",
1189
- "install": "npx rahman-resources add notion-sidebar",
1190
- "npmPackages": [],
1191
- "exampleCode": "",
1192
- "agentRecipe": "Run `npx rr add notion-sidebar`. Import `import { NotionSidebar, type NotionSidebarPage } from \"@/features/notion-sidebar\"`. Feed it a flat `pages: NotionSidebarPage[]` ({ id, title, icon, parentId }) — the sidebar builds the tree. Wire callbacks: onSelect(id), onCreate(parentId|null), onRename(id, title) [double-click a title to trigger], onDelete(id), onMove(id, parentId, beforeId) [drag the grip — reorders + reparents], onIconChange(id, icon). For rich icons pass `renderIcon` (display) + `renderIconPicker` (click-to-pick) wired to `@/features/icon-picker` (DynamicIcon + IconPickerPopover). npm: @dnd-kit/core + sortable + utilities. Pair with notion-shell (page editor) + notion-database (embedded DBs) — the notion-page-clone-os template shows the full reducer wiring.",
1193
- "tags": [
1194
- "ui",
1195
- "notion",
1196
- "sidebar",
1197
- "tree",
1198
- "nav",
1199
- "page",
1200
- "crud",
1201
- "rename",
1202
- "drag",
1203
- "dnd",
1204
- "reorder",
1205
- "reparent",
1206
- "icon-picker",
1207
- "primitive",
1208
- "portable",
1209
- "notion-like"
1210
- ]
1211
- },
1212
- {
1213
- "slug": "notion-shell",
1214
- "title": "Notion Shell — page + block editor primitives (pure, no sidebar/database)",
1215
- "category": "ui",
1216
- "description": "Portable Notion-style PAGE EDITOR primitives. v0.22 split the tree-nav SIDEBAR out into the standalone `notion-sidebar` slice (so the page editor and the sidebar are independently reusable); embedded DATABASES already live in the `notion-database` peer. notion-shell ships: NotionPage (optional cover image band + header + body), NotionHeader, NotionBlock (live inline-markdown decorator, hover actions menu, optional dragHandle slot, BUILT-IN code (highlight.js) + equation (KaTeX) blocks), SlashMenu (searchable block-type picker w/ keyboard nav), BlockActionsMenu (turn-into / duplicate / delete), InsertBlockButton (`+` trigger w/ SlashMenu), SortableBlockList (@dnd-kit render-prop wrapper for block reorder), PageActionsMenu (header dropdown: cover/favorite/duplicate/export/trash), InlineFormatToolbar + BlockColorPicker (colour) + MentionTypeahead + PageLayoutSection (layout). SPECIALISED BLOCK RENDERERS: ImageRenderer, EmbedRenderer (YouTube/Vimeo/Loom/Figma/CodePen/Spotify auto-detect). Domain types (Database, Property, PropertyValue, DbView, DatabaseViewConfig, DatabaseFilter, DatabaseSort) remain in notion-shell as the single source of truth (Page.rowOfDatabaseId + rowProps reference them). Pure / props-driven — host owns data + change handlers. Compose notion-sidebar + notion-shell + notion-database for the full Notion-clone OS.",
1217
- "source": "notion-page-clone",
1218
- "install": "npx rahman-resources add notion-shell",
1219
- "npmPackages": [],
1220
- "exampleCode": "",
1221
- "agentRecipe": "Run `npx rr add notion-shell` for the portable PAGE EDITOR wrappers ONLY (no backend; the tree-nav sidebar is the separate `notion-sidebar` slice). NPM deps: @dnd-kit/core, @dnd-kit/sortable, @dnd-kit/utilities. Import: `import { NotionPage, NotionBlock, SortableBlockList, PageActionsMenu, InsertBlockButton, InlineFormatToolbar, ImageRenderer, EmbedRenderer } from \"@/features/notion-shell\"`. NotionBlock ships slash menu + decorator + actions menu + dragHandle slot. **`createDefaultBlockRenderers()` returns the block-renderer registry — pass it to `<NotionBlock blockRenderers={…}>` so callout (icon+kind picker), table (editable grid), divider, image, embed, code (highlight.js) + equation (KaTeX) all render. code + equation are now BUILT-IN to notion-shell (npm: katex + highlight.js) — no adapter needed. Only `database` + `toc` are injected at the app level (they depend on host data + the sibling notion-database slice).** NotionPage ships optional cover prop. SortableBlockList wraps a render-prop callback `(id, dragProps) => <NotionBlock dragHandle={...} />`. NotionDatabase ships 6 views via VIEW_REGISTRY. Property cells: text/number/checkbox/select/multi-select/status/date/url/email/phone all built in. For rich icon UX wire `renderIcon` + `renderIconPicker` to `@/features/icon-picker`. **v0.17 — Notion-canonical editing keys (`blockKeyHandler.ts`): Enter splits at the caret into a new block (lists continue their type; an empty list item exits to paragraph); Backspace on an empty non-paragraph downgrades it to a plain paragraph (re-triggerable with `/`); a second Backspace on an empty paragraph merges into the previous block; Arrow up/down at a line edge hops blocks. Wire the host callbacks on `<NotionBlock>`: `onInsertAfter(type, init) => newId`, `onMergeBack()`, `onFocusSibling(dir)` — plus `focusBlock(id, offset?)` exported to move the caret after a host state change. The preview `page-demo.tsx` and the notion-clone template `DocView` show full array- and reducer-based wirings.** PRODUCT POINTER: the full Convex-backed Notion-clone OS (multi-workspace + auth + sharing + comments + snapshots + MCP) lives at https://github.com/rahmanef63/open-silong — clone that repo for the production stack; use this slice when you only need to embed the Notion-style UI in another project.**",
1222
- "tags": [
1223
- "ui",
1224
- "notion",
1225
- "shell",
1226
- "wrapper",
1227
- "page",
1228
- "block",
1229
- "editor",
1230
- "primitive",
1231
- "portable",
1232
- "slash-menu",
1233
- "decorator",
1234
- "wysiwyg",
1235
- "drag",
1236
- "cover",
1237
- "embed",
1238
- "image",
1239
- "code",
1240
- "equation",
1241
- "notion-like"
1242
- ]
1243
- },
1244
1333
  {
1245
1334
  "slug": "workspace-shell",
1246
1335
  "title": "Workspace Shell — atomic (workspace × menuSet) NavContext",
@@ -1327,41 +1416,24 @@
1327
1416
  ]
1328
1417
  },
1329
1418
  {
1330
- "slug": "empty-states",
1331
- "title": "Empty States — 404/500/403 + zero-data",
1419
+ "slug": "feedback-states",
1420
+ "title": "Feedback States — loading skeletons + empty/error states",
1332
1421
  "category": "ui",
1333
- "description": "Configurable EmptyState composing the shadcn Empty primitive: kind presets 404 / 500 / 403 / no-results / empty-list / first-use with default lucide icon + copy, all overridable. Primary/secondary actions. ErrorPage full-page wrapper is a drop-in for app/not-found.tsx and app/error.tsx (recipes in README).",
1422
+ "description": "Two co-located placeholder surfaces behind one slug. loading: a configurable LoadingSkeleton over the shadcn Skeleton (kind presets text / card / list / table / form / page / block, overridable count + columns) plus a spinner LoadingState (inline / block / overlay) for in-flight work. empty: a configurable EmptyState over the shadcn Empty (404 / 500 / 403 / no-results / empty-list / first-use, overridable icon/title/copy/actions) plus an ErrorPage full-page wrapper for app/not-found.tsx and app/error.tsx. Install one surface with `npx rr add feedback-states loading|empty`, or both with `npx rr add feedback-states`. Replaces ad-hoc animate-pulse divs, hand-rolled Loader2 spans, and one-off error pages.",
1334
1423
  "source": "rr original",
1335
- "install": "npx rahman-resources add empty-states",
1424
+ "install": "npx rahman-resources add feedback-states",
1336
1425
  "npmPackages": [],
1337
1426
  "exampleCode": "",
1338
- "agentRecipe": "Run `npx rr add empty-states`. Drop <EmptyState kind=\"no-results\" /> into zero-data spots; wrap with <ErrorPage kind=\"404\" /> in app/not-found.tsx and kind=\"500\" in app/error.tsx. Every preset's icon/title/description/action overridable per use.",
1427
+ "agentRecipe": "Run `npx rr add feedback-states` for both, or `npx rr add feedback-states loading` / `empty` for one surface. loading: <LoadingSkeleton kind=\"table\" count={8} /> mirrors streamed content, kind=\"page\" drops into route loading.tsx, <LoadingState variant=\"inline|block|overlay\" /> for in-flight work. empty: <EmptyState kind=\"no-results\" /> in zero-data spots, <ErrorPage kind=\"404\" /> in app/not-found.tsx and kind=\"500\" in app/error.tsx. Every preset overridable per use.",
1339
1428
  "tags": [
1429
+ "loading",
1430
+ "skeleton",
1431
+ "spinner",
1340
1432
  "empty-state",
1341
1433
  "404",
1342
1434
  "500",
1343
1435
  "403",
1344
1436
  "error-page",
1345
- "no-results",
1346
- "onboarding",
1347
- "basics"
1348
- ]
1349
- },
1350
- {
1351
- "slug": "loading-states",
1352
- "title": "Loading States — skeletons + spinners SSOT",
1353
- "category": "ui",
1354
- "description": "Configurable LoadingSkeleton composing the shadcn Skeleton primitive: kind presets text / card / list / table / form / page / block with overridable count + columns. Spinner-based LoadingState (inline / block / overlay) covers in-flight work where a skeleton would be wrong. The page kind drops straight into a route loading.tsx (recipe in README).",
1355
- "source": "rr original",
1356
- "install": "npx rahman-resources add loading-states",
1357
- "npmPackages": [],
1358
- "exampleCode": "",
1359
- "agentRecipe": "Run `npx rr add loading-states`. Pick the LoadingSkeleton kind that mirrors the streamed content (<LoadingSkeleton kind=\"table\" count={8} />); use kind=\"page\" inside route loading.tsx. For in-flight work (submits, refetches) use <LoadingState variant=\"inline|block|overlay\" /> instead of a skeleton.",
1360
- "tags": [
1361
- "loading",
1362
- "skeleton",
1363
- "spinner",
1364
- "suspense",
1365
1437
  "fallback",
1366
1438
  "placeholder",
1367
1439
  "basics"
@@ -1388,22 +1460,25 @@
1388
1460
  ]
1389
1461
  },
1390
1462
  {
1391
- "slug": "settings-page",
1392
- "title": "Settings Page adapter-driven shell",
1463
+ "slug": "settings",
1464
+ "title": "Settings — account + appearance shells",
1393
1465
  "category": "ui",
1394
- "description": "SettingsShell two-column settings surface: section nav (mobile collapses to a Select) + Profile (avatar/name/email/bio), Preferences (theme/language/density), Notifications (switch rows), Danger zone (AlertDialog-confirmed delete). SettingsAdapter = load() + save(patch) wire to Convex or anything; createMemoryAdapter ships for demos. Optimistic save with rollback.",
1466
+ "description": "Two settings surfaces behind one slug, each adapter-driven so the slice owns no data. account: SettingsShell two-column surface (nav collapses to a Select on mobile) Profile (avatar/name/email/bio), Preferences (theme/language/density), Notifications (switch rows), Danger zone (AlertDialog-confirmed delete) over an ASYNC SettingsAdapter { load, save(patch) } with optimistic save + rollback; createMemoryAdapter ships for demos. appearance: AppearancePanel (style/mode/accent/wallpaper/reduce-transparency/display) over a SYNC per-setting AppearanceAdapter, plus the generic SettingsSection / SettingsRow / Segmented / AccentSwatches primitives you compose custom panels from. Install one surface with `npx rr add settings account|appearance`, or both with `npx rr add settings`.",
1395
1467
  "source": "rr original",
1396
- "install": "npx rahman-resources add settings-page",
1468
+ "install": "npx rahman-resources add settings",
1397
1469
  "npmPackages": [],
1398
1470
  "exampleCode": "",
1399
- "agentRecipe": "Run `npx rr add settings-page`. Implement SettingsAdapter { load, save } over your backend (Convex query + mutation), pass to <SettingsShell adapter>. save receives per-section partial patches shallow-merge server-side. onDeleteAccount callback wires the danger zone.",
1471
+ "agentRecipe": "Run `npx rr add settings` for both, or `npx rr add settings account` / `appearance` for one. account: implement SettingsAdapter { load, save } over your backend (Convex query + mutation), pass to <SettingsShell adapter>; save gets per-section partial patches (shallow-merge server-side); onDeleteAccount wires the danger zone. appearance: build an AppearanceAdapter (per-setting SegSetting values) from your appearance store, pass to <AppearancePanel appearance>; or compose custom panels from <SettingsSection>/<SettingsRow>/<Segmented>/<AccentSwatches>.",
1400
1472
  "tags": [
1401
1473
  "settings",
1402
- "account",
1403
- "profile",
1404
1474
  "preferences",
1405
- "notifications",
1406
- "danger-zone",
1475
+ "account",
1476
+ "appearance",
1477
+ "theme",
1478
+ "adapter",
1479
+ "shell",
1480
+ "primitives",
1481
+ "ui",
1407
1482
  "basics"
1408
1483
  ]
1409
1484
  },
@@ -1427,15 +1502,15 @@
1427
1502
  ]
1428
1503
  },
1429
1504
  {
1430
- "slug": "media-studio",
1431
- "title": "Media Studio — photo / social design canvas",
1505
+ "slug": "design-studio",
1506
+ "title": "Design Studio — photo / social design canvas",
1432
1507
  "category": "os",
1433
1508
  "description": "A layered canvas studio: image/text/shape layers with filters, masks, transforms, safe-area guides and aspect presets (1:1/4:5/9:16/16:9), plus an export modal (download / copy / import JSON). Runs fully offline on bundled gradient-SVG samples. Host wiring is one call: configureMediaStudio({ saveDoc, imageSources }) lights up Save-to-host and feeds real image sources. Self-contained: inspector hooks are inert seams in lib/host.ts.",
1434
1509
  "source": "rahmanef63/os-vps",
1435
- "install": "npx rahman-resources add media-studio",
1510
+ "install": "npx rahman-resources add design-studio",
1436
1511
  "npmPackages": [],
1437
- "exampleCode": "\"use client\";\nimport { MediaStudio } from \"@/features/media-studio\";\n\nexport default function StudioDemo() {\n return <div className=\"h-dvh w-full\"><MediaStudio /></div>;\n}",
1438
- "agentRecipe": "Stack: Next 16 + React 19 + Tailwind 4 + shadcn/ui. Layered canvas editor. Fully client-side; no backend required.\n\nSTEP 1 — Install. `npx rr add media-studio`. Ensure `@/features/media-studio` resolves and Tailwind scans the slice folder.\n\nSTEP 2 — Deps. npm: `lucide-react`. shadcn: button, dialog, badge, tooltip, scroll-area.\n\nSTEP 3 — Mount. `<MediaStudio />` in a height-bearing box — unwired it edits bundled sample layers. Or register `mediaStudioApp` in an appshell manifest.\n\nSTEP 4 — Host wiring. `configureMediaStudio({ saveDoc, imageSources })` — saveDoc persists the serialized document (enables Save-to-host in the export modal); imageSources supplies image URLs for new layers.",
1512
+ "exampleCode": "\"use client\";\nimport { MediaStudio } from \"@/features/design-studio\";\n\nexport default function StudioDemo() {\n return <div className=\"h-dvh w-full\"><MediaStudio /></div>;\n}",
1513
+ "agentRecipe": "Stack: Next 16 + React 19 + Tailwind 4 + shadcn/ui. Layered canvas editor. Fully client-side; no backend required.\n\nSTEP 1 — Install. `npx rr add design-studio`. Ensure `@/features/design-studio` resolves and Tailwind scans the slice folder.\n\nSTEP 2 — Deps. npm: `lucide-react`. shadcn: button, dialog, badge, tooltip, scroll-area.\n\nSTEP 3 — Mount. `<MediaStudio />` in a height-bearing box — unwired it edits bundled sample layers. Or register `mediaStudioApp` in an appshell manifest.\n\nSTEP 4 — Host wiring. `configureMediaStudio({ saveDoc, imageSources })` — saveDoc persists the serialized document (enables Save-to-host in the export modal); imageSources supplies image URLs for new layers.",
1439
1514
  "tags": [
1440
1515
  "canvas",
1441
1516
  "editor",
@@ -1463,24 +1538,6 @@
1463
1538
  "launcher",
1464
1539
  "ui"
1465
1540
  ]
1466
- },
1467
- {
1468
- "slug": "shell-settings",
1469
- "title": "Shell Settings — settings-app UI primitives",
1470
- "category": "ui",
1471
- "description": "The settings-app building blocks: SettingsSection, Row, AccentSwatches, a slice-local Segmented control, and a ready AppearancePanel (style/mode/accent/wallpaper/device/transparency groups — every group optional). Pure presentation: the injected AppearanceAdapter IS the contract, so it binds to any appearance store (appshell capabilities, zustand, plain useState) with zero slice edits.",
1472
- "source": "rahmanef63/os-vps",
1473
- "install": "npx rahman-resources add shell-settings",
1474
- "npmPackages": [],
1475
- "exampleCode": "\"use client\";\nimport { useState } from \"react\";\nimport { AppearancePanel } from \"@/features/shell-settings\";\n\nexport default function SettingsDemo() {\n const [mode, setMode] = useState<\"light\" | \"dark\">(\"light\");\n return <AppearancePanel adapter={{ mode: { value: mode, set: setMode } }} />;\n}",
1476
- "agentRecipe": "Stack: Next 16 + React 19 + Tailwind 4 + shadcn/ui. Settings UI primitives. Pure presentation; state injected.\n\nSTEP 1 — Install. `npx rr add shell-settings`. Ensure `@/features/shell-settings` resolves and Tailwind scans the slice folder.\n\nSTEP 2 — Deps. npm: `lucide-react`. shadcn: button, switch, toggle-group, separator.\n\nSTEP 3 — Mount. `<AppearancePanel adapter={adapter} />` with an AppearanceAdapter (all groups optional — omit a group to hide it), or compose SettingsSection/Row/AccentSwatches/Segmented directly for custom panels.\n\nSTEP 4 — Bind. Wire the adapter to your appearance store (theme mode, accent, wallpaper, device, transparency) — the panel re-renders from the values you pass; no internal state.",
1477
- "tags": [
1478
- "settings",
1479
- "preferences",
1480
- "appearance",
1481
- "primitives",
1482
- "ui"
1483
- ]
1484
1541
  }
1485
1542
  ],
1486
1543
  "slices": [
@@ -1675,6 +1732,190 @@
1675
1732
  ],
1676
1733
  "agentRecipe": "Stack: Next 16 + React 19 + Tailwind 4 + shadcn/ui. Host telemetry dashboard. Fully client-side; no backend required.\n\nSTEP 1 — Install. `npx rr add system-monitor`. Ensure `@/features/system-monitor` resolves and Tailwind scans the slice folder.\n\nSTEP 2 — Deps. npm: `lucide-react`. shadcn: `npx shadcn@latest add scroll-area`.\n\nSTEP 3 — Mount. `<SystemMonitor />` in a height-bearing box — unwired it runs a wavy in-browser telemetry mock. Or register `systemMonitorApp` in an appshell manifest.\n\nSTEP 4 — Real telemetry. `configureSysmon({ mode:\"live\", stats, processes })` — stats returns { cpu:{pct,cores}, mem:{used,total}, disk:{used,total}, net?:{rx,tx}, uptime }; processes returns [{ pid, name, status, cpu, mem }]."
1677
1734
  },
1735
+ {
1736
+ "slug": "booking",
1737
+ "title": "Booking — session request form + owner inbox",
1738
+ "category": "os",
1739
+ "kind": "ui",
1740
+ "version": "1.0.0",
1741
+ "description": "One app that is BOTH a public 'book a session' request form AND the owner's triage inbox — it flips to show the inbox when the viewer can manage. Visitors submit name/email/topic (+ optional preferred time / note); the owner sees pending requests with Confirm / Decline. The backend is INJECTED via a small BookingAdapter (submit/list/setStatus/canManage): point configureBooking at your store, or keep the bundled in-memory mock so it renders fully interactive — form + inbox — with zero backend.",
1742
+ "source": "rahmanef63/os-vps",
1743
+ "slicePath": "frontend/slices/booking",
1744
+ "convexPaths": [],
1745
+ "npm": [
1746
+ "lucide-react"
1747
+ ],
1748
+ "shadcn": [
1749
+ "button",
1750
+ "input",
1751
+ "textarea",
1752
+ "scroll-area"
1753
+ ],
1754
+ "env": [],
1755
+ "peers": [],
1756
+ "providers": [],
1757
+ "tags": [
1758
+ "booking",
1759
+ "contact",
1760
+ "form",
1761
+ "inbox",
1762
+ "lead",
1763
+ "scheduling",
1764
+ "ui"
1765
+ ],
1766
+ "agentRecipe": "Stack: Next 16 + React 19 + Tailwind 4 + shadcn/ui. A booking request form + owner inbox. Fully client-side; backend optional.\n\nSTEP 1 — Install. `npx rr add booking`. Ensure `@/features/booking` resolves and Tailwind scans the slice folder.\n\nSTEP 2 — Deps. npm: `lucide-react`. shadcn: `npx shadcn@latest add button input textarea scroll-area`.\n\nSTEP 3 — Mount. `<Booking />` in a height-bearing box — unwired it runs on an in-memory mock store (form + inbox both live). Or register `bookingApp` in an appshell manifest.\n\nSTEP 4 — Real backend. `configureBooking({ mode:\"live\", submit, list, setStatus, canManage })` — submit takes { name, email, topic, preferredTime?, note? }; list returns rows with { id, status, createdAt }; omit list/canManage for a write-only public form."
1767
+ },
1768
+ {
1769
+ "slug": "html-studio",
1770
+ "title": "HTML Studio — sandboxed HTML/CSS/JS editor with live preview",
1771
+ "category": "os",
1772
+ "kind": "ui",
1773
+ "version": "1.0.0",
1774
+ "description": "A tiny web-page studio: write HTML / CSS / JS and see it render LIVE in a sandboxed iframe (srcdoc + sandbox=allow-scripts WITHOUT allow-same-origin, so user code runs in an opaque origin and cannot read the host) — then Save to a shareable /p/<slug>. Code / Split / Preview view toggle, a device-width preview (responsive / tablet / phone), a saved-pages rail, and public/private visibility. The backend is INJECTED via a small HtmlStudioAdapter (save/load/list/remove): point configureHtmlStudio at your store, or keep the bundled in-memory mock so the editor + live preview + saved list are fully interactive with zero backend.",
1775
+ "source": "rahmanef63/os-vps",
1776
+ "slicePath": "frontend/slices/html-studio",
1777
+ "convexPaths": [],
1778
+ "npm": [
1779
+ "lucide-react"
1780
+ ],
1781
+ "shadcn": [
1782
+ "button",
1783
+ "input",
1784
+ "textarea",
1785
+ "scroll-area"
1786
+ ],
1787
+ "env": [],
1788
+ "peers": [],
1789
+ "providers": [],
1790
+ "tags": [
1791
+ "html",
1792
+ "editor",
1793
+ "sandbox",
1794
+ "iframe",
1795
+ "preview",
1796
+ "playground",
1797
+ "code",
1798
+ "ui"
1799
+ ],
1800
+ "agentRecipe": "Stack: Next 16 + React 19 + Tailwind 4 + shadcn/ui. A sandboxed HTML/CSS/JS studio: editor + live iframe preview + saved pages. Fully client-side; backend optional.\n\nSTEP 1 — Install. `npx rr add html-studio`. Ensure `@/features/html-studio` resolves and Tailwind scans the slice folder.\n\nSTEP 2 — Deps. npm: `lucide-react`. shadcn: `npx shadcn@latest add button input textarea scroll-area`.\n\nSTEP 3 — Mount. `<HtmlStudio />` in a height-bearing box — unwired it runs on an in-memory mock (editor + live sandboxed preview + saved list all live). Pass `payload={{ slug }}` to open a page, or register `htmlStudioApp` in an appshell manifest.\n\nSTEP 4 — Real backend. `configureHtmlStudio({ mode:\"live\", save, load, list, remove })` — save takes { slug?, title, html, visibility } and returns { slug }; load(slug) -> SavedPage | null; omit save for a read-only sandbox or list to hide the saved rail. KEEP the iframe sandbox without allow-same-origin — it is the security boundary."
1801
+ },
1802
+ {
1803
+ "slug": "resources-launcher-admin",
1804
+ "title": "Resources Admin — curated icon-launcher CRUD",
1805
+ "category": "os",
1806
+ "kind": "ui",
1807
+ "version": "1.0.0",
1808
+ "description": "An owner-gated admin app for a curated icon-launcher: add / edit / remove / reorder links (label, lucide icon NAME, url, group, order) that open in a new tab. The backend is INJECTED via a small ResourcesAdapter (list/upsert/remove/canManage): point configureResources at your store, or keep the bundled in-memory mock so the whole CRUD — including reorder — is interactive with zero backend. Icons are stored as lucide NAME strings and resolved client-side, so the same data drives a public launcher surface.",
1809
+ "source": "rahmanef63/os-vps",
1810
+ "slicePath": "frontend/slices/resources-launcher-admin",
1811
+ "convexPaths": [],
1812
+ "npm": [
1813
+ "lucide-react"
1814
+ ],
1815
+ "shadcn": [
1816
+ "button",
1817
+ "input",
1818
+ "label",
1819
+ "scroll-area",
1820
+ "native-select"
1821
+ ],
1822
+ "env": [],
1823
+ "peers": [],
1824
+ "providers": [],
1825
+ "tags": [
1826
+ "launcher",
1827
+ "links",
1828
+ "bookmarks",
1829
+ "admin",
1830
+ "crud",
1831
+ "icons",
1832
+ "ui"
1833
+ ],
1834
+ "agentRecipe": "Stack: Next 16 + React 19 + Tailwind 4 + shadcn/ui. A curated icon-launcher admin (CRUD + reorder). Fully client-side; backend optional.\n\nSTEP 1 — Install. `npx rr add resources-launcher-admin`. Ensure `@/features/resources-launcher-admin` resolves and Tailwind scans the slice folder.\n\nSTEP 2 — Deps. npm: `lucide-react`. shadcn: `npx shadcn@latest add button input label scroll-area native-select`.\n\nSTEP 3 — Mount. `<ResourcesAdmin />` in a height-bearing box — unwired it runs on an in-memory mock store (add / edit / remove / reorder all live). Or register `resourcesAdminApp` in an appshell manifest.\n\nSTEP 4 — Real backend. `configureResources({ mode:\"live\", list, upsert, remove, canManage })` — list returns rows { id, label, icon, url, group, order }; upsert takes the same minus id to insert (pass id to patch); canManage gates the editor + reorder. Icons are lucide NAME strings resolved via resolveIcon."
1835
+ },
1836
+ {
1837
+ "slug": "profile",
1838
+ "title": "Profile — CV + identity card",
1839
+ "category": "os",
1840
+ "kind": "ui",
1841
+ "version": "1.0.0",
1842
+ "description": "One owner's identity in two co-located variants, behind one slug. resume: a clean one-column résumé / CV — name, roles, location, contacts, summary, skills, experience (role · org · period + bullets), projects — rendered by <Resume /> off a configureResume() seam, with a Print / PDF button. card: an \"About This Mac\"-style identity card — avatar / monogram, name, roles, outbound links, FAQ accordion — rendered by <AboutProfile /> off a configureAbout() seam. Both render a populated placeholder unwired (zero backend). Install one surface with `npx rr add profile resume|card`, or both with `npx rr add profile`.",
1843
+ "source": "rahmanef63/os-vps",
1844
+ "slicePath": "frontend/slices/profile",
1845
+ "convexPaths": [],
1846
+ "npm": [
1847
+ "lucide-react"
1848
+ ],
1849
+ "shadcn": [
1850
+ "button",
1851
+ "scroll-area",
1852
+ "avatar"
1853
+ ],
1854
+ "env": [],
1855
+ "peers": [],
1856
+ "providers": [],
1857
+ "tags": [
1858
+ "resume",
1859
+ "cv",
1860
+ "profile",
1861
+ "portfolio",
1862
+ "about",
1863
+ "identity",
1864
+ "bio",
1865
+ "card",
1866
+ "links",
1867
+ "faq",
1868
+ "print",
1869
+ "ui"
1870
+ ],
1871
+ "agentRecipe": "Stack: Next 16 + React 19 + Tailwind 4 + shadcn/ui. Two identity renderers driven by injected data. Fully client-side; no backend required.\n\nSTEP 1 — Install. `npx rr add profile` for both, or `npx rr add profile resume` / `card` for one. Ensure `@/features/profile` resolves and Tailwind scans the slice folder.\n\nSTEP 2 — Deps. npm: `lucide-react`. shadcn: `npx shadcn@latest add button scroll-area avatar`.\n\nSTEP 3 — Mount. `<Resume />` (CV) or `<AboutProfile />` (card) in a height-bearing box — unwired each renders a generic placeholder. Or register `resumeApp` / `aboutProfileApp` in an appshell manifest.\n\nSTEP 4 — Real data. `configureResume(profile)` with a ResumeProfile { name, roles[], location, summary, contacts[], skills[], experience[], projects[] }, and/or `configureAbout(card)` with { name, roles[], description, links[], faq[] }, once at boot from Convex / a CMS / a JSON file. Resume's \"Print / PDF\" button calls window.print() against a print-friendly layout.",
1872
+ "variants": {
1873
+ "default": "resume",
1874
+ "items": [
1875
+ {
1876
+ "id": "resume",
1877
+ "title": "Resume",
1878
+ "description": "Formal one-column printable CV (Resume + configureResume)."
1879
+ },
1880
+ {
1881
+ "id": "card",
1882
+ "title": "Card",
1883
+ "description": "Compact avatar + links + FAQ identity card (AboutProfile + configureAbout)."
1884
+ }
1885
+ ]
1886
+ }
1887
+ },
1888
+ {
1889
+ "slug": "start-here",
1890
+ "title": "Start Here — guided OS onboarding tour",
1891
+ "category": "os",
1892
+ "kind": "ui",
1893
+ "version": "1.0.0",
1894
+ "description": "A guided 'Start Here' tour that lays the OS out as a path of stages, each stage opening real apps from the LIVE registry — drift-proof, it reads the injected app catalog instead of a hardcoded list, so adding an app surfaces it automatically (in a stage if listed, else a final 'Everything else' bucket). The catalog, the open(id) callback, and the stage journey are INJECTED via a small StartHereAdapter (apps / open / stages): point configureStartHere at your live app registry + window opener, or keep the bundled in-memory mock (a few generic apps + 3 stages) so the welcome tour renders fully alive with zero host.",
1895
+ "source": "rahmanef63/os-vps",
1896
+ "slicePath": "frontend/slices/start-here",
1897
+ "convexPaths": [],
1898
+ "npm": [
1899
+ "lucide-react"
1900
+ ],
1901
+ "shadcn": [
1902
+ "button",
1903
+ "scroll-area"
1904
+ ],
1905
+ "env": [],
1906
+ "peers": [],
1907
+ "providers": [],
1908
+ "tags": [
1909
+ "onboarding",
1910
+ "tour",
1911
+ "welcome",
1912
+ "launcher",
1913
+ "guide",
1914
+ "os",
1915
+ "ui"
1916
+ ],
1917
+ "agentRecipe": "Stack: Next 16 + React 19 + Tailwind 4 + shadcn/ui. A guided onboarding tour that renders your live app catalog as a path of stages. Fully client-side; the catalog is injected.\n\nSTEP 1 — Install. `npx rr add start-here`. Ensure `@/features/start-here` resolves and Tailwind scans the slice folder.\n\nSTEP 2 — Deps. npm: `lucide-react`. shadcn: `npx shadcn@latest add button scroll-area`.\n\nSTEP 3 — Mount. `<StartHere />` in a height-bearing box — unwired it reads an in-memory mock catalog (generic apps + 3 stages) so the tour is fully alive. Or register `startHereApp` in an appshell manifest.\n\nSTEP 4 — Real catalog. `configureStartHere({ mode:\"live\", apps, open, stages })` — apps is your live registry as [{ id, title, icon, description? }]; open(id) launches the real app/window; stages is [{ title, blurb, appIds }] (apps not placed fall into a final \"Everything else\" stage). Drift-proof: read the registry, never hardcode the list."
1918
+ },
1678
1919
  {
1679
1920
  "slug": "os-terminal",
1680
1921
  "title": "Terminal — shell emulator with live passthrough + PTY seam",
@@ -1955,78 +2196,14 @@
1955
2196
  "agentRecipe": "Run `rr add convex-auth`. Then create convex/auth.ts using the kitab pattern (Resend provider). Set env via `npx convex env set` for self-hosted."
1956
2197
  },
1957
2198
  {
1958
- "slug": "doku-payment",
1959
- "title": "DOKU — Indonesia Payment",
2199
+ "slug": "payment",
2200
+ "title": "Payment — Indonesia PSP (DOKU · Midtrans)",
1960
2201
  "category": "integrations",
1961
2202
  "kind": "full",
1962
2203
  "version": "0.4.0",
1963
- "description": "Pembayaran lokal Indonesia via DOKU Checkout (hosted) + Direct (VA / QRIS / e-Wallet / PayLater / Minimarket / Kartu). HMAC-signed REST + signature-verified webhook + idempotent retries. Sibling slice to midtrans-payment dengan paymentOrders schema yang dishare.",
2204
+ "description": "Indonesia payment providers behind one slug + ONE shared Convex backend (convex/features/payment discriminates on a provider column: paymentOrders + paymentWebhookEvents, unprefixed). Two frontend variants: doku — DOKU Hosted Checkout + Direct (VA / QRIS / e-Wallet / PayLater), HMAC-SHA256 signed REST, signature-verified webhook, idempotent retries, dependency-free, server-side env only. midtrans Snap hosted-modal checkout + orders history (needs npm midtrans-client + a NEXT_PUBLIC_MIDTRANS_CLIENT_KEY). Install one with `npx rr add payment doku|midtrans`, or both. A future stripe variant is reserved in the schema's provider union.",
1964
2205
  "source": "rahmanef63/resource-site",
1965
- "slicePath": "frontend/slices/doku-payment",
1966
- "convexPaths": [
1967
- "convex/features/payment"
1968
- ],
1969
- "npm": [],
1970
- "shadcn": [
1971
- "card",
1972
- "button",
1973
- "dialog",
1974
- "input",
1975
- "label",
1976
- "select",
1977
- "badge",
1978
- "skeleton"
1979
- ],
1980
- "env": [
1981
- {
1982
- "name": "DOKU_CLIENT_ID",
1983
- "scope": "convex",
1984
- "required": true
1985
- },
1986
- {
1987
- "name": "DOKU_SECRET_KEY",
1988
- "scope": "convex",
1989
- "required": true
1990
- },
1991
- {
1992
- "name": "DOKU_IS_PRODUCTION",
1993
- "scope": "convex"
1994
- },
1995
- {
1996
- "name": "DOKU_NOTIFY_PATH",
1997
- "scope": "convex"
1998
- }
1999
- ],
2000
- "peers": [
2001
- {
2002
- "slug": "convex-auth",
2003
- "range": "^0.1",
2004
- "reason": "Order ownership requires authenticated user."
2005
- }
2006
- ],
2007
- "providers": [
2008
- "doku"
2009
- ],
2010
- "tags": [
2011
- "payment",
2012
- "doku",
2013
- "indonesia",
2014
- "qris",
2015
- "virtual-account",
2016
- "ewallet",
2017
- "checkout"
2018
- ],
2019
- "agentRecipe": "Run `npx rr add doku-payment`. DOKU dual-mode: Checkout (hosted, all channels) atau Direct (single channel, returns VA/QRIS/deeplink). Webhook di /webhooks/doku verify HMAC-SHA256 (canonical: Client-Id + Request-Id + Request-Timestamp + Request-Target + Digest). Idempotency by request_id index. Server-only — no NEXT_PUBLIC_*. Sandbox default (api-sandbox.doku.com); flip DOKU_IS_PRODUCTION=true for live."
2020
- },
2021
- {
2022
- "slug": "midtrans-payment",
2023
- "title": "Midtrans — Indonesia Payment",
2024
- "category": "integrations",
2025
- "kind": "full",
2026
- "version": "0.2.0",
2027
- "description": "Pembayaran lokal Indonesia via Midtrans Snap (BCA, Mandiri, BRI, e-wallet GoPay/OVO/Dana, QRIS). Webhook untuk konfirmasi. Provider-isolated under components/providers/midtrans + actions/midtrans so Doku/Stripe land as siblings.",
2028
- "source": "rahmanef63/resource-site",
2029
- "slicePath": "frontend/slices/midtrans-payment",
2206
+ "slicePath": "frontend/slices/payment",
2030
2207
  "convexPaths": [
2031
2208
  "convex/features/payment"
2032
2209
  ],
@@ -2034,22 +2211,35 @@
2034
2211
  "midtrans-client@^1.4.2"
2035
2212
  ],
2036
2213
  "shadcn": [
2037
- "card",
2214
+ "badge",
2038
2215
  "button",
2216
+ "card",
2039
2217
  "dialog",
2040
2218
  "input",
2041
- "label"
2219
+ "label",
2220
+ "select",
2221
+ "skeleton"
2042
2222
  ],
2043
2223
  "env": [
2224
+ {
2225
+ "name": "DOKU_CLIENT_ID",
2226
+ "scope": "convex"
2227
+ },
2228
+ {
2229
+ "name": "DOKU_SECRET_KEY",
2230
+ "scope": "convex"
2231
+ },
2232
+ {
2233
+ "name": "DOKU_IS_PRODUCTION",
2234
+ "scope": "convex"
2235
+ },
2044
2236
  {
2045
2237
  "name": "MIDTRANS_SERVER_KEY",
2046
- "scope": "convex",
2047
- "required": true
2238
+ "scope": "convex"
2048
2239
  },
2049
2240
  {
2050
2241
  "name": "MIDTRANS_CLIENT_KEY",
2051
- "scope": "next-public",
2052
- "required": true
2242
+ "scope": "next-public"
2053
2243
  },
2054
2244
  {
2055
2245
  "name": "MIDTRANS_IS_PRODUCTION",
@@ -2060,20 +2250,41 @@
2060
2250
  {
2061
2251
  "slug": "convex-auth",
2062
2252
  "range": "^0.1",
2063
- "reason": "Order ownership requires authenticated user."
2253
+ "reason": "Order ownership requires authenticated user (guest checkout works without)."
2064
2254
  }
2065
2255
  ],
2066
2256
  "providers": [
2257
+ "doku",
2067
2258
  "midtrans"
2068
2259
  ],
2069
2260
  "tags": [
2070
2261
  "payment",
2071
- "midtrans",
2262
+ "checkout",
2072
2263
  "indonesia",
2264
+ "doku",
2265
+ "midtrans",
2266
+ "snap",
2073
2267
  "qris",
2074
- "snap"
2075
- ],
2076
- "agentRecipe": "Run `npx rr add midtrans-payment`. Midtrans Snap untuk pembayaran instant. Webhook ke Convex HTTP action /api/midtrans-callback untuk update order status. Ingat: PPN 11% sudah included di amount, jangan double-count."
2268
+ "virtual-account",
2269
+ "ewallet",
2270
+ "psp"
2271
+ ],
2272
+ "agentRecipe": "Run `npx rr add payment` for both providers, or `npx rr add payment doku` / `midtrans`. Either variant copies the shared convex/features/payment backend. doku: Checkout (hosted) or Direct (single channel → VA/QRIS/deeplink); webhook /webhooks/doku verifies HMAC-SHA256; server-only, no NEXT_PUBLIC_*. midtrans: Snap.js + window.snap.pay(token); webhook verifies signature_key; needs NEXT_PUBLIC_MIDTRANS_CLIENT_KEY. Both patch paymentOrders by orderId; sandbox by default.",
2273
+ "variants": {
2274
+ "default": "doku",
2275
+ "items": [
2276
+ {
2277
+ "id": "doku",
2278
+ "title": "DOKU",
2279
+ "description": "Hosted Checkout + Direct channel picker, HMAC REST, dependency-free."
2280
+ },
2281
+ {
2282
+ "id": "midtrans",
2283
+ "title": "Midtrans",
2284
+ "description": "Snap hosted-checkout button + orders history (needs midtrans-client + next-public key)."
2285
+ }
2286
+ ]
2287
+ }
2077
2288
  },
2078
2289
  {
2079
2290
  "slug": "resend-newsletter",
@@ -3129,44 +3340,90 @@
3129
3340
  },
3130
3341
  {
3131
3342
  "slug": "admin",
3132
- "title": "Admin — Generic Shell",
3343
+ "title": "Admin — generic shell + composed console",
3133
3344
  "category": "infra",
3134
3345
  "kind": "full",
3135
3346
  "version": "0.2.1",
3136
- "description": "HEADLESS admin scaffoldno chrome of its own; pair with dashboard-shell for app chrome. Per-instance admin landing scaffold + portable nav-from-registry factory. Consumer supplies a SliceRegistryAdapter (each slice declares its own admin.activity[]) + queryTable reader; the slice's buildAdminStats(opts) emits the { counts, unreadMessages, activity } shape Convex's admin.stats query returns. Pulled UP from rahmanef.com (Wave N+3.1, commit b542389) domain literals dropped at the kitab boundary. Gated by requireAdmin on Convex side; superadmin email gate via SUPER_ADMIN_EMAIL env.",
3347
+ "description": "Access-gated admin surfaces behind one slug, in two variants each pulls ONLY its own convex backend (per-variant convex gating). shell: a HEADLESS minimal generic admin shell — a titled landing region + a portable buildAdminStats(opts) nav-from-registry factory (consumer supplies a SliceRegistryAdapter + queryTable reader) over convex/features/admin; superadmin gate via SUPER_ADMIN_EMAIL. console: the composed admin panel distilled from ~15 project admin panels — a gated two-column shell (AdminConsole) over a 26-section registry (ADMIN_CONSOLE_SECTIONS: observability / identity / ai / content / commerce / config) that mounts OTHER rr slices via a consumer-supplied `components` map (users→user-management, roles→rbac-roles, ai→ai-admin, tenants→platform-admin) plus 5 owned gap sections (Analytics, Audit-log, Nav config, SEO health, Leads/CRM) over convex/features/admin_console (ac_leads + ac_nav_items); gate injected, PLATFORM_ADMIN_EMAILS allowlist. Install one with `npx rr add admin shell|console`, or both with `npx rr add admin`. NOT the multi-tenant control plane that's the separate `platform-admin` slice (the console's `tenants` section provider).",
3137
3348
  "source": "rahmanef63/resource-site",
3138
3349
  "slicePath": "frontend/slices/admin",
3139
3350
  "convexPaths": [
3140
- "convex/features/admin"
3351
+ "convex/features/admin",
3352
+ "convex/features/admin_console"
3141
3353
  ],
3142
3354
  "npm": [],
3143
3355
  "shadcn": [
3356
+ "badge",
3357
+ "button",
3144
3358
  "card",
3145
- "button"
3359
+ "input",
3360
+ "progress",
3361
+ "scroll-area",
3362
+ "select",
3363
+ "sheet",
3364
+ "table",
3365
+ "textarea"
3146
3366
  ],
3147
3367
  "env": [
3148
3368
  {
3149
3369
  "name": "SUPER_ADMIN_EMAIL",
3150
3370
  "scope": "convex",
3151
- "required": false
3371
+ "required": false,
3372
+ "description": "shell variant — single super-admin gate."
3373
+ },
3374
+ {
3375
+ "name": "PLATFORM_ADMIN_EMAILS",
3376
+ "scope": "convex",
3377
+ "required": false,
3378
+ "description": "console variant — comma-separated platform-admin allowlist."
3152
3379
  }
3153
3380
  ],
3154
3381
  "peers": [
3155
3382
  {
3156
3383
  "slug": "convex-auth",
3157
3384
  "range": "^0.1",
3158
- "reason": "requireAdmin gate uses convex-auth user identity."
3385
+ "reason": "requireAdmin gate uses convex-auth identity."
3386
+ },
3387
+ {
3388
+ "slug": "rbac-roles",
3389
+ "range": "^0.1",
3390
+ "reason": "console section gates are permission tokens resolved by rbac-roles."
3159
3391
  }
3160
3392
  ],
3161
3393
  "providers": [],
3162
3394
  "tags": [
3163
3395
  "infra",
3164
3396
  "admin",
3397
+ "console",
3165
3398
  "shell",
3166
- "crud",
3167
- "nav-from-registry"
3168
- ],
3169
- "agentRecipe": "Run `rr add admin`. Wire <AdminPage labels={...} /> at /admin and call buildAdminStats({ sliceRegistry, queryTable }) inside convex/features/admin/query.ts — sliceRegistry.entries flat-maps each feature's admin.activity[] declarations. Set SUPER_ADMIN_EMAIL via `npx convex env set` to lock down /admin to one address."
3399
+ "dashboard",
3400
+ "composition",
3401
+ "rbac",
3402
+ "access-gate",
3403
+ "registry"
3404
+ ],
3405
+ "agentRecipe": "Run `npx rr add admin` for both, or `npx rr add admin shell` / `console` for one — each variant pulls only its own convex backend. shell: mount <AdminPage labels={...} /> + call buildAdminStats({ sliceRegistry, queryTable }) in convex/features/admin/query.ts; lock down with SUPER_ADMIN_EMAIL. console: mount <AdminConsole access={useAdminAccess()} components={{ users: <UsersPanel/>, ... }} /> — owned sections (analytics/audit-log/nav-config/seo-health/leads) render as-is, map each reuse section id to the panel from the peer slice you installed; compose adminConsoleTables into convex/schema.ts and front ac_leads.create with rate-limit; gate via PLATFORM_ADMIN_EMAILS.",
3406
+ "variants": {
3407
+ "default": "console",
3408
+ "items": [
3409
+ {
3410
+ "id": "shell",
3411
+ "title": "Shell",
3412
+ "description": "Minimal generic admin shell (titled card + buildAdminStats).",
3413
+ "convex": [
3414
+ "convex/features/admin"
3415
+ ]
3416
+ },
3417
+ {
3418
+ "id": "console",
3419
+ "title": "Console",
3420
+ "description": "Composed access-gated 26-section console mounting other rr slices.",
3421
+ "convex": [
3422
+ "convex/features/admin_console"
3423
+ ]
3424
+ }
3425
+ ]
3426
+ }
3170
3427
  },
3171
3428
  {
3172
3429
  "slug": "platform-admin",
@@ -3320,6 +3577,61 @@
3320
3577
  ],
3321
3578
  "agentRecipe": "Run `rr add seo`. Call seo.generate from server actions or admin mutations with `personaContext` describing your brand voice (or rely on the generic default). Cost guard rate-limits per-user within 24h via callsInWindow query."
3322
3579
  },
3580
+ {
3581
+ "slug": "publisher-clean-html",
3582
+ "title": "Publisher — clean HTML",
3583
+ "category": "content",
3584
+ "kind": "ui",
3585
+ "version": "0.1.0",
3586
+ "description": "A pure render-to-clean-HTML engine harvested from the Instatic CMS publisher, decoupled from its host caching / loops / visual-components / Layer-C islands. publishPage(tree, registry, options) walks a generic node tree bottom-up: render children, escape every prop by its schema-declared control type (url -> safe-URL, richtext -> DOMPurify, svg -> SVG profile, else HTML-escape), dedup CSS by moduleId (~60-80% shrink), splice author classes + inline styles onto each rendered root, then assemble <!DOCTYPE> + reset + framework + module CSS + a deterministic (sorted) CSP plan. Bring your own ModuleRegistry (each module is a pure render(props, children) -> { html, css? }). Security spine: HTML escape + safe-URL, CSS-value guard (expression()/{}/</), </style RAWTEXT neutraliser, and an injectable DOMPurify seam (configureRichtextSanitizer) that fails closed — without a runtime, richtext strips all tags and SVG returns empty. Stateless, env-free, ZERO npm deps, no Convex. Ships a PublishPreview iframe-srcdoc pane. A Wave-1 leaf of the feature-harvest ULTRAPLAN; a dependency of the planned visual-page-canvas.",
3587
+ "source": "rahman-resources",
3588
+ "slicePath": "frontend/slices/publisher-clean-html",
3589
+ "convexPaths": [],
3590
+ "npm": [],
3591
+ "shadcn": [],
3592
+ "env": [],
3593
+ "peers": [],
3594
+ "providers": [],
3595
+ "tags": [
3596
+ "content",
3597
+ "publisher",
3598
+ "html",
3599
+ "static-export",
3600
+ "sanitization",
3601
+ "csp",
3602
+ "css-dedup",
3603
+ "render"
3604
+ ],
3605
+ "agentRecipe": "Run `npx rr add publisher-clean-html`. Build a registry: createModuleRegistry([{ id: 'base.body', render: (_p, kids) => ({ html: kids.join('') }) }, { id: 'demo.h', schema: { text: { type: 'text' } }, render: (p) => ({ html: `<h1>${p.text}</h1>`, css: 'h1{font-size:1.5rem}' }) }]). Tree = { rootNodeId, nodes: { [id]: { id, moduleId, props?, children?, classIds?, inlineStyles?, hidden? } } }. const { html } = publishPage(tree, registry, { title, cssEmission: 'inline' }). Preview: <PublishPreview html={html} />. Enable rich HTML/SVG by calling configureRichtextSanitizer(DOMPurify) once — without it, richtext/svg props fail closed (strip/empty). Props escape by schema control type, not key name."
3606
+ },
3607
+ {
3608
+ "slug": "content-loops",
3609
+ "title": "Content Loops",
3610
+ "category": "content",
3611
+ "kind": "ui",
3612
+ "version": "0.1.0",
3613
+ "description": "A data-source-driven repeater harvested from the Instatic CMS base.loop engine, decoupled from its publisher / page-tree / entryStack machinery into a plain React slice. Register pluggable LoopEntitySource backends (each declares display fields + an async fetch returning { items, totalItems }); drop <ContentLoop source|sourceId filters orderBy variants={[A, B]} /> to render one component per item, round-robining items across variants so alternating / featured layouts need no per-item branching. Ships a namespaced source registry (ids must be 'ns.name', so consumer sources can't shadow each other), createMockLoopSource for env-free previews + tests, and none/infinite pagination via useLoopPagination (a shadcn Load more button accumulates pageSize chunks). LoopItem.fields is a generic resolved-value bag — variants read item.fields.title directly, no second lookup. UI-only: no Convex tables shipped; point a source's fetch at Convex/REST when you have a backend. First slice of the feature-harvest ULTRAPLAN (docs/feature-harvest) and a dependency of the planned site-templates-engine + visual-page-canvas.",
3614
+ "source": "rahman-resources",
3615
+ "slicePath": "frontend/slices/content-loops",
3616
+ "convexPaths": [],
3617
+ "npm": [],
3618
+ "shadcn": [
3619
+ "button"
3620
+ ],
3621
+ "env": [],
3622
+ "peers": [],
3623
+ "providers": [],
3624
+ "tags": [
3625
+ "content",
3626
+ "loop",
3627
+ "repeater",
3628
+ "list",
3629
+ "data-source",
3630
+ "pagination",
3631
+ "variants"
3632
+ ],
3633
+ "agentRecipe": "Run `npx rr add content-loops`. Env-free demo: createMockLoopSource() then <ContentLoop source={s} pagination='infinite' pageSize={6} variants={[CardA, CardB]} /> — variants round-robin (item i -> variants[i % n]). Real source: implement LoopEntitySource { id: 'blog.posts' (namespaced 'ns.name'), fields, async fetch({ filters, orderBy, direction, limit, offset }) returns { items, totalItems } }, call loopSourceRegistry.registerOrReplace(source), then <ContentLoop sourceId='blog.posts' variants={[...]} />. item.fields holds RESOLVED values — resolve media/author inside fetch."
3634
+ },
3323
3635
  {
3324
3636
  "slug": "markdown",
3325
3637
  "title": "Markdown — page container with CRUD tabs + diagrams",
@@ -3360,14 +3672,14 @@
3360
3672
  "agentRecipe": "Run `npx rr add markdown`. Read-only: `<MarkdownReader content={md}/>`. Full surface: `<MarkdownPage content={md} tabs={['read','write','review']} onContentChange={save} comments={list} onAddComment={add} onResolveComment={resolve}/>` (omit callbacks for internal-state demo mode). Diagrams: fence ```mermaid; charts: fence ```chart with { type: bar|line|area|pie, data: [...] }. To bridge from the notion editor call `blocksToMarkdown(page.blocks)` from `@notion/shared/lib/markdown`; reverse with `markdownToBlocks(md)`."
3361
3673
  },
3362
3674
  {
3363
- "slug": "notion",
3364
- "title": "Notion — Block Editor",
3675
+ "slug": "notion-app",
3676
+ "title": "Notion App — Block Editor",
3365
3677
  "category": "content",
3366
3678
  "kind": "full",
3367
3679
  "version": "1.1.1",
3368
3680
  "description": "Nested vertical slice (slice-of-slices) housing the full notion-page-clone block editor. Mount <PageEditor pageId/> inside <EditorAdapterProvider adapter/> — with `{}` it is a working plain-text/markdown block editor (slash menu, markdown triggers `# - > [] etc.`, dnd-kit drag with column layouts, per-block toolbar with turn-into/color/duplicate, per-block undo, paste-markdown import); host capabilities light up per optional adapter: data (block+page CRUD), selection (multi-select), comments (per-block popover), ai (Ask-AI panel), database (render + picker), mention (@-typeahead), page (nav/uploads/covers). Cluster-private shared layer under @notion/* — vendored block/page/database model, uid, inline markdown, page→md/html export. Pure convex block helpers (_blocks/_blockOps, unit-tested) ship in convex/features/notion. Same markdown grammar as the standalone `markdown` slice (blocksToMarkdown/markdownToBlocks bridge).",
3369
3681
  "source": "notion-page-clone",
3370
- "slicePath": "frontend/slices/notion",
3682
+ "slicePath": "frontend/slices/notion-app",
3371
3683
  "convexPaths": [
3372
3684
  "convex/features/notion"
3373
3685
  ],
@@ -3401,17 +3713,17 @@
3401
3713
  "drag-drop",
3402
3714
  "adapter-seam"
3403
3715
  ],
3404
- "agentRecipe": "Run `npx rr add notion`. Wire the `@notion/*` path alias to `./slices/notion/*` in tsconfig. Minimal mount: `<EditorAdapterProvider adapter={{ data }}><PageEditor pageId={id}/></EditorAdapterProvider>` where `data` implements EditorDataAdapter (block+page CRUD over your store — see lib/dataAdapter.ts; a localStorage reference impl lives in the rr preview). Add capabilities incrementally: `selection` for multi-select, `comments` for per-block threads, `database.renderDatabase` to mount your database renderer inside database blocks, `mention.search` for @-typeahead, `page.navigateToPage`/`uploadFile` for nav + media. Convex hosts: copy convex/features/notion (_blocks/_blockOps are pure, unit-tested array ops) and keep handlers thin."
3716
+ "agentRecipe": "Run `npx rr add notion-app`. Wire the `@notion/*` path alias to `./slices/notion-app/*` in tsconfig. Minimal mount: `<EditorAdapterProvider adapter={{ data }}><PageEditor pageId={id}/></EditorAdapterProvider>` where `data` implements EditorDataAdapter (block+page CRUD over your store — see lib/dataAdapter.ts; a localStorage reference impl lives in the rr preview). Add capabilities incrementally: `selection` for multi-select, `comments` for per-block threads, `database.renderDatabase` to mount your database renderer inside database blocks, `mention.search` for @-typeahead, `page.navigateToPage`/`uploadFile` for nav + media. Convex hosts: copy convex/features/notion (_blocks/_blockOps are pure, unit-tested array ops) and keep handlers thin."
3405
3717
  },
3406
3718
  {
3407
- "slug": "landing-sections",
3408
- "title": "Landing Sections",
3719
+ "slug": "sections",
3720
+ "title": "Sections — composable marketing/landing sections",
3409
3721
  "category": "content",
3410
3722
  "kind": "ui",
3411
3723
  "version": "0.4.0",
3412
3724
  "description": "Canonical landing-page composition slice — replaces the former standalone hero / cta / pricing-page / faq-section / feature-grid / testimonials-grid / blog-section / portfolio-section / changelog-feed slices (all merged here as `kind` variants in v0.2.0). Ships a pure reducer (v0.4.0: LANDING_UPSERT auto-shifts sibling `order` to keep positions unique; LANDING_DELETE closes the gap) + LandingProvider store adapter + admin LandingView/LandingEditorView built on the shared CRUD primitives, plus a per-section LandingSectionShell (background image + custom Tailwind className overlay + scroll-reveal). NEW in v0.4.0: a `sections/` library of config-driven public renderers (StatsSection, TestimonialsSection, FaqSection, PricingSection, NewsletterSection, CustomSection) that read `LandingSection.config` JSON merged over template defaults — content stays dashboard-controlled without per-template renderer code; plus `parse-config` helpers (parseConfigBadge/parseConfigField) and `sections/config` guards (parseConfigObject, cfg*). Sections carry { kind, order, title, subtitle, enabled, imageUrl, imageRatio, bgImageUrl, className, config (JSON) } with up/down reorder arrows. Lifted from the _templates fleet `_shared/landing` (2026-06-11) — the 8 standalone templates ship a byte-similar copy; this rr slice is the SSOT. Used by all 7 rr website templates.",
3413
3725
  "source": "rahman-resources (lifted from _templates fleet)",
3414
- "slicePath": "frontend/slices/landing-sections",
3726
+ "slicePath": "frontend/slices/sections",
3415
3727
  "convexPaths": [],
3416
3728
  "npm": [
3417
3729
  "lucide-react@^0.400.0",
@@ -3443,7 +3755,7 @@
3443
3755
  "crud",
3444
3756
  "renderer"
3445
3757
  ],
3446
- "agentRecipe": "Run `npx rr add landing-sections`. Fold `landingReducer` into your root reducer (cases LANDING_UPSERT + LANDING_DELETE), seed State.landingSections with `defaultLandingSections()`, wrap your StoreProvider with `<LandingProvider value={adapter}/>` where adapter maps {items, publicBase, adminBase, create, update, remove} from your dispatch. Mount `<LandingView/>` at `/admin/landing` and `<LandingEditorView id={params.id}/>` at `/admin/landing/[id]`. In HomePage iterate `state.landingSections.filter(s => s.enabled).sort((a,b) => a.order - b.order)` and render each inside `<LandingSectionShell section={s}>`; for stats/testimonials/pricing/faq/newsletter/custom kinds drop in the shipped `<StatsSection/>` etc. (they read `section.config` JSON over your template defaults), or map the remaining kinds (hero/features/blog/etc.) to your own renderer. Use `parseConfigBadge(section.config)` for a section badge. Requires the template-base shared surface that ships in every rr website template: `@/components/templates/_shared/motion` (Reveal/Stagger/CountUp/Marquee/useInView — the motion-kit primitives), `@/components/templates/_shared/ui/section-head`, and `@/components/templates/_shared/crud/*`. Sections also use shadcn accordion/card/carousel + embla-carousel-autoplay."
3758
+ "agentRecipe": "Run `npx rr add sections`. Fold `landingReducer` into your root reducer (cases LANDING_UPSERT + LANDING_DELETE), seed State.landingSections with `defaultLandingSections()`, wrap your StoreProvider with `<LandingProvider value={adapter}/>` where adapter maps {items, publicBase, adminBase, create, update, remove} from your dispatch. Mount `<LandingView/>` at `/admin/landing` and `<LandingEditorView id={params.id}/>` at `/admin/landing/[id]`. In HomePage iterate `state.landingSections.filter(s => s.enabled).sort((a,b) => a.order - b.order)` and render each inside `<LandingSectionShell section={s}>`; for stats/testimonials/pricing/faq/newsletter/custom kinds drop in the shipped `<StatsSection/>` etc. (they read `section.config` JSON over your template defaults), or map the remaining kinds (hero/features/blog/etc.) to your own renderer. Use `parseConfigBadge(section.config)` for a section badge. Requires the template-base shared surface that ships in every rr website template: `@/components/templates/_shared/motion` (Reveal/Stagger/CountUp/Marquee/useInView — the motion-kit primitives), `@/components/templates/_shared/ui/section-head`, and `@/components/templates/_shared/crud/*`. Sections also use shadcn accordion/card/carousel + embla-carousel-autoplay."
3447
3759
  },
3448
3760
  {
3449
3761
  "slug": "motion-kit",
@@ -3502,8 +3814,8 @@
3502
3814
  "env": [],
3503
3815
  "peers": [
3504
3816
  {
3505
- "slug": "doku-payment",
3506
- "range": "^0.2",
3817
+ "slug": "payment",
3818
+ "range": "^0.4",
3507
3819
  "reason": "Optional payment step — checkout page composes DokuDirectForm + DokuPaymentInstructions (or swap midtrans-payment)."
3508
3820
  }
3509
3821
  ],
@@ -3554,14 +3866,14 @@
3554
3866
  "agentRecipe": "Run `npx rr add theme-presets` (registry-data.json ships inside the slice — no separate public/ copy step). Wrap your tree once with `<ThemePresetProvider>` (inside next-themes' ThemeProvider). Mount `<ThemePresetSwitcher />` anywhere in your header / sidebar / settings — one component handles light/dark/system + preset palette. Wrap dashboard with `<ThemeColorSync>` if you need live tweakcn variable preview on inner routes. Deeply-nested consumers read state via `useThemePreset()` (returns `{ presetName, registry, setPreset, preview, restore, isReady }`). For lower-level access: `applyTweakcnPreset(name)`, `previewTweakcnPreset(name)`, `restoreTweakcnPreset()`, `groupTweakcnPresets(items)`, `tweakcnSwatches(preset)` all exported from `@/features/theme-presets`. To rename localStorage key, fork `STORAGE_KEY` in `lib/tweakcn/types.ts`."
3555
3867
  },
3556
3868
  {
3557
- "slug": "onboarding-wizard",
3558
- "title": "Onboarding Wizard — first-run site setup",
3869
+ "slug": "site-setup-wizard",
3870
+ "title": "Site Setup Wizard — first-run site setup",
3559
3871
  "category": "ui",
3560
3872
  "kind": "ui",
3561
3873
  "version": "0.2.0",
3562
3874
  "description": "Post-claim onboarding wizard for clone-to-own templates, graduated from the headless template surface (2026-06-06). Multi-step card flow (Identitas / Branding / Konten / Selesai) that stores ALL site config in the host backend via a props-driven save callback — a non-coder configures their site with zero code. Branding step ships a readable shadcn Select theme-preset picker (color swatches per preset + grouped headers + live preview callback — replaces the white-on-white native select), brand color quick-chips, light/dark/system default mode, logo/favicon upload via injected ImageField, and optional Analytics ID. Identity step hints invalid email format. 'Lewati setup' marks onboarded without fields and reverts any browsed-but-unsaved preset. Props-driven (R3): no convex/react import — host wires settings.upsert / seed.seedSample / setup.status into props; pairs naturally with the theme-presets slice (registry + tweakcnSwatches + previewTweakcnPreset) but works with any theme system or none.",
3563
3875
  "source": "personal-brand-os",
3564
- "slicePath": "frontend/slices/onboarding-wizard",
3876
+ "slicePath": "frontend/slices/site-setup-wizard",
3565
3877
  "convexPaths": [],
3566
3878
  "npm": [],
3567
3879
  "shadcn": [
@@ -3586,17 +3898,17 @@
3586
3898
  "clone-to-own",
3587
3899
  "templates"
3588
3900
  ],
3589
- "agentRecipe": "Run `npx rr add onboarding-wizard`. Show from your admin gate when `setup.status().onboarded === false`: `<OnboardingWizard onDone={...} save={(f) => settingsUpsert(f)} seedSample={() => seedSample({})} seeded={status?.seeded} ImageField={ImageField} presetOptions={presets} onPresetPreview={(n) => preview(n)} />`. `save` receives Partial<OnboardingFields> + `markOnboarded: true` — back it with a `settings.upsert` mutation that patches only provided fields. Theme bridge (optional): with the theme-presets slice installed build `presetOptions` from `groupTweakcnPresets(registry.items)` + `tweakcnSwatches(p)` and pass `useThemePreset().preview` as `onPresetPreview` — the picker then live-previews while the user browses and `Lewati setup` reverts via `onPresetPreview(null)`. Omit `presetOptions` to hide the picker entirely; omit `ImageField` to hide logo/favicon upload. Full wiring recipe in the slice's HOST-SETUP.md."
3901
+ "agentRecipe": "Run `npx rr add site-setup-wizard`. Show from your admin gate when `setup.status().onboarded === false`: `<OnboardingWizard onDone={...} save={(f) => settingsUpsert(f)} seedSample={() => seedSample({})} seeded={status?.seeded} ImageField={ImageField} presetOptions={presets} onPresetPreview={(n) => preview(n)} />`. `save` receives Partial<OnboardingFields> + `markOnboarded: true` — back it with a `settings.upsert` mutation that patches only provided fields. Theme bridge (optional): with the theme-presets slice installed build `presetOptions` from `groupTweakcnPresets(registry.items)` + `tweakcnSwatches(p)` and pass `useThemePreset().preview` as `onPresetPreview` — the picker then live-previews while the user browses and `Lewati setup` reverts via `onPresetPreview(null)`. Omit `presetOptions` to hide the picker entirely; omit `ImageField` to hide logo/favicon upload. Full wiring recipe in the slice's HOST-SETUP.md."
3590
3902
  },
3591
3903
  {
3592
- "slug": "files",
3593
- "title": "Files — pluggable upload + URL resolver with storage-adapter contract",
3904
+ "slug": "file-upload",
3905
+ "title": "File Upload — pluggable upload + URL resolver with storage-adapter contract",
3594
3906
  "category": "data",
3595
3907
  "kind": "ui",
3596
3908
  "version": "0.3.0",
3597
3909
  "description": "Host-pluggable file upload + URL resolution. Ships <FileUploadButton>, <FileChip>, useFileUpload(), useFileUrl() — all reading from a FilesAdapter the host wires via <FilesAdapterProvider>. Bundled localStorage demo adapter stores blobs as data URLs (small files only). Drop in your own adapter for Convex / S3 / GCS / R2. The slice itself has zero backend coupling, proving the storage-adapter pattern for the rest of the open-silong blocked-pending-adapter wave (cover, workspace-io, templates, …).",
3598
3910
  "source": "notion-page-clone",
3599
- "slicePath": "frontend/slices/files",
3911
+ "slicePath": "frontend/slices/file-upload",
3600
3912
  "convexPaths": [],
3601
3913
  "npm": [],
3602
3914
  "shadcn": [
@@ -3614,7 +3926,7 @@
3614
3926
  "portable",
3615
3927
  "notion-like"
3616
3928
  ],
3617
- "agentRecipe": "Run `npx rr add files`. Wrap your tree with `<FilesAdapterProvider adapter={...}>` — pass `useLocalStorageFilesAdapter()` for a quick demo or implement `FilesAdapter` (upload + remove + useUrl) against your backend. Then drop `<FileUploadButton onUploaded={...}>` anywhere; pair with `<FileChip fileRef={...}>` for rendered chips. Hooks: `useFileUpload()` returns `{upload, uploading, progress, removeFromStorage}`; `useFileUrl(storageId)` resolves to a fetchable URL (Convex adapter uses useQuery for live invalidation; demo reads localStorage synchronously). To wire S3: implement the FilesAdapter interface with presigned URLs + DELETE; the slice doesn't care which backend you pick."
3929
+ "agentRecipe": "Run `npx rr add file-upload`. Wrap your tree with `<FilesAdapterProvider adapter={...}>` — pass `useLocalStorageFilesAdapter()` for a quick demo or implement `FilesAdapter` (upload + remove + useUrl) against your backend. Then drop `<FileUploadButton onUploaded={...}>` anywhere; pair with `<FileChip fileRef={...}>` for rendered chips. Hooks: `useFileUpload()` returns `{upload, uploading, progress, removeFromStorage}`; `useFileUrl(storageId)` resolves to a fetchable URL (Convex adapter uses useQuery for live invalidation; demo reads localStorage synchronously). To wire S3: implement the FilesAdapter interface with presigned URLs + DELETE; the slice doesn't care which backend you pick."
3618
3930
  },
3619
3931
  {
3620
3932
  "slug": "selection",
@@ -3645,43 +3957,40 @@
3645
3957
  "agentRecipe": "Run `npx rr add selection`. Zero deps (react-dom only). Wrap your list area in `<SelectionProvider onBulkDelete={(ids) => removeMany(ids)}>`, give the surface a `position: relative` div with a ref, drop `<SelectionMarquee containerRef={ref} />` inside it, and wrap each item in `<SelectableBlock id={item.id} orderedIds={allIds}>…</SelectableBlock>`. Hold-drag on empty space to rubber-band: drag RIGHT = window (only fully-enclosed, solid ring), drag LEFT = crossing (anything touched, dashed green). Edge-click an item to pick it (Shift = range, Cmd/Ctrl = toggle). Backspace/Delete bulk-deletes (focus outside a contentEditable), Escape + click-outside clear, floating `N selected · Delete · Clear` toolbar. Read state anywhere via `useSelection()`. The slice owns ONLY the id set — you own the data + the delete. Works on table rows / cards too, not just notion blocks."
3646
3958
  },
3647
3959
  {
3648
- "slug": "notion-database",
3649
- "title": "Notion Database",
3960
+ "slug": "notion-ui",
3961
+ "title": "Notion UI — page editor · database · sidebar primitives",
3650
3962
  "category": "ui",
3651
3963
  "kind": "ui",
3652
- "version": "0.18.0",
3653
- "description": "Drop-in Notion-style database surface. 11 views (table, board, list, gallery, calendar, feed, chart, dashboard, form, map, timeline), 18 property/cell types, and a per-type column-header config menu (number format, date ranges, select, relation, rollup, formula) plus filter / sort / group / calculate, row peek, row multi-select, table cell selection + drag-to-fill (click a cell, drag the handle to copy down merged from the former database-cell-selection slice in v0.16), and CSV + JSON import-export. Pure and props-driven — the host owns the data and dispatches change callbacks. Domain types live in notion-shell (install it as the peer). Full release history in CHANGELOG.md.",
3654
- "source": "open-silong",
3655
- "slicePath": "frontend/slices/notion-database",
3656
- "convexPaths": [
3657
- "template-base/database-silong/convex/handlers/databases.ts",
3658
- "template-base/database-silong/convex/handlers/pages.ts",
3659
- "template-base/database-silong/convex/schema.database-silong.ts"
3660
- ],
3964
+ "version": "0.24.0",
3965
+ "description": "The pure, props-driven Notion-clone primitives suite behind one slug, over one shared domain-type model (Block / Page / Property / Database / DbView …). page: the page + block editor (NotionPage / NotionHeader / NotionBlock, SlashMenu, block renderers, inline-markdown decorator, built-in code (highlight.js) + equation (KaTeX)). database: a drop-in 11-view database (table/board/list/gallery/calendar/feed/chart/dashboard/form/map/timeline, 18 property/cell types, per-type column config, filter/sort/group/calculate, row peek + multi-select, cell drag-fill, formula engine, CSV/JSON import-export). sidebar: a standalone tree-nav sidebar (dnd reorder + reparent with depth projection, inline rename, per-row icon picker). All stateless + callback-CRUD — the host owns the data. Install one surface with `npx rr add notion-ui page|database|sidebar`, or all with `npx rr add notion-ui`; the shared/ domain type model is copied for every variant. NOT the full Notion app — that's the separate `notion` slice (adapter + Convex backed).",
3966
+ "source": "notion-page-clone",
3967
+ "slicePath": "frontend/slices/notion-ui",
3968
+ "convexPaths": [],
3661
3969
  "npm": [
3662
- "recharts@^2.13.0"
3970
+ "@dnd-kit/core@^6",
3971
+ "@dnd-kit/sortable",
3972
+ "@dnd-kit/utilities",
3973
+ "katex@^0.16.45",
3974
+ "highlight.js@^11.11.1",
3975
+ "recharts@^3",
3976
+ "lucide-react"
3663
3977
  ],
3664
3978
  "shadcn": [
3665
3979
  "button",
3666
- "input",
3667
3980
  "checkbox",
3981
+ "dialog",
3668
3982
  "dropdown-menu",
3983
+ "input",
3669
3984
  "popover",
3670
3985
  "select",
3671
- "dialog",
3986
+ "separator",
3672
3987
  "sheet",
3988
+ "switch",
3673
3989
  "toggle-group",
3674
- "tooltip",
3675
- "separator"
3990
+ "tooltip"
3676
3991
  ],
3677
3992
  "env": [],
3678
- "peers": [
3679
- {
3680
- "slug": "notion-shell",
3681
- "range": "^0.7",
3682
- "reason": "Domain types live in notion-shell. v0.7 extends Database with `locked` flag for the DatabaseMenu lock-toggle action."
3683
- }
3684
- ],
3993
+ "peers": [],
3685
3994
  "providers": [],
3686
3995
  "tags": [
3687
3996
  "ui",
@@ -3721,7 +4030,28 @@
3721
4030
  "optional",
3722
4031
  "embeddable"
3723
4032
  ],
3724
- "agentRecipe": "**Controlled component.** `<NotionDatabase />` renders the whole surface — 11 views (table, board, list, gallery, calendar, feed, chart, dashboard, form, map, timeline), 18 cell types, filter / sort / group / calculate, row peek + multi-select, table cell drag-fill, CSV / JSON import-export. It is 100% props-driven: it owns NO data state — you hold `db` + `rows` and persist every change callback. The view tab strip scrolls horizontally and the card clips to its border, so it stays inside any container width.\n\n**1. Install** — `npx rr add notion-database`. Cascades the `notion-shell` peer (the domain types live there). Components import from `@/features/notion-database`; types from `@/features/notion-shell`.\n\n**2. Minimal wire-up** — keep `db: Database` + `rows: Page[]` in your store (a Convex query result or `useState`) and pass change handlers:\n```tsx\nimport { NotionDatabase } from '@/features/notion-database';\n\n<NotionDatabase\n db={db}\n rows={rows}\n onRowAdd={addRow}\n onRowUpdate={(rowId, propId, value) => setValue(rowId, propId, value)}\n onRowRemove={removeRow}\n onPropertyAdd={addProperty}\n onViewActivate={setActiveView}\n onViewAdd={addView}\n onViewConfigChange={(viewId, patch) => patchView(viewId, patch)}\n/>\n```\nOmit any callback and that affordance goes read-only; pass `readOnly` to freeze everything at once.\n\n**3. Data shape** — `Database = { id, name, properties: Property[], views: DatabaseViewConfig[], activeViewId }`; each row `Page = { id, title, rowProps: Record<propId, PropertyValue> }`. For `relation` / `rollup` cells also pass `pages` + `databases`; for `person` / `created_by` cells pass `userLookup(id)`.\n\n**4. Import / export** — mount `<DatabaseIOActions db={db} rows={rows} onImport={handleImport} />` in your toolbar: CSV/JSON in (with schema-diff), CSV/JSON + live-schema templates out. New columns arrive with a `tempId` — map it to your real backend id before writing their `rowProps`.\n\n**5. Backend (optional)** — the UI is store-agnostic. For Convex persistence copy `template-base/database-silong/convex/` (handlers → `convex/`, schema fragment merges into `convex/schema.ts`). Pick `_shared/minimal/` (single-user, noop authz) or `_shared/full/` (`@convex-dev/auth` + workspaces). See CONVEX-BACKEND.md.\n\n**Just one view?** Import it directly — `import { TableView } from '@/features/notion-database'` — and feed it `rows` + `renderCell` + `renderColumnHeader`."
4033
+ "agentRecipe": "**Controlled component.** `<NotionDatabase />` renders the whole surface — 11 views (table, board, list, gallery, calendar, feed, chart, dashboard, form, map, timeline), 18 cell types, filter / sort / group / calculate, row peek + multi-select, table cell drag-fill, CSV / JSON import-export. It is 100% props-driven: it owns NO data state — you hold `db` + `rows` and persist every change callback. The view tab strip scrolls horizontally and the card clips to its border, so it stays inside any container width.\n\n**1. Install** — `npx rr add notion-ui database`. Cascades the `notion-shell` peer (the domain types live there). Components import from `@/features/notion-ui`; types from `@/features/notion-ui`.\n\n**2. Minimal wire-up** — keep `db: Database` + `rows: Page[]` in your store (a Convex query result or `useState`) and pass change handlers:\n```tsx\nimport { NotionDatabase } from '@/features/notion-ui';\n\n<NotionDatabase\n db={db}\n rows={rows}\n onRowAdd={addRow}\n onRowUpdate={(rowId, propId, value) => setValue(rowId, propId, value)}\n onRowRemove={removeRow}\n onPropertyAdd={addProperty}\n onViewActivate={setActiveView}\n onViewAdd={addView}\n onViewConfigChange={(viewId, patch) => patchView(viewId, patch)}\n/>\n```\nOmit any callback and that affordance goes read-only; pass `readOnly` to freeze everything at once.\n\n**3. Data shape** — `Database = { id, name, properties: Property[], views: DatabaseViewConfig[], activeViewId }`; each row `Page = { id, title, rowProps: Record<propId, PropertyValue> }`. For `relation` / `rollup` cells also pass `pages` + `databases`; for `person` / `created_by` cells pass `userLookup(id)`.\n\n**4. Import / export** — mount `<DatabaseIOActions db={db} rows={rows} onImport={handleImport} />` in your toolbar: CSV/JSON in (with schema-diff), CSV/JSON + live-schema templates out. New columns arrive with a `tempId` — map it to your real backend id before writing their `rowProps`.\n\n**5. Backend (optional)** — the UI is store-agnostic. For Convex persistence copy `template-base/database-silong/convex/` (handlers → `convex/`, schema fragment merges into `convex/schema.ts`). Pick `_shared/minimal/` (single-user, noop authz) or `_shared/full/` (`@convex-dev/auth` + workspaces). See CONVEX-BACKEND.md.\n\n**Just one view?** Import it directly — `import { TableView } from '@/features/notion-ui'` — and feed it `rows` + `renderCell` + `renderColumnHeader`.",
4034
+ "variants": {
4035
+ "default": "page",
4036
+ "shared": "shared",
4037
+ "items": [
4038
+ {
4039
+ "id": "page",
4040
+ "title": "Page",
4041
+ "description": "Page + block editor primitives (NotionPage / NotionBlock, SlashMenu, renderers)."
4042
+ },
4043
+ {
4044
+ "id": "database",
4045
+ "title": "Database",
4046
+ "description": "11-view database (NotionDatabase, filter/sort/group, formula, CSV/JSON I/O)."
4047
+ },
4048
+ {
4049
+ "id": "sidebar",
4050
+ "title": "Sidebar",
4051
+ "description": "Tree-nav sidebar (NotionSidebar, dnd reorder + reparent, inline rename)."
4052
+ }
4053
+ ]
4054
+ }
3725
4055
  },
3726
4056
  {
3727
4057
  "slug": "image-picker",
@@ -3766,98 +4096,6 @@
3766
4096
  ],
3767
4097
  "agentRecipe": "Run `npx rr add image-picker`. The headline component is `<ImagePickerButton label=\"Change image\" onChange={(img)=>save(img)} onUpload={…} searchUnsplash={…} />` — ONE button that opens the 4-tab dialog (gallery / upload / link / Unsplash). For a reposition-able cover/hero band use `<ImageBanner image={value} onChange={save} resolvedUrl={…} onUpload={…} searchUnsplash={…} />` (also passable to notion-shell's `<NotionPage coverSlot={…} />`). Inject the backend: `onUpload` = the `files` slice's useFileUpload().upload (returns a FileRef); resolve upload images for display with `resolvedUrl` = files useFileUrl(parseFileRef(imageRef(parseImage(value))).storageId). `searchUnsplash` = `unsplashSearchVia('/api/unsplash')` — add a server route that proxies api.unsplash.com with UNSPLASH_ACCESS_KEY (never expose the key client-side). Ships a curated Unsplash + gallery fallback so it works with zero wiring. ImageValue = { type, value, positionY?, metadata? }; parseImage handles legacy string values."
3768
4098
  },
3769
- {
3770
- "slug": "notion-sidebar",
3771
- "title": "Notion Sidebar — tree nav + page CRUD (rename · drag · icon picker)",
3772
- "category": "ui",
3773
- "kind": "ui",
3774
- "version": "0.1.0",
3775
- "description": "Standalone Notion-style tree-nav sidebar with full page CRUD, lifted out of notion-shell so it is reusable on its own. Props-driven + fully decoupled — owns its own lightweight NotionSidebarPage type (id / title / icon / parentId), imports no other slice. Capabilities: click a row to open; DOUBLE-CLICK a title to rename inline; drag the grip to reorder AND reparent (a @dnd-kit sortable tree with horizontal-offset depth projection); collapse/expand subtrees; hover a row for +subpage / delete. Optional per-row icon PICKER — wire `renderIconPicker` + `onIconChange` (e.g. @/features/icon-picker's IconPickerPopover) so clicking a row icon opens the picker. The host owns the data and dispatches onSelect / onCreate / onRename / onDelete / onMove / onIconChange. Compose with notion-shell (page editor) + notion-database (embedded DBs) for the full Notion-clone OS — see the notion-page-clone-os template.",
3776
- "source": "notion-page-clone",
3777
- "slicePath": "frontend/slices/notion-sidebar",
3778
- "convexPaths": [],
3779
- "npm": [
3780
- "@dnd-kit/core",
3781
- "@dnd-kit/sortable",
3782
- "@dnd-kit/utilities"
3783
- ],
3784
- "shadcn": [
3785
- "button",
3786
- "input"
3787
- ],
3788
- "env": [],
3789
- "peers": [],
3790
- "providers": [],
3791
- "tags": [
3792
- "ui",
3793
- "notion",
3794
- "sidebar",
3795
- "tree",
3796
- "nav",
3797
- "page",
3798
- "crud",
3799
- "rename",
3800
- "drag",
3801
- "dnd",
3802
- "reorder",
3803
- "reparent",
3804
- "icon-picker",
3805
- "primitive",
3806
- "portable",
3807
- "notion-like"
3808
- ],
3809
- "agentRecipe": "Run `npx rr add notion-sidebar`. Import `import { NotionSidebar, type NotionSidebarPage } from \"@/features/notion-sidebar\"`. Feed it a flat `pages: NotionSidebarPage[]` ({ id, title, icon, parentId }) — the sidebar builds the tree. Wire callbacks: onSelect(id), onCreate(parentId|null), onRename(id, title) [double-click a title to trigger], onDelete(id), onMove(id, parentId, beforeId) [drag the grip — reorders + reparents], onIconChange(id, icon). For rich icons pass `renderIcon` (display) + `renderIconPicker` (click-to-pick) wired to `@/features/icon-picker` (DynamicIcon + IconPickerPopover). npm: @dnd-kit/core + sortable + utilities. Pair with notion-shell (page editor) + notion-database (embedded DBs) — the notion-page-clone-os template shows the full reducer wiring."
3810
- },
3811
- {
3812
- "slug": "notion-shell",
3813
- "title": "Notion Shell — page + block editor primitives (pure, no sidebar/database)",
3814
- "category": "ui",
3815
- "kind": "ui",
3816
- "version": "0.24.0",
3817
- "description": "Portable Notion-style PAGE EDITOR primitives. v0.22 split the tree-nav SIDEBAR out into the standalone `notion-sidebar` slice (so the page editor and the sidebar are independently reusable); embedded DATABASES already live in the `notion-database` peer. notion-shell ships: NotionPage (optional cover image band + header + body), NotionHeader, NotionBlock (live inline-markdown decorator, hover actions menu, optional dragHandle slot, BUILT-IN code (highlight.js) + equation (KaTeX) blocks), SlashMenu (searchable block-type picker w/ keyboard nav), BlockActionsMenu (turn-into / duplicate / delete), InsertBlockButton (`+` trigger w/ SlashMenu), SortableBlockList (@dnd-kit render-prop wrapper for block reorder), PageActionsMenu (header dropdown: cover/favorite/duplicate/export/trash), InlineFormatToolbar + BlockColorPicker (colour) + MentionTypeahead + PageLayoutSection (layout). SPECIALISED BLOCK RENDERERS: ImageRenderer, EmbedRenderer (YouTube/Vimeo/Loom/Figma/CodePen/Spotify auto-detect). Domain types (Database, Property, PropertyValue, DbView, DatabaseViewConfig, DatabaseFilter, DatabaseSort) remain in notion-shell as the single source of truth (Page.rowOfDatabaseId + rowProps reference them). Pure / props-driven — host owns data + change handlers. Compose notion-sidebar + notion-shell + notion-database for the full Notion-clone OS.",
3818
- "source": "notion-page-clone",
3819
- "slicePath": "frontend/slices/notion-shell",
3820
- "convexPaths": [],
3821
- "npm": [
3822
- "@dnd-kit/core",
3823
- "@dnd-kit/sortable",
3824
- "@dnd-kit/utilities",
3825
- "katex@^0.16.45",
3826
- "highlight.js@^11.11.1"
3827
- ],
3828
- "shadcn": [
3829
- "button",
3830
- "input",
3831
- "checkbox",
3832
- "dropdown-menu",
3833
- "popover"
3834
- ],
3835
- "env": [],
3836
- "peers": [],
3837
- "providers": [],
3838
- "tags": [
3839
- "ui",
3840
- "notion",
3841
- "shell",
3842
- "wrapper",
3843
- "page",
3844
- "block",
3845
- "editor",
3846
- "primitive",
3847
- "portable",
3848
- "slash-menu",
3849
- "decorator",
3850
- "wysiwyg",
3851
- "drag",
3852
- "cover",
3853
- "embed",
3854
- "image",
3855
- "code",
3856
- "equation",
3857
- "notion-like"
3858
- ],
3859
- "agentRecipe": "Run `npx rr add notion-shell` for the portable PAGE EDITOR wrappers ONLY (no backend; the tree-nav sidebar is the separate `notion-sidebar` slice). NPM deps: @dnd-kit/core, @dnd-kit/sortable, @dnd-kit/utilities. Import: `import { NotionPage, NotionBlock, SortableBlockList, PageActionsMenu, InsertBlockButton, InlineFormatToolbar, ImageRenderer, EmbedRenderer } from \"@/features/notion-shell\"`. NotionBlock ships slash menu + decorator + actions menu + dragHandle slot. **`createDefaultBlockRenderers()` returns the block-renderer registry — pass it to `<NotionBlock blockRenderers={…}>` so callout (icon+kind picker), table (editable grid), divider, image, embed, code (highlight.js) + equation (KaTeX) all render. code + equation are now BUILT-IN to notion-shell (npm: katex + highlight.js) — no adapter needed. Only `database` + `toc` are injected at the app level (they depend on host data + the sibling notion-database slice).** NotionPage ships optional cover prop. SortableBlockList wraps a render-prop callback `(id, dragProps) => <NotionBlock dragHandle={...} />`. NotionDatabase ships 6 views via VIEW_REGISTRY. Property cells: text/number/checkbox/select/multi-select/status/date/url/email/phone all built in. For rich icon UX wire `renderIcon` + `renderIconPicker` to `@/features/icon-picker`. **v0.17 — Notion-canonical editing keys (`blockKeyHandler.ts`): Enter splits at the caret into a new block (lists continue their type; an empty list item exits to paragraph); Backspace on an empty non-paragraph downgrades it to a plain paragraph (re-triggerable with `/`); a second Backspace on an empty paragraph merges into the previous block; Arrow up/down at a line edge hops blocks. Wire the host callbacks on `<NotionBlock>`: `onInsertAfter(type, init) => newId`, `onMergeBack()`, `onFocusSibling(dir)` — plus `focusBlock(id, offset?)` exported to move the caret after a host state change. The preview `page-demo.tsx` and the notion-clone template `DocView` show full array- and reducer-based wirings.** PRODUCT POINTER: the full Convex-backed Notion-clone OS (multi-workspace + auth + sharing + comments + snapshots + MCP) lives at https://github.com/rahmanef63/open-silong — clone that repo for the production stack; use this slice when you only need to embed the Notion-style UI in another project.**"
3860
- },
3861
4099
  {
3862
4100
  "slug": "workspace-shell",
3863
4101
  "title": "Workspace Shell — atomic (workspace × menuSet) NavContext",
@@ -4015,17 +4253,21 @@
4015
4253
  "agentRecipe": "Run `npx rr add pages-cms`. Wrap your admin surface in <LocalPagesProvider seed={defaultPages()}> (localStorage, zero backend) or supply your own PagesStore via <PagesProvider>. Render <PagesView publicBase adminBase> for the list and <PageEditorView id publicBase adminBase> for the editor route. Public catch-all looks up the page by slug and renders <BlocksRenderer blocks={page.blocks} />. Add block kinds by extending the PageBlock union + emptyBlock + the renderer/editor switches."
4016
4254
  },
4017
4255
  {
4018
- "slug": "empty-states",
4019
- "title": "Empty States — 404/500/403 + zero-data",
4256
+ "slug": "feedback-states",
4257
+ "title": "Feedback States — loading skeletons + empty/error states",
4020
4258
  "category": "ui",
4021
4259
  "kind": "ui",
4022
4260
  "version": "0.2.0",
4023
- "description": "Configurable EmptyState composing the shadcn Empty primitive: kind presets 404 / 500 / 403 / no-results / empty-list / first-use with default lucide icon + copy, all overridable. Primary/secondary actions. ErrorPage full-page wrapper is a drop-in for app/not-found.tsx and app/error.tsx (recipes in README).",
4261
+ "description": "Two co-located placeholder surfaces behind one slug. loading: a configurable LoadingSkeleton over the shadcn Skeleton (kind presets text / card / list / table / form / page / block, overridable count + columns) plus a spinner LoadingState (inline / block / overlay) for in-flight work. empty: a configurable EmptyState over the shadcn Empty (404 / 500 / 403 / no-results / empty-list / first-use, overridable icon/title/copy/actions) plus an ErrorPage full-page wrapper for app/not-found.tsx and app/error.tsx. Install one surface with `npx rr add feedback-states loading|empty`, or both with `npx rr add feedback-states`. Replaces ad-hoc animate-pulse divs, hand-rolled Loader2 spans, and one-off error pages.",
4024
4262
  "source": "rr original",
4025
- "slicePath": "frontend/slices/empty-states",
4263
+ "slicePath": "frontend/slices/feedback-states",
4026
4264
  "convexPaths": [],
4027
- "npm": [],
4265
+ "npm": [
4266
+ "lucide-react@^0.400.0"
4267
+ ],
4028
4268
  "shadcn": [
4269
+ "skeleton",
4270
+ "spinner",
4029
4271
  "empty",
4030
4272
  "button"
4031
4273
  ],
@@ -4033,45 +4275,34 @@
4033
4275
  "peers": [],
4034
4276
  "providers": [],
4035
4277
  "tags": [
4278
+ "loading",
4279
+ "skeleton",
4280
+ "spinner",
4036
4281
  "empty-state",
4037
4282
  "404",
4038
4283
  "500",
4039
4284
  "403",
4040
4285
  "error-page",
4041
- "no-results",
4042
- "onboarding",
4043
- "basics"
4044
- ],
4045
- "agentRecipe": "Run `npx rr add empty-states`. Drop <EmptyState kind=\"no-results\" /> into zero-data spots; wrap with <ErrorPage kind=\"404\" /> in app/not-found.tsx and kind=\"500\" in app/error.tsx. Every preset's icon/title/description/action overridable per use."
4046
- },
4047
- {
4048
- "slug": "loading-states",
4049
- "title": "Loading States — skeletons + spinners SSOT",
4050
- "category": "ui",
4051
- "kind": "ui",
4052
- "version": "0.2.0",
4053
- "description": "Configurable LoadingSkeleton composing the shadcn Skeleton primitive: kind presets text / card / list / table / form / page / block with overridable count + columns. Spinner-based LoadingState (inline / block / overlay) covers in-flight work where a skeleton would be wrong. The page kind drops straight into a route loading.tsx (recipe in README).",
4054
- "source": "rr original",
4055
- "slicePath": "frontend/slices/loading-states",
4056
- "convexPaths": [],
4057
- "npm": [],
4058
- "shadcn": [
4059
- "skeleton",
4060
- "spinner"
4061
- ],
4062
- "env": [],
4063
- "peers": [],
4064
- "providers": [],
4065
- "tags": [
4066
- "loading",
4067
- "skeleton",
4068
- "spinner",
4069
- "suspense",
4070
4286
  "fallback",
4071
4287
  "placeholder",
4072
4288
  "basics"
4073
4289
  ],
4074
- "agentRecipe": "Run `npx rr add loading-states`. Pick the LoadingSkeleton kind that mirrors the streamed content (<LoadingSkeleton kind=\"table\" count={8} />); use kind=\"page\" inside route loading.tsx. For in-flight work (submits, refetches) use <LoadingState variant=\"inline|block|overlay\" /> instead of a skeleton."
4290
+ "agentRecipe": "Run `npx rr add feedback-states` for both, or `npx rr add feedback-states loading` / `empty` for one surface. loading: <LoadingSkeleton kind=\"table\" count={8} /> mirrors streamed content, kind=\"page\" drops into route loading.tsx, <LoadingState variant=\"inline|block|overlay\" /> for in-flight work. empty: <EmptyState kind=\"no-results\" /> in zero-data spots, <ErrorPage kind=\"404\" /> in app/not-found.tsx and kind=\"500\" in app/error.tsx. Every preset overridable per use.",
4291
+ "variants": {
4292
+ "default": "loading",
4293
+ "items": [
4294
+ {
4295
+ "id": "loading",
4296
+ "title": "Loading",
4297
+ "description": "Skeletons + spinners for in-flight UI (LoadingSkeleton, LoadingState)."
4298
+ },
4299
+ {
4300
+ "id": "empty",
4301
+ "title": "Empty",
4302
+ "description": "404/500/403 + zero-data placeholders (EmptyState, ErrorPage)."
4303
+ }
4304
+ ]
4305
+ }
4075
4306
  },
4076
4307
  {
4077
4308
  "slug": "marketing-chrome",
@@ -4104,42 +4335,63 @@
4104
4335
  "agentRecipe": "Run `npx rr add marketing-chrome`. Feed MarketingHeader { brand, nav[], cta, layout } and MarketingFooter { brand, columns[], social[], legal[], layout }. Header layout split is the default marketing pattern; footer columns for full sites, slim for single-pagers."
4105
4336
  },
4106
4337
  {
4107
- "slug": "settings-page",
4108
- "title": "Settings Page adapter-driven shell",
4338
+ "slug": "settings",
4339
+ "title": "Settings — account + appearance shells",
4109
4340
  "category": "ui",
4110
4341
  "kind": "ui",
4111
- "version": "0.2.0",
4112
- "description": "SettingsShell two-column settings surface: section nav (mobile collapses to a Select) + Profile (avatar/name/email/bio), Preferences (theme/language/density), Notifications (switch rows), Danger zone (AlertDialog-confirmed delete). SettingsAdapter = load() + save(patch) wire to Convex or anything; createMemoryAdapter ships for demos. Optimistic save with rollback.",
4342
+ "version": "1.0.0",
4343
+ "description": "Two settings surfaces behind one slug, each adapter-driven so the slice owns no data. account: SettingsShell two-column surface (nav collapses to a Select on mobile) Profile (avatar/name/email/bio), Preferences (theme/language/density), Notifications (switch rows), Danger zone (AlertDialog-confirmed delete) over an ASYNC SettingsAdapter { load, save(patch) } with optimistic save + rollback; createMemoryAdapter ships for demos. appearance: AppearancePanel (style/mode/accent/wallpaper/reduce-transparency/display) over a SYNC per-setting AppearanceAdapter, plus the generic SettingsSection / SettingsRow / Segmented / AccentSwatches primitives you compose custom panels from. Install one surface with `npx rr add settings account|appearance`, or both with `npx rr add settings`.",
4113
4344
  "source": "rr original",
4114
- "slicePath": "frontend/slices/settings-page",
4345
+ "slicePath": "frontend/slices/settings",
4115
4346
  "convexPaths": [],
4116
- "npm": [],
4347
+ "npm": [
4348
+ "lucide-react@^0.400.0"
4349
+ ],
4117
4350
  "shadcn": [
4118
- "card",
4351
+ "alert-dialog",
4352
+ "avatar",
4119
4353
  "button",
4354
+ "card",
4120
4355
  "input",
4121
4356
  "label",
4122
- "switch",
4123
4357
  "select",
4124
4358
  "separator",
4125
- "avatar",
4126
- "alert-dialog",
4359
+ "skeleton",
4360
+ "switch",
4127
4361
  "textarea",
4128
- "skeleton"
4362
+ "toggle-group"
4129
4363
  ],
4130
4364
  "env": [],
4131
4365
  "peers": [],
4132
4366
  "providers": [],
4133
4367
  "tags": [
4134
4368
  "settings",
4135
- "account",
4136
- "profile",
4137
4369
  "preferences",
4138
- "notifications",
4139
- "danger-zone",
4370
+ "account",
4371
+ "appearance",
4372
+ "theme",
4373
+ "adapter",
4374
+ "shell",
4375
+ "primitives",
4376
+ "ui",
4140
4377
  "basics"
4141
4378
  ],
4142
- "agentRecipe": "Run `npx rr add settings-page`. Implement SettingsAdapter { load, save } over your backend (Convex query + mutation), pass to <SettingsShell adapter>. save receives per-section partial patches shallow-merge server-side. onDeleteAccount callback wires the danger zone."
4379
+ "agentRecipe": "Run `npx rr add settings` for both, or `npx rr add settings account` / `appearance` for one. account: implement SettingsAdapter { load, save } over your backend (Convex query + mutation), pass to <SettingsShell adapter>; save gets per-section partial patches (shallow-merge server-side); onDeleteAccount wires the danger zone. appearance: build an AppearanceAdapter (per-setting SegSetting values) from your appearance store, pass to <AppearancePanel appearance>; or compose custom panels from <SettingsSection>/<SettingsRow>/<Segmented>/<AccentSwatches>.",
4380
+ "variants": {
4381
+ "default": "account",
4382
+ "items": [
4383
+ {
4384
+ "id": "account",
4385
+ "title": "Account",
4386
+ "description": "Profile/preferences/notifications/danger-zone shell over an async load+save adapter."
4387
+ },
4388
+ {
4389
+ "id": "appearance",
4390
+ "title": "Appearance",
4391
+ "description": "Style/mode/accent/wallpaper/display shell over a sync per-setting adapter + the shared Section/Row/Segmented primitives."
4392
+ }
4393
+ ]
4394
+ }
4143
4395
  },
4144
4396
  {
4145
4397
  "slug": "notifications-center",
@@ -4176,14 +4428,14 @@
4176
4428
  "agentRecipe": "Run `npx rr add notifications-center`. Mount <NotificationBell adapter> in your topbar. Implement NotificationsAdapter over your feed (Convex query + mutations) or start with createMemoryNotificationsAdapter(seed). surface=\"sheet\" for mobile-heavy apps."
4177
4429
  },
4178
4430
  {
4179
- "slug": "media-studio",
4180
- "title": "Media Studio — photo / social design canvas",
4431
+ "slug": "design-studio",
4432
+ "title": "Design Studio — photo / social design canvas",
4181
4433
  "category": "os",
4182
4434
  "kind": "ui",
4183
4435
  "version": "1.0.0",
4184
4436
  "description": "A layered canvas studio: image/text/shape layers with filters, masks, transforms, safe-area guides and aspect presets (1:1/4:5/9:16/16:9), plus an export modal (download / copy / import JSON). Runs fully offline on bundled gradient-SVG samples. Host wiring is one call: configureMediaStudio({ saveDoc, imageSources }) lights up Save-to-host and feeds real image sources. Self-contained: inspector hooks are inert seams in lib/host.ts.",
4185
4437
  "source": "rahmanef63/os-vps",
4186
- "slicePath": "frontend/slices/media-studio",
4438
+ "slicePath": "frontend/slices/design-studio",
4187
4439
  "convexPaths": [],
4188
4440
  "npm": [
4189
4441
  "lucide-react"
@@ -4207,7 +4459,7 @@
4207
4459
  "design",
4208
4460
  "ui"
4209
4461
  ],
4210
- "agentRecipe": "Stack: Next 16 + React 19 + Tailwind 4 + shadcn/ui. Layered canvas editor. Fully client-side; no backend required.\n\nSTEP 1 — Install. `npx rr add media-studio`. Ensure `@/features/media-studio` resolves and Tailwind scans the slice folder.\n\nSTEP 2 — Deps. npm: `lucide-react`. shadcn: button, dialog, badge, tooltip, scroll-area.\n\nSTEP 3 — Mount. `<MediaStudio />` in a height-bearing box — unwired it edits bundled sample layers. Or register `mediaStudioApp` in an appshell manifest.\n\nSTEP 4 — Host wiring. `configureMediaStudio({ saveDoc, imageSources })` — saveDoc persists the serialized document (enables Save-to-host in the export modal); imageSources supplies image URLs for new layers."
4462
+ "agentRecipe": "Stack: Next 16 + React 19 + Tailwind 4 + shadcn/ui. Layered canvas editor. Fully client-side; no backend required.\n\nSTEP 1 — Install. `npx rr add design-studio`. Ensure `@/features/design-studio` resolves and Tailwind scans the slice folder.\n\nSTEP 2 — Deps. npm: `lucide-react`. shadcn: button, dialog, badge, tooltip, scroll-area.\n\nSTEP 3 — Mount. `<MediaStudio />` in a height-bearing box — unwired it edits bundled sample layers. Or register `mediaStudioApp` in an appshell manifest.\n\nSTEP 4 — Host wiring. `configureMediaStudio({ saveDoc, imageSources })` — saveDoc persists the serialized document (enables Save-to-host in the export modal); imageSources supplies image URLs for new layers."
4211
4463
  },
4212
4464
  {
4213
4465
  "slug": "quicklinks",
@@ -4236,37 +4488,6 @@
4236
4488
  "ui"
4237
4489
  ],
4238
4490
  "agentRecipe": "Stack: Next 16 + React 19 + Tailwind 4 + shadcn/ui. Website shortcut grid. Fully client-side; no backend required.\n\nSTEP 1 — Install. `npx rr add quicklinks`. Ensure `@/features/quicklinks` resolves and Tailwind scans the slice folder.\n\nSTEP 2 — Deps. npm: `lucide-react`. shadcn: button.\n\nSTEP 3 — Mount. `<Quicklinks />` — unwired it persists to localStorage (\"rr:quicklinks\") with 4 demo seeds. Or register `quicklinksApp` in an appshell manifest.\n\nSTEP 4 — Host store. `configureQuicklinks(store)` with { get, subscribe, add, remove, hydrate? } — or feed appshell's useQuickLinks capability from the same store so dock shortcuts stay in sync."
4239
- },
4240
- {
4241
- "slug": "shell-settings",
4242
- "title": "Shell Settings — settings-app UI primitives",
4243
- "category": "ui",
4244
- "kind": "ui",
4245
- "version": "1.0.0",
4246
- "description": "The settings-app building blocks: SettingsSection, Row, AccentSwatches, a slice-local Segmented control, and a ready AppearancePanel (style/mode/accent/wallpaper/device/transparency groups — every group optional). Pure presentation: the injected AppearanceAdapter IS the contract, so it binds to any appearance store (appshell capabilities, zustand, plain useState) with zero slice edits.",
4247
- "source": "rahmanef63/os-vps",
4248
- "slicePath": "frontend/slices/shell-settings",
4249
- "convexPaths": [],
4250
- "npm": [
4251
- "lucide-react"
4252
- ],
4253
- "shadcn": [
4254
- "button",
4255
- "switch",
4256
- "toggle-group",
4257
- "separator"
4258
- ],
4259
- "env": [],
4260
- "peers": [],
4261
- "providers": [],
4262
- "tags": [
4263
- "settings",
4264
- "preferences",
4265
- "appearance",
4266
- "primitives",
4267
- "ui"
4268
- ],
4269
- "agentRecipe": "Stack: Next 16 + React 19 + Tailwind 4 + shadcn/ui. Settings UI primitives. Pure presentation; state injected.\n\nSTEP 1 — Install. `npx rr add shell-settings`. Ensure `@/features/shell-settings` resolves and Tailwind scans the slice folder.\n\nSTEP 2 — Deps. npm: `lucide-react`. shadcn: button, switch, toggle-group, separator.\n\nSTEP 3 — Mount. `<AppearancePanel adapter={adapter} />` with an AppearanceAdapter (all groups optional — omit a group to hide it), or compose SettingsSection/Row/AccentSwatches/Segmented directly for custom panels.\n\nSTEP 4 — Bind. Wire the adapter to your appearance store (theme mode, accent, wallpaper, device, transparency) — the panel re-renders from the values you pass; no internal state."
4270
4491
  }
4271
4492
  ]
4272
4493
  }