Skip to content
File

Blob: src/client/components/app-shell.tsx

typescript53 lines
1import { useMemo, useState } from "react";
2import { Outlet } from "react-router-dom";
3import { Header } from "@/client/components/header";
4import { Footer } from "@/client/components/footer";
5import { ToastContainer } from "@/client/components/toast";
6import { loadInboxSessions, storeInboxSession, type InboxSession, type InboxSessionSummary } from "@/client/lib/api";
7 
8export interface AppShellContext {
9 sessions: InboxSessionSummary[];
10 onCreated: (session: InboxSession) => void;
11 onDeleted: (address: string) => void;
12}
13 
14export function AppShell() {
15 const [sessions, setSessions] = useState<InboxSessionSummary[]>(() => loadInboxSessions());
16 const sessionCount = useMemo(() => sessions.length, [sessions]);
17 
18 const handleCreated = (session: InboxSession) => {
19 setSessions(storeInboxSession(session));
20 };
21 
22 const handleDeleted = (_address: string) => {
23 setSessions(loadInboxSessions());
24 };
25 
26 const context: AppShellContext = {
27 sessions,
28 onCreated: handleCreated,
29 onDeleted: handleDeleted,
30 };
31 
32 return (
33 <div className="relative z-10 flex min-h-screen flex-col sm:h-screen">
34 <a
35 href="#main-content"
36 className="sr-only focus:not-sr-only focus:fixed focus:top-4 focus:left-4 focus:z-200 focus:rounded-lg focus:bg-zinc-900 focus:px-4 focus:py-2 focus:text-accent-400 focus:ring-2 focus:ring-accent-500/50"
37 >
38 Skip to content
39 </a>
40 <Header sessionCount={sessionCount} />
41 <main id="main-content" className="flex-1 sm:overflow-y-auto">
42 <div className="mx-auto max-w-7xl px-4 py-6 sm:px-6">
43 <div className="animate-slide-up">
44 <Outlet context={context} />
45 </div>
46 </div>
47 </main>
48 <Footer />
49 <ToastContainer />
50 </div>
51 );
52}