feat(fixing forms tunnel & wip dashboard)
This commit is contained in:
@@ -36,6 +36,6 @@ class PasswordResetLinkController extends Controller
|
|||||||
$request->only('email')
|
$request->only('email')
|
||||||
);
|
);
|
||||||
|
|
||||||
return back()->with('status', __('A reset link will be sent if the account exists.'));
|
return back()->with('status', __('passwords.sent_if_exists'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
10
lang/en/passwords.php
Normal file
10
lang/en/passwords.php
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
return [
|
||||||
|
'reset' => 'Your password has been reset.',
|
||||||
|
'sent' => 'We have emailed your password reset link.',
|
||||||
|
'sent_if_exists' => 'A reset link will be sent if the account exists.',
|
||||||
|
'throttled' => 'Please wait before retrying.',
|
||||||
|
'token' => 'This password reset token is invalid.',
|
||||||
|
'user' => 'We can\'t find a user with that email address.',
|
||||||
|
];
|
||||||
10
lang/fr/passwords.php
Normal file
10
lang/fr/passwords.php
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
return [
|
||||||
|
'reset' => 'Votre mot de passe a été réinitialisé.',
|
||||||
|
'sent' => 'Nous vous avons envoyé le lien de réinitialisation par e-mail.',
|
||||||
|
'sent_if_exists' => 'Un lien de réinitialisation sera envoyé si le compte existe.',
|
||||||
|
'throttled' => 'Veuillez patienter avant de réessayer.',
|
||||||
|
'token' => 'Ce jeton de réinitialisation est invalide.',
|
||||||
|
'user' => 'Aucun utilisateur trouvé avec cette adresse e-mail.',
|
||||||
|
];
|
||||||
@@ -26,15 +26,24 @@
|
|||||||
--color-card: var(--card);
|
--color-card: var(--card);
|
||||||
--color-card-foreground: var(--card-foreground);
|
--color-card-foreground: var(--card-foreground);
|
||||||
|
|
||||||
|
--color-popover: var(--popover);
|
||||||
|
--color-popover-foreground: var(--popover-foreground);
|
||||||
|
|
||||||
--color-primary: var(--primary);
|
--color-primary: var(--primary);
|
||||||
--color-primary-foreground: var(--primary-foreground);
|
--color-primary-foreground: var(--primary-foreground);
|
||||||
|
|
||||||
--color-secondary: var(--secondary);
|
--color-secondary: var(--secondary);
|
||||||
--color-secondary-foreground: var(--secondary-foreground);
|
--color-secondary-foreground: var(--secondary-foreground);
|
||||||
|
|
||||||
|
--color-muted: var(--muted);
|
||||||
|
--color-muted-foreground: var(--muted-foreground);
|
||||||
|
|
||||||
--color-accent: var(--accent);
|
--color-accent: var(--accent);
|
||||||
--color-accent-foreground: var(--accent-foreground);
|
--color-accent-foreground: var(--accent-foreground);
|
||||||
|
|
||||||
|
--color-destructive: var(--destructive);
|
||||||
|
--color-destructive-foreground: var(--destructive-foreground);
|
||||||
|
|
||||||
--color-border: var(--border);
|
--color-border: var(--border);
|
||||||
--color-input: var(--input);
|
--color-input: var(--input);
|
||||||
--color-ring: var(--ring);
|
--color-ring: var(--ring);
|
||||||
@@ -43,7 +52,15 @@
|
|||||||
--color-chart-2: var(--chart-2);
|
--color-chart-2: var(--chart-2);
|
||||||
--color-chart-3: var(--chart-3);
|
--color-chart-3: var(--chart-3);
|
||||||
|
|
||||||
|
/* Sidebar */
|
||||||
|
--color-sidebar: var(--sidebar);
|
||||||
|
--color-sidebar-foreground: var(--sidebar-foreground);
|
||||||
|
--color-sidebar-primary: var(--sidebar-primary);
|
||||||
|
--color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
|
||||||
|
--color-sidebar-accent: var(--sidebar-accent);
|
||||||
|
--color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
|
||||||
|
--color-sidebar-border: var(--sidebar-border);
|
||||||
|
--color-sidebar-ring: var(--sidebar-ring);
|
||||||
}
|
}
|
||||||
|
|
||||||
:root {
|
:root {
|
||||||
@@ -52,22 +69,40 @@
|
|||||||
--card: #ffffff;
|
--card: #ffffff;
|
||||||
--card-foreground: #0a0a0a;
|
--card-foreground: #0a0a0a;
|
||||||
|
|
||||||
|
--popover: #ffffff;
|
||||||
|
--popover-foreground: #0a0a0a;
|
||||||
|
|
||||||
--primary: #f5a623;
|
--primary: #f5a623;
|
||||||
--primary-foreground: #0a0a0a;
|
--primary-foreground: #0a0a0a;
|
||||||
|
|
||||||
--secondary: #f48fb1;
|
--secondary: #f48fb1;
|
||||||
--secondary-foreground: #0a0a0a;
|
--secondary-foreground: #0a0a0a;
|
||||||
|
|
||||||
|
--muted: #f5f5f5;
|
||||||
|
--muted-foreground: #737373;
|
||||||
|
|
||||||
--accent: #00473e;
|
--accent: #00473e;
|
||||||
--accent-foreground: #ffffff;
|
--accent-foreground: #ffffff;
|
||||||
|
|
||||||
|
--destructive: #dc2626;
|
||||||
|
--destructive-foreground: #ffffff;
|
||||||
|
|
||||||
--border: #e5e5e5;
|
--border: #e5e5e5;
|
||||||
--input: #e5e5e5;
|
--input: #e5e5e5;
|
||||||
--ring: #d4d4d4;
|
--ring: #d4d4d4;
|
||||||
|
|
||||||
--chart-1: #f5a623; /* orange */
|
--chart-1: #f5a623;
|
||||||
--chart-2: #f48fb1; /* rose */
|
--chart-2: #f48fb1;
|
||||||
--chart-3: #ffffff; /* blanc */
|
--chart-3: #ffffff;
|
||||||
|
|
||||||
|
--sidebar: #ffffff;
|
||||||
|
--sidebar-foreground: #0a0a0a;
|
||||||
|
--sidebar-primary: #f5a623;
|
||||||
|
--sidebar-primary-foreground: #0a0a0a;
|
||||||
|
--sidebar-accent: #f5f5f5;
|
||||||
|
--sidebar-accent-foreground: #0a0a0a;
|
||||||
|
--sidebar-border: #e5e5e5;
|
||||||
|
--sidebar-ring: #d4d4d4;
|
||||||
}
|
}
|
||||||
|
|
||||||
.dark {
|
.dark {
|
||||||
@@ -76,15 +111,24 @@
|
|||||||
--card: #171717;
|
--card: #171717;
|
||||||
--card-foreground: #f9f9f9;
|
--card-foreground: #f9f9f9;
|
||||||
|
|
||||||
--primary: #007c6c; /* vert plus clair */
|
--popover: #171717;
|
||||||
|
--popover-foreground: #f9f9f9;
|
||||||
|
|
||||||
|
--primary: #007c6c;
|
||||||
--primary-foreground: #0a0a0a;
|
--primary-foreground: #0a0a0a;
|
||||||
|
|
||||||
--secondary: #2c2c2c;
|
--secondary: #2c2c2c;
|
||||||
--secondary-foreground: #f9f9f9;
|
--secondary-foreground: #f9f9f9;
|
||||||
|
|
||||||
|
--muted: #2c2c2c;
|
||||||
|
--muted-foreground: #a3a3a3;
|
||||||
|
|
||||||
--accent: #f48fb1;
|
--accent: #f48fb1;
|
||||||
--accent-foreground: #171717;
|
--accent-foreground: #171717;
|
||||||
|
|
||||||
|
--destructive: #ef4444;
|
||||||
|
--destructive-foreground: #ffffff;
|
||||||
|
|
||||||
--border: #2c2c2c;
|
--border: #2c2c2c;
|
||||||
--input: #2c2c2c;
|
--input: #2c2c2c;
|
||||||
--ring: #6f6f6f;
|
--ring: #6f6f6f;
|
||||||
@@ -92,6 +136,24 @@
|
|||||||
--chart-1: #f48fb1;
|
--chart-1: #f48fb1;
|
||||||
--chart-2: #ffb300;
|
--chart-2: #ffb300;
|
||||||
--chart-3: #f9f9f9;
|
--chart-3: #f9f9f9;
|
||||||
|
|
||||||
|
--sidebar: #171717;
|
||||||
|
--sidebar-foreground: #f9f9f9;
|
||||||
|
--sidebar-primary: #007c6c;
|
||||||
|
--sidebar-primary-foreground: #f9f9f9;
|
||||||
|
--sidebar-accent: #2c2c2c;
|
||||||
|
--sidebar-accent-foreground: #f9f9f9;
|
||||||
|
--sidebar-border: #2c2c2c;
|
||||||
|
--sidebar-ring: #6f6f6f;
|
||||||
|
}
|
||||||
|
|
||||||
|
@layer utilities {
|
||||||
|
.nb-shadow {
|
||||||
|
@apply border-3 border-black shadow-[4px_4px_0px_rgba(0,0,0,1)] hover:shadow-none hover:translate-2 transition delay-50 duration-200 ease-in-out;
|
||||||
|
}
|
||||||
|
.nb-shadow-static {
|
||||||
|
@apply border-3 border-black shadow-[4px_4px_0px_rgba(0,0,0,1)];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@layer base {
|
@layer base {
|
||||||
@@ -124,7 +186,7 @@
|
|||||||
text-decoration-line: underline;
|
text-decoration-line: underline;
|
||||||
}
|
}
|
||||||
|
|
||||||
button {
|
button:not([data-slot="button"]):not([data-slot="checkbox"]) {
|
||||||
@apply bg-white border border-black shadow-sm text-black px-4 py-2 rounded-md hover:shadow-md transition;
|
@apply bg-white border border-black shadow-sm text-black px-4 py-2 rounded-md hover:shadow-md transition;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,54 +13,27 @@ import {
|
|||||||
NavigationMenuList,
|
NavigationMenuList,
|
||||||
navigationMenuTriggerStyle,
|
navigationMenuTriggerStyle,
|
||||||
} from '@/components/ui/navigation-menu';
|
} from '@/components/ui/navigation-menu';
|
||||||
import {
|
|
||||||
Sheet,
|
|
||||||
SheetContent,
|
|
||||||
SheetHeader,
|
|
||||||
SheetTitle,
|
|
||||||
SheetTrigger,
|
|
||||||
} from '@/components/ui/sheet';
|
|
||||||
import {
|
|
||||||
Tooltip,
|
|
||||||
TooltipContent,
|
|
||||||
TooltipProvider,
|
|
||||||
TooltipTrigger,
|
|
||||||
} from '@/components/ui/tooltip';
|
|
||||||
import { UserMenuContent } from '@/components/user-menu-content';
|
import { UserMenuContent } from '@/components/user-menu-content';
|
||||||
|
import { useAppearance } from '@/hooks/use-appearance';
|
||||||
import { useInitials } from '@/hooks/use-initials';
|
import { useInitials } from '@/hooks/use-initials';
|
||||||
|
import { useMobileNavigation } from '@/hooks/use-mobile-navigation';
|
||||||
import { cn } from '@/lib/utils';
|
import { cn } from '@/lib/utils';
|
||||||
import { dashboard } from '@/routes';
|
import { dashboard, logout } from '@/routes';
|
||||||
import { type BreadcrumbItem, type NavItem, type SharedData } from '@/types';
|
import { type BreadcrumbItem, type NavItem, type SharedData } from '@/types';
|
||||||
import { Link, usePage } from '@inertiajs/react';
|
import { Link, router, usePage } from '@inertiajs/react';
|
||||||
import { BookOpen, Folder, LayoutGrid, Menu, Search } from 'lucide-react';
|
import { LayoutGrid, LogOut, Menu, Moon, Settings, Sun, X } from 'lucide-react';
|
||||||
import AppearanceToggleDropdown from './appearance-dropdown';
|
import { useEffect, useState } from 'react';
|
||||||
import AppLogo from './app-logo';
|
import AppLogo from './app-logo';
|
||||||
import AppLogoIcon from './app-logo-icon';
|
import AppLogoIcon from './app-logo-icon';
|
||||||
|
|
||||||
const mainNavItems: NavItem[] = [
|
const mainNavItems: NavItem[] = [
|
||||||
{
|
{
|
||||||
title: 'Dashboard',
|
title: 'Tableau de Bord',
|
||||||
href: dashboard(),
|
href: dashboard(),
|
||||||
icon: LayoutGrid,
|
icon: LayoutGrid,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
const rightNavItems: NavItem[] = [
|
|
||||||
{
|
|
||||||
title: 'Repository',
|
|
||||||
href: 'https://github.com/laravel/react-starter-kit',
|
|
||||||
icon: Folder,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Documentation',
|
|
||||||
href: 'https://laravel.com/docs/starter-kits#react',
|
|
||||||
icon: BookOpen,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
const activeItemStyles =
|
|
||||||
'text-neutral-900 dark:bg-neutral-800 dark:text-neutral-100';
|
|
||||||
|
|
||||||
interface AppHeaderProps {
|
interface AppHeaderProps {
|
||||||
breadcrumbs?: BreadcrumbItem[];
|
breadcrumbs?: BreadcrumbItem[];
|
||||||
}
|
}
|
||||||
@@ -69,122 +42,68 @@ export function AppHeader({ breadcrumbs = [] }: AppHeaderProps) {
|
|||||||
const page = usePage<SharedData>();
|
const page = usePage<SharedData>();
|
||||||
const { auth } = page.props;
|
const { auth } = page.props;
|
||||||
const getInitials = useInitials();
|
const getInitials = useInitials();
|
||||||
|
const cleanup = useMobileNavigation();
|
||||||
|
const { appearance, updateAppearance } = useAppearance();
|
||||||
|
const [isMenuOpen, setIsMenuOpen] = useState(false);
|
||||||
|
|
||||||
|
const toggleAppearance = () => {
|
||||||
|
updateAppearance(appearance === 'dark' ? 'light' : 'dark');
|
||||||
|
};
|
||||||
|
|
||||||
|
const closeMenu = () => setIsMenuOpen(false);
|
||||||
|
|
||||||
|
const handleLogout = () => {
|
||||||
|
cleanup();
|
||||||
|
router.flushAll();
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
return router.on('navigate', closeMenu);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const handleKeyDown = (e: KeyboardEvent) => {
|
||||||
|
if (e.key === 'Escape') closeMenu();
|
||||||
|
};
|
||||||
|
document.addEventListener('keydown', handleKeyDown);
|
||||||
|
return () => document.removeEventListener('keydown', handleKeyDown);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
document.body.style.overflow = isMenuOpen ? 'hidden' : '';
|
||||||
|
return () => { document.body.style.overflow = ''; };
|
||||||
|
}, [isMenuOpen]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="border-b border-sidebar-border/80">
|
<div className="border-b border-border bg-background">
|
||||||
<div className="mx-auto flex h-16 items-center px-4 md:max-w-7xl">
|
<div className="mx-auto flex h-16 items-center px-4 md:max-w-7xl">
|
||||||
{/* Mobile Menu */}
|
|
||||||
<div className="lg:hidden">
|
|
||||||
<Sheet>
|
|
||||||
<SheetTrigger asChild>
|
|
||||||
<Button
|
|
||||||
variant="ghost"
|
|
||||||
size="icon"
|
|
||||||
className="mr-2 h-[34px] w-[34px]"
|
|
||||||
>
|
|
||||||
<Menu className="h-5 w-5" />
|
|
||||||
</Button>
|
|
||||||
</SheetTrigger>
|
|
||||||
<SheetContent
|
|
||||||
side="left"
|
|
||||||
className="flex h-full w-64 flex-col items-stretch justify-between bg-sidebar"
|
|
||||||
>
|
|
||||||
<SheetTitle className="sr-only">
|
|
||||||
Navigation Menu
|
|
||||||
</SheetTitle>
|
|
||||||
<SheetHeader className="flex justify-start text-left">
|
|
||||||
<AppLogoIcon className="h-6 w-6 fill-current text-black dark:text-white" />
|
|
||||||
</SheetHeader>
|
|
||||||
<div className="flex h-full flex-1 flex-col space-y-4 p-4">
|
|
||||||
<div className="flex h-full flex-col justify-between text-sm">
|
|
||||||
<div className="flex flex-col space-y-4">
|
|
||||||
{mainNavItems.map((item) => (
|
|
||||||
<Link
|
|
||||||
key={item.title}
|
|
||||||
href={item.href}
|
|
||||||
className="flex items-center space-x-2 font-medium"
|
|
||||||
>
|
|
||||||
{item.icon && (
|
|
||||||
<Icon
|
|
||||||
iconNode={item.icon}
|
|
||||||
className="h-5 w-5"
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
<span>{item.title}</span>
|
|
||||||
</Link>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="flex flex-col space-y-4">
|
{/* Logo */}
|
||||||
{rightNavItems.map((item) => (
|
<Link href={dashboard()} prefetch className="flex items-center no-underline text-foreground">
|
||||||
<a
|
<AppLogo className="h-8 w-auto max-w-[180px]" />
|
||||||
key={item.title}
|
|
||||||
href={
|
|
||||||
typeof item.href ===
|
|
||||||
'string'
|
|
||||||
? item.href
|
|
||||||
: item.href.url
|
|
||||||
}
|
|
||||||
target="_blank"
|
|
||||||
rel="noopener noreferrer"
|
|
||||||
className="flex items-center space-x-2 font-medium"
|
|
||||||
>
|
|
||||||
{item.icon && (
|
|
||||||
<Icon
|
|
||||||
iconNode={item.icon}
|
|
||||||
className="h-5 w-5"
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
<span>{item.title}</span>
|
|
||||||
</a>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</SheetContent>
|
|
||||||
</Sheet>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<Link
|
|
||||||
href={dashboard()}
|
|
||||||
prefetch
|
|
||||||
className="flex items-center space-x-2 no-underline"
|
|
||||||
>
|
|
||||||
<AppLogo />
|
|
||||||
</Link>
|
</Link>
|
||||||
|
|
||||||
{/* Desktop Navigation */}
|
{/* Desktop nav */}
|
||||||
<div className="ml-6 hidden h-full items-center space-x-6 lg:flex">
|
<div className="ml-6 hidden h-full items-center lg:flex">
|
||||||
<NavigationMenu className="flex h-full items-stretch">
|
<NavigationMenu className="flex h-full items-stretch">
|
||||||
<NavigationMenuList className="flex h-full items-stretch space-x-2">
|
<NavigationMenuList className="flex h-full items-stretch gap-1">
|
||||||
{mainNavItems.map((item, index) => (
|
{mainNavItems.map((item, index) => (
|
||||||
<NavigationMenuItem
|
<NavigationMenuItem key={index} className="relative flex h-full items-center">
|
||||||
key={index}
|
|
||||||
className="relative flex h-full items-center"
|
|
||||||
>
|
|
||||||
<Link
|
<Link
|
||||||
href={item.href}
|
href={item.href}
|
||||||
className={cn(
|
className={cn(
|
||||||
navigationMenuTriggerStyle(),
|
navigationMenuTriggerStyle(),
|
||||||
page.url ===
|
'h-9 cursor-pointer px-3 text-foreground no-underline',
|
||||||
(typeof item.href ===
|
page.url === (typeof item.href === 'string' ? item.href : item.href.url) &&
|
||||||
'string'
|
'font-semibold',
|
||||||
? item.href
|
|
||||||
: item.href.url) &&
|
|
||||||
activeItemStyles,
|
|
||||||
'h-9 cursor-pointer px-3',
|
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{item.icon && (
|
{item.icon && <Icon iconNode={item.icon} className="mr-2 h-4 w-4" />}
|
||||||
<Icon
|
|
||||||
iconNode={item.icon}
|
|
||||||
className="mr-2 h-4 w-4"
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
{item.title}
|
{item.title}
|
||||||
</Link>
|
</Link>
|
||||||
{page.url === item.href && (
|
{page.url === (typeof item.href === 'string' ? item.href : item.href.url) && (
|
||||||
<div className="absolute bottom-0 left-0 h-0.5 w-full translate-y-px bg-black dark:bg-white"></div>
|
<div className="absolute bottom-0 left-0 h-0.5 w-full translate-y-px bg-primary" />
|
||||||
)}
|
)}
|
||||||
</NavigationMenuItem>
|
</NavigationMenuItem>
|
||||||
))}
|
))}
|
||||||
@@ -192,66 +111,23 @@ export function AppHeader({ breadcrumbs = [] }: AppHeaderProps) {
|
|||||||
</NavigationMenu>
|
</NavigationMenu>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="ml-auto flex items-center space-x-2">
|
{/* Right actions */}
|
||||||
<div className="relative flex items-center space-x-1">
|
<div className="ml-auto flex items-center gap-2">
|
||||||
<Button
|
{/* Theme toggle — desktop only */}
|
||||||
variant="ghost"
|
<button
|
||||||
size="icon"
|
onClick={toggleAppearance}
|
||||||
className="group h-9 w-9 cursor-pointer"
|
className="hidden lg:flex nb-shadow bg-primary text-secondary-foreground hover:bg-primary/80 h-10 px-4 py-2 font-bold"
|
||||||
|
aria-label="Changer le thème"
|
||||||
>
|
>
|
||||||
<Search className="!size-5 opacity-80 group-hover:opacity-100" />
|
{appearance === 'dark' ? <Sun className="size-4" /> : <Moon className="size-4" />}
|
||||||
</Button>
|
</button>
|
||||||
<div className="hidden lg:flex">
|
|
||||||
{rightNavItems.map((item) => (
|
{/* Avatar dropdown — always visible */}
|
||||||
<TooltipProvider
|
|
||||||
key={item.title}
|
|
||||||
delayDuration={0}
|
|
||||||
>
|
|
||||||
<Tooltip>
|
|
||||||
<TooltipTrigger>
|
|
||||||
<a
|
|
||||||
href={
|
|
||||||
typeof item.href ===
|
|
||||||
'string'
|
|
||||||
? item.href
|
|
||||||
: item.href.url
|
|
||||||
}
|
|
||||||
target="_blank"
|
|
||||||
rel="noopener noreferrer"
|
|
||||||
className="group ml-1 inline-flex h-9 w-9 items-center justify-center rounded-md bg-transparent p-0 text-sm font-medium text-accent-foreground ring-offset-background transition-colors hover:bg-accent hover:text-accent-foreground focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:outline-none disabled:pointer-events-none disabled:opacity-50"
|
|
||||||
>
|
|
||||||
<span className="sr-only">
|
|
||||||
{item.title}
|
|
||||||
</span>
|
|
||||||
{item.icon && (
|
|
||||||
<Icon
|
|
||||||
iconNode={item.icon}
|
|
||||||
className="size-5 opacity-80 group-hover:opacity-100"
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</a>
|
|
||||||
</TooltipTrigger>
|
|
||||||
<TooltipContent>
|
|
||||||
<p>{item.title}</p>
|
|
||||||
</TooltipContent>
|
|
||||||
</Tooltip>
|
|
||||||
</TooltipProvider>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<AppearanceToggleDropdown />
|
|
||||||
<DropdownMenu>
|
<DropdownMenu>
|
||||||
<DropdownMenuTrigger asChild>
|
<DropdownMenuTrigger asChild>
|
||||||
<Button
|
<Button variant="secondary" className="size-10 rounded-full mr-2">
|
||||||
variant="ghost"
|
|
||||||
className="size-10 rounded-full p-1"
|
|
||||||
>
|
|
||||||
<Avatar className="size-8 overflow-hidden rounded-full">
|
<Avatar className="size-8 overflow-hidden rounded-full">
|
||||||
<AvatarImage
|
<AvatarFallback className="rounded-full bg-secondary text-secondary-foreground font-semibold text-sm">
|
||||||
src={auth.user.avatar}
|
|
||||||
alt={auth.user.name}
|
|
||||||
/>
|
|
||||||
<AvatarFallback className="rounded-lg bg-neutral-200 text-black dark:bg-neutral-700 dark:text-white">
|
|
||||||
{getInitials(auth.user.name)}
|
{getInitials(auth.user.name)}
|
||||||
</AvatarFallback>
|
</AvatarFallback>
|
||||||
</Avatar>
|
</Avatar>
|
||||||
@@ -261,12 +137,109 @@ export function AppHeader({ breadcrumbs = [] }: AppHeaderProps) {
|
|||||||
<UserMenuContent user={auth.user} />
|
<UserMenuContent user={auth.user} />
|
||||||
</DropdownMenuContent>
|
</DropdownMenuContent>
|
||||||
</DropdownMenu>
|
</DropdownMenu>
|
||||||
|
|
||||||
|
{/* Hamburger — mobile only */}
|
||||||
|
<button
|
||||||
|
onClick={() => setIsMenuOpen(!isMenuOpen)}
|
||||||
|
className="flex lg:hidden nb-shadow bg-primary text-secondary-foreground hover:bg-primary/80 h-10 px-4 py-2 font-bold"
|
||||||
|
aria-label={isMenuOpen ? 'Fermer le menu' : 'Ouvrir le menu'}
|
||||||
|
aria-expanded={isMenuOpen}
|
||||||
|
>
|
||||||
|
{isMenuOpen ? <X className="size-5" /> : <Menu className="size-5" />}
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* Mobile menu */}
|
||||||
|
{isMenuOpen && (
|
||||||
|
<>
|
||||||
|
<div
|
||||||
|
className="fixed inset-0 z-40 bg-black/30 lg:hidden"
|
||||||
|
onClick={closeMenu}
|
||||||
|
aria-hidden="true"
|
||||||
|
/>
|
||||||
|
<div className="fixed inset-x-0 top-0 z-50 lg:hidden bg-[#F5F5F5] dark:bg-[#0a0a0a] border-b-4 border-black flex flex-col gap-6 p-6">
|
||||||
|
{/* Header du panel */}
|
||||||
|
<div className="flex justify-between items-center">
|
||||||
|
<Link href={dashboard()} onClick={closeMenu} className="flex items-center gap-2 no-underline text-foreground">
|
||||||
|
<AppLogoIcon className="size-8" />
|
||||||
|
<span className="font-bold text-foreground">Le Retzien Libre</span>
|
||||||
|
</Link>
|
||||||
|
<button
|
||||||
|
onClick={closeMenu}
|
||||||
|
className="p-2 rounded-md border border-black/20 dark:border-white/20 hover:bg-black/5 dark:hover:bg-white/5 transition"
|
||||||
|
aria-label="Fermer le menu"
|
||||||
|
>
|
||||||
|
<X className="size-5" />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Nav links */}
|
||||||
|
<nav className="flex flex-col">
|
||||||
|
{mainNavItems.map((item) => (
|
||||||
|
<Link
|
||||||
|
key={item.title}
|
||||||
|
href={item.href}
|
||||||
|
onClick={closeMenu}
|
||||||
|
className="flex items-center gap-2 text-lg py-3 border-b border-black/10 dark:border-white/10 no-underline text-foreground hover:underline"
|
||||||
|
>
|
||||||
|
{item.icon && <Icon iconNode={item.icon} className="size-5" />}
|
||||||
|
<span>{item.title}</span>
|
||||||
|
</Link>
|
||||||
|
))}
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
{/* Theme toggle */}
|
||||||
|
<button
|
||||||
|
onClick={toggleAppearance}
|
||||||
|
className="flex items-center gap-2 text-lg py-3 border-b border-black/10 dark:border-white/10 text-foreground hover:underline w-full"
|
||||||
|
aria-label="Changer le thème"
|
||||||
|
>
|
||||||
|
{appearance === 'dark' ? <Sun className="size-5" /> : <Moon className="size-5" />}
|
||||||
|
<span>{appearance === 'dark' ? 'Mode clair' : 'Mode sombre'}</span>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
{/* User actions */}
|
||||||
|
<div className="flex flex-col gap-3">
|
||||||
|
<div className="flex items-center gap-3 py-2 border-b border-black/10 dark:border-white/10">
|
||||||
|
<Avatar className="size-8 rounded-full">
|
||||||
|
<AvatarFallback className="rounded-full bg-secondary text-secondary-foreground font-semibold text-sm">
|
||||||
|
{getInitials(auth.user.name)}
|
||||||
|
</AvatarFallback>
|
||||||
|
</Avatar>
|
||||||
|
<div className="flex flex-col">
|
||||||
|
<span className="text-sm font-semibold text-foreground">{auth.user.name}</span>
|
||||||
|
<span className="text-xs text-muted-foreground">{auth.user.email}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<Link
|
||||||
|
href="/profile/edit"
|
||||||
|
onClick={closeMenu}
|
||||||
|
className="flex items-center gap-2 text-lg py-3 border-b border-black/10 dark:border-white/10 no-underline text-foreground hover:underline"
|
||||||
|
>
|
||||||
|
<Settings className="size-5" />
|
||||||
|
<span>Paramètres</span>
|
||||||
|
</Link>
|
||||||
|
<Link
|
||||||
|
href={logout()}
|
||||||
|
method="post"
|
||||||
|
as="button"
|
||||||
|
onClick={() => { closeMenu(); handleLogout(); }}
|
||||||
|
className="flex bg-primary items-center gap-2 text-lg py-3 no-underline text-foreground hover:underline border-black border-3 shadow-[4px_4px_0px_rgba(0,0,0,1)]"
|
||||||
|
data-test="logout-button"
|
||||||
|
>
|
||||||
|
<LogOut className="size-5" />
|
||||||
|
<span>Se déconnecter</span>
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
|
||||||
{breadcrumbs.length > 1 && (
|
{breadcrumbs.length > 1 && (
|
||||||
<div className="flex w-full border-b border-sidebar-border/70">
|
<div className="flex w-full border-b border-border">
|
||||||
<div className="mx-auto flex h-12 w-full items-center justify-start px-4 text-neutral-500 md:max-w-7xl">
|
<div className="mx-auto flex h-12 w-full items-center justify-start px-4 text-muted-foreground md:max-w-7xl">
|
||||||
<Breadcrumbs breadcrumbs={breadcrumbs} />
|
<Breadcrumbs breadcrumbs={breadcrumbs} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -3,12 +3,12 @@ import { SVGAttributes } from 'react';
|
|||||||
export default function AppLogoIcon(props: SVGAttributes<SVGElement>) {
|
export default function AppLogoIcon(props: SVGAttributes<SVGElement>) {
|
||||||
return (
|
return (
|
||||||
<svg {...props} viewBox="0 0 42 33" fill="none" xmlns="http://www.w3.org/2000/svg">
|
<svg {...props} viewBox="0 0 42 33" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
<circle cx="21.138" cy="16.5" r="15" stroke="#000" strokeWidth="3"/>
|
<circle cx="21.138" cy="16.5" r="15" stroke="currentColor" strokeWidth="3"/>
|
||||||
<path d="M21.138 15c-4.4-5.2-11-2.167-13.5 0 1.6-10.4 9.333-12 13-12 10.4.4 13.667 8.167 14 12-6.4-5.6-11.5-2.333-13.5 0Z" fill="#000" stroke="#000"/>
|
<path d="M21.138 15c-4.4-5.2-11-2.167-13.5 0 1.6-10.4 9.333-12 13-12 10.4.4 13.667 8.167 14 12-6.4-5.6-11.5-2.333-13.5 0Z" fill="currentColor" stroke="currentColor"/>
|
||||||
<circle cx="13" cy="17" r="2" fill="#FFA8BA"/>
|
<circle cx="13" cy="17" r="2" fill="#FFA8BA"/>
|
||||||
<circle cx="29" cy="17" r="2" fill="#FFA8BA"/>
|
<circle cx="29" cy="17" r="2" fill="#FFA8BA"/>
|
||||||
<path d="M5.638 11.5c-3.5 5.167-8.4 14.2 0 9v-9ZM36.638 11.5c3.5 5.167 8.4 14.2 0 9v-9Z" fill="#000" stroke="#000"/>
|
<path d="M5.638 11.5c-3.5 5.167-8.4 14.2 0 9v-9ZM36.638 11.5c3.5 5.167 8.4 14.2 0 9v-9Z" fill="currentColor" stroke="currentColor"/>
|
||||||
<path d="M21.736 18.768a1.28 1.28 0 0 1-1.472 0l-2.879-2.117c-.778-.572-.298-1.651.736-1.651h5.758c1.034 0 1.514 1.079.736 1.651l-2.88 2.117Z" fill="#FAAE2B"/>
|
<path d="M21.736 18.768a1.28 1.28 0 0 1-1.472 0l-2.879-2.117c-.778-.572-.298-1.651.736-1.651h5.758c1.034 0 1.514 1.079.736 1.651l-2.88 2.117Z" fill="#FAAE2B"/>
|
||||||
</svg>
|
</svg>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -1,4 +1,3 @@
|
|||||||
import { NavFooter } from '@/components/nav-footer';
|
|
||||||
import { NavMain } from '@/components/nav-main';
|
import { NavMain } from '@/components/nav-main';
|
||||||
import { NavUser } from '@/components/nav-user';
|
import { NavUser } from '@/components/nav-user';
|
||||||
import {
|
import {
|
||||||
@@ -13,7 +12,7 @@ import {
|
|||||||
import { dashboard } from '@/routes';
|
import { dashboard } from '@/routes';
|
||||||
import { type NavItem } from '@/types';
|
import { type NavItem } from '@/types';
|
||||||
import { Link } from '@inertiajs/react';
|
import { Link } from '@inertiajs/react';
|
||||||
import { BookOpen, Folder, LayoutGrid } from 'lucide-react';
|
import { LayoutGrid } from 'lucide-react';
|
||||||
import AppLogo from './app-logo';
|
import AppLogo from './app-logo';
|
||||||
|
|
||||||
const mainNavItems: NavItem[] = [
|
const mainNavItems: NavItem[] = [
|
||||||
@@ -24,19 +23,6 @@ const mainNavItems: NavItem[] = [
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
const footerNavItems: NavItem[] = [
|
|
||||||
{
|
|
||||||
title: 'Repository',
|
|
||||||
href: 'https://github.com/laravel/react-starter-kit',
|
|
||||||
icon: Folder,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Documentation',
|
|
||||||
href: 'https://laravel.com/docs/starter-kits#react',
|
|
||||||
icon: BookOpen,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
export function AppSidebar() {
|
export function AppSidebar() {
|
||||||
return (
|
return (
|
||||||
<Sidebar collapsible="icon" variant="inset">
|
<Sidebar collapsible="icon" variant="inset">
|
||||||
@@ -44,7 +30,7 @@ export function AppSidebar() {
|
|||||||
<SidebarMenu>
|
<SidebarMenu>
|
||||||
<SidebarMenuItem>
|
<SidebarMenuItem>
|
||||||
<SidebarMenuButton size="lg" asChild>
|
<SidebarMenuButton size="lg" asChild>
|
||||||
<Link href={dashboard()} prefetch>
|
<Link href={dashboard()} prefetch className="text-foreground">
|
||||||
<AppLogo />
|
<AppLogo />
|
||||||
</Link>
|
</Link>
|
||||||
</SidebarMenuButton>
|
</SidebarMenuButton>
|
||||||
@@ -57,7 +43,6 @@ export function AppSidebar() {
|
|||||||
</SidebarContent>
|
</SidebarContent>
|
||||||
|
|
||||||
<SidebarFooter>
|
<SidebarFooter>
|
||||||
<NavFooter items={footerNavItems} className="mt-auto" />
|
|
||||||
<NavUser />
|
<NavUser />
|
||||||
</SidebarFooter>
|
</SidebarFooter>
|
||||||
</Sidebar>
|
</Sidebar>
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ export function ScrollToTop() {
|
|||||||
<button
|
<button
|
||||||
onClick={scrollToTop}
|
onClick={scrollToTop}
|
||||||
aria-label="Retour en haut"
|
aria-label="Retour en haut"
|
||||||
className="fixed bottom-6 right-6 z-50 p-3 rounded-full border-3 border-black bg-primary shadow-[4px_4px_0px_rgba(0,0,0,1)] hover:shadow-none hover:translate-x-1 hover:translate-y-1 transition duration-200"
|
className="nb-shadow fixed bottom-6 right-6 z-50 p-3 rounded-full bg-primary"
|
||||||
>
|
>
|
||||||
<ChevronUp className="size-5" />
|
<ChevronUp className="size-5" />
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ export function AboutSection() {
|
|||||||
subtitle="Le Retzien Libre, c’est une association qui promeut l’auto-hébergement et la décentralisation des services en ligne depuis 2017."
|
subtitle="Le Retzien Libre, c’est une association qui promeut l’auto-hébergement et la décentralisation des services en ligne depuis 2017."
|
||||||
align='left'/>
|
align='left'/>
|
||||||
<div
|
<div
|
||||||
className="bg-white rounded-4xl border-3 border-black mt-10 px-10 pt-20 pb-10 shadow-[4px_4px_0px_rgba(0,0,0,1)]">
|
className="nb-shadow-static bg-white rounded-4xl mt-10 px-10 pt-20 pb-10">
|
||||||
<div className="grid grid-cols-1 md:grid-cols-3 gap-8">
|
<div className="grid grid-cols-1 md:grid-cols-3 gap-8">
|
||||||
<div className="flex flex-col gap-3 lg:border-r-2 border-black lg:pr-10 border-0">
|
<div className="flex flex-col gap-3 lg:border-r-2 border-black lg:pr-10 border-0">
|
||||||
<h3 className="text-xl text-primary font-semibold">Une association locale</h3>
|
<h3 className="text-xl text-primary font-semibold">Une association locale</h3>
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import {Service} from "@/types";
|
|||||||
export function ServiceCard({title, colorTitle, bgColor, bgTitle, description, link, illustration}: Service) {
|
export function ServiceCard({title, colorTitle, bgColor, bgTitle, description, link, illustration}: Service) {
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={`flex gap-1 items-center bg-${bgColor} justify-center gap-4 rounded-4xl p-10 border-3 border-black shadow-[4px_4px_0px_rgba(0,0,0,1)] hover:shadow-none hover:translate-2 transition delay-50 duration-200 ease-in-out`}>
|
className={`nb-shadow flex gap-1 items-center bg-${bgColor} justify-center gap-4 rounded-4xl p-10`}>
|
||||||
<div>
|
<div>
|
||||||
<div className="max-w-[150px]">
|
<div className="max-w-[150px]">
|
||||||
<h3 className={`inline text-2xl font-semibold text-${colorTitle} font-medium bg-${bgTitle} rounded p-1 line-clamp-2`}>{title}</h3>
|
<h3 className={`inline text-2xl font-semibold text-${colorTitle} font-medium bg-${bgTitle} rounded p-1 line-clamp-2`}>{title}</h3>
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ export function Footer() {
|
|||||||
const currentYear = new Date().getFullYear();
|
const currentYear = new Date().getFullYear();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<footer className="gap-10 bg-accent rounded-t-4xl text-white py-10 px-20 mt-auto mx-5">
|
<footer className="gap-10 bg-accent dark:bg-primary rounded-t-4xl text-white py-10 px-20 mt-auto mx-5">
|
||||||
<div className="max-w-7xl mx-auto px-4 flex flex-col gap-8">
|
<div className="max-w-7xl mx-auto px-4 flex flex-col gap-8">
|
||||||
<div className="flex flex-col lg:flex-row justify-between gap-8">
|
<div className="flex flex-col lg:flex-row justify-between gap-8">
|
||||||
<div className="flex flex-col gap-3">
|
<div className="flex flex-col gap-3">
|
||||||
|
|||||||
@@ -14,13 +14,13 @@ const buttonVariants = cva(
|
|||||||
destructive:
|
destructive:
|
||||||
"bg-destructive text-white shadow-xs hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40",
|
"bg-destructive text-white shadow-xs hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40",
|
||||||
outline:
|
outline:
|
||||||
"bg-white shadow-sm hover:bg-background",
|
"bg-background text-foreground shadow-sm hover:bg-muted",
|
||||||
secondary:
|
secondary:
|
||||||
"bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80",
|
"bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80",
|
||||||
ghost: "bg-accent hover:text-accent-foreground hover:text-accent-foreground",
|
ghost: "bg-transparent text-foreground border-transparent shadow-none hover:bg-primary/10",
|
||||||
},
|
},
|
||||||
size: {
|
size: {
|
||||||
default: "h-10 px-4 py-2 shadow-[4px_4px_0px_rgba(0,0,0,1)] hover:shadow-none hover:translate-2 transition delay-50 duration-200 ease-in-out",
|
default: "h-10 px-4 py-2 nb-shadow",
|
||||||
sm: "h-8 rounded-md px-3 has-[>svg]:px-2.5",
|
sm: "h-8 rounded-md px-3 has-[>svg]:px-2.5",
|
||||||
lg: "h-10 rounded-md px-6 has-[>svg]:px-4",
|
lg: "h-10 rounded-md px-6 has-[>svg]:px-4",
|
||||||
icon: "size-9",
|
icon: "size-9",
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ function Checkbox({
|
|||||||
<CheckboxPrimitive.Root
|
<CheckboxPrimitive.Root
|
||||||
data-slot="checkbox"
|
data-slot="checkbox"
|
||||||
className={cn(
|
className={cn(
|
||||||
"border-3 border-black bg-white peer pr-0 data-[state=checked]:bg-black data-[state=checked]:text-white data-[state=checked]:border-black focus-visible:shadow-[4px_4px_0px_rgba(0,0,0,1)] transition duration-100 ease-in-out aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive size-4 shrink-0 rounded-[4px] shadow-xs outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50",
|
"flex items-center justify-center border-3 border-black bg-white peer data-[state=checked]:bg-black data-[state=checked]:text-white data-[state=checked]:border-black focus-visible:shadow-[4px_4px_0px_rgba(0,0,0,1)] transition duration-100 ease-in-out aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive w-5 h-5 aspect-square shrink-0 rounded-[4px] shadow-xs outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50",
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ function DropdownMenuContent({
|
|||||||
data-slot="dropdown-menu-content"
|
data-slot="dropdown-menu-content"
|
||||||
sideOffset={sideOffset}
|
sideOffset={sideOffset}
|
||||||
className={cn(
|
className={cn(
|
||||||
"bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 min-w-[8rem] overflow-hidden rounded-md border p-1 shadow-md",
|
"bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 min-w-[8rem] overflow-hidden rounded-xl border-2 border-black dark:border-border p-1 shadow-[4px_4px_0px_rgba(0,0,0,1)] dark:shadow-[4px_4px_0px_rgba(255,255,255,0.1)]",
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
@@ -72,7 +72,7 @@ function DropdownMenuItem({
|
|||||||
data-inset={inset}
|
data-inset={inset}
|
||||||
data-variant={variant}
|
data-variant={variant}
|
||||||
className={cn(
|
className={cn(
|
||||||
"focus:bg-accent focus:text-accent-foreground data-[variant=destructive]:text-destructive-foreground data-[variant=destructive]:focus:bg-destructive/10 dark:data-[variant=destructive]:focus:bg-destructive/40 data-[variant=destructive]:focus:text-destructive-foreground data-[variant=destructive]:*:[svg]:!text-destructive-foreground [&_svg:not([class*='text-'])]:text-muted-foreground relative flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 data-[inset]:pl-8 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
"focus:bg-primary/15 focus:text-foreground data-[variant=destructive]:text-destructive-foreground data-[variant=destructive]:focus:bg-destructive/10 dark:data-[variant=destructive]:focus:bg-destructive/40 data-[variant=destructive]:focus:text-destructive-foreground data-[variant=destructive]:*:[svg]:!text-destructive-foreground [&_svg:not([class*='text-'])]:text-muted-foreground relative flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 data-[inset]:pl-8 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
@@ -90,7 +90,7 @@ function DropdownMenuCheckboxItem({
|
|||||||
<DropdownMenuPrimitive.CheckboxItem
|
<DropdownMenuPrimitive.CheckboxItem
|
||||||
data-slot="dropdown-menu-checkbox-item"
|
data-slot="dropdown-menu-checkbox-item"
|
||||||
className={cn(
|
className={cn(
|
||||||
"focus:bg-accent focus:text-accent-foreground relative flex cursor-default items-center gap-2 rounded-sm py-1.5 pr-2 pl-8 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
"focus:bg-primary/15 focus:text-foreground relative flex cursor-default items-center gap-2 rounded-sm py-1.5 pr-2 pl-8 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
checked={checked}
|
checked={checked}
|
||||||
@@ -126,7 +126,7 @@ function DropdownMenuRadioItem({
|
|||||||
<DropdownMenuPrimitive.RadioItem
|
<DropdownMenuPrimitive.RadioItem
|
||||||
data-slot="dropdown-menu-radio-item"
|
data-slot="dropdown-menu-radio-item"
|
||||||
className={cn(
|
className={cn(
|
||||||
"focus:bg-accent focus:text-accent-foreground relative flex cursor-default items-center gap-2 rounded-sm py-1.5 pr-2 pl-8 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
"focus:bg-primary/15 focus:text-foreground relative flex cursor-default items-center gap-2 rounded-sm py-1.5 pr-2 pl-8 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
@@ -209,7 +209,7 @@ function DropdownMenuSubTrigger({
|
|||||||
data-slot="dropdown-menu-sub-trigger"
|
data-slot="dropdown-menu-sub-trigger"
|
||||||
data-inset={inset}
|
data-inset={inset}
|
||||||
className={cn(
|
className={cn(
|
||||||
"focus:bg-accent focus:text-accent-foreground data-[state=open]:bg-accent data-[state=open]:text-accent-foreground flex cursor-default items-center rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-[inset]:pl-8",
|
"focus:bg-primary/15 focus:text-foreground data-[state=open]:bg-accent data-[state=open]:text-accent-foreground flex cursor-default items-center rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-[inset]:pl-8",
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ export function UserMenuContent({ user }: UserMenuContentProps) {
|
|||||||
onClick={cleanup}
|
onClick={cleanup}
|
||||||
>
|
>
|
||||||
<Settings className="mr-2" />
|
<Settings className="mr-2" />
|
||||||
Settings
|
Paramètres
|
||||||
</Link>
|
</Link>
|
||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
</DropdownMenuGroup>
|
</DropdownMenuGroup>
|
||||||
@@ -56,7 +56,7 @@ export function UserMenuContent({ user }: UserMenuContentProps) {
|
|||||||
data-test="logout-button"
|
data-test="logout-button"
|
||||||
>
|
>
|
||||||
<LogOut className="mr-2" />
|
<LogOut className="mr-2" />
|
||||||
Log out
|
Se déconnecter
|
||||||
</Link>
|
</Link>
|
||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
</>
|
</>
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ export default function NavGuestLayout() {
|
|||||||
<>
|
<>
|
||||||
<header className="flex justify-between items-center my-6 w-full max-w-[335px] lg:max-w-7xl text-sm">
|
<header className="flex justify-between items-center my-6 w-full max-w-[335px] lg:max-w-7xl text-sm">
|
||||||
{/* Logo */}
|
{/* Logo */}
|
||||||
<Link href={home()} className="flex items-center gap-2 font-medium no-underline">
|
<Link href={home()} className="flex items-center gap-2 font-medium no-underline text-foreground">
|
||||||
<div className="flex items-center justify-center rounded-md">
|
<div className="flex items-center justify-center rounded-md">
|
||||||
<AppLogo className="max-w-[200px] max-h-[42px] w-full h-auto" />
|
<AppLogo className="max-w-[200px] max-h-[42px] w-full h-auto" />
|
||||||
</div>
|
</div>
|
||||||
@@ -79,13 +79,13 @@ export default function NavGuestLayout() {
|
|||||||
|
|
||||||
{auth.user ? (
|
{auth.user ? (
|
||||||
<>
|
<>
|
||||||
<Link href={dashboard()} className="no-underline">
|
<Link href={dashboard()} className="no-underline text-foreground">
|
||||||
<Button variant="outline">Tableau de bord</Button>
|
<Button variant="outline">Tableau de bord</Button>
|
||||||
</Link>
|
</Link>
|
||||||
<Link
|
<Link
|
||||||
href={logout()}
|
href={logout()}
|
||||||
onClick={handleLogout}
|
onClick={handleLogout}
|
||||||
className="border-3 bg-secondary text-secondary-foreground hover:bg-secondary/80 h-10 px-4 py-2 shadow-[4px_4px_0px_rgba(0,0,0,1)] hover:shadow-none hover:translate-2 transition delay-50 duration-200 ease-in-out font-bold no-underline"
|
className="nb-shadow bg-secondary text-secondary-foreground hover:bg-secondary/80 h-10 px-4 py-2 font-bold no-underline"
|
||||||
data-test="logout-button"
|
data-test="logout-button"
|
||||||
>
|
>
|
||||||
Se déconnecter
|
Se déconnecter
|
||||||
@@ -103,7 +103,7 @@ export default function NavGuestLayout() {
|
|||||||
)}
|
)}
|
||||||
<button
|
<button
|
||||||
onClick={toggleAppearance}
|
onClick={toggleAppearance}
|
||||||
className="border-3 bg-primary text-secondary-foreground hover:bg-primary/80 h-10 px-4 py-2 shadow-[4px_4px_0px_rgba(0,0,0,1)] hover:shadow-none hover:translate-2 transition delay-50 duration-200 ease-in-out font-bold no-underline"
|
className="nb-shadow bg-primary text-secondary-foreground hover:bg-primary/80 h-10 px-4 py-2 font-bold no-underline"
|
||||||
aria-label="Changer le thème"
|
aria-label="Changer le thème"
|
||||||
>
|
>
|
||||||
{appearance === 'dark' ? <Sun className="size-4" /> : <Moon className="size-4" />}
|
{appearance === 'dark' ? <Sun className="size-4" /> : <Moon className="size-4" />}
|
||||||
@@ -114,7 +114,7 @@ export default function NavGuestLayout() {
|
|||||||
<div className="flex lg:hidden items-center gap-2">
|
<div className="flex lg:hidden items-center gap-2">
|
||||||
<button
|
<button
|
||||||
onClick={() => setIsMenuOpen(!isMenuOpen)}
|
onClick={() => setIsMenuOpen(!isMenuOpen)}
|
||||||
className="border-3 bg-secondary text-secondary-foreground hover:bg-secondary/80 h-10 px-4 py-2 shadow-[4px_4px_0px_rgba(0,0,0,1)] hover:shadow-none hover:translate-2 transition delay-50 duration-200 ease-in-out font-bold no-underline"
|
className="nb-shadow bg-secondary text-secondary-foreground hover:bg-secondary/80 h-10 px-4 py-2 font-bold no-underline"
|
||||||
aria-label={isMenuOpen ? 'Fermer le menu' : 'Ouvrir le menu'}
|
aria-label={isMenuOpen ? 'Fermer le menu' : 'Ouvrir le menu'}
|
||||||
aria-expanded={isMenuOpen}
|
aria-expanded={isMenuOpen}
|
||||||
>
|
>
|
||||||
@@ -122,7 +122,7 @@ export default function NavGuestLayout() {
|
|||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
onClick={toggleAppearance}
|
onClick={toggleAppearance}
|
||||||
className="border-3 bg-primary text-secondary-foreground hover:bg-primary/80 h-10 px-4 py-2 shadow-[4px_4px_0px_rgba(0,0,0,1)] hover:shadow-none hover:translate-2 transition delay-50 duration-200 ease-in-out font-bold no-underline"
|
className="nb-shadow bg-primary text-secondary-foreground hover:bg-primary/80 h-10 px-4 py-2 font-bold no-underline"
|
||||||
aria-label="Changer le thème"
|
aria-label="Changer le thème"
|
||||||
>
|
>
|
||||||
{appearance === 'dark' ? <Sun className="size-4" /> : <Moon className="size-4" />}
|
{appearance === 'dark' ? <Sun className="size-4" /> : <Moon className="size-4" />}
|
||||||
@@ -177,7 +177,7 @@ export default function NavGuestLayout() {
|
|||||||
<div className="flex flex-col gap-3">
|
<div className="flex flex-col gap-3">
|
||||||
{auth.user ? (
|
{auth.user ? (
|
||||||
<>
|
<>
|
||||||
<Link href={dashboard()} onClick={closeMenu} className="no-underline mx-auto mb-4">
|
<Link href={dashboard()} onClick={closeMenu} className="no-underline text-foreground mx-auto mb-4">
|
||||||
<Button variant="outline" className="max-w-[150px]">Tableau de bord</Button>
|
<Button variant="outline" className="max-w-[150px]">Tableau de bord</Button>
|
||||||
</Link>
|
</Link>
|
||||||
<Link
|
<Link
|
||||||
@@ -185,7 +185,7 @@ export default function NavGuestLayout() {
|
|||||||
method="post"
|
method="post"
|
||||||
as="button"
|
as="button"
|
||||||
onClick={() => { closeMenu(); handleLogout(); }}
|
onClick={() => { closeMenu(); handleLogout(); }}
|
||||||
className="inline-flex items-center justify-center max-w-[150px] mx-auto gap-2 whitespace-nowrap rounded-md text-sm font-bold cursor-pointer focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 bg-secondary text-secondary-foreground hover:bg-secondary/80 h-10 px-4 py-2 border-3 border-black shadow-[4px_4px_0px_rgba(0,0,0,1)] hover:shadow-none hover:translate-2 transition delay-50 duration-200 ease-in-out w-full no-underline"
|
className="nb-shadow inline-flex items-center justify-center max-w-[150px] mx-auto gap-2 whitespace-nowrap rounded-md text-sm font-bold cursor-pointer focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 bg-secondary text-secondary-foreground hover:bg-secondary/80 h-10 px-4 py-2 w-full no-underline"
|
||||||
data-test="logout-button"
|
data-test="logout-button"
|
||||||
>
|
>
|
||||||
Se déconnecter
|
Se déconnecter
|
||||||
|
|||||||
@@ -14,10 +14,10 @@ import AuthLayout from '@/layouts/auth-layout';
|
|||||||
export default function ForgotPassword({ status }: { status?: string }) {
|
export default function ForgotPassword({ status }: { status?: string }) {
|
||||||
return (
|
return (
|
||||||
<AuthLayout
|
<AuthLayout
|
||||||
title="Forgot password"
|
title="Mot de passe oublié"
|
||||||
description="Enter your email to receive a password reset link"
|
description="Entrez votre adresse mail pour recevoir le lien de réinitialisation de mot de passe"
|
||||||
>
|
>
|
||||||
<Head title="Forgot password" />
|
<Head title="Mot de passe oublié" />
|
||||||
|
|
||||||
{status && (
|
{status && (
|
||||||
<div className="mb-4 text-center text-sm font-medium text-green-600">
|
<div className="mb-4 text-center text-sm font-medium text-green-600">
|
||||||
@@ -30,14 +30,14 @@ export default function ForgotPassword({ status }: { status?: string }) {
|
|||||||
{({ processing, errors }) => (
|
{({ processing, errors }) => (
|
||||||
<>
|
<>
|
||||||
<div className="grid gap-2">
|
<div className="grid gap-2">
|
||||||
<Label htmlFor="email">Email address</Label>
|
<Label htmlFor="email">Adresse Mail</Label>
|
||||||
<Input
|
<Input
|
||||||
id="email"
|
id="email"
|
||||||
type="email"
|
type="email"
|
||||||
name="email"
|
name="email"
|
||||||
autoComplete="off"
|
autoComplete="off"
|
||||||
autoFocus
|
autoFocus
|
||||||
placeholder="email@example.com"
|
placeholder="email@exemple.com"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<InputError message={errors.email} />
|
<InputError message={errors.email} />
|
||||||
@@ -52,7 +52,7 @@ export default function ForgotPassword({ status }: { status?: string }) {
|
|||||||
{processing && (
|
{processing && (
|
||||||
<LoaderCircle className="h-4 w-4 animate-spin" />
|
<LoaderCircle className="h-4 w-4 animate-spin" />
|
||||||
)}
|
)}
|
||||||
Email password reset link
|
Envoyer le mail de réinitialisation
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
@@ -60,8 +60,8 @@ export default function ForgotPassword({ status }: { status?: string }) {
|
|||||||
</Form>
|
</Form>
|
||||||
|
|
||||||
<div className="space-x-1 text-center text-sm text-muted-foreground">
|
<div className="space-x-1 text-center text-sm text-muted-foreground">
|
||||||
<span>Or, return to</span>
|
<span>Ou, retourner à la page</span>
|
||||||
<TextLink href={login()}>log in</TextLink>
|
<TextLink href={login()}>Se connecter</TextLink>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</AuthLayout>
|
</AuthLayout>
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import { FlashMessage } from '@/components/flash-message';
|
|||||||
import { Container } from '@/components/common/Container';
|
import { Container } from '@/components/common/Container';
|
||||||
import { SectionHeading } from '@/components/common/SectionHeading';
|
import { SectionHeading } from '@/components/common/SectionHeading';
|
||||||
import { Footer } from '@/components/footer';
|
import { Footer } from '@/components/footer';
|
||||||
|
import IllustrationLogo from "@/img/utils/lrl-logo-full.svg";
|
||||||
|
|
||||||
export default function Contact() {
|
export default function Contact() {
|
||||||
const { flash, captcha_question } = usePage().props as PageProps;
|
const { flash, captcha_question } = usePage().props as PageProps;
|
||||||
@@ -50,6 +51,7 @@ export default function Contact() {
|
|||||||
color="primary"
|
color="primary"
|
||||||
subtitle="Une question, une remarque ? Remplissez le formulaire ci-dessous, nous vous répondrons dans les plus brefs délais."
|
subtitle="Une question, une remarque ? Remplissez le formulaire ci-dessous, nous vous répondrons dans les plus brefs délais."
|
||||||
align="left"
|
align="left"
|
||||||
|
className="mx-auto"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{showFlashMessage && <FlashMessage messages={flash ?? {}} />}
|
{showFlashMessage && <FlashMessage messages={flash ?? {}} />}
|
||||||
@@ -60,11 +62,18 @@ export default function Contact() {
|
|||||||
disableWhileProcessing
|
disableWhileProcessing
|
||||||
>
|
>
|
||||||
{({ processing, errors }) => (
|
{({ processing, errors }) => (
|
||||||
<div className="grid grid-cols-1 lg:grid-cols-2 gap-8 max-w-4xl">
|
<div className="grid grid-cols-1 lg:grid-cols-2 gap-8 max-w-4xl mx-auto">
|
||||||
|
|
||||||
{/* Left — Identité + adresse */}
|
{/* Left — Identité + adresse */}
|
||||||
<div className="bg-white dark:bg-[#171717] rounded-2xl border-3 border-black p-6 shadow-[4px_4px_0px_rgba(0,0,0,1)] flex flex-col gap-4">
|
<div className="nb-shadow-static bg-primary dark:bg-[#171717] rounded-2xl p-6 flex flex-col gap-4">
|
||||||
<h2 className="text-lg font-semibold text-primary">Vos informations</h2>
|
<div className="lg:w-1/2 flex justify-center mx-auto">
|
||||||
|
<img
|
||||||
|
src={IllustrationLogo}
|
||||||
|
alt="Le Retzien Libre"
|
||||||
|
className="rounded-lg max-w-md w-full"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<h2 className="text-lg text-accent font-semibold">Vos informations</h2>
|
||||||
|
|
||||||
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
|
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
|
||||||
<div className="grid gap-1">
|
<div className="grid gap-1">
|
||||||
@@ -96,7 +105,7 @@ export default function Contact() {
|
|||||||
|
|
||||||
{/* Right — Message + captcha + submit */}
|
{/* Right — Message + captcha + submit */}
|
||||||
<div className="flex flex-col gap-6">
|
<div className="flex flex-col gap-6">
|
||||||
<div className="bg-white dark:bg-[#171717] rounded-2xl border-3 border-black p-6 shadow-[4px_4px_0px_rgba(0,0,0,1)] flex flex-col gap-4">
|
<div className="bg-white dark:bg-[#171717] nb-shadow-static rounded-2xl p-6 flex flex-col gap-4">
|
||||||
<h2 className="text-lg font-semibold text-primary">Votre message</h2>
|
<h2 className="text-lg font-semibold text-primary">Votre message</h2>
|
||||||
|
|
||||||
<div className="grid gap-1">
|
<div className="grid gap-1">
|
||||||
@@ -124,7 +133,7 @@ export default function Contact() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="bg-white dark:bg-[#171717] rounded-2xl border-3 border-black p-6 shadow-[4px_4px_0px_rgba(0,0,0,1)] flex flex-col gap-5">
|
<div className="bg-white dark:bg-[#171717] nb-shadow-static rounded-2xl p-6 flex flex-col gap-5">
|
||||||
<div className="grid gap-1">
|
<div className="grid gap-1">
|
||||||
<Label htmlFor="captcha" className="font-semibold">{captcha_question}</Label>
|
<Label htmlFor="captcha" className="font-semibold">{captcha_question}</Label>
|
||||||
<Input
|
<Input
|
||||||
@@ -143,10 +152,10 @@ export default function Contact() {
|
|||||||
type="submit"
|
type="submit"
|
||||||
variant="secondary"
|
variant="secondary"
|
||||||
tabIndex={8}
|
tabIndex={8}
|
||||||
className="w-full border-3 border-black shadow-[4px_4px_0px_rgba(0,0,0,1)] hover:shadow-none hover:translate-x-0.5 hover:translate-y-0.5 font-bold text-base py-5"
|
className="nb-shadow w-full font-bold text-base py-5"
|
||||||
>
|
>
|
||||||
{processing && <LoaderCircle className="h-4 w-4 animate-spin" />}
|
{processing && <LoaderCircle className="h-4 w-4 animate-spin" />}
|
||||||
Envoyer
|
Envoyer mon message
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import { FlashMessage } from '@/components/flash-message';
|
|||||||
import { Container } from '@/components/common/Container';
|
import { Container } from '@/components/common/Container';
|
||||||
import { SectionHeading } from '@/components/common/SectionHeading';
|
import { SectionHeading } from '@/components/common/SectionHeading';
|
||||||
import { Footer } from '@/components/footer';
|
import { Footer } from '@/components/footer';
|
||||||
|
import IllustrationLogo from "@/img/utils/lrl-logo-full.svg";
|
||||||
|
|
||||||
export default function Membership() {
|
export default function Membership() {
|
||||||
const { flash, plans, services, captcha_question } = usePage().props as PageProps;
|
const { flash, plans, services, captcha_question } = usePage().props as PageProps;
|
||||||
@@ -66,8 +67,15 @@ export default function Membership() {
|
|||||||
<div className="grid grid-cols-1 lg:grid-cols-2 gap-8">
|
<div className="grid grid-cols-1 lg:grid-cols-2 gap-8">
|
||||||
|
|
||||||
{/* Left — Personal info */}
|
{/* Left — Personal info */}
|
||||||
<div className="bg-white dark:bg-[#171717] rounded-2xl border-3 border-black p-6 shadow-[4px_4px_0px_rgba(0,0,0,1)] flex flex-col gap-4">
|
<div className="bg-primary dark:bg-[#171717] nb-shadow-static rounded-2xl p-6 flex flex-col gap-4">
|
||||||
<h2 className="text-lg font-semibold text-primary">Vos informations</h2>
|
<div className="lg:w-1/2 flex justify-center mx-auto">
|
||||||
|
<img
|
||||||
|
src={IllustrationLogo}
|
||||||
|
alt="Le Retzien Libre"
|
||||||
|
className="rounded-lg max-w-md w-full pt-4"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<h2 className="text-lg font-semibold text-accent">Vos informations</h2>
|
||||||
|
|
||||||
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
|
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
|
||||||
<div className="grid gap-1">
|
<div className="grid gap-1">
|
||||||
@@ -124,7 +132,7 @@ export default function Membership() {
|
|||||||
<div className="flex flex-col gap-6">
|
<div className="flex flex-col gap-6">
|
||||||
|
|
||||||
{/* Plan selection */}
|
{/* Plan selection */}
|
||||||
<div className="bg-white dark:bg-[#171717] rounded-2xl border-3 border-black p-6 shadow-[4px_4px_0px_rgba(0,0,0,1)] flex flex-col gap-4">
|
<div className="bg-white dark:bg-[#171717] nb-shadow-static rounded-2xl p-6 flex flex-col gap-4">
|
||||||
<h2 className="text-lg font-semibold text-primary">Choisissez votre formule</h2>
|
<h2 className="text-lg font-semibold text-primary">Choisissez votre formule</h2>
|
||||||
|
|
||||||
<div className="flex flex-col gap-3">
|
<div className="flex flex-col gap-3">
|
||||||
@@ -138,7 +146,7 @@ export default function Membership() {
|
|||||||
'flex items-center justify-between rounded-xl border-3 border-black px-5 py-4 text-left transition-all duration-150',
|
'flex items-center justify-between rounded-xl border-3 border-black px-5 py-4 text-left transition-all duration-150',
|
||||||
'shadow-[3px_3px_0px_rgba(0,0,0,1)] hover:shadow-none hover:translate-x-0.5 hover:translate-y-0.5',
|
'shadow-[3px_3px_0px_rgba(0,0,0,1)] hover:shadow-none hover:translate-x-0.5 hover:translate-y-0.5',
|
||||||
selectedPlan === plan.identifier
|
selectedPlan === plan.identifier
|
||||||
? 'bg-primary text-black'
|
? 'bg-secondary text-black'
|
||||||
: 'bg-white dark:bg-[#1a1a1a] hover:bg-primary/20',
|
: 'bg-white dark:bg-[#1a1a1a] hover:bg-primary/20',
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
@@ -162,17 +170,17 @@ export default function Membership() {
|
|||||||
<InputError message={errors.package} />
|
<InputError message={errors.package} />
|
||||||
|
|
||||||
<p className="text-center text-sm text-muted-foreground border-t border-border pt-3">
|
<p className="text-center text-sm text-muted-foreground border-t border-border pt-3">
|
||||||
Montant total : <strong className="text-primary text-lg">{amount}€</strong>
|
Montant total : <strong className="text-secondary text-lg">{amount}€</strong>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Services included */}
|
{/* Services included */}
|
||||||
<div className="bg-white dark:bg-[#171717] rounded-2xl border-3 border-black p-6 shadow-[4px_4px_0px_rgba(0,0,0,1)] flex flex-col gap-4">
|
<div className="bg-accent text-white dark:bg-[#171717] nb-shadow-static rounded-2xl p-6 flex flex-col gap-4">
|
||||||
<h2 className="text-lg font-semibold text-primary">Services inclus</h2>
|
<h2 className="text-lg font-semibold text-primary">Services inclus</h2>
|
||||||
<div className="grid grid-cols-1 sm:grid-cols-2 gap-3">
|
<div className="grid grid-cols-1 sm:grid-cols-2 gap-3">
|
||||||
{services?.map((service) => (
|
{services?.map((service) => (
|
||||||
<div key={service.name} className="flex items-start gap-2">
|
<div key={service.name} className="flex items-start gap-2">
|
||||||
<CheckIcon className="h-4 w-4 mt-0.5 shrink-0 text-accent" />
|
<CheckIcon className="h-4 w-4 mt-0.5 shrink-0 text-white" />
|
||||||
<div>
|
<div>
|
||||||
<p className="text-sm font-medium leading-tight">{service.name}</p>
|
<p className="text-sm font-medium leading-tight">{service.name}</p>
|
||||||
<p className="text-xs text-muted-foreground">{service.description}</p>
|
<p className="text-xs text-muted-foreground">{service.description}</p>
|
||||||
@@ -183,7 +191,7 @@ export default function Membership() {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Captcha + CGU + Submit */}
|
{/* Captcha + CGU + Submit */}
|
||||||
<div className="bg-white dark:bg-[#171717] rounded-2xl border-3 border-black p-6 shadow-[4px_4px_0px_rgba(0,0,0,1)] flex flex-col gap-5">
|
<div className="bg-white dark:bg-[#171717] nb-shadow-static rounded-2xl p-6 flex flex-col gap-5">
|
||||||
<div className="grid gap-1">
|
<div className="grid gap-1">
|
||||||
<Label htmlFor="captcha" className="font-semibold">{captcha_question}</Label>
|
<Label htmlFor="captcha" className="font-semibold">{captcha_question}</Label>
|
||||||
<Input
|
<Input
|
||||||
@@ -213,7 +221,7 @@ export default function Membership() {
|
|||||||
type="submit"
|
type="submit"
|
||||||
variant="secondary"
|
variant="secondary"
|
||||||
tabIndex={12}
|
tabIndex={12}
|
||||||
className="w-full border-3 border-black shadow-[4px_4px_0px_rgba(0,0,0,1)] hover:shadow-none hover:translate-x-0.5 hover:translate-y-0.5 font-bold text-base py-5"
|
className="nb-shadow w-full font-bold text-base py-5"
|
||||||
>
|
>
|
||||||
{processing && <LoaderCircle className="h-4 w-4 animate-spin" />}
|
{processing && <LoaderCircle className="h-4 w-4 animate-spin" />}
|
||||||
Envoyer ma demande d'adhésion
|
Envoyer ma demande d'adhésion
|
||||||
|
|||||||
Reference in New Issue
Block a user