feat: architectural grid editor fullPage + slash commands + doc info panel + AI title

This commit is contained in:
Antigravity
2026-05-07 22:29:02 +00:00
parent 0d8252aec0
commit e458b63115
126 changed files with 7652 additions and 1110 deletions

View File

@@ -25,6 +25,7 @@ import { useLabels } from '@/context/LabelContext'
import { LabelFilter } from './label-filter'
import { NotificationPanel } from './notification-panel'
import { updateTheme } from '@/app/actions/profile'
import { applyDocumentTheme, normalizeThemeId } from '@/lib/apply-document-theme'
import { useDebounce } from '@/hooks/use-debounce'
import { useLanguage } from '@/lib/i18n'
import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar'
@@ -46,7 +47,7 @@ export function Header({
user
}: HeaderProps = {}) {
const [searchQuery, setSearchQuery] = useState('')
const [theme, setTheme] = useState<'light' | 'dark'>('light')
const [theme, setTheme] = useState<string>('light')
const [isSidebarOpen, setIsSidebarOpen] = useState(false)
const [isSemanticSearching, setIsSemanticSearching] = useState(false)
const pathname = usePathname()
@@ -167,24 +168,13 @@ export function Header({
}, [currentUser])
const applyTheme = async (newTheme: string, persist = true) => {
setTheme(newTheme as any)
localStorage.setItem('theme-preference', newTheme)
// Remove all theme classes first
document.documentElement.classList.remove('dark')
document.documentElement.removeAttribute('data-theme')
if (newTheme === 'dark') {
document.documentElement.classList.add('dark')
} else if (newTheme !== 'light') {
document.documentElement.setAttribute('data-theme', newTheme)
if (newTheme === 'midnight') {
document.documentElement.classList.add('dark')
}
}
const normalized = normalizeThemeId(newTheme)
setTheme(normalized)
localStorage.setItem('theme-preference', normalized)
applyDocumentTheme(normalized)
if (persist && currentUser) {
await updateTheme(newTheme)
await updateTheme(normalized)
}
}
@@ -265,10 +255,10 @@ export function Header({
<button
onClick={onClick}
className={cn(
"w-full flex items-center gap-3 px-4 py-3 rounded-r-full text-sm font-medium transition-colors mr-2 text-left",
"w-full flex items-center gap-3 px-4 py-3 rounded-lg text-sm font-medium transition-all duration-200 mr-2 text-left",
active
? "bg-primary/10 text-primary dark:bg-primary/20 dark:text-primary-foreground"
: "hover:bg-gray-100 dark:hover:bg-zinc-800 text-gray-700 dark:text-gray-300"
? "bg-primary/10 text-primary dark:bg-primary/15 dark:text-primary"
: "hover:bg-gray-100 dark:hover:bg-white/5 text-gray-700 dark:text-gray-300"
)}
style={{ minHeight: '44px' }}
aria-pressed={active}
@@ -283,10 +273,10 @@ export function Header({
href={href}
onClick={() => setIsSidebarOpen(false)}
className={cn(
"flex items-center gap-3 px-4 py-3 rounded-r-full text-sm font-medium transition-colors mr-2",
"flex items-center gap-3 px-4 py-3 rounded-lg text-sm font-medium transition-all duration-200 mr-2",
active
? "bg-primary/10 text-primary dark:bg-primary/20 dark:text-primary-foreground"
: "hover:bg-gray-100 dark:hover:bg-zinc-800 text-gray-700 dark:text-gray-300"
? "bg-primary/10 text-primary dark:bg-primary/15 dark:text-primary"
: "hover:bg-gray-100 dark:hover:bg-white/5 text-gray-700 dark:text-gray-300"
)}
style={{ minHeight: '44px' }}
aria-current={active ? 'page' : undefined}
@@ -301,26 +291,27 @@ export function Header({
return (
<>
{/* Top Navigation - Style Keep */}
<header className="flex-none flex items-center justify-between whitespace-nowrap border-b border-solid border-slate-200 dark:border-slate-800 bg-white dark:bg-[#1e2128] px-6 py-3 z-20">
<div className="flex items-center gap-8">
<header className="flex-none flex items-center justify-between whitespace-nowrap border-b border-border/50 bg-card/85 backdrop-blur-xl px-5 py-3 z-20 shadow-sm md:px-8">
<div className="flex items-center gap-6 md:gap-10">
{/* Logo MEMENTO */}
<div className="flex items-center gap-3 text-slate-900 dark:text-white cursor-pointer group" onClick={() => router.push('/')}>
<div className="size-8 bg-primary rounded-lg flex items-center justify-center text-primary-foreground shadow-sm group-hover:shadow-md transition-all">
<StickyNote className="w-5 h-5" />
{/* Wordmark */}
<div className="flex cursor-pointer items-center gap-3 text-foreground group" onClick={() => router.push('/')}>
<div className="flex size-9 items-center justify-center rounded-xl bg-primary text-primary-foreground shadow-md shadow-primary/20 transition-all duration-200 group-hover:shadow-lg group-hover:shadow-primary/25">
<StickyNote className="w-[1.15rem] h-[1.15rem]" strokeWidth={2} />
</div>
<h2 className="text-xl font-bold leading-tight tracking-tight">MEMENTO</h2>
<h2 className="font-memento-serif text-[1.35rem] font-normal tracking-tight leading-none md:text-2xl">Memento</h2>
</div>
{/* Search Bar */}
<label className="hidden md:flex flex-col min-w-40 w-96 !h-10">
<div className="flex w-full flex-1 items-stretch rounded-full h-full bg-slate-100 dark:bg-slate-800 border border-transparent focus-within:bg-white dark:focus-within:bg-slate-700 focus-within:border-primary/30 focus-within:shadow-md transition-all duration-200">
<div className="text-slate-400 dark:text-slate-400 flex items-center justify-center pl-4 focus-within:text-primary transition-colors">
<div className="flex w-full flex-1 items-stretch rounded-xl h-full bg-muted/50 border border-transparent focus-within:bg-card focus-within:border-primary/35 focus-within:shadow-[0_0_0_3px_color-mix(in_oklab,var(--primary)_18%,transparent)] transition-all duration-200">
<div className="text-muted-foreground flex items-center justify-center pl-4 focus-within:text-primary transition-colors">
<Search className="w-4 h-4" />
</div>
<input
className="form-input flex w-full min-w-0 flex-1 resize-none overflow-hidden bg-transparent border-none text-slate-900 dark:text-white placeholder:text-slate-400 dark:placeholder:text-slate-500 px-3 text-sm focus:ring-0 focus:outline-none"
id="memento-global-search"
className="form-input flex w-full min-w-0 flex-1 resize-none overflow-hidden bg-transparent border-none text-foreground placeholder:text-muted-foreground px-3 text-sm focus:ring-0 focus:outline-none"
placeholder={t('search.placeholder') }
type="text"
value={searchQuery}
@@ -333,15 +324,15 @@ export function Header({
<div className="flex flex-1 justify-end gap-2 items-center">
{/* Quick nav: Notes (hidden-sidebar only), Chat, Agents, Lab */}
<div className="hidden md:flex items-center gap-1 bg-slate-100 dark:bg-slate-800/60 rounded-full px-1.5 py-1">
<div className="hidden md:flex items-center gap-1 rounded-xl bg-muted/60 px-1.5 py-1 ring-1 ring-border/50">
{noSidebarMode && (
<Link
href="/"
className={cn(
"flex items-center justify-center gap-1.5 px-3 py-1.5 rounded-full text-xs font-medium transition-colors",
"flex items-center justify-center gap-1.5 px-3 py-1.5 rounded-lg text-xs font-medium transition-all duration-200",
pathname === '/'
? "bg-white dark:bg-slate-700 text-primary shadow-sm"
: "text-muted-foreground hover:text-foreground"
? "bg-card text-primary shadow-sm ring-1 ring-primary/15"
: "text-muted-foreground hover:text-foreground hover:bg-muted/80"
)}
>
<StickyNote className="h-3.5 w-3.5" />
@@ -351,10 +342,10 @@ export function Header({
<Link
href="/agents"
className={cn(
"flex items-center justify-center gap-1.5 px-3 py-1.5 rounded-full text-xs font-medium transition-colors",
"flex items-center justify-center gap-1.5 px-3 py-1.5 rounded-lg text-xs font-medium transition-all duration-200",
pathname === '/agents'
? "bg-white dark:bg-slate-700 text-primary shadow-sm"
: "text-muted-foreground hover:text-foreground"
? "bg-card text-primary shadow-sm ring-1 ring-primary/15"
: "text-muted-foreground hover:text-foreground hover:bg-muted/80"
)}
>
<Bot className="h-3.5 w-3.5" />
@@ -363,10 +354,10 @@ export function Header({
<Link
href="/lab"
className={cn(
"flex items-center justify-center gap-1.5 px-3 py-1.5 rounded-full text-xs font-medium transition-colors",
pathname === '/lab'
? "bg-white dark:bg-slate-700 text-primary shadow-sm"
: "text-muted-foreground hover:text-foreground"
"flex items-center justify-center gap-1.5 px-3 py-1.5 rounded-lg text-xs font-medium transition-all duration-200",
pathname === '/lab'
? "bg-card text-primary shadow-sm ring-1 ring-primary/15"
: "text-muted-foreground hover:text-foreground hover:bg-muted/80"
)}
>
<FlaskConical className="h-3.5 w-3.5" />
@@ -380,7 +371,7 @@ export function Header({
{/* Settings Button */}
<Link
href="/settings"
className="flex items-center justify-center size-10 rounded-full hover:bg-slate-100 dark:hover:bg-slate-800 text-slate-600 dark:text-slate-300 transition-colors"
className="flex items-center justify-center size-10 rounded-xl text-muted-foreground hover:bg-muted/80 hover:text-foreground transition-colors duration-200"
>
<Settings className="w-5 h-5" />
</Link>
@@ -388,7 +379,7 @@ export function Header({
{/* User Avatar Menu */}
<DropdownMenu>
<DropdownMenuTrigger asChild>
<div className="flex items-center justify-center bg-center bg-no-repeat bg-cover rounded-full size-10 ring-2 ring-white dark:ring-slate-700 cursor-pointer shadow-sm hover:shadow-md transition-shadow bg-primary/10 dark:bg-primary/20 text-primary dark:text-primary-foreground"
<div className="flex items-center justify-center bg-center bg-no-repeat bg-cover rounded-xl size-10 ring-2 ring-border/60 cursor-pointer shadow-sm hover:shadow-md transition-shadow duration-200 bg-primary/10 text-primary"
style={currentUser?.image ? { backgroundImage: `url(${currentUser?.image})` } : undefined}>
{!currentUser?.image && (
<span className="text-sm font-semibold">