482 lines
15 KiB
HTML
482 lines
15 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="fr" data-theme="dark">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>Esenjin | FTéxPlorateur</title>
|
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/js/all.min.js"></script>
|
|
<style>
|
|
:root[data-theme="dark"] {
|
|
--primary-color: #64B5F6;
|
|
--hover-color: #42A5F5;
|
|
--bg-color: #1a1a1a;
|
|
--container-bg: #2d2d2d;
|
|
--text-color: #e0e0e0;
|
|
--border-color: #404040;
|
|
--meta-color: #909090;
|
|
--input-bg: #3d3d3d;
|
|
}
|
|
|
|
:root[data-theme="light"] {
|
|
--primary-color: #4a90e2;
|
|
--hover-color: #357abd;
|
|
--bg-color: #f5f6fa;
|
|
--container-bg: white;
|
|
--text-color: #333;
|
|
--border-color: #eee;
|
|
--meta-color: #666;
|
|
--input-bg: white;
|
|
}
|
|
|
|
body {
|
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
margin: 0;
|
|
padding: 20px;
|
|
background: var(--bg-color);
|
|
color: var(--text-color);
|
|
}
|
|
|
|
.theme-toggle {
|
|
position: absolute;
|
|
top: 20px;
|
|
right: 20px;
|
|
padding: 10px;
|
|
border-radius: 5px;
|
|
background: var(--input-bg);
|
|
border: 1px solid var(--border-color);
|
|
color: var(--text-color);
|
|
cursor: pointer;
|
|
}
|
|
|
|
.container {
|
|
max-width: 1200px;
|
|
margin: 0 auto;
|
|
background: var(--container-bg);
|
|
border-radius: 10px;
|
|
box-shadow: 0 2px 10px rgba(0,0,0,0.2);
|
|
padding: 20px;
|
|
}
|
|
|
|
h1 {
|
|
color: var(--primary-color);
|
|
margin-bottom: 30px;
|
|
padding-bottom: 10px;
|
|
border-bottom: 2px solid var(--border-color);
|
|
}
|
|
|
|
.file-grid {
|
|
display: grid;
|
|
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
|
|
gap: 20px;
|
|
padding: 20px;
|
|
}
|
|
|
|
.file-item {
|
|
background: var(--container-bg);
|
|
border: 1px solid var(--border-color);
|
|
border-radius: 8px;
|
|
padding: 15px;
|
|
transition: all 0.3s ease;
|
|
cursor: pointer;
|
|
text-decoration: none;
|
|
color: var(--text-color);
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
text-align: center;
|
|
}
|
|
|
|
.file-item:hover {
|
|
transform: translateY(-2px);
|
|
box-shadow: 0 4px 12px rgba(0,0,0,0.2);
|
|
border-color: var(--primary-color);
|
|
}
|
|
|
|
.file-icon {
|
|
font-size: 2em;
|
|
margin-bottom: 10px;
|
|
color: var(--primary-color);
|
|
}
|
|
|
|
.file-name {
|
|
word-break: break-word;
|
|
margin-top: 8px;
|
|
font-size: 0.9em;
|
|
}
|
|
|
|
.file-meta {
|
|
font-size: 0.8em;
|
|
color: var(--meta-color);
|
|
margin-top: 5px;
|
|
}
|
|
|
|
.search-bar {
|
|
width: 100%;
|
|
max-width: 500px;
|
|
margin: 0 auto 20px;
|
|
display: flex;
|
|
gap: 10px;
|
|
}
|
|
|
|
.search-input {
|
|
flex: 1;
|
|
padding: 10px 15px;
|
|
border: 2px solid var(--border-color);
|
|
border-radius: 5px;
|
|
font-size: 1em;
|
|
background: var(--input-bg);
|
|
color: var(--text-color);
|
|
transition: border-color 0.3s ease;
|
|
}
|
|
|
|
.search-input:focus {
|
|
outline: none;
|
|
border-color: var(--primary-color);
|
|
}
|
|
|
|
.sort-select {
|
|
padding: 10px;
|
|
border: 2px solid var(--border-color);
|
|
border-radius: 5px;
|
|
background: var(--input-bg);
|
|
color: var(--text-color);
|
|
cursor: pointer;
|
|
}
|
|
|
|
.sort-select:focus {
|
|
outline: none;
|
|
border-color: var(--primary-color);
|
|
}
|
|
|
|
@media (max-width: 768px) {
|
|
.file-grid {
|
|
grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
|
|
}
|
|
}
|
|
|
|
/* Styles pour la modal */
|
|
.modal {
|
|
display: none;
|
|
position: fixed;
|
|
top: 0;
|
|
left: 0;
|
|
width: 100%;
|
|
height: 100%;
|
|
background: rgba(0, 0, 0, 0.9);
|
|
z-index: 1000;
|
|
overflow: auto;
|
|
}
|
|
|
|
.modal-content {
|
|
position: relative;
|
|
margin: auto;
|
|
padding: 20px;
|
|
width: 90%;
|
|
max-width: 1200px;
|
|
min-height: 200px;
|
|
top: 50%;
|
|
transform: translateY(-50%);
|
|
}
|
|
|
|
.modal-close {
|
|
position: absolute;
|
|
right: 25px;
|
|
top: 25px;
|
|
color: var(--text-color);
|
|
font-size: 24px;
|
|
cursor: pointer;
|
|
z-index: 1001;
|
|
background: rgba(0, 0, 0, 0.5);
|
|
width: 40px;
|
|
height: 40px;
|
|
border-radius: 50%;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
}
|
|
|
|
.preview-container {
|
|
width: 100%;
|
|
height: 80vh;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
}
|
|
|
|
.preview-container img {
|
|
max-width: 100%;
|
|
max-height: 100%;
|
|
object-fit: contain;
|
|
}
|
|
|
|
.preview-container video,
|
|
.preview-container audio {
|
|
width: 100%;
|
|
max-width: 800px;
|
|
}
|
|
|
|
.preview-container iframe {
|
|
width: 100%;
|
|
height: 100%;
|
|
border: none;
|
|
}
|
|
|
|
.loading {
|
|
color: var(--text-color);
|
|
text-align: center;
|
|
padding: 20px;
|
|
}
|
|
|
|
@media (max-width: 768px) {
|
|
.modal-content {
|
|
width: 95%;
|
|
padding: 10px;
|
|
}
|
|
|
|
.preview-container {
|
|
height: 60vh;
|
|
}
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<button class="theme-toggle" id="themeToggle">
|
|
<i class="fas fa-moon"></i>
|
|
</button>
|
|
|
|
<div class="container">
|
|
<h1>De bric et de broc...</h1>
|
|
|
|
<div class="search-bar">
|
|
<input type="text" class="search-input" placeholder="Rechercher des fichiers..." id="searchInput">
|
|
<select class="sort-select" id="sortSelect">
|
|
<option value="name">Nom</option>
|
|
<option value="date">Date</option>
|
|
<option value="size">Taille</option>
|
|
</select>
|
|
</div>
|
|
|
|
<div id="previewModal" class="modal">
|
|
<span class="modal-close" id="modalClose">×</span>
|
|
<div class="modal-content">
|
|
<div id="previewContainer" class="preview-container">
|
|
<div class="loading">Chargement...</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="file-grid" id="fileGrid">
|
|
<!-- Les fichiers seront ajoutés ici dynamiquement -->
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
// Toggle thème
|
|
const themeToggle = document.getElementById('themeToggle');
|
|
const html = document.documentElement;
|
|
|
|
themeToggle.addEventListener('click', () => {
|
|
const currentTheme = html.getAttribute('data-theme');
|
|
const newTheme = currentTheme === 'dark' ? 'light' : 'dark';
|
|
html.setAttribute('data-theme', newTheme);
|
|
themeToggle.innerHTML = newTheme === 'dark' ? '<i class="fas fa-moon"></i>' : '<i class="fas fa-sun"></i>';
|
|
});
|
|
|
|
// Fonction pour déterminer l'icône
|
|
function getFileIcon(filename) {
|
|
const ext = filename.split('.').pop().toLowerCase();
|
|
const iconMap = {
|
|
pdf: 'file-pdf',
|
|
doc: 'file-word',
|
|
docx: 'file-word',
|
|
xls: 'file-excel',
|
|
xlsx: 'file-excel',
|
|
jpg: 'file-image',
|
|
jpeg: 'file-image',
|
|
png: 'file-image',
|
|
gif: 'file-image',
|
|
mp3: 'file-audio',
|
|
wav: 'file-audio',
|
|
mp4: 'file-video',
|
|
zip: 'file-archive',
|
|
rar: 'file-archive'
|
|
};
|
|
|
|
return iconMap[ext] || 'file';
|
|
}
|
|
|
|
// Fonction pour formater la taille
|
|
function formatFileSize(bytes) {
|
|
if (bytes === 0) return '0 Bytes';
|
|
const k = 1024;
|
|
const sizes = ['Bytes', 'KB', 'MB', 'GB'];
|
|
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
|
|
}
|
|
|
|
function createFileElement(file) {
|
|
const fileItem = document.createElement('a');
|
|
fileItem.className = 'file-item';
|
|
fileItem.href = '#';
|
|
|
|
const icon = getFileIcon(file.name);
|
|
|
|
fileItem.innerHTML = `
|
|
<i class="fa-solid fa-${icon} file-icon"></i>
|
|
<div class="file-name">${file.name}</div>
|
|
<div class="file-meta">${formatFileSize(file.size)}</div>
|
|
<div class="file-meta">${file.date}</div>
|
|
`;
|
|
|
|
// Gestion du clic pour la prévisualisation
|
|
fileItem.addEventListener('click', (e) => {
|
|
e.preventDefault();
|
|
previewFile(file);
|
|
});
|
|
|
|
return fileItem;
|
|
}
|
|
|
|
// Gestion de la prévisualisation
|
|
const modal = document.getElementById('previewModal');
|
|
const modalClose = document.getElementById('modalClose');
|
|
const previewContainer = document.getElementById('previewContainer');
|
|
|
|
modalClose.addEventListener('click', () => {
|
|
modal.style.display = 'none';
|
|
previewContainer.innerHTML = '<div class="loading">Chargement...</div>';
|
|
});
|
|
|
|
window.addEventListener('click', (e) => {
|
|
if (e.target === modal) {
|
|
modal.style.display = 'none';
|
|
previewContainer.innerHTML = '<div class="loading">Chargement...</div>';
|
|
}
|
|
});
|
|
|
|
function getFileType(filename) {
|
|
const ext = filename.split('.').pop().toLowerCase();
|
|
const imageTypes = ['jpg', 'jpeg', 'png', 'gif', 'webp'];
|
|
const videoTypes = ['mp4', 'webm', 'ogg'];
|
|
const audioTypes = ['mp3', 'wav', 'ogg'];
|
|
const documentTypes = ['pdf'];
|
|
|
|
if (imageTypes.includes(ext)) return 'image';
|
|
if (videoTypes.includes(ext)) return 'video';
|
|
if (audioTypes.includes(ext)) return 'audio';
|
|
if (documentTypes.includes(ext)) return 'pdf';
|
|
return 'other';
|
|
}
|
|
|
|
async function previewFile(file) {
|
|
modal.style.display = 'block';
|
|
const fileType = getFileType(file.name);
|
|
const fileUrl = file.path;
|
|
|
|
switch (fileType) {
|
|
case 'image':
|
|
previewContainer.innerHTML = `
|
|
<img src="${fileUrl}" alt="${file.name}" />
|
|
`;
|
|
break;
|
|
|
|
case 'video':
|
|
previewContainer.innerHTML = `
|
|
<video controls>
|
|
<source src="${fileUrl}" type="video/${file.name.split('.').pop()}">
|
|
Votre navigateur ne supporte pas la lecture vidéo.
|
|
</video>
|
|
`;
|
|
break;
|
|
|
|
case 'audio':
|
|
previewContainer.innerHTML = `
|
|
<audio controls>
|
|
<source src="${fileUrl}" type="audio/${file.name.split('.').pop()}">
|
|
Votre navigateur ne supporte pas la lecture audio.
|
|
</audio>
|
|
`;
|
|
break;
|
|
|
|
case 'pdf':
|
|
// Utilisation de PDF.js pour les PDF
|
|
previewContainer.innerHTML = `
|
|
<iframe src="${fileUrl}" type="application/pdf"></iframe>
|
|
`;
|
|
break;
|
|
|
|
default:
|
|
previewContainer.innerHTML = `
|
|
<div class="loading">
|
|
Ce type de fichier ne peut pas être prévisualisé.<br>
|
|
<a href="${fileUrl}" target="_blank" style="color: var(--primary-color);">
|
|
Télécharger le fichier
|
|
</a>
|
|
</div>
|
|
`;
|
|
}
|
|
}
|
|
|
|
// Charger les fichiers depuis l'API
|
|
async function loadFiles() {
|
|
try {
|
|
const response = await fetch('list-files.php');
|
|
const files = await response.json();
|
|
return files;
|
|
} catch (error) {
|
|
console.error('Erreur lors du chargement des fichiers:', error);
|
|
return [];
|
|
}
|
|
}
|
|
|
|
// Initialisation
|
|
let allFiles = [];
|
|
|
|
async function initializeFiles() {
|
|
allFiles = await loadFiles();
|
|
displayFiles(allFiles);
|
|
}
|
|
|
|
function displayFiles(files) {
|
|
const fileGrid = document.getElementById('fileGrid');
|
|
fileGrid.innerHTML = '';
|
|
files.forEach(file => {
|
|
fileGrid.appendChild(createFileElement(file));
|
|
});
|
|
}
|
|
|
|
// Recherche
|
|
const searchInput = document.getElementById('searchInput');
|
|
searchInput.addEventListener('input', (e) => {
|
|
const searchTerm = e.target.value.toLowerCase();
|
|
const filteredFiles = allFiles.filter(file =>
|
|
file.name.toLowerCase().includes(searchTerm)
|
|
);
|
|
displayFiles(filteredFiles);
|
|
});
|
|
|
|
// Tri
|
|
const sortSelect = document.getElementById('sortSelect');
|
|
sortSelect.addEventListener('change', (e) => {
|
|
const sortBy = e.target.value;
|
|
const sortedFiles = [...allFiles].sort((a, b) => {
|
|
switch(sortBy) {
|
|
case 'name':
|
|
return a.name.localeCompare(b.name);
|
|
case 'date':
|
|
return new Date(b.date) - new Date(a.date);
|
|
case 'size':
|
|
return b.size - a.size;
|
|
default:
|
|
return 0;
|
|
}
|
|
});
|
|
displayFiles(sortedFiles);
|
|
});
|
|
|
|
// Initialiser l'application
|
|
initializeFiles();
|
|
</script>
|
|
</body>
|
|
</html>
|