feat: add UI/UX polish with navigation rail, confirm dialogs, welcome banner, and form validation

- Add NavigationRail component (desktop vertical icon sidebar + mobile bottom tab bar)
- Add ConfirmDialog with promise-based useConfirmDialog hook for async confirmation flow
- Add WelcomeBanner onboarding component (one-time display, localStorage persistence)
- Polish login form UX (shake on error, TOTP slide animation, password visibility toggle, session expired banner)
- Add inline form validation with shake animation in email composer and contacts
- Add empty state patterns for contacts (no data vs no search results with contextual actions)
- Improve toast notification system with undo action support and typed durations
- Add WCAG AA prefers-reduced-motion media query, safe area insets, sr-only live regions
- Add template settings tab and keyboard shortcut integration
- Update all 8 locale translations
This commit is contained in:
Matthieu MALVACHE
2026-02-17 02:31:50 +01:00
committed by Matthieu MALVACHE
parent 2636a88820
commit a43096485b
44 changed files with 2148 additions and 669 deletions
+6 -2
View File
@@ -2,7 +2,7 @@
import { useState, useMemo } from "react";
import { useTranslations, useFormatter } from "next-intl";
import { ChevronLeft, ChevronRight } from "lucide-react";
import { ChevronLeft, ChevronRight, ChevronDown } from "lucide-react";
import {
startOfMonth, endOfMonth, startOfWeek, endOfWeek,
addMonths, subMonths, addYears, subYears, setMonth, setYear,
@@ -113,13 +113,17 @@ export function MiniCalendar({
<button
onClick={handleHeaderClick}
disabled={pickerView === "years"}
title={pickerView !== "years" ? t("mini_calendar_change") : undefined}
className={cn(
"text-sm font-medium px-1 rounded transition-colors",
"text-sm font-medium px-2 py-1 rounded-md transition-colors inline-flex items-center gap-1",
pickerView !== "years" && "hover:bg-muted cursor-pointer",
pickerView === "years" && "cursor-default"
)}
>
{headerLabel}
{pickerView !== "years" && (
<ChevronDown className="w-3.5 h-3.5 text-muted-foreground" />
)}
</button>
<button
onClick={handleNext}