Add a Production dashboard with an animated knowledge graph
The sidebar now groups Production under Dashboard and the four existing pages under Settings, and Production is the landing page. It shows content in progress, material, content made, approved and LMS-ready counts, plus a knowledge graph linking Brain documents, results, found sources and schedules, with the schedule and what is being made right now beside it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -7,13 +7,21 @@ import { workspaceCredits } from '../api/engine'
|
||||
import { Brand, Icon, type IconName } from './Icon'
|
||||
import { Toaster } from './Toast'
|
||||
|
||||
// Express Mode has four doors: feed the Brain, give an instruction, watch the schedule, collect results.
|
||||
export const NAV: { to: string; label: Key; icon: IconName }[] = [
|
||||
{ to: '/brain', label: 'nav.brain', icon: 'brain' },
|
||||
{ to: '/instruction', label: 'nav.instruction', icon: 'spark' },
|
||||
{ to: '/schedule', label: 'nav.schedule', icon: 'calendar' },
|
||||
{ to: '/results', label: 'nav.results', icon: 'layers' },
|
||||
// The Production dashboard shows what Express is making; the four settings doors run it:
|
||||
// feed the Brain, give an instruction, watch the schedule, collect results.
|
||||
export const NAV_GROUPS: { label: Key; items: { to: string; label: Key; icon: IconName }[] }[] = [
|
||||
{ label: 'nav.dashboard', items: [{ to: '/production', label: 'nav.production', icon: 'chart' }] },
|
||||
{
|
||||
label: 'nav.settings',
|
||||
items: [
|
||||
{ to: '/brain', label: 'nav.brain', icon: 'brain' },
|
||||
{ to: '/instruction', label: 'nav.instruction', icon: 'spark' },
|
||||
{ to: '/schedule', label: 'nav.schedule', icon: 'calendar' },
|
||||
{ to: '/results', label: 'nav.results', icon: 'layers' },
|
||||
],
|
||||
},
|
||||
]
|
||||
export const NAV = NAV_GROUPS.flatMap(g => g.items)
|
||||
|
||||
export function LanguageSwitch() {
|
||||
const lang = useLang()
|
||||
@@ -129,15 +137,17 @@ export function AppLayout() {
|
||||
return (
|
||||
<div className="app">
|
||||
<aside className="sidebar">
|
||||
<NavLink to="/brain"><Brand /></NavLink>
|
||||
<NavLink to="/production"><Brand /></NavLink>
|
||||
<OrgSwitcher />
|
||||
<div className="nav-label">{t('nav.workspace')}</div>
|
||||
<nav aria-label={t('layout.mainNav')}>
|
||||
{NAV.map(n => (
|
||||
<NavLink key={n.to} to={n.to} className={({ isActive }) => (isActive ? 'active' : undefined)}>
|
||||
<Icon name={n.icon} />{t(n.label)}
|
||||
</NavLink>
|
||||
))}
|
||||
{NAV_GROUPS.map(g => [
|
||||
<div key={g.label} className="nav-label">{t(g.label)}</div>,
|
||||
...g.items.map(n => (
|
||||
<NavLink key={n.to} to={n.to} className={({ isActive }) => (isActive ? 'active' : undefined)}>
|
||||
<Icon name={n.icon} />{t(n.label)}
|
||||
</NavLink>
|
||||
)),
|
||||
])}
|
||||
</nav>
|
||||
<div className="sidebar-help">
|
||||
<Icon name="info" />
|
||||
|
||||
@@ -23,6 +23,7 @@ const paths: Record<string, string> = {
|
||||
video: '<rect x="3" y="5" width="18" height="14" rx="3"/><path d="m10 9 5 3-5 3z"/>',
|
||||
audio: '<path d="M4 13v-2a8 8 0 0 1 16 0v2"/><rect x="3" y="11" width="4" height="8" rx="2"/><rect x="17" y="11" width="4" height="8" rx="2"/>',
|
||||
scorm: '<path d="m12 3 9 5-9 5-9-5zM3 8v9l9 5 9-5V8M12 13v9"/>',
|
||||
chart: '<path d="M4 20V10M10 20V4M16 20v-7M22 20H2"/>',
|
||||
coin: '<circle cx="12" cy="12" r="9"/><path d="M15 9.5c-.5-1-1.6-1.5-3-1.5-1.7 0-3 .8-3 2s1.3 1.7 3 2 3 .8 3 2-1.3 2-3 2c-1.4 0-2.5-.5-3-1.5M12 6v2M12 16v2"/>',
|
||||
brain: '<path d="M12 5c-3-4-8-1-7 3-4 2-3 7 0 8-1 4 5 6 7 2M12 5c3-4 8-1 7 3 4 2 3 7 0 8 1 4-5 6-7 2M12 5v15M7 9l3 2M17 9l-3 2M6 15l3-1M18 15l-3-1"/>',
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user