From c712ca8a15c6710574d7bb256ae00e81e9bf3796 Mon Sep 17 00:00:00 2001 From: IliesAllali Date: Tue, 27 Oct 2026 15:41:45 +0100 Subject: [PATCH] =?UTF-8?q?Souvenir=20sur=20t=C3=A9l=C3=A9phone=20:=20glis?= =?UTF-8?q?ser=20la=20photo=20vers=20le=20bas=20le=20ferme,=20comme=20la?= =?UTF-8?q?=20fiche?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Même geste et mêmes seuils que la fiche (useSheetDrag) : la carte suit le doigt, se ferme passé un tiers ou sur un lâcher rapide, revient sinon ; tirée vers le haut, elle résiste. Zone : la photo seulement (.mv-photo-box), la légende garde ses boutons et son défilement. Coupé pendant l'identification et quand la carte a défilé (nouvelle option canStart du hook). - L'entrée de la carte ne garde plus sa valeur finale sur téléphone (fill-mode backwards), sinon elle l'emportait sur le transform du glisser. Fond plein sous la carte collée en bas (sous 560 px). - Un toucher simple sur la photo montre toujours les prénoms ; un glisser n'en déclenche pas. Planche validée par Patch le 27/10 : _bmad-output/parenthese/motion/2026-10-27-glisser-souvenir/ Co-Authored-By: Claude Opus 5.5 --- frontend/src/components/MediaViewer.css | 18 ++++++++++++++++++ frontend/src/components/MediaViewer.jsx | 14 ++++++++++++++ frontend/src/hooks/useSheetDrag.js | 3 +++ 3 files changed, 35 insertions(+) diff --git a/frontend/src/components/MediaViewer.css b/frontend/src/components/MediaViewer.css index 350864c..b9e7cf1 100644 --- a/frontend/src/components/MediaViewer.css +++ b/frontend/src/components/MediaViewer.css @@ -513,3 +513,21 @@ @media (prefers-reduced-motion: reduce) { .media-viewer-card { animation: none; } } + +/* Téléphone : la photo se glisse vers le bas pour fermer (useSheetDrag, zone .mv-photo-box). L'entrée ne garde pas sa + valeur finale (fill-mode backwards) : sinon elle l'emporterait sur le transform du glisser, posé en ligne. */ +@media (max-width: 768px) { + .media-viewer-card { + animation-fill-mode: backwards; + transition: transform 240ms var(--pz-ease-drawer); + } + .media-viewer-card[data-dragging] { transition: none; } + .media-viewer-card .mv-photo-box { touch-action: none; } +} +/* Collée en bas (pz.css, sous 560 px) : un fond plein sous la carte, pour qu'elle tirée vers le haut ne découvre pas l'arbre */ +@media (max-width: 560px) { + .media-viewer-card { box-shadow: 0 40px 0 var(--pz-surface), var(--pz-shadow-lg); } +} +@media (prefers-reduced-motion: reduce) { + .media-viewer-card { transition-duration: 1ms; } +} diff --git a/frontend/src/components/MediaViewer.jsx b/frontend/src/components/MediaViewer.jsx index de44afc..1080004 100644 --- a/frontend/src/components/MediaViewer.jsx +++ b/frontend/src/components/MediaViewer.jsx @@ -14,6 +14,7 @@ import { firstNameLabel } from '../utils/personName.js' import { eventTitle } from '../utils/lifeTimeline.js' import { getAccountErrorMessage } from '../utils/errorMessages.js' import { growFromTransform, takeOrigin } from '../utils/openOrigin.js' +import { useSheetDrag, useSheetMode } from '../hooks/useSheetDrag.js' const HTTP_URL_RE = /^https?:\/\/\S+$/i const MAX_TITLE_LENGTH = 280 @@ -589,12 +590,25 @@ const MediaViewer = ({ card.animate?.([{ transform: start.transform }, { transform: 'none' }], { duration: 280, easing: 'cubic-bezier(.23, 1, .32, 1)' }) }, [mediaId]) + // Téléphone : glisser la photo vers le bas ferme le souvenir, comme la fiche (Patch, 27/10). Pas pendant + // l'identification (on touche la photo pour placer un visage), ni quand la carte a défilé (on remonte d'abord). + const sheetMode = useSheetMode() + const drag = useSheetDrag({ + enabled: sheetMode && !tagging, + zone: '.mv-photo-box', + onClose, + canStart: () => (cardRef.current?.scrollTop ?? 0) <= 0, + }) + if (!media) return null return (
` */ @@ -49,6 +50,7 @@ export function useSheetDrag({ onClose, closes = shouldCloseSheet, closeDelayMs = 180, + canStart = null, }) { const [offset, setOffset] = useState(0) const [dragging, setDragging] = useState(false) @@ -77,6 +79,7 @@ export function useSheetDrag({ if (!enabled || closingRef.current || event.button > 0) return const selection = typeof window !== 'undefined' ? window.getSelection?.()?.toString() ?? '' : '' if (!canStartSheetDrag(event.target, zone, selection)) return + if (canStart && !canStart(event)) return gesture.current = { id: event.pointerId, x: event.clientX,