|
|
<!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>
|
|
|
|
|
|
|
|
|
<div id="renameModal" class="modal">
|
|
|
<div class="modal-content">
|
|
|
<div class="modal-header">
|
|
|
<h4>Rename File</h4>
|
|
|
<span class="close" onclick="closeModal('renameModal')">×</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>
|
|
|
|
|
|
|
|
|
<div id="deleteModal" class="modal">
|
|
|
<div class="modal-content">
|
|
|
<div class="modal-header">
|
|
|
<h4>Delete File</h4>
|
|
|
<span class="close" onclick="closeModal('deleteModal')">×</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 = '';
|
|
|
|
|
|
|
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
|
checkAuthenticationAndInit();
|
|
|
});
|
|
|
|
|
|
async function checkAuthenticationAndInit() {
|
|
|
try {
|
|
|
const response = await fetch('save.php?action=checkAuth');
|
|
|
if (response.status === 401) {
|
|
|
|
|
|
window.location.href = 'index.html';
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
const data = await response.json();
|
|
|
if (!data.authenticated) {
|
|
|
|
|
|
window.location.href = 'index.html';
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
|
|
|
loadUserInfo();
|
|
|
loadFileList();
|
|
|
} catch (error) {
|
|
|
console.error('Auth check failed:', error);
|
|
|
|
|
|
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);
|
|
|
}
|
|
|
|
|
|
|
|
|
window.onclick = function(event) {
|
|
|
const modals = document.querySelectorAll('.modal');
|
|
|
modals.forEach(modal => {
|
|
|
if (event.target === modal) {
|
|
|
modal.style.display = 'none';
|
|
|
}
|
|
|
});
|
|
|
}
|
|
|
</script>
|
|
|
</body>
|
|
|
</html> |