flagon-io/g1t

public

Where people and agents ship software together. The open-source git platform for the whole job: issues, agents, checks and deploys to the edge.

Account settings in the same shape as a workspace's #4

Mergedsyntaqx merged account-settings into main
2 files+54−110/2 viewed
+42−3
285285 );
286286 }
287287
288+/** Your own settings, as the sidebar shows them on the settings page. */
289+function AccountSettingsMenu({ open }: { open: boolean }) {
290+ const { hash } = useLocation();
291+ const item = (id: string, icon: ReactNode, label: string) => (
292+ <Link
293+ to={`/settings#${id}`}
294+ className={`group flex h-8 items-center gap-2.5 rounded-md px-2 text-[0.8125rem] transition-colors ${
295+ hash === `#${id}` ? "bg-raised font-medium text-fg" : "text-muted hover:bg-raised/60 hover:text-fg"
296+ }`}
297+ >
298+ <span className="shrink-0 text-faint group-hover:text-muted">{icon}</span>
299+ {label}
300+ </Link>
301+ );
302+ return (
303+ <nav
304+ aria-label="Your settings"
305+ inert={!open}
306+ className={`${SLIDE} ${open ? "translate-x-0 opacity-100" : "pointer-events-none translate-x-full opacity-0"}`}
307+ >
308+ <Link
309+ to="/"
310+ className="group mt-3 flex h-8 items-center gap-2 rounded-md px-2 text-[0.8125rem] text-muted transition-colors hover:bg-raised/60 hover:text-fg"
311+ >
312+ <ArrowLeft size={15} className="text-faint transition-transform group-hover:-translate-x-0.5 group-hover:text-muted" />
313+ Mission control
314+ </Link>
315+ <SidebarGroup title="Account">
316+ {item("ssh-keys", <KeyRound size={15} />, "SSH keys")}
317+ {item("tokens", <Lock size={15} />, "Access tokens")}
318+ {item("applications", <Plug size={15} />, "Connected applications")}
319+ </SidebarGroup>
320+ </nav>
321+ );
322+}
323+
288324 function Sidebar({ user, shell, onFind }: { user: User; shell: ShellData; onFind: () => void }) {
289325 const ws = shell.workspace;
290326 const { pathname } = useLocation();
292328 // On a workspace's settings page, or on the way to one, its settings take
293329 // the sidebar over.
294330 const inSettings = ws != null && SETTINGS_PAGE.exec(going ?? pathname)?.[1]?.toLowerCase() === ws.slug;
331+ const inAccount = (going ?? pathname) === "/settings";
332+ const away = inSettings || inAccount;
295333 const active = shell.repo;
296334 const repoBase = active ? `/${active.namespace}/${active.name}` : null;
297335 // The repository being looked at is listed even when it is someone else's.
325363 <div className="relative min-h-0 grow overflow-hidden">
326364 <nav
327365 aria-label="g1t"
328− inert={inSettings}
329− className={`${SLIDE} ${inSettings ? "pointer-events-none -translate-x-1/3 opacity-0" : "translate-x-0 opacity-100"}`}
366+ inert={away}
367+ className={`${SLIDE} ${away ? "pointer-events-none -translate-x-1/3 opacity-0" : "translate-x-0 opacity-100"}`}
330368 >
331369 <div className="mt-3 space-y-px">
332370 <SidebarLink to="/" end icon={<LayoutDashboard size={15} />}>
438476 </SidebarGroup>
439477 </nav>
440478 {ws && <SettingsMenu slug={ws.slug} owner={ws.role === "owner"} open={inSettings} />}
479+ <AccountSettingsMenu open={inAccount} />
441480 </div>
442481
443482 <div className="space-y-2 p-2">
472511 if (parts.length === 0) return <span className="text-sm font-medium">Mission control</span>;
473512 if (reserved.includes(parts[0]!)) {
474513 const words: Record<string, string> = {
475− settings: "Your settings",
514+ settings: "Account",
476515 explore: "Explore",
477516 new: "New repository",
478517 search: "Search",
+12−8
8080 }: Route.ComponentProps) {
8181 const { user, keys, tokens, applications } = loaderData;
8282 return (
83− <main className="mx-auto max-w-2xl space-y-12 px-4 py-12">
84− <h1 className="text-xl font-semibold">
85− Settings <span className="font-mono text-muted">{user.username}</span>
86− </h1>
87−
88− <section>
83+ <main className="mx-auto max-w-5xl px-4 py-10 sm:px-8">
84+ <header className="mb-8 border-b border-line pb-6">
85+ <h1 className="text-2xl font-semibold tracking-tight">Account</h1>
86+ <p className="mt-1.5 text-sm text-muted">
87+ How <span className="font-mono text-fg">{user.username}</span> signs in from git, tools and agents.
88+ </p>
89+ </header>
90+ <div className="max-w-2xl space-y-12">
91+ <section id="ssh-keys" className="scroll-mt-20">
8992 <h2 className="font-medium">SSH keys</h2>
9093 <ul className="mt-4 divide-y divide-line rounded-md border border-line empty:hidden">
9194 {keys.map((key) => (
113116 </Form>
114117 </section>
115118
116− <section>
119+ <section id="tokens" className="scroll-mt-20">
117120 <h2 className="font-medium">Access tokens</h2>
118121 <p className="mt-1 text-sm text-muted">
119122 Use a token as the password when git asks for one over HTTPS, and to
176179 </Form>
177180 </section>
178181
179− <section>
182+ <section id="applications" className="scroll-mt-20">
180183 <h2 className="font-medium">Connected applications</h2>
181184 <p className="mt-1 text-sm text-muted">
182185 Applications you signed in to through your browser, such as an agent
206209 </ul>
207210 )}
208211 </section>
212+ </div>
209213 </main>
210214 );
211215 }