{# # ============================================================================ # ATOM: BUTTON # ============================================================================ # # Bouton paramétrable utilisant 100% Tailwind CSS. # Les couleurs sont définies dans: assets/styles/variables.css # # ============================================================================ # PARAMÈTRES # ============================================================================ # # | Paramètre | Type | Défaut | Description | # |----------------|---------|-------------|------------------------------------------------| # | label | string | '' | Texte du bouton | # | variant | string | 'primary' | Style visuel (voir variantes ci-dessous) | # | size | string | 'lg' | Taille: xs, sm, md, lg, xl | # | radius | string | 'lg' | Arrondi: none, sm, md, lg, xl, full | # | width | string | 'auto' | Largeur: auto, full | # | type | string | 'button' | Type HTML: button, submit, reset | # | href | string | null | Si défini, rendu comme | # | target | string | null | Target pour liens (_blank, etc.) | # | icon | string | null | Nom de l'icône (ex: 'check', 'plus') | # | iconPosition | string | 'left' | Position icône: left, right | # | iconOnly | bool | false | Afficher uniquement l'icône | # | mobileIconOnly | bool | false | Icône seule sur mobile, texte complet desktop | # | mobileBreakpoint | string | 'sm' | Breakpoint: 'sm', 'md', 'lg' | # | loading | bool | false | État de chargement avec spinner | # | disabled | bool | false | Désactiver le bouton | # | class | string | '' | Classes Tailwind additionnelles | # | attr | object | {} | Attributs HTML additionnels | # | labelAttr | object | {} | Attributs posés sur le du libellé | # | | | | (utile pour un target Stimulus qui réécrit le | # | | | | texte : le bouton lui-même en porte déjà un) | # | gradientFrom | string | null | Custom gradient start color (hex) | # | gradientTo | string | null | Custom gradient end color (hex) | # # ============================================================================ # VARIANTES (variant) # ============================================================================ # # | Variante | Description | # |----------------|-----------------------------------------------------| # | primary | Dégradé bleu principal avec shadow | # | secondary | Fond blanc, bordure bleue | # | success | Fond vert | # | error | Fond rouge | # | warning | Fond orange | # | dark | Fond noir | # | outline | Transparent avec bordure bleue | # | outline-dark | Transparent avec bordure noire | # | ghost | Transparent, fond gris au hover | # | back | Bouton retour (ghost + icône arrow-left auto) | # | link | Style lien avec underline | # | soft-primary | Fond bleu léger, texte primary | # | soft-success | Fond vert léger, texte success | # | soft-warning | Fond orange léger, texte warning | # | soft-error | Fond rouge léger, texte error | # | soft-cohorts | Fond violet léger, texte cohorts | # | cohorts | Dégradé violet cohorts avec shadow | # | custom-gradient | Dégradé personnalisé via gradientFrom/gradientTo | # | custom-soft | Fond+couleur via style inline (attr), hover:brightness-90 | # | ghost-primary | Transparent, hover bg primary-muted + texte primary | # | outline-light | Bordure primaire subtile, hover bg primary-muted | # | white | Fond blanc, texte primary, shadow-sm (sur fond coloré)| # # ============================================================================ # EXEMPLES D'UTILISATION # ============================================================================ # # Bouton simple: # {% include '_atoms/button/button.html.twig' with { label: 'Enregistrer' } %} # # Bouton avec icône: # {% include '_atoms/button/button.html.twig' with { # label: 'Ajouter', # variant: 'success', # icon: 'plus', # iconPosition: 'left' # } %} # # Bouton icône seule sur mobile, texte complet sur desktop (≥ lg): # {% include '_atoms/button/button.html.twig' with { # label: 'Export MBZ', # variant: 'primary', # icon: 'download', # mobileIconOnly: true, # mobileBreakpoint: 'lg' # } %} # # Bouton avec dégradé personnalisé (ex: couleur outil depuis DB): # {% include '_atoms/button/button.html.twig' with { # label: 'Essayer Slidia', # gradientFrom: c1, # gradientTo: c2, # size: 'lg' # } %} # # ============================================================================ #} {# ============================================================================ CONFIGURATION DES VALEURS PAR DÉFAUT ============================================================================ #} {% set label = label ?? '' %} {% set variant = variant ?? 'primary' %} {% set size = size ?? 'lg' %} {% set radius = radius ?? 'lg' %} {% set width = width ?? 'auto' %} {% set type = type ?? 'button' %} {% set href = href ?? null %} {% set target = target ?? null %} {% set icon = icon ?? null %} {% set iconPosition = iconPosition ?? 'left' %} {% set iconOnly = iconOnly ?? false %} {% set mobileIconOnly = mobileIconOnly ?? false %} {% set mobileBreakpoint = mobileBreakpoint ?? 'sm' %} {% set iconSize = iconSize ?? null %} {% set loading = loading ?? false %} {% set disabled = disabled ?? false %} {% set class = class ?? '' %} {% set attr = attr ?? {} %} {% set labelAttr = labelAttr ?? {} %} {% set gradientFrom = gradientFrom ?? null %} {% set gradientTo = gradientTo ?? null %} {% if gradientFrom and gradientTo %} {% set variant = 'custom-gradient' %} {% set customGradientStyle = 'background: linear-gradient(135deg, ' ~ gradientFrom ~ ', ' ~ gradientTo ~ '); box-shadow: 0 4px 14px ' ~ gradientFrom ~ '4D;' %} {% endif %} {% set outlineHex = outlineHex ?? null %} {% if outlineHex %} {% set variant = 'outline-tool' %} {% set outlineBtnId = 'btn-ol-' ~ random(9999999) %} {% endif %} {# Variant "back" : forcer icône arrow-left, radius xl, label par défaut #} {# Passer icon: false pour supprimer explicitement l'icône sur ce variant #} {% if variant == 'back' %} {% if icon is not same as(false) %} {% set icon = icon ? icon : 'arrow-left' %} {% else %} {% set icon = null %} {% endif %} {% set iconPosition = 'left' %} {% set radius = 'xl' %} {% set label = label ? label : 'Retour' %} {% endif %} {# ============================================================================ CLASSES TAILWIND - BASE Utilise les variables de tokens/variables.css ============================================================================ #} {% set baseClasses = 'inline-flex items-center justify-center gap-2 font-primary font-semibold leading-none no-underline text-center border-none cursor-pointer whitespace-nowrap select-none transition-all duration-base ease-default focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-primary/50 disabled:opacity-50 disabled:cursor-not-allowed disabled:pointer-events-none' %} {# ============================================================================ CLASSES TAILWIND - VARIANTES Toutes les couleurs utilisent les tokens définis dans variables.css ============================================================================ #} {# `outline-tool` — le blanc bordé des barres d'outils. Texte en gray-700 et non gray-600 : à la taille `sm`, le libellé passait pour désactivé à côté d'un bouton plein voisin. Son survol vient de `outlineHex`, qui teinte bordure, texte et fond à la couleur de l'outil. #} {% set variantClasses = { 'primary': 'bg-gradient-to-r from-gradient-start via-gradient-middle to-gradient-end text-white shadow-primary hover:shadow-primary-hover hover:-translate-y-0.5 active:translate-y-0', 'secondary': 'bg-white text-primary border-2 border-solid border-primary shadow-sm hover:bg-primary hover:text-white hover:shadow-primary hover:-translate-y-0.5 active:translate-y-0', 'success': 'bg-gradient-to-r from-gradient-success-start via-gradient-success-middle to-gradient-success-end text-white shadow-success hover:shadow-success-hover hover:-translate-y-0.5 active:translate-y-0', 'error': 'bg-gradient-to-r from-gradient-error-start via-gradient-error-middle to-gradient-error-end text-white shadow-error hover:shadow-error-hover hover:-translate-y-0.5 active:translate-y-0', 'warning': 'bg-gradient-to-r from-gradient-warning-start via-gradient-warning-middle to-gradient-warning-end text-white shadow-warning hover:shadow-warning-hover hover:-translate-y-0.5 active:translate-y-0', 'dark': 'bg-black text-white shadow-dark hover:bg-black-hover hover:shadow-dark-hover hover:-translate-y-0.5 active:translate-y-0', 'outline': 'bg-transparent text-primary border-2 border-solid border-primary hover:bg-primary hover:text-white hover:shadow-primary hover:-translate-y-0.5 active:translate-y-0', 'outline-dark': 'bg-transparent text-black border-2 border-solid border-black hover:bg-black hover:text-white hover:-translate-y-0.5 active:translate-y-0', 'ghost': 'bg-transparent text-gray-600 shadow-none hover:bg-gray-200 hover:-translate-y-0.5 active:translate-y-0', 'back': 'bg-white text-gray-600 border border-gray-200 shadow-sm hover:shadow-md hover:border-gray-300 hover:text-gray-900 hover:-translate-y-0.5 active:translate-y-0', 'link': 'bg-transparent text-primary shadow-none p-0 underline underline-offset-4 hover:text-primary-dark hover:bg-transparent hover:translate-y-0', 'soft-primary': 'bg-primary/10 text-primary hover:bg-primary/20 shadow-none hover:-translate-y-0.5 active:translate-y-0', 'soft-success': 'bg-success/10 text-success hover:bg-success/20 shadow-none hover:-translate-y-0.5 active:translate-y-0', 'soft-warning': 'bg-warning/10 text-warning hover:bg-warning/20 shadow-none hover:-translate-y-0.5 active:translate-y-0', 'soft-error': 'bg-error/10 text-error hover:bg-error/20 shadow-none hover:-translate-y-0.5 active:translate-y-0', 'soft-cohorts': 'bg-cohorts/10 text-cohorts hover:bg-cohorts/20 shadow-none hover:-translate-y-0.5 active:translate-y-0', 'cohorts': 'bg-gradient-to-r from-gradient-cohorts-start via-gradient-cohorts-middle to-gradient-cohorts-end text-white shadow-cohorts hover:shadow-cohorts-hover hover:-translate-y-0.5 active:translate-y-0', 'promptly': 'bg-gradient-to-r from-gradient-promptly-start via-gradient-promptly-middle to-gradient-promptly-end text-white shadow-promptly hover:shadow-promptly-hover hover:-translate-y-0.5 active:translate-y-0', 'soft-promptly': 'bg-promptly/10 text-promptly hover:bg-promptly/20 shadow-none hover:-translate-y-0.5 active:translate-y-0', 'pink': 'bg-gradient-to-r from-[#E91E8C] to-[#EC4899] text-white shadow-[0_4px_14px_rgba(233,30,140,0.30)] hover:shadow-[0_6px_20px_rgba(233,30,140,0.40)] hover:-translate-y-0.5 active:translate-y-0', 'custom-gradient': 'text-white hover:-translate-y-0.5 active:translate-y-0', 'custom-soft': 'shadow-none hover:brightness-[0.88] hover:saturate-[1.6] hover:-translate-y-0.5 active:translate-y-0', 'ghost-primary': 'bg-transparent text-gray-600 shadow-none hover:text-primary hover:bg-primary-muted', 'outline-light': 'bg-transparent text-gray-600 border border-primary/15 shadow-none hover:text-primary hover:bg-primary-muted', 'outline-amber': 'bg-white text-gray-600 border border-gray-200 shadow-sm hover:border-amber-300 hover:text-amber-600 hover:bg-amber-50 active:translate-y-0', 'outline-tool': 'bg-white text-gray-700 border border-gray-200 shadow-sm active:translate-y-0', 'white': 'bg-white text-primary shadow-sm hover:shadow-md hover:-translate-y-0.5 active:translate-y-0' } %} {# ============================================================================ CLASSES TAILWIND - TAILLES ============================================================================ #} {% set sizeClasses = { 'xs': 'h-6 px-2 text-xs gap-1', 'sm': 'h-8 px-3 sm:px-4 text-xs sm:text-sm gap-1.5', 'md': 'h-9 sm:h-10 px-4 sm:px-6 text-sm sm:text-base gap-2', 'lg': 'h-10 sm:h-12 px-5 sm:px-8 text-sm sm:text-base gap-2 sm:gap-2.5', 'xl': 'h-12 sm:h-14 px-7 sm:px-10 text-base sm:text-xl gap-2.5 sm:gap-3' } %} {# Classes pour iconOnly #} {% set iconOnlySizeClasses = { 'xs': 'h-6 w-6 p-0', 'sm': 'h-8 w-8 p-0', 'md': 'h-9 w-9 sm:h-10 sm:w-10 p-0', 'lg': 'h-10 w-10 sm:h-12 sm:w-12 p-0', 'xl': 'h-12 w-12 sm:h-14 sm:w-14 p-0' } %} {# Classes pour mobileIconOnly — icône seule < breakpoint, texte complet ≥ breakpoint #} {% set mobileIconOnlySizeClassesByBreakpoint = { 'sm': { 'xs': 'h-6 w-6 px-0 sm:w-auto sm:px-2 text-xs gap-1', 'sm': 'h-8 w-8 px-0 sm:w-auto sm:px-4 text-xs sm:text-sm gap-1.5', 'md': 'h-9 sm:h-10 w-9 sm:w-auto px-0 sm:px-6 text-sm sm:text-base gap-2', 'lg': 'h-10 sm:h-12 w-10 sm:w-auto px-0 sm:px-8 text-sm sm:text-base gap-2 sm:gap-2.5', 'xl': 'h-12 sm:h-14 w-12 sm:w-auto px-0 sm:px-10 text-base sm:text-xl gap-2.5 sm:gap-3' }, 'md': { 'xs': 'h-6 w-6 px-0 md:w-auto md:px-2 text-xs gap-1', 'sm': 'h-8 w-8 px-0 md:w-auto md:px-4 text-xs md:text-sm gap-1.5', 'md': 'h-9 md:h-10 w-9 md:w-auto px-0 md:px-6 text-sm md:text-base gap-2', 'lg': 'h-10 md:h-12 w-10 md:w-auto px-0 md:px-8 text-sm md:text-base gap-2 md:gap-2.5', 'xl': 'h-12 md:h-14 w-12 md:w-auto px-0 md:px-10 text-base md:text-xl gap-2.5 md:gap-3' }, 'lg': { 'xs': 'h-6 w-6 px-0 lg:w-auto lg:px-2 text-xs gap-1', 'sm': 'h-8 w-8 px-0 lg:w-auto lg:px-4 text-xs lg:text-sm gap-1.5', 'md': 'h-9 lg:h-10 w-9 lg:w-auto px-0 lg:px-6 text-sm lg:text-base gap-2', 'lg': 'h-10 lg:h-12 w-10 lg:w-auto px-0 lg:px-8 text-sm lg:text-base gap-2 lg:gap-2.5', 'xl': 'h-12 lg:h-14 w-12 lg:w-auto px-0 lg:px-10 text-base lg:text-xl gap-2.5 lg:gap-3' } } %} {% set mobileIconOnlySizeClasses = mobileIconOnlySizeClassesByBreakpoint[mobileBreakpoint] ?? mobileIconOnlySizeClassesByBreakpoint['sm'] %} {# ============================================================================ CLASSES TAILWIND - RADIUS ============================================================================ #} {% set radiusClasses = { 'none': 'rounded-none', 'sm': 'rounded-sm', 'md': 'rounded-md', 'lg': 'rounded-lg', 'xl': 'rounded-xl', 'full': 'rounded-full' } %} {# ============================================================================ CLASSES TAILWIND - LARGEUR ============================================================================ #} {% set widthClasses = { 'auto': '', 'full': 'w-full' } %} {# ============================================================================ CLASSES TAILWIND - ÉTATS ============================================================================ #} {# État désactivé — deux traitements, et c'est délibéré. Un {% endif %}