feat: architectural grid editor fullPage + slash commands + doc info panel + AI title
This commit is contained in:
@@ -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">
|
||||
|
||||
Reference in New Issue
Block a user