fix(rnetwork): consolidate to single sub-tab menu, remove empty nav items

- Reduce tabs to Members (default), Trust, CRM
- Remove empty outputPaths (Connections, Groups placeholders)
- Hide subnav when tabbar is present (avoid double menu)
- CRM tab redirects to the CRM sub-app

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Jeff Emmett 2026-04-15 17:12:50 -04:00
parent 992d974449
commit 8146f97550
3 changed files with 7 additions and 27 deletions

View File

@ -203,42 +203,23 @@ class FolkGraphViewer extends HTMLElement {
private applyTab(tab: string) { private applyTab(tab: string) {
const wasTrust = this.trustMode; const wasTrust = this.trustMode;
const wasLayers = this.layersMode;
switch (tab) { switch (tab) {
case "members": case "members":
this.filter = "all"; this.filter = "all";
this.trustMode = false; this.trustMode = false;
if (wasLayers) this.exitLayersMode();
break;
case "people":
this.filter = "person";
this.trustMode = false;
if (wasLayers) this.exitLayersMode();
break;
case "companies":
this.filter = "company";
this.trustMode = false;
if (wasLayers) this.exitLayersMode();
break; break;
case "trust": case "trust":
this.filter = "all"; this.filter = "all";
this.trustMode = true; this.trustMode = true;
if (wasLayers) this.exitLayersMode();
if (this.layoutMode !== "rings") { if (this.layoutMode !== "rings") {
this.layoutMode = "rings"; this.layoutMode = "rings";
const ringsBtn = this.shadow.getElementById("rings-toggle"); const ringsBtn = this.shadow.getElementById("rings-toggle");
if (ringsBtn) ringsBtn.classList.add("active"); if (ringsBtn) ringsBtn.classList.add("active");
} }
break; break;
case "layers":
this.filter = "all";
this.trustMode = false;
if (!wasLayers) this.enterLayersMode();
break;
} }
this.updateAuthorityBar(); this.updateAuthorityBar();
// Trust mode change needs full data reload
if (this.trustMode !== wasTrust) { if (this.trustMode !== wasTrust) {
this.loadData(); this.loadData();
} else { } else {

View File

@ -695,10 +695,8 @@ routes.get("/api/opportunities", async (c) => {
// ── Graph tabs (main view) ── // ── Graph tabs (main view) ──
const GRAPH_TABS = [ const GRAPH_TABS = [
{ id: "members", label: "Members" }, { id: "members", label: "Members" },
{ id: "people", label: "People" },
{ id: "companies", label: "Companies" },
{ id: "trust", label: "Trust" }, { id: "trust", label: "Trust" },
{ id: "layers", label: "Layers" }, { id: "crm", label: "CRM" },
] as const; ] as const;
const GRAPH_TAB_IDS = new Set(GRAPH_TABS.map(t => t.id)); const GRAPH_TAB_IDS = new Set(GRAPH_TABS.map(t => t.id));
@ -767,6 +765,11 @@ routes.get("/:tabId", (c, next) => {
const tabId = c.req.param("tabId"); const tabId = c.req.param("tabId");
// Only handle graph tab IDs here; let other routes (crm, api, etc.) pass through // Only handle graph tab IDs here; let other routes (crm, api, etc.) pass through
if (!GRAPH_TAB_IDS.has(tabId as any)) return next(); if (!GRAPH_TAB_IDS.has(tabId as any)) return next();
// "crm" tab redirects to the CRM sub-app
if (tabId === "crm") {
const space = c.req.param("space") || "demo";
return c.redirect(c.get("isSubdomain") ? `/rnetwork/crm/pipeline` : `/${space}/rnetwork/crm/pipeline`, 302);
}
const space = c.req.param("space") || "demo"; const space = c.req.param("space") || "demo";
return c.html(renderGraph(space, tabId, c.get("isSubdomain"))); return c.html(renderGraph(space, tabId, c.get("isSubdomain")));
}); });
@ -836,10 +839,6 @@ export const networkModule: RSpaceModule = {
}, },
], ],
acceptsFeeds: ["data", "trust", "governance"], acceptsFeeds: ["data", "trust", "governance"],
outputPaths: [
{ path: "connections", name: "Connections", icon: "🤝", description: "Community member connections" },
{ path: "groups", name: "Groups", icon: "👥", description: "Relationship groups and circles" },
],
subPageInfos: [ subPageInfos: [
{ {
path: "crm", path: "crm",

View File

@ -353,7 +353,7 @@ export function renderShell(opts: ShellOptions): string {
<rstack-user-dashboard space="${escapeAttr(spaceSlug)}" style="display:none"></rstack-user-dashboard> <rstack-user-dashboard space="${escapeAttr(spaceSlug)}" style="display:none"></rstack-user-dashboard>
${moduleId !== "rspace" ? `<rstack-module-comments module-id="${escapeAttr(moduleId)}" space="${escapeAttr(spaceSlug)}"></rstack-module-comments>` : ''} ${moduleId !== "rspace" ? `<rstack-module-comments module-id="${escapeAttr(moduleId)}" space="${escapeAttr(spaceSlug)}"></rstack-module-comments>` : ''}
<main id="app"${moduleId === "rspace" ? ' class="canvas-layout"' : ''}> <main id="app"${moduleId === "rspace" ? ' class="canvas-layout"' : ''}>
${renderModuleSubNav(moduleId, spaceSlug, visibleModules, opts.isSubdomain ?? IS_PRODUCTION)} ${opts.tabs ? '' : renderModuleSubNav(moduleId, spaceSlug, visibleModules, opts.isSubdomain ?? IS_PRODUCTION)}
${opts.tabs ? renderTabBar(opts.tabs, opts.activeTab, opts.tabBasePath || ((opts.isSubdomain ?? IS_PRODUCTION) ? `/${escapeAttr(moduleId)}` : `/${escapeAttr(spaceSlug)}/${escapeAttr(moduleId)}`)) : ''} ${opts.tabs ? renderTabBar(opts.tabs, opts.activeTab, opts.tabBasePath || ((opts.isSubdomain ?? IS_PRODUCTION) ? `/${escapeAttr(moduleId)}` : `/${escapeAttr(spaceSlug)}/${escapeAttr(moduleId)}`)) : ''}
<div class="rapp-content">${body}</div> <div class="rapp-content">${body}</div>
</main> </main>