fix: restore Expand/Minimize button in AI panel + dynamic width, note thumbnail SVG placeholder with emoji/letter

This commit is contained in:
Antigravity
2026-05-07 23:33:20 +00:00
parent 3b036e84b8
commit 38c637cfac
3 changed files with 71 additions and 3 deletions

View File

@@ -516,7 +516,8 @@ export function ContextualAIChat({
return ( return (
<aside className={cn( <aside className={cn(
'border-l border-border/40 bg-background flex flex-col h-full w-full flex-shrink-0 z-10 transition-all duration-300', 'border-l border-border/40 bg-background flex flex-col h-full flex-shrink-0 z-10 transition-all duration-300',
expanded ? 'w-[560px]' : 'w-[360px]',
className, className,
)}> )}>
@@ -553,6 +554,16 @@ export function ContextualAIChat({
<Wand2 className="h-3.5 w-3.5" /> <Wand2 className="h-3.5 w-3.5" />
</Button> </Button>
)} )}
<Button
variant="ghost" size="icon"
className="h-7 w-7 text-muted-foreground hover:text-foreground"
onClick={() => setExpanded(e => !e)}
title={expanded ? t('ai.shrinkPanel') : t('ai.expandPanel')}
>
{expanded
? <Minimize2 className="h-3.5 w-3.5" />
: <Maximize2 className="h-3.5 w-3.5" />}
</Button>
<Button variant="ghost" size="icon" onClick={onClose} className="h-7 w-7 text-muted-foreground hover:text-foreground"> <Button variant="ghost" size="icon" onClick={onClose} className="h-7 w-7 text-muted-foreground hover:text-foreground">
<X className="h-3.5 w-3.5" /> <X className="h-3.5 w-3.5" />
</Button> </Button>

View File

@@ -899,7 +899,7 @@ export function NoteEditor({ note, readOnly = false, onClose, fullPage = false }
{/* ── Side panel: AI Chat ── */} {/* ── Side panel: AI Chat ── */}
{aiOpen && ( {aiOpen && (
<div className="w-[400px] h-full self-stretch border-l border-black/10 dark:border-white/10 bg-background flex flex-col z-50 shrink-0"> <div className="h-full self-stretch bg-background flex flex-col z-50 shrink-0">
<ContextualAIChat <ContextualAIChat
onClose={() => setAiOpen(false)} onClose={() => setAiOpen(false)}
noteTitle={title} noteTitle={title}

View File

@@ -116,6 +116,63 @@ function EditorialNoteMenu({ note, onOpen, onOpenHistory }: {
) )
} }
/** Deterministic hue from a string — consistent per note */
function stringToHue(s: string): number {
let h = 0
for (let i = 0; i < s.length; i++) h = (h * 31 + s.charCodeAt(i)) & 0xffff
return h % 360
}
/** SVG thumbnail for notes without an image */
function NoteThumbnailPlaceholder({ title, noteId }: { title: string; noteId: string }) {
// Try to extract the first emoji from the title
const emojiMatch = title.match(/\p{Emoji_Presentation}|\p{Emoji}\uFE0F/u)
const emoji = emojiMatch?.[0]
const letter = title.replace(/\p{Emoji_Presentation}|\p{Emoji}\uFE0F/gu, '').trim()[0]?.toUpperCase() || '?'
const hue = stringToHue(noteId)
return (
<div
className="h-full w-full flex items-center justify-center relative overflow-hidden"
style={{ background: `linear-gradient(145deg, hsl(${hue} 25% 94%) 0%, hsl(${hue} 18% 87%) 100%)` }}
>
{/* Decorative concentric circles */}
<svg
className="absolute inset-0 w-full h-full"
viewBox="0 0 224 168"
fill="none"
aria-hidden
style={{ color: `hsl(${hue} 30% 60%)` }}
>
<circle cx="112" cy="84" r="90" stroke="currentColor" strokeWidth="0.6" opacity="0.25" />
<circle cx="112" cy="84" r="64" stroke="currentColor" strokeWidth="0.6" opacity="0.2" />
<circle cx="112" cy="84" r="38" stroke="currentColor" strokeWidth="0.6" opacity="0.15" />
<line x1="22" y1="84" x2="202" y2="84" stroke="currentColor" strokeWidth="0.4" opacity="0.15" />
<line x1="112" y1="4" x2="112" y2="164" stroke="currentColor" strokeWidth="0.4" opacity="0.15" />
</svg>
{emoji ? (
<span
className="relative text-5xl leading-none select-none"
style={{ filter: `drop-shadow(0 2px 8px hsl(${hue} 40% 40% / 0.2))` }}
>
{emoji}
</span>
) : (
<span
className="relative font-memento-serif font-bold select-none leading-none"
style={{
fontSize: '4.5rem',
color: `hsl(${hue} 35% 35%)`,
opacity: 0.35,
}}
>
{letter}
</span>
)}
</div>
)
}
export function NotesEditorialView({ export function NotesEditorialView({
notes, notes,
onOpen, onOpen,
@@ -166,7 +223,7 @@ export function NotesEditorialView({
className="w-full h-full object-cover mix-blend-multiply opacity-80 grayscale contrast-125 hover:grayscale-0 hover:opacity-100 transition-all duration-500" className="w-full h-full object-cover mix-blend-multiply opacity-80 grayscale contrast-125 hover:grayscale-0 hover:opacity-100 transition-all duration-500"
/> />
) : ( ) : (
<div className="h-full w-full bg-gradient-to-br from-muted/40 to-muted/10" aria-hidden /> <NoteThumbnailPlaceholder title={title} noteId={note.id} />
)} )}
</div> </div>
<div className="space-y-3 flex-1"> <div className="space-y-3 flex-1">