390 lines
21 KiB
HTML
390 lines
21 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
|
|
<head>
|
|
<meta charset="UTF-8" />
|
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
<title>FileRise</title>
|
|
<link rel="icon" type="image/png" href="/assets/logo.png">
|
|
<link rel="icon" type="image/svg+xml" href="/assets/logo.svg">
|
|
<meta name="csrf-token" content="">
|
|
<meta name="share-url" content="">
|
|
<!-- Google Fonts and Material Icons -->
|
|
<link href="https://fonts.googleapis.com/css2?family=Roboto:wght@400;500&display=swap" rel="stylesheet" />
|
|
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet" />
|
|
<!-- Bootstrap CSS -->
|
|
<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css" rel="stylesheet" />
|
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.5/codemirror.min.css" />
|
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.5/theme/material-darker.min.css">
|
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.5/codemirror.min.js"></script>
|
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.5/mode/xml/xml.min.js"></script>
|
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.5/mode/css/css.min.js"></script>
|
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.5/mode/javascript/javascript.min.js"></script>
|
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/resumable.js/1.1.0/resumable.min.js"></script>
|
|
<link rel="stylesheet" href="styles.css" />
|
|
</head>
|
|
|
|
<body>
|
|
<header class="header-container">
|
|
<div class="header-left">
|
|
<div class="header-logo">
|
|
<svg version="1.1" id="filingCabinetLogo" xmlns="http://www.w3.org/2000/svg"
|
|
xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 64 64" xml:space="preserve">
|
|
<defs>
|
|
<!-- Gradient for the cabinet body -->
|
|
<linearGradient id="cabinetGradient" x1="0%" y1="0%" x2="0%" y2="100%">
|
|
<stop offset="0%" style="stop-color:#2196F3;stop-opacity:1" />
|
|
<stop offset="100%" style="stop-color:#1976D2;stop-opacity:1" />
|
|
</linearGradient>
|
|
<!-- Drop shadow filter with animated attributes for a lifting effect -->
|
|
<filter id="shadowFilter" x="-20%" y="-20%" width="140%" height="140%">
|
|
<feDropShadow id="dropShadow" dx="0" dy="2" stdDeviation="2" flood-color="#000" flood-opacity="0.2">
|
|
<!-- Animate the vertical offset: from 2 to 1 (as it rises), hold, then back to 2 -->
|
|
<animate attributeName="dy" values="2;1;1;2" keyTimes="0;0.2;0.8;1" dur="5s" fill="freeze" />
|
|
<!-- Animate the blur similarly: from 2 to 1.5 then back to 2 -->
|
|
<animate attributeName="stdDeviation" values="2;1.5;1.5;2" keyTimes="0;0.2;0.8;1" dur="5s"
|
|
fill="freeze" />
|
|
</feDropShadow>
|
|
</filter>
|
|
</defs>
|
|
<style type="text/css">
|
|
/* Cabinet with gradient, white outline, and drop shadow */
|
|
.cabinet {
|
|
fill: url(#cabinetGradient);
|
|
stroke: white;
|
|
stroke-width: 2;
|
|
}
|
|
|
|
.divider {
|
|
stroke: #1565C0;
|
|
stroke-width: 1.5;
|
|
}
|
|
|
|
.drawer {
|
|
fill: #FFFFFF;
|
|
}
|
|
|
|
.handle {
|
|
fill: #1565C0;
|
|
}
|
|
</style>
|
|
<!-- Group that will animate upward and then back down once -->
|
|
<g id="cabinetGroup">
|
|
<!-- Cabinet Body with rounded corners, white outline, and drop shadow -->
|
|
<rect x="4" y="4" width="56" height="56" rx="6" ry="6" class="cabinet" filter="url(#shadowFilter)" />
|
|
<!-- Divider lines for drawers -->
|
|
<line x1="5" y1="22" x2="59" y2="22" class="divider" />
|
|
<line x1="5" y1="34" x2="59" y2="34" class="divider" />
|
|
<!-- Drawers with Handles -->
|
|
<rect x="8" y="24" width="48" height="6" rx="1" ry="1" class="drawer" />
|
|
<circle cx="54" cy="27" r="1.5" class="handle" />
|
|
<rect x="8" y="36" width="48" height="6" rx="1" ry="1" class="drawer" />
|
|
<circle cx="54" cy="39" r="1.5" class="handle" />
|
|
<rect x="8" y="48" width="48" height="6" rx="1" ry="1" class="drawer" />
|
|
<circle cx="54" cy="51" r="1.5" class="handle" />
|
|
<!-- Additional detail: a small top handle on the cabinet door -->
|
|
<rect x="28" y="10" width="8" height="4" rx="1" ry="1" fill="#1565C0" />
|
|
<!-- Animate transform: rises by 2 pixels over 1s, holds for 3s, then falls over 1s (total 5s) -->
|
|
<animateTransform attributeName="transform" type="translate" values="0 0; 0 -2; 0 -2; 0 0"
|
|
keyTimes="0;0.2;0.8;1" dur="5s" fill="freeze" />
|
|
</g>
|
|
</svg>
|
|
</div>
|
|
</div>
|
|
<div class="header-title">
|
|
<h1>FileRise</h1>
|
|
</div>
|
|
<div class="header-right">
|
|
<div class="header-buttons">
|
|
<button id="logoutBtn" title="Logout">
|
|
<i class="material-icons">exit_to_app</i>
|
|
</button>
|
|
<button id="changePasswordBtn" title="Change Password">
|
|
<i class="material-icons">vpn_key</i>
|
|
</button>
|
|
<div id="restoreFilesModal" class="modal centered-modal" style="display: none;">
|
|
<div class="modal-content">
|
|
<h4 class="custom-restore-header">
|
|
<i class="material-icons orange-icon">restore_from_trash</i>
|
|
<span>Restore or</span>
|
|
<i class="material-icons red-icon">delete_for_ever</i>
|
|
<span>Delete Trash Items</span>
|
|
</h4>
|
|
<div id="restoreFilesList"
|
|
style="max-height:300px; overflow-y:auto; border:1px solid #ccc; padding:10px; margin-bottom:10px;">
|
|
<!-- Trash items will be loaded here -->
|
|
</div>
|
|
<div style="text-align: right;">
|
|
<button id="restoreSelectedBtn" class="btn btn-primary">Restore Selected</button>
|
|
<button id="restoreAllBtn" class="btn btn-secondary">Restore All</button>
|
|
<button id="deleteTrashSelectedBtn" class="btn btn-warning">Delete Selected</button>
|
|
<button id="deleteAllBtn" class="btn btn-danger">Delete All</button>
|
|
<button id="closeRestoreModal" class="btn btn-dark">Close</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<button id="addUserBtn" title="Add User">
|
|
<i class="material-icons">person_add</i>
|
|
</button>
|
|
<button id="removeUserBtn" title="Remove User">
|
|
<i class="material-icons">person_remove</i>
|
|
</button>
|
|
<button id="darkModeToggle" class="dark-mode-toggle">Dark Mode</button>
|
|
</div>
|
|
</div>
|
|
</header>
|
|
|
|
<!-- Custom Toast Container -->
|
|
<div id="customToast"></div>
|
|
|
|
<!-- Main Wrapper: Hidden by default; remove "display: none;" after login -->
|
|
<div class="main-wrapper">
|
|
<!-- Sidebar Drop Zone: Hidden until you drag a card (display controlled by JS) -->
|
|
<div id="sidebarDropArea" class="drop-target-sidebar"></div>
|
|
<!-- Main Column -->
|
|
<div id="mainColumn" class="main-column">
|
|
<div class="container-fluid">
|
|
<!-- Login Form (unchanged) -->
|
|
<div class="row" id="loginForm">
|
|
<div class="col-12">
|
|
<form id="authForm" method="post">
|
|
<div class="form-group">
|
|
<label for="loginUsername">User:</label>
|
|
<input type="text" class="form-control" id="loginUsername" name="username" required />
|
|
</div>
|
|
<div class="form-group">
|
|
<label for="loginPassword">Password:</label>
|
|
<input type="password" class="form-control" id="loginPassword" name="password" required />
|
|
</div>
|
|
<button type="submit" class="btn btn-primary btn-block btn-login">Login</button>
|
|
<div class="form-group remember-me-container">
|
|
<input type="checkbox" id="rememberMeCheckbox" name="remember_me" />
|
|
<label for="rememberMeCheckbox">Remember me</label>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Main Operations: Upload and Folder Management -->
|
|
<div id="mainOperations">
|
|
<div class="container" style="max-width: 1400px; margin: 0 auto;">
|
|
<!-- Top Zone: Two columns (60% and 40%) -->
|
|
<div id="uploadFolderRow" class="row">
|
|
<!-- Left Column (60% for Upload Card) -->
|
|
<div id="leftCol" class="col-md-7" style="display: flex; justify-content: center;">
|
|
<div id="uploadCard" class="card" style="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">
|
|
<div class="form-group flex-grow-1" style="margin-bottom: 1rem;">
|
|
<div id="uploadDropArea"
|
|
style="border:2px dashed #ccc; padding:20px; cursor:pointer; display:flex; flex-direction:column; justify-content:center; align-items:center; position:relative;">
|
|
<span>Drop files/folders here or click 'Choose Files'</span>
|
|
<br />
|
|
<input type="file" id="file" name="file[]" class="form-control-file" multiple
|
|
style="opacity:0; position:absolute; width:1px; height:1px;" />
|
|
<button type="button" id="customChooseBtn">Choose Files</button>
|
|
</div>
|
|
</div>
|
|
<button type="submit" id="uploadBtn" class="btn btn-primary d-block mx-auto">Upload</button>
|
|
<div id="uploadProgressContainer"></div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<!-- Right Column (40% for Folder Management Card) -->
|
|
<div id="rightCol" class="col-md-5" style="display: flex; justify-content: center;">
|
|
<div id="folderManagementCard" class="card" style="width: 100%; position: relative;">
|
|
<div class="card-header" style="display: flex; justify-content: space-between; align-items: center;">
|
|
<span>Folder Navigation & Management</span>
|
|
<button id="folderHelpBtn" class="btn btn-link" title="Folder Help"
|
|
style="padding: 0; border: none; background: none;">
|
|
<i class="material-icons folder-help-icon" style="font-size: 24px;">info</i>
|
|
</button>
|
|
</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>
|
|
<div class="folder-actions mt-3">
|
|
<button id="createFolderBtn" class="btn btn-primary">Create Folder</button>
|
|
<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">drive_file_rename_outline</i>
|
|
</button>
|
|
<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>
|
|
<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="folderHelpTooltip" class="folder-help-tooltip"
|
|
style="display: none; position: absolute; top: 50px; right: 15px; background: #fff; border: 1px solid #ccc; padding: 10px; z-index: 1000; box-shadow: 2px 2px 6px rgba(0,0,0,0.2);">
|
|
<ul class="folder-help-list" style="margin: 0; padding-left: 20px;">
|
|
<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>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div> <!-- end uploadFolderRow -->
|
|
</div> <!-- end container -->
|
|
</div> <!-- end mainOperations -->
|
|
|
|
<!-- File List Section -->
|
|
<div id="fileListContainer" style="display: none;">
|
|
<h2 id="fileListTitle">Files in (Root)</h2>
|
|
<div id="fileListActions" class="file-list-actions">
|
|
<button id="deleteSelectedBtn" class="btn action-btn" style="display: none;">Delete Files</button>
|
|
<div id="deleteFilesModal" class="modal">
|
|
<div class="modal-content">
|
|
<h4>Delete Selected Files</h4>
|
|
<p id="deleteFilesMessage">Are you sure you want to delete the selected files?</p>
|
|
<div class="modal-footer">
|
|
<button id="cancelDeleteFiles" class="btn btn-secondary">Cancel</button>
|
|
<button id="confirmDeleteFiles" class="btn btn-danger">Delete</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<button id="copySelectedBtn" class="btn action-btn" style="display: none;" disabled>Copy Files</button>
|
|
<div id="copyFilesModal" class="modal">
|
|
<div class="modal-content">
|
|
<h4>Copy Selected Files</h4>
|
|
<p id="copyFilesMessage">Select a target folder for copying the selected files:</p>
|
|
<select id="copyTargetFolder" class="form-control modal-input"></select>
|
|
<div class="modal-footer">
|
|
<button id="cancelCopyFiles" class="btn btn-secondary">Cancel</button>
|
|
<button id="confirmCopyFiles" class="btn btn-primary">Copy</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<button id="moveSelectedBtn" class="btn action-btn" style="display: none;" disabled>Move Files</button>
|
|
<div id="moveFilesModal" class="modal">
|
|
<div class="modal-content">
|
|
<h4>Move Selected Files</h4>
|
|
<p id="moveFilesMessage">Select a target folder for moving the selected files:</p>
|
|
<select id="moveTargetFolder" class="form-control modal-input"></select>
|
|
<div class="modal-footer">
|
|
<button id="cancelMoveFiles" class="btn btn-secondary">Cancel</button>
|
|
<button id="confirmMoveFiles" class="btn btn-primary">Move</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<button id="downloadZipBtn" class="btn action-btn" style="display: none;" disabled>Download ZIP</button>
|
|
<button id="extractZipBtn" class="btn btn-sm btn-info" title="Extract Zip">Extract Zip</button>
|
|
<div id="downloadZipModal" class="modal" style="display:none;">
|
|
<div class="modal-content">
|
|
<h4>Download Selected Files as Zip</h4>
|
|
<p>Enter a name for the zip file:</p>
|
|
<input type="text" id="zipFileNameInput" class="form-control" placeholder="files.zip" />
|
|
<div class="modal-footer" style="margin-top:15px; text-align:right;">
|
|
<button id="cancelDownloadZip" class="btn btn-secondary">Cancel</button>
|
|
<button id="confirmDownloadZip" class="btn btn-primary">Download</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div id="fileList"></div>
|
|
</div>
|
|
</div> <!-- end container-fluid -->
|
|
</div> <!-- end mainColumn -->
|
|
</div> <!-- end main-wrapper -->
|
|
|
|
<!-- Change Password, Add User, Remove User, Rename File, and Custom Confirm Modals (unchanged) -->
|
|
<div id="changePasswordModal" class="modal" style="display:none;">
|
|
<div class="modal-content" style="max-width:400px; margin:auto;">
|
|
<span id="closeChangePasswordModal" style="cursor:pointer;">×</span>
|
|
<h3>Change Password</h3>
|
|
<input type="password" id="oldPassword" placeholder="Old Password" style="width:100%; margin: 5px 0;" />
|
|
<input type="password" id="newPassword" placeholder="New Password" style="width:100%; margin: 5px 0;" />
|
|
<input type="password" id="confirmPassword" placeholder="Confirm New Password"
|
|
style="width:100%; margin: 5px 0;" />
|
|
<button id="saveNewPasswordBtn" class="btn btn-primary" style="width:100%;">Save</button>
|
|
</div>
|
|
</div>
|
|
<div id="addUserModal" class="modal">
|
|
<div class="modal-content">
|
|
<h3>Create New User</h3>
|
|
<label for="newUsername">Username:</label>
|
|
<input type="text" id="newUsername" class="form-control" />
|
|
<label for="addUserPassword">Password:</label>
|
|
<input type="password" id="addUserPassword" class="form-control" />
|
|
<div id="adminCheckboxContainer">
|
|
<input type="checkbox" id="isAdmin" />
|
|
<label for="isAdmin">Grant Admin Access</label>
|
|
</div>
|
|
<div class="button-container">
|
|
<button id="cancelUserBtn" class="btn btn-secondary">Cancel</button>
|
|
<button id="saveUserBtn" class="btn btn-primary">Save User</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div id="removeUserModal" class="modal">
|
|
<div class="modal-content">
|
|
<h3>Remove User</h3>
|
|
<label for="removeUsernameSelect">Select a user to remove:</label>
|
|
<select id="removeUsernameSelect" class="form-control"></select>
|
|
<div class="button-container">
|
|
<button id="cancelRemoveUserBtn" class="btn btn-secondary">Cancel</button>
|
|
<button id="deleteUserBtn" class="btn btn-danger">Delete User</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div id="renameFileModal" class="modal">
|
|
<div class="modal-content">
|
|
<h4>Rename File</h4>
|
|
<input type="text" id="newFileName" class="form-control" placeholder="Enter new file name"
|
|
style="margin-top:10px;" />
|
|
<div style="margin-top:15px; text-align:right;">
|
|
<button id="cancelRenameFile" class="btn btn-secondary">Cancel</button>
|
|
<button id="submitRenameFile" class="btn btn-primary">Rename</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div id="customConfirmModal" class="modal" style="display:none;">
|
|
<div class="modal-content">
|
|
<p id="confirmMessage"></p>
|
|
<div class="modal-actions">
|
|
<button id="confirmYesBtn" class="btn btn-primary">Yes</button>
|
|
<button id="confirmNoBtn" class="btn btn-secondary">No</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- JavaScript Files -->
|
|
<script type="module" src="main.js"></script>
|
|
</body>
|
|
|
|
</html> |