275 lines
11 KiB
HTML
275 lines
11 KiB
HTML
{{define "folder"}}
|
|
{{template "base" .}}
|
|
{{end}}
|
|
|
|
{{define "folder_content"}}
|
|
<div class="p-6">
|
|
<!-- Header with upload button -->
|
|
<div class="flex items-center justify-between mb-6">
|
|
<div>
|
|
<h1 class="text-2xl font-bold text-white mb-2">
|
|
{{if .folder_path}}
|
|
{{.folder_path}}
|
|
{{else}}
|
|
Welcome to {{.app_name}}
|
|
{{end}}
|
|
</h1>
|
|
<p class="text-gray-400">
|
|
{{if .folder_contents}}
|
|
{{len .folder_contents}} items
|
|
{{else}}
|
|
No items found
|
|
{{end}}
|
|
</p>
|
|
</div>
|
|
<div class="flex items-center space-x-3">
|
|
<button id="upload-btn" class="btn-primary">
|
|
<i class="fas fa-upload mr-2"></i>Upload File
|
|
</button>
|
|
<a href="/editor/create?folder={{.folder_path}}" class="btn-secondary">
|
|
<i class="fas fa-plus mr-2"></i>New Note
|
|
</a>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Upload Area (hidden by default) -->
|
|
<div id="upload-area" class="upload-area mb-6 hidden">
|
|
<div class="flex flex-col items-center">
|
|
<i class="fas fa-cloud-upload text-4xl text-gray-500 mb-4"></i>
|
|
<p class="text-gray-400 mb-2">Drag and drop files here or click to select</p>
|
|
<input type="file" id="file-input" multiple class="hidden">
|
|
<button id="select-files" class="btn-secondary">Select Files</button>
|
|
</div>
|
|
<div id="upload-progress" class="mt-4 hidden">
|
|
<div class="w-full bg-gray-700 rounded-full h-2">
|
|
<div id="progress-bar" class="bg-blue-600 h-2 rounded-full transition-all duration-300" style="width: 0%"></div>
|
|
</div>
|
|
<p id="upload-status" class="text-sm text-gray-400 mt-2"></p>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Content Grid -->
|
|
<div class="grid gap-4">
|
|
{{if .folder_contents}}
|
|
{{range .folder_contents}}
|
|
<div class="bg-gray-800 rounded-lg p-4 hover:bg-gray-700 transition-colors duration-200 cursor-pointer item-card"
|
|
data-path="{{.Path}}" data-type="{{.Type}}">
|
|
<div class="flex items-center justify-between">
|
|
<div class="flex items-center space-x-3">
|
|
<span class="text-2xl">{{fileTypeIcon .Type}}</span>
|
|
<div>
|
|
<h3 class="font-medium text-white">{{.DisplayName}}</h3>
|
|
<p class="text-sm text-gray-400">
|
|
{{if eq .Type "dir"}}
|
|
Folder
|
|
{{else}}
|
|
{{formatSize .Size}} • {{formatTime .ModTime}}
|
|
{{end}}
|
|
</p>
|
|
</div>
|
|
</div>
|
|
<div class="flex items-center space-x-2">
|
|
{{if eq .Type "md"}}
|
|
<a href="/editor/edit/{{.Path}}" class="text-blue-400 hover:text-blue-300 p-2" title="Edit">
|
|
<i class="fas fa-edit"></i>
|
|
</a>
|
|
{{end}}
|
|
{{if eq .Type "text"}}
|
|
<a href="/editor/edit_text/{{.Path}}" class="text-blue-400 hover:text-blue-300 p-2" title="Edit">
|
|
<i class="fas fa-edit"></i>
|
|
</a>
|
|
{{end}}
|
|
{{if eq .Type "image"}}
|
|
<a href="/serve_attached_image/{{.Path}}" target="_blank" class="text-yellow-400 hover:text-yellow-300 p-2" title="View">
|
|
<i class="fas fa-eye"></i>
|
|
</a>
|
|
{{end}}
|
|
{{if ne .Type "dir"}}
|
|
<a href="/download/{{.Path}}" class="text-green-400 hover:text-green-300 p-2" title="Download">
|
|
<i class="fas fa-download"></i>
|
|
</a>
|
|
{{end}}
|
|
<button class="text-red-400 hover:text-red-300 p-2 delete-btn" data-path="{{.Path}}" title="Delete">
|
|
<i class="fas fa-trash"></i>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{{end}}
|
|
{{else}}
|
|
<div class="text-center py-12">
|
|
<i class="fas fa-folder-open text-6xl text-gray-600 mb-4"></i>
|
|
<p class="text-xl text-gray-400 mb-2">This folder is empty</p>
|
|
<p class="text-gray-500">Create a new note or upload files to get started</p>
|
|
</div>
|
|
{{end}}
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Delete Confirmation Modal -->
|
|
<div id="delete-modal" class="modal-overlay hidden">
|
|
<div class="modal-content">
|
|
<h3 class="text-lg font-medium text-white mb-4">Confirm Delete</h3>
|
|
<p class="text-gray-300 mb-6">Are you sure you want to delete this item? This action cannot be undone.</p>
|
|
<div class="flex justify-end space-x-3">
|
|
<button id="cancel-delete" class="btn-secondary">Cancel</button>
|
|
<button id="confirm-delete" class="btn-danger">Delete</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{{end}}
|
|
|
|
{{define "folder_scripts"}}
|
|
<script>
|
|
let uploadArea = document.getElementById('upload-area');
|
|
let fileInput = document.getElementById('file-input');
|
|
let uploadBtn = document.getElementById('upload-btn');
|
|
let selectFilesBtn = document.getElementById('select-files');
|
|
let uploadProgress = document.getElementById('upload-progress');
|
|
let progressBar = document.getElementById('progress-bar');
|
|
let uploadStatus = document.getElementById('upload-status');
|
|
let deleteModal = document.getElementById('delete-modal');
|
|
let deleteTarget = null;
|
|
|
|
// Toggle upload area
|
|
uploadBtn.addEventListener('click', function() {
|
|
uploadArea.classList.toggle('hidden');
|
|
});
|
|
|
|
// File selection
|
|
selectFilesBtn.addEventListener('click', function() {
|
|
fileInput.click();
|
|
});
|
|
|
|
fileInput.addEventListener('change', function() {
|
|
if (this.files.length > 0) {
|
|
uploadFiles(this.files);
|
|
}
|
|
});
|
|
|
|
// Drag and drop
|
|
uploadArea.addEventListener('dragover', function(e) {
|
|
e.preventDefault();
|
|
this.classList.add('dragover');
|
|
});
|
|
|
|
uploadArea.addEventListener('dragleave', function(e) {
|
|
e.preventDefault();
|
|
this.classList.remove('dragover');
|
|
});
|
|
|
|
uploadArea.addEventListener('drop', function(e) {
|
|
e.preventDefault();
|
|
this.classList.remove('dragover');
|
|
if (e.dataTransfer.files.length > 0) {
|
|
uploadFiles(e.dataTransfer.files);
|
|
}
|
|
});
|
|
|
|
// Upload files function
|
|
function uploadFiles(files) {
|
|
uploadProgress.classList.remove('hidden');
|
|
progressBar.style.width = '0%';
|
|
uploadStatus.textContent = 'Preparing upload...';
|
|
|
|
const formData = new FormData();
|
|
formData.append('path', '{{.folder_path}}');
|
|
|
|
for (let file of files) {
|
|
formData.append('file', file);
|
|
}
|
|
|
|
const m = document.cookie.match(/(?:^|; )csrf_token=([^;]+)/);
|
|
const csrf = m && m[1] ? decodeURIComponent(m[1]) : '';
|
|
fetch('/editor/upload', {
|
|
method: 'POST',
|
|
headers: csrf ? { 'X-CSRF-Token': csrf } : {},
|
|
body: formData
|
|
})
|
|
.then(response => response.json())
|
|
.then(data => {
|
|
if (data.success) {
|
|
progressBar.style.width = '100%';
|
|
uploadStatus.textContent = 'Upload complete!';
|
|
showNotification('Files uploaded successfully', 'success');
|
|
setTimeout(() => {
|
|
window.location.reload();
|
|
}, 1000);
|
|
} else {
|
|
throw new Error(data.error || 'Upload failed');
|
|
}
|
|
})
|
|
.catch(error => {
|
|
uploadStatus.textContent = 'Upload failed: ' + error.message;
|
|
showNotification('Upload failed: ' + error.message, 'error');
|
|
});
|
|
}
|
|
|
|
// Item click handlers
|
|
document.addEventListener('click', function(e) {
|
|
const itemCard = e.target.closest('.item-card');
|
|
if (itemCard && !e.target.closest('a') && !e.target.closest('button')) {
|
|
const path = itemCard.dataset.path;
|
|
const type = itemCard.dataset.type;
|
|
|
|
if (type === 'dir') {
|
|
window.location.href = '/folder/' + path;
|
|
} else if (type === 'md') {
|
|
window.location.href = '/note/' + path;
|
|
} else if (type === 'image') {
|
|
window.open('/serve_attached_image/' + path, '_blank');
|
|
} else {
|
|
window.location.href = '/view_text/' + path;
|
|
}
|
|
}
|
|
});
|
|
|
|
// Delete functionality
|
|
document.addEventListener('click', function(e) {
|
|
if (e.target.closest('.delete-btn')) {
|
|
e.stopPropagation();
|
|
deleteTarget = e.target.closest('.delete-btn').dataset.path;
|
|
deleteModal.classList.remove('hidden');
|
|
}
|
|
});
|
|
|
|
document.getElementById('cancel-delete').addEventListener('click', function() {
|
|
deleteModal.classList.add('hidden');
|
|
deleteTarget = null;
|
|
});
|
|
|
|
document.getElementById('confirm-delete').addEventListener('click', function() {
|
|
if (deleteTarget) {
|
|
const m = document.cookie.match(/(?:^|; )csrf_token=([^;]+)/);
|
|
const csrf = m && m[1] ? decodeURIComponent(m[1]) : '';
|
|
fetch('/editor/delete/' + deleteTarget, {
|
|
method: 'DELETE',
|
|
headers: csrf ? { 'X-CSRF-Token': csrf } : {}
|
|
})
|
|
.then(response => response.json())
|
|
.then(data => {
|
|
if (data.success) {
|
|
showNotification('Item deleted successfully', 'success');
|
|
window.location.reload();
|
|
} else {
|
|
throw new Error(data.error || 'Delete failed');
|
|
}
|
|
})
|
|
.catch(error => {
|
|
showNotification('Delete failed: ' + error.message, 'error');
|
|
});
|
|
}
|
|
deleteModal.classList.add('hidden');
|
|
deleteTarget = null;
|
|
});
|
|
|
|
// Close modal when clicking outside
|
|
deleteModal.addEventListener('click', function(e) {
|
|
if (e.target === this) {
|
|
this.classList.add('hidden');
|
|
deleteTarget = null;
|
|
}
|
|
});
|
|
</script>
|
|
{{end}}
|