flask-vim-docs/app/templates/category_documents.html
2025-04-17 11:27:48 +02:00

379 lines
No EOL
16 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

{% 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 %}