Section de l’accueil sur les pays couverts, groupés par statut du plus sûr au moins sûr, puis le reste du monde ; un pays ouvre la fenêtre « Où Pathou fonctionne » sur lui.
stableÀ valider
// Titre : Carte des pays couverts
import HomeCountries from '@pathou/components/HomeCountries';
export default function Exemple() {
return (
<div style={{ width: 900 }}>
<HomeCountries onOpen={() => {}} />
</div>
);
}
Installation
Copie le fichier dans ton projet, ainsi que les tokens qu’il utilise.
import { REAL_PROFILE } from '../lib/sources/profile';
import type { ReactNode } from 'react';
import type { CountryCode, Support } from '../lib/sources/types';
import { COUNTRY_GROUPS, FLAG, STATUS } from './CountriesInfo';
import { opensModal } from './opensModal';
/** Finesse de l’altitude d’un pays : « à 1 m », ou « de 1 à 5 m » quand ses régions diffèrent (l’Allemagne). Insécable : la ligne se coupe avant, pas au milieu. */
function resolution(regions: string[]): string | null {
const res = regions.flatMap((r) => REAL_PROFILE.regions[r as keyof typeof REAL_PROFILE.regions]?.elevation?.resolutionM ?? []);
if (!res.length) return null;
const [lo, hi] = [Math.min(...res), Math.max(...res)].map((m) => m.toLocaleString('fr-FR'));
return (lo === hi ? `à ${lo} m` : `de ${lo} à ${hi} m`).replace(/ /g, '\u00a0');
}
/**
* Section de l’accueil : les pays couverts, groupés par statut, du plus sûr au moins sûr, puis le reste du monde.
* Même source que la modale « Où Pathou fonctionne », qui s’ouvre sur le pays choisi.
*/
export default function HomeCountries({ onOpen }: { onOpen: (code?: CountryCode) => void }) {
return (
<section className="hp-countries" aria-labelledby="hp-countries">
<div className="hp-inner">
<div className="hpc-head">
<h2 id="hp-countries">Où Pathou fonctionne</h2>
<p>Dans ces pays, Pathou lit l’altitude des instituts géographiques nationaux, bien plus fine que le relief mondial.</p>
</div>
{COUNTRY_GROUPS.map((g) => (
<Band key={g.status} status={g.status} label={STATUS[g.status].label} text={STATUS[g.status].text}>
<ul className="hpc-list">
{g.cards.map((c) => {
const res = resolution(c.regions);
return (
<li key={c.code}>
<button type="button" className="hpc-country" onClick={() => onOpen(c.code)} aria-label={`${c.name}, ${STATUS[g.status].label.toLowerCase()} : voir le détail`}>
{FLAG[c.code] ? <img className="hpc-flag" src={FLAG[c.code]} alt="" width={32} height={32} /> : <span className="hpc-flag" aria-hidden="true" />}
<span>
<b>{c.name}</b>
{res && <small>Altitude {res}</small>}
</span>
</button>
</li>
);
})}
</ul>
</Band>
))}
<Band status="degrade" label="Partout ailleurs" text="Pathou fonctionne avec l’altitude du GPX ou le relief mondial : le verdict est moins sûr.">
<a className="hp-link hpc-more" href="/pays" onClick={opensModal(() => onOpen())}>
Voir le détail par pays
</a>
</Band>
</div>
</section>
);
}
function Band({ status, label, text, children }: { status: Support; label: string; text: string; children: ReactNode }) {
return (
<div className={`hpc-band hpc-${status}`}>
<div className="hpc-status">
<h3>
<Mark status={status} />
{label}
</h3>
<p>{text}</p>
</div>
{children}
</div>
);
}
/** Pastille du statut, au motif de la carte des pays (à-plat, hachures, points) : le statut se lit sans la couleur. */
function Mark({ status }: { status: Support }) {
return (
<svg className="hpc-mark" viewBox="0 0 16 16" aria-hidden="true">
<clipPath id={`hpc-clip-${status}`}>
<rect x="0.5" y="0.5" width="15" height="15" rx="4" />
</clipPath>
<g clipPath={`url(#hpc-clip-${status})`}>
<rect width="16" height="16" className="hpc-mark-bg" />
{status === 'beta' && [-8, -4, 0, 4, 8, 12, 16].map((d) => <line key={d} x1={d} y1="16" x2={d + 16} y2="0" className="hpc-mark-ink" />)}
{status === 'degrade' && [3, 8, 13].flatMap((cx) => [3, 8, 13].map((cy) => <circle key={`${cx}-${cy}`} cx={cx} cy={cy} r="1.3" className="hpc-mark-dot" />))}
</g>
</svg>
);
}
Tokens : --bg --panel --text --muted --line --accent --chip --ease-out --font --display --status-complet (non déterminé) --status-beta --status-degrade
Utilisation
import HomeCountries from './components/HomeCountries';
<HomeCountries onOpen={(code) => openCountries(code)} />Guidelines
- MUSTTirer les pays et leur statut de la même source que la fenêtre des pays (CountriesInfo) ; les deux ne doivent jamais diverger.
- SHOULDDire le statut en mots (complet, bêta, dégradé), la couleur des tokens --status-* ne faisant que l’appuyer.
Référence de l’API
| Prop | Type | Défaut |
|---|---|---|
onOpen | (code?: CountryCode) => void | requis |