feat: Implement collection deletion and loading spinners

- Add API endpoint and handler to delete collections
- Introduce LoadingSpinner component for async operations
- Show loading spinners during file loading and preview rendering
- Enhance modal accessibility by removing aria-hidden attribute
- Refactor delete functionality to distinguish between collections and files/folders
- Remove unused collection definitions from config
This commit is contained in:
Mahmoud-Emad
2025-10-27 11:32:20 +03:00
parent afcd074913
commit 3961628b3d
15 changed files with 557 additions and 32 deletions

View File

@@ -16,6 +16,10 @@ class MarkdownEditor {
this.editor = null; // Will be initialized later
this.isShowingCustomPreview = false; // Flag to prevent auto-update when showing binary files
// Initialize loading spinners (will be created lazily when needed)
this.editorSpinner = null;
this.previewSpinner = null;
// Only initialize CodeMirror if not in read-only mode (view mode)
if (!readOnly) {
this.initCodeMirror();
@@ -206,11 +210,34 @@ class MarkdownEditor {
}
}
/**
* Initialize loading spinners (lazy initialization)
*/
initLoadingSpinners() {
if (!this.editorSpinner && !this.readOnly && this.editorElement) {
this.editorSpinner = new LoadingSpinner(this.editorElement, 'Loading file...');
}
if (!this.previewSpinner && this.previewElement) {
this.previewSpinner = new LoadingSpinner(this.previewElement, 'Rendering preview...');
}
}
/**
* Load file
*/
async loadFile(path) {
try {
// Initialize loading spinners if not already done
this.initLoadingSpinners();
// Show loading spinners
if (this.editorSpinner) {
this.editorSpinner.show('Loading file...');
}
if (this.previewSpinner) {
this.previewSpinner.show('Loading preview...');
}
// Reset custom preview flag when loading text files
this.isShowingCustomPreview = false;
@@ -232,8 +259,25 @@ class MarkdownEditor {
// Save as last viewed page
this.saveLastViewedPage(path);
// Hide loading spinners
if (this.editorSpinner) {
this.editorSpinner.hide();
}
if (this.previewSpinner) {
this.previewSpinner.hide();
}
// No notification for successful file load - it's not critical
} catch (error) {
// Hide loading spinners on error
if (this.editorSpinner) {
this.editorSpinner.hide();
}
if (this.previewSpinner) {
this.previewSpinner.hide();
}
console.error('Failed to load file:', error);
if (window.showNotification) {
window.showNotification('Failed to load file', 'danger');
@@ -409,6 +453,14 @@ class MarkdownEditor {
}
try {
// Initialize loading spinners if not already done
this.initLoadingSpinners();
// Show preview loading spinner (only if not already shown by loadFile)
if (this.previewSpinner && !this.previewSpinner.isVisible()) {
this.previewSpinner.show('Rendering preview...');
}
// Step 0: Convert JSX-style syntax to HTML
let processedContent = this.convertJSXToHTML(markdown);
@@ -422,6 +474,9 @@ class MarkdownEditor {
if (!this.marked) {
console.error("Markdown parser (marked) not initialized.");
previewDiv.innerHTML = `<div class="alert alert-danger">Preview engine not loaded.</div>`;
if (this.previewSpinner) {
this.previewSpinner.hide();
}
return;
}
@@ -459,6 +514,13 @@ class MarkdownEditor {
console.warn('Mermaid rendering error:', error);
}
}
// Hide preview loading spinner after a small delay to ensure rendering is complete
setTimeout(() => {
if (this.previewSpinner) {
this.previewSpinner.hide();
}
}, 100);
} catch (error) {
console.error('Preview rendering error:', error);
previewDiv.innerHTML = `
@@ -467,6 +529,11 @@ class MarkdownEditor {
${error.message}
</div>
`;
// Hide loading spinner on error
if (this.previewSpinner) {
this.previewSpinner.hide();
}
}
}