session persistent Items Per Page & dark/light modes

This commit is contained in:
Ryan
2025-03-15 00:51:42 -04:00
committed by GitHub
parent eee3611da9
commit 5e50304295
6 changed files with 342 additions and 247 deletions

230
auth.js
View File

@@ -1,11 +1,10 @@
// auth.js
import { sendRequest } from './networkUtils.js';
import { toggleVisibility, showToast } from './domUtils.js';
// Import loadFileList from fileManager.js to refresh the file list upon login.
import { loadFileList } from './fileManager.js';
// Import loadFileList and renderFileTable from fileManager.js to refresh the file list upon login.
import { loadFileList, renderFileTable, displayFilePreview, initFileActions } from './fileManager.js';
import { loadFolderTree } from './folderManager.js';
export function initAuth() {
function initAuth() {
// First, check if the user is already authenticated.
checkAuthentication();
@@ -31,99 +30,99 @@ export function initAuth() {
})
.catch(error => console.error("❌ Error logging in:", error));
});
// Set up the logout button.
document.getElementById("logoutBtn").addEventListener("click", function () {
fetch("logout.php", {
method: "POST",
credentials: "include" // Ensure the session cookie is sent.
})
.then(() => window.location.reload(true))
.catch(error => console.error("Logout error:", error));
});
// Set up Add User functionality.
document.getElementById("addUserBtn").addEventListener("click", function () {
resetUserForm();
toggleVisibility("addUserModal", true);
});
document.getElementById("saveUserBtn").addEventListener("click", function () {
const newUsername = document.getElementById("newUsername").value.trim();
const newPassword = document.getElementById("newPassword").value.trim();
const isAdmin = document.getElementById("isAdmin").checked;
if (!newUsername || !newPassword) {
showToast("Username and password are required!");
return;
}
let url = "addUser.php";
if (window.setupMode) {
url += "?setup=1";
}
fetch(url, {
method: "POST",
credentials: "include",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ username: newUsername, password: newPassword, isAdmin })
})
.then(response => response.json())
.then(data => {
if (data.success) {
showToast("User added successfully!");
closeAddUserModal();
checkAuthentication();
} else {
showToast("Error: " + (data.error || "Could not add user"));
}
})
.catch(error => console.error("Error adding user:", error));
});
document.getElementById("cancelUserBtn").addEventListener("click", function () {
closeAddUserModal();
});
// Set up Remove User functionality.
document.getElementById("removeUserBtn").addEventListener("click", function () {
loadUserList();
toggleVisibility("removeUserModal", true);
});
document.getElementById("deleteUserBtn").addEventListener("click", function () {
const selectElem = document.getElementById("removeUsernameSelect");
const usernameToRemove = selectElem.value;
if (!usernameToRemove) {
showToast("Please select a user to remove.");
return;
}
if (!confirm("Are you sure you want to delete user " + usernameToRemove + "?")) {
return;
}
fetch("removeUser.php", {
method: "POST",
credentials: "include",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ username: usernameToRemove })
})
.then(response => response.json())
.then(data => {
if (data.success) {
showToast("User removed successfully!");
closeRemoveUserModal();
loadUserList();
} else {
showToast("Error: " + (data.error || "Could not remove user"));
}
})
.catch(error => console.error("Error removing user:", error));
});
document.getElementById("cancelRemoveUserBtn").addEventListener("click", function () {
closeRemoveUserModal();
});
}
// Set up the logout button.
document.getElementById("logoutBtn").addEventListener("click", function () {
fetch("logout.php", {
method: "POST",
credentials: "include" // Ensure the session cookie is sent.
})
.then(() => window.location.reload(true))
.catch(error => console.error("Logout error:", error));
});
// Set up Add User functionality.
document.getElementById("addUserBtn").addEventListener("click", function () {
resetUserForm();
toggleVisibility("addUserModal", true);
});
document.getElementById("saveUserBtn").addEventListener("click", function () {
const newUsername = document.getElementById("newUsername").value.trim();
const newPassword = document.getElementById("newPassword").value.trim();
const isAdmin = document.getElementById("isAdmin").checked;
if (!newUsername || !newPassword) {
showToast("Username and password are required!");
return;
}
let url = "addUser.php";
if (window.setupMode) {
url += "?setup=1";
}
fetch(url, {
method: "POST",
credentials: "include",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ username: newUsername, password: newPassword, isAdmin })
})
.then(response => response.json())
.then(data => {
if (data.success) {
showToast("User added successfully!");
closeAddUserModal();
checkAuthentication();
} else {
showToast("Error: " + (data.error || "Could not add user"));
}
})
.catch(error => console.error("Error adding user:", error));
});
document.getElementById("cancelUserBtn").addEventListener("click", function () {
closeAddUserModal();
});
// Set up Remove User functionality.
document.getElementById("removeUserBtn").addEventListener("click", function () {
loadUserList();
toggleVisibility("removeUserModal", true);
});
document.getElementById("deleteUserBtn").addEventListener("click", function () {
const selectElem = document.getElementById("removeUsernameSelect");
const usernameToRemove = selectElem.value;
if (!usernameToRemove) {
showToast("Please select a user to remove.");
return;
}
if (!confirm("Are you sure you want to delete user " + usernameToRemove + "?")) {
return;
}
fetch("removeUser.php", {
method: "POST",
credentials: "include",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ username: usernameToRemove })
})
.then(response => response.json())
.then(data => {
if (data.success) {
showToast("User removed successfully!");
closeRemoveUserModal();
loadUserList();
} else {
showToast("Error: " + (data.error || "Could not remove user"));
}
})
.catch(error => console.error("Error removing user:", error));
});
document.getElementById("cancelRemoveUserBtn").addEventListener("click", function () {
closeRemoveUserModal();
});
export function checkAuthentication() {
function checkAuthentication() {
// Return the promise from sendRequest
return sendRequest("checkAuth.php")
.then(data => {
@@ -157,6 +156,12 @@ export function checkAuthentication() {
if (removeUserBtn) removeUserBtn.style.display = "none";
}
document.querySelector(".header-buttons").style.visibility = "visible";
// Update persistent items-per-page select once main operations are visible.
const selectElem = document.querySelector(".form-control.bottom-select");
if (selectElem) {
const stored = localStorage.getItem("itemsPerPage") || "10";
selectElem.value = stored;
}
return true;
} else {
showToast("Please log in to continue.");
@@ -175,7 +180,34 @@ export function checkAuthentication() {
}
window.checkAuthentication = checkAuthentication;
// Helper functions for auth modals.
/* ------------------------------
Persistent Items-Per-Page Setting
------------------------------ */
// When the select value changes, save it to localStorage and refresh the file list.
window.changeItemsPerPage = function (value) {
console.log("Saving itemsPerPage:", value);
localStorage.setItem("itemsPerPage", value);
// Refresh the file list automatically.
const folder = window.currentFolder || "root";
if (typeof renderFileTable === "function") {
renderFileTable(folder);
}
};
// On DOMContentLoaded, set the select to the persisted value.
document.addEventListener("DOMContentLoaded", function () {
const selectElem = document.querySelector(".form-control.bottom-select");
if (selectElem) {
const stored = localStorage.getItem("itemsPerPage") || "10";
console.log("Loaded itemsPerPage from localStorage:", stored);
selectElem.value = stored;
}
});
/* ------------------------------
Helper functions for modals and user list
------------------------------ */
function resetUserForm() {
document.getElementById("newUsername").value = "";
document.getElementById("newPassword").value = "";
@@ -214,4 +246,6 @@ function loadUserList() {
}
})
.catch(error => console.error("Error loading user list:", error));
}
}
export { initAuth, checkAuthentication };

View File

@@ -128,16 +128,21 @@ export function renderFileTable(folder) {
const folderPath = (folder === "root")
? "uploads/"
: "uploads/" + folder.split("/").map(encodeURIComponent).join("/") + "/";
let searchInputElement = document.getElementById("searchInput");
// Attempt to get the search input element.
const searchInputElement = document.getElementById("searchInput");
const searchHadFocus = searchInputElement && (document.activeElement === searchInputElement);
let searchTerm = searchInputElement ? searchInputElement.value : "";
const searchTerm = searchInputElement ? searchInputElement.value : "";
const filteredFiles = fileData.filter(file =>
file.name.toLowerCase().includes(searchTerm.toLowerCase())
);
const itemsPerPage = window.itemsPerPage || 10;
// Read persistent items per page from localStorage, default to 10.
const itemsPerPageSetting = parseInt(localStorage.getItem('itemsPerPage') || '10', 10);
const currentPage = window.currentPage || 1;
const totalFiles = filteredFiles.length;
const totalPages = Math.ceil(totalFiles / itemsPerPage);
const totalPages = Math.ceil(totalFiles / itemsPerPageSetting);
const safeSearchTerm = escapeHTML(searchTerm);
const topControlsHTML = `
@@ -177,8 +182,8 @@ export function renderFileTable(folder) {
</thead>
`;
const startIndex = (currentPage - 1) * itemsPerPage;
const endIndex = Math.min(startIndex + itemsPerPage, totalFiles);
const startIndex = (currentPage - 1) * itemsPerPageSetting;
const endIndex = Math.min(startIndex + itemsPerPageSetting, totalFiles);
let tableBody = `<tbody>`;
if (totalFiles > 0) {
@@ -190,10 +195,9 @@ export function renderFileTable(folder) {
const safeSize = escapeHTML(file.size);
const safeUploader = escapeHTML(file.uploader || "Unknown");
// Check if the file is an image using a regex
// Check if file is an image.
const isImage = /\.(jpg|jpeg|png|gif|bmp|webp)$/i.test(file.name);
// Build the preview button HTML string using the file's properties directly.
const previewButton = isImage
? `<button class="btn btn-sm btn-info ml-2" onclick="event.stopPropagation(); previewImage('${folderPath + encodeURIComponent(file.name)}', '${safeFileName}')">
<i class="material-icons">image</i>
@@ -230,7 +234,9 @@ export function renderFileTable(folder) {
<div class="d-flex align-items-center mt-3 bottom-controls">
<label class="label-inline mr-2 mb-0">Show</label>
<select class="form-control bottom-select" onchange="changeItemsPerPage(this.value)">
${[10, 20, 50, 100].map(num => `<option value="${num}" ${num === itemsPerPage ? "selected" : ""}>${num}</option>`).join("")}
${[10, 20, 50, 100]
.map(num => `<option value="${num}" ${num === itemsPerPageSetting ? "selected" : ""}>${num}</option>`)
.join("")}
</select>
<span class="items-per-page-text ml-2 mb-0">items per page</span>
</div>
@@ -238,28 +244,28 @@ export function renderFileTable(folder) {
fileListContainer.innerHTML = topControlsHTML + tableHTML + tableBody + bottomControlsHTML;
const newSearchInput = document.getElementById("searchInput");
if (searchHadFocus && newSearchInput) {
newSearchInput.focus();
newSearchInput.setSelectionRange(newSearchInput.value.length, newSearchInput.value.length);
// Only add event listeners if searchInputElement exists.
if (searchInputElement) {
searchInputElement.addEventListener("input", function () {
window.currentPage = 1;
renderFileTable(folder);
});
}
newSearchInput.addEventListener("input", function () {
window.currentPage = 1;
renderFileTable(folder);
});
const headerCells = document.querySelectorAll("table.table thead th[data-column]");
headerCells.forEach(cell => {
document.querySelectorAll("table.table thead th[data-column]").forEach(cell => {
cell.addEventListener("click", function () {
const column = this.getAttribute("data-column");
sortFiles(column, folder);
});
});
document.querySelectorAll('#fileList .file-checkbox').forEach(checkbox => {
checkbox.addEventListener('change', function (e) {
updateRowHighlight(e.target);
updateFileActionButtons();
});
});
updateFileActionButtons();
}

View File

@@ -70,100 +70,98 @@
</div>
<!-- Main Operations: Upload and Folder Management -->
<div id="mainOperations" style="display: none;">
<div class="row align-items-stretch" id="uploadFolderRow">
<!-- Upload Card: 50% width on medium, 58% on large -->
<div class="container" style="max-width: 1400px; margin: 0 auto;">
<div class="row">
<div class="col-md-6 col-lg-7 d-flex">
<div class="card flex-fill" style="max-width: 900px; width: 100%;">
<div class="card-header">Upload Files</div>
<!-- Card body is a flex container in column direction -->
<div class="card-body d-flex flex-column">
<form id="uploadFileForm" method="post" enctype="multipart/form-data" class="d-flex flex-column"
style="height: 100%;">
<div class="form-group flex-grow-1" style="margin-bottom: 1rem;">
<div id="uploadDropArea"
style="border:2px dashed #ccc; padding:20px; cursor:pointer; height: 100%; display: flex; flex-direction: column; justify-content: center; align-items: center;">
<span>Drop files here or click 'Choose files'</span>
<br />
<input type="file" id="file" name="file[]" class="form-control-file" multiple required
style="display:none;" />
</div>
<div id="mainOperations">
<div class="container" style="max-width: 1400px; margin: 0 auto;">
<div class="row align-items-stretch" id="uploadFolderRow">
<!-- Upload Card: 50% width on medium, 58% on large -->
<div class="col-md-6 col-lg-7 d-flex">
<div id="uploadCard" class="card flex-fill" style="max-width: 900px; width: 100%;">
<div class="card-header">Upload Files/Folders</div>
<div class="card-body d-flex flex-column">
<form id="uploadFileForm" method="post" enctype="multipart/form-data" class="d-flex flex-column"
style="height: 100%;">
<div class="form-group flex-grow-1" style="margin-bottom: 1rem;">
<div id="uploadDropArea"
style="border:2px dashed #ccc; padding:20px; cursor:pointer; height: 100%; display: flex; flex-direction: column; justify-content: center; align-items: center;">
<span>Drop files/folders here or click 'Choose files'</span>
<br />
<input type="file" id="file" name="file[]" class="form-control-file" multiple required
webkitdirectory directory mozdirectory style="opacity:0; position:absolute; z-index:-1;" />
<button type="button" onclick="document.getElementById('file').click();">Choose Folder</button>
</div>
<button type="submit" id="uploadBtn" class="btn btn-primary d-block mx-auto">Upload</button>
<div id="uploadProgressContainer"></div>
</form>
</div>
</div>
<button type="submit" id="uploadBtn" class="btn btn-primary d-block mx-auto">Upload</button>
<div id="uploadProgressContainer"></div>
</form>
</div>
</div>
<!-- Folder Management Card: 50% width on medium, 42% on large -->
<div class="col-md-6 col-lg-5 d-flex">
<div class="card flex-fill" style="max-width: 900px; width: 100%;">
<div class="card-header">Folder Navigation & Management</div>
<div class="card-body custom-folder-card-body">
<div class="form-group d-flex align-items-top" style="padding-top:0; margin-bottom:0;">
<div id="folderTreeContainer"></div>
</div>
<!-- Folder actions -->
<div class="folder-actions mt-3">
<button id="createFolderBtn" class="btn btn-primary">Create Folder</button>
<!-- Create Folder Modal -->
<div id="createFolderModal" class="modal">
<div class="modal-content">
<h4>Create Folder</h4>
<input type="text" id="newFolderName" class="form-control" placeholder="Enter folder name"
style="margin-top:10px;" />
<div style="margin-top:15px; text-align:right;">
<button id="cancelCreateFolder" class="btn btn-secondary">Cancel</button>
<button id="submitCreateFolder" class="btn btn-primary">Create</button>
</div>
</div>
</div>
<button id="renameFolderBtn" class="btn btn-secondary ml-2" title="Rename Folder">
<i class="material-icons">edit</i>
</button>
<!-- Rename Folder Modal -->
<div id="renameFolderModal" class="modal">
<div class="modal-content">
<h4>Rename Folder</h4>
<input type="text" id="newRenameFolderName" class="form-control"
placeholder="Enter new folder name" style="margin-top:10px;" />
<div style="margin-top:15px; text-align:right;">
<button id="cancelRenameFolder" class="btn btn-secondary">Cancel</button>
<button id="submitRenameFolder" class="btn btn-primary">Rename</button>
</div>
</div>
</div>
<button id="deleteFolderBtn" class="btn btn-danger ml-2" title="Delete Folder">
<i class="material-icons">delete</i>
</button>
<!-- Delete Folder Modal -->
<div id="deleteFolderModal" class="modal">
<div class="modal-content">
<h4>Delete Folder</h4>
<p id="deleteFolderMessage">Are you sure you want to delete this folder?</p>
<div style="margin-top:15px; text-align:right;">
<button id="cancelDeleteFolder" class="btn btn-secondary">Cancel</button>
<button id="confirmDeleteFolder" class="btn btn-danger">Delete</button>
</div>
</div>
<!-- Folder Management Card: 50% width on medium, 42% on large -->
<div class="col-md-6 col-lg-5 d-flex">
<div class="card flex-fill" style="max-width: 900px; width: 100%;">
<div class="card-header">Folder Navigation &amp; Management</div>
<div class="card-body custom-folder-card-body">
<div class="form-group d-flex align-items-top" style="padding-top:0; margin-bottom:0;">
<div id="folderTreeContainer"></div>
</div>
<!-- Folder actions (create, rename, delete) -->
<div class="folder-actions mt-3">
<button id="createFolderBtn" class="btn btn-primary">Create Folder</button>
<!-- Create Folder Modal -->
<div id="createFolderModal" class="modal">
<div class="modal-content">
<h4>Create Folder</h4>
<input type="text" id="newFolderName" class="form-control" placeholder="Enter folder name"
style="margin-top:10px;" />
<div style="margin-top:15px; text-align:right;">
<button id="cancelCreateFolder" class="btn btn-secondary">Cancel</button>
<button id="submitCreateFolder" class="btn btn-primary">Create</button>
</div>
</div>
</div>
<div id="folderExplanation" class="folder-explanation">
<details class="folder-help-details">
<summary class="folder-help-summary">
<i class="material-icons folder-help-icon">info</i>
Folder Navigation &amp; Management Help Info
</summary>
<ul class="folder-help-list">
<li>Click on a folder in the tree to view its files.</li>
<li>Use [-] to collapse and [+] to expand folders.</li>
<li>Select a folder and click "Create Folder" to add a subfolder.</li>
<li>To rename or delete a folder, select it and then click the appropriate button.</li>
</ul>
</details>
<button id="renameFolderBtn" class="btn btn-secondary ml-2" title="Rename Folder">
<i class="material-icons">edit</i>
</button>
<!-- Rename Folder Modal -->
<div id="renameFolderModal" class="modal">
<div class="modal-content">
<h4>Rename Folder</h4>
<input type="text" id="newRenameFolderName" class="form-control"
placeholder="Enter new folder name" style="margin-top:10px;" />
<div style="margin-top:15px; text-align:right;">
<button id="cancelRenameFolder" class="btn btn-secondary">Cancel</button>
<button id="submitRenameFolder" class="btn btn-primary">Rename</button>
</div>
</div>
</div>
<button id="deleteFolderBtn" class="btn btn-danger ml-2" title="Delete Folder">
<i class="material-icons">delete</i>
</button>
<!-- Delete Folder Modal -->
<div id="deleteFolderModal" class="modal">
<div class="modal-content">
<h4>Delete Folder</h4>
<p id="deleteFolderMessage">Are you sure you want to delete this folder?</p>
<div style="margin-top:15px; text-align:right;">
<button id="cancelDeleteFolder" class="btn btn-secondary">Cancel</button>
<button id="confirmDeleteFolder" class="btn btn-danger">Delete</button>
</div>
</div>
</div>
</div>
<div id="folderExplanation" class="folder-explanation">
<details class="folder-help-details">
<summary class="folder-help-summary">
<i class="material-icons folder-help-icon">info</i>
Folder Navigation &amp; Management Help Info
</summary>
<ul class="folder-help-list">
<li>Click on a folder in the tree to view its files.</li>
<li>Use [-] to collapse and [+] to expand folders.</li>
<li>Select a folder and click "Create Folder" to add a subfolder.</li>
<li>To rename or delete a folder, select it and then click the appropriate button.</li>
</ul>
</details>
</div>
</div>
</div>
@@ -278,14 +276,6 @@
<!-- JavaScript Files -->
<script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
<script type="module" src="main.js"></script>
<script>
// Dark mode toggle script
const darkModeToggle = document.getElementById('darkModeToggle');
darkModeToggle.addEventListener('click', () => {
document.body.classList.toggle('dark-mode');
darkModeToggle.innerText = document.body.classList.contains('dark-mode') ? 'Light Mode' : 'Dark Mode';
});
</script>
</body>
</html>

90
main.js
View File

@@ -1,17 +1,15 @@
// main.js
import { sendRequest } from './networkUtils.js';
import {
toggleVisibility,
toggleAllCheckboxes,
import {
toggleVisibility,
toggleAllCheckboxes,
updateFileActionButtons,
showToast
} from './domUtils.js';
import {
loadFileList,
initFileActions,
editFile,
saveFile,
import {
loadFileList,
initFileActions,
editFile,
saveFile,
displayFilePreview,
renameFile
} from './fileManager.js';
@@ -27,38 +25,66 @@ window.editFile = editFile;
window.saveFile = saveFile;
window.renameFile = renameFile;
// Global variable for the current folder.
window.currentFolder = "root";
// DOMContentLoaded initialization.
document.addEventListener("DOMContentLoaded", function () {
// Call initAuth synchronously.
initAuth();
// Check OS theme preference & apply dark mode
if (window.matchMedia && window.matchMedia("(prefers-color-scheme: dark)").matches) {
document.body.classList.add("dark-mode"); // Enable dark mode if OS is set to dark
}
// Listen for real-time OS theme changes
window.matchMedia("(prefers-color-scheme: dark)").addEventListener("change", (event) => {
if (event.matches) {
document.body.classList.add("dark-mode"); // Enable dark mode
} else {
document.body.classList.remove("dark-mode"); // Disable dark mode
}
});
// ✅ Fix the Button Label on Page Load
// --- Dark Mode Persistence ---
// Get the dark mode toggle button.
const darkModeToggle = document.getElementById("darkModeToggle");
if (document.body.classList.contains("dark-mode")) {
darkModeToggle.textContent = "Light Mode";
// Retrieve stored user preference (if any).
const storedDarkMode = localStorage.getItem("darkMode");
// Apply stored preference; if none, fall back to OS setting.
if (storedDarkMode === "true") {
document.body.classList.add("dark-mode");
} else if (storedDarkMode === "false") {
document.body.classList.remove("dark-mode");
} else {
darkModeToggle.textContent = "Dark Mode";
if (window.matchMedia && window.matchMedia("(prefers-color-scheme: dark)").matches) {
document.body.classList.add("dark-mode");
} else {
document.body.classList.remove("dark-mode");
}
}
// Set the initial button label.
if (darkModeToggle) {
darkModeToggle.textContent = document.body.classList.contains("dark-mode")
? "Light Mode"
: "Dark Mode";
// When clicked, toggle dark mode and store preference.
darkModeToggle.addEventListener("click", function () {
if (document.body.classList.contains("dark-mode")) {
document.body.classList.remove("dark-mode");
localStorage.setItem("darkMode", "false");
darkModeToggle.textContent = "Dark Mode";
} else {
document.body.classList.add("dark-mode");
localStorage.setItem("darkMode", "true");
darkModeToggle.textContent = "Light Mode";
}
});
}
// Listen for OS theme changes if no user preference is set.
if (localStorage.getItem("darkMode") === null && window.matchMedia) {
window.matchMedia("(prefers-color-scheme: dark)").addEventListener("change", (event) => {
if (event.matches) {
document.body.classList.add("dark-mode");
if (darkModeToggle) darkModeToggle.textContent = "Light Mode";
} else {
document.body.classList.remove("dark-mode");
if (darkModeToggle) darkModeToggle.textContent = "Dark Mode";
}
});
}
// --- End Dark Mode Persistence ---
const message = sessionStorage.getItem("welcomeMessage");
if (message) {
showToast(message);
@@ -76,4 +102,4 @@ document.addEventListener("DOMContentLoaded", function () {
console.warn("User not authenticated. Data loading deferred.");
}
});
});
});

View File

@@ -294,13 +294,13 @@ body.dark-mode header {
/* folder icon and remove file to be uploaded */
.material-icons.folder-icon {
color: black;
margin-right: 3px;
margin-right: 5px;
/* adjust the value as needed */
}
body.dark-mode .material-icons.folder-icon {
color: white;
margin-right: 3px;
margin-right: 5px;
}
/* Remove button default styling */
@@ -1514,6 +1514,13 @@ body.dark-mode .file-icon {
margin-left: 5px;
}
.upload-progress-wrapper {
max-height: 300px;
/* Adjust the value as needed */
overflow-y: auto;
/* Optional: Add some padding or border if desired */
}
.upload-progress-list {
list-style: none;
padding: 0;

View File

@@ -45,6 +45,25 @@ function getFilesFromDataTransferItems(items) {
return Promise.all(promises).then(results => results.flat());
}
function adjustFolderHelpExpansion() {
const uploadCard = document.getElementById("uploadCard");
const folderHelpDetails = document.querySelector(".folder-help-details");
if (uploadCard && folderHelpDetails) {
if (uploadCard.offsetHeight > 400) {
folderHelpDetails.setAttribute("open", "");
} else {
folderHelpDetails.removeAttribute("open");
}
}
}
function adjustFolderHelpExpansionClosed() {
const folderHelpDetails = document.querySelector(".folder-help-details");
if (folderHelpDetails) {
folderHelpDetails.removeAttribute("open");
}
}
// Helper: Update file info container count/preview.
function updateFileInfoCount() {
const fileInfoContainer = document.getElementById("fileInfoContainer");
@@ -226,9 +245,20 @@ function processFiles(filesInput) {
list.appendChild(extra);
}
}
progressContainer.appendChild(list);
const listWrapper = document.createElement("div");
listWrapper.classList.add("upload-progress-wrapper");
// Set a maximum height (adjust as needed) and enable vertical scrolling.
listWrapper.style.maxHeight = "300px"; // for example, 300px
listWrapper.style.overflowY = "auto";
listWrapper.appendChild(list);
progressContainer.appendChild(listWrapper);
}
// Call once on page load:
adjustFolderHelpExpansion();
// Also call on window resize:
window.addEventListener("resize", adjustFolderHelpExpansion);
// Store files globally for submission.
window.selectedFiles = files;
updateFileInfoCount();
@@ -367,6 +397,8 @@ function submitFiles(allFiles) {
removeBtns.forEach(btn => btn.style.display = "none");
progressContainer.innerHTML = "";
window.selectedFiles = [];
adjustFolderHelpExpansionClosed();
window.addEventListener("resize", adjustFolderHelpExpansionClosed);
const fileInfoContainer = document.getElementById("fileInfoContainer");
if (fileInfoContainer) {
fileInfoContainer.innerHTML = `<span id="fileInfoDefault">No files selected</span>`;