diff --git a/frontend/src/components/AdminPanel.jsx b/frontend/src/components/AdminPanel.jsx index 866f919..b0b58c6 100644 --- a/frontend/src/components/AdminPanel.jsx +++ b/frontend/src/components/AdminPanel.jsx @@ -24,6 +24,7 @@ import { removeManager } from '../api/managersApi.js' import { t } from '../i18n/index.js' import { readGedcomFile } from '../utils/gedcomText.js' import { readGedcomBundle, zipErrorMessage } from '../utils/gedcomBundle.js' +import Skeleton from './Skeleton.jsx' function normalizeSlug(value) { return String(value || '') @@ -442,7 +443,7 @@ const AdminPanel = ({
{t('Chargement…')}
+{notice}
if (entries.length === 0) { + // Premier chargement, aucune date connue sur la fiche : la place de la frise, au lieu d'un « pas encore de + // date » qui serait faux une seconde après. Avec des dates connues, elles s'affichent tout de suite. + if (loading && !life) return{t('Pas encore de date connue pour {name}.', { name: person.firstName })}
diff --git a/frontend/src/components/SearchSourcesPanel.jsx b/frontend/src/components/SearchSourcesPanel.jsx index ddc216b..cd5f932 100644 --- a/frontend/src/components/SearchSourcesPanel.jsx +++ b/frontend/src/components/SearchSourcesPanel.jsx @@ -8,6 +8,7 @@ import { fetchSearchSources, searchSource } from '../api/searchSourcesApi.js' import { SEARCH_LINKS, SEARCH_LINK_REGIONS } from '../data/searchLinks.js' import { changesFromResult, personFromResult } from '../utils/searchResultChanges.js' import { fullNameLabel } from '../utils/personName.js' +import Skeleton from './Skeleton.jsx' // Ce que chaque source interrogée couvre et ce qui part vers elle : affiché avant qu'on coche const SOURCE_INFO = { @@ -283,7 +284,7 @@ function SearchSourcesPanel({ visible, treeId, token, persons = [], canApply = f{t('Où chercher')}
- {sources === null &&{t('Chargement…')}
} + {sources === null &&{t("Ce serveur n'interroge aucune source : aucun nom ne quitte l'instance. Les liens plus bas ouvrent les sites dans votre navigateur.")}
)} diff --git a/frontend/src/components/Skeleton.css b/frontend/src/components/Skeleton.css new file mode 100644 index 0000000..c9bd481 --- /dev/null +++ b/frontend/src/components/Skeleton.css @@ -0,0 +1,14 @@ +/* Blocs gris de chargement (Skeleton.jsx) : immobiles, couleur des séparateurs */ +.pz-skel { display: grid; gap: 14px; padding: 4px 0; } +.pz-skel-row { display: flex; align-items: center; gap: 12px; } +.pz-skel-text { display: grid; gap: 7px; flex: 1; min-width: 0; } +.pz-skel-bar { display: block; height: 12px; border-radius: 6px; background: var(--pz-line); } +.pz-skel-bar--thin { height: 9px; background: var(--pz-line-soft); } +.pz-skel-dot { flex: none; width: 32px; height: 32px; border-radius: 50%; background: var(--pz-line); } + +/* Frise : année, point sur le rail, texte */ +.pz-skel--timeline { gap: 22px; padding: 8px 0 4px; } +.pz-skel--timeline .pz-skel-year { flex: none; width: 34px; height: 11px; } +.pz-skel--timeline .pz-skel-dot { width: 10px; height: 10px; } + +.pz-skel--lines .pz-skel-bar { height: 10px; } diff --git a/frontend/src/components/Skeleton.jsx b/frontend/src/components/Skeleton.jsx new file mode 100644 index 0000000..5d4008b --- /dev/null +++ b/frontend/src/components/Skeleton.jsx @@ -0,0 +1,34 @@ +import { useEffect, useState } from 'react' +import { t } from '../i18n/index.js' +import './Skeleton.css' + +// Blocs gris à la forme de ce qui arrive, à la place d'un « Chargement… ». Rien avant SHOW_AFTER : une réponse +// rapide ne fait pas clignoter l'écran. Aucun mouvement (pas de reflet qui passe), juste la place réservée. +const SHOW_AFTER = 300 + +// variant : rows (avatar et deux lignes : personnes, visites, propositions), timeline (frise de l'onglet Vie), +// lines (paragraphes) +export default function Skeleton({ variant = 'rows', count = 3, label = '' }) { + const [shown, setShown] = useState(false) + useEffect(() => { + const timer = setTimeout(() => setShown(true), SHOW_AFTER) + return () => clearTimeout(timer) + }, []) + + return ( +{t('Chargement…')}
+ if (state.loading) return{t('Chargement…')}
+ if (state.loading) return