feat: RTL/i18n, AI translate+undo, no-refresh saves, settings perf

- RTL: force dir=rtl on LabelFilter, NotesViewToggle, LabelManagementDialog
- i18n: add missing keys (notifications, privacy, edit/preview, AI translate/undo)
- Settings pages: convert to Server Components (general, appearance) + loading skeleton
- AI menu: add Translate option (10 languages) + Undo AI button in toolbar
- Fix: saveInline uses REST API instead of Server Action → eliminates all implicit refreshes in list mode
- Fix: NotesTabsView notes sync effect preserves selected note on content changes
- Fix: auto-tag suggestions now filter already-assigned labels
- Fix: color change in card view uses local state (no refresh)
- Fix: nav links use <Link> for prefetching (Settings, Admin)
- Fix: suppress duplicate label suggestions already on note
- Route: add /api/ai/translate endpoint
This commit is contained in:
Sepehr Ramezani
2026-04-15 23:48:28 +02:00
parent 39671c6472
commit b6a548acd8
68 changed files with 5014 additions and 485 deletions

View File

@@ -8,14 +8,25 @@ import {
Bell,
Archive,
Trash2,
Plus,
Sparkles,
} from 'lucide-react'
import { Button } from '@/components/ui/button'
import {
Tooltip,
TooltipContent,
TooltipProvider,
TooltipTrigger,
} from '@/components/ui/tooltip'
import { useLanguage } from '@/lib/i18n'
import { NotebooksList } from './notebooks-list'
import { useHomeViewOptional } from '@/context/home-view-context'
export function Sidebar({ className, user }: { className?: string, user?: any }) {
const pathname = usePathname()
const searchParams = useSearchParams()
const { t } = useLanguage()
const homeBridge = useHomeViewOptional()
// Helper to determine if a link is active
const isActive = (href: string, exact = false) => {
@@ -43,7 +54,7 @@ export function Sidebar({ className, user }: { className?: string, user?: any })
<Link
href={href}
className={cn(
"flex items-center gap-4 px-6 py-3 rounded-r-full mr-2 transition-colors",
"flex items-center gap-4 px-6 py-3 rounded-e-full me-2 transition-colors",
"text-sm font-medium tracking-wide",
active
? "bg-primary/10 text-primary dark:bg-primary/20 dark:text-primary-foreground"
@@ -61,7 +72,7 @@ export function Sidebar({ className, user }: { className?: string, user?: any })
className
)}>
{/* Main Navigation */}
<div className="flex flex-col">
<div className="flex flex-col gap-1 px-3">
<NavItem
href="/"
icon={Lightbulb}
@@ -74,6 +85,26 @@ export function Sidebar({ className, user }: { className?: string, user?: any })
label={t('sidebar.reminders') || 'Rappels'}
active={isActive('/reminders')}
/>
{pathname === '/' && homeBridge?.controls?.isTabsMode && (
<TooltipProvider delayDuration={200}>
<Tooltip>
<TooltipTrigger asChild>
<Button
type="button"
className="w-full justify-start gap-3 rounded-e-full ps-4 pe-3 font-medium shadow-sm"
onClick={() => homeBridge.controls?.openNoteComposer()}
>
<Plus className="h-5 w-5 shrink-0" />
<span className="truncate">{t('sidebar.newNoteTabs')}</span>
<Sparkles className="ml-auto h-4 w-4 shrink-0 text-primary" aria-hidden />
</Button>
</TooltipTrigger>
<TooltipContent side="right" className="max-w-[240px]">
{t('sidebar.newNoteTabsHint')}
</TooltipContent>
</Tooltip>
</TooltipProvider>
)}
</div>
{/* Notebooks Section */}