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. + )}
+ {selected.length === 0 &&

Connect a channel to publish — open Channels in the sidebar.

} +
setScheduleOpen(false)} title="Schedule post" footer={}> setScheduledAt(event.target.value)} className="mt-2 min-h-12" />
{[1, 24, 48].map((hours) => )}
setPreviewOpen(false)} title="Target previews">{selected.map((target) =>

{target.label}

{editor?.getText() || "Your post preview appears here…"}

)}
diff --git a/apps/web/src/app/(main)/more/page.tsx b/apps/web/src/app/(main)/more/page.tsx index 3f40f0e..a6491d5 100644 --- a/apps/web/src/app/(main)/more/page.tsx +++ b/apps/web/src/app/(main)/more/page.tsx @@ -72,13 +72,12 @@ export default function MorePage(): React.ReactElement {
- + -
; 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 { );