379 lines
No EOL
16 KiB
HTML
379 lines
No EOL
16 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;
|
||
}
|
||
|
||
.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;
|
||
}
|
||
</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">
|
||
<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>
|
||
</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">
|
||
{{ doc.content[:200] }}{% if doc.content|length > 200 %}...{% endif %}
|
||
</div>
|
||
|
||
<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">
|
||
{{ doc.content[:200] }}{% if doc.content|length > 200 %}...{% endif %}
|
||
</div>
|
||
</div>
|
||
|
||
<div class="flex items-center mt-2 sm:mt-0">
|
||
<a href="{{ url_for('main.view_document', doc_id=doc.id) }}" class="p-2 text-gray-400 hover:text-primary rounded" title="View">
|
||
<i class="mdi mdi-eye-outline"></i>
|
||
</a>
|
||
<a href="{{ url_for('main.edit_document', doc_id=doc.id) }}" class="p-2 text-gray-400 hover:text-primary rounded" title="Edit">
|
||
<i class="mdi mdi-pencil-outline"></i>
|
||
</a>
|
||
<a href="{{ url_for('main.export_document', doc_id=doc.id) }}" class="p-2 text-gray-400 hover:text-primary rounded" title="Export">
|
||
<i class="mdi mdi-download-outline"></i>
|
||
</a>
|
||
</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>
|
||
{% endblock %}
|
||
|
||
{% block extra_js %}
|
||
<script>
|
||
document.addEventListener('DOMContentLoaded', function() {
|
||
// 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');
|
||
});
|
||
});
|
||
|
||
// 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 %} |