922a57fe34
Self-hosted 開源:WASM 零件 + recipe + cypher-executor,跑在你自己的 Cloudflare。 此為重建的乾淨歷史起點(移除曾誤 commit 的 GCP SA 金鑰,舊歷史保留在 richblack/arcrun 與本地 backup 分支)。含: - acr init --self-hosted installer(建 KV/R2 + codeload 拉預編譯 wasm + wrangler deploy + seed recipe) - recipe push 把關(資料外流提醒 + 打通檢查) - 19 個正當零件預編譯 wasm(claude_api/km_writer/kbdb_upsert_block 排除:違反 DECISIONS §1) - CLI / cypher-executor / registry / 完整 SDD Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
57 lines
1.5 KiB
React
57 lines
1.5 KiB
React
// App root — screen switcher with persistent route
|
|
const { useState, useEffect } = React;
|
|
|
|
const SCREENS = [
|
|
{ id: 'landing', label: 'Landing' },
|
|
{ id: 'auth', label: 'Auth' },
|
|
{ id: 'dashboard', label: 'Dashboard' },
|
|
{ id: 'keys', label: 'API Keys' },
|
|
{ id: 'workflow', label: 'Workflow' },
|
|
];
|
|
|
|
// Synonyms from sidebar ids
|
|
const aliases = { apps: 'dashboard', workflows: 'dashboard', docs: 'landing', settings: 'keys' };
|
|
|
|
function App() {
|
|
const [screen, setScreen] = useState(() => {
|
|
const saved = localStorage.getItem('arcrun:screen');
|
|
return saved && SCREENS.some(s => s.id === saved) ? saved : 'landing';
|
|
});
|
|
|
|
useEffect(() => {
|
|
localStorage.setItem('arcrun:screen', screen);
|
|
window.scrollTo(0, 0);
|
|
}, [screen]);
|
|
|
|
const nav = (id) => {
|
|
const resolved = aliases[id] || id;
|
|
if (SCREENS.some(s => s.id === resolved)) setScreen(resolved);
|
|
};
|
|
|
|
const Current = {
|
|
landing: Landing,
|
|
auth: Auth,
|
|
dashboard: Dashboard,
|
|
keys: ApiKeys,
|
|
workflow: WorkflowViewer,
|
|
}[screen];
|
|
|
|
return (
|
|
<div className="app">
|
|
<Current onNav={nav} />
|
|
|
|
<div className="proto-switch" role="tablist" aria-label="Screen switcher">
|
|
{SCREENS.map(s => (
|
|
<button key={s.id}
|
|
className={screen === s.id ? 'active' : ''}
|
|
onClick={() => nav(s.id)}>
|
|
{s.label}
|
|
</button>
|
|
))}
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
ReactDOM.createRoot(document.getElementById('root')).render(<App />);
|