feat(frontend): socle de refonte au Système de Design de l'État (DSFR)
- charge le DSFR (CSS/JS officiels) en statique via public/dsfr + postinstall - en-tête officiel (bloc Marianne « République Française » + nom de service) - pied de page officiel DSFR (liens institutionnels, licence etalab) - page d'accueil refondue (hero, fr-card, fr-tile, fr-callout, fr-btn) - composant Button mappé sur fr-btn - assets DSFR hors git (régénérés par `npm install`) Build OK (19 routes). Pages internes encore en Tailwind : conversion à poursuivre. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -11,23 +11,19 @@ interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
|
||||
loading?: boolean;
|
||||
}
|
||||
|
||||
// Mappe les variantes internes sur les classes du Système de Design de l'État (DSFR).
|
||||
const variantClasses: Record<ButtonVariant, string> = {
|
||||
primary:
|
||||
"bg-candlelight-500 hover:bg-candlelight-600 text-black font-semibold shadow-sm hover:shadow-md",
|
||||
secondary:
|
||||
"bg-malachite-500 hover:bg-malachite-600 text-white font-semibold shadow-sm hover:shadow-md",
|
||||
outline:
|
||||
"border-2 border-candlelight-500 text-candlelight-700 dark:text-candlelight-400 hover:bg-candlelight-50 dark:hover:bg-candlelight-950",
|
||||
ghost:
|
||||
"hover:bg-gray-100 dark:hover:bg-gray-800 text-gray-700 dark:text-gray-300",
|
||||
danger:
|
||||
"bg-red-500 hover:bg-red-600 text-white font-semibold shadow-sm hover:shadow-md",
|
||||
primary: "",
|
||||
secondary: "fr-btn--secondary",
|
||||
outline: "fr-btn--secondary",
|
||||
ghost: "fr-btn--tertiary-no-outline",
|
||||
danger: "fr-btn--secondary",
|
||||
};
|
||||
|
||||
const sizeClasses: Record<ButtonSize, string> = {
|
||||
sm: "px-3 py-1.5 text-sm",
|
||||
md: "px-5 py-2.5 text-base",
|
||||
lg: "px-7 py-3.5 text-lg",
|
||||
sm: "fr-btn--sm",
|
||||
md: "",
|
||||
lg: "fr-btn--lg",
|
||||
};
|
||||
|
||||
export default function Button({
|
||||
@@ -39,43 +35,18 @@ export default function Button({
|
||||
className = "",
|
||||
...rest
|
||||
}: ButtonProps) {
|
||||
const classes = [
|
||||
"fr-btn",
|
||||
variantClasses[variant],
|
||||
sizeClasses[size],
|
||||
loading ? "fr-btn--icon-left fr-icon-refresh-line" : "",
|
||||
className,
|
||||
]
|
||||
.filter(Boolean)
|
||||
.join(" ");
|
||||
|
||||
return (
|
||||
<button
|
||||
disabled={disabled || loading}
|
||||
className={`
|
||||
inline-flex items-center justify-center gap-2
|
||||
rounded-xl transition-all duration-200
|
||||
focus:outline-none focus:ring-2 focus:ring-candlelight-500 focus:ring-offset-2
|
||||
dark:focus:ring-offset-gray-900
|
||||
disabled:opacity-50 disabled:cursor-not-allowed
|
||||
${variantClasses[variant]}
|
||||
${sizeClasses[size]}
|
||||
${className}
|
||||
`}
|
||||
{...rest}
|
||||
>
|
||||
{loading && (
|
||||
<svg
|
||||
className="animate-spin h-4 w-4"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<circle
|
||||
className="opacity-25"
|
||||
cx="12"
|
||||
cy="12"
|
||||
r="10"
|
||||
stroke="currentColor"
|
||||
strokeWidth="4"
|
||||
/>
|
||||
<path
|
||||
className="opacity-75"
|
||||
fill="currentColor"
|
||||
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
|
||||
/>
|
||||
</svg>
|
||||
)}
|
||||
<button className={classes} disabled={disabled || loading} {...rest}>
|
||||
{children}
|
||||
</button>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user