EditBanner

←→

Bandeau des alternatives appliquées à la trace : leur liste, l’écart total de distance et de dénivelé, le téléchargement du GPX modifié et le retour à l’original.

stableÀ valider
// Titre : Deux alternatives appliquées
import EditBanner from '@pathou/components/EditBanner';
import type { AppliedDetour } from '@pathou/lib/edit/compose';

// seuls les champs affichés comptent ici : position, écart de distance et de D+
const applied = [
  { id: 'a', fromIdx: 0, toIdx: 0, path: [], km: 12.4, toKm: 13.1, extraM: 380, extraGain: 22 },
  { id: 'b', fromIdx: 0, toIdx: 0, path: [], km: 27.9, toKm: 28.6, extraM: -120, extraGain: -8 },
] satisfies AppliedDetour[];

export default function Exemple() {
  return (
    <div style={{ width: 340 }}>
      <EditBanner applied={applied} onRemove={() => {}} onReset={() => {}} onDownload={() => {}} />
    </div>
  );
}

Installation

Copie le fichier dans ton projet, ainsi que les tokens qu’il utilise.

src/components/EditBanner.tsx
import type { AppliedDetour } from '../lib/edit/compose';
import { formatDelta } from '../lib/detour/result';
import { fmt } from '../lib/format';

/** Alternatives appliquées à la trace : liste, écart total, téléchargement et retour à l'original. */
export default function EditBanner({ applied, onRemove, onReset, onDownload }: { applied: AppliedDetour[]; onRemove: (id: string) => void; onReset: () => void; onDownload: () => void }) {
  if (applied.length === 0) return null;
  const extraM = applied.reduce((s, a) => s + a.extraM, 0);
  const gain = Math.round(applied.reduce((s, a) => s + a.extraGain, 0));
  const n = applied.length;
  return (
    <section className="edit-banner" aria-label="Trace modifiée">
      <div className="edit-head">
        <b>Trace modifiée</b>
        <span>
          {n} alternative{n > 1 ? 's' : ''} appliquée{n > 1 ? 's' : ''} · {formatDelta(extraM)} · {gain < 0 ? '−' : '+'}
          {Math.abs(gain)} m D+
        </span>
      </div>
      <ul className="edit-list">
        {[...applied].sort((a, b) => a.km - b.km).map((a) => (
          <li key={a.id}>
            <span>
              km {fmt(a.km, 1)} → {fmt(a.toKm, 1)} · {formatDelta(a.extraM)}
            </span>
            <button type="button" className="ghost" onClick={() => onRemove(a.id)}>
              Retirer
            </button>
          </li>
        ))}
      </ul>
      <div className="edit-actions">
        <button type="button" className="primary" onClick={onDownload}>
          Télécharger le GPX
        </button>
        <button type="button" className="ghost" onClick={onReset}>
          Revenir à l’original
        </button>
      </div>
    </section>
  );
}

Tokens : --panel --muted --accent --accent-ink --chip --replaced

Utilisation

import EditBanner from './components/EditBanner';

<EditBanner applied={applied} onRemove={removeDetour} onReset={resetEdit} onDownload={downloadGpx} />

Anatomie

#ÉlémentRôle
1En-tête« Trace modifiée » et le bilan (nombre d’alternatives, écart de distance, écart de D+).
2ListeUne ligne par alternative, triée par kilomètre, avec son bouton « Retirer ».
3Actions« Télécharger le GPX » (principal) et « Revenir à l’original ».

Guidelines

  • MUST
    N’afficher le bandeau que lorsqu’au moins une alternative est appliquée ; le composant ne rend rien sinon.
  • SHOULD
    Garder le téléchargement du GPX en action principale ; c’est le seul moyen de conserver la trace modifiée.

Référence de l’API

PropTypeDéfaut
appliedAppliedDetour[]requis
onRemove(id: string) => voidrequis
onReset() => voidrequis
onDownload() => voidrequis