Page de cas
Le cas raconté : la vitrine, le récit et sa fiche collante, la cellule allumée, la citation, le cas suivant, les cas limites.
Le déroulé
Huit blocs, d’après la maquette validée par JB le 12 octobre : le visuel d’abord, puis le récit et sa fiche, le point fort dans une cellule allumée, ce qu’en dit le client, le cas suivant, la bande et le contact. Tout vient de la fiche markdown de src/content/realisations et des libellés de pages-v3 et accueil-v3 ; la page n’écrit aucun texte.
| Bloc | Composant | Donnée |
|---|---|---|
| L’en-tête | EnTetePage, sans bouton : FilAriane, le logo, h1, chapô, étiquette d’offre | fil Réalisations › client (P.realisations.etiquette) ; logo : logoClient ; h1 : client ; chapô : resume ; étiquette : V3.realisations.offreLibelle de l’expertise ; le titre de l’onglet « client · Grinn » ; la description : resume, à défaut accroche, à défaut celle de la page Réalisations |
| La vitrine large | Section tr-sec--plein + Vitrine format large, eager | matiere, support, vitrine.capture, vitrine.adresse (à défaut le domaine de site), vitrine.puces ; P.realisations.reserve sans capture |
| Le récit et la fiche | Section #recit tr-sec--plein + div.tr-recit : Prose et FicheCas | le texte d’avant le premier ##, les sections 1 à 3, puis la 5e et les suivantes (src/data/recit-cas.ts) ; offre (nom et page), perimetre, stack, duree, remplace, depuis, tourne ; site (P.realisations.voirSite), sinon les stores (P.realisation.stores) ; V3.cta vers #contact |
| Le point fort | Section #point-fort tr-sec--plein + PointFort, une Vitrine format cellule dans son slot visuel | la 4e section ## et P.realisation.pointFort ; etapes ; vitrine.captureAngle, adresseAngle, pucesAngle (angle) ; sans captureAngle, la capture de tête sans puces |
| La citation | Section #citation tr-sec--plein, nommée par aria-label + CitationCas | la collection verbatims, par son champ client (l’id du cas ou le nom) ; sinon P.realisation.citation : emplacement au nom du client, signataire, note |
| Le cas suivant | Section #cas-suivant tr-sec--plein + CasSuivant, une Vitrine format carte sans puces dans son slot visuel | « P.realisation.suivant · » et l’offre du cas suivant ; client ; accroche, à défaut resume ; P.realisations.lireCas |
| La bande | Bande motif a | aucune : décorative |
| Le contact | Section #contact tr-contact + Contact | V3.contact (surtitre, sousTitre, corps, types), V3.cta, P.realisation.contact.titre ; typeProjet : celui de l’offre, sinon l’étiquette si V3.contact.types la propose |
Une page sort pour chaque fiche marquée page, avec l’accord du client et sans masque : aujourd’hui 7, Bosco Services, Cathédrale de Nantes, PepPsy, La Grande Table, Mes Jardiniers, Clotilde Davenne, Builders. Le récit est découpé à chaque ## par src/data/recit-cas.ts ; chaque morceau passe par le processeur markdown d’Astro, avec les réglages du site. Deux blocs de la page précédente sont partis : les tarifs du suivi, qui restent sur /suivi/, et le relevé en paires clé et valeur, dont la durée, ce que ça remplace et la mise en service passent dans la fiche ; la ligne du résultat n’a plus de place.
L’en-tête et la vitrine large
Le fil, le logo du client, son nom, son résumé, l’étiquette d’offre, et aucun bouton : celui du contact est dans la fiche. Puis la vitrine en 21/9, d’un rail à l’autre : la matière du client, la capture principale dans son cadre, ses puces.
Mes Jardiniers
Un site où l’on réserve son jardinier en quelques clics, et derrière, le logiciel qui planifie les interventions des équipes terrain.
Site internet et logiciel métier
const tete = {
fil: [{ href: '/realisations/', libelle: P.realisations.etiquette }, { href: `/realisations/${cas.id}/`, libelle: nom }],
titre: nom, lead: d.resume ?? undefined, offre: etiquette, logo: logoClient(cas.id),
}
<EnTetePage {...tete} />
<Section classe="tr-sec--plein">
<Vitrine slug={cas.id} matiere={d.matiere} support={d.support} vitrine={d.vitrine} site={d.site}
format="large" eager reserve={P.realisations.reserve} />
</Section> | Classe | Zone | Valeur |
|---|---|---|
| .tr-page__marque .tr-page__logo | le logo | 36 px de haut × --echelle, 200 px au plus, opacité .9 ; marge de 19 px en haut, 18 px en bas ; alt vide, le titre porte le nom |
| .tr-page h1 | le nom | Outfit 700 clamp(36px, 4.6vw, 66px), interligne 0,98, -0,03em, 16ch au plus, équilibré : le titre des pages intérieures |
| .tr-page .lead | le résumé | 48ch au plus |
| .tr-page__offre | l’étiquette d’offre | une étiquette de section (.tr-etq, avec son carré vert moyen), 26 px sous le chapô |
| .tr-sec--plein > .tr-in | les sections du cas | padding 0 : la vitrine, le récit, la cellule, la citation et le cas suivant vont d’un rail à l’autre, et posent chacun leur marge |
| Vitrine format large | la vitrine de tête | 21/9 ; le navigateur à 62 % de large et 6 % sous le bas, la borne à 48 % dès 721 px ; trois puces au plus ; en 4/3 et sans puces sous 720 px ; chargée tout de suite (eager) |
EnTetePage a deux props que seule la page de cas passe : logo, posé au-dessus du titre quand le fichier existe, et offre, l’étiquette sous le chapô. Les cadres, les formats et les places des puces sont dans Vitrine des cas.
Le récit et la fiche collante
À gauche, le récit : le texte de la fiche jusqu’à la troisième section. À droite, le projet en bref, sur fond pâle, qui reste à portée pendant la lecture. Les lignes suivent toujours le même ordre et ne portent que des faits que Grinn détient : jamais un résultat.
Le problème
Mes Jardiniers entretient les jardins de particuliers dans quatorze communes autour de Nantes, avec ses propres équipes salariées. Le planning tournait sur un logiciel du marché, sans lien avec le site. Chaque demande reçue en ligne était ressaisie à la main.
Ce logiciel ne connaissait ni les forfaits ni les tournées par secteur. Il se prêtait mal à un usage au téléphone, sur le terrain.
Ce qui a été construit
Côté client, un site où l’on choisit son forfait, son créneau et son adresse, puis où l’on décrit son besoin. Une demande hors forfait passe par un devis, et chaque commune desservie a sa page.
Côté agence, un logiciel métier qui gère les clients et les contrats annuels, compose les tournées et répartit les interventions entre les équipes.
Les décisions techniques
Le site et le logiciel sont développés en Next.js et partagent les mêmes données. Aucune passerelle n’est à entretenir entre deux outils.
Le logiciel est pensé pour le téléphone autant que pour le bureau. Ses premiers utilisateurs passent leurs journées dans les jardins.
const { recit, fort } = await recitCas(cas.body)
<Section id="recit" classe="tr-sec--plein">
<div class="tr-recit">
<div class="tr-recit__texte"><Prose><Fragment set:html={recit} /></Prose></div>
<FicheCas label={P.realisation.releve.titre} libelles={P.realisation.fiche} offre={offre}
perimetre={d.perimetre} stack={d.stack} duree={d.duree} remplace={d.remplace} depuis={d.depuis} tourne={d.tourne}
externes={externes} cta={{ href: '#contact', libelle: V3.cta }} />
</div>
</Section> | Classe | Zone | Valeur |
|---|---|---|
| .tr-recit | le récit et la fiche | une colonne ; dès 960 px, 1fr et 360 px, alignés en haut |
| .tr-recit__texte | le récit | padding clamp(28px, 4vw, 56px) en haut et en bas ; dès 960 px, un trait pointillé vertical à sa droite |
| .tr-recit .tr-prose | le texte | la prose de la trame (64ch, marge clamp(20px, 3vw, 48px)) ; le premier paragraphe à l’encre, les suivants à l’encre seconde |
| .tr-fiche | la fiche | aside, nommée par P.realisation.releve.titre ; fond pâle ; dès 960 px, collante à 64 px du haut, sous l’en-tête collé du site ; dessous, à sa place sous le récit, un trait pointillé en haut |
| .tr-fiche__l | une ligne | padding 16 / 22 px, trait pointillé en bas ; une ligne sans valeur ne s’affiche pas |
| .tr-fiche dt | la clé | Inter 600 11 px, capitales, .14em, encre troisième, 8 px au-dessus de la valeur |
| .tr-fiche dd | la valeur | 15 px, interligne 1,45, encre ; le lien d’offre souligné de vert profond, et sa ligne entière cliquable (::after en inset 0) |
| .tr-fiche__liste | ce qu’on a fait | sans puce ; un carré vert profond de 6 px devant chaque ligne |
| .tr-fiche__puces span | la stack | trait vert, fond blanc, Inter 600 10 px capitales, .12em, vert profond ; écart 6 px |
| .tr-fiche__liens | les liens | padding 18 / 22 / 22 px, écart 8 px ; des petits boutons pleine largeur, la flèche au bout : le site ou les stores au trait, dans un nouvel onglet, puis le bouton plein vers #contact |
L’ordre des lignes : Offre, Ce qu’on a fait, Avec, Durée, Ce que ça remplace, En service depuis, Aujourd’hui (P.realisation.fiche), puis les liens. L’offre mène à sa page quand la fiche en nomme une. La fiche n’a pas de titre visible : son nom pour les lecteurs d’écran est « Le projet en bref. ».
La cellule allumée
La quatrième section du récit, propre au cas, dans une cellule vert clair qui va d’un rail à l’autre : l’étiquette, le titre, le texte, les étapes de la fiche au besoin, et une seconde vitrine à droite. Sous 861 px, la vitrine passe sous le texte.
Le point fort
De la réservation au camion
Un client réserve un forfait sur le site, et la demande entre aussitôt dans le planning. Elle prend sa place dans la tournée du bon secteur.
Le chef d’équipe retrouve l’intervention sur son téléphone, avec l’adresse et le besoin décrit par le client. Personne ne recopie rien entre les deux.
- Site Le client réserve
- Planning La tournée se compose
- Terrain L’équipe intervient
{fort && (
<Section id="point-fort" classe="tr-sec--plein" titreId="tr-fort">
<PointFort etiquette={P.realisation.pointFort} titre={fort.titre} texte={fort.texte} etapes={d.etapes} titreId="tr-fort">
<Vitrine slot="visuel" slug={cas.id} matiere={d.matiere} support={d.support} vitrine={vitrine} site={d.site}
angle={Boolean(vitrine.captureAngle)} maxPuces={vitrine.captureAngle ? undefined : 0} format="cellule" reserve={P.realisations.reserve} />
</PointFort>
</Section>
)} | Classe | Zone | Valeur |
|---|---|---|
| .tr-fort | la cellule allumée | fond --grinn-light (#E9F4EA), d’un rail à l’autre ; une colonne ; dès 861 px, 1fr et 1,2fr |
| .tr-fort__texte | le texte | padding clamp(28px, 4vw, 56px) clamp(20px, 3vw, 48px), écart 18 px, centré en hauteur |
| .tr-fort .tr-etq | l’étiquette | P.realisation.pointFort, sur fond blanc |
| .tr-fort h2 | le titre | le titre de la 4e section ; var(--t-h2), clamp(28px, 3.9vw, 50px), 12ch au plus, équilibré |
| .tr-fort__corps p | le texte | 44ch, interligne 1,6, encre seconde ; 14 px entre deux paragraphes |
| .tr-fort__etapes | les étapes | une liste ordonnée, une colonne par étape (--n), trait pointillé en haut ; sous 480 px, une étape par ligne, séparées d’un trait |
| .tr-fort__etapes b | le nom | Inter 600 11 px, capitales, .14em, encre seconde (6,8:1 sur le vert clair) ; la flèche → vers l’étape suivante, décorative (aria-hidden), en vert profond |
| .tr-fort__etapes li > span | le texte de l’étape | 14 px, interligne 1,4, encre ; un mot trop long se coupe |
| Vitrine format cellule | la vitrine | la hauteur de la rangée, 440 px au moins, à toutes les largeurs ; sous 861 px, sous le texte |
Le titre et le texte arrivent déjà rendus par le processeur markdown : la typographie du récit reste telle quelle. Le vert clair est un vert Grinn : aucune teinte nouvelle. Sans captureAngle, la cellule reprend la capture de tête sans ses puces : c’est aujourd’hui le cas de Bosco Services, Cathédrale de Nantes, PepPsy, La Grande Table, Clotilde Davenne. Une seconde capture par cas reste à fournir.
La citation
Une carte bordée, le logo, la citation, la signature ; à côté, l’étiquette. Aucun texte client n’est inventé : tant que le verbatim signé manque, la carte montre sa réserve au nom du client, en encre troisième, et la note dit qu’il est à venir.
Le témoignage de Mes Jardiniers sur le travail mené ensemble.
Ce qu’en dit le client
Témoignage signé à venir.
<Section id="citation" classe="tr-sec--plein" label={C.etiquette}>
<CitationCas verbatim={verbatim} logo={logo} client={nom} etiquette={C.etiquette}
emplacement={C.emplacement.replace('{client}', nom)} signataire={C.signataire} note={C.note} />
</Section> | Classe | Zone | Valeur |
|---|---|---|
| .tr-citation | le bloc | une colonne ; dès 861 px, deux : la carte, puis l’étiquette et la note ; centrés en hauteur |
| .tr-citation__carte | la carte | figure, fond blanc, bord plein --line ; marge clamp(20px, 3vw, 40px), padding clamp(24px, 3vw, 40px) |
| .tr-citation__logo | le logo | 24 px × --echelle, 150 px au plus, opacité .9 ; alt vide en réserve, le client quand la citation est signée |
| .tr-citation blockquote | la citation | Outfit 500 clamp(20px, 1.8vw, 24px), interligne 1,35, -0,02em, encre, entre « » ; en réserve, l’emplacement en encre troisième |
| figcaption | la signature | Inter 600 11 px capitales, encre troisième ; auteur et fonction, ou P.realisation.citation.signataire |
| .tr-citation__note | à côté | l’étiquette, et la note tant que la citation manque ; 40ch, encre seconde |
La page cherche le verbatim dans la collection verbatims par son champ client, comparé à l’identifiant du cas et au nom du client. Aujourd’hui, 1 verbatim a un client et une citation. Le mur de citations de l’accueil est un autre composant, dans Citations.
Le cas suivant
Le nom en grand, l’accroche, un bouton dessiné, et la vitrine du cas à droite : tout le bloc est un lien. On suit l’ordre des fiches parmi les cas publiés ; le dernier renvoie au premier.
{suivant && (
<Section id="cas-suivant" classe="tr-sec--plein" titreId="tr-suivant">
<CasSuivant href={`/realisations/${suivant.id}/`} etiquette={`${P.realisation.suivant} · ${libelleOffre(suivant.data.expertise)}`}
nom={suivant.data.client} accroche={suivant.data.accroche ?? suivant.data.resume} bouton={P.realisations.lireCas} titreId="tr-suivant">
<Vitrine slot="visuel" slug={suivant.id} matiere={suivant.data.matiere} support={suivant.data.support} vitrine={suivant.data.vitrine}
site={suivant.data.site} maxPuces={0} reserve={P.realisations.reserve} />
</CasSuivant>
</Section>
)} | Classe | Zone | Valeur |
|---|---|---|
| .tr-suivant | le bloc | un seul lien ; une colonne ; dès 861 px, deux, la vitrine à droite ; fond pâle au survol et au focus, en 380 ms |
| .tr-suivant:focus-visible::after | le focus | l’anneau vert profond de 2 px, tracé par-dessus tout le bloc (décalé de -3 px) : la vitrine ne le cache pas |
| .tr-suivant__texte | le texte | padding clamp(28px, 4vw, 56px) clamp(20px, 3vw, 48px), écart 14 px, centré en hauteur |
| .tr-suivant__etq | l’étiquette | « P.realisation.suivant · » et l’offre : Inter 600 11 px capitales, encre troisième, sans pastille |
| .tr-suivant h2 | le nom | var(--t-h2), clamp(28px, 3.9vw, 50px), équilibré ; 17ch au plus, la largeur des titres de la trame (.tr h2), que la règle ne réduit pas |
| .tr-suivant__accroche | l’accroche | 40ch, interligne 1,55, encre seconde |
| .btn.btn--trait.btn--sm | le bouton | un dessin (un lien n’en contient pas un autre) ; au survol du bloc, il se remplit et sa flèche sort ; rien ne bouge en mouvement réduit |
| Vitrine format carte | la vitrine | 16/10, sans puces (maxPuces 0) ; la matière s’approche et le cadre se soulève au survol du lien |
L’ordre : Bosco Services → Cathédrale de Nantes → PepPsy → La Grande Table → Mes Jardiniers → Clotilde Davenne → Builders, puis de nouveau Bosco Services. Sous le nom, l’accroche de la fiche, la phrase courte écrite pour les cartes, plutôt que le résumé, qui est le chapô de sa propre page.
Les cas limites
Ce que fait la page quand une fiche ne donne pas tout. La dernière colonne est calculée sur les fiches, à la construction de cette page.
| Cas | Ce que fait la page | Aujourd’hui |
|---|---|---|
| Pas marquée page, pas d’accord, ou masquée | aucune page : getStaticPaths ne retient que page, accordClient et pas masque ; le cas suivant et le badge de la page Réalisations suivent la même règle | IE Architecture, Renault |
| Moins de quatre sections ## | pas de point fort ; la construction le dit dans la console et nomme ce qui ne s’affiche pas (etapes, captureAngle, adresseAngle, pucesAngle) | aucune |
| Plus de quatre sections ## | la cinquième et les suivantes reprennent le récit, après la troisième : rien ne se perd | aucune |
| Du texte avant le premier ## | il ouvre le récit | aucune |
| Sans captureAngle | la cellule reprend la capture de tête, sans ses puces, pour ne pas les répéter | Bosco Services, Cathédrale de Nantes, PepPsy, La Grande Table, Clotilde Davenne |
| Sans capture | la réserve, P.realisations.reserve, sans puce : en tête, dans la cellule, et dans le cas suivant qui mène à lui | Bosco Services |
| Ni site ni stores | la fiche n’a que le bouton du contact | Bosco Services, Builders |
| Les stores, sans site | App Store, Google Play, au trait, dans un nouvel onglet ; un site passe avant les stores | Cathédrale de Nantes, PepPsy, La Grande Table |
| Une ligne de la fiche sans valeur | elle ne s’affiche pas : ni marque d’attente, ni chiffre à la place | Bosco Services (durée, ce que ça remplace, en service depuis, aujourd’hui) ; Builders (ce que ça remplace) |
| Sans offre | la ligne Offre donne l’étiquette, sans lien ; le formulaire présélectionne l’étiquette si V3.contact.types la propose, sinon aucun type | Builders (« Borne d’arcade », aucun type présélectionné) |
| Sans logo | ni logo dans l’en-tête, ni dans la citation | aucune |
| Sans citation signée | la réserve au nom du client, et la note | Bosco Services, Cathédrale de Nantes, La Grande Table, Mes Jardiniers, Clotilde Davenne, Builders |
| Sans accroche | le cas suivant donne le résumé | aucune |
| Sans résumé | pas de chapô ; la description de la page prend l’accroche, à défaut celle de la page Réalisations | aucune |
| Le dernier cas | son cas suivant est le premier, par ordre ; seul cas publié, il n’a pas de cas suivant | Builders renvoie à Bosco Services |
| Fiche | Accord du client | Marquée page | Page |
|---|---|---|---|
| Bosco Services | oui | oui | /realisations/bosco-services/ |
| Cathédrale de Nantes | oui | oui | /realisations/cathedrale-de-nantes/ |
| PepPsy | oui | oui | /realisations/peppsy/ |
| La Grande Table | oui | oui | /realisations/la-grande-table/ |
| Mes Jardiniers | oui | oui | /realisations/mes-jardiniers/ |
| IE Architecture | oui | non | aucune |
| Clotilde Davenne | oui | oui | /realisations/clotilde-davenne/ |
| Builders | oui | oui | /realisations/builders/ |
Une page de cas ne se publie qu’avec l’accord du client : le récit, le résumé et l’adresse de la page le nomment, une page anonyme le nommerait quand même. Il n’y a donc ni page anonyme, ni pastille d’attente, ni noindex sur une page de cas.
Une capture peut porter un chiffre du client sans que la fiche le dise. Celle de l’accueil de Mes Jardiniers (accueil.webp) montre le bandeau de son site, avec le nombre et la note de ses avis Google ; elle paraît dans la vitrine de tête de sa page, dans sa carte de la page Réalisations, dans sa carte de l’accueil (depuis le 13 octobre) et dans les spécimens du design system. Elle est à recadrer, ou à remplacer ; c’est à JB de trancher.
RègleUn cas se publie nommé, avec l’accord du client, et sans chiffre de résultat : ni note de store, ni nombre d’avis, ni téléchargements, pas même dans une capture.