Next.js app — chat interface, auth, settings, PWA manifest
This commit is contained in:
+103
-55
@@ -1,65 +1,113 @@
|
||||
import Image from "next/image";
|
||||
'use client';
|
||||
|
||||
import { useEffect } from 'react';
|
||||
import { useStore } from '@/lib/store';
|
||||
import { api } from '@/lib/api';
|
||||
import Sidebar from '@/components/Sidebar';
|
||||
import MessageList from '@/components/MessageList';
|
||||
import MessageInput from '@/components/MessageInput';
|
||||
import SettingsPanel from '@/components/SettingsPanel';
|
||||
|
||||
export default function Home() {
|
||||
const {
|
||||
settings,
|
||||
setSettings,
|
||||
setConversations,
|
||||
setCurrentId,
|
||||
setMessages,
|
||||
currentId,
|
||||
settingsOpen,
|
||||
sidebarOpen,
|
||||
setSidebarOpen,
|
||||
} = useStore();
|
||||
|
||||
useEffect(() => {
|
||||
// Load settings from server
|
||||
api.getSettings().then(setSettings).catch(console.error);
|
||||
// Load conversations
|
||||
api.getConversations().then(setConversations).catch(console.error);
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
// Load messages when conversation changes
|
||||
if (currentId) {
|
||||
api.getMessages(currentId).then(setMessages).catch(console.error);
|
||||
} else {
|
||||
setMessages([]);
|
||||
}
|
||||
}, [currentId]);
|
||||
|
||||
return (
|
||||
<div className="flex flex-col flex-1 items-center justify-center bg-zinc-50 font-sans dark:bg-black">
|
||||
<main className="flex flex-1 w-full max-w-3xl flex-col items-center justify-between py-32 px-16 bg-white dark:bg-black sm:items-start">
|
||||
<Image
|
||||
className="dark:invert"
|
||||
src="/next.svg"
|
||||
alt="Next.js logo"
|
||||
width={100}
|
||||
height={20}
|
||||
priority
|
||||
<div
|
||||
className="flex h-dvh overflow-hidden"
|
||||
style={{ background: 'var(--bg)' }}
|
||||
data-theme={settings.theme}
|
||||
data-font={settings.font_size}
|
||||
>
|
||||
{/* Mobile sidebar overlay */}
|
||||
{sidebarOpen && (
|
||||
<div
|
||||
className="fixed inset-0 z-20 bg-black/40 md:hidden"
|
||||
onClick={() => setSidebarOpen(false)}
|
||||
/>
|
||||
<div className="flex flex-col items-center gap-6 text-center sm:items-start sm:text-left">
|
||||
<h1 className="max-w-xs text-3xl font-semibold leading-10 tracking-tight text-black dark:text-zinc-50">
|
||||
To get started, edit the page.tsx file.
|
||||
</h1>
|
||||
<p className="max-w-md text-lg leading-8 text-zinc-600 dark:text-zinc-400">
|
||||
Looking for a starting point or more instructions? Head over to{" "}
|
||||
<a
|
||||
href="https://vercel.com/templates?framework=next.js&utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
|
||||
className="font-medium text-zinc-950 dark:text-zinc-50"
|
||||
)}
|
||||
|
||||
{/* Sidebar */}
|
||||
<div
|
||||
className={`
|
||||
fixed inset-y-0 left-0 z-30 w-72 transform transition-transform duration-200
|
||||
md:relative md:translate-x-0 md:w-64 md:flex-shrink-0
|
||||
${sidebarOpen ? 'translate-x-0' : '-translate-x-full'}
|
||||
`}
|
||||
style={{ background: 'var(--sidebar-bg)', borderRight: '1px solid var(--border)' }}
|
||||
>
|
||||
<Sidebar />
|
||||
</div>
|
||||
|
||||
{/* Main */}
|
||||
<div className="flex flex-col flex-1 min-w-0">
|
||||
{/* Topbar */}
|
||||
<div
|
||||
className="flex items-center justify-between px-4 py-3 flex-shrink-0"
|
||||
style={{ borderBottom: '1px solid var(--border)' }}
|
||||
>
|
||||
<div className="flex items-center gap-3">
|
||||
{/* Hamburger — mobile only */}
|
||||
<button
|
||||
className="md:hidden p-1 rounded"
|
||||
style={{ color: 'var(--text3)' }}
|
||||
onClick={() => setSidebarOpen(!sidebarOpen)}
|
||||
aria-label="Toggle sidebar"
|
||||
>
|
||||
Templates
|
||||
</a>{" "}
|
||||
or the{" "}
|
||||
<a
|
||||
href="https://nextjs.org/learn?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
|
||||
className="font-medium text-zinc-950 dark:text-zinc-50"
|
||||
>
|
||||
Learning
|
||||
</a>{" "}
|
||||
center.
|
||||
</p>
|
||||
</div>
|
||||
<div className="flex flex-col gap-4 text-base font-medium sm:flex-row">
|
||||
<a
|
||||
className="flex h-12 w-full items-center justify-center gap-2 rounded-full bg-foreground px-5 text-background transition-colors hover:bg-[#383838] dark:hover:bg-[#ccc] md:w-[158px]"
|
||||
href="https://vercel.com/new?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
<svg width="20" height="20" viewBox="0 0 20 20" fill="currentColor">
|
||||
<rect y="3" width="20" height="2" rx="1"/>
|
||||
<rect y="9" width="20" height="2" rx="1"/>
|
||||
<rect y="15" width="20" height="2" rx="1"/>
|
||||
</svg>
|
||||
</button>
|
||||
<span style={{ fontSize: '13px', color: 'var(--text3)' }}>
|
||||
<strong style={{ color: 'var(--text)', fontWeight: 500 }}>Aaron AI</strong>
|
||||
{' '}— personal knowledge assistant
|
||||
</span>
|
||||
</div>
|
||||
<button
|
||||
onClick={() => useStore.getState().setSettingsOpen(!settingsOpen)}
|
||||
style={{ color: 'var(--text3)', background: 'none', border: 'none', cursor: 'pointer', padding: '4px', borderRadius: '6px', fontSize: '18px' }}
|
||||
aria-label="Settings"
|
||||
>
|
||||
<Image
|
||||
className="dark:invert"
|
||||
src="/vercel.svg"
|
||||
alt="Vercel logomark"
|
||||
width={16}
|
||||
height={16}
|
||||
/>
|
||||
Deploy Now
|
||||
</a>
|
||||
<a
|
||||
className="flex h-12 w-full items-center justify-center rounded-full border border-solid border-black/[.08] px-5 transition-colors hover:border-transparent hover:bg-black/[.04] dark:border-white/[.145] dark:hover:bg-[#1a1a1a] md:w-[158px]"
|
||||
href="https://nextjs.org/docs?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
Documentation
|
||||
</a>
|
||||
⚙
|
||||
</button>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
{/* Messages */}
|
||||
<MessageList />
|
||||
|
||||
{/* Input */}
|
||||
<MessageInput />
|
||||
</div>
|
||||
|
||||
{/* Settings panel */}
|
||||
<SettingsPanel />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user