Initial commit
This commit is contained in:
116
static/index.html
Normal file
116
static/index.html
Normal file
@@ -0,0 +1,116 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Album Manager</title>
|
||||
<link rel="stylesheet" href="/static/style.css">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/css/all.min.css" integrity="sha512-HfPclDlQUkcjYlZPzfdEftS5HkVU/LN8pPwqcSeCjJ83JGnVcqt7FYVgVkxGWMPN9IasvZp+hqQjW1FB2FYlnQ==" crossorigin="anonymous" referrerpolicy="no-referrer" />
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<header>
|
||||
<h1>Cloud Drive</h1>
|
||||
<div class="progress-bar">
|
||||
<div id="progress" style="width: 70%;">70.2 GB of 100 GB</div>
|
||||
</div>
|
||||
</header>
|
||||
<div class="main-content">
|
||||
<aside>
|
||||
<button id="add-project" class="btn">+ Add Project</button>
|
||||
<nav>
|
||||
<ul>
|
||||
<li id="projects-tab">Projects</li>
|
||||
<li>Expiring</li>
|
||||
<li>Archived Projects</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</aside>
|
||||
<!-- Update the login form to only show if the user is not logged in -->
|
||||
<section class="content">
|
||||
<form id="login-form" style="display: none;">
|
||||
<h2>Login</h2>
|
||||
<div>
|
||||
<label for="username">Username:</label>
|
||||
<input type="text" id="username" name="username" required>
|
||||
</div>
|
||||
<div>
|
||||
<label for="password">Password:</label>
|
||||
<input type="password" id="password" name="password" required>
|
||||
</div>
|
||||
<button type="submit">Login</button>
|
||||
</form>
|
||||
<table id="album-table" style="display:none;">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Project</th>
|
||||
<th>Shoot Date</th>
|
||||
<th>Expires</th>
|
||||
<th>Likes</th>
|
||||
<th>Link to Project</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="project-list">
|
||||
<!-- Project items will be dynamically populated here -->
|
||||
</tbody>
|
||||
</table>
|
||||
<div id="album-view" style="display:none;">
|
||||
<div id="album-header">
|
||||
<button id="back-to-projects" class="btn">Back to Projects</button>
|
||||
<h2 id="album-name"></h2>
|
||||
<button id="upload-button" class="btn">Upload</button>
|
||||
</div>
|
||||
<input type="file" id="file-input" multiple style="display:none;">
|
||||
<div id="image-gallery"></div>
|
||||
<div id="progress-bar" class="progress-bar">
|
||||
<div id="upload-progress"></div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
<div id="modal" class="modal">
|
||||
<span id="close-modal">×</span>
|
||||
<div id="modal-content"></div>
|
||||
<div id="modal-prev" class="modal-nav">❮</div>
|
||||
<div id="modal-next" class="modal-nav">❯</div>
|
||||
</div>
|
||||
<!-- Add Project Modal -->
|
||||
<div id="add-project-modal" class="modal">
|
||||
<div class="modal-content">
|
||||
<span class="close">×</span>
|
||||
<h2>Add New Project</h2>
|
||||
<form id="add-project-form">
|
||||
<label for="name">Project Name</label>
|
||||
<input type="text" id="name" name="name" required>
|
||||
|
||||
<label for="password">Password (optional)</label>
|
||||
<input type="password" id="password" name="password">
|
||||
|
||||
<label>
|
||||
<input type="checkbox" id="watermarked" name="watermarked">
|
||||
Watermarked
|
||||
</label>
|
||||
|
||||
<label>
|
||||
<input type="checkbox" id="allow_comments" name="allow_comments">
|
||||
Allow Comments
|
||||
</label>
|
||||
|
||||
<label>
|
||||
<input type="checkbox" id="allow_favourite" name="allow_favourite">
|
||||
Allow Favourite
|
||||
</label>
|
||||
|
||||
<label>
|
||||
<input type="checkbox" id="allow_downloads" name="allow_downloads">
|
||||
Allow Downloads
|
||||
</label>
|
||||
|
||||
<button type="submit">Create Project</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<script src="/static/script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
238
static/script.js
Normal file
238
static/script.js
Normal file
@@ -0,0 +1,238 @@
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
const projectList = document.getElementById('project-list');
|
||||
const loginForm = document.getElementById('login-form');
|
||||
const albumTable = document.getElementById('album-table');
|
||||
const albumView = document.getElementById('album-view');
|
||||
const albumName = document.getElementById('album-name');
|
||||
const imageGallery = document.getElementById('image-gallery');
|
||||
const uploadButton = document.getElementById('upload-button');
|
||||
const fileInput = document.getElementById('file-input');
|
||||
const progressBar = document.getElementById('progress-bar');
|
||||
const uploadProgress = document.getElementById('upload-progress');
|
||||
|
||||
let currentAlbumId = null;
|
||||
let currentIndex = 0;
|
||||
|
||||
const checkLoginStatus = async () => {
|
||||
try {
|
||||
const response = await fetch('/albums', { credentials: 'include' });
|
||||
if (response.ok) {
|
||||
loginForm.style.display = 'none';
|
||||
loadProjects();
|
||||
} else {
|
||||
loginForm.style.display = 'block';
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error checking login status:', error);
|
||||
loginForm.style.display = 'block';
|
||||
}
|
||||
};
|
||||
|
||||
const loadProjects = async () => {
|
||||
try {
|
||||
const response = await fetch('/albums', { credentials: 'include' });
|
||||
const data = await response.json();
|
||||
projectList.innerHTML = '';
|
||||
if (data !== undefined && data.albums !== null) {
|
||||
data.albums.forEach(album => {
|
||||
const row = document.createElement('tr');
|
||||
row.innerHTML = `
|
||||
<td>${album.name}</td>
|
||||
<td>${album.created_at}</td>
|
||||
<td>${album.expire_at}</td>
|
||||
<td>${album.likes}</td>
|
||||
<td><a href="#" data-id="${album.id}" class="view-album">View Album</a></td>
|
||||
`;
|
||||
projectList.appendChild(row);
|
||||
});
|
||||
}
|
||||
|
||||
albumTable.style.display = 'block';
|
||||
} catch (error) {
|
||||
console.error('Error loading projects:', error);
|
||||
}
|
||||
};
|
||||
|
||||
const handleLogin = async (event) => {
|
||||
event.preventDefault();
|
||||
const formData = new FormData(loginForm);
|
||||
try {
|
||||
const response = await fetch('/login', {
|
||||
method: 'POST',
|
||||
body: formData
|
||||
});
|
||||
if (response.ok) {
|
||||
loginForm.style.display = 'none';
|
||||
loadProjects();
|
||||
} else {
|
||||
alert('Login failed');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error logging in:', error);
|
||||
}
|
||||
};
|
||||
|
||||
const loadAlbum = async (albumId) => {
|
||||
currentAlbumId = albumId;
|
||||
albumTable.style.display = 'none'; // Hide the album table when viewing an album
|
||||
try {
|
||||
const response = await fetch(`/albums/${albumId}/list`);
|
||||
const data = await response.json();
|
||||
albumView.style.display = 'block';
|
||||
albumName.textContent = data.name;
|
||||
imageGallery.innerHTML = '';
|
||||
data.images.forEach((image, index) => {
|
||||
const fileType = image.split('.').pop();
|
||||
const item = document.createElement('div');
|
||||
item.className = 'gallery-item';
|
||||
item.dataset.index = index;
|
||||
if (fileType === 'mp4') {
|
||||
item.innerHTML = `
|
||||
<video src="${image}" class="gallery-thumb" data-id="${image}"></video>
|
||||
`;
|
||||
} else {
|
||||
item.innerHTML = `
|
||||
<img src="${image}" class="gallery-thumb" data-id="${image}">
|
||||
`;
|
||||
}
|
||||
imageGallery.appendChild(item);
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Error loading album:', error);
|
||||
}
|
||||
};
|
||||
|
||||
const handleUpload = async (formData, albumId) => {
|
||||
progressBar.style.display = 'block';
|
||||
try {
|
||||
await fetch(`/album/${albumId}/upload`, {
|
||||
method: 'POST',
|
||||
body: formData,
|
||||
credentials: 'include',
|
||||
onUploadProgress: (progressEvent) => {
|
||||
const percentCompleted = Math.round((progressEvent.loaded * 100) / progressEvent.total);
|
||||
uploadProgress.style.width = `${percentCompleted}%`;
|
||||
uploadProgress.textContent = `${percentCompleted}%`;
|
||||
}
|
||||
});
|
||||
progressBar.style.display = 'none';
|
||||
loadAlbum(albumId);
|
||||
} catch (error) {
|
||||
console.error('Error uploading images:', error);
|
||||
progressBar.style.display = 'none';
|
||||
}
|
||||
};
|
||||
|
||||
const handleFiles = (files) => {
|
||||
const formData = new FormData();
|
||||
for (let i = 0; i < files.length; i++) {
|
||||
formData.append('files[]', files[i]);
|
||||
}
|
||||
handleUpload(formData, currentAlbumId);
|
||||
};
|
||||
|
||||
const openModal = (index) => {
|
||||
const items = document.querySelectorAll('.gallery-thumb');
|
||||
currentIndex = index;
|
||||
const item = items[currentIndex];
|
||||
if (item.tagName === 'VIDEO') {
|
||||
document.getElementById('modal-content').innerHTML = `
|
||||
<video controls autoplay>
|
||||
<source src="${item.dataset.id}" type="video/mp4">
|
||||
</video>
|
||||
`;
|
||||
} else {
|
||||
document.getElementById('modal-content').innerHTML = `
|
||||
<img src="${item.dataset.id}">
|
||||
`;
|
||||
}
|
||||
document.getElementById('modal').style.display = 'flex';
|
||||
};
|
||||
|
||||
const closeModal = () => {
|
||||
document.getElementById('modal').style.display = 'none';
|
||||
const video = document.querySelector('#modal-content video');
|
||||
if (video) {
|
||||
video.pause();
|
||||
}
|
||||
};
|
||||
|
||||
const nextModal = () => {
|
||||
const items = document.querySelectorAll('.gallery-thumb');
|
||||
currentIndex = (currentIndex + 1) % items.length;
|
||||
openModal(currentIndex);
|
||||
};
|
||||
|
||||
const prevModal = () => {
|
||||
const items = document.querySelectorAll('.gallery-thumb');
|
||||
currentIndex = (currentIndex - 1 + items.length) % items.length;
|
||||
openModal(currentIndex);
|
||||
};
|
||||
|
||||
const openAddProjectModal = () => {
|
||||
document.getElementById('add-project-modal').style.display = 'flex';
|
||||
};
|
||||
|
||||
const closeAddProjectModal = () => {
|
||||
document.getElementById('add-project-modal').style.display = 'none';
|
||||
};
|
||||
|
||||
const handleAddProject = async (event) => {
|
||||
event.preventDefault();
|
||||
const formData = new FormData(event.target);
|
||||
try {
|
||||
const response = await fetch('/albums/new', {
|
||||
method: 'POST',
|
||||
body: formData,
|
||||
credentials: 'include'
|
||||
});
|
||||
if (response.ok) {
|
||||
closeAddProjectModal();
|
||||
loadProjects();
|
||||
} else {
|
||||
alert('Failed to create project');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error creating project:', error);
|
||||
}
|
||||
};
|
||||
|
||||
document.addEventListener('click', (event) => {
|
||||
if (event.target.classList.contains('view-album')) {
|
||||
const albumId = event.target.dataset.id;
|
||||
loadAlbum(albumId);
|
||||
}
|
||||
if (event.target.classList.contains('gallery-thumb')) {
|
||||
openModal(parseInt(event.target.parentElement.dataset.index));
|
||||
}
|
||||
if (event.target.id === 'close-modal') {
|
||||
closeModal();
|
||||
}
|
||||
if (event.target.id === 'modal-next') {
|
||||
nextModal();
|
||||
}
|
||||
if (event.target.id === 'modal-prev') {
|
||||
prevModal();
|
||||
}
|
||||
if (event.target.id === 'add-project') {
|
||||
openAddProjectModal();
|
||||
}
|
||||
if (event.target.id === 'close-add-project-modal') {
|
||||
closeAddProjectModal();
|
||||
}
|
||||
});
|
||||
|
||||
loginForm.addEventListener('submit', handleLogin);
|
||||
|
||||
document.getElementById('add-project-form').addEventListener('submit', handleAddProject);
|
||||
|
||||
uploadButton.addEventListener('click', () => {
|
||||
fileInput.click();
|
||||
});
|
||||
|
||||
fileInput.addEventListener('change', () => {
|
||||
handleFiles(fileInput.files);
|
||||
});
|
||||
|
||||
checkLoginStatus(); // Check if the user is logged in on page load
|
||||
});
|
||||
353
static/style.css
Normal file
353
static/style.css
Normal file
@@ -0,0 +1,353 @@
|
||||
/* Existing CSS */
|
||||
body {
|
||||
font-family: Arial, sans-serif;
|
||||
background-color: #f4f4f4;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100vh;
|
||||
}
|
||||
|
||||
header {
|
||||
background-color: #2c3e50;
|
||||
color: white;
|
||||
padding: 1rem;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.progress-bar {
|
||||
background-color: #bdc3c7;
|
||||
border-radius: 10px;
|
||||
overflow: hidden;
|
||||
width: 300px;
|
||||
}
|
||||
|
||||
#progress {
|
||||
background-color: #27ae60;
|
||||
color: white;
|
||||
padding: 5px;
|
||||
text-align: center;
|
||||
border-radius: 10px 0 0 10px;
|
||||
}
|
||||
|
||||
.main-content {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
aside {
|
||||
background-color: #34495e;
|
||||
color: white;
|
||||
padding: 1rem;
|
||||
width: 200px;
|
||||
}
|
||||
|
||||
aside .btn {
|
||||
background-color: #27ae60;
|
||||
color: white;
|
||||
border: none;
|
||||
padding: 10px 20px;
|
||||
cursor: pointer;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
aside nav ul {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
aside nav ul li {
|
||||
padding: 10px 0;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
aside nav ul li:hover {
|
||||
background-color: #2c3e50;
|
||||
}
|
||||
|
||||
.content {
|
||||
flex: 1;
|
||||
overflow: auto;
|
||||
padding: 1rem;
|
||||
background-color: white;
|
||||
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
th, td {
|
||||
padding: 1rem;
|
||||
text-align: left;
|
||||
border-bottom: 1px solid #ddd;
|
||||
}
|
||||
|
||||
th {
|
||||
background-color: #ecf0f1;
|
||||
}
|
||||
|
||||
tr:hover {
|
||||
background-color: #f1f1f1;
|
||||
}
|
||||
|
||||
/* New CSS for Login Form */
|
||||
#login-form {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 300px;
|
||||
margin: 50px auto;
|
||||
padding: 20px;
|
||||
border: 1px solid #ccc;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
#login-form h2 {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
#login-form div {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
#login-form label {
|
||||
display: block;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
#login-form input {
|
||||
width: 100%;
|
||||
padding: 8px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
#login-form button {
|
||||
padding: 10px;
|
||||
background-color: #27ae60;
|
||||
color: white;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#login-form button:hover {
|
||||
background-color: #219150;
|
||||
}
|
||||
|
||||
/* New CSS for Album View */
|
||||
#album-view {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
#album-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
#image-gallery {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
#image-gallery img, #image-gallery video {
|
||||
width: 150px;
|
||||
height: 150px;
|
||||
object-fit: cover;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#progress-bar {
|
||||
display: none;
|
||||
background-color: #bdc3c7;
|
||||
border-radius: 10px;
|
||||
overflow: hidden;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
#upload-progress {
|
||||
background-color: #27ae60;
|
||||
color: white;
|
||||
padding: 5px;
|
||||
text-align: center;
|
||||
border-radius: 10px 0 0 10px;
|
||||
width: 0;
|
||||
}
|
||||
|
||||
.modal {
|
||||
display: none;
|
||||
position: fixed;
|
||||
z-index: 1000;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: auto;
|
||||
background-color: rgba(0, 0, 0, 0.9);
|
||||
}
|
||||
|
||||
.modal-content {
|
||||
margin: auto;
|
||||
display: block;
|
||||
width: 80%;
|
||||
max-width: 700px;
|
||||
}
|
||||
|
||||
.modal-nav {
|
||||
cursor: pointer;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
width: auto;
|
||||
padding: 16px;
|
||||
margin-top: -22px;
|
||||
color: white;
|
||||
font-weight: bold;
|
||||
font-size: 20px;
|
||||
transition: 0.6s ease;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
#modal-prev {
|
||||
left: 0;
|
||||
}
|
||||
|
||||
#modal-next {
|
||||
right: 0;
|
||||
}
|
||||
|
||||
#close-modal {
|
||||
position: absolute;
|
||||
top: 15px;
|
||||
right: 35px;
|
||||
color: white;
|
||||
font-size: 40px;
|
||||
font-weight: bold;
|
||||
transition: 0.3s;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#close-modal:hover,
|
||||
#close-modal:focus {
|
||||
color: #bbb;
|
||||
text-decoration: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
/* Modal content scaled to viewport */
|
||||
.modal-content {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.modal-content img, .modal-content video {
|
||||
max-width: 100%;
|
||||
max-height: 90vh;
|
||||
}
|
||||
|
||||
/* Add Project Modal */
|
||||
#add-project-modal {
|
||||
display: none;
|
||||
position: fixed;
|
||||
z-index: 1000;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: auto;
|
||||
background-color: rgba(0, 0, 0, 0.8);
|
||||
}
|
||||
|
||||
#add-project-modal .modal-content {
|
||||
background-color: #fefefe;
|
||||
margin: 5% auto;
|
||||
padding: 20px;
|
||||
border: 1px solid #888;
|
||||
border-radius: 10px;
|
||||
width: 40%;
|
||||
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.3);
|
||||
animation: modalopen 0.5s;
|
||||
}
|
||||
|
||||
@keyframes modalopen {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(-50px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
#add-project-modal .modal-content h2 {
|
||||
margin-top: 0;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
#add-project-modal .modal-content form {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
#add-project-modal .modal-content label {
|
||||
margin: 10px 0 5px;
|
||||
}
|
||||
|
||||
#add-project-modal .modal-content input[type="text"],
|
||||
#add-project-modal .modal-content input[type="password"] {
|
||||
padding: 10px;
|
||||
margin: 5px 0 15px;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 4px;
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
#add-project-modal .modal-content input[type="checkbox"] {
|
||||
width: auto;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
#add-project-modal .modal-content button[type="submit"] {
|
||||
background-color: #27ae60;
|
||||
color: white;
|
||||
padding: 10px 20px;
|
||||
text-align: center;
|
||||
text-decoration: none;
|
||||
display: inline-block;
|
||||
font-size: 16px;
|
||||
margin: 4px 2px;
|
||||
cursor: pointer;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
#add-project-modal .modal-content button[type="submit"]:hover {
|
||||
background-color: #219150;
|
||||
}
|
||||
|
||||
#add-project-modal .close {
|
||||
color: #aaa;
|
||||
float: right;
|
||||
font-size: 28px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
#add-project-modal .close:hover,
|
||||
#add-project-modal .close:focus {
|
||||
color: black;
|
||||
text-decoration: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
Reference in New Issue
Block a user