752 lines
No EOL
31 KiB
HTML
752 lines
No EOL
31 KiB
HTML
{% extends "base.html" %}
|
||
|
||
{% block title %}All Documents - {{ category.name }} - Vim Docs{% endblock %}
|
||
|
||
{% block header_title %}
|
||
<a href="{{ url_for('main.view_category', category_id=category.id) }}" class="hover:underline flex items-center">
|
||
<i class="mdi {{ category.icon }} mr-2"></i> {{ category.name }} <span class="mx-2">›</span> All Documents
|
||
</a>
|
||
{% endblock %}
|
||
|
||
{% block header_actions %}
|
||
<a href="{{ url_for('main.new_document') }}?category={{ category.id }}" class="inline-flex items-center px-4 py-2 bg-primary text-black rounded-md hover:bg-primary-dark transition-colors">
|
||
<i class="mdi mdi-plus mr-2"></i> New Document
|
||
</a>
|
||
<a href="{{ url_for('main.view_category', category_id=category.id) }}" class="inline-flex items-center px-4 py-2 bg-gray-700 text-white rounded-md hover:bg-gray-600 transition-colors ml-2">
|
||
<i class="mdi mdi-folder-outline mr-2"></i> Back to Category
|
||
</a>
|
||
{% endblock %}
|
||
|
||
{% block extra_css %}
|
||
<style>
|
||
.documents-container {
|
||
max-width: 1200px;
|
||
margin: 0 auto;
|
||
}
|
||
|
||
.document-card {
|
||
transition: all 0.2s ease;
|
||
}
|
||
|
||
.document-card:hover {
|
||
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.3);
|
||
transform: translateY(-2px);
|
||
}
|
||
|
||
.document-category {
|
||
font-size: 0.75rem;
|
||
color: #8b949e;
|
||
display: flex;
|
||
align-items: center;
|
||
}
|
||
|
||
.document-category i {
|
||
margin-right: 4px;
|
||
}
|
||
|
||
.document-preview {
|
||
max-height: 4.5rem;
|
||
overflow: hidden;
|
||
display: -webkit-box;
|
||
-webkit-line-clamp: 3;
|
||
-webkit-box-orient: vertical;
|
||
text-overflow: ellipsis;
|
||
transition: max-height 0.3s ease;
|
||
}
|
||
|
||
.document-preview.expanded {
|
||
max-height: 20rem;
|
||
-webkit-line-clamp: unset;
|
||
overflow-y: auto;
|
||
}
|
||
|
||
.document-preview.fully-expanded {
|
||
max-height: 60rem;
|
||
-webkit-line-clamp: unset;
|
||
overflow-y: auto;
|
||
}
|
||
|
||
.preview-fold-btn {
|
||
display: block;
|
||
width: 100%;
|
||
text-align: center;
|
||
padding: 0.25rem;
|
||
color: #58a6ff;
|
||
background-color: rgba(88, 166, 255, 0.05);
|
||
border-radius: 0.25rem;
|
||
cursor: pointer;
|
||
font-size: 0.75rem;
|
||
margin-top: 0.5rem;
|
||
transition: background-color 0.2s ease;
|
||
}
|
||
|
||
.preview-fold-btn:hover {
|
||
background-color: rgba(88, 166, 255, 0.1);
|
||
}
|
||
|
||
.document-preview .markdown-content {
|
||
font-size: 0.875rem;
|
||
}
|
||
|
||
.document-preview .markdown-content h1 {
|
||
font-size: 1.2rem;
|
||
margin-top: 0.5rem;
|
||
margin-bottom: 0.5rem;
|
||
}
|
||
|
||
.document-preview .markdown-content h2 {
|
||
font-size: 1.1rem;
|
||
margin-top: 0.5rem;
|
||
margin-bottom: 0.5rem;
|
||
}
|
||
|
||
.document-preview .markdown-content h3,
|
||
.document-preview .markdown-content h4,
|
||
.document-preview .markdown-content h5,
|
||
.document-preview .markdown-content h6 {
|
||
font-size: 1rem;
|
||
margin-top: 0.5rem;
|
||
margin-bottom: 0.5rem;
|
||
}
|
||
|
||
.document-preview .markdown-content p {
|
||
margin-bottom: 0.5rem;
|
||
}
|
||
|
||
.document-preview .markdown-content ul,
|
||
.document-preview .markdown-content ol {
|
||
padding-left: 1.5rem;
|
||
margin-bottom: 0.5rem;
|
||
}
|
||
|
||
.document-preview .markdown-content pre {
|
||
background-color: #1e1e2e;
|
||
padding: 0.5rem;
|
||
border-radius: 0.25rem;
|
||
overflow-x: auto;
|
||
margin-bottom: 0.5rem;
|
||
}
|
||
|
||
.document-preview .markdown-content blockquote {
|
||
border-left: 3px solid #30363d;
|
||
padding-left: 0.5rem;
|
||
color: #8b949e;
|
||
margin-bottom: 0.5rem;
|
||
}
|
||
|
||
.document-preview .markdown-content img {
|
||
max-width: 100%;
|
||
height: auto;
|
||
}
|
||
|
||
.document-preview .markdown-content table {
|
||
width: 100%;
|
||
border-collapse: collapse;
|
||
margin-bottom: 0.5rem;
|
||
}
|
||
|
||
.document-preview .markdown-content th,
|
||
.document-preview .markdown-content td {
|
||
border: 1px solid #30363d;
|
||
padding: 0.25rem 0.5rem;
|
||
}
|
||
|
||
.document-tag {
|
||
background-color: rgba(80, 250, 123, 0.1);
|
||
color: #50fa7b;
|
||
padding: 2px 8px;
|
||
border-radius: 12px;
|
||
font-size: 0.75rem;
|
||
transition: all 0.2s ease;
|
||
}
|
||
|
||
.document-tag:hover {
|
||
background-color: rgba(80, 250, 123, 0.2);
|
||
}
|
||
|
||
.view-toggle {
|
||
display: flex;
|
||
background-color: #2d333b;
|
||
border-radius: 0.375rem;
|
||
padding: 0.25rem;
|
||
}
|
||
|
||
.view-toggle-btn {
|
||
padding: 0.375rem 0.75rem;
|
||
border-radius: 0.25rem;
|
||
font-size: 0.875rem;
|
||
display: flex;
|
||
align-items: center;
|
||
cursor: pointer;
|
||
transition: all 0.2s ease;
|
||
}
|
||
|
||
.view-toggle-btn i {
|
||
margin-right: 0.25rem;
|
||
}
|
||
|
||
.view-toggle-btn.active {
|
||
background-color: rgba(80, 250, 123, 0.2);
|
||
color: #50fa7b;
|
||
}
|
||
|
||
.document-actions {
|
||
display: flex;
|
||
gap: 0.25rem;
|
||
}
|
||
|
||
.action-btn {
|
||
padding: 0.25rem;
|
||
border-radius: 0.25rem;
|
||
color: #8b949e;
|
||
transition: all 0.2s ease;
|
||
}
|
||
|
||
.action-btn:hover {
|
||
background-color: rgba(255, 255, 255, 0.1);
|
||
}
|
||
|
||
.action-btn.delete:hover {
|
||
color: #f85149;
|
||
background-color: rgba(248, 81, 73, 0.1);
|
||
}
|
||
|
||
.confirm-delete-modal {
|
||
position: fixed;
|
||
top: 0;
|
||
left: 0;
|
||
right: 0;
|
||
bottom: 0;
|
||
background-color: rgba(0, 0, 0, 0.5);
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
z-index: 50;
|
||
}
|
||
|
||
.confirm-delete-content {
|
||
background-color: #2d333b;
|
||
border-radius: 0.5rem;
|
||
width: 90%;
|
||
max-width: 28rem;
|
||
padding: 1.5rem;
|
||
box-shadow: 0 10px 25px rgba(0, 0, 0, 0.5);
|
||
}
|
||
</style>
|
||
{% endblock %}
|
||
|
||
{% block content %}
|
||
<div class="documents-container">
|
||
<div class="flex items-center justify-between mb-6">
|
||
<h2 class="text-xl font-semibold text-white">All Documents ({{ documents|length }})</h2>
|
||
|
||
<div class="flex items-center gap-4">
|
||
<!-- Search input -->
|
||
<div class="relative">
|
||
<input type="text" id="document-search" placeholder="Search in documents..." class="px-3 py-2 bg-gray-700 border border-gray-600 rounded-md text-white focus:outline-none focus:ring-2 focus:ring-primary focus:border-primary pr-10">
|
||
<i class="mdi mdi-magnify absolute right-3 top-1/2 transform -translate-y-1/2 text-gray-400"></i>
|
||
</div>
|
||
|
||
<!-- View toggle -->
|
||
<div class="view-toggle">
|
||
<button id="grid-view-btn" class="view-toggle-btn active-view">
|
||
<i class="mdi mdi-view-grid"></i> Grid
|
||
</button>
|
||
<button id="list-view-btn" class="view-toggle-btn">
|
||
<i class="mdi mdi-view-list"></i> List
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
{% if documents %}
|
||
<!-- Grid view (default) -->
|
||
<div id="grid-view" class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
|
||
{% for doc in documents %}
|
||
<div class="document-card bg-gray-800 rounded-lg overflow-hidden shadow" data-title="{{ doc.title|lower }}" data-content="{{ doc.content|lower }}">
|
||
<div class="p-5">
|
||
<div class="flex items-start justify-between mb-2">
|
||
<h3 class="text-white font-medium truncate w-5/6">
|
||
<a href="{{ url_for('main.view_document', doc_id=doc.id) }}" class="hover:text-primary transition-colors">
|
||
{{ doc.title }}
|
||
</a>
|
||
</h3>
|
||
<div class="dropdown relative">
|
||
<button class="p-1 text-gray-400 hover:text-white rounded">
|
||
<i class="mdi mdi-dots-vertical"></i>
|
||
</button>
|
||
<div class="dropdown-menu hidden absolute right-0 mt-2 w-48 bg-gray-700 rounded shadow-lg z-10">
|
||
<a href="{{ url_for('main.view_document', doc_id=doc.id) }}" class="block px-4 py-2 text-gray-300 hover:bg-gray-600 hover:text-white">
|
||
<i class="mdi mdi-eye-outline mr-2"></i> View
|
||
</a>
|
||
<a href="{{ url_for('main.edit_document', doc_id=doc.id) }}" class="block px-4 py-2 text-gray-300 hover:bg-gray-600 hover:text-white">
|
||
<i class="mdi mdi-pencil-outline mr-2"></i> Edit
|
||
</a>
|
||
<a href="{{ url_for('main.export_document', doc_id=doc.id) }}" class="block px-4 py-2 text-gray-300 hover:bg-gray-600 hover:text-white">
|
||
<i class="mdi mdi-download-outline mr-2"></i> Export
|
||
</a>
|
||
<button class="delete-document-btn block w-full text-left px-4 py-2 text-red-400 hover:bg-gray-600 hover:text-red-300" data-doc-id="{{ doc.id }}" data-doc-title="{{ doc.title }}">
|
||
<i class="mdi mdi-delete-outline mr-2"></i> Delete
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
{% if doc.category %}
|
||
<div class="document-category mb-2">
|
||
<i class="mdi {{ doc.category.icon }}"></i>
|
||
<a href="{{ url_for('main.view_category', category_id=doc.category.id) }}" class="hover:text-primary">
|
||
{{ doc.category.name }}
|
||
</a>
|
||
</div>
|
||
{% endif %}
|
||
|
||
<div class="document-preview text-gray-400 text-sm mb-3">
|
||
<div class="markdown-content" data-content="{{ doc.content }}">
|
||
<!-- Markdown will be rendered here -->
|
||
</div>
|
||
</div>
|
||
|
||
<button class="preview-fold-btn" data-doc-id="{{ doc.id }}">Show more</button>
|
||
|
||
<div class="flex items-center justify-between mt-3 text-xs text-gray-500">
|
||
<div>
|
||
<i class="mdi mdi-clock-outline mr-1"></i>
|
||
{{ doc.updated_date.strftime('%b %d, %Y') }}
|
||
</div>
|
||
</div>
|
||
|
||
{% if doc.tags %}
|
||
<div class="flex flex-wrap gap-1 mt-3">
|
||
{% for tag in doc.tags %}
|
||
<span class="document-tag">{{ tag.name }}</span>
|
||
{% endfor %}
|
||
</div>
|
||
{% endif %}
|
||
</div>
|
||
</div>
|
||
{% endfor %}
|
||
</div>
|
||
|
||
<!-- List view (initially hidden) -->
|
||
<div id="list-view" class="hidden bg-gray-800 rounded-lg shadow overflow-hidden">
|
||
<div class="divide-y divide-gray-700">
|
||
{% for doc in documents %}
|
||
<div class="document-item p-4 hover:bg-gray-700 transition-colors" data-title="{{ doc.title|lower }}" data-content="{{ doc.content|lower }}">
|
||
<div class="flex flex-col sm:flex-row items-start sm:items-center justify-between">
|
||
<div class="flex-1 min-w-0 mr-4">
|
||
<div class="flex items-center mb-1">
|
||
<h3 class="text-white font-medium truncate">
|
||
<a href="{{ url_for('main.view_document', doc_id=doc.id) }}" class="hover:text-primary transition-colors">
|
||
{{ doc.title }}
|
||
</a>
|
||
</h3>
|
||
</div>
|
||
|
||
<div class="flex items-center text-xs text-gray-500 mb-2">
|
||
{% if doc.category %}
|
||
<span class="document-category mr-3">
|
||
<i class="mdi {{ doc.category.icon }}"></i>
|
||
<a href="{{ url_for('main.view_category', category_id=doc.category.id) }}" class="hover:text-primary">
|
||
{{ doc.category.name }}
|
||
</a>
|
||
</span>
|
||
{% endif %}
|
||
|
||
<span class="mr-3">
|
||
<i class="mdi mdi-clock-outline mr-1"></i>
|
||
{{ doc.updated_date.strftime('%b %d, %Y') }}
|
||
</span>
|
||
|
||
{% if doc.tags %}
|
||
<div class="flex flex-wrap gap-1">
|
||
{% for tag in doc.tags %}
|
||
<span class="document-tag">{{ tag.name }}</span>
|
||
{% endfor %}
|
||
</div>
|
||
{% endif %}
|
||
</div>
|
||
|
||
<div class="document-preview text-gray-400 text-sm">
|
||
<div class="markdown-content" data-content="{{ doc.content }}">
|
||
<!-- Markdown will be rendered here -->
|
||
</div>
|
||
</div>
|
||
|
||
<button class="preview-fold-btn" data-doc-id="{{ doc.id }}-list">Show more</button>
|
||
</div>
|
||
|
||
<div class="flex items-center mt-2 sm:mt-0">
|
||
<div class="document-actions">
|
||
<a href="{{ url_for('main.view_document', doc_id=doc.id) }}" class="action-btn" title="View">
|
||
<i class="mdi mdi-eye-outline"></i>
|
||
</a>
|
||
<a href="{{ url_for('main.edit_document', doc_id=doc.id) }}" class="action-btn" title="Edit">
|
||
<i class="mdi mdi-pencil-outline"></i>
|
||
</a>
|
||
<a href="{{ url_for('main.export_document', doc_id=doc.id) }}" class="action-btn" title="Export">
|
||
<i class="mdi mdi-download-outline"></i>
|
||
</a>
|
||
<button class="action-btn delete delete-document-btn" title="Delete" data-doc-id="{{ doc.id }}" data-doc-title="{{ doc.title }}">
|
||
<i class="mdi mdi-delete-outline"></i>
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
{% endfor %}
|
||
</div>
|
||
</div>
|
||
|
||
{% else %}
|
||
<div class="bg-gray-800/50 rounded-lg p-8 text-center">
|
||
<i class="mdi mdi-file-document-outline text-6xl text-gray-700 mb-3"></i>
|
||
<h3 class="text-lg text-gray-400 mb-3">No documents found</h3>
|
||
<p class="text-gray-500 mb-4">This category and its subcategories don't have any documents yet</p>
|
||
<a href="{{ url_for('main.new_document') }}?category={{ category.id }}" class="inline-flex items-center px-4 py-2 bg-primary text-black rounded-md hover:bg-primary-dark transition-colors">
|
||
<i class="mdi mdi-plus mr-2"></i> Create Document
|
||
</a>
|
||
</div>
|
||
{% endif %}
|
||
|
||
<!-- No results message (hidden by default) -->
|
||
<div id="no-results" class="hidden bg-gray-800/50 rounded-lg p-8 text-center mt-4">
|
||
<i class="mdi mdi-file-search-outline text-6xl text-gray-700 mb-3"></i>
|
||
<h3 class="text-lg text-gray-400 mb-3">No matching documents</h3>
|
||
<p class="text-gray-500">Try a different search term</p>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Delete confirmation modal -->
|
||
<div id="delete-document-modal" class="confirm-delete-modal hidden">
|
||
<div class="confirm-delete-content">
|
||
<h3 class="text-lg font-medium text-white mb-4">Delete Document</h3>
|
||
<p class="text-gray-300 mb-6">Are you sure you want to delete "<span id="document-delete-name"></span>"? This action cannot be undone.</p>
|
||
<div class="flex justify-end space-x-3">
|
||
<button id="cancel-delete-doc" class="px-4 py-2 bg-gray-700 text-white rounded-md hover:bg-gray-600 transition-colors">
|
||
Cancel
|
||
</button>
|
||
<button id="confirm-delete-doc" class="px-4 py-2 bg-red-600 text-white rounded-md hover:bg-red-500 transition-colors">
|
||
Delete
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
{% endblock %}
|
||
|
||
{% block extra_js %}
|
||
<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
|
||
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.7.0/highlight.min.js"></script>
|
||
<script>
|
||
document.addEventListener('DOMContentLoaded', function() {
|
||
// Set up Marked.js for markdown rendering
|
||
marked.setOptions({
|
||
gfm: true,
|
||
breaks: true,
|
||
sanitize: false,
|
||
highlight: function(code, lang) {
|
||
if (lang && hljs.getLanguage(lang)) {
|
||
return hljs.highlight(code, { language: lang }).value;
|
||
}
|
||
return hljs.highlightAuto(code).value;
|
||
}
|
||
});
|
||
|
||
// Custom renderer for alert blocks
|
||
const renderer = new marked.Renderer();
|
||
|
||
// Fix blockquote renderer for GitHub-style alerts
|
||
const originalBlockquote = renderer.blockquote;
|
||
renderer.blockquote = function(quote) {
|
||
const text = quote.replace(/<\/?p>/g, '');
|
||
const admonitionRegex = /^\s*\[!(NOTE|TIP|IMPORTANT|WARNING|CAUTION|DANGER)\]\s*([\s\S]*)/i;
|
||
const match = text.match(admonitionRegex);
|
||
|
||
if (match) {
|
||
const type = match[1].toLowerCase();
|
||
const title = match[1].charAt(0).toUpperCase() + match[1].slice(1).toLowerCase();
|
||
const content = match[2] ? match[2].trim() : '';
|
||
|
||
return `<div class="admonition admonition-${type}">
|
||
<p class="admonition-title">${title}</p>
|
||
<p>${content}</p>
|
||
</div>`;
|
||
}
|
||
|
||
return originalBlockquote.call(this, quote);
|
||
};
|
||
|
||
marked.use({ renderer });
|
||
|
||
// Render markdown content in document previews
|
||
document.querySelectorAll('.markdown-content').forEach(container => {
|
||
const content = container.getAttribute('data-content');
|
||
if (content) {
|
||
// Limit the content length for initial display
|
||
const previewLength = 300;
|
||
const shortenedContent = content.length > previewLength
|
||
? content.substring(0, previewLength) + "..."
|
||
: content;
|
||
|
||
container.innerHTML = marked.parse(shortenedContent);
|
||
}
|
||
});
|
||
|
||
// Handle preview fold/unfold
|
||
const previewBtns = document.querySelectorAll('.preview-fold-btn');
|
||
previewBtns.forEach(btn => {
|
||
btn.addEventListener('click', function() {
|
||
const docId = this.getAttribute('data-doc-id');
|
||
const previewEl = this.previousElementSibling;
|
||
const markdownContainer = previewEl.querySelector('.markdown-content');
|
||
const content = markdownContainer.getAttribute('data-content');
|
||
|
||
if (previewEl.classList.contains('expanded')) {
|
||
if (previewEl.classList.contains('fully-expanded')) {
|
||
// Collapse to normal preview
|
||
previewEl.classList.remove('fully-expanded');
|
||
previewEl.classList.remove('expanded');
|
||
|
||
const previewLength = 300;
|
||
const shortenedContent = content.length > previewLength
|
||
? content.substring(0, previewLength) + "..."
|
||
: content;
|
||
|
||
markdownContainer.innerHTML = marked.parse(shortenedContent);
|
||
this.textContent = 'Show more';
|
||
} else {
|
||
// Expand to full view
|
||
previewEl.classList.add('fully-expanded');
|
||
markdownContainer.innerHTML = marked.parse(content);
|
||
this.textContent = 'Show less';
|
||
}
|
||
} else {
|
||
// Expand to first level
|
||
previewEl.classList.add('expanded');
|
||
|
||
const previewLength = 1000;
|
||
const shortenedContent = content.length > previewLength
|
||
? content.substring(0, previewLength) + "..."
|
||
: content;
|
||
|
||
markdownContainer.innerHTML = marked.parse(shortenedContent);
|
||
this.textContent = content.length > previewLength ? 'Show even more' : 'Show less';
|
||
}
|
||
|
||
// Apply syntax highlighting
|
||
previewEl.querySelectorAll('pre code').forEach(block => {
|
||
hljs.highlightElement(block);
|
||
});
|
||
});
|
||
});
|
||
|
||
// View toggle functionality
|
||
const gridViewBtn = document.getElementById('grid-view-btn');
|
||
const listViewBtn = document.getElementById('list-view-btn');
|
||
const gridView = document.getElementById('grid-view');
|
||
const listView = document.getElementById('list-view');
|
||
|
||
// Load view preference from localStorage
|
||
const viewPreference = localStorage.getItem('categoryDocumentsView') || 'grid';
|
||
|
||
// Set initial view based on preference
|
||
if (viewPreference === 'list') {
|
||
gridView.classList.add('hidden');
|
||
listView.classList.remove('hidden');
|
||
gridViewBtn.classList.remove('active');
|
||
listViewBtn.classList.add('active');
|
||
}
|
||
|
||
// Toggle views
|
||
gridViewBtn.addEventListener('click', function() {
|
||
gridView.classList.remove('hidden');
|
||
listView.classList.add('hidden');
|
||
gridViewBtn.classList.add('active');
|
||
listViewBtn.classList.remove('active');
|
||
localStorage.setItem('categoryDocumentsView', 'grid');
|
||
});
|
||
|
||
listViewBtn.addEventListener('click', function() {
|
||
listView.classList.remove('hidden');
|
||
gridView.classList.add('hidden');
|
||
listViewBtn.classList.add('active');
|
||
gridViewBtn.classList.remove('active');
|
||
localStorage.setItem('categoryDocumentsView', 'list');
|
||
});
|
||
|
||
// Search functionality
|
||
const searchInput = document.getElementById('document-search');
|
||
const documentItems = document.querySelectorAll('.document-card, .document-item');
|
||
const noResults = document.getElementById('no-results');
|
||
|
||
searchInput.addEventListener('input', function() {
|
||
const query = this.value.toLowerCase().trim();
|
||
let hasResults = false;
|
||
|
||
documentItems.forEach(item => {
|
||
const title = item.getAttribute('data-title');
|
||
const content = item.getAttribute('data-content');
|
||
|
||
if (title.includes(query) || content.includes(query)) {
|
||
item.style.display = '';
|
||
hasResults = true;
|
||
} else {
|
||
item.style.display = 'none';
|
||
}
|
||
});
|
||
|
||
// Show/hide no results message
|
||
if (hasResults) {
|
||
noResults.classList.add('hidden');
|
||
if (viewPreference === 'grid') {
|
||
gridView.classList.remove('hidden');
|
||
} else {
|
||
listView.classList.remove('hidden');
|
||
}
|
||
} else {
|
||
noResults.classList.remove('hidden');
|
||
gridView.classList.add('hidden');
|
||
listView.classList.add('hidden');
|
||
}
|
||
});
|
||
|
||
// Dropdown functionality
|
||
document.querySelectorAll('.dropdown button').forEach(btn => {
|
||
btn.addEventListener('click', function(e) {
|
||
e.stopPropagation();
|
||
const menu = this.nextElementSibling;
|
||
menu.classList.toggle('hidden');
|
||
|
||
// Close other open dropdowns
|
||
document.querySelectorAll('.dropdown-menu:not(.hidden)').forEach(m => {
|
||
if (m !== menu) m.classList.add('hidden');
|
||
});
|
||
});
|
||
});
|
||
|
||
// Close dropdowns when clicking outside
|
||
document.addEventListener('click', function() {
|
||
document.querySelectorAll('.dropdown-menu:not(.hidden)').forEach(menu => {
|
||
menu.classList.add('hidden');
|
||
});
|
||
});
|
||
|
||
// Delete document functionality
|
||
const deleteModal = document.getElementById('delete-document-modal');
|
||
const documentNameSpan = document.getElementById('document-delete-name');
|
||
const cancelDeleteBtn = document.getElementById('cancel-delete-doc');
|
||
const confirmDeleteBtn = document.getElementById('confirm-delete-doc');
|
||
let currentDocId = null;
|
||
|
||
// Show delete confirmation modal
|
||
document.querySelectorAll('.delete-document-btn').forEach(btn => {
|
||
btn.addEventListener('click', function(e) {
|
||
e.preventDefault();
|
||
e.stopPropagation();
|
||
|
||
const docId = this.getAttribute('data-doc-id');
|
||
const docTitle = this.getAttribute('data-doc-title');
|
||
|
||
documentNameSpan.textContent = docTitle;
|
||
currentDocId = docId;
|
||
deleteModal.classList.remove('hidden');
|
||
});
|
||
});
|
||
|
||
// Cancel document deletion
|
||
cancelDeleteBtn.addEventListener('click', function() {
|
||
deleteModal.classList.add('hidden');
|
||
currentDocId = null;
|
||
});
|
||
|
||
// Confirm document deletion
|
||
confirmDeleteBtn.addEventListener('click', function() {
|
||
if (currentDocId) {
|
||
// Send delete request to server
|
||
fetch(`/api/document/${currentDocId}`, {
|
||
method: 'DELETE',
|
||
headers: {
|
||
'Content-Type': 'application/json',
|
||
'X-CSRFToken': document.querySelector('meta[name="csrf-token"]')?.getAttribute('content') || ''
|
||
}
|
||
})
|
||
.then(response => {
|
||
if (!response.ok) {
|
||
throw new Error('Failed to delete document');
|
||
}
|
||
return response.json();
|
||
})
|
||
.then(data => {
|
||
// Remove the document from the DOM
|
||
document.querySelectorAll(`[data-doc-id="${currentDocId}"]`).forEach(el => {
|
||
const card = el.closest('.document-card, .document-item');
|
||
if (card) {
|
||
card.remove();
|
||
}
|
||
});
|
||
|
||
// Close the modal
|
||
deleteModal.classList.add('hidden');
|
||
|
||
// Show a success message
|
||
showNotification('Document deleted successfully');
|
||
|
||
// Update count in the heading
|
||
const countEl = document.querySelector('h2');
|
||
if (countEl) {
|
||
const count = document.querySelectorAll('.document-card').length;
|
||
countEl.textContent = `All Documents (${count})`;
|
||
}
|
||
|
||
// Show "no results" if there are no documents left
|
||
if (document.querySelectorAll('.document-card').length === 0) {
|
||
noResults.classList.remove('hidden');
|
||
gridView.classList.add('hidden');
|
||
listView.classList.add('hidden');
|
||
}
|
||
})
|
||
.catch(error => {
|
||
console.error('Error:', error);
|
||
showNotification('Error deleting document', 'error');
|
||
});
|
||
}
|
||
});
|
||
|
||
// Helper function to show notifications
|
||
function showNotification(message, type = 'success') {
|
||
const notification = document.createElement('div');
|
||
const bgColor = type === 'success' ? 'bg-green-600' : 'bg-red-600';
|
||
|
||
notification.className = `fixed bottom-4 right-4 ${bgColor} text-white px-4 py-2 rounded-md shadow-lg transform translate-y-0 opacity-100 transition-all duration-300`;
|
||
notification.textContent = message;
|
||
|
||
document.body.appendChild(notification);
|
||
|
||
setTimeout(() => {
|
||
notification.classList.add('translate-y-16', 'opacity-0');
|
||
setTimeout(() => notification.remove(), 300);
|
||
}, 3000);
|
||
}
|
||
|
||
// Highlight current category in sidebar
|
||
const sidebarCategories = document.querySelectorAll('.category-item');
|
||
sidebarCategories.forEach(item => {
|
||
if (item.dataset.categoryId === "{{ category.id }}") {
|
||
const categoryLink = item.querySelector('a');
|
||
if (categoryLink) {
|
||
categoryLink.classList.add('text-primary');
|
||
}
|
||
|
||
// Expand parent category if necessary
|
||
const parentContainer = item.closest('.category-children');
|
||
if (parentContainer && parentContainer.style.display === 'none') {
|
||
const toggleBtn = parentContainer.parentElement.querySelector('.toggle-btn');
|
||
if (toggleBtn) {
|
||
toggleBtn.click();
|
||
}
|
||
}
|
||
}
|
||
});
|
||
});
|
||
</script>
|
||
{% endblock %} |