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
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:
@@ -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>
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user