commit initial
mise en place d'un système d'affichage intuitif et moderne
This commit is contained in:
parent
f5cb373111
commit
d88dac0546
481
index.html
Normal file
481
index.html
Normal file
@ -0,0 +1,481 @@
|
||||
<!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>
|
Loading…
x
Reference in New Issue
Block a user