merge: resolve rsocials conflict, keep dev campaigns page
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
commit
b553acd756
|
|
@ -360,17 +360,31 @@ Gear: EUR 400 (10%)</code></pre><p><em>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() {
|
||||
|
|
@ -726,16 +740,20 @@ Gear: EUR 400 (10%)</code></pre><p><em>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();
|
||||
|
|
|
|||
|
|
@ -131,7 +131,7 @@ export class FolkCampaignManager extends HTMLElement {
|
|||
</div>
|
||||
</div>
|
||||
<div class="actions">
|
||||
<a href="/${this.esc(this._space)}/rsocials/thread" class="btn btn--outline">Open Thread Builder</a>
|
||||
<a href="/${this.esc(this._space)}/rsocials/thread-editor" class="btn btn--outline">Open Thread Builder</a>
|
||||
<button class="btn btn--primary" id="import-md-btn">Import from Markdown</button>
|
||||
</div>
|
||||
${phaseHTML}
|
||||
|
|
|
|||
|
|
@ -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`;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -274,7 +274,7 @@ export class FolkThreadBuilder extends HTMLElement {
|
|||
</div>
|
||||
<div class="preview ro-cards">${tweetCards}</div>
|
||||
<div class="ro-actions">
|
||||
<a href="/${this.esc(this._space)}/rsocials/thread/${this.esc(t.id)}/edit" class="btn btn--primary">Edit Thread</a>
|
||||
<a href="/${this.esc(this._space)}/rsocials/thread-editor/${this.esc(t.id)}/edit" class="btn btn--primary">Edit Thread</a>
|
||||
<button class="btn btn--outline" id="ro-copy-thread">Copy Thread</button>
|
||||
<button class="btn btn--outline" id="ro-copy-link">Copy Link</button>
|
||||
<div class="export-dropdown">
|
||||
|
|
@ -289,7 +289,7 @@ export class FolkThreadBuilder extends HTMLElement {
|
|||
</div>
|
||||
</div>
|
||||
<div class="ro-cta">
|
||||
<a href="/${this.esc(this._space)}/rsocials/thread" class="btn btn--success">Create Your Own Thread</a>
|
||||
<a href="/${this.esc(this._space)}/rsocials/thread-editor" class="btn btn--success">Create Your Own Thread</a>
|
||||
<a href="/${this.esc(this._space)}/rsocials/threads" class="btn btn--outline">Browse All Threads</a>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -96,7 +96,7 @@ export class FolkThreadGallery extends HTMLElement {
|
|||
const cardsHTML = threads.length === 0
|
||||
? `<div class="empty">
|
||||
<p>No threads yet. Create your first thread!</p>
|
||||
<a href="/${this.esc(space)}/rsocials/thread" class="btn btn--success">Create Thread</a>
|
||||
<a href="/${this.esc(space)}/rsocials/thread-editor" class="btn btn--success">Create Thread</a>
|
||||
</div>`
|
||||
: `<div class="grid">
|
||||
${threads.map(t => {
|
||||
|
|
@ -164,7 +164,7 @@ export class FolkThreadGallery extends HTMLElement {
|
|||
<div class="gallery">
|
||||
<div class="header">
|
||||
<h1>Threads</h1>
|
||||
<a href="/${this.esc(space)}/rsocials/thread" class="btn btn--primary">New Thread</a>
|
||||
<a href="/${this.esc(space)}/rsocials/thread-editor" class="btn btn--primary">New Thread</a>
|
||||
</div>
|
||||
${cardsHTML}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -467,7 +467,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 dataSpace = (c.get("effectiveSpace" as any) as string) || space;
|
||||
const id = c.req.param("id");
|
||||
|
|
@ -490,11 +490,11 @@ routes.get("/thread/:id/edit", async (c) => {
|
|||
}));
|
||||
});
|
||||
|
||||
routes.get("/thread", (c) => {
|
||||
routes.get("/thread-editor", (c) => {
|
||||
const space = c.req.param("space") || "demo";
|
||||
const dataSpace = (c.get("effectiveSpace" as any) as string) || space;
|
||||
return c.html(renderShell({
|
||||
title: `Thread Builder — rSocials | rSpace`,
|
||||
title: `Thread Editor — rSocials | rSpace`,
|
||||
moduleId: "rsocials",
|
||||
spaceSlug: space,
|
||||
modules: getModuleInfoList(),
|
||||
|
|
@ -522,8 +522,16 @@ routes.get("/threads", (c) => {
|
|||
|
||||
routes.get("/campaigns", (c) => {
|
||||
const space = c.req.param("space") || "demo";
|
||||
const dataSpace = (c.get("effectiveSpace" as any) as string) || space;
|
||||
return c.redirect(`/${space}/rsocials/campaign`);
|
||||
return c.html(renderShell({
|
||||
title: `Campaigns — rSocials | rSpace`,
|
||||
moduleId: "rsocials",
|
||||
spaceSlug: space,
|
||||
modules: getModuleInfoList(),
|
||||
theme: "dark",
|
||||
body: `<folk-campaign-manager space="${escapeHtml(space)}"></folk-campaign-manager>`,
|
||||
styles: `<link rel="stylesheet" href="/modules/rsocials/socials.css">`,
|
||||
scripts: `<script type="module" src="/modules/rsocials/folk-campaign-manager.js"></script>`,
|
||||
}));
|
||||
});
|
||||
|
||||
// ── Demo feed rendering (server-rendered, no web component needed) ──
|
||||
|
|
@ -615,20 +623,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 dataSpace = (c.get("effectiveSpace" as any) as string) || space;
|
||||
const base = `/${escapeHtml(space)}/rsocials`;
|
||||
return c.html(renderShell({
|
||||
title: `${space} — rSocials | rSpace`,
|
||||
title: `rSocials — ${space} | rSpace`,
|
||||
moduleId: "rsocials",
|
||||
spaceSlug: space,
|
||||
modules: getModuleInfoList(),
|
||||
body: `<folk-campaign-planner space="${escapeHtml(space)}"></folk-campaign-planner>`,
|
||||
scripts: `<script type="module" src="/modules/rsocials/folk-campaign-planner.js"></script>`,
|
||||
styles: `<link rel="stylesheet" href="/modules/rsocials/campaign-planner.css">`,
|
||||
theme: "dark",
|
||||
styles: `<style>
|
||||
.rs-hub{max-width:720px;margin:3rem auto;padding:0 1.5rem}
|
||||
.rs-hub h1{font-size:1.8rem;margin-bottom:.5rem}
|
||||
.rs-hub p{color:var(--rs-text-secondary,#aaa);margin-bottom:2rem}
|
||||
.rs-nav{display:flex;flex-direction:column;gap:1rem}
|
||||
.rs-nav a{display:flex;align-items:center;gap:1rem;padding:1.25rem 1.5rem;border-radius:12px;background:var(--rs-surface,#1e1e2e);border:1px solid var(--rs-border,#333);text-decoration:none;color:inherit;transition:border-color .15s,background .15s}
|
||||
.rs-nav a:hover{border-color:var(--rs-accent,#14b8a6);background:var(--rs-surface-hover,#252538)}
|
||||
.rs-nav .nav-icon{font-size:2rem;flex-shrink:0}
|
||||
.rs-nav .nav-body h3{margin:0 0 .25rem;font-size:1.1rem}
|
||||
.rs-nav .nav-body p{margin:0;font-size:.85rem;color:var(--rs-text-secondary,#aaa)}
|
||||
</style>`,
|
||||
body: `<div class="rs-hub">
|
||||
<h1>rSocials</h1>
|
||||
<p>Social media tools for your community</p>
|
||||
<nav class="rs-nav">
|
||||
<a href="${base}/campaigns">
|
||||
<span class="nav-icon">📢</span>
|
||||
<div class="nav-body">
|
||||
<h3>Campaigns</h3>
|
||||
<p>Plan and manage multi-platform social media campaigns</p>
|
||||
</div>
|
||||
</a>
|
||||
<a href="${base}/threads">
|
||||
<span class="nav-icon">📋</span>
|
||||
<div class="nav-body">
|
||||
<h3>Threads</h3>
|
||||
<p>Browse saved thread drafts and published threads</p>
|
||||
</div>
|
||||
</a>
|
||||
<a href="${base}/thread-editor">
|
||||
<span class="nav-icon">🧵</span>
|
||||
<div class="nav-body">
|
||||
<h3>Thread Editor</h3>
|
||||
<p>Compose and preview tweet threads with live card preview</p>
|
||||
</div>
|
||||
</a>
|
||||
</nav>
|
||||
</div>`,
|
||||
}));
|
||||
});
|
||||
|
||||
|
|
@ -667,19 +710,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",
|
||||
|
|
@ -697,5 +728,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." },
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
|
|
|
|||
Loading…
Reference in New Issue