diff --git a/frontend/src/components/layout/MobileNav.tsx b/frontend/src/components/layout/MobileNav.tsx index ea705ee..08b31d3 100644 --- a/frontend/src/components/layout/MobileNav.tsx +++ b/frontend/src/components/layout/MobileNav.tsx @@ -1,12 +1,20 @@ import type { ViewId } from "../../types"; import { useApp } from "../../context/AppContext"; +import { + IconAgent, + IconGraph, + IconHome, + IconReview, + IconSearch, + IconSpark, +} from "../ui/icons"; -const ITEMS: { id: ViewId; label: string; icon: string }[] = [ - { id: "home", label: "Overview", icon: "⌂" }, - { id: "ask", label: "Search", icon: "?" }, - { id: "explore", label: "Map", icon: "◎" }, - { id: "agents", label: "AI", icon: "⚡" }, - { id: "review", label: "Review", icon: "⚖" }, +const ITEMS: { id: ViewId; label: string; Icon: typeof IconHome }[] = [ + { id: "home", label: "Overview", Icon: IconHome }, + { id: "ask", label: "Search", Icon: IconSearch }, + { id: "explore", label: "Map", Icon: IconGraph }, + { id: "agents", label: "AI", Icon: IconAgent }, + { id: "review", label: "Review", Icon: IconReview }, ]; /** Bottom tab bar for phone/tablet — primary navigation on small screens. */ @@ -22,9 +30,10 @@ export function MobileNav() { className={`mobile-nav__item ${view === item.id ? "mobile-nav__item--active" : ""}`} onClick={() => setView(item.id)} aria-current={view === item.id ? "page" : undefined} + aria-label={item.label} > - {item.icon} + {item.label} @@ -36,7 +45,7 @@ export function MobileNav() { aria-label="Open Cortex Assist" > - ✦ + Assist diff --git a/frontend/src/components/layout/Sidebar.tsx b/frontend/src/components/layout/Sidebar.tsx index 734d0c7..612990c 100644 --- a/frontend/src/components/layout/Sidebar.tsx +++ b/frontend/src/components/layout/Sidebar.tsx @@ -1,12 +1,19 @@ import type { ViewId } from "../../types"; import { useApp } from "../../context/AppContext"; +import { + IconAgent, + IconGraph, + IconHome, + IconReview, + IconSearch, +} from "../ui/icons"; -const NAV: { id: ViewId; label: string; hint: string; icon: string }[] = [ - { id: "home", label: "Overview", hint: "Executive summary", icon: "⌂" }, - { id: "ask", label: "Search", hint: "Ask memory", icon: "?" }, - { id: "explore", label: "Memory map", hint: "Connections & lineage", icon: "◎" }, - { id: "agents", label: "AI agents", hint: "Inject & capture", icon: "⚡" }, - { id: "review", label: "Conflicts", hint: "Human review", icon: "⚖" }, +const NAV: { id: ViewId; label: string; hint: string; Icon: typeof IconHome }[] = [ + { id: "home", label: "Overview", hint: "Executive summary", Icon: IconHome }, + { id: "ask", label: "Search", hint: "Ask memory", Icon: IconSearch }, + { id: "explore", label: "Memory map", hint: "Connections & lineage", Icon: IconGraph }, + { id: "agents", label: "AI agents", hint: "Inject & capture", Icon: IconAgent }, + { id: "review", label: "Conflicts", hint: "Human review", Icon: IconReview }, ]; export function Sidebar() { @@ -26,9 +33,10 @@ export function Sidebar() { className={`sidebar__link ${view === item.id ? "sidebar__link--active" : ""}`} onClick={() => setView(item.id)} aria-current={view === item.id ? "page" : undefined} + aria-label={`${item.label} — ${item.hint}`} > - {item.icon} + {item.label} diff --git a/frontend/src/components/memory/TimelineView.tsx b/frontend/src/components/memory/TimelineView.tsx index d6b4fa6..2d51bb9 100644 --- a/frontend/src/components/memory/TimelineView.tsx +++ b/frontend/src/components/memory/TimelineView.tsx @@ -1,5 +1,7 @@ import type { DecisionResult } from "../../types"; import { formatRelativeTime, formatSource } from "../../lib/format"; +import { StateView } from "../ui/StateView"; +import { IconEmpty } from "../ui/icons"; type Props = { decisions: DecisionResult[]; @@ -13,9 +15,9 @@ export function TimelineView({ decisions, onSelect }: Props) { if (sorted.length === 0) { return ( -
-

Your organizational timeline will appear here after you search or load memories.

-
+ } title="Timeline is empty"> + Your organizational timeline will appear here after you search or load memories. + ); } diff --git a/frontend/src/components/ui/StateView.tsx b/frontend/src/components/ui/StateView.tsx index c176257..2ea12e1 100644 --- a/frontend/src/components/ui/StateView.tsx +++ b/frontend/src/components/ui/StateView.tsx @@ -1,7 +1,8 @@ import type { ReactNode } from "react"; +import { IconEmpty } from "./icons"; type Props = { - icon?: string; + icon?: ReactNode; title: string; children?: ReactNode; action?: ReactNode; @@ -9,7 +10,8 @@ type Props = { }; /** Empty / error / informational state shared across views. */ -export function StateView({ icon = "◇", title, children, action, tone = "neutral" }: Props) { +export function StateView({ icon, title, children, action, tone = "neutral" }: Props) { + const glyph = icon ?? ; return (
- {icon} + {glyph}

{title}

- {children ?

{children}

: null} - {action ?
{action}
: null} + {children ?
{children}
: null} + {action ?
{action}
: null}
); } diff --git a/frontend/src/components/ui/icons.tsx b/frontend/src/components/ui/icons.tsx new file mode 100644 index 0000000..c547ade --- /dev/null +++ b/frontend/src/components/ui/icons.tsx @@ -0,0 +1,101 @@ +import type { SVGProps, ReactNode } from "react"; + +type IconProps = SVGProps & { size?: number }; + +function Icon({ size = 18, children, ...props }: IconProps & { children: ReactNode }) { + return ( + + {children} + + ); +} + +export function IconHome(props: IconProps) { + return ( + + + + ); +} + +export function IconSearch(props: IconProps) { + return ( + + + + + ); +} + +export function IconGraph(props: IconProps) { + return ( + + + + + + + ); +} + +export function IconAgent(props: IconProps) { + return ( + + + + ); +} + +export function IconReview(props: IconProps) { + return ( + + + + ); +} + +export function IconEmpty(props: IconProps) { + return ( + + + + + ); +} + +export function IconSpark(props: IconProps) { + return ( + + + + ); +} + +export function IconLock(props: IconProps) { + return ( + + + + + ); +} + +export function IconLink(props: IconProps) { + return ( + + + + + ); +} diff --git a/frontend/src/lib/assistant.ts b/frontend/src/lib/assistant.ts index e1d022b..cdb4fd5 100644 --- a/frontend/src/lib/assistant.ts +++ b/frontend/src/lib/assistant.ts @@ -32,7 +32,7 @@ export const WELCOME_MESSAGES: AssistantMessage[] = [ export function summarizeQueryResults(response: QueryResponse): string { const { total, latency_ms, query, results } = response; if (total === 0) { - return `I searched your workspace memory for **"${query}"** but didn't find matching decisions yet. If you're on a fresh install, run \`make demo\` to seed example memories, or capture a decision with **Remember** via the API.`; + return `I searched your workspace memory for **"${query}"** but didn't find matching decisions yet. Connect your tools or capture a decision via **AI agents** to build organizational memory.`; } const top = results[0];