diff --git a/apps/web/src/app/(main)/compose/page.tsx b/apps/web/src/app/(main)/compose/page.tsx
index 464584c..a8bd792 100644
--- a/apps/web/src/app/(main)/compose/page.tsx
+++ b/apps/web/src/app/(main)/compose/page.tsx
@@ -274,7 +274,10 @@ export default function ComposePage(): React.ReactElement {
className="w-52 py-1 text-xs"
/>
-
+
+ {targets.length === 0 && !over && (
+
Connect a channel to publish — open Channels in the sidebar.
+ )}
;
diff --git a/apps/web/src/app/(main)/onboarding/page.tsx b/apps/web/src/app/(main)/onboarding/page.tsx
index d1287a1..ce92603 100644
--- a/apps/web/src/app/(main)/onboarding/page.tsx
+++ b/apps/web/src/app/(main)/onboarding/page.tsx
@@ -271,7 +271,7 @@ export default function OnboardingPage(): React.ReactElement {
onChange={(e) => setUsername(e.target.value.toLowerCase())}
placeholder="Username — this is how you sign in"
autoComplete="username"
- pattern="[a-z0-9][a-z0-9_.-]{1,31}"
+ pattern="[a-z0-9][a-z0-9._-]{1,31}"
title="2-32 characters: lowercase letters, digits, dot, underscore or hyphen"
/>
(x: T): string => x.es;
+ // Respect the reading language the user picked on the landing page (tmbh.lang
+ // in localStorage); Spanish stays the fallback for a fresh visitor.
+ const [lang, setLang] = useState<"es" | "en">("es");
+ useEffect(() => {
+ try {
+ const stored = window.localStorage.getItem("tmbh.manual.lang");
+ if (stored === "en" || stored === "es") setLang(stored);
+ } catch { /* private mode: keep the default */ }
+ }, []);
+ const t =
(x: T): string => x[lang];
const name = session?.user.displayName?.trim() || session?.user.username || "";
return (
diff --git a/apps/web/src/components/shell/sidebar.tsx b/apps/web/src/components/shell/sidebar.tsx
index 0734399..f30f75d 100644
--- a/apps/web/src/components/shell/sidebar.tsx
+++ b/apps/web/src/components/shell/sidebar.tsx
@@ -9,23 +9,44 @@ import type { DraftRecord } from "../../lib/api-types";
import { LogoMark } from "../brand/logo";
import { NavIcon } from "../brand";
-const NAV: { href: string; label: string; icon: string; external?: boolean }[] = [
- { href: "/streams", label: "Streams", icon: "video" },
- { href: "/control-room", label: "Control Room", icon: "video" },
- { href: "/compose", label: "Compose", icon: "compose" },
- { href: "/calendar", label: "Calendar", icon: "calendar" },
- { href: "/chat", label: "Chat", icon: "chat" },
- { href: "/files", label: "Files", icon: "files" },
- { href: "/archive", label: "Archive", icon: "files" },
- { href: "/inbox", label: "Inbox", icon: "inbox" },
- { href: "/approvals", label: "Approvals", icon: "approvals" },
- { href: "/video", label: "Video", icon: "video" },
- { href: "/analytics", label: "Analytics", icon: "analytics" },
- { href: "/connections", label: "Channels", icon: "connections" },
- { href: "/team", label: "Team", icon: "team" },
- { href: "/audit", label: "Audit log", icon: "audit" },
- { href: "/onboarding", label: "Onboarding", icon: "home" },
- { href: "/settings", label: "Settings", icon: "settings" },
+/** Grouped per the 2026-10 UX audit (16 flat items → 5 scannable sections). */
+const NAV: { section: string; items: { href: string; label: string; icon: string; external?: boolean }[] }[] = [
+ {
+ section: "Publish",
+ items: [
+ { href: "/compose", label: "Compose", icon: "compose" },
+ { href: "/calendar", label: "Calendar", icon: "calendar" },
+ { href: "/streams", label: "Home", icon: "video" },
+ ],
+ },
+ {
+ section: "Content",
+ items: [
+ { href: "/video", label: "Video library", icon: "video" },
+ { href: "/files", label: "Files", icon: "files" },
+ { href: "/archive", label: "Archive", icon: "archive" },
+ { href: "/chat", label: "Chat", icon: "chat" },
+ ],
+ },
+ {
+ section: "Operations",
+ items: [
+ { href: "/inbox", label: "Inbox", icon: "inbox" },
+ { href: "/approvals", label: "Approvals", icon: "approvals" },
+ { href: "/groups", label: "Groups", icon: "team" },
+ { href: "/control-room", label: "Control Room", icon: "control" },
+ { href: "/analytics", label: "Analytics", icon: "analytics" },
+ { href: "/audit", label: "Audit trail", icon: "audit" },
+ ],
+ },
+ {
+ section: "Admin",
+ items: [
+ { href: "/connections", label: "Connections", icon: "connections" },
+ { href: "/team", label: "Team", icon: "team" },
+ { href: "/settings", label: "Settings", icon: "settings" },
+ ],
+ },
];
const identity = (drafts: DraftRecord[]): DraftRecord[] => drafts;
@@ -72,18 +93,16 @@ export function Sidebar(): React.ReactElement {