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>
83 lines
2.7 KiB
TypeScript
83 lines
2.7 KiB
TypeScript
'use client';
|
|
|
|
import { useEffect, useState } from 'react';
|
|
import Link from 'next/link';
|
|
import AppLauncher from './AppLauncher';
|
|
|
|
const API_BASE = process.env.NEXT_PUBLIC_API_BASE ?? 'https://cypher.arcrun.dev';
|
|
|
|
type NavUser = {
|
|
display_name: string;
|
|
email: string;
|
|
avatar_url?: string;
|
|
};
|
|
|
|
export default function SiteNav({ currentPath }: { currentPath?: string }) {
|
|
const [user, setUser] = useState<NavUser | null | undefined>(undefined);
|
|
|
|
useEffect(() => {
|
|
fetch(`${API_BASE}/me`, { credentials: 'include' })
|
|
.then(r => r.ok ? r.json() as Promise<NavUser> : null)
|
|
.then(u => setUser(u))
|
|
.catch(() => setUser(null));
|
|
}, []);
|
|
|
|
const logout = async () => {
|
|
await fetch(`${API_BASE}/auth/logout`, { method: 'POST', credentials: 'include' });
|
|
window.location.href = '/';
|
|
};
|
|
|
|
const linkCls = (path: string) =>
|
|
`transition-colors text-sm ${currentPath === path ? 'text-white' : 'text-[#666] hover:text-white'}`;
|
|
|
|
return (
|
|
<nav className="flex items-center justify-between px-6 py-4 border-b border-[#1a1a1a]">
|
|
<Link href="/" className="text-white font-bold text-lg tracking-tight hover:opacity-80 transition-opacity">
|
|
arcrun
|
|
</Link>
|
|
|
|
<div className="flex items-center gap-4 text-sm">
|
|
<Link href="/integrations" className={linkCls('/integrations')}>Integrations</Link>
|
|
<Link href="/api-docs" className={linkCls('/api-docs')}>API</Link>
|
|
<a
|
|
href="https://github.com/richblack/arcrun"
|
|
target="_blank"
|
|
rel="noopener noreferrer"
|
|
className="text-[#666] hover:text-white transition-colors"
|
|
>
|
|
GitHub
|
|
</a>
|
|
|
|
{user === undefined ? (
|
|
// Loading — placeholder to prevent layout shift
|
|
<div className="w-20 h-7" />
|
|
) : user ? (
|
|
<>
|
|
<AppLauncher userEmail={user.email} />
|
|
<Link href="/dashboard" className="flex items-center gap-2 hover:opacity-80 transition-opacity">
|
|
{user.avatar_url && (
|
|
// eslint-disable-next-line @next/next/no-img-element
|
|
<img src={user.avatar_url} alt="" width={26} height={26} className="rounded-full" />
|
|
)}
|
|
<span className="text-[#aaa]">{user.display_name}</span>
|
|
</Link>
|
|
<button
|
|
onClick={logout}
|
|
className="text-[#555] hover:text-[#888] transition-colors cursor-pointer"
|
|
>
|
|
登出
|
|
</button>
|
|
</>
|
|
) : (
|
|
<Link
|
|
href="/login"
|
|
className="bg-indigo-600 hover:bg-indigo-500 text-white px-4 py-1.5 rounded-md font-medium transition-colors"
|
|
>
|
|
Get API Key
|
|
</Link>
|
|
)}
|
|
</div>
|
|
</nav>
|
|
);
|
|
}
|