feat: design system overhaul — sidebar, AI chats, settings, brainstorm, color cleanup
All checks were successful
Deploy to Production / Build and Deploy (push) Successful in 12s

- Sidebar: dynamic brand-accent colors, brainstorm section restyled
- AI chat general: popup panel with expand/collapse, hides when contextual AI open
- AI chat contextual: tabs reordered (Actions first), X close button, height fix
- Settings: all tabs restyled, 6 new color presets (sage, terracotta, iron, etc.)
- Global color cleanup: emerald/orange hardcoded → brand-accent dynamic
- Brainstorm page: orange → brand-accent throughout
- PageEntry animation component added to key pages
- Floating AI button: bg-brand-accent instead of hardcoded black
- i18n: all 15 locales updated with new AI/billing keys
- Billing: freemium quota tracking, BYOK, stripe subscription scaffolding
- Admin: integrated into new design
- AGENTS.md + CLAUDE.md project rules added
This commit is contained in:
Antigravity
2026-05-16 12:59:30 +00:00
parent 1fcea6ed7d
commit bd495be965
2284 changed files with 395285 additions and 2327 deletions

View File

@@ -23,8 +23,9 @@ import { NoteHistoryModal } from '@/components/note-history-modal'
import { CreateNotebookDialog } from '@/components/create-notebook-dialog'
import { toast } from 'sonner'
import { AnimatePresence, motion } from 'motion/react'
import { PageEntry } from '@/components/page-entry'
type SortOrder = 'newest' | 'oldest' | 'alpha'
type SortOrder = 'newest' | 'oldest' | 'alpha' | 'manual'
const NoteEditor = dynamic(
() => import('@/components/note-editor').then(m => ({ default: m.NoteEditor })),
@@ -409,6 +410,7 @@ export function HomeClient({ initialNotes, initialSettings }: HomeClientProps) {
if (sortOrder === 'newest') sorted.sort((a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime())
if (sortOrder === 'oldest') sorted.sort((a, b) => new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime())
if (sortOrder === 'alpha') sorted.sort((a, b) => (a.title || '').localeCompare(b.title || ''))
if (sortOrder === 'manual') sorted.sort((a, b) => (a.order ?? 0) - (b.order ?? 0))
if (selectedTagIds.length > 0) {
const selectedNames = selectedTagIds
@@ -430,6 +432,7 @@ export function HomeClient({ initialNotes, initialSettings }: HomeClientProps) {
newest: t('sidebar.sortNewest') || 'Plus récentes',
oldest: t('sidebar.sortOldest') || 'Plus anciennes',
alpha: t('sidebar.sortAlpha') || 'A → Z',
manual: t('sidebar.sortManual') || 'Libre',
}
@@ -454,6 +457,7 @@ export function HomeClient({ initialNotes, initialSettings }: HomeClientProps) {
}, [refreshNotes])
return (
<PageEntry>
<div
className={cn(
'flex w-full min-h-0 flex-1 flex-col gap-3 py-1'
@@ -599,7 +603,7 @@ export function HomeClient({ initialNotes, initialSettings }: HomeClientProps) {
{currentNotebook && initialSettings.aiAssistantEnabled && (
<button
onClick={() => setOrganizeNotebookOpen(true)}
className="flex items-center gap-2 text-[13px] text-blueprint font-medium hover:opacity-70 transition-opacity"
className="flex items-center gap-2 text-[13px] text-brand-accent font-medium hover:opacity-70 transition-opacity"
title={t('notebook.organizeNotebookWithAITooltip')}
>
<Sparkles size={16} />
@@ -623,7 +627,7 @@ export function HomeClient({ initialNotes, initialSettings }: HomeClientProps) {
</button>
)}
<button
onClick={() => setSortOrder(s => s === 'newest' ? 'oldest' : s === 'oldest' ? 'alpha' : 'newest')}
onClick={() => setSortOrder(s => s === 'newest' ? 'oldest' : s === 'oldest' ? 'alpha' : s === 'alpha' ? 'manual' : 'newest')}
className="flex items-center gap-2 text-[13px] text-foreground font-medium hover:opacity-70 transition-opacity"
>
<ArrowUpDown size={16} />
@@ -639,7 +643,7 @@ export function HomeClient({ initialNotes, initialSettings }: HomeClientProps) {
<TagIcon size={12} />
<span>{t('labels.filterByTags') || 'Filter by Tags'}</span>
{selectedTagIds.length > 0 && (
<span className="bg-memento-blue/10 text-memento-blue px-2 py-0.5 rounded-full text-[9px] lowercase tracking-normal">
<span className="bg-brand-accent/10 text-brand-accent px-2 py-0.5 rounded-full text-[9px] lowercase tracking-normal">
{selectedTagIds.length} active
</span>
)}
@@ -648,7 +652,7 @@ export function HomeClient({ initialNotes, initialSettings }: HomeClientProps) {
<input
type="text"
placeholder={t('labels.searchTags') || 'Search tags...'}
className="bg-transparent border-b border-foreground/10 text-[10px] outline-none focus:border-memento-blue/40 py-1 px-2 w-32 transition-all focus:w-48 placeholder:text-muted-foreground/40"
className="bg-transparent border-b border-foreground/10 text-[10px] outline-none focus:border-brand-accent/40 py-1 px-2 w-32 transition-all focus:w-48 placeholder:text-muted-foreground/40"
value={tagSearchQuery}
onChange={e => setTagSearchQuery(e.target.value)}
/>
@@ -677,7 +681,7 @@ export function HomeClient({ initialNotes, initialSettings }: HomeClientProps) {
{tag.type === 'ai' && (
<Sparkles
size={10}
className={isActive ? 'text-memento-blue' : 'text-memento-blue/60'}
className={isActive ? 'text-brand-accent' : 'text-brand-accent/60'}
/>
)}
{tag.name}
@@ -833,5 +837,6 @@ export function HomeClient({ initialNotes, initialSettings }: HomeClientProps) {
/>
)}
</div>
</PageEntry>
)
}