diff --git a/shared/components/rstack-app-switcher.ts b/shared/components/rstack-app-switcher.ts index 0c13d52..afae3c2 100644 --- a/shared/components/rstack-app-switcher.ts +++ b/shared/components/rstack-app-switcher.ts @@ -18,29 +18,43 @@ export interface AppSwitcherModule { // Pastel badge abbreviations & colors for each module const MODULE_BADGES: Record = { + // 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 + // Planning cal: { badge: "rC", color: "#7dd3fc" }, // sky-300 trips: { badge: "rT", color: "#6ee7b7" }, // emerald-300 maps: { badge: "rM", color: "#86efac" }, // green-300 - work: { badge: "rWk", color: "#fdba74" }, // orange-300 - forum: { badge: "rFo", color: "#a5b4fc" }, // indigo-300 + // Communicating + chats: { badge: "rCh", color: "#6ee7b7" }, // emerald-200 inbox: { badge: "rI", color: "#a5b4fc" }, // indigo-300 - choices: { badge: "rCh", color: "#f0abfc" }, // fuchsia-300 + mail: { badge: "rMa", color: "#93c5fd" }, // blue-200 + forum: { badge: "rFo", color: "#fcd34d" }, // amber-200 + // Deciding + choices: { badge: "rCo", color: "#f0abfc" }, // fuchsia-300 vote: { 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 - providers: { badge: "rPr", color: "#fdba74" }, // orange-300 - books: { badge: "rB", color: "#fda4af" }, // rose-300 - files: { badge: "rFi", color: "#67e8f9" }, // cyan-300 - tube: { badge: "rTu", color: "#f9a8d4" }, // pink-300 - data: { badge: "rD", color: "#d8b4fe" }, // purple-300 - network: { badge: "rNe", color: "#93c5fd" }, // blue-300 auctions: { badge: "rA", color: "#fca5a5" }, // red-300 + providers: { badge: "rPr", color: "#fdba74" }, // orange-300 + // Social & Media + photos: { badge: "rPh", color: "#f9a8d4" }, // pink-200 + tube: { badge: "rTu", color: "#f9a8d4" }, // pink-300 + network: { badge: "rNe", color: "#93c5fd" }, // blue-300 + socials: { badge: "rSo", color: "#7dd3fc" }, // sky-200 + files: { badge: "rFi", color: "#67e8f9" }, // cyan-300 + data: { badge: "rD", color: "#d8b4fe" }, // purple-300 + books: { badge: "rB", color: "#fda4af" }, // rose-300 + // Work & Productivity + work: { badge: "rWo", color: "#cbd5e1" }, // slate-300 + // Identity & Infrastructure + ids: { badge: "rId", color: "#6ee7b7" }, // emerald-300 + stack: { badge: "r*", color: "" }, // gradient (handled separately) }; // Category definitions for the rApp dropdown (display-only grouping) @@ -53,29 +67,38 @@ const MODULE_CATEGORIES: Record = { cal: "Planning", trips: "Planning", maps: "Planning", - work: "Planning", - forum: "Discussing & Deciding", - inbox: "Discussing & Deciding", - choices: "Discussing & Deciding", - vote: "Discussing & Deciding", + chats: "Communicating", + inbox: "Communicating", + mail: "Communicating", + forum: "Communicating", + choices: "Deciding", + vote: "Deciding", funds: "Funding & Commerce", wallet: "Funding & Commerce", cart: "Funding & Commerce", - providers: "Funding & Commerce", auctions: "Funding & Commerce", - network: "Social & Sharing", - books: "Social & Sharing", - files: "Social & Sharing", - tube: "Social & Sharing", - data: "Social & Sharing", + providers: "Funding & Commerce", + photos: "Social & Media", + tube: "Social & Media", + network: "Social & Media", + socials: "Social & Media", + files: "Social & Media", + data: "Social & Media", + books: "Social & Media", + work: "Work & Productivity", + ids: "Identity & Infrastructure", + stack: "Identity & Infrastructure", }; const CATEGORY_ORDER = [ "Creating", "Planning", - "Discussing & Deciding", + "Communicating", + "Deciding", "Funding & Commerce", - "Social & Sharing", + "Social & Media", + "Work & Productivity", + "Identity & Infrastructure", ]; export class RStackAppSwitcher extends HTMLElement { diff --git a/shared/components/rstack-space-switcher.ts b/shared/components/rstack-space-switcher.ts index 5cd38c3..29fa080 100644 --- a/shared/components/rstack-space-switcher.ts +++ b/shared/components/rstack-space-switcher.ts @@ -106,6 +106,13 @@ export class RStackSpaceSwitcher extends HTMLElement { document.addEventListener("click", () => menu.classList.remove("open")); } + #visibilityInfo(s: SpaceInfo): { cls: string; label: string } { + const v = s.visibility || "public_read"; + if (v === "members_only") return { cls: "vis-private", label: "PRIVATE" }; + if (v === "authenticated") return { cls: "vis-permissioned", label: "PERMISSIONED" }; + return { cls: "vis-public", label: "PUBLIC" }; + } + #renderMenu(menu: HTMLElement, current: string) { if (this.#spaces.length === 0) { menu.innerHTML = ` @@ -128,16 +135,17 @@ export class RStackSpaceSwitcher extends HTMLElement { if (mySpaces.length > 0) { html += ``; html += mySpaces - .map( - (s) => ` - { + const vis = this.#visibilityInfo(s); + return ` + ${s.icon || "🌐"} ${s.name} - ${s.role ? `${s.role}` : ""} + ${vis.label} - ` - ) + `; + }) .join(""); } @@ -145,15 +153,17 @@ export class RStackSpaceSwitcher extends HTMLElement { if (mySpaces.length > 0) html += `
`; html += ``; html += publicSpaces - .map( - (s) => ` - { + const vis = this.#visibilityInfo(s); + return ` + ${s.icon || "🌐"} ${s.name} + ${vis.label} - ` - ) + `; + }) .join(""); } @@ -179,23 +189,23 @@ const STYLES = ` .switcher { position: relative; } .trigger { - display: flex; align-items: center; gap: 4px; - padding: 6px 12px; border-radius: 8px; border: none; - font-size: 0.875rem; font-weight: 500; cursor: pointer; - transition: background 0.15s; background: transparent; color: inherit; + display: flex; align-items: center; gap: 6px; + padding: 6px 14px; border-radius: 8px; border: none; + font-size: 0.875rem; font-weight: 600; cursor: pointer; + transition: background 0.15s; color: inherit; } -:host-context([data-theme="light"]) .trigger { color: #374151; } -:host-context([data-theme="dark"]) .trigger { color: #94a3b8; } -.trigger:hover { background: rgba(0,0,0,0.05); } -:host-context([data-theme="dark"]) .trigger:hover { background: rgba(255,255,255,0.05); } +:host-context([data-theme="light"]) .trigger { background: rgba(0,0,0,0.05); color: #374151; } +:host-context([data-theme="light"]) .trigger:hover { background: rgba(0,0,0,0.08); } +:host-context([data-theme="dark"]) .trigger { background: rgba(255,255,255,0.08); color: #e2e8f0; } +:host-context([data-theme="dark"]) .trigger:hover { background: rgba(255,255,255,0.12); } .slash { opacity: 0.4; font-weight: 300; margin-right: 2px; } .space-name { max-width: 160px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } -.caret { font-size: 0.7em; opacity: 0.5; } +.caret { font-size: 0.7em; opacity: 0.6; } .menu { position: absolute; top: 100%; left: 0; margin-top: 6px; - min-width: 240px; max-height: 400px; overflow-y: auto; + min-width: 260px; max-height: 400px; overflow-y: auto; border-radius: 12px; box-shadow: 0 8px 30px rgba(0,0,0,0.25); display: none; z-index: 200; } @@ -211,7 +221,7 @@ const STYLES = ` .item { display: flex; align-items: center; gap: 10px; padding: 10px 14px; text-decoration: none; cursor: pointer; - transition: background 0.12s; + transition: background 0.12s; border-left: 3px solid transparent; } :host-context([data-theme="light"]) .item { color: #374151; } :host-context([data-theme="light"]) .item:hover { background: #f1f5f9; } @@ -220,18 +230,30 @@ const STYLES = ` :host-context([data-theme="dark"]) .item:hover { background: rgba(255,255,255,0.05); } :host-context([data-theme="dark"]) .item.active { background: rgba(6,182,212,0.1); } +/* Visibility color accents — left border */ +.item.vis-public { border-left-color: #34d399; } +.item.vis-private { border-left-color: #f87171; } +.item.vis-permissioned { border-left-color: #fbbf24; } + .item-icon { font-size: 1.1rem; flex-shrink: 0; } .item-name { font-size: 0.875rem; font-weight: 500; flex: 1; } -.item-role { - font-size: 0.65rem; font-weight: 600; text-transform: uppercase; + +/* Visibility badge */ +.item-vis { + font-size: 0.55rem; font-weight: 700; text-transform: uppercase; padding: 2px 6px; border-radius: 4px; flex-shrink: 0; - letter-spacing: 0.03em; + letter-spacing: 0.04em; line-height: 1.4; } -:host-context([data-theme="light"]) .item-role { background: #e0f2fe; color: #0369a1; } -:host-context([data-theme="dark"]) .item-role { background: rgba(6,182,212,0.15); color: #22d3ee; } +.item-vis.vis-public { background: rgba(52,211,153,0.15); color: #34d399; } +.item-vis.vis-private { background: rgba(248,113,113,0.15); color: #f87171; } +.item-vis.vis-permissioned { background: rgba(251,191,36,0.15); color: #fbbf24; } +:host-context([data-theme="light"]) .item-vis.vis-public { background: #d1fae5; color: #059669; } +:host-context([data-theme="light"]) .item-vis.vis-private { background: #fee2e2; color: #dc2626; } +:host-context([data-theme="light"]) .item-vis.vis-permissioned { background: #fef3c7; color: #d97706; } .item--create { font-size: 0.85rem; font-weight: 600; color: #06b6d4 !important; + border-left-color: transparent !important; } .item--create:hover { background: rgba(6,182,212,0.08) !important; }