feat: r-prefix module slugs, landing page, clickable rStack header
- Rename all 23 module IDs to r-prefixed slugs (canvas→rspace, notes→rnotes, etc.) - Root rspace.online/ now serves the landing page instead of redirecting to demo - rStack header in app switcher dropdown is now a clickable link to rstack.online - Update all internal navigation links, badge maps, and URL helpers - Space root redirects to /rspace instead of /canvas Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
a2e3e2cb9c
commit
4895af19db
|
|
@ -235,7 +235,7 @@ export class FolkBookReader extends HTMLElement {
|
|||
${this.getStyles()}
|
||||
<div class="reader-container">
|
||||
<div class="rapp-nav">
|
||||
<a class="rapp-nav__back" href="/${window.location.pathname.split('/')[1]}/books">\u2190 Library</a>
|
||||
<a class="rapp-nav__back" href="/${window.location.pathname.split('/')[1]}/rbooks">\u2190 Library</a>
|
||||
<span class="rapp-nav__title">${this.escapeHtml(this._title)}</span>
|
||||
${this._author ? `<span class="rapp-nav__subtitle">by ${this.escapeHtml(this._author)}</span>` : ""}
|
||||
<span class="rapp-nav__meta">
|
||||
|
|
|
|||
|
|
@ -389,7 +389,7 @@ export class FolkBookShelf extends HTMLElement {
|
|||
</div>`
|
||||
: `<div class="grid">
|
||||
${books.map((b) => `
|
||||
<a class="book-card" href="/${this._spaceSlug}/books/read/${b.slug}">
|
||||
<a class="book-card" href="/${this._spaceSlug}/rbooks/read/${b.slug}">
|
||||
<div class="book-cover" style="background:${b.cover_color}">
|
||||
<span class="book-cover-title">${this.escapeHtml(b.title)}</span>
|
||||
${b.featured ? '<span class="featured-badge">Featured</span>' : ""}
|
||||
|
|
@ -553,7 +553,7 @@ export class FolkBookShelf extends HTMLElement {
|
|||
}
|
||||
|
||||
try {
|
||||
const res = await fetch(`/${this._spaceSlug}/books/api/books`, {
|
||||
const res = await fetch(`/${this._spaceSlug}/rbooks/api/books`, {
|
||||
method: "POST",
|
||||
headers: { Authorization: `Bearer ${token}` },
|
||||
body: formData,
|
||||
|
|
@ -565,7 +565,7 @@ export class FolkBookShelf extends HTMLElement {
|
|||
}
|
||||
|
||||
// Navigate to the new book
|
||||
window.location.href = `/${this._spaceSlug}/books/read/${data.slug}`;
|
||||
window.location.href = `/${this._spaceSlug}/rbooks/read/${data.slug}`;
|
||||
} catch (e: any) {
|
||||
errorEl.textContent = e.message;
|
||||
errorEl.hidden = false;
|
||||
|
|
|
|||
|
|
@ -206,7 +206,7 @@ routes.get("/", (c) => {
|
|||
const spaceSlug = c.req.param("space") || "personal";
|
||||
return c.html(renderShell({
|
||||
title: `${spaceSlug} — Library | rSpace`,
|
||||
moduleId: "books",
|
||||
moduleId: "rbooks",
|
||||
spaceSlug,
|
||||
modules: getModuleInfoList(),
|
||||
theme: "dark",
|
||||
|
|
@ -229,9 +229,9 @@ routes.get("/read/:id", async (c) => {
|
|||
if (rows.length === 0) {
|
||||
const html = renderShell({
|
||||
title: "Book not found | rSpace",
|
||||
moduleId: "books",
|
||||
moduleId: "rbooks",
|
||||
spaceSlug,
|
||||
body: `<div style="padding:3rem;text-align:center;color:#94a3b8;"><h2>Book not found</h2><p><a href="/${spaceSlug}/books" style="color:#60a5fa;">Back to library</a></p></div>`,
|
||||
body: `<div style="padding:3rem;text-align:center;color:#94a3b8;"><h2>Book not found</h2><p><a href="/${spaceSlug}/rbooks" style="color:#60a5fa;">Back to library</a></p></div>`,
|
||||
modules: getModuleInfoList(),
|
||||
});
|
||||
return c.html(html, 404);
|
||||
|
|
@ -246,11 +246,11 @@ routes.get("/read/:id", async (c) => {
|
|||
);
|
||||
|
||||
// Build the PDF URL relative to this module's mount point
|
||||
const pdfUrl = `/${spaceSlug}/books/api/books/${book.slug}/pdf`;
|
||||
const pdfUrl = `/${spaceSlug}/rbooks/api/books/${book.slug}/pdf`;
|
||||
|
||||
const html = renderShell({
|
||||
title: `${book.title} | rSpace`,
|
||||
moduleId: "books",
|
||||
moduleId: "rbooks",
|
||||
spaceSlug,
|
||||
body: `
|
||||
<folk-book-reader
|
||||
|
|
@ -295,7 +295,7 @@ function escapeAttr(s: string): string {
|
|||
// ── Module export ──
|
||||
|
||||
export const booksModule: RSpaceModule = {
|
||||
id: "books",
|
||||
id: "rbooks",
|
||||
name: "rBooks",
|
||||
icon: "📚",
|
||||
description: "Community PDF library with flipbook reader",
|
||||
|
|
|
|||
|
|
@ -377,7 +377,7 @@ routes.get("/", (c) => {
|
|||
const space = c.req.param("space") || "demo";
|
||||
return c.html(renderShell({
|
||||
title: `${space} — Calendar | rSpace`,
|
||||
moduleId: "cal",
|
||||
moduleId: "rcal",
|
||||
spaceSlug: space,
|
||||
modules: getModuleInfoList(),
|
||||
theme: "dark",
|
||||
|
|
@ -388,7 +388,7 @@ routes.get("/", (c) => {
|
|||
});
|
||||
|
||||
export const calModule: RSpaceModule = {
|
||||
id: "cal",
|
||||
id: "rcal",
|
||||
name: "rCal",
|
||||
icon: "\u{1F4C5}",
|
||||
description: "Temporal coordination calendar with lunar, solar, and seasonal systems",
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ routes.get("/", async (c) => {
|
|||
|
||||
const html = renderShell({
|
||||
title: `${spaceSlug} — Canvas | rSpace`,
|
||||
moduleId: "canvas",
|
||||
moduleId: "rspace",
|
||||
spaceSlug,
|
||||
body: canvasBody,
|
||||
modules: getModuleInfoList(),
|
||||
|
|
@ -50,7 +50,7 @@ routes.get("/", async (c) => {
|
|||
});
|
||||
|
||||
export const canvasModule: RSpaceModule = {
|
||||
id: "canvas",
|
||||
id: "rspace",
|
||||
name: "rSpace",
|
||||
icon: "🎨",
|
||||
description: "Real-time collaborative canvas",
|
||||
|
|
|
|||
|
|
@ -443,7 +443,7 @@ routes.get("/", (c) => {
|
|||
const space = c.req.param("space") || "demo";
|
||||
return c.html(renderShell({
|
||||
title: `Shop | rSpace`,
|
||||
moduleId: "cart",
|
||||
moduleId: "rcart",
|
||||
spaceSlug: space,
|
||||
modules: getModuleInfoList(),
|
||||
theme: "dark",
|
||||
|
|
@ -454,7 +454,7 @@ routes.get("/", (c) => {
|
|||
});
|
||||
|
||||
export const cartModule: RSpaceModule = {
|
||||
id: "cart",
|
||||
id: "rcart",
|
||||
name: "rCart",
|
||||
icon: "\u{1F6D2}",
|
||||
description: "Cosmolocal print-on-demand shop",
|
||||
|
|
|
|||
|
|
@ -78,7 +78,7 @@ class FolkChoicesDashboard extends HTMLElement {
|
|||
<div class="rapp-nav">
|
||||
<span class="rapp-nav__title">Choices</span>
|
||||
<div class="create-btns">
|
||||
<a class="create-btn" href="/${this.space}/canvas" title="Open canvas to create choices">\u2795 New on Canvas</a>
|
||||
<a class="create-btn" href="/${this.space}/rspace" title="Open canvas to create choices">\u2795 New on Canvas</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
@ -96,14 +96,14 @@ class FolkChoicesDashboard extends HTMLElement {
|
|||
return `<div class="empty">
|
||||
<div class="empty-icon">\u2611</div>
|
||||
<p>No choices in this space yet.</p>
|
||||
<p>Open the <a href="/${this.space}/canvas" style="color:#818cf8">canvas</a> and use the Poll, Rank, or Spider buttons to create one.</p>
|
||||
<p>Open the <a href="/${this.space}/rspace" style="color:#818cf8">canvas</a> and use the Poll, Rank, or Spider buttons to create one.</p>
|
||||
</div>`;
|
||||
}
|
||||
|
||||
private renderGrid(icons: Record<string, string>, labels: Record<string, string>): string {
|
||||
return `<div class="grid">
|
||||
${this.choices.map((ch) => `
|
||||
<a class="card" href="/${this.space}/canvas">
|
||||
<a class="card" href="/${this.space}/rspace">
|
||||
<div class="card-icon">${icons[ch.type] || "\u2611"}</div>
|
||||
<div class="card-type">${labels[ch.type] || ch.type}</div>
|
||||
<h3 class="card-title">${this.esc(ch.title)}</h3>
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ routes.get("/", (c) => {
|
|||
const spaceSlug = c.req.param("space") || "demo";
|
||||
return c.html(renderShell({
|
||||
title: `${spaceSlug} — Choices | rSpace`,
|
||||
moduleId: "choices",
|
||||
moduleId: "rchoices",
|
||||
spaceSlug,
|
||||
modules: getModuleInfoList(),
|
||||
theme: "dark",
|
||||
|
|
@ -61,7 +61,7 @@ routes.get("/", (c) => {
|
|||
});
|
||||
|
||||
export const choicesModule: RSpaceModule = {
|
||||
id: "choices",
|
||||
id: "rchoices",
|
||||
name: "rChoices",
|
||||
icon: "☑",
|
||||
description: "Polls, rankings, and multi-criteria scoring",
|
||||
|
|
|
|||
|
|
@ -122,7 +122,7 @@ routes.get("/", (c) => {
|
|||
const space = c.req.param("space") || "demo";
|
||||
return c.html(renderShell({
|
||||
title: `${space} — Data | rSpace`,
|
||||
moduleId: "data",
|
||||
moduleId: "rdata",
|
||||
spaceSlug: space,
|
||||
modules: getModuleInfoList(),
|
||||
theme: "dark",
|
||||
|
|
@ -133,7 +133,7 @@ routes.get("/", (c) => {
|
|||
});
|
||||
|
||||
export const dataModule: RSpaceModule = {
|
||||
id: "data",
|
||||
id: "rdata",
|
||||
name: "rData",
|
||||
icon: "\u{1F4CA}",
|
||||
description: "Privacy-first analytics for the r* ecosystem",
|
||||
|
|
|
|||
|
|
@ -368,7 +368,7 @@ routes.get("/", (c) => {
|
|||
const spaceSlug = c.req.param("space") || "demo";
|
||||
return c.html(renderShell({
|
||||
title: `${spaceSlug} — Files | rSpace`,
|
||||
moduleId: "files",
|
||||
moduleId: "rfiles",
|
||||
spaceSlug,
|
||||
modules: getModuleInfoList(),
|
||||
theme: "dark",
|
||||
|
|
@ -379,7 +379,7 @@ routes.get("/", (c) => {
|
|||
});
|
||||
|
||||
export const filesModule: RSpaceModule = {
|
||||
id: "files",
|
||||
id: "rfiles",
|
||||
name: "rFiles",
|
||||
icon: "\uD83D\uDCC1",
|
||||
description: "File sharing, share links, and memory cards",
|
||||
|
|
|
|||
|
|
@ -159,7 +159,7 @@ routes.get("/", (c) => {
|
|||
const spaceSlug = c.req.param("space") || "demo";
|
||||
return c.html(renderShell({
|
||||
title: `${spaceSlug} — Forum | rSpace`,
|
||||
moduleId: "forum",
|
||||
moduleId: "rforum",
|
||||
spaceSlug,
|
||||
modules: getModuleInfoList(),
|
||||
theme: "dark",
|
||||
|
|
@ -170,7 +170,7 @@ routes.get("/", (c) => {
|
|||
});
|
||||
|
||||
export const forumModule: RSpaceModule = {
|
||||
id: "forum",
|
||||
id: "rforum",
|
||||
name: "rForum",
|
||||
icon: "\uD83D\uDCAC",
|
||||
description: "Deploy and manage Discourse forums",
|
||||
|
|
|
|||
|
|
@ -198,7 +198,7 @@ routes.get("/", (c) => {
|
|||
const spaceSlug = c.req.param("space") || "demo";
|
||||
return c.html(renderShell({
|
||||
title: `rFunds — TBFF Flow Funding | rSpace`,
|
||||
moduleId: "funds",
|
||||
moduleId: "rfunds",
|
||||
spaceSlug,
|
||||
modules: getModuleInfoList(),
|
||||
theme: "dark",
|
||||
|
|
@ -213,7 +213,7 @@ routes.get("/demo", (c) => {
|
|||
const spaceSlug = c.req.param("space") || "demo";
|
||||
return c.html(renderShell({
|
||||
title: `TBFF Demo — rFunds | rSpace`,
|
||||
moduleId: "funds",
|
||||
moduleId: "rfunds",
|
||||
spaceSlug,
|
||||
modules: getModuleInfoList(),
|
||||
theme: "dark",
|
||||
|
|
@ -229,7 +229,7 @@ routes.get("/flow/:flowId", (c) => {
|
|||
const flowId = c.req.param("flowId");
|
||||
return c.html(renderShell({
|
||||
title: `Flow — rFunds | rSpace`,
|
||||
moduleId: "funds",
|
||||
moduleId: "rfunds",
|
||||
spaceSlug,
|
||||
modules: getModuleInfoList(),
|
||||
theme: "dark",
|
||||
|
|
@ -240,7 +240,7 @@ routes.get("/flow/:flowId", (c) => {
|
|||
});
|
||||
|
||||
export const fundsModule: RSpaceModule = {
|
||||
id: "funds",
|
||||
id: "rfunds",
|
||||
name: "rFunds",
|
||||
icon: "\uD83C\uDF0A",
|
||||
description: "Budget flows, river visualization, and treasury management",
|
||||
|
|
|
|||
|
|
@ -532,7 +532,7 @@ routes.get("/", (c) => {
|
|||
const space = c.req.param("space") || "demo";
|
||||
return c.html(renderShell({
|
||||
title: `${space} — Inbox | rSpace`,
|
||||
moduleId: "inbox",
|
||||
moduleId: "rinbox",
|
||||
spaceSlug: space,
|
||||
modules: getModuleInfoList(),
|
||||
theme: "dark",
|
||||
|
|
@ -543,7 +543,7 @@ routes.get("/", (c) => {
|
|||
});
|
||||
|
||||
export const inboxModule: RSpaceModule = {
|
||||
id: "inbox",
|
||||
id: "rinbox",
|
||||
name: "rInbox",
|
||||
icon: "\u{1F4E8}",
|
||||
description: "Collaborative email with multisig approval",
|
||||
|
|
|
|||
|
|
@ -135,7 +135,7 @@ routes.get("/", (c) => {
|
|||
const space = c.req.param("space") || "demo";
|
||||
return c.html(renderShell({
|
||||
title: `${space} — Maps | rSpace`,
|
||||
moduleId: "maps",
|
||||
moduleId: "rmaps",
|
||||
spaceSlug: space,
|
||||
modules: getModuleInfoList(),
|
||||
theme: "dark",
|
||||
|
|
@ -151,7 +151,7 @@ routes.get("/:room", (c) => {
|
|||
const room = c.req.param("room");
|
||||
return c.html(renderShell({
|
||||
title: `${room} — Maps | rSpace`,
|
||||
moduleId: "maps",
|
||||
moduleId: "rmaps",
|
||||
spaceSlug: space,
|
||||
modules: getModuleInfoList(),
|
||||
theme: "dark",
|
||||
|
|
@ -162,7 +162,7 @@ routes.get("/:room", (c) => {
|
|||
});
|
||||
|
||||
export const mapsModule: RSpaceModule = {
|
||||
id: "maps",
|
||||
id: "rmaps",
|
||||
name: "rMaps",
|
||||
icon: "\u{1F5FA}",
|
||||
description: "Real-time collaborative location sharing and indoor/outdoor maps",
|
||||
|
|
|
|||
|
|
@ -218,7 +218,7 @@ routes.get("/", (c) => {
|
|||
const space = c.req.param("space") || "demo";
|
||||
return c.html(renderShell({
|
||||
title: `${space} — Network | rSpace`,
|
||||
moduleId: "network",
|
||||
moduleId: "rnetwork",
|
||||
spaceSlug: space,
|
||||
modules: getModuleInfoList(),
|
||||
theme: "dark",
|
||||
|
|
@ -229,7 +229,7 @@ routes.get("/", (c) => {
|
|||
});
|
||||
|
||||
export const networkModule: RSpaceModule = {
|
||||
id: "network",
|
||||
id: "rnetwork",
|
||||
name: "rNetwork",
|
||||
icon: "\u{1F310}",
|
||||
description: "Community relationship graph visualization with CRM sync",
|
||||
|
|
|
|||
|
|
@ -363,7 +363,7 @@ routes.get("/", (c) => {
|
|||
const space = c.req.param("space") || "demo";
|
||||
return c.html(renderShell({
|
||||
title: `${space} — Notes | rSpace`,
|
||||
moduleId: "notes",
|
||||
moduleId: "rnotes",
|
||||
spaceSlug: space,
|
||||
modules: getModuleInfoList(),
|
||||
theme: "dark",
|
||||
|
|
@ -374,7 +374,7 @@ routes.get("/", (c) => {
|
|||
});
|
||||
|
||||
export const notesModule: RSpaceModule = {
|
||||
id: "notes",
|
||||
id: "rnotes",
|
||||
name: "rNotes",
|
||||
icon: "\u{1F4DD}",
|
||||
description: "Notebooks with rich-text notes, voice transcription, and collaboration",
|
||||
|
|
|
|||
|
|
@ -110,7 +110,7 @@ routes.get("/", (c) => {
|
|||
const spaceSlug = c.req.param("space") || "demo";
|
||||
return c.html(renderShell({
|
||||
title: `${spaceSlug} — Photos | rSpace`,
|
||||
moduleId: "photos",
|
||||
moduleId: "rphotos",
|
||||
spaceSlug,
|
||||
modules: getModuleInfoList(),
|
||||
theme: "dark",
|
||||
|
|
@ -121,7 +121,7 @@ routes.get("/", (c) => {
|
|||
});
|
||||
|
||||
export const photosModule: RSpaceModule = {
|
||||
id: "photos",
|
||||
id: "rphotos",
|
||||
name: "rPhotos",
|
||||
icon: "📸",
|
||||
description: "Community photo commons",
|
||||
|
|
@ -129,7 +129,7 @@ export const photosModule: RSpaceModule = {
|
|||
standaloneDomain: "rphotos.online",
|
||||
feeds: [
|
||||
{
|
||||
id: "photos",
|
||||
id: "rphotos",
|
||||
name: "Recent Photos",
|
||||
kind: "data",
|
||||
description: "Stream of recently uploaded photos",
|
||||
|
|
|
|||
|
|
@ -350,7 +350,7 @@ routes.get("/", (c) => {
|
|||
const space = c.req.param("space") || "demo";
|
||||
return c.html(renderShell({
|
||||
title: `Providers | rSpace`,
|
||||
moduleId: "providers",
|
||||
moduleId: "rproviders",
|
||||
spaceSlug: space,
|
||||
modules: getModuleInfoList(),
|
||||
theme: "dark",
|
||||
|
|
@ -361,7 +361,7 @@ routes.get("/", (c) => {
|
|||
});
|
||||
|
||||
export const providersModule: RSpaceModule = {
|
||||
id: "providers",
|
||||
id: "rproviders",
|
||||
name: "rProviders",
|
||||
icon: "\u{1F3ED}",
|
||||
description: "Local provider directory for cosmolocal production",
|
||||
|
|
|
|||
|
|
@ -323,7 +323,7 @@ routes.get("/", (c) => {
|
|||
const spaceSlug = c.req.param("space") || "personal";
|
||||
return c.html(renderShell({
|
||||
title: `${spaceSlug} — rPubs Editor | rSpace`,
|
||||
moduleId: "pubs",
|
||||
moduleId: "rpubs",
|
||||
spaceSlug,
|
||||
modules: getModuleInfoList(),
|
||||
theme: "dark",
|
||||
|
|
@ -336,7 +336,7 @@ routes.get("/", (c) => {
|
|||
// ── Module export ──
|
||||
|
||||
export const pubsModule: RSpaceModule = {
|
||||
id: "pubs",
|
||||
id: "rpubs",
|
||||
name: "rPubs",
|
||||
icon: "📖",
|
||||
description: "Drop in a document, get a pocket book",
|
||||
|
|
|
|||
|
|
@ -80,7 +80,7 @@ export class FolkSplatViewer extends HTMLElement {
|
|||
const status = s.processing_status || "ready";
|
||||
const isReady = status === "ready";
|
||||
const tag = isReady ? "a" : "div";
|
||||
const href = isReady ? ` href="/${this._spaceSlug}/splat/view/${s.slug}"` : "";
|
||||
const href = isReady ? ` href="/${this._spaceSlug}/rsplat/view/${s.slug}"` : "";
|
||||
const statusClass = !isReady ? ` splat-card--${status}` : "";
|
||||
|
||||
let overlay = "";
|
||||
|
|
@ -259,7 +259,7 @@ export class FolkSplatViewer extends HTMLElement {
|
|||
|
||||
try {
|
||||
const token = localStorage.getItem("encryptid_token") || "";
|
||||
const res = await fetch(`/${this._spaceSlug}/splat/api/splats`, {
|
||||
const res = await fetch(`/${this._spaceSlug}/rsplat/api/splats`, {
|
||||
method: "POST",
|
||||
headers: token ? { Authorization: `Bearer ${token}` } : {},
|
||||
body: formData,
|
||||
|
|
@ -287,7 +287,7 @@ export class FolkSplatViewer extends HTMLElement {
|
|||
const splat = await res.json() as SplatItem;
|
||||
status.textContent = "Uploaded!";
|
||||
setTimeout(() => {
|
||||
window.location.href = `/${this._spaceSlug}/splat/view/${splat.slug}`;
|
||||
window.location.href = `/${this._spaceSlug}/rsplat/view/${splat.slug}`;
|
||||
}, 500);
|
||||
} catch (e) {
|
||||
status.textContent = "Network error";
|
||||
|
|
@ -347,7 +347,7 @@ export class FolkSplatViewer extends HTMLElement {
|
|||
|
||||
try {
|
||||
const token = localStorage.getItem("encryptid_token") || "";
|
||||
const res = await fetch(`/${this._spaceSlug}/splat/api/splats/from-media`, {
|
||||
const res = await fetch(`/${this._spaceSlug}/rsplat/api/splats/from-media`, {
|
||||
method: "POST",
|
||||
headers: token ? { Authorization: `Bearer ${token}` } : {},
|
||||
body: formData,
|
||||
|
|
@ -374,7 +374,7 @@ export class FolkSplatViewer extends HTMLElement {
|
|||
|
||||
status.textContent = "Uploaded! Queued for processing.";
|
||||
setTimeout(() => {
|
||||
window.location.href = `/${this._spaceSlug}/splat`;
|
||||
window.location.href = `/${this._spaceSlug}/rsplat`;
|
||||
}, 1000);
|
||||
} catch (e) {
|
||||
status.textContent = "Network error";
|
||||
|
|
@ -393,7 +393,7 @@ export class FolkSplatViewer extends HTMLElement {
|
|||
<div class="splat-loading__text">Loading splat...</div>
|
||||
</div>
|
||||
<div class="splat-viewer__controls">
|
||||
<a class="splat-viewer__back" href="/${this._spaceSlug}/splat">← Gallery</a>
|
||||
<a class="splat-viewer__back" href="/${this._spaceSlug}/rsplat">← Gallery</a>
|
||||
</div>
|
||||
${this._splatTitle ? `
|
||||
<div class="splat-viewer__info">
|
||||
|
|
|
|||
|
|
@ -429,7 +429,7 @@ routes.get("/", async (c) => {
|
|||
|
||||
const html = renderShell({
|
||||
title: `${spaceSlug} — rSplat | rSpace`,
|
||||
moduleId: "splat",
|
||||
moduleId: "rsplat",
|
||||
spaceSlug,
|
||||
body: `<folk-splat-viewer id="gallery" mode="gallery"></folk-splat-viewer>`,
|
||||
modules: getModuleInfoList(),
|
||||
|
|
@ -464,9 +464,9 @@ routes.get("/view/:id", async (c) => {
|
|||
if (rows.length === 0) {
|
||||
const html = renderShell({
|
||||
title: "Splat not found | rSpace",
|
||||
moduleId: "splat",
|
||||
moduleId: "rsplat",
|
||||
spaceSlug,
|
||||
body: `<div style="padding:3rem;text-align:center;color:#94a3b8;"><h2>Splat not found</h2><p><a href="/${spaceSlug}/splat" style="color:#818cf8;">Back to gallery</a></p></div>`,
|
||||
body: `<div style="padding:3rem;text-align:center;color:#94a3b8;"><h2>Splat not found</h2><p><a href="/${spaceSlug}/rsplat" style="color:#818cf8;">Back to gallery</a></p></div>`,
|
||||
modules: getModuleInfoList(),
|
||||
theme: "dark",
|
||||
});
|
||||
|
|
@ -481,11 +481,11 @@ routes.get("/view/:id", async (c) => {
|
|||
[splat.id]
|
||||
);
|
||||
|
||||
const fileUrl = `/${spaceSlug}/splat/api/splats/${splat.slug}/${splat.slug}.${splat.file_format}`;
|
||||
const fileUrl = `/${spaceSlug}/rsplat/api/splats/${splat.slug}/${splat.slug}.${splat.file_format}`;
|
||||
|
||||
const html = renderShell({
|
||||
title: `${splat.title} | rSplat`,
|
||||
moduleId: "splat",
|
||||
moduleId: "rsplat",
|
||||
spaceSlug,
|
||||
body: `
|
||||
<folk-splat-viewer
|
||||
|
|
@ -534,7 +534,7 @@ async function initDB(): Promise<void> {
|
|||
// ── Module export ──
|
||||
|
||||
export const splatModule: RSpaceModule = {
|
||||
id: "splat",
|
||||
id: "rsplat",
|
||||
name: "rSplat",
|
||||
icon: "🔮",
|
||||
description: "3D Gaussian splat viewer",
|
||||
|
|
|
|||
|
|
@ -230,7 +230,7 @@ routes.get("/", (c) => {
|
|||
const space = c.req.param("space") || "demo";
|
||||
return c.html(renderShell({
|
||||
title: `Swag Designer | rSpace`,
|
||||
moduleId: "swag",
|
||||
moduleId: "rswag",
|
||||
spaceSlug: space,
|
||||
modules: getModuleInfoList(),
|
||||
theme: "dark",
|
||||
|
|
@ -241,7 +241,7 @@ routes.get("/", (c) => {
|
|||
});
|
||||
|
||||
export const swagModule: RSpaceModule = {
|
||||
id: "swag",
|
||||
id: "rswag",
|
||||
name: "rSwag",
|
||||
icon: "\u{1F3A8}",
|
||||
description: "Design print-ready swag: stickers, posters, tees",
|
||||
|
|
|
|||
|
|
@ -240,7 +240,7 @@ routes.get("/routes", (c) => {
|
|||
const space = c.req.param("space") || "demo";
|
||||
return c.html(renderShell({
|
||||
title: `${space} — Route Planner | rTrips`,
|
||||
moduleId: "trips",
|
||||
moduleId: "rtrips",
|
||||
spaceSlug: space,
|
||||
modules: getModuleInfoList(),
|
||||
theme: "dark",
|
||||
|
|
@ -255,7 +255,7 @@ routes.get("/", (c) => {
|
|||
const space = c.req.param("space") || "demo";
|
||||
return c.html(renderShell({
|
||||
title: `${space} — Trips | rSpace`,
|
||||
moduleId: "trips",
|
||||
moduleId: "rtrips",
|
||||
spaceSlug: space,
|
||||
modules: getModuleInfoList(),
|
||||
theme: "dark",
|
||||
|
|
@ -266,7 +266,7 @@ routes.get("/", (c) => {
|
|||
});
|
||||
|
||||
export const tripsModule: RSpaceModule = {
|
||||
id: "trips",
|
||||
id: "rtrips",
|
||||
name: "rTrips",
|
||||
icon: "\u{2708}\u{FE0F}",
|
||||
description: "Collaborative trip planner with itinerary, bookings, and expense splitting",
|
||||
|
|
|
|||
|
|
@ -193,7 +193,7 @@ routes.get("/", (c) => {
|
|||
const space = c.req.param("space") || "demo";
|
||||
return c.html(renderShell({
|
||||
title: `${space} — Tube | rSpace`,
|
||||
moduleId: "tube",
|
||||
moduleId: "rtube",
|
||||
spaceSlug: space,
|
||||
modules: getModuleInfoList(),
|
||||
theme: "dark",
|
||||
|
|
@ -204,7 +204,7 @@ routes.get("/", (c) => {
|
|||
});
|
||||
|
||||
export const tubeModule: RSpaceModule = {
|
||||
id: "tube",
|
||||
id: "rtube",
|
||||
name: "rTube",
|
||||
icon: "\u{1F3AC}",
|
||||
description: "Community video hosting & live streaming",
|
||||
|
|
|
|||
|
|
@ -329,7 +329,7 @@ routes.get("/", (c) => {
|
|||
const space = c.req.param("space") || "demo";
|
||||
return c.html(renderShell({
|
||||
title: `${space} — Vote | rSpace`,
|
||||
moduleId: "vote",
|
||||
moduleId: "rvote",
|
||||
spaceSlug: space,
|
||||
modules: getModuleInfoList(),
|
||||
theme: "dark",
|
||||
|
|
@ -340,7 +340,7 @@ routes.get("/", (c) => {
|
|||
});
|
||||
|
||||
export const voteModule: RSpaceModule = {
|
||||
id: "vote",
|
||||
id: "rvote",
|
||||
name: "rVote",
|
||||
icon: "\u{1F5F3}",
|
||||
description: "Conviction voting engine for collaborative governance",
|
||||
|
|
|
|||
|
|
@ -96,7 +96,7 @@ routes.get("/", (c) => {
|
|||
const spaceSlug = c.req.param("space") || "demo";
|
||||
return c.html(renderShell({
|
||||
title: `${spaceSlug} — Wallet | rSpace`,
|
||||
moduleId: "wallet",
|
||||
moduleId: "rwallet",
|
||||
spaceSlug,
|
||||
modules: getModuleInfoList(),
|
||||
theme: "dark",
|
||||
|
|
@ -107,7 +107,7 @@ routes.get("/", (c) => {
|
|||
});
|
||||
|
||||
export const walletModule: RSpaceModule = {
|
||||
id: "wallet",
|
||||
id: "rwallet",
|
||||
name: "rWallet",
|
||||
icon: "\uD83D\uDCB0",
|
||||
description: "Multichain Safe wallet visualization and treasury management",
|
||||
|
|
|
|||
|
|
@ -219,7 +219,7 @@ routes.get("/", (c) => {
|
|||
const space = c.req.param("space") || "demo";
|
||||
return c.html(renderShell({
|
||||
title: `${space} — Work | rSpace`,
|
||||
moduleId: "work",
|
||||
moduleId: "rwork",
|
||||
spaceSlug: space,
|
||||
modules: getModuleInfoList(),
|
||||
theme: "dark",
|
||||
|
|
@ -230,7 +230,7 @@ routes.get("/", (c) => {
|
|||
});
|
||||
|
||||
export const workModule: RSpaceModule = {
|
||||
id: "work",
|
||||
id: "rwork",
|
||||
name: "rWork",
|
||||
icon: "\u{1F4CB}",
|
||||
description: "Kanban workspace boards for collaborative task management",
|
||||
|
|
|
|||
|
|
@ -209,7 +209,7 @@ function generateFallbackResponse(
|
|||
}
|
||||
|
||||
if (q.includes("help") || q.includes("what can")) {
|
||||
return `rSpace has ${modules.length} apps you can use. Some popular ones: **rSpace** (canvas), **rNotes** (notes), **rChat** (messaging), **rFunds** (community funding), and **rVote** (governance). What would you like to explore?`;
|
||||
return `rSpace has ${modules.length} apps you can use. Some popular ones: **rSpace** (spatial canvas), **rNotes** (notes), **rChat** (messaging), **rFunds** (community funding), and **rVote** (governance). What would you like to explore?`;
|
||||
}
|
||||
|
||||
if (q.includes("search") || q.includes("find")) {
|
||||
|
|
@ -474,8 +474,14 @@ for (const mod of getAllModules()) {
|
|||
|
||||
// ── Page routes ──
|
||||
|
||||
// Landing page: rspace.online/ → redirect to demo canvas (overlay shows there)
|
||||
app.get("/", (c) => c.redirect("/demo/canvas", 302));
|
||||
// Landing page: rspace.online/ → serve marketing/info page
|
||||
app.get("/", async (c) => {
|
||||
const file = Bun.file(resolve(DIST_DIR, "index.html"));
|
||||
if (await file.exists()) {
|
||||
return new Response(file, { headers: { "Content-Type": "text/html" } });
|
||||
}
|
||||
return c.text("rSpace", 200);
|
||||
});
|
||||
|
||||
// About/info page (full landing content)
|
||||
app.get("/about", async (c) => {
|
||||
|
|
@ -507,12 +513,12 @@ app.get("/admin", async (c) => {
|
|||
return c.text("Admin", 200);
|
||||
});
|
||||
|
||||
// Space root: /:space → redirect to /:space/canvas
|
||||
// Space root: /:space → redirect to /:space/rspace
|
||||
app.get("/:space", (c) => {
|
||||
const space = c.req.param("space");
|
||||
// Don't redirect for static file paths
|
||||
if (space.includes(".")) return c.notFound();
|
||||
return c.redirect(`/${space}/canvas`);
|
||||
return c.redirect(`/${space}/rspace`);
|
||||
});
|
||||
|
||||
// ── WebSocket types ──
|
||||
|
|
@ -743,9 +749,9 @@ const server = Bun.serve<WSData>({
|
|||
if (subdomain) {
|
||||
const pathSegments = url.pathname.split("/").filter(Boolean);
|
||||
|
||||
// Root: redirect to default module (canvas)
|
||||
// Root: redirect to default module (rspace)
|
||||
if (pathSegments.length === 0) {
|
||||
return Response.redirect(`${url.protocol}//${host}/canvas`, 302);
|
||||
return Response.redirect(`${url.protocol}//${host}/rspace`, 302);
|
||||
}
|
||||
|
||||
// Global routes pass through without subdomain prefix
|
||||
|
|
|
|||
|
|
@ -19,76 +19,76 @@ export interface AppSwitcherModule {
|
|||
// Pastel badge abbreviations & colors for each module
|
||||
const MODULE_BADGES: Record<string, { badge: string; color: string }> = {
|
||||
// Creating
|
||||
canvas: { badge: "rS", color: "#5eead4" }, // teal-300
|
||||
notes: { badge: "rN", color: "#fcd34d" }, // amber-300
|
||||
pubs: { badge: "rP", color: "#fda4af" }, // rose-300
|
||||
swag: { badge: "rSw", color: "#fda4af" }, // rose-300
|
||||
splat: { badge: "r3", color: "#d8b4fe" }, // purple-300
|
||||
rspace: { badge: "rS", color: "#5eead4" }, // teal-300
|
||||
rnotes: { badge: "rN", color: "#fcd34d" }, // amber-300
|
||||
rpubs: { badge: "rP", color: "#fda4af" }, // rose-300
|
||||
rswag: { badge: "rSw", color: "#fda4af" }, // rose-300
|
||||
rsplat: { badge: "r3", color: "#d8b4fe" }, // purple-300
|
||||
// Planning
|
||||
cal: { badge: "rC", color: "#7dd3fc" }, // sky-300
|
||||
trips: { badge: "rT", color: "#6ee7b7" }, // emerald-300
|
||||
maps: { badge: "rM", color: "#86efac" }, // green-300
|
||||
rcal: { badge: "rC", color: "#7dd3fc" }, // sky-300
|
||||
rtrips: { badge: "rT", color: "#6ee7b7" }, // emerald-300
|
||||
rmaps: { badge: "rM", color: "#86efac" }, // green-300
|
||||
// Communicating
|
||||
chats: { badge: "rCh", color: "#6ee7b7" }, // emerald-200
|
||||
inbox: { badge: "rI", color: "#a5b4fc" }, // indigo-300
|
||||
mail: { badge: "rMa", color: "#93c5fd" }, // blue-200
|
||||
forum: { badge: "rFo", color: "#fcd34d" }, // amber-200
|
||||
rchats: { badge: "rCh", color: "#6ee7b7" }, // emerald-200
|
||||
rinbox: { badge: "rI", color: "#a5b4fc" }, // indigo-300
|
||||
rmail: { badge: "rMa", color: "#93c5fd" }, // blue-200
|
||||
rforum: { badge: "rFo", color: "#fcd34d" }, // amber-200
|
||||
// Deciding
|
||||
choices: { badge: "rCo", color: "#f0abfc" }, // fuchsia-300
|
||||
vote: { badge: "rV", color: "#c4b5fd" }, // violet-300
|
||||
rchoices: { badge: "rCo", color: "#f0abfc" }, // fuchsia-300
|
||||
rvote: { badge: "rV", color: "#c4b5fd" }, // violet-300
|
||||
// Funding & Commerce
|
||||
funds: { badge: "rF", color: "#bef264" }, // lime-300
|
||||
wallet: { badge: "rW", color: "#fde047" }, // yellow-300
|
||||
cart: { badge: "rCt", color: "#fdba74" }, // orange-300
|
||||
auctions: { badge: "rA", color: "#fca5a5" }, // red-300
|
||||
providers: { badge: "rPr", color: "#fdba74" }, // orange-300
|
||||
tube: { badge: "rTu", color: "#f9a8d4" }, // pink-300
|
||||
rfunds: { badge: "rF", color: "#bef264" }, // lime-300
|
||||
rwallet: { badge: "rW", color: "#fde047" }, // yellow-300
|
||||
rcart: { badge: "rCt", color: "#fdba74" }, // orange-300
|
||||
rauctions: { badge: "rA", color: "#fca5a5" }, // red-300
|
||||
rproviders: { badge: "rPr", color: "#fdba74" }, // orange-300
|
||||
rtube: { badge: "rTu", color: "#f9a8d4" }, // pink-300
|
||||
// Sharing
|
||||
photos: { badge: "rPh", color: "#f9a8d4" }, // pink-200
|
||||
network: { badge: "rNe", color: "#93c5fd" }, // blue-300
|
||||
socials: { badge: "rSo", color: "#7dd3fc" }, // sky-200
|
||||
files: { badge: "rFi", color: "#67e8f9" }, // cyan-300
|
||||
books: { badge: "rB", color: "#fda4af" }, // rose-300
|
||||
rphotos: { badge: "rPh", color: "#f9a8d4" }, // pink-200
|
||||
rnetwork: { badge: "rNe", color: "#93c5fd" }, // blue-300
|
||||
rsocials: { badge: "rSo", color: "#7dd3fc" }, // sky-200
|
||||
rfiles: { badge: "rFi", color: "#67e8f9" }, // cyan-300
|
||||
rbooks: { badge: "rB", color: "#fda4af" }, // rose-300
|
||||
// Observing
|
||||
data: { badge: "rD", color: "#d8b4fe" }, // purple-300
|
||||
rdata: { badge: "rD", color: "#d8b4fe" }, // purple-300
|
||||
// Work & Productivity
|
||||
work: { badge: "rWo", color: "#cbd5e1" }, // slate-300
|
||||
rwork: { badge: "rWo", color: "#cbd5e1" }, // slate-300
|
||||
// Identity & Infrastructure
|
||||
ids: { badge: "rId", color: "#6ee7b7" }, // emerald-300
|
||||
stack: { badge: "r*", color: "" }, // gradient (handled separately)
|
||||
rids: { badge: "rId", color: "#6ee7b7" }, // emerald-300
|
||||
rstack: { badge: "r*", color: "" }, // gradient (handled separately)
|
||||
};
|
||||
|
||||
// Category definitions for the rApp dropdown (display-only grouping)
|
||||
const MODULE_CATEGORIES: Record<string, string> = {
|
||||
canvas: "Creating",
|
||||
notes: "Creating",
|
||||
pubs: "Creating",
|
||||
tube: "Creating",
|
||||
swag: "Creating",
|
||||
splat: "Creating",
|
||||
cal: "Planning",
|
||||
trips: "Planning",
|
||||
maps: "Planning",
|
||||
chats: "Communicating",
|
||||
inbox: "Communicating",
|
||||
mail: "Communicating",
|
||||
forum: "Communicating",
|
||||
choices: "Deciding",
|
||||
vote: "Deciding",
|
||||
funds: "Funding & Commerce",
|
||||
wallet: "Funding & Commerce",
|
||||
cart: "Funding & Commerce",
|
||||
auctions: "Funding & Commerce",
|
||||
providers: "Funding & Commerce",
|
||||
photos: "Sharing",
|
||||
network: "Sharing",
|
||||
socials: "Sharing",
|
||||
files: "Sharing",
|
||||
books: "Sharing",
|
||||
data: "Observing",
|
||||
work: "Work & Productivity",
|
||||
ids: "Identity & Infrastructure",
|
||||
stack: "Identity & Infrastructure",
|
||||
rspace: "Creating",
|
||||
rnotes: "Creating",
|
||||
rpubs: "Creating",
|
||||
rtube: "Creating",
|
||||
rswag: "Creating",
|
||||
rsplat: "Creating",
|
||||
rcal: "Planning",
|
||||
rtrips: "Planning",
|
||||
rmaps: "Planning",
|
||||
rchats: "Communicating",
|
||||
rinbox: "Communicating",
|
||||
rmail: "Communicating",
|
||||
rforum: "Communicating",
|
||||
rchoices: "Deciding",
|
||||
rvote: "Deciding",
|
||||
rfunds: "Funding & Commerce",
|
||||
rwallet: "Funding & Commerce",
|
||||
rcart: "Funding & Commerce",
|
||||
rauctions: "Funding & Commerce",
|
||||
rproviders: "Funding & Commerce",
|
||||
rphotos: "Sharing",
|
||||
rnetwork: "Sharing",
|
||||
rsocials: "Sharing",
|
||||
rfiles: "Sharing",
|
||||
rbooks: "Sharing",
|
||||
rdata: "Observing",
|
||||
rwork: "Work & Productivity",
|
||||
rids: "Identity & Infrastructure",
|
||||
rstack: "Identity & Infrastructure",
|
||||
};
|
||||
|
||||
const CATEGORY_ORDER = [
|
||||
|
|
@ -150,15 +150,15 @@ export class RStackAppSwitcher extends HTMLElement {
|
|||
}
|
||||
}
|
||||
|
||||
// rStack header
|
||||
// rStack header (clickable)
|
||||
let html = `
|
||||
<div class="rstack-header">
|
||||
<a class="rstack-header" href="https://rstack.online" target="_blank" rel="noopener">
|
||||
<span class="rstack-badge">r*</span>
|
||||
<div class="rstack-info">
|
||||
<span class="rstack-title">rStack</span>
|
||||
<span class="rstack-subtitle">Self-hosted community app suite</span>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
`;
|
||||
|
||||
for (const cat of CATEGORY_ORDER) {
|
||||
|
|
@ -304,10 +304,13 @@ const STYLES = `
|
|||
}
|
||||
|
||||
/* rStack header */
|
||||
.rstack-header {
|
||||
a.rstack-header {
|
||||
display: flex; align-items: center; gap: 10px;
|
||||
padding: 12px 14px; border-bottom: 1px solid rgba(128,128,128,0.15);
|
||||
text-decoration: none; color: inherit; cursor: pointer;
|
||||
transition: background 0.12s;
|
||||
}
|
||||
a.rstack-header:hover { background: rgba(255,255,255,0.05); }
|
||||
.rstack-badge {
|
||||
display: flex; align-items: center; justify-content: center;
|
||||
width: 28px; height: 28px; border-radius: 8px;
|
||||
|
|
|
|||
|
|
@ -146,7 +146,7 @@ function _getCurrentSpace(): string {
|
|||
}
|
||||
function _getCurrentModule(): string {
|
||||
const parts = window.location.pathname.split("/").filter(Boolean);
|
||||
return _isSubdomain() ? (parts[0] || "canvas") : (parts[1] || "canvas");
|
||||
return _isSubdomain() ? (parts[0] || "rspace") : (parts[1] || "rspace");
|
||||
}
|
||||
function _navUrl(space: string, moduleId: string): string {
|
||||
const h = window.location.host.split(":")[0].split(".");
|
||||
|
|
|
|||
|
|
@ -25,33 +25,33 @@ import { FLOW_COLORS, FLOW_LABELS } from "../../lib/layer-types";
|
|||
|
||||
// Re-export badge info so the tab bar can show module colors
|
||||
const MODULE_BADGES: Record<string, { badge: string; color: string }> = {
|
||||
canvas: { badge: "rS", color: "#5eead4" },
|
||||
notes: { badge: "rN", color: "#fcd34d" },
|
||||
pubs: { badge: "rP", color: "#fda4af" },
|
||||
swag: { badge: "rSw", color: "#fda4af" },
|
||||
splat: { badge: "r3", color: "#d8b4fe" },
|
||||
cal: { badge: "rC", color: "#7dd3fc" },
|
||||
trips: { badge: "rT", color: "#6ee7b7" },
|
||||
maps: { badge: "rM", color: "#86efac" },
|
||||
chats: { badge: "rCh", color: "#6ee7b7" },
|
||||
inbox: { badge: "rI", color: "#a5b4fc" },
|
||||
mail: { badge: "rMa", color: "#93c5fd" },
|
||||
forum: { badge: "rFo", color: "#fcd34d" },
|
||||
choices: { badge: "rCo", color: "#f0abfc" },
|
||||
vote: { badge: "rV", color: "#c4b5fd" },
|
||||
funds: { badge: "rF", color: "#bef264" },
|
||||
wallet: { badge: "rW", color: "#fde047" },
|
||||
cart: { badge: "rCt", color: "#fdba74" },
|
||||
auctions: { badge: "rA", color: "#fca5a5" },
|
||||
providers: { badge: "rPr", color: "#fdba74" },
|
||||
tube: { badge: "rTu", color: "#f9a8d4" },
|
||||
photos: { badge: "rPh", color: "#f9a8d4" },
|
||||
network: { badge: "rNe", color: "#93c5fd" },
|
||||
socials: { badge: "rSo", color: "#7dd3fc" },
|
||||
files: { badge: "rFi", color: "#67e8f9" },
|
||||
books: { badge: "rB", color: "#fda4af" },
|
||||
data: { badge: "rD", color: "#d8b4fe" },
|
||||
work: { badge: "rWo", color: "#cbd5e1" },
|
||||
rspace: { badge: "rS", color: "#5eead4" },
|
||||
rnotes: { badge: "rN", color: "#fcd34d" },
|
||||
rpubs: { badge: "rP", color: "#fda4af" },
|
||||
rswag: { badge: "rSw", color: "#fda4af" },
|
||||
rsplat: { badge: "r3", color: "#d8b4fe" },
|
||||
rcal: { badge: "rC", color: "#7dd3fc" },
|
||||
rtrips: { badge: "rT", color: "#6ee7b7" },
|
||||
rmaps: { badge: "rM", color: "#86efac" },
|
||||
rchats: { badge: "rCh", color: "#6ee7b7" },
|
||||
rinbox: { badge: "rI", color: "#a5b4fc" },
|
||||
rmail: { badge: "rMa", color: "#93c5fd" },
|
||||
rforum: { badge: "rFo", color: "#fcd34d" },
|
||||
rchoices: { badge: "rCo", color: "#f0abfc" },
|
||||
rvote: { badge: "rV", color: "#c4b5fd" },
|
||||
rfunds: { badge: "rF", color: "#bef264" },
|
||||
rwallet: { badge: "rW", color: "#fde047" },
|
||||
rcart: { badge: "rCt", color: "#fdba74" },
|
||||
rauctions: { badge: "rA", color: "#fca5a5" },
|
||||
rproviders: { badge: "rPr", color: "#fdba74" },
|
||||
rtube: { badge: "rTu", color: "#f9a8d4" },
|
||||
rphotos: { badge: "rPh", color: "#f9a8d4" },
|
||||
rnetwork: { badge: "rNe", color: "#93c5fd" },
|
||||
rsocials: { badge: "rSo", color: "#7dd3fc" },
|
||||
rfiles: { badge: "rFi", color: "#67e8f9" },
|
||||
rbooks: { badge: "rB", color: "#fda4af" },
|
||||
rdata: { badge: "rD", color: "#d8b4fe" },
|
||||
rwork: { badge: "rWo", color: "#cbd5e1" },
|
||||
};
|
||||
|
||||
export class RStackTabBar extends HTMLElement {
|
||||
|
|
|
|||
|
|
@ -35,9 +35,9 @@ export function getCurrentSpace(): string {
|
|||
export function getCurrentModule(): string {
|
||||
const parts = window.location.pathname.split("/").filter(Boolean);
|
||||
if (isSubdomain()) {
|
||||
return parts[0] || "canvas";
|
||||
return parts[0] || "rspace";
|
||||
}
|
||||
return parts[1] || "canvas";
|
||||
return parts[1] || "rspace";
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -379,7 +379,7 @@
|
|||
|
||||
<div class="cta-buttons">
|
||||
<a href="/create-space" class="cta-primary" id="cta-primary">Create a Space</a>
|
||||
<a href="/demo/canvas" class="cta-secondary" id="cta-demo">Try the Demo</a>
|
||||
<a href="/demo/rspace" class="cta-secondary" id="cta-demo">Try the Demo</a>
|
||||
</div>
|
||||
|
||||
<div class="features">
|
||||
|
|
|
|||
Loading…
Reference in New Issue