The AI trust layer between agents: identity, agreements, safeguards, and outcome intelligence for A2A.

Commit 4bfaf3cc

4bfaf3cca6a5Merged

aryaamin <[email protected]> · 2 months ago · 2 files · ~2 modified

Description

feat: add persistent dashboard theme toggle

Details

Commit
4bfaf3cca6a5
Parent
791506c0dbc6

apps/dashboard/src/main.tsxmodifiedView file

@@ -9,8 +9,10 @@
99 type Auth0User = { sub: string; name?: string; email?: string; picture?: string };
1010 type AuthSession = { user: Auth0User };
1111 type AuthTransaction = { state: string; nonce: string; verifier: string };
12+type Theme = 'dark' | 'light';
1213
1314 const authTransactionKey = 'openclasp.auth0.transaction';
15+const themeKey = 'openclasp.theme.v1';
1416
1517 type DashboardData = {
1618 agents: Record<string, any>[];
@@ -113,8 +115,15 @@
113115 return pages.includes(value as Page) ? (value as Page) : 'dashboard';
114116 }
115117
118+function initialTheme(): Theme {
119+ const saved = localStorage.getItem(themeKey);
120+ if (saved === 'dark' || saved === 'light') return saved;
121+ return matchMedia('(prefers-color-scheme: light)').matches ? 'light' : 'dark';
122+}
123+
116124 function App() {
117125 const [session, setSession] = useState<AuthSession | null>();
126+ const [theme, setTheme] = useState<Theme>(initialTheme);
118127 const [page, setPage] = useState<Page>(route());
119128 const [data, setData] = useState<DashboardData>(emptyData);
120129 const [settings, setSettings] = useState<Settings>(defaultSettings);
@@ -135,6 +144,11 @@
135144 }, []);
136145
137146 useEffect(() => {
147+ document.documentElement.dataset.theme = theme;
148+ localStorage.setItem(themeKey, theme);
149+ }, [theme]);
150+
151+ useEffect(() => {
138152 const onPopState = () => setPage(route());
139153 addEventListener('popstate', onPopState);
140154 return () => removeEventListener('popstate', onPopState);
@@ -183,6 +197,14 @@
183197 <Nav page="connect" active={page} onClick={navigate} label="Connect" glyph="+" />
184198 <Nav page="settings" active={page} onClick={navigate} label="Settings" glyph="⚙" />
185199 </nav>
200+ <button
201+ className="themeSwitch"
202+ onClick={() => setTheme((current) => (current === 'dark' ? 'light' : 'dark'))}
203+ aria-label={`Switch to ${theme === 'dark' ? 'light' : 'dark'} theme`}
204+ >
205+ <span>{theme === 'dark' ? '☼' : '◐'}</span>
206+ {theme === 'dark' ? 'Light theme' : 'Dark theme'}
207+ </button>
186208 <div className="privacyStamp">
187209 <span className="liveDot" />
188210 <div>