File size: 4,357 Bytes
29b7dfa
b8dbf99
740e5bf
ae81ce5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7186ef8
ae81ce5
 
 
 
 
 
 
 
 
7186ef8
ae81ce5
 
 
 
 
 
 
 
740e5bf
7186ef8
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
b8dbf99
7186ef8
 
 
 
740e5bf
7186ef8
740e5bf
7186ef8
 
740e5bf
7186ef8
 
 
 
740e5bf
7186ef8
 
740e5bf
 
 
7186ef8
 
 
 
 
 
 
740e5bf
 
7186ef8
 
740e5bf
7186ef8
740e5bf
b8dbf99
740e5bf
7186ef8
740e5bf
7186ef8
740e5bf
 
7186ef8
 
740e5bf
 
7186ef8
740e5bf
ae81ce5
7186ef8
ae81ce5
b8dbf99
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
import React from 'react'
import Dashboard from './components/Dashboard'

class ErrorBoundary extends React.Component {
  constructor(props) {
    super(props)
    this.state = { error: null }
  }
  static getDerivedStateFromError(error) {
    return { error }
  }
  componentDidCatch(error, info) {
    console.error('Dashboard crashed:', error, info)
  }
  render() {
    if (this.state.error) {
      return (
        <div style={{ background: '#fef2f2', border: '1px solid #fca5a5',
          borderRadius: 12, padding: 24, margin: 24, fontFamily: 'system-ui,sans-serif' }}>
          <div style={{ fontSize: 18, fontWeight: 800, color: '#dc2626', marginBottom: 8 }}>
            The dashboard hit a render error
          </div>
          <div style={{ fontSize: 13, color: '#7f1d1d', marginBottom: 12,
            fontFamily: 'monospace', background: '#fff', padding: 12, borderRadius: 8,
            border: '1px solid #fecaca', whiteSpace: 'pre-wrap' }}>
            {String(this.state.error?.message || this.state.error)}
          </div>
          <button onClick={() => this.setState({ error: null })}
            style={{ background: '#dc2626', color: '#fff', border: 'none',
              borderRadius: 8, padding: '10px 18px', fontWeight: 700, cursor: 'pointer' }}>
            Reset Dashboard
          </button>
        </div>
      )
    }
    return this.props.children
  }
}

export default function App() {
  const [theme, setTheme] = React.useState(() => {
    if (typeof window === 'undefined') return 'light'
    return localStorage.getItem('clm-theme') || 'light'
  })

  React.useEffect(() => {
    try { localStorage.setItem('clm-theme', theme) } catch {}
  }, [theme])

  const isDark = theme === 'dark'
  const palette = isDark
    ? { bg: '#0b1220', headerBg: '#0f172a', headerBorder: '#1e293b',
        text: '#e2e8f0', subText: '#94a3b8', border: '#334155',
        bannerFrom: '#1e3a8a', bannerTo: '#0c4a6e' }
    : { bg: '#f1f5f9', headerBg: '#ffffff', headerBorder: '#e2e8f0',
        text: '#0f172a', subText: '#64748b', border: '#cbd5e1',
        bannerFrom: '#4f46e5', bannerTo: '#0ea5e9' }

  return (
    <div style={{ minHeight: '100vh', background: palette.bg,
      fontFamily: 'system-ui,sans-serif', color: palette.text,
      transition: 'background .25s ease, color .25s ease' }}>
      {/* Header */}
      <header style={{
        background: palette.headerBg, position: 'sticky', top: 0, zIndex: 20,
        display: 'flex', alignItems: 'center', gap: 32, padding: '0 24px',
        borderBottom: `1px solid ${palette.headerBorder}`,
        boxShadow: isDark ? '0 1px 3px rgba(0,0,0,.5)' : '0 1px 3px rgba(15,23,42,.06)',
      }}>
        <div style={{ padding: '14px 0', whiteSpace: 'nowrap', flex: 1 }}>
          <span style={{ fontSize: 18, fontWeight: 800, color: palette.text,
            letterSpacing: '-0.4px' }}>
            Cognitive Load Manager
          </span>
          <span style={{ fontSize: 12, color: palette.subText, marginLeft: 10 }}>
            OpenEnv
          </span>
        </div>

        <button onClick={() => setTheme(isDark ? 'light' : 'dark')}
          style={{ fontSize: 12, color: palette.text, background: 'transparent',
            padding: '6px 14px', border: `1px solid ${palette.border}`,
            borderRadius: 6, cursor: 'pointer', fontWeight: 600,
            whiteSpace: 'nowrap' }}>
          {isDark ? 'Light' : 'Dark'} mode
        </button>

        <a href="/docs" target="_blank" rel="noreferrer"
          style={{ fontSize: 12, color: palette.subText, textDecoration: 'none',
            padding: '6px 12px', border: `1px solid ${palette.border}`, borderRadius: 6,
            whiteSpace: 'nowrap' }}>
          API Docs
        </a>
      </header>

      {/* Banner */}
      <div style={{
        background: `linear-gradient(135deg,${palette.bannerFrom} 0%,${palette.bannerTo} 100%)`,
        padding: '10px 24px', textAlign: 'center', fontSize: 13, color: '#fff',
      }}>
        AI agent plays live — press <b>Play Episode</b> to start streaming.
        Switch to <b>Manual</b> to control the agent yourself.
      </div>

      {/* Content */}
      <main style={{ maxWidth: 1400, margin: '0 auto', padding: 24 }}>
        <ErrorBoundary>
          <Dashboard isDark={isDark} />
        </ErrorBoundary>
      </main>
    </div>
  )
}