formulaires · upload
Zone de dépôt de fichier (glisser-déposer ou clic pour parcourir), qui affiche le nom et le poids du fichier une fois choisi. Nécessite du JavaScript.
<style>
.bn-upload {
max-width: 420px;
padding: 2rem;
font-family: 'Inter', sans-serif;
background: #0B0F10;
}
.bn-upload__zone {
display: flex;
flex-direction: column;
align-items: center;
gap: 0.4rem;
padding: 2.5rem 1.5rem;
border: 1px dashed rgba(230, 228, 221, 0.3);
border-radius: 8px;
cursor: pointer;
transition: border-color 0.2s ease, background 0.2s ease;
}
.bn-upload__zone:hover,
.bn-upload__zone.is-dragover {
border-color: #E6E4DD;
background: rgba(255, 255, 255, 0.03);
}
.bn-upload__icon {
font-size: 1.4rem;
color: #979793;
margin-bottom: 0.4rem;
}
.bn-upload__text {
color: #E6E4DD;
font-size: 0.85rem;
font-weight: 600;
letter-spacing: 0.04em;
text-transform: uppercase;
}
.bn-upload__sub {
color: #5C6160;
font-size: 0.8rem;
}
.bn-upload__input {
position: absolute;
width: 1px;
height: 1px;
opacity: 0;
}
.bn-upload__file {
display: flex;
align-items: center;
gap: 0.75rem;
margin-top: 1rem;
padding: 0.9rem 1rem;
border: 1px solid rgba(230, 228, 221, 0.15);
border-radius: 8px;
}
.bn-upload__file-icon {
font-size: 1.2rem;
}
.bn-upload__file-info {
flex: 1;
min-width: 0;
display: flex;
flex-direction: column;
}
.bn-upload__file-name {
color: #E6E4DD;
font-size: 0.85rem;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.bn-upload__file-size {
color: #979793;
font-size: 0.75rem;
}
.bn-upload__file-remove {
flex-shrink: 0;
width: 24px;
height: 24px;
border: none;
border-radius: 50%;
background: rgba(255, 255, 255, 0.06);
color: #E6E4DD;
cursor: pointer;
}
.bn-upload__hint {
margin: 1rem 0 0;
font-size: 0.75rem;
color: #5C6160;
}
</style>
<div class="bn-upload" data-fx-root>
<label class="bn-upload__zone" for="bn-upload-input">
<span class="bn-upload__icon">⇧</span>
<span class="bn-upload__text">Glissez votre fichier ici</span>
<span class="bn-upload__sub">ou cliquez pour parcourir</span>
<input type="file" id="bn-upload-input" class="bn-upload__input" />
</label>
<div class="bn-upload__file" hidden>
<span class="bn-upload__file-icon">📄</span>
<div class="bn-upload__file-info">
<span class="bn-upload__file-name"></span>
<span class="bn-upload__file-size"></span>
</div>
<button type="button" class="bn-upload__file-remove" aria-label="Retirer le fichier">✕</button>
</div>
<p class="bn-upload__hint">Formats acceptés : PDF, JPG, PNG, DOC, DOCX · Taille max : 10 Mo</p>
</div>
<script>
/* ==========================================================
UPLOAD DE FICHIER
Gère 3 choses : le glisser-déposer (surbrillance + dépôt réel),
l'affichage du fichier une fois choisi (nom + poids lisible),
et le bouton pour le retirer.
========================================================== */
(function () {
const root = document.querySelector('.bn-upload[data-fx-root]');
if (!root) return;
const zone = root.querySelector('.bn-upload__zone');
const input = root.querySelector('.bn-upload__input');
const filePanel = root.querySelector('.bn-upload__file');
const fileName = root.querySelector('.bn-upload__file-name');
const fileSize = root.querySelector('.bn-upload__file-size');
const removeBtn = root.querySelector('.bn-upload__file-remove');
// Convertit un nombre d'octets en texte lisible (Ko / Mo)
function formatSize(bytes) {
if (bytes < 1024) return `${bytes} o`;
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} Ko`;
return `${(bytes / (1024 * 1024)).toFixed(1)} Mo`;
}
function showFile(file) {
fileName.textContent = file.name;
fileSize.textContent = formatSize(file.size);
filePanel.hidden = false;
zone.hidden = true;
}
function clearFile() {
input.value = '';
filePanel.hidden = true;
zone.hidden = false;
}
input.addEventListener('change', () => {
if (input.files[0]) showFile(input.files[0]);
});
removeBtn.addEventListener('click', clearFile);
// Glisser-déposer : surbrillance de la zone au survol du fichier
['dragenter', 'dragover'].forEach((eventName) => {
zone.addEventListener(eventName, (event) => {
event.preventDefault();
zone.classList.add('is-dragover');
});
});
['dragleave', 'drop'].forEach((eventName) => {
zone.addEventListener(eventName, () => {
zone.classList.remove('is-dragover');
});
});
zone.addEventListener('drop', (event) => {
event.preventDefault();
const file = event.dataTransfer.files[0];
if (file) {
input.files = event.dataTransfer.files;
showFile(file);
}
});
})();
</script>