VvvebJs / dashboard.html
CatPtain's picture
Upload 2 files
69c1665 verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>VvvebJs - User Dashboard</title>
<link href="css/editor.css" rel="stylesheet">
<style>
.user-dashboard {
max-width: 1200px;
margin: 0 auto;
padding: 20px;
}
.user-info {
background: #f8f9fa;
padding: 15px;
border-radius: 5px;
margin-bottom: 20px;
}
.file-manager {
background: white;
border: 1px solid #ddd;
border-radius: 5px;
overflow: hidden;
}
.file-manager-header {
background: #007bff;
color: white;
padding: 15px;
display: flex;
justify-content: space-between;
align-items: center;
}
.file-list {
max-height: 400px;
overflow-y: auto;
}
.file-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 10px 15px;
border-bottom: 1px solid #eee;
transition: background-color 0.2s;
}
.file-item:hover {
background-color: #f8f9fa;
}
.file-name {
font-weight: 500;
color: #333;
}
.file-meta {
font-size: 0.85em;
color: #666;
}
.file-actions {
display: flex;
gap: 10px;
}
.btn {
padding: 5px 10px;
border: none;
border-radius: 3px;
cursor: pointer;
font-size: 0.85em;
text-decoration: none;
display: inline-block;
}
.btn-primary {
background: #007bff;
color: white;
}
.btn-warning {
background: #ffc107;
color: #333;
}
.btn-danger {
background: #dc3545;
color: white;
}
.btn-success {
background: #28a745;
color: white;
}
.empty-state {
text-align: center;
padding: 40px;
color: #666;
}
.loading {
text-align: center;
padding: 20px;
color: #666;
}
.error {
background: #f8d7da;
color: #721c24;
padding: 10px;
border-radius: 3px;
margin: 10px 0;
}
.success {
background: #d4edda;
color: #155724;
padding: 10px;
border-radius: 3px;
margin: 10px 0;
}
.modal {
display: none;
position: fixed;
z-index: 1000;
left: 0;
top: 0;
width: 100%;
height: 100%;
background-color: rgba(0,0,0,0.4);
}
.modal-content {
background-color: #fefefe;
margin: 15% auto;
padding: 20px;
border: 1px solid #888;
border-radius: 5px;
width: 300px;
}
.modal-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 15px;
}
.close {
color: #aaa;
font-size: 28px;
font-weight: bold;
cursor: pointer;
}
.close:hover {
color: black;
}
.form-group {
margin-bottom: 15px;
}
.form-group label {
display: block;
margin-bottom: 5px;
font-weight: bold;
}
.form-group input {
width: 100%;
padding: 8px;
border: 1px solid #ddd;
border-radius: 3px;
box-sizing: border-box;
}
</style>
</head>
<body>
<div class="user-dashboard">
<div class="user-info">
<h2>Welcome to VvvebJs</h2>
<p><strong>User:</strong> <span id="current-user">Loading...</span></p>
<p><strong>Storage Path:</strong> <span id="user-path">Loading...</span></p>
</div>
<div class="file-manager">
<div class="file-manager-header">
<h3>My Files</h3>
<div>
<button class="btn btn-success" onclick="createNewFile()">New Page</button>
<button class="btn btn-primary" onclick="refreshFileList()">Refresh</button>
<a href="editor.html" class="btn btn-primary">Open Editor</a>
</div>
</div>
<div id="file-list-container">
<div class="loading">Loading files...</div>
</div>
</div>
</div>
<!-- Rename Modal -->
<div id="renameModal" class="modal">
<div class="modal-content">
<div class="modal-header">
<h4>Rename File</h4>
<span class="close" onclick="closeModal('renameModal')">&times;</span>
</div>
<div class="form-group">
<label for="newFileName">New filename:</label>
<input type="text" id="newFileName" placeholder="Enter new filename">
</div>
<div>
<button class="btn btn-primary" onclick="confirmRename()">Rename</button>
<button class="btn" onclick="closeModal('renameModal')">Cancel</button>
</div>
</div>
</div>
<!-- Delete Confirmation Modal -->
<div id="deleteModal" class="modal">
<div class="modal-content">
<div class="modal-header">
<h4>Delete File</h4>
<span class="close" onclick="closeModal('deleteModal')">&times;</span>
</div>
<p>Are you sure you want to delete <strong id="deleteFileName"></strong>?</p>
<div>
<button class="btn btn-danger" onclick="confirmDelete()">Delete</button>
<button class="btn" onclick="closeModal('deleteModal')">Cancel</button>
</div>
</div>
</div>
<script>
let currentFiles = [];
let selectedFile = '';
// Check authentication first, then load user info and files
document.addEventListener('DOMContentLoaded', function() {
checkAuthenticationAndInit();
});
async function checkAuthenticationAndInit() {
try {
const response = await fetch('save.php?action=checkAuth');
if (response.status === 401) {
// Not logged in, redirect to login page
window.location.href = 'index.html';
return;
}
const data = await response.json();
if (!data.authenticated) {
// Not authenticated, redirect to login page
window.location.href = 'index.html';
return;
}
// User is authenticated, proceed with loading dashboard
loadUserInfo();
loadFileList();
} catch (error) {
console.error('Auth check failed:', error);
// On error, redirect to login page
window.location.href = 'index.html';
}
}
async function loadUserInfo() {
try {
const response = await fetch('save.php?action=checkAuth');
const data = await response.json();
if (data.success) {
document.getElementById('current-user').textContent = data.user;
document.getElementById('user-path').textContent = data.userPath || 'Default';
}
} catch (error) {
console.error('Error loading user info:', error);
}
}
async function loadFileList() {
const container = document.getElementById('file-list-container');
container.innerHTML = '<div class="loading">Loading files...</div>';
try {
const response = await fetch('save.php?action=listFiles');
const data = await response.json();
if (data.success) {
currentFiles = data.files;
renderFileList(data.files);
} else {
container.innerHTML = '<div class="error">Error loading files: ' + (data.message || 'Unknown error') + '</div>';
}
} catch (error) {
console.error('Error loading files:', error);
container.innerHTML = '<div class="error">Error loading files: ' + error.message + '</div>';
}
}
function renderFileList(files) {
const container = document.getElementById('file-list-container');
if (files.length === 0) {
container.innerHTML = `
<div class="empty-state">
<p>No files found. <a href="editor.html" class="btn btn-success">Create your first page</a></p>
</div>
`;
return;
}
const fileListHTML = files.map(file => `
<div class="file-item">
<div>
<div class="file-name">${file.name}</div>
<div class="file-meta">
${file.size ? `Size: ${formatFileSize(file.size)} • ` : ''}
Path: ${file.path || file.name}
</div>
</div>
<div class="file-actions">
<a href="editor.html?file=${encodeURIComponent(file.path || file.name)}"
class="btn btn-primary">Edit</a>
${file.url ? `<a href="${file.url}" target="_blank" class="btn btn-success">View</a>` : ''}
<button class="btn btn-warning" onclick="renameFile('${file.name}')">Rename</button>
<button class="btn btn-danger" onclick="deleteFile('${file.name}')">Delete</button>
</div>
</div>
`).join('');
container.innerHTML = '<div class="file-list">' + fileListHTML + '</div>';
}
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 refreshFileList() {
loadFileList();
}
function createNewFile() {
const fileName = prompt('Enter filename (without .html extension):');
if (fileName) {
const safeFileName = fileName.replace(/[^a-zA-Z0-9_-]/g, '_') + '.html';
window.location.href = `editor.html?file=${encodeURIComponent(safeFileName)}`;
}
}
function renameFile(fileName) {
selectedFile = fileName;
document.getElementById('newFileName').value = fileName.replace('.html', '');
openModal('renameModal');
}
async function confirmRename() {
const newFileName = document.getElementById('newFileName').value.trim();
if (!newFileName) {
alert('Please enter a valid filename');
return;
}
const safeNewFileName = newFileName.replace(/[^a-zA-Z0-9_-]/g, '_') + '.html';
try {
const formData = new FormData();
formData.append('file', selectedFile);
formData.append('newfile', safeNewFileName);
const response = await fetch('save.php?action=rename', {
method: 'POST',
body: formData
});
const result = await response.text();
if (response.ok) {
showMessage('File renamed successfully', 'success');
closeModal('renameModal');
loadFileList();
} else {
showMessage('Error renaming file: ' + result, 'error');
}
} catch (error) {
showMessage('Error renaming file: ' + error.message, 'error');
}
}
function deleteFile(fileName) {
selectedFile = fileName;
document.getElementById('deleteFileName').textContent = fileName;
openModal('deleteModal');
}
async function confirmDelete() {
try {
const formData = new FormData();
formData.append('file', selectedFile);
const response = await fetch('save.php?action=delete', {
method: 'POST',
body: formData
});
const result = await response.text();
if (response.ok) {
showMessage('File deleted successfully', 'success');
closeModal('deleteModal');
loadFileList();
} else {
showMessage('Error deleting file: ' + result, 'error');
}
} catch (error) {
showMessage('Error deleting file: ' + error.message, 'error');
}
}
function openModal(modalId) {
document.getElementById(modalId).style.display = 'block';
}
function closeModal(modalId) {
document.getElementById(modalId).style.display = 'none';
}
function showMessage(message, type) {
const container = document.querySelector('.user-dashboard');
const messageDiv = document.createElement('div');
messageDiv.className = type;
messageDiv.textContent = message;
container.insertBefore(messageDiv, container.firstChild);
setTimeout(() => {
messageDiv.remove();
}, 5000);
}
// Close modals when clicking outside
window.onclick = function(event) {
const modals = document.querySelectorAll('.modal');
modals.forEach(modal => {
if (event.target === modal) {
modal.style.display = 'none';
}
});
}
</script>
</body>
</html>