From b8f32a863e550af18c2371e816633143447ff462 Mon Sep 17 00:00:00 2001 From: Jeff Emmett Date: Mon, 9 Mar 2026 12:56:18 -0700 Subject: [PATCH 1/3] chore(rwallet): cache-bust wallet viewer JS (v=2) Co-Authored-By: Claude Opus 4.6 --- modules/rwallet/mod.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/rwallet/mod.ts b/modules/rwallet/mod.ts index b27bbbd..8c9aba8 100644 --- a/modules/rwallet/mod.ts +++ b/modules/rwallet/mod.ts @@ -390,7 +390,7 @@ routes.get("/", (c) => { modules: getModuleInfoList(), theme: "dark", body: ``, - scripts: ``, + scripts: ``, styles: ``, })); }); From 6173e17bb99031d043c329d5659e98ae28deb134 Mon Sep 17 00:00:00 2001 From: Jeff Emmett Date: Mon, 9 Mar 2026 13:31:23 -0700 Subject: [PATCH 2/3] feat(rsocials): hub navigation page, route renames, and campaigns listing Restructure rSocials landing to a hub with navigation cards for Campaigns, Threads, and Thread Editor. Rename /thread routes to /thread-editor for clarity. Render campaigns listing inline instead of redirecting. Also improve rNotes notebook creation to auto-open first note for editing. Co-Authored-By: Claude Opus 4.6 --- modules/rnotes/components/folk-notes-app.ts | 24 +++-- .../components/folk-campaign-manager.ts | 2 +- .../components/folk-campaign-planner.ts | 4 +- .../components/folk-thread-builder.ts | 4 +- .../components/folk-thread-gallery.ts | 4 +- modules/rsocials/mod.ts | 89 ++++++++++++++----- 6 files changed, 93 insertions(+), 34 deletions(-) diff --git a/modules/rnotes/components/folk-notes-app.ts b/modules/rnotes/components/folk-notes-app.ts index cee4a1b..29054e6 100644 --- a/modules/rnotes/components/folk-notes-app.ts +++ b/modules/rnotes/components/folk-notes-app.ts @@ -360,17 +360,31 @@ Gear: EUR 400 (10%)

Maya is tracking expenses in rF } private demoCreateNotebook() { - const title = prompt("Notebook name:"); - if (!title?.trim()) return; const now = Date.now(); + const nbId = `demo-nb-${now}`; + const noteId = `demo-note-${now}`; + const newNote: Note = { + id: noteId, title: "Untitled Note", content: "", content_plain: "", + content_format: 'tiptap-json', + type: "NOTE", tags: null, is_pinned: false, + created_at: new Date(now).toISOString(), updated_at: new Date(now).toISOString(), + }; const nb = { - id: `demo-nb-${now}`, title, description: "", - cover_color: "#8b5cf6", note_count: "0", - updated_at: new Date(now).toISOString(), notes: [] as Note[], + id: nbId, title: "Untitled Notebook", description: "", + cover_color: "#8b5cf6", note_count: "1", + updated_at: new Date(now).toISOString(), notes: [newNote], } as any; this.demoNotebooks.push(nb); this.notebooks = this.demoNotebooks.map(({ notes, ...rest }) => rest as Notebook); + this.selectedNotebook = { ...nb }; + this.view = "notebook"; this.render(); + // Auto-open the note for editing + this.selectedNote = newNote; + this.view = "note"; + this.renderNav(); + this.renderMeta(); + this.mountEditor(newNote); } private demoCreateNote() { diff --git a/modules/rsocials/components/folk-campaign-manager.ts b/modules/rsocials/components/folk-campaign-manager.ts index c836e98..e321baa 100644 --- a/modules/rsocials/components/folk-campaign-manager.ts +++ b/modules/rsocials/components/folk-campaign-manager.ts @@ -131,7 +131,7 @@ export class FolkCampaignManager extends HTMLElement {

- Open Thread Builder + Open Thread Builder
${phaseHTML} diff --git a/modules/rsocials/components/folk-campaign-planner.ts b/modules/rsocials/components/folk-campaign-planner.ts index d920448..13dd22c 100644 --- a/modules/rsocials/components/folk-campaign-planner.ts +++ b/modules/rsocials/components/folk-campaign-planner.ts @@ -820,7 +820,7 @@ class FolkCampaignPlanner extends HTMLElement { } else if (action === 'open-thread') { const d = node.data as ThreadNodeData; if (d.threadId) { - window.location.href = `/${this.space}/rsocials/thread/${d.threadId}/edit`; + window.location.href = `/${this.space}/rsocials/thread-editor/${d.threadId}/edit`; } } }); @@ -1457,7 +1457,7 @@ class FolkCampaignPlanner extends HTMLElement { if (node?.type === 'thread') { const d = node.data as ThreadNodeData; if (d.threadId) { - window.location.href = `/${this.space}/rsocials/thread/${d.threadId}/edit`; + window.location.href = `/${this.space}/rsocials/thread-editor/${d.threadId}/edit`; } } }); diff --git a/modules/rsocials/components/folk-thread-builder.ts b/modules/rsocials/components/folk-thread-builder.ts index 4a6f28e..441c80e 100644 --- a/modules/rsocials/components/folk-thread-builder.ts +++ b/modules/rsocials/components/folk-thread-builder.ts @@ -274,7 +274,7 @@ export class FolkThreadBuilder extends HTMLElement {
${tweetCards}
- Edit Thread + Edit Thread
@@ -289,7 +289,7 @@ export class FolkThreadBuilder extends HTMLElement {
diff --git a/modules/rsocials/components/folk-thread-gallery.ts b/modules/rsocials/components/folk-thread-gallery.ts index 5682f32..a074066 100644 --- a/modules/rsocials/components/folk-thread-gallery.ts +++ b/modules/rsocials/components/folk-thread-gallery.ts @@ -96,7 +96,7 @@ export class FolkThreadGallery extends HTMLElement { const cardsHTML = threads.length === 0 ? `

No threads yet. Create your first thread!

- Create Thread + Create Thread
` : `
${threads.map(t => { @@ -164,7 +164,7 @@ export class FolkThreadGallery extends HTMLElement { diff --git a/modules/rsocials/mod.ts b/modules/rsocials/mod.ts index a99ef4f..92c6728 100644 --- a/modules/rsocials/mod.ts +++ b/modules/rsocials/mod.ts @@ -459,7 +459,7 @@ routes.get("/thread/:id", async (c) => { })); }); -routes.get("/thread/:id/edit", async (c) => { +routes.get("/thread-editor/:id/edit", async (c) => { const space = c.req.param("space") || "demo"; const id = c.req.param("id"); if (!id || id.includes("..") || id.includes("/")) return c.text("Not found", 404); @@ -481,10 +481,10 @@ routes.get("/thread/:id/edit", async (c) => { })); }); -routes.get("/thread", (c) => { +routes.get("/thread-editor", (c) => { const space = c.req.param("space") || "demo"; return c.html(renderShell({ - title: `Thread Builder — rSocials | rSpace`, + title: `Thread Editor — rSocials | rSpace`, moduleId: "rsocials", spaceSlug: space, modules: getModuleInfoList(), @@ -511,7 +511,16 @@ routes.get("/threads", (c) => { routes.get("/campaigns", (c) => { const space = c.req.param("space") || "demo"; - return c.redirect(`/${space}/rsocials/campaign`); + return c.html(renderShell({ + title: `Campaigns — rSocials | rSpace`, + moduleId: "rsocials", + spaceSlug: space, + modules: getModuleInfoList(), + theme: "dark", + body: ``, + styles: ``, + scripts: ``, + })); }); // ── Demo feed rendering (server-rendered, no web component needed) ── @@ -600,19 +609,55 @@ routes.get("/landing", (c) => { })); }); -// ── Default: campaign planner canvas ── +// ── Default: rSocials hub with navigation ── routes.get("/", (c) => { const space = c.req.param("space") || "demo"; + const base = `/${escapeHtml(space)}/rsocials`; return c.html(renderShell({ - title: `${space} — rSocials | rSpace`, + title: `rSocials — ${space} | rSpace`, moduleId: "rsocials", spaceSlug: space, modules: getModuleInfoList(), - body: ``, - scripts: ``, - styles: ``, theme: "dark", + styles: ``, + body: ``, })); }); @@ -651,19 +696,7 @@ export const socialsModule: RSpaceModule = { ], subPageInfos: [ { - path: "thread", - title: "Thread Builder", - icon: "🧵", - tagline: "rSocials Tool", - description: "Compose, preview, and schedule tweet threads with a live card-by-card preview. Save drafts, generate share images, and publish when ready.", - features: [ - { icon: "✍️", title: "Live Preview", text: "See your thread as tweet cards in real time as you type, with character counts and thread numbering." }, - { icon: "💾", title: "Save & Edit Drafts", text: "Save thread drafts to your space, revisit and refine them before publishing." }, - { icon: "🖼️", title: "Share Images", text: "Auto-generate a branded share image of your thread for cross-posting." }, - ], - }, - { - path: "campaign", + path: "campaigns", title: "Campaign Manager", icon: "📢", tagline: "rSocials Tool", @@ -681,5 +714,17 @@ export const socialsModule: RSpaceModule = { tagline: "rSocials Tool", description: "Browse all saved thread drafts in your community. Find inspiration, remix threads, or pick up where you left off.", }, + { + path: "thread-editor", + title: "Thread Editor", + icon: "🧵", + tagline: "rSocials Tool", + description: "Compose, preview, and schedule tweet threads with a live card-by-card preview. Save drafts, generate share images, and publish when ready.", + features: [ + { icon: "✍️", title: "Live Preview", text: "See your thread as tweet cards in real time as you type, with character counts and thread numbering." }, + { icon: "💾", title: "Save & Edit Drafts", text: "Save thread drafts to your space, revisit and refine them before publishing." }, + { icon: "🖼️", title: "Share Images", text: "Auto-generate a branded share image of your thread for cross-posting." }, + ], + }, ], }; From 79f0ebb53850a566cbfe1dc25e32a8cc0fea0734 Mon Sep 17 00:00:00 2001 From: Jeff Emmett Date: Mon, 9 Mar 2026 13:32:03 -0700 Subject: [PATCH 3/3] fix(rnotes): create notebook instantly without browser prompt MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Skip the browser prompt() dialog — clicking "+ New Notebook" now immediately creates an "Untitled Notebook" and opens it for editing. Co-Authored-By: Claude Opus 4.6 --- modules/rnotes/components/folk-notes-app.ts | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/modules/rnotes/components/folk-notes-app.ts b/modules/rnotes/components/folk-notes-app.ts index 29054e6..66d5555 100644 --- a/modules/rnotes/components/folk-notes-app.ts +++ b/modules/rnotes/components/folk-notes-app.ts @@ -740,16 +740,20 @@ Gear: EUR 400 (10%)

Maya is tracking expenses in rF } private async createNotebook() { - const title = prompt("Notebook name:"); - if (!title?.trim()) return; try { const base = this.getApiBase(); - await fetch(`${base}/api/notebooks`, { + const res = await fetch(`${base}/api/notebooks`, { method: "POST", headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ title }), + body: JSON.stringify({ title: "Untitled Notebook" }), }); - await this.loadNotebooks(); + const nb = await res.json(); + if (nb?.id) { + this.view = "notebook"; + await this.loadNotebook(nb.id); + } else { + await this.loadNotebooks(); + } } catch { this.error = "Failed to create notebook"; this.render();