fix(rsocials): subdomain-aware link generation
Links on subdomain routing (e.g. jeff.rspace.online) were including the space in the path (/demo/rsocials/campaigns) instead of just /rsocials/campaigns. Added basePath getter to all components and detect subdomain in the server-rendered hub page. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
eedf2cf189
commit
a5c7bb784e
|
|
@ -72,6 +72,14 @@ export class FolkCampaignManager extends HTMLElement {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private get basePath() {
|
||||||
|
const host = window.location.hostname;
|
||||||
|
if (host.endsWith('.rspace.online') || host.endsWith('.rsocials.online')) {
|
||||||
|
return '/rsocials/';
|
||||||
|
}
|
||||||
|
return `/${this._space}/rsocials/`;
|
||||||
|
}
|
||||||
|
|
||||||
private esc(s: string): string {
|
private esc(s: string): string {
|
||||||
return s.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"');
|
return s.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"');
|
||||||
}
|
}
|
||||||
|
|
@ -131,7 +139,7 @@ export class FolkCampaignManager extends HTMLElement {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="actions">
|
<div class="actions">
|
||||||
<a href="/rsocials/thread-editor" class="btn btn--outline">Open Thread Editor</a>
|
<a href="${this.basePath}thread-editor" class="btn btn--outline">Open Thread Editor</a>
|
||||||
<button class="btn btn--primary" id="import-md-btn">Import from Markdown</button>
|
<button class="btn btn--primary" id="import-md-btn">Import from Markdown</button>
|
||||||
</div>
|
</div>
|
||||||
${phaseHTML}
|
${phaseHTML}
|
||||||
|
|
|
||||||
|
|
@ -121,6 +121,14 @@ class FolkCampaignPlanner extends HTMLElement {
|
||||||
private shadow: ShadowRoot;
|
private shadow: ShadowRoot;
|
||||||
private space = '';
|
private space = '';
|
||||||
|
|
||||||
|
private get basePath() {
|
||||||
|
const host = window.location.hostname;
|
||||||
|
if (host.endsWith('.rspace.online') || host.endsWith('.rsocials.online')) {
|
||||||
|
return '/rsocials/';
|
||||||
|
}
|
||||||
|
return `/${this.space}/rsocials/`;
|
||||||
|
}
|
||||||
|
|
||||||
// Data
|
// Data
|
||||||
private nodes: CampaignPlannerNode[] = [];
|
private nodes: CampaignPlannerNode[] = [];
|
||||||
private edges: CampaignEdge[] = [];
|
private edges: CampaignEdge[] = [];
|
||||||
|
|
@ -820,7 +828,7 @@ class FolkCampaignPlanner extends HTMLElement {
|
||||||
} else if (action === 'open-thread') {
|
} else if (action === 'open-thread') {
|
||||||
const d = node.data as ThreadNodeData;
|
const d = node.data as ThreadNodeData;
|
||||||
if (d.threadId) {
|
if (d.threadId) {
|
||||||
window.location.href = `/rsocials/thread-editor/${d.threadId}/edit`;
|
window.location.href = `${this.basePath}thread-editor/${d.threadId}/edit`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
@ -1457,7 +1465,7 @@ class FolkCampaignPlanner extends HTMLElement {
|
||||||
if (node?.type === 'thread') {
|
if (node?.type === 'thread') {
|
||||||
const d = node.data as ThreadNodeData;
|
const d = node.data as ThreadNodeData;
|
||||||
if (d.threadId) {
|
if (d.threadId) {
|
||||||
window.location.href = `/rsocials/thread-editor/${d.threadId}/edit`;
|
window.location.href = `${this.basePath}thread-editor/${d.threadId}/edit`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -274,7 +274,7 @@ export class FolkThreadBuilder extends HTMLElement {
|
||||||
</div>
|
</div>
|
||||||
<div class="preview ro-cards">${tweetCards}</div>
|
<div class="preview ro-cards">${tweetCards}</div>
|
||||||
<div class="ro-actions">
|
<div class="ro-actions">
|
||||||
<a href="/rsocials/thread-editor/${this.esc(t.id)}/edit" class="btn btn--primary">Edit Thread</a>
|
<a href="${this.basePath}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-thread">Copy Thread</button>
|
||||||
<button class="btn btn--outline" id="ro-copy-link">Copy Link</button>
|
<button class="btn btn--outline" id="ro-copy-link">Copy Link</button>
|
||||||
<div class="export-dropdown">
|
<div class="export-dropdown">
|
||||||
|
|
@ -289,8 +289,8 @@ export class FolkThreadBuilder extends HTMLElement {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="ro-cta">
|
<div class="ro-cta">
|
||||||
<a href="/rsocials/thread-editor" class="btn btn--success">Create Your Own Thread</a>
|
<a href="${this.basePath}thread-editor" class="btn btn--success">Create Your Own Thread</a>
|
||||||
<a href="/rsocials/threads" class="btn btn--outline">Browse All Threads</a>
|
<a href="${this.basePath}threads" class="btn btn--outline">Browse All Threads</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="toast" id="export-toast" hidden></div>
|
<div class="toast" id="export-toast" hidden></div>
|
||||||
|
|
|
||||||
|
|
@ -82,6 +82,14 @@ export class FolkThreadGallery extends HTMLElement {
|
||||||
this.render();
|
this.render();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private get basePath() {
|
||||||
|
const host = window.location.hostname;
|
||||||
|
if (host.endsWith('.rspace.online') || host.endsWith('.rsocials.online')) {
|
||||||
|
return '/rsocials/';
|
||||||
|
}
|
||||||
|
return `/${this._space}/rsocials/`;
|
||||||
|
}
|
||||||
|
|
||||||
private esc(s: string): string {
|
private esc(s: string): string {
|
||||||
return s.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"');
|
return s.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"');
|
||||||
}
|
}
|
||||||
|
|
@ -94,7 +102,7 @@ export class FolkThreadGallery extends HTMLElement {
|
||||||
const cardsHTML = threads.length === 0
|
const cardsHTML = threads.length === 0
|
||||||
? `<div class="empty">
|
? `<div class="empty">
|
||||||
<p>No threads yet. Create your first thread!</p>
|
<p>No threads yet. Create your first thread!</p>
|
||||||
<a href="/rsocials/thread-editor" class="btn btn--success">Create Thread</a>
|
<a href="${this.basePath}thread-editor" class="btn btn--success">Create Thread</a>
|
||||||
</div>`
|
</div>`
|
||||||
: `<div class="grid">
|
: `<div class="grid">
|
||||||
${threads.map(t => {
|
${threads.map(t => {
|
||||||
|
|
@ -105,8 +113,8 @@ export class FolkThreadGallery extends HTMLElement {
|
||||||
? `<div class="card__image"><img src="${this.esc(t.imageUrl)}" alt="" loading="lazy"></div>`
|
? `<div class="card__image"><img src="${this.esc(t.imageUrl)}" alt="" loading="lazy"></div>`
|
||||||
: '';
|
: '';
|
||||||
const href = this._isDemoFallback
|
const href = this._isDemoFallback
|
||||||
? `/rsocials/thread-editor`
|
? `${this.basePath}thread-editor`
|
||||||
: `/rsocials/thread-editor/${this.esc(t.id)}/edit`;
|
: `${this.basePath}thread-editor/${this.esc(t.id)}/edit`;
|
||||||
return `<a href="${href}" class="card">
|
return `<a href="${href}" class="card">
|
||||||
${imageTag}
|
${imageTag}
|
||||||
<h3 class="card__title">${this.esc(t.title || 'Untitled Thread')}</h3>
|
<h3 class="card__title">${this.esc(t.title || 'Untitled Thread')}</h3>
|
||||||
|
|
@ -165,7 +173,7 @@ export class FolkThreadGallery extends HTMLElement {
|
||||||
<div class="gallery">
|
<div class="gallery">
|
||||||
<div class="header">
|
<div class="header">
|
||||||
<h1>Threads</h1>
|
<h1>Threads</h1>
|
||||||
<a href="/rsocials/thread-editor" class="btn btn--primary">New Thread</a>
|
<a href="${this.basePath}thread-editor" class="btn btn--primary">New Thread</a>
|
||||||
</div>
|
</div>
|
||||||
${cardsHTML}
|
${cardsHTML}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -644,7 +644,9 @@ routes.get("/landing", (c) => {
|
||||||
|
|
||||||
routes.get("/", (c) => {
|
routes.get("/", (c) => {
|
||||||
const space = c.req.param("space") || "demo";
|
const space = c.req.param("space") || "demo";
|
||||||
const base = `/${escapeHtml(space)}/rsocials`;
|
const host = c.req.header("host")?.split(":")[0] || "";
|
||||||
|
const isSubdomain = (host.endsWith(".rspace.online") && host !== "rspace.online" && !host.startsWith("www.")) || host.endsWith(".rsocials.online");
|
||||||
|
const base = isSubdomain ? "/rsocials" : `/${escapeHtml(space)}/rsocials`;
|
||||||
return c.html(renderShell({
|
return c.html(renderShell({
|
||||||
title: `rSocials — ${space} | rSpace`,
|
title: `rSocials — ${space} | rSpace`,
|
||||||
moduleId: "rsocials",
|
moduleId: "rsocials",
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue