fix: unify theme system - fix theme switching persistence

- Unified localStorage key to 'theme-preference' across all components
- Fixed header.tsx using wrong localStorage key ('theme' instead of 'theme-preference')
- Added localStorage hybrid persistence for instant theme changes
- Removed router.refresh() which was causing stale data revert
- Replaced Blue theme with Sepia
- Consolidated auth() calls to prevent race conditions
- Updated UserSettingsData types to include all themes
This commit is contained in:
2026-01-18 22:33:41 +01:00
parent ef60dafd73
commit ddb67ba9e5
306 changed files with 59580 additions and 6063 deletions

View File

@@ -10,7 +10,7 @@ import {
DropdownMenuItem,
DropdownMenuTrigger,
} from '@/components/ui/dropdown-menu'
import { Pin, Bell, GripVertical, X, Link2, FolderOpen, StickyNote, LucideIcon, Folder, Briefcase, FileText, Zap, BarChart3, Globe, Sparkles, Book, Heart, Crown, Music, Building2 } from 'lucide-react'
import { Pin, Bell, GripVertical, X, Link2, FolderOpen, StickyNote, LucideIcon, Folder, Briefcase, FileText, Zap, BarChart3, Globe, Sparkles, Book, Heart, Crown, Music, Building2, Tag } from 'lucide-react'
import { useState, useEffect, useTransition, useOptimistic } from 'react'
import { useSession } from 'next-auth/react'
import { useRouter, useSearchParams } from 'next/navigation'
@@ -270,12 +270,25 @@ export function NoteCard({ note, onEdit, isDragging, isDragOver, onDragStart, on
return (
<Card
data-testid="note-card"
data-draggable="true"
data-note-id={note.id}
data-size={note.size}
draggable={true}
onDragStart={(e) => {
e.dataTransfer.setData('text/plain', note.id)
e.dataTransfer.effectAllowed = 'move'
e.dataTransfer.setData('text/html', '') // Prevent ghost image in some browsers
onDragStart?.(note.id)
}}
onDragEnd={() => onDragEnd?.()}
className={cn(
'note-card group relative rounded-lg p-4 transition-all duration-200 border shadow-sm hover:shadow-md',
'note-card group relative rounded-2xl overflow-hidden p-5 border shadow-sm',
'transition-all duration-200 ease-out',
'hover:shadow-xl hover:-translate-y-1',
colorClasses.bg,
colorClasses.card,
colorClasses.hover,
isDragging && 'opacity-30'
isDragging && 'opacity-60 scale-105 shadow-2xl rotate-1'
)}
onClick={(e) => {
// Only trigger edit if not clicking on buttons
@@ -350,6 +363,8 @@ export function NoteCard({ note, onEdit, isDragging, isDragOver, onDragStart, on
/>
</Button>
{/* Reminder Icon - Move slightly if pin button is there */}
{note.reminder && new Date(note.reminder) > new Date() && (
<Bell
@@ -437,11 +452,11 @@ export function NoteCard({ note, onEdit, isDragging, isDragOver, onDragStart, on
{optimisticNote.links && optimisticNote.links.length > 0 && (
<div className="flex flex-col gap-2 mb-2">
{optimisticNote.links.map((link, idx) => (
<a
key={idx}
href={link.url}
target="_blank"
rel="noopener noreferrer"
<a
key={idx}
href={link.url}
target="_blank"
rel="noopener noreferrer"
className="block border rounded-md overflow-hidden bg-white/50 dark:bg-black/20 hover:bg-white/80 dark:hover:bg-black/40 transition-colors"
onClick={(e) => e.stopPropagation()}
>
@@ -475,9 +490,44 @@ export function NoteCard({ note, onEdit, isDragging, isDragOver, onDragStart, on
{/* Labels - ONLY show if note belongs to a notebook (labels are contextual per PRD) */}
{optimisticNote.notebookId && optimisticNote.labels && optimisticNote.labels.length > 0 && (
<div className="flex flex-wrap gap-1 mt-3">
{optimisticNote.labels.map((label) => (
<LabelBadge key={label} label={label} />
))}
{optimisticNote.labels.map((label) => {
// Map label names to Keep style colors
const getLabelColor = (labelName: string) => {
if (labelName.includes('hôtels') || labelName.includes('réservations')) {
return 'bg-indigo-50 dark:bg-indigo-900/30 text-indigo-700 dark:text-indigo-300'
} else if (labelName.includes('vols') || labelName.includes('flight')) {
return 'bg-sky-50 dark:bg-sky-900/30 text-sky-700 dark:text-sky-300'
} else if (labelName.includes('restos') || labelName.includes('restaurant')) {
return 'bg-orange-50 dark:bg-orange-900/30 text-orange-700 dark:text-orange-300'
} else {
return 'bg-emerald-50 dark:bg-emerald-900/30 text-emerald-700 dark:text-emerald-300'
}
}
// Map label names to Keep style icons
const getLabelIcon = (labelName: string) => {
if (labelName.includes('hôtels')) return 'label'
else if (labelName.includes('vols')) return 'flight'
else if (labelName.includes('restos')) return 'restaurant'
else return 'label'
}
const icon = getLabelIcon(label)
const colorClass = getLabelColor(label)
return (
<span
key={label}
className={cn(
"inline-flex items-center gap-1.5 px-2.5 py-1 rounded-full text-xs font-semibold",
colorClass
)}
>
<Tag className="w-3 h-3" />
{label}
</span>
)
})}
</div>
)}