Ajoute un accès direct à la galerie en plus de la caméra
Deux boutons séparés (deux inputs file) plutôt qu'un seul avec capture=environment qui masquait l'option galerie — retour de Kévin après test réel. État de sélection centralisé dans state.selectedFile.
This commit is contained in:
+19
-5
@@ -36,11 +36,15 @@
|
||||
|
||||
<form id="upload-form" class="upload-form" hidden novalidate>
|
||||
<div class="field">
|
||||
<label for="photo-input">Ta photo</label>
|
||||
<!-- capture="environment" : ouvre directement l'appareil photo
|
||||
(caméra arrière) sur mobile plutôt que la galerie — décision
|
||||
actée avec Kévin le 2026-09-16, remplace le choix initial qui
|
||||
laissait le choix caméra/galerie. -->
|
||||
<label id="photo-field-label">Ta photo</label>
|
||||
<!-- Deux entrées séparées : "photo-input" (capture="environment")
|
||||
ouvre directement l'appareil photo, "photo-input-gallery" ouvre
|
||||
le sélecteur de fichiers classique. Décision actée avec Kévin le
|
||||
2026-09-16 : les deux doivent être accessibles en un tap. -->
|
||||
<div class="photo-source-buttons">
|
||||
<label for="photo-input" class="btn-secondary">📷 Prendre une photo</label>
|
||||
<label for="photo-input-gallery" class="btn-secondary">🖼️ Depuis la galerie</label>
|
||||
</div>
|
||||
<input
|
||||
type="file"
|
||||
id="photo-input"
|
||||
@@ -48,7 +52,17 @@
|
||||
accept="image/*,.heic,.heif"
|
||||
capture="environment"
|
||||
required
|
||||
class="visually-hidden"
|
||||
>
|
||||
<input
|
||||
type="file"
|
||||
id="photo-input-gallery"
|
||||
accept="image/*,.heic,.heif"
|
||||
class="visually-hidden"
|
||||
tabindex="-1"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<p id="file-chosen-label" class="file-chosen-label">Aucun fichier choisi</p>
|
||||
</div>
|
||||
|
||||
<img id="preview" class="preview" alt="Aperçu de la photo choisie" hidden>
|
||||
|
||||
@@ -112,6 +112,50 @@ input[type="file"] {
|
||||
padding: 0.55rem 0.5rem;
|
||||
}
|
||||
|
||||
.visually-hidden {
|
||||
position: absolute;
|
||||
width: 1px;
|
||||
height: 1px;
|
||||
padding: 0;
|
||||
margin: -1px;
|
||||
overflow: hidden;
|
||||
clip: rect(0, 0, 0, 0);
|
||||
white-space: nowrap;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.photo-source-buttons {
|
||||
display: flex;
|
||||
gap: 0.6rem;
|
||||
}
|
||||
|
||||
.btn-secondary {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
text-align: center;
|
||||
font-weight: 600;
|
||||
font-size: 0.9rem;
|
||||
padding: 0.85rem 0.6rem;
|
||||
min-height: 48px;
|
||||
border: 1px solid var(--color-accent);
|
||||
border-radius: var(--radius);
|
||||
color: var(--color-accent);
|
||||
background: #fff;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.btn-secondary:active {
|
||||
transform: translateY(1px);
|
||||
}
|
||||
|
||||
.file-chosen-label {
|
||||
font-size: 0.85rem;
|
||||
color: var(--color-muted);
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
textarea {
|
||||
resize: vertical;
|
||||
min-height: 4.5rem;
|
||||
|
||||
+24
-4
@@ -40,6 +40,8 @@ const successBlock = document.getElementById("success-block");
|
||||
const addAnotherBtn = document.getElementById("add-another-btn");
|
||||
const form = document.getElementById("upload-form");
|
||||
const photoInput = document.getElementById("photo-input");
|
||||
const photoInputGallery = document.getElementById("photo-input-gallery");
|
||||
const fileChosenLabel = document.getElementById("file-chosen-label");
|
||||
const previewImg = document.getElementById("preview");
|
||||
const nomInput = document.getElementById("nom-input");
|
||||
const messageInput = document.getElementById("message-input");
|
||||
@@ -413,17 +415,20 @@ async function insertPhotoRow(eventId, path, nom, message) {
|
||||
|
||||
let previewObjectUrl = null;
|
||||
|
||||
photoInput.addEventListener("change", () => {
|
||||
// Deux inputs (caméra directe / galerie) partagent la même logique de
|
||||
// sélection — état centralisé dans state.selectedFile plutôt que de lire
|
||||
// photoInput.files[0] un peu partout, pour rester correct quel que soit
|
||||
// l'input utilisé.
|
||||
function handleFileSelected(file) {
|
||||
// Nouveau fichier choisi -> on invalide toute compression déjà faite.
|
||||
state.compressedBlob = null;
|
||||
state.selectedFile = photoInput.files[0] || null;
|
||||
state.selectedFile = file || null;
|
||||
|
||||
if (previewObjectUrl) {
|
||||
URL.revokeObjectURL(previewObjectUrl);
|
||||
previewObjectUrl = null;
|
||||
}
|
||||
|
||||
const file = state.selectedFile;
|
||||
if (file && file.type && file.type.startsWith("image/")) {
|
||||
previewObjectUrl = URL.createObjectURL(file);
|
||||
previewImg.src = previewObjectUrl;
|
||||
@@ -435,6 +440,20 @@ photoInput.addEventListener("change", () => {
|
||||
// Pas d'aperçu fiable pour les HEIC sur la plupart des navigateurs.
|
||||
previewImg.hidden = true;
|
||||
}
|
||||
|
||||
fileChosenLabel.textContent = file ? file.name : "Aucun fichier choisi";
|
||||
}
|
||||
|
||||
photoInput.addEventListener("change", () => {
|
||||
handleFileSelected(photoInput.files[0] || null);
|
||||
// Un seul fichier actif à la fois : on vide l'autre input pour éviter
|
||||
// toute ambiguïté si l'utilisateur change de méthode après coup.
|
||||
photoInputGallery.value = "";
|
||||
});
|
||||
|
||||
photoInputGallery.addEventListener("change", () => {
|
||||
handleFileSelected(photoInputGallery.files[0] || null);
|
||||
photoInput.value = "";
|
||||
});
|
||||
|
||||
async function submitPhoto() {
|
||||
@@ -444,7 +463,7 @@ async function submitPhoto() {
|
||||
return;
|
||||
}
|
||||
|
||||
const file = photoInput.files[0];
|
||||
const file = state.selectedFile;
|
||||
if (!file) return showError(appError("file-missing"));
|
||||
if (!isAcceptableImageFile(file)) return showError(appError("file-not-image"));
|
||||
if (file.size > MAX_INPUT_BYTES) return showError(appError("file-too-large"));
|
||||
@@ -487,6 +506,7 @@ addAnotherBtn.addEventListener("click", () => {
|
||||
form.reset();
|
||||
state.selectedFile = null;
|
||||
state.compressedBlob = null;
|
||||
fileChosenLabel.textContent = "Aucun fichier choisi";
|
||||
previewImg.hidden = true;
|
||||
if (previewObjectUrl) {
|
||||
URL.revokeObjectURL(previewObjectUrl);
|
||||
|
||||
Reference in New Issue
Block a user