From 6252b656712579de5aa7470f4d1058680c3161ce Mon Sep 17 00:00:00 2001 From: Colin Maudry Date: Wed, 15 Jul 2026 16:08:56 +0200 Subject: [PATCH] =?UTF-8?q?Aligne=20la=20hauteur=20du=20bouton=20de=20rech?= =?UTF-8?q?erche=20sur=20l'input=20(d=C3=A9bordement=20en=20bas)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Le bouton utilisait height:auto, dépendant du padding/line-height par défaut de .btn (~38px), plus haut que l'input fixé à 34px. Fixe la hauteur du bouton à 34px pour qu'il s'aligne avec l'input. Inclut aussi les changements en cours sur recherche.py (tagline dynamique avec stats, home_intro, layout en fonction). --- src/pages/recherche.py | 157 +++++++++++++++++++++++++---------------- tests/test_main.py | 13 ++++ 2 files changed, 109 insertions(+), 61 deletions(-) diff --git a/src/pages/recherche.py b/src/pages/recherche.py index bb8c44e..5a5ece6 100644 --- a/src/pages/recherche.py +++ b/src/pages/recherche.py @@ -1,15 +1,47 @@ +import math + import dash_bootstrap_components as dbc from dash import Input, Output, State, callback, dcc, html, register_page +from src.db import count_unique_marches from src.figures import DataTable from src.pages.a_propos.abonnement import abonnement_features +from src.utils.cache import cache from src.utils.data import DF_ACHETEURS, DF_TITULAIRES from src.utils.search import search_org from src.utils.seo import META_CONTENT -from src.utils.table import setup_table_columns +from src.utils.table import format_number, setup_table_columns NAME = "Recherche" +_STAT_STYLE = {"fontWeight": "bold", "color": "var(--primary-color-text)"} + + +@cache.memoize(timeout=12 * 60 * 60) +def _tagline_stats() -> tuple[str, str, str]: + nb_acheteurs = format_number(round(DF_ACHETEURS.height, -3)) + nb_titulaires = format_number(round(DF_TITULAIRES.height, -3)) + nb_marches_millions = math.floor(count_unique_marches() / 100_000) / 10 + unite_marches = "million" if nb_marches_millions < 2 else "millions" + nb_marches = f"{nb_marches_millions:.1f}".replace(".", ",") + " " + unite_marches + return nb_acheteurs, nb_titulaires, nb_marches + + +def _tagline() -> html.P: + nb_acheteurs, nb_titulaires, nb_marches = _tagline_stats() + return html.P( + [ + "Recherchez parmi ", + html.Span(nb_acheteurs, style=_STAT_STYLE), + " acheteurs et ", + html.Span(nb_titulaires, style=_STAT_STYLE), + " titulaires dans une base de données de plus de ", + html.Span(nb_marches, style=_STAT_STYLE), + " de marchés publics", + ] + ) + + _features_gratuites = dcc.Markdown(""" - Recherche d'acheteurs et de titulaires - [Tableau](/tableau) filtrable et personnalisable sur des dizaines de colonnes et exports Excel @@ -52,6 +84,7 @@ home_intro = html.Div( dcc.Link( "En savoir plus et s'abonner", href="/a-propos/abonnement", + style={"marginLeft": "20px"}, ), ], md=6, @@ -73,66 +106,68 @@ register_page( order=0, ) -layout = html.Div( - className="container", - children=[ - html.Div( - className="tagline", - children=html.P("Recherchez un acheteur ou un titulaire de marché public"), - ), - html.Div( - style={ - "display": "flex", - "justifyContent": "center", - "marginTop": "30px", - "marginBottom": "30px", - }, - children=[ - dcc.Input( - id="search", - type="text", - placeholder="Nom d'acheteur/entreprise, SIREN/SIRET, code département", - autoFocus=True, - style={ - "margin": "0", - "width": "500px", - "border": "1px solid #ccc", - "borderRight": "none", - "borderRadius": "3px 0 0 3px", - "padding": "5px 10px", - "outline": "none", - "height": "34px", - }, - ), - html.Button( - "=>", - id="search-button", - className="btn btn-secondary", - style={ - "border": "1px solid #ccc", - "borderRadius": "0 3px 3px 0", - "marginLeft": "0", - "height": "auto", # Ensure it matches input height if necessary, often relying on padding/line-height - }, - ), - ], - ), - html.P( - [ - "...ou bien filtrez les marchés publics dans la vue ", - dcc.Link("Tableau", href="/tableau"), - ], - style={"textAlign": "center"}, - id="mention_tableau", - ), - home_intro, - # html.Div( - # className="search_options", - # children=[dcc.RadioItems(options=["Acheteur(s)"])], - # ), - dbc.Row(id="search_results"), - ], -) + +def layout(**_): + return html.Div( + className="container", + children=[ + html.Div( + className="tagline", + children=_tagline(), + ), + html.Div( + style={ + "display": "flex", + "justifyContent": "center", + "marginTop": "30px", + "marginBottom": "30px", + }, + children=[ + dcc.Input( + id="search", + type="text", + placeholder="Nom d'acheteur/entreprise, SIREN/SIRET, code département", + autoFocus=True, + style={ + "margin": "0", + "width": "500px", + "border": "1px solid #ccc", + "borderRight": "none", + "borderRadius": "3px 0 0 3px", + "padding": "5px 10px", + "outline": "none", + "height": "34px", + }, + ), + html.Button( + "=>", + id="search-button", + className="btn btn-secondary", + style={ + "border": "1px solid #ccc", + "borderRadius": "0 3px 3px 0", + "marginLeft": "0", + "height": "34px", + }, + ), + ], + ), + html.P( + [ + "...ou bien filtrez les marchés publics dans la vue ", + dcc.Link("Tableau", href="/tableau"), + ], + style={"textAlign": "center"}, + id="mention_tableau", + ), + home_intro, + # html.Div( + # className="search_options", + # children=[dcc.RadioItems(options=["Acheteur(s)"])], + # ), + dbc.Row(id="search_results"), + ], + ) @callback( diff --git a/tests/test_main.py b/tests/test_main.py index df78a00..2f0d256 100644 --- a/tests/test_main.py +++ b/tests/test_main.py @@ -402,3 +402,16 @@ def test_015_org_pages_filter_date(dash_duo: DashComposite): # la mise à jour de la grille plutôt que de lire les lignes immédiatement # (sinon on lit l'état pré-filtre). dash_duo.wait_for_no_elements(filter_cell_result, timeout=4) + + +def test_016_search_button_matches_input_height(): + # Import app first to initialize Dash + from src.app import app # noqa: F401 + from src.pages.recherche import layout + + search_input, search_button = layout().children[1].children + + assert search_input.style["height"] == search_button.style["height"], ( + "Le bouton de recherche doit avoir la même hauteur que le champ de " + "recherche pour ne pas déborder en bas" + )