new list page addded"

This commit is contained in:
Faheed 2025-10-09 19:51:53 +03:00
parent d8a7442b9d
commit ff42e35855
16 changed files with 839 additions and 891 deletions

Binary file not shown.

View File

@ -242,6 +242,14 @@ class JobPosting(Base):
self.save()
class JobPostingImage(models.Model):
job=models.ForeignKey('JobPosting',on_delete=models.CASCADE,related_name='post_images')
post_image = models.ImageField(upload_to='post/',
height_field='photo_height',
width_field='photo_width')
post_image_height = models.PositiveIntegerField(null=True, blank=True)
post_image_width = models.PositiveIntegerField(null=True, blank=True)
class Candidate(Base):
class Stage(models.TextChoices):
APPLIED = "Applied", _("Applied")

View File

@ -2,12 +2,12 @@
{% load static i18n crispy_forms_tags %}
{% load partials %}
{% block title %}Form Templates - ATS{% endblock %}
{% block title %}Form Templates - {{ block.super }}{% endblock %}
{% block customCSS %}
<style>
/* ================================================= */
/* UI Variables (Matching Job List) */
/* UI Variables (Matching Standard Theme) */
/* ================================================= */
:root {
--kaauh-teal: #00636e;
@ -20,23 +20,22 @@
/* --- Typography and Color Overrides --- */
.text-primary { color: var(--kaauh-teal) !important; }
/* --- Button Base Styles (Matching Job List) --- */
/* --- Button Base Styles (Consistent) --- */
.btn-main-action {
background-color: var(--kaauh-teal);
border-color: var(--kaauh-teal);
color: white;
font-weight: 600;
padding: 0.375rem 0.75rem;
border-radius: 0.5rem;
transition: all 0.2s ease;
display: inline-flex;
align-items: center;
gap: 0.5rem;
gap: 0.4rem;
padding: 0.5rem 1rem;
}
.btn-main-action:hover {
background-color: var(--kaauh-teal-dark);
border-color: var(--kaauh-teal-dark);
transform: translateY(-1px);
transform: none; /* Removed translate to match other lists */
box-shadow: 0 4px 8px rgba(0,0,0,0.15);
color: white;
}
@ -51,18 +50,17 @@
color: white;
border-color: var(--kaauh-teal-dark);
}
/* Size Utilities (matching Bootstrap convention) */
.btn-lg {
padding: 0.75rem 1.5rem;
font-size: 1.1rem;
/* Primary Outline for View/Preview */
.btn-outline-primary {
color: var(--kaauh-teal);
border-color: var(--kaauh-teal);
}
.btn-sm {
font-size: 0.8rem;
padding: 0.3rem 0.6rem;
.btn-outline-primary:hover {
background-color: var(--kaauh-teal);
color: white;
}
/* --- Card and Layout Styles (Matching Job List) --- */
/* --- Card and Layout Styles (Consistent) --- */
.card {
border: 1px solid var(--kaauh-border);
border-radius: 0.75rem;
@ -70,42 +68,24 @@
background-color: white;
transition: transform 0.2s, box-shadow 0.2s;
}
/* Template Card Hover Effect (Consistent with job list card hover) */
.template-card {
height: 100%;
}
.template-card:hover {
.card:not(.no-hover):hover {
transform: translateY(-2px);
box-shadow: 0 6px 16px rgba(0,0,0,0.1) !important;
}
/* Card Header Theming */
.card.no-hover:hover {
transform: none;
box-shadow: 0 4px 12px rgba(0,0,0,0.06);
}
/* Card Header (For Search/Filter Card) */
.card-header {
/* FIX: Use !important to override default white/light backgrounds from Bootstrap */
background-color: var(--kaauh-teal-dark) !important;
border-bottom: 1px solid var(--kaauh-border);
color: white !important; /* Base color for header text */
font-weight: 600;
padding: 1rem 1.25rem;
border-radius: 0.75rem 0.75rem 0 0;
}
/* Ensure all elements within the header are visible */
.card-header h3 {
color: white !important;
font-weight: 700;
}
.card-header .fas {
color: white !important;
}
.card-header .small {
color: rgba(255, 255, 255, 0.7) !important;
padding: 1.25rem;
border-bottom: 1px solid var(--kaauh-border);
background-color: var(--kaauh-gray-light);
}
/* Stats Theming */
/* --- Content Styles (Stats, Description) --- */
.stat-value {
font-size: 1.5rem;
font-weight: 800;
@ -116,58 +96,28 @@
color: var(--kaauh-primary-text);
font-weight: 500;
}
.card-description {
min-height: 60px;
color: var(--kaauh-primary-text);
}
/* Search Input Theming */
.form-control {
border-radius: 0.5rem 0 0 0.5rem;
/* Table Styling (Consistent) */
.table-view .table thead th {
background-color: var(--kaauh-teal-dark);
color: white;
font-weight: 600;
border-color: var(--kaauh-border);
border-radius: 0 0.5rem 0.5rem 0;
text-transform: uppercase;
font-size: 0.8rem;
letter-spacing: 0.5px;
padding: 1rem;
}
.form-control-search:focus {
border-color: var(--kaauh-teal);
box-shadow: 0 0 0 0.1rem rgba(0, 99, 110, 0.25);
}
.input-group-search .input-group-text {
background-color: white;
border-right: none;
.table-view .table tbody td {
vertical-align: middle;
padding: 1rem;
border-color: var(--kaauh-border);
border-radius: 0.5rem 0 0 0.5rem;
}
.input-group-search .form-control {
border-left: none;
}
/* --- Danger Outline (Delete) --- */
.btn-outline-danger {
--bs-btn-color: #dc3545;
--bs-btn-border-color: #dc3545;
--bs-btn-hover-bg: #dc3545;
--bs-btn-hover-color: white;
}
/* Empty State Theming */
.empty-state {
text-align: center;
padding: 3rem 1rem;
color: var(--kaauh-primary-text);
border: 2px dashed var(--kaauh-border);
border-radius: 0.75rem;
.table-view .table tbody tr:hover {
background-color: var(--kaauh-gray-light);
}
.empty-state i {
font-size: 3.5rem;
margin-bottom: 1rem;
color: var(--kaauh-teal-dark);
}
.empty-state .btn-main-action .fas {
color: white !important;
}
/* --- Pagination Styling (Matching Job List) --- */
/* Pagination Styling (Consistent) */
.pagination .page-item .page-link {
color: var(--kaauh-teal-dark);
border-color: var(--kaauh-border);
@ -180,30 +130,40 @@
.pagination .page-item:hover .page-link:not(.active) {
background-color: #e9ecef;
}
</style>
/* Empty State Icon Color */
.empty-state i, .text-center i.fa-3x {
color: var(--kaauh-teal-dark) !important;
}
/* Filter Buttons Container */
.filter-buttons {
display: flex;
gap: 0.5rem;
}
</style>
{% endblock %}
{% block content %}
<div class="container py-4">
<div class="d-flex justify-content-between align-items-center mb-4 pb-2 border-bottom border-primary">
<h1 class="h3 mb-0 fw-bold" style="color: var(--kaauh-teal-dark); font-weight: 700;">
<div class="container-fluid py-4">
<div class="d-flex justify-content-between align-items-center mb-4">
<h1 class="h3 mb-0" style="color: var(--kaauh-teal-dark); font-weight: 700;">
<i class="fas fa-file-alt me-2"></i>{% trans "Form Templates" %}
</h1>
<button type="button" class="btn btn-main-action" data-bs-toggle="modal" data-bs-target="#createTemplateModal">
<i class="fas fa-plus me-1"></i> Create New Template
<i class="fas fa-plus me-1"></i> {% trans "Create New Template" %}
</button>
</div>
{# Search/Filter Area - Matching Job List Structure #}
{# Search/Filter Area - Matching Standard Structure #}
<div class="card mb-4 shadow-sm no-hover">
<div class="card-body">
<h5 class="card-title text-muted mb-3" style="font-weight: 500;">Search Templates</h5>
<form method="get" class="row g-3 align-items-end">
<div class="col-md-6">
<label for="search" class="form-label small text-muted">Search by Template Name</label>
<div class="input-group input-group-lg input-group-search">
<label for="searchInput" class="form-label small text-muted">{% trans "Search by Template Name" %}</label>
<div class="input-group input-group-lg">
<span class="input-group-text"><i class="fas fa-search text-muted"></i></span>
<input type="text" name="q" id="searchInput" class="form-control form-control-search"
placeholder="{% trans 'Search templates by name...' %}"
@ -214,13 +174,13 @@
<div class="col-md-6">
<div class="filter-buttons">
<button type="submit" class="btn btn-main-action btn-lg">
<i class="fas fa-filter me-1"></i> Search
<i class="fas fa-filter me-1"></i> {% trans "Search" %}
</button>
{# Show Clear button if search is active #}
{% if query %}
<a href="{% url 'form_templates_list' %}" class="btn btn-outline-danger btn-sm">
<i class="fas fa-times me-1"></i> Clear Search
<a href="{% url 'form_templates_list' %}" class="btn btn-outline-secondary btn-lg">
<i class="fas fa-times me-1"></i> {% trans "Clear Search" %}
</a>
{% endif %}
</div>
@ -239,59 +199,62 @@
<div class="card-view active row g-4">
{% for template in templates %}
<div class="col-lg-4 col-md-6">
<div class="card template-card h-100">
<div class="card-header ">
<h3 class="h5 mb-2">{{ template.name }}</h3>
<span><i class="fas fa-sync-alt me-1"></i> {{ template.job }}</span>
<div class="d-flex justify-content-between text-muted small">
<span><i class="fas fa-calendar me-1"></i> {{ template.created_at|date:"M d, Y" }}</span>
<span><i class="fas fa-sync-alt me-1"></i> {{ template.updated_at|timesince }} {% trans "ago" %}</span>
</div>
</div>
<div class="card template-card h-100 shadow-sm">
<div class="card-body d-flex flex-column">
{# Content area - includes stats and description #}
<div class="flex-grow-1">
<div class="row text-center mb-3">
<div class="col-6">
<div class="stat-value">{{ template.get_stage_count }}</div>
<div class="stat-label">{% trans "Stages" %}</div>
</div>
<div class="col-6">
<div class="stat-value">{{ template.get_field_count }}</div>
<div class="stat-label">{% trans "Fields" %}</div>
</div>
<h5 class="card-title fw-bold" style="color: var(--kaauh-teal-dark);">{{ template.name }}</h5>
<span class="text-muted small mb-3">
<i class="fas fa-briefcase me-1"></i> {{ template.job|default:"N/A" }}
</span>
{# Stats #}
<div class="row text-center mb-3">
<div class="col-6 border-end">
<div class="stat-value">{{ template.get_stage_count }}</div>
<div class="stat-label">{% trans "Stages" %}</div>
</div>
<div class="col-6">
<div class="stat-value">{{ template.get_field_count }}</div>
<div class="stat-label">{% trans "Fields" %}</div>
</div>
<p class="card-text card-description small">
{% if template.description %}
{{ template.description|truncatewords:20 }}
{% else %}
<em class="text-muted">{% trans "No description provided" %}</em>
{% endif %}
</p>
</div>
{# Description #}
<p class="card-text small text-muted flex-grow-1">
{% if template.description %}
{{ template.description|truncatewords:20 }}
{% else %}
<em class="text-muted">{% trans "No description provided" %}</em>
{% endif %}
</p>
{# Action area - visually separated with pt-2 border-top #}
{# Action area #}
<div class="mt-auto pt-2 border-top">
<div class="d-grid gap-2 d-md-flex justify-content-md-end">
<div class="d-flex gap-2 justify-content-end">
<a href="{% url 'form_wizard' template.id %}" class="btn btn-outline-secondary btn-sm action-btn">
<i class="fas fa-eye me-1"></i> {% trans "Preview" %}
<a href="{% url 'form_wizard' template.id %}" class="btn btn-outline-primary btn-sm" title="{% trans 'Preview' %}">
<i class="fas fa-eye"></i>
</a>
<a href="{% url 'form_builder' template.id %}" class="btn btn-outline-secondary btn-sm action-btn">
<i class="fas fa-edit me-1"></i> {% trans "Edit" %}
<a href="{% url 'form_builder' template.id %}" class="btn btn-outline-secondary btn-sm" title="{% trans 'Edit' %}">
<i class="fas fa-edit"></i>
</a>
<a href="{% url 'form_template_submissions_list' template.slug %}" class="btn btn-outline-secondary btn-sm action-btn">
<i class="fas fa-file-alt me-1"></i> {% trans "Submissions" %}
<a href="{% url 'form_template_submissions_list' template.slug %}" class="btn btn-outline-secondary btn-sm" title="{% trans 'Submissions' %}">
<i class="fas fa-file-alt"></i>
</a>
<button class="btn btn-outline-danger btn-sm action-btn delete"
data-template-id="{{ template.id }}"
data-template-name="{{ template.name }}">
<i class="fas fa-trash me-1"></i> {% trans "Delete" %}
<button type="button" class="btn btn-outline-danger btn-sm" title="{% trans 'Delete' %}"
data-bs-toggle="modal" data-bs-target="#deleteModal"
data-delete-url="#"
data-item-name="{{ template.name }}">
<i class="fas fa-trash-alt"></i>
</button>
</div>
</div>
</div>
<div class="card-footer bg-light text-muted small">
<div class="d-flex justify-content-between">
<span><i class="fas fa-calendar-alt me-1"></i> {% trans "Created:" %} {{ template.created_at|date:"M d, Y" }}</span>
<span><i class="fas fa-sync-alt me-1"></i> {{ template.updated_at|timesince }} {% trans "ago" %}</span>
</div>
</div>
</div>
</div>
{% endfor %}
@ -300,23 +263,23 @@
{# Table View #}
<div class="table-view">
<div class="table-responsive">
<table class="table table-hover">
<table class="table table-hover align-middle mb-0">
<thead>
<tr>
<th scope="col">{% trans "Template Name" %}</th>
<th scope="col">{% trans "Job" %}</th>
<th scope="col">{% trans "Stages" %}</th>
<th scope="col">{% trans "Fields" %}</th>
<th scope="col">{% trans "Created" %}</th>
<th scope="col">{% trans "Last Updated" %}</th>
<th scope="col" class="text-end">{% trans "Actions" %}</th>
<th scope="col" style="width: 30%;">{% trans "Template Name" %}</th>
<th scope="col" style="width: 15%;">{% trans "Job" %}</th>
<th scope="col" style="width: 8%;">{% trans "Stages" %}</th>
<th scope="col" style="width: 8%;">{% trans "Fields" %}</th>
<th scope="col" style="width: 15%;">{% trans "Created" %}</th>
<th scope="col" style="width: 15%;">{% trans "Last Updated" %}</th>
<th scope="col" style="width: 9%;" class="text-end">{% trans "Actions" %}</th>
</tr>
</thead>
<tbody>
{% for template in templates %}
<tr>
<td class="fw-medium">{{ template.name }}</td>
<td>{{ template.job }}</td>
<td class="fw-medium text-primary">{{ template.name }}</td>
<td>{{ template.job|default:"N/A" }}</td>
<td>{{ template.get_stage_count }}</td>
<td>{{ template.get_field_count }}</td>
<td>{{ template.created_at|date:"M d, Y" }}</td>
@ -329,11 +292,14 @@
<a href="{% url 'form_builder' template.id %}" class="btn btn-outline-secondary" title="{% trans 'Edit' %}">
<i class="fas fa-edit"></i>
</a>
<a href="{% url 'form_template_submissions_list' template.slug %}" class="btn btn-outline-info" title="{% trans 'Submissions' %}">
<a href="{% url 'form_template_submissions_list' template.slug %}" class="btn btn-outline-secondary" title="{% trans 'Submissions' %}">
<i class="fas fa-file-alt"></i>
</a>
<button class="btn btn-outline-danger delete-btn" data-bs-toggle="modal" data-bs-target="#deleteModal" data-template-id="{{ template.id }}" data-template-name="{{ template.name }}" title="{% trans 'Delete' %}">
<i class="fas fa-trash"></i>
<button type="button" class="btn btn-outline-danger" title="{% trans 'Delete' %}"
data-bs-toggle="modal" data-bs-target="#deleteModal"
data-delete-url="#"
data-item-name="{{ template.name }}">
<i class="fas fa-trash-alt"></i>
</button>
</div>
</td>
@ -345,10 +311,10 @@
</div>
</div>
{# Pagination (Standardized) #}
{% if templates.has_other_pages %}
<nav aria-label="Page navigation" class="mt-4">
<ul class="pagination justify-content-center">
{# Previous page logic #}
{% if templates.has_previous %}
<li class="page-item">
<a class="page-link" href="?page=1{% if query %}&q={{ query }}{% endif %}">First</a>
@ -358,12 +324,10 @@
</li>
{% endif %}
{# Current Page #}
<li class="page-item active">
<span class="page-link">{{ templates.number }} of {{ templates.paginator.num_pages }}</span>
</li>
{# Next page logic #}
{% if templates.has_next %}
<li class="page-item">
<a class="page-link" href="?page={{ templates.next_page_number }}{% if query %}&q={{ query }}{% endif %}">Next</a>
@ -387,9 +351,9 @@
{% trans "You haven't created any form templates yet." %}
{% endif %}
</p>
<a href="{% url 'form_builder' %}" class="btn btn-main-action mt-3">
<i class="fas fa-plus me-1 text-white"></i> {% trans "Create Your First Template" %}
</a>
<button type="button" class="btn btn-main-action mt-3" data-bs-toggle="modal" data-bs-target="#createTemplateModal">
<i class="fas fa-plus me-1"></i> {% trans "Create Your First Template" %}
</button>
</div>
</div>
{% endif %}
@ -398,13 +362,12 @@
{% include 'includes/delete_modal.html' %}
<!-- Create Template Modal -->
<div class="modal fade" id="createTemplateModal" tabindex="-1" aria-labelledby="createTemplateModalLabel" aria-hidden="true">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<div class="modal-header bg-light">
<h5 class="modal-title" id="createTemplateModalLabel">
<i class="fas fa-file-alt me-2"></i>Create New Form Template
<i class="fas fa-file-alt me-2"></i>{% trans "Create New Form Template" %}
</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
@ -416,12 +379,12 @@
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
<button type="submit" form="createTemplateForm" class="btn btn-primary">
<i class="fas fa-save me-1"></i>Create Template
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">{% trans "Cancel" %}</button>
<button type="submit" form="createTemplateForm" class="btn btn-main-action">
<i class="fas fa-save me-1"></i>{% trans "Create Template" %}
</button>
</div>
</div>
</div>
</div>
{% endblock %}
{% endblock %}

View File

@ -10,6 +10,8 @@
</div>
<style>
/* --- View Switcher Styles (Consolidated & Corrected) --- */
/* View Toggle Styles */
.view-toggle {
border-radius: 0.25rem;
@ -28,13 +30,17 @@
/* Hide elements by default */
.table-view,
.card-view {
display: none;
display: none !important; /* Use !important to ensure hiding works */
}
/* Show active view */
.table-view.active,
.table-view.active {
display: block !important;
}
.card-view.active {
display: block;
/* Rely on the 'row' class which uses display: flex for proper column alignment. */
display: flex !important; /* rows often use display: flex in Bootstrap */
flex-wrap: wrap !important;
}
/* Card View Styles */
@ -105,16 +111,19 @@
.table-view .table tbody tr {
transition: background-color 0.2s;
}
/* NOTE: We need to assume var(--kaauh-gray-light) is defined in base.html or job_list.html */
.table-view .table tbody tr:hover {
background-color: var(--kaauh-gray-light);
background-color: #f0f0f0; /* Fallback color for hover */
}
</style>
<script>
document.addEventListener('DOMContentLoaded', function() {
// Get the list ID from the data attribute
const listId = document.querySelector('.view-toggle').getAttribute('data-list-id');
const listContainer = document.getElementById(listId);
const listContainer = document.getElementById('{{ list_id }}');
if (!listContainer) return; // Exit if container isn't found
// Get list ID from the data attribute (or use the variable from Django context if the button is loaded)
const listId = listContainer.id;
// Get saved view preference from localStorage
const savedView = localStorage.getItem(`list_view_${listId}`) || 'table';
@ -124,15 +133,18 @@ document.addEventListener('DOMContentLoaded', function() {
// Add click event listeners to view toggle buttons
document.querySelectorAll('.view-toggle').forEach(button => {
button.addEventListener('click', function() {
const view = this.getAttribute('data-view');
setView(view);
});
// Ensure the button belongs to this list (optional check)
if (button.getAttribute('data-list-id') === listId) {
button.addEventListener('click', function() {
const view = this.getAttribute('data-view');
setView(view);
});
}
});
function setView(view) {
// Update button states
document.querySelectorAll('.view-toggle').forEach(button => {
document.querySelectorAll('.view-toggle[data-list-id="{{ list_id }}"]').forEach(button => {
if (button.getAttribute('data-view') === view) {
button.classList.add('active');
} else {
@ -144,16 +156,17 @@ document.addEventListener('DOMContentLoaded', function() {
const tableView = listContainer.querySelector('.table-view');
const cardView = listContainer.querySelector('.card-view');
// Apply active class to the correct container
if (view === 'table') {
tableView.classList.add('active');
cardView.classList.remove('active');
if (tableView) tableView.classList.add('active');
if (cardView) cardView.classList.remove('active');
} else {
tableView.classList.remove('active');
cardView.classList.add('active');
if (tableView) tableView.classList.remove('active');
if (cardView) cardView.classList.add('active');
}
// Save preference to localStorage
localStorage.setItem(`list_view_${listId}`, view);
}
});
</script>
</script>

View File

@ -261,7 +261,20 @@
</div>
<div class="d-flex align-items-center gap-2">
<span class="badge bg-success status-badge">
<span class="badge status-badge">
{% if job.status == "ACTIVE" %}
<span class="badge bg-success status-badge">
{% elif job.status == "DRAFT" %}
<span class="badge bg-secondary status-badge">
{% elif job.status == "CLOSED" %}
<span class="badge bg-warning status-badge">
{% elif job.status == "CANCELLED" %}
<span class="badge bg-danger status-badge">
{% elif job.status == "ARCHIVED" %}
<span class="badge bg-secondary status-badge">
{% else %}
<span class="badge bg-secondary status-badge">
{% endif %}
{{ job.get_status_display }}
<button type="button" class="btn btn-outline-light btn-sm ms-2" data-bs-toggle="modal" data-bs-target="#editStatusModal">
<i class="fas fa-edit text-primary"></i>
@ -550,7 +563,7 @@
</div>
</div>
</div>
<!--image modal class-->
{% include "jobs/partials/image_upload.html" %}
<!-- JOB STATUS MODAL-->

View File

@ -171,7 +171,7 @@
{# Card View (Default) #}
<div class="card-view active row">
{% for job in page_obj %}
<div class="col-md-6 col-lg-4 mb-4">
<div class="col-md-6 col-lg-4 mb-4 ">
<div class="card job-card h-100">
<div class="card-body d-flex flex-column">
<div class="d-flex justify-content-between align-items-start mb-2">

View File

@ -2,11 +2,11 @@
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="myModalLabel">Add New Comment</h5>
<h5 class="modal-title" id="myModalLabel">Add New Image</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<form method="post" action="{% url 'job_create' %}">
<form method="post" action="{% url 'job_detail' job.slug %}">
{% csrf_token %}
{{ image_form }}
<div class="modal-footer">

View File

@ -2,199 +2,120 @@
{% load static i18n %}
{% block title %}{% trans "Zoom Meetings" %} - {{ block.super }}{% endblock %}
{% block customCSS %}
<style>
/* UI Variables for the KAAT-S Theme */
/* UI Variables for the KAAT-S Theme (Consistent with Reference) */
:root {
--kaauh-teal: #00636e;
--kaauh-teal-dark: #004a53;
--kaauh-border: #eaeff3;
--kaauh-primary-text: #343a40;
--kaauh-gray: #6c757d;
/* Status Colors based on KAAT-S example */
--kaauh-success: var(--kaauh-teal);
--kaauh-warning: #ffc107;
--kaauh-danger: #dc3545;
--kaauh-secondary: #6c757d;
--kaauh-gray-light: #f8f9fa;
}
/* Base style for all buttons to inherit Bootstrap's basic structure/reset */
.btn-base {
display: inline-block;
text-align: center;
vertical-align: middle;
cursor: pointer;
user-select: none;
padding: 0.375rem 0.75rem; /* Standard default padding */
font-size: 1rem;
line-height: 1.5;
border-radius: 0.25rem;
border: 1px solid transparent;
transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
/* FIX: Remove link underline for anchor tags used as buttons */
text-decoration: none;
/* Enhanced Card Styling (Consistent) */
.card {
border: 1px solid var(--kaauh-border);
border-radius: 0.75rem;
box-shadow: 0 4px 12px rgba(0,0,0,0.06);
transition: transform 0.2s, box-shadow 0.2s;
background-color: white;
}
.card:not(.no-hover):hover {
transform: translateY(-2px);
box-shadow: 0 6px 16px rgba(0,0,0,0.1);
}
.card.no-hover:hover {
transform: none;
box-shadow: 0 4px 12px rgba(0,0,0,0.06);
}
/* Small Button Size */
.btn-sm {
padding: 0.3rem 0.6rem;
font-size: 0.8rem;
font-weight: 600;
line-height: 1.5;
}
/* Main Action Button (Create Meeting) */
/* Main Action Button Style (Teal Theme) */
.btn-main-action {
background-color: var(--kaauh-teal);
border-color: var(--kaauh-teal);
color: white;
font-weight: 600;
transition: all 0.2s ease;
display: inline-flex;
align-items: center;
gap: 0.4rem;
padding: 0.5rem 1rem;
}
.btn-main-action:hover {
background-color: var(--kaauh-teal-dark);
border-color: var(--kaauh-teal-dark);
box-shadow: 0 4px 8px rgba(0,0,0,0.15);
text-decoration: none; /* Ensure no hover underline if base fails */
}
/* Outline Primary (View/Join buttons) */
.btn-kaats-outline-primary {
/* Secondary Button Style (For Edit/Outline - Consistent) */
.btn-outline-secondary {
color: var(--kaauh-teal-dark);
border-color: var(--kaauh-teal);
}
.btn-outline-secondary:hover {
background-color: var(--kaauh-teal-dark);
color: white;
border-color: var(--kaauh-teal-dark);
}
/* Primary Outline for View/Join */
.btn-outline-primary {
color: var(--kaauh-teal);
border-color: var(--kaauh-teal);
background-color: transparent;
}
.btn-kaats-outline-primary:hover {
.btn-outline-primary:hover {
background-color: var(--kaauh-teal);
color: white;
text-decoration: none;
}
/* Outline Secondary (Update button) */
.btn-kaats-outline-secondary {
color: var(--kaauh-secondary);
border-color: var(--kaauh-secondary);
background-color: transparent;
}
.btn-kaats-outline-secondary:hover {
background-color: var(--kaauh-secondary);
color: white;
border-color: var(--kaauh-secondary);
text-decoration: none;
}
/* Outline Danger (Delete button) */
.btn-kaats-outline-danger {
color: var(--kaauh-danger);
border-color: var(--kaauh-danger);
background-color: transparent;
}
.btn-kaats-outline-danger:hover {
background-color: var(--kaauh-danger);
color: white;
border-color: var(--kaauh-danger);
text-decoration: none;
}
/* --- General UI Styles (Unchanged) --- */
/* CARD GRID STYLES */
.meetings-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
gap: 1.5rem;
padding: 1rem;
}
.meeting-card {
background: white;
border-radius: 0.75rem;
box-shadow: 0 4px 12px rgba(0,0,0,0.06);
padding: 1.5rem;
border: 1px solid var(--kaauh-border);
transition: transform 0.2s ease, box-shadow 0.2s ease;
height: 100%;
}
.meeting-card:hover {
transform: translateY(-2px);
box-shadow: 0 6px 16px rgba(0,0,0,0.1);
}
/* TOPIC AND DETAILS STYLES */
.meeting-topic {
font-size: 1.15rem;
font-weight: 600;
/* Meeting Card Specifics (Adapted to Standard Card View) */
.meeting-card .card-title {
color: var(--kaauh-teal-dark);
margin-bottom: 1rem;
border-bottom: 1px solid var(--kaauh-border);
padding-bottom: 0.5rem;
}
.meeting-detail {
display: flex;
margin-bottom: 0.75rem;
align-items: flex-start;
}
.detail-label {
font-weight: 600;
min-width: 80px;
color: var(--kaauh-gray);
font-size: 0.9rem;
flex-shrink: 0;
font-size: 1.15rem;
}
.detail-value {
flex: 1;
font-size: 0.9rem;
word-break: break-word;
color: var(--kaauh-primary-text);
.meeting-card .card-text i {
color: var(--kaauh-teal);
width: 1.25rem;
}
/* STATUS BADGE STYLES */
/* Status Badges (Standardized) */
.status-badge {
display: inline-block;
font-size: 0.75rem;
font-weight: 700;
font-size: 0.8rem;
padding: 0.4em 0.8em;
border-radius: 0.4rem;
text-align: center;
color: white;
}
.bg-warning {
background: var(--kaauh-warning) !important;
color: var(--kaauh-primary-text) !important;
}
.bg-success {
background: var(--kaauh-success) !important;
color: white !important;
}
.bg-danger {
background: var(--kaauh-danger) !important;
color: white !important;
}
/* ACTION AREA STYLES */
.actions {
margin-top: 1rem;
display: flex;
gap: 0.5rem;
flex-wrap: wrap;
}
/* Header Styling */
.card-header h1 {
color: var(--kaauh-teal-dark);
font-weight: 700;
text-transform: uppercase;
letter-spacing: 0.7px;
}
.card {
border: 1px solid var(--kaauh-border);
border-radius: 0.75rem;
box-shadow: 0 4px 12px rgba(0,0,0,0.06);
}
/* Status Badge Mapping */
.bg-waiting { background-color: #ffc107 !important; color: var(--kaauh-primary-text) !important;}
.bg-started { background-color: var(--kaauh-teal) !important; color: white !important;}
.bg-ended { background-color: #dc3545 !important; color: white !important;}
/* Empty State Icon Color */
.text-muted.mb-3 {
color: var(--kaauh-teal-dark) !important;
/* Table Styling (Consistent with Reference) */
.table-view .table thead th {
background-color: var(--kaauh-teal-dark);
color: white;
font-weight: 600;
border-color: var(--kaauh-border);
text-transform: uppercase;
font-size: 0.8rem;
letter-spacing: 0.5px;
padding: 1rem;
}
/* Pagination Link Styling */
.table-view .table tbody td {
vertical-align: middle;
padding: 1rem;
border-color: var(--kaauh-border);
}
.table-view .table tbody tr:hover {
background-color: var(--kaauh-gray-light);
}
/* Pagination Link Styling (Consistent) */
.pagination .page-item .page-link {
color: var(--kaauh-teal-dark);
border-color: var(--kaauh-border);
@ -208,120 +129,123 @@
background-color: #e9ecef;
}
/* RESPONSIVE STYLES */
@media (max-width: 768px) {
.meetings-grid {
grid-template-columns: 1fr;
}
.meeting-detail {
flex-direction: column;
gap: 0.25rem;
}
.detail-label {
min-width: auto;
}
/* Filter & Search Layout Adjustments */
.filter-buttons {
display: flex;
gap: 0.5rem;
}
/* Icon color for empty state */
.text-muted.fa-3x {
color: var(--kaauh-teal-dark) !important;
}
</style>
{% endblock %}
{% block content %}
<div class="card">
<div class="card-header">
<div class="d-flex justify-content-between align-items-center">
<h1 class="h3 mb-0">
{% include "icons/meeting.html" %}
{% trans "Zoom Meetings" %}
</h1>
<div class="d-flex gap-2 align-items-center">
{% include "includes/search_form.html" with search_query=search_query %}
<div class="container-fluid py-4">
<div class="d-flex justify-content-between align-items-center mb-4">
<h1 style="color: var(--kaauh-teal-dark); font-weight: 700;">
<i class="fas fa-video me-2"></i> {% trans "Zoom Meetings" %}
</h1>
<a href="{% url 'create_meeting' %}" class="btn btn-main-action">
<i class="fas fa-plus me-1"></i> {% trans "Create Meeting" %}
</a>
</div>
<a href="{% url 'create_meeting' %}" class="btn-base btn-main-action">
<svg class="heroicon" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M12 4v16m8-8H4" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></path>
</svg>
{% trans "Create Meeting" %}
</a>
<div class="card mb-4 shadow-sm no-hover">
<div class="card-body">
<div class="row">
<div class="col-md-4">
<label for="search" class="form-label small text-muted">{% trans "Search by Topic" %}</label>
<div class="input-group input-group-lg mb-3">
<form method="get" action="" class="w-100">
{% include "includes/search_form.html" with search_query=search_query %}
</form>
</div>
</div>
<div class="col-md-8">
<form method="GET" class="row g-3 align-items-end" >
{% if search_query %}<input type="hidden" name="q" value="{{ search_query }}">{% endif %}
<div class="col-md-3">
<label for="status" class="form-label small text-muted">{% trans "Filter by Status" %}</label>
<select name="status" id="status" class="form-select form-select-sm">
<option value="">{% trans "All Statuses" %}</option>
<option value="waiting" {% if status_filter == 'waiting' %}selected{% endif %}>{% trans "Waiting" %}</option>
<option value="started" {% if status_filter == 'started' %}selected{% endif %}>{% trans "Started" %}</option>
<option value="ended" {% if status_filter == 'ended' %}selected{% endif %}>{% trans "Ended" %}</option>
</select>
</div>
<div class="col-md-5">
<div class="filter-buttons">
<button type="submit" class="btn btn-main-action btn-lg">
<i class="fas fa-filter me-1"></i> {% trans "Apply Filters" %}
</button>
{% if status_filter or search_query %}
<a href="{% url 'meeting_list' %}" class="btn btn-outline-secondary btn-lg">
<i class="fas fa-times me-1"></i> {% trans "Clear" %}
</a>
{% endif %}
</div>
</div>
</form>
</div>
</div>
</div>
</div>
{% if meetings %}
<div id="meetings-list">
{# View Switcher #}
{% include "includes/_list_view_switcher.html" with list_id="meetings-list" %}
{# Card View (Default) #}
<div class="card-view active">
<div class="meetings-grid">
{% for meeting in meetings %}
<div class="meeting-card">
<div class="meeting-topic">{{ meeting.topic }}</div>
<div class="meeting-detail">
<div class="detail-label">{% trans "ID" %}:</div>
<div class="detail-value">{{ meeting.meeting_id|default:meeting.id }}</div>
</div>
<div class="meeting-detail">
<div class="detail-label">{% trans "Start Time" %}:</div>
<div class="detail-value">{{ meeting.start_time|date:"M d, Y H:i" }}</div>
</div>
<div class="meeting-detail">
<div class="detail-label">{% trans "Duration" %}:</div>
<div class="detail-value">{{ meeting.duration }} minutes</div>
</div>
<div class="meeting-detail">
<div class="detail-label">{% trans "Status" %}:</div>
<div class="detail-value">
<span class="status-badge {% if meeting.status == 'waiting' %}bg-warning{% elif meeting.status == 'started' %}bg-success{% elif meeting.status == 'ended' %}bg-danger{% endif %}">
{% if meeting.status == 'waiting' %}
{% trans "Waiting" %}
{% elif meeting.status == 'started' %}
{% trans "Started" %}
{% elif meeting.status == 'ended' %}
{% trans "Ended" %}
{% endif %}
{# Card View #}
<div class="card-view active row">
{% for meeting in meetings %}
<div class="col-md-6 col-lg-4 mb-4">
<div class="card meeting-card h-100 shadow-sm">
<div class="card-body d-flex flex-column">
<div class="d-flex justify-content-between align-items-start mb-2">
<h5 class="card-title flex-grow-1 me-3">{{ meeting.topic }}</h5>
<span class="status-badge bg-{{ meeting.status }}">
{{ meeting.status|title }}
</span>
</div>
</div>
{% if meeting.join_url %}
<div class="meeting-detail">
<div class="detail-label">{% trans "Join URL" %}:</div>
<div class="detail-value">
<a href="{{ meeting.join_url }}" target="_blank" class="btn-base btn-kaats-outline-primary btn-sm">
{% trans "Join Meeting" %}
<p class="card-text text-muted small mb-3">
<i class="fas fa-hashtag"></i> {% trans "ID" %}: {{ meeting.meeting_id|default:meeting.id }}<br>
<i class="fas fa-clock"></i> {% trans "Start" %}: {{ meeting.start_time|date:"M d, Y H:i" }}<br>
<i class="fas fa-stopwatch"></i> {% trans "Duration" %}: {{ meeting.duration }} minutes
</p>
<div class="mt-auto pt-2 border-top">
<div class="d-flex gap-2">
<a href="{% url 'meeting_details' meeting.pk %}" class="btn btn-sm btn-outline-primary">
<i class="fas fa-eye"></i> {% trans "View" %}
</a>
{% if meeting.join_url %}
<a href="{{ meeting.join_url }}" target="_blank" class="btn btn-sm btn-main-action">
<i class="fas fa-link"></i> {% trans "Join" %}
</a>
{% endif %}
<a href="{% url 'update_meeting' meeting.pk %}" class="btn btn-sm btn-outline-secondary">
<i class="fas fa-edit"></i>
</a>
<button type="button" class="btn btn-outline-danger btn-sm" title="{% trans 'Delete' %}"
data-bs-toggle="modal" data-bs-target="#deleteModal"
data-delete-url="{% url 'delete_meeting' meeting.pk %}"
data-item-name="{{ meeting.topic }}">
<i class="fas fa-trash-alt"></i>
</button>
</div>
</div>
{% endif %}
<div class="actions">
<a href="{% url 'meeting_details' meeting.pk %}" class="btn-base btn-kaats-outline-primary btn-sm" title="{% trans 'View' %}">
<svg class="heroicon" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></path>
<path d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0 8.268-2.943-9.542-7z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></path>
</svg>
</a>
<a href="{% url 'update_meeting' meeting.pk %}" class="btn-base btn-kaats-outline-secondary btn-sm" title="{% trans 'Update' %}">
<svg class="heroicon" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></path>
</svg>
</a>
<button type="button" class="btn-base btn-kaats-outline-danger btn-sm" title="{% trans 'Delete' %}"
data-bs-toggle="deleteModal"
data-delete-url="{% url 'delete_meeting' meeting.pk %}"
data-item-name="{{ meeting.topic }}">
<svg class="heroicon" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></path>
</svg>
</button>
</div>
</div>
{% endfor %}
</div>
</div>
{% endfor %}
</div>
{# Table View #}
@ -330,34 +254,33 @@
<table class="table table-hover">
<thead>
<tr>
<th scope="col">{% trans "Topic" %}</th>
<th scope="col">{% trans "ID" %}</th>
<th scope="col">{% trans "Start Time" %}</th>
<th scope="col">{% trans "Duration" %}</th>
<th scope="col">{% trans "Status" %}</th>
<th scope="col" class="text-end">{% trans "Actions" %}</th>
<th scope="col" style="width: 30%;">{% trans "Topic" %}</th>
<th scope="col" style="width: 15%;">{% trans "ID" %}</th>
<th scope="col" style="width: 20%;">{% trans "Start Time" %}</th>
<th scope="col" style="width: 10%;">{% trans "Duration" %}</th>
<th scope="col" style="width: 15%;">{% trans "Status" %}</th>
<th scope="col" style="width: 10%;" class="text-end">{% trans "Actions" %}</th>
</tr>
</thead>
<tbody>
{% for meeting in meetings %}
<tr>
<td><strong>{{ meeting.topic }}</strong></td>
<td><strong class="text-primary">{{ meeting.topic }}</strong></td>
<td>{{ meeting.meeting_id|default:meeting.id }}</td>
<td>{{ meeting.start_time|date:"M d, Y H:i" }}</td>
<td>{{ meeting.duration }} minutes</td>
<td>{{ meeting.duration }} min</td>
<td>
<span class="status-badge {% if meeting.status == 'waiting' %}bg-warning{% elif meeting.status == 'started' %}bg-success{% elif meeting.status == 'ended' %}bg-danger{% endif %}">
{% if meeting.status == 'waiting' %}
{% trans "Waiting" %}
{% elif meeting.status == 'started' %}
{% trans "Started" %}
{% elif meeting.status == 'ended' %}
{% trans "Ended" %}
{% endif %}
<span class="status-badge bg-{{ meeting.status }}">
{{ meeting.status|title }}
</span>
</td>
<td class="text-end">
<div class="btn-group btn-group-sm" role="group">
{% if meeting.join_url %}
<a href="{{ meeting.join_url }}" target="_blank" class="btn btn-main-action" title="{% trans 'Join' %}">
<i class="fas fa-sign-in-alt"></i>
</a>
{% endif %}
<a href="{% url 'meeting_details' meeting.pk %}" class="btn btn-outline-primary" title="{% trans 'View' %}">
<i class="fas fa-eye"></i>
</a>
@ -365,10 +288,10 @@
<i class="fas fa-edit"></i>
</a>
<button type="button" class="btn btn-outline-danger" title="{% trans 'Delete' %}"
data-bs-toggle="deleteModal"
data-bs-toggle="modal" data-bs-target="#deleteModal"
data-delete-url="{% url 'delete_meeting' meeting.pk %}"
data-item-name="{{ meeting.topic }}">
<i class="fas fa-trash"></i>
<i class="fas fa-trash-alt"></i>
</button>
</div>
</td>
@ -380,52 +303,45 @@
</div>
</div>
{# Pagination (Standardized) #}
{% if is_paginated %}
<nav aria-label="Page navigation" class="mt-4">
<ul class="pagination justify-content-center">
{% if page_obj.has_previous %}
<li class="page-item">
<a class="page-link" href="?page={{ page_obj.previous_page_number }}&search={{ search_query }}" aria-label="Previous">
<span aria-hidden="true">&laquo;</span>
</a>
<a class="page-link" href="?page=1{% if status_filter %}&status={{ status_filter }}{% endif %}{% if search_query %}&q={{ search_query }}{% endif %}">First</a>
</li>
<li class="page-item">
<a class="page-link" href="?page={{ page_obj.previous_page_number }}{% if status_filter %}&status={{ status_filter }}{% endif %}{% if search_query %}&q={{ search_query }}{% endif %}">Previous</a>
</li>
{% endif %}
{% for num in page_obj.paginator.page_range %}
{% if page_obj.number == num %}
<li class="page-item active"><span class="page-link">{{ num }}</span></li>
{% elif num > page_obj.number|add:'-3' and num < page_obj.number|add:'3' %}
<li class="page-item">
<a class="page-link" href="?page={{ num }}&search={{ search_query }}">{{ num }}</a>
</li>
{% endif %}
{% endfor %}
<li class="page-item active">
<span class="page-link">{{ page_obj.number }} of {{ page_obj.paginator.num_pages }}</span>
</li>
{% if page_obj.has_next %}
<li class="page-item">
<a class="page-link" href="?page={{ page_obj.next_page_number }}&search={{ search_query }}" aria-label="Next">
<span aria-hidden="true">&raquo;</span>
</a>
<a class="page-link" href="?page={{ page_obj.next_page_number }}{% if status_filter %}&status={{ status_filter }}{% endif %}{% if search_query %}&q={{ search_query }}{% endif %}">Next</a>
</li>
<li class="page-item">
<a class="page-link" href="?page={{ page_obj.paginator.num_pages }}{% if status_filter %}&status={{ status_filter }}{% endif %}{% if search_query %}&q={{ search_query }}{% endif %}">Last</a>
</li>
{% endif %}
</ul>
</nav>
{% endif %}
{% else %}
<div class="text-center py-5">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="text-muted mb-3" style="width: 80px;">
<path stroke-linecap="round" stroke-linejoin="round" d="M9.879 7.519c1.171-1.025 3.071-1.025 4.242 0 1.172 1.025 1.172 2.687 0 3.712-.203.179-.43.326-.67.442-.745.361-1.45.999-1.45 1.827v.75M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0Zm-9 5.25h.008v.008H12v-.008Z" />
</svg>
<p class="text-muted">{% trans "No meetings found." %}</p>
{% if user.is_staff %}
<a href="{% url 'create_meeting' %}" class="btn-base btn-main-action mt-3">
<svg class="heroicon" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M12 4v16m8-8H4" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></path>
</svg>
{% trans "Create Your First Meeting" %}
<div class="text-center py-5 card shadow-sm">
<div class="card-body">
<i class="fas fa-video fa-3x mb-3" style="color: var(--kaauh-teal-dark);"></i>
<h3>{% trans "No Zoom meetings found" %}</h3>
<p class="text-muted">{% trans "Create your first meeting or adjust your filters." %}</p>
<a href="{% url 'create_meeting' %}" class="btn btn-main-action mt-3">
<i class="fas fa-plus me-1"></i> {% trans "Create Your First Meeting" %}
</a>
{% endif %}
</div>
</div>
{% endif %}
</div>
{% endblock %}
{% endblock %}

View File

@ -115,8 +115,8 @@
color: var(--kaauh-teal);
}
.main-tabs .nav-link.active {
color: var(--kaauh-teal-dark);
background-color: white;
color: var(--kaauh-teal-dark) !important;
background-color: white !important;
border-bottom: 3px solid var(--kaauh-teal);
font-weight: 600;
}
@ -141,8 +141,8 @@
border-right: none;
}
.right-column-card .nav-link.active {
background-color: white;
color: var(--kaauh-teal-dark);
background-color: white !important;
color: var(--kaauh-teal-dark) !important;
border-bottom: 3px solid var(--kaauh-teal);
border-right-color: transparent;
margin-bottom: -1px;

View File

@ -5,15 +5,16 @@
{% block customCSS %}
<style>
/* UI Variables for the KAAT-S Theme */
/* UI Variables for the KAAT-S Theme (Consistent with Reference) */
:root {
--kaauh-teal: #00636e;
--kaauh-teal-dark: #004a53;
--kaauh-border: #eaeff3;
--kaauh-primary-text: #343a40;
--kaauh-gray-light: #f8f9fa; /* Added for hover/background consistency */
}
/* Enhanced Card Styling */
/* Enhanced Card Styling (Consistent) */
.card {
border: 1px solid var(--kaauh-border);
border-radius: 0.75rem;
@ -21,19 +22,15 @@
transition: transform 0.2s, box-shadow 0.2s;
background-color: white;
}
.card:hover {
/* Remove hover effect from the main list card to avoid visual noise */
.card:not(.no-hover):hover { /* Use no-hover class for main structure cards */
transform: translateY(-2px);
box-shadow: 0 6px 16px rgba(0,0,0,0.1);
}
.card.no-hover:hover {
transform: none;
box-shadow: 0 4px 12px rgba(0,0,0,0.06);
}
.card-header {
font-weight: 600;
padding: 1.25rem;
border-bottom: 1px solid var(--kaauh-border);
background-color: #f8f9fa; /* Light header background */
}
/* Main Action Button Style (Teal Theme) */
.btn-main-action {
background-color: var(--kaauh-teal);
@ -53,50 +50,63 @@
box-shadow: 0 4px 8px rgba(0,0,0,0.15);
}
/* Secondary Action Buttons (used in table) */
.btn-group .btn-outline-primary {
color: var(--kaauh-teal);
border-color: var(--kaauh-border);
background-color: white;
}
.btn-group .btn-outline-primary:hover {
background-color: var(--kaauh-teal);
color: white;
/* Secondary Button Style (For Edit/Outline - Consistent) */
.btn-outline-secondary {
color: var(--kaauh-teal-dark);
border-color: var(--kaauh-teal);
}
/* Table Styling */
.table thead th {
.btn-outline-secondary:hover {
background-color: var(--kaauh-teal-dark);
color: white;
border-color: var(--kaauh-teal-dark);
}
/* Card Specifics (Adapted from Job Card to Candidate Card) */
.candidate-card .card-title {
color: var(--kaauh-teal-dark);
font-weight: 600;
border-bottom: 2px solid var(--kaauh-teal); /* Highlight bottom border */
vertical-align: middle;
padding: 0.75rem 1rem;
font-size: 0.95rem;
font-size: 1.15rem;
}
.candidate-card .card-text i {
color: var(--kaauh-teal);
width: 1.25rem;
}
.table tbody tr:hover {
background-color: #f3f9f9; /* Light teal hover for rows */
}
.table tbody td {
vertical-align: middle;
padding: 0.75rem 1rem;
}
/* Badge Styling */
/* Table & Card Badge Styling (Unified) */
.badge {
font-weight: 600;
padding: 0.4em 0.7em;
border-radius: 0.3rem;
text-transform: uppercase;
letter-spacing: 0.5px;
}
/* Status Badge Mapping */
.table .bg-primary { background-color: var(--kaauh-teal) !important; color: white !important;} /* Job Title Badge */
.table .bg-success { background-color: #28a745 !important; } /* Applied: Yes */
.table .bg-warning { background-color: #ffc107 !important; } /* Applied: No */
/* Status Badge Mapping (Using standard Bootstrap names where possible) */
.bg-primary { background-color: var(--kaauh-teal) !important; color: white !important;} /* Main job/stage badge */
.bg-success { background-color: #28a745 !important; color: white !important;}
.bg-warning { background-color: #ffc107 !important; color: #343a40 !important;}
/* Pagination Link Styling */
/* Table Styling (Consistent with Reference) */
.table-view .table thead th {
background-color: var(--kaauh-teal-dark); /* Dark header background */
color: white;
font-weight: 600;
border-color: var(--kaauh-border);
text-transform: uppercase;
font-size: 0.8rem;
letter-spacing: 0.5px;
padding: 1rem;
}
.table-view .table tbody td {
vertical-align: middle;
padding: 1rem;
border-color: var(--kaauh-border);
}
.table-view .table tbody tr:hover {
background-color: var(--kaauh-gray-light);
}
/* Pagination Link Styling (Consistent) */
.pagination .page-item .page-link {
color: var(--kaauh-teal-dark);
border-color: var(--kaauh-border);
@ -109,189 +119,213 @@
.pagination .page-item:hover .page-link:not(.active) {
background-color: #e9ecef;
}
/* Icon Sizing in Buttons */
.btn-group .btn-sm svg {
width: 1rem;
height: 1rem;
/* Filter & Search Layout Adjustments */
.filter-buttons {
display: flex;
gap: 0.5rem;
}
</style>
{% endblock %}
{% block content %}
<div class="container-fluid py-4">
<div class="card shadow-sm">
<div class="card-header">
<div class="d-flex justify-content-between align-items-center">
<h1 class="h3 mb-0" style="color: var(--kaauh-teal-dark); font-weight: 700;">
<i class="fas fa-users me-2"></i>
{% trans "Candidate Profiles" %}
</h1>
<div class="d-flex gap-3 align-items-center">
{# The search form structure should be updated to align with the job_list style if possible #}
{% include "includes/search_form.html" with search_query=search_query %}
<div class="d-flex justify-content-between align-items-center mb-4">
<h1 style="color: var(--kaauh-teal-dark); font-weight: 700;">
<i class="fas fa-users me-2"></i> {% trans "Candidate Profiles" %}
</h1>
{% if user.is_staff %}
<a href="{% url 'candidate_create' %}" class="btn btn-main-action">
<i class="fas fa-plus me-1"></i> {% trans "Add New Candidate" %}
</a>
{% endif %}
</div>
{% if user.is_staff %}
<a href="{% url 'candidate_create' %}" class="btn btn-main-action">
<i class="fas fa-plus"></i>
{% trans "Add New Candidate" %}
</a>
{% endif %}
<div class="card mb-4 shadow-sm no-hover">
<div class="card-body">
<div class="row">
<div class="col-md-4">
<label for="search" class="form-label small text-muted">{% trans "Search by Name or Email" %}</label>
<div class="input-group input-group-lg mb-3">
<form method="get" action="" class="w-100">
{% include 'includes/search_form.html' %}
</form>
</div>
</div>
<div class="col-md-8">
{% url 'candidate_list' as candidate_list_url %}
<form method="GET" class="row g-3 align-items-end" >
{% if search_query %}<input type="hidden" name="q" value="{{ search_query }}">{% endif %}
<div class="col-md-3">
<label for="job_filter" class="form-label small text-muted">{% trans "Filter by Job" %}</label>
<select name="job" id="job_filter" class="form-select form-select-sm">
<option value="">{% trans "All Jobs" %}</option>
{% for job in available_jobs %} {# Assuming you pass a context variable 'available_jobs' #}
<option value="{{ job.slug }}" {% if job_filter == job.slug %}selected{% endif %}>{{ job.title }}</option>
{% endfor %}
</select>
</div>
<div class="col-md-5">
<div class="filter-buttons">
<button type="submit" class="btn btn-main-action btn-lg">
<i class="fas fa-filter me-1"></i> {% trans "Apply Filters" %}
</button>
{% if job_filter or search_query %}
<a href="{% url 'candidate_list' %}" class="btn btn-outline-secondary btn-lg">
<i class="fas fa-times me-1"></i> {% trans "Clear" %}
</a>
{% endif %}
</div>
</div>
</form>
</div>
</div>
</div>
</div>
{% if candidates %}
<div id="candidate-list">
{# View Switcher - list_id must match the container ID #}
{% include "includes/_list_view_switcher.html" with list_id="candidate-list" %}
{% if candidates %}
<div id="candidate-list">
{# View Switcher #}
{% include "includes/_list_view_switcher.html" with list_id="candidate-list" %}
{# Table View (Default) #}
<div class="table-view active">
<div class="table-responsive">
<table class="table table-hover mb-0">
<thead>
{# Table View (Default) #}
<div class="table-view active">
<div class="table-responsive">
<table class="table table-hover mb-0">
<thead>
<tr>
<th scope="col" style="width: 20%;">{% trans "Name" %}</th>
<th scope="col" style="width: 20%;">{% trans "Email" %}</th>
<th scope="col" style="width: 15%;">{% trans "Phone" %}</th>
<th scope="col" style="width: 15%;">{% trans "Job" %}</th>
<th scope="col" style="width: 10%;">{% trans "Stage" %}</th>
<th scope="col" style="width: 10%;">{% trans "Created" %}</th>
<th scope="col" style="width: 10%;" class="text-end">{% trans "Actions" %}</th>
</tr>
</thead>
<tbody>
{% for candidate in candidates %}
<tr>
<th scope="col" style="width: 20%;">{% trans "Name" %}</th>
<th scope="col" style="width: 20%;">{% trans "Email" %}</th>
<th scope="col" style="width: 15%;">{% trans "Phone" %}</th>
<th scope="col" style="width: 15%;">{% trans "Job" %}</th>
<th scope="col" style="width: 10%;">{% trans "Stage" %}</th>
<th scope="col" style="width: 10%;">{% trans "Created" %}</th>
<th scope="col" style="width: 10%;" class="text-center">{% trans "Actions" %}</th>
</tr>
</thead>
<tbody>
{% for candidate in candidates %}
<tr>
<td><strong>{{ candidate.name }}</strong></td>
<td>{{ candidate.email }}</td>
<td>{{ candidate.phone }}</td>
<td> <span class="badge bg-primary">{{ candidate.job.title }}</span></td>
<td>
<span class="badge bg-primary">
{{ candidate.stage }}
</span>
</td>
<td>{{ candidate.created_at|date:"M d, Y" }}</td>
<td class="text-center">
<div class="btn-group btn-group-sm" role="group">
<a href="{% url 'candidate_detail' candidate.slug %}" class="btn btn-outline-primary" title="{% trans 'View' %}">
<i class="fas fa-eye"></i>
</a>
{% if user.is_staff %}
<a href="{% url 'candidate_update' candidate.slug %}" class="btn btn-outline-primary" title="{% trans 'Edit' %}">
<i class="fas fa-edit"></i>
</a>
<button type="button" class="btn btn-outline-danger" title="{% trans 'Delete' %}"
data-bs-toggle="deleteModal"
data-delete-url="{% url 'candidate_delete' candidate.slug %}"
data-item-name="{{ candidate.name }}">
<i class="fas fa-trash-alt"></i>
</button>
{% endif %}
</div>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
{# Card View #}
<div class="card-view">
<div class="row g-4">
{% for candidate in candidates %}
<div class="col-md-6 col-lg-4">
<div class="card h-100">
<div class="card-header">
<h5 class="h5 mb-1">{{ candidate.name }}</h5>
<small class="text-white-50">{{ candidate.email }}</small>
</div>
<div class="card-body">
<p class="card-text">
<strong>{% trans "Phone" %}:</strong> {{ candidate.phone|default:"N/A" }}<br>
<strong>{% trans "Job" %}:</strong> <span class="badge bg-primary">{{ candidate.job.title }}</span><br>
<strong>{% trans "Stage" %}:</strong> <span class="badge bg-primary">{{ candidate.stage }}</span><br>
<strong>{% trans "Created" %}:</strong> {{ candidate.created_at|date:"M d, Y" }}
</p>
</div>
<div class="card-footer">
<div class="d-flex gap-2">
<a href="{% url 'candidate_detail' candidate.slug %}" class="btn btn-sm btn-outline-primary w-100">
<i class="fas fa-eye"></i> {% trans "View" %}
<td class="fw-medium">{{ candidate.name }}</td>
<td>{{ candidate.email }}</td>
<td>{{ candidate.phone }}</td>
<td> <span class="badge bg-primary">{{ candidate.job.title }}</span></td>
<td>
<span class="badge bg-primary">
{{ candidate.stage }}
</span>
</td>
<td>{{ candidate.created_at|date:"M d, Y" }}</td>
<td class="text-end">
<div class="btn-group btn-group-sm" role="group">
<a href="{% url 'candidate_detail' candidate.slug %}" class="btn btn-outline-primary" title="{% trans 'View' %}">
<i class="fas fa-eye"></i>
</a>
{% if user.is_staff %}
<div class="btn-group w-100" role="group">
<a href="{% url 'candidate_update' candidate.slug %}" class="btn btn-sm btn-outline-secondary" title="{% trans 'Edit' %}">
<i class="fas fa-edit"></i>
</a>
<button type="button" class="btn btn-outline-danger btn-sm" title="{% trans 'Delete' %}"
data-bs-toggle="deleteModal"
data-delete-url="{% url 'candidate_delete' candidate.slug %}"
data-item-name="{{ candidate.name }}">
<i class="fas fa-trash-alt"></i>
</button>
</div>
<a href="{% url 'candidate_update' candidate.slug %}" class="btn btn-outline-secondary" title="{% trans 'Edit' %}">
<i class="fas fa-edit"></i>
</a>
<button type="button" class="btn btn-outline-danger" title="{% trans 'Delete' %}"
data-bs-toggle="modal" data-bs-target="#deleteModal" {# Updated to standard Bootstrap usage #}
data-delete-url="{% url 'candidate_delete' candidate.slug %}"
data-item-name="{{ candidate.name }}">
<i class="fas fa-trash-alt"></i>
</button>
{% endif %}
</div>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
{# Card View #}
<div class="card-view row"> {# Added 'row' class for grid structure #}
{% for candidate in candidates %}
<div class="col-md-6 col-lg-4 mb-4"> {# Column wrapper for grid #}
<div class="card candidate-card h-100 shadow-sm">
<div class="card-body d-flex flex-column">
<div class="d-flex justify-content-between align-items-start mb-2">
<h5 class="card-title flex-grow-1 me-3">{{ candidate.name }}</h5>
<span class="badge bg-primary">{{ candidate.stage }}</span>
</div>
<p class="card-text text-muted small">
<i class="fas fa-envelope"></i> {{ candidate.email }}<br>
<i class="fas fa-phone-alt"></i> {{ candidate.phone|default:"N/A" }}<br>
<i class="fas fa-briefcase"></i> <span class="badge bg-primary">{{ candidate.job.title }}</span>
</p>
<div class="mt-auto pt-2 border-top">
<div class="d-flex gap-2">
<a href="{% url 'candidate_detail' candidate.slug %}" class="btn btn-sm btn-main-action">
<i class="fas fa-eye"></i> {% trans "View" %}
</a>
{% if user.is_staff %}
<a href="{% url 'candidate_update' candidate.slug %}" class="btn btn-sm btn-outline-secondary">
<i class="fas fa-edit"></i> {% trans "Edit" %}
</a>
<button type="button" class="btn btn-outline-danger btn-sm" title="{% trans 'Delete' %}"
data-bs-toggle="modal" data-bs-target="#deleteModal"
data-delete-url="{% url 'candidate_delete' candidate.slug %}"
data-item-name="{{ candidate.name }}">
<i class="fas fa-trash-alt"></i>
</button>
{% endif %}
</div>
</div>
</div>
{% endfor %}
</div>
</div>
</div>
{% endfor %}
</div>
</div>
{% if is_paginated %}
<div class="card-footer bg-white border-top">
<nav aria-label="Page navigation">
<ul class="pagination justify-content-center mb-0">
{% if page_obj.has_previous %}
<li class="page-item">
<a class="page-link" href="?page={{ page_obj.previous_page_number }}{% if search_query %}&q={{ search_query }}{% endif %}" aria-label="Previous">
<span aria-hidden="true">&laquo;</span>
</a>
</li>
{% endif %}
{# Pagination (Standardized to Reference) #}
{% if is_paginated %}
<nav aria-label="Page navigation" class="mt-4">
<ul class="pagination justify-content-center">
{% if page_obj.has_previous %}
<li class="page-item">
<a class="page-link" href="?page=1{% if search_query %}&q={{ search_query }}{% endif %}{% if job_filter %}&job={{ job_filter }}{% endif %}">First</a>
</li>
<li class="page-item">
<a class="page-link" href="?page={{ page_obj.previous_page_number }}{% if search_query %}&q={{ search_query }}{% endif %}{% if job_filter %}&job={{ job_filter }}{% endif %}">Previous</a>
</li>
{% endif %}
{# Simplified pagination logic for theme consistency #}
{% for num in page_obj.paginator.page_range %}
{% if page_obj.number == num %}
<li class="page-item active"><span class="page-link">{{ num }}</span></li>
{% elif num > page_obj.number|add:'-2' and num < page_obj.number|add:'2' %}
<li class="page-item">
<a class="page-link" href="?page={{ num }}{% if search_query %}&q={{ search_query }}{% endif %}">{{ num }}</a>
</li>
{% endif %}
{% endfor %}
<li class="page-item active">
<span class="page-link">{{ page_obj.number }} of {{ page_obj.paginator.num_pages }}</span>
</li>
{% if page_obj.has_next %}
<li class="page-item">
<a class="page-link" href="?page={{ page_obj.next_page_number }}{% if search_query %}&q={{ search_query }}{% endif %}" aria-label="Next">
<span aria-hidden="true">&raquo;</span>
</a>
</li>
{% endif %}
</ul>
</nav>
</div>
{% endif %}
{% else %}
<div class="text-center py-5">
{% if page_obj.has_next %}
<li class="page-item">
<a class="page-link" href="?page={{ page_obj.next_page_number }}{% if search_query %}&q={{ search_query }}{% endif %}{% if job_filter %}&job={{ job_filter }}{% endif %}">Next</a>
</li>
<li class="page-item">
<a class="page-link" href="?page={{ page_obj.paginator.num_pages }}{% if search_query %}&q={{ search_query }}{% endif %}{% if job_filter %}&job={{ job_filter }}{% endif %}">Last</a>
</li>
{% endif %}
</ul>
</nav>
{% endif %}
{% else %}
<div class="text-center py-5 card shadow-sm">
<div class="card-body">
<i class="fas fa-users fa-3x mb-3" style="color: var(--kaauh-teal-dark);"></i>
<h4 class="text-muted">{% trans "No candidates found." %}</h4>
<p class="text-muted">{% trans "Start by adding a new profile or adjusting your search filters." %}</p>
<h3>{% trans "No candidate profiles found" %}</h3>
<p class="text-muted">{% trans "Create your first candidate profile or adjust your filters." %}</p>
{% if user.is_staff %}
<a href="{% url 'candidate_create' %}" class="btn btn-main-action mt-3">
<i class="fas fa-plus me-1"></i>
{% trans "Add Your First Candidate" %}
<i class="fas fa-plus me-1"></i> {% trans "Add Candidate" %}
</a>
{% endif %}
</div>
{% endif %}
</div>
</div>
{% endif %}
</div>
{% endblock %}
{% endblock %}

View File

@ -5,48 +5,53 @@
{% block customCSS %}
<style>
/* ================================================= */
/* THEME VARIABLES AND GLOBAL STYLES (FROM JOB DETAIL) */
/* ================================================= */
/* UI Variables for the KAAT-S Theme (Consistent with Reference) */
:root {
--kaauh-teal: #00636e;
--kaauh-teal-dark: #004a53;
--kaauh-border: #eaeff3;
--kaauh-primary-text: #343a40;
--kaauh-gray-light: #f8f9fa; /* Added for hover/background consistency */
}
/* Primary Color Overrides */
.text-primary { color: var(--kaauh-teal) !important; }
/* Enhanced Card Styling (Consistent) */
.card {
border: 1px solid var(--kaauh-border);
border-radius: 0.75rem;
box-shadow: 0 4px 12px rgba(0,0,0,0.06);
transition: transform 0.2s, box-shadow 0.2s;
background-color: white;
}
/* Standard card hover effect for list items */
.card:not(.no-hover):hover {
transform: translateY(-2px);
box-shadow: 0 6px 16px rgba(0,0,0,0.1);
}
.card.no-hover:hover {
transform: none;
box-shadow: 0 4px 12px rgba(0,0,0,0.06);
}
/* Main Action Button Style (Applied to .btn-primary) */
.btn-main-action, .btn-primary {
/* Main Action Button Style (Teal Theme) */
.btn-main-action {
background-color: var(--kaauh-teal);
border-color: var(--kaauh-teal);
color: white;
font-weight: 600;
padding: 0.6rem 1.2rem;
transition: all 0.2s ease;
display: inline-flex;
align-items: center;
gap: 0.5rem;
text-decoration: none; /* Ensure links look like buttons */
gap: 0.4rem;
padding: 0.5rem 1rem;
}
.btn-main-action:hover, .btn-primary:hover {
.btn-main-action:hover {
background-color: var(--kaauh-teal-dark);
border-color: var(--kaauh-teal-dark);
transform: translateY(-1px);
box-shadow: 0 4px 8px rgba(0,0,0,0.15);
}
/* Outlined Button Styles for Table Actions */
.btn-outline-primary {
color: var(--kaauh-teal);
border-color: var(--kaauh-teal);
}
.btn-outline-primary:hover {
background-color: var(--kaauh-teal);
color: white;
}
/* Secondary Button Style (For Edit/Outline - Consistent) */
.btn-outline-secondary {
color: var(--kaauh-teal-dark);
border-color: var(--kaauh-teal);
@ -56,54 +61,44 @@
color: white;
border-color: var(--kaauh-teal-dark);
}
/* Danger button remains standard for deletion */
/* Card enhancements */
.card {
border: 1px solid var(--kaauh-border);
border-radius: 0.75rem;
overflow: hidden;
box-shadow: 0 4px 12px rgba(0,0,0,0.06);
background-color: white;
.btn-outline-primary {
color: var(--kaauh-teal);
border-color: var(--kaauh-teal);
}
/* Colored Header Card */
.list-header-card {
background: linear-gradient(135deg, var(--kaauh-teal), #004d57);
.btn-outline-primary:hover {
background-color: var(--kaauh-teal);
color: white;
border-radius: 0.75rem 0.75rem 0 0;
padding: 1.5rem;
box-shadow: 0 4px 10px rgba(0,0,0,0.15);
}
.list-header-card h1 {
font-weight: 700;
margin: 0;
font-size: 1.8rem;
}
.heroicon {
width: 1.25rem;
height: 1.25rem;
vertical-align: text-bottom;
stroke: currentColor;
margin-right: 0.5rem;
}
/* Table Styling */
.table thead th {
background-color: #f8f9fa;
color: var(--kaauh-primary-text);
/* Training Card Specifics */
.training-card .card-title {
color: var(--kaauh-teal-dark);
font-weight: 600;
border-bottom: 2px solid var(--kaauh-border);
}
.table tbody tr:hover {
background-color: #f0f8ff; /* Light hover color */
}
.btn-group .btn-sm {
padding: 0.35rem 0.6rem;
font-size: 1.15rem;
}
/* Pagination Styling */
.pagination .page-link {
/* Table Styling (Consistent with Reference) */
.table-view .table thead th {
background-color: var(--kaauh-teal-dark); /* Dark header background */
color: white;
font-weight: 600;
border-color: var(--kaauh-border);
text-transform: uppercase;
font-size: 0.8rem;
letter-spacing: 0.5px;
padding: 1rem;
}
.table-view .table tbody td {
vertical-align: middle;
padding: 1rem;
border-color: var(--kaauh-border);
}
.table-view .table tbody tr:hover {
background-color: var(--kaauh-gray-light);
}
/* Pagination Link Styling (Consistent) */
.pagination .page-item .page-link {
color: var(--kaauh-teal-dark);
border-color: var(--kaauh-border);
}
@ -112,173 +107,179 @@
border-color: var(--kaauh-teal);
color: white;
}
.pagination .page-item:hover .page-link:not(.active) {
background-color: #e9ecef;
}
/* Filter & Search Layout Adjustments */
.filter-buttons {
display: flex;
gap: 0.5rem;
}
/* Override for the primary text color being used for card-titles in table */
.text-primary { color: var(--kaauh-teal) !important; }
</style>
{% endblock %}
{% block content %}
<div class="container-fluid py-4">
<div class="card shadow-sm">
<div class="d-flex justify-content-between align-items-center mb-4">
<h1 style="color: var(--kaauh-teal-dark); font-weight: 700;">
<i class="fas fa-graduation-cap me-2"></i> {% trans "Training Materials" %}
</h1>
{% if user.is_authenticated %}
<a href="{% url 'training_create' %}" class="btn btn-main-action">
<i class="fas fa-plus me-1"></i> {% trans "Add New Material" %}
</a>
{% endif %}
</div>
<div class="list-header-card">
<div class="d-flex justify-content-between align-items-center flex-wrap">
<h1 class="h3 mb-0">
<i class="fas fa-graduation-cap me-2"></i>
{% trans "Training Materials" %}
</h1>
<div class="d-flex gap-3 align-items-center mt-2 mt-md-0">
<div class="order-3 order-md-1">
{% include "includes/search_form.html" with search_query=search_query %}
<div class="card mb-4 shadow-sm no-hover">
<div class="card-body">
<div class="row">
<div class="col-md-6">
<label for="search" class="form-label small text-muted">{% trans "Search by Title or Creator" %}</label>
<div class="input-group input-group-lg mb-3">
<form method="get" action="" class="w-100">
{% include "includes/search_form.html" with search_query=search_query %}
</form>
</div>
</div>
<div class="col-md-6 d-flex align-items-end">
{# Additional Filters can go here if needed #}
</div>
</div>
</div>
</div>
{% if materials %}
<div id="training-materials-list">
{# View Switcher - list_id must match the container ID #}
{% include "includes/_list_view_switcher.html" with list_id="training-materials-list" %}
{% if user.is_authenticated %}
<a href="{% url 'training_create' %}" class="btn btn-main-action btn-sm order-1 order-md-2" title="{% trans 'Add New Material' %}">
<i class="fas fa-plus"></i>
<span class="d-none d-sm-inline">{% trans "Add New Material" %}</span>
</a>
{% endif %}
{# Card View (Default) - Must have 'row' class for grid layout #}
<div class="card-view active row">
{% for material in materials %}
<div class="col-md-6 col-lg-4 mb-4">
<div class="card training-card h-100 shadow-sm">
<div class="card-body d-flex flex-column">
<div class="d-flex justify-content-between align-items-start mb-2">
<h5 class="card-title flex-grow-1 me-3">{{ material.title }}</h5>
</div>
<p class="card-text text-muted small">
<i class="fas fa-user-edit"></i> {% trans "Created By" %}: {{ material.created_by.username|default:"Anonymous" }}<br>
<i class="fas fa-calendar-alt"></i> {% trans "Created On" %}: {{ material.created_at|date:"M d, Y" }}
</p>
<div class="mt-auto pt-2 border-top">
<div class="d-flex gap-2">
<a href="{% url 'training_detail' material.pk %}" class="btn btn-sm btn-main-action">
<i class="fas fa-eye"></i> {% trans "View" %}
</a>
{% if user.is_authenticated and material.created_by == user %}
<a href="{% url 'training_update' material.pk %}" class="btn btn-sm btn-outline-secondary">
<i class="fas fa-edit"></i> {% trans "Edit" %}
</a>
<button type="button" class="btn btn-outline-danger btn-sm" title="{% trans 'Delete' %}"
data-bs-toggle="modal" data-bs-target="#deleteModal" {# Assuming standard Bootstrap modal trigger #}
data-delete-url="{% url 'training_delete' material.pk %}"
data-item-name="{{ material.title }}">
<i class="fas fa-trash-alt"></i>
</button>
{% endif %}
</div>
</div>
</div>
</div>
</div>
{% endfor %}
</div>
{# Table View #}
<div class="table-view">
<div class="table-responsive">
<table class="table table-hover align-middle mb-0">
<thead>
<tr>
<th scope="col" style="width: 40%;">{% trans "Title" %}</th>
<th scope="col" style="width: 30%;">{% trans "Created By" %}</th>
<th scope="col" style="width: 20%;">{% trans "Created" %}</th>
<th scope="col" style="width: 10%;" class="text-end">{% trans "Actions" %}</th>
</tr>
</thead>
<tbody>
{% for material in materials %}
<tr>
<td><strong class="text-primary">{{ material.title }}</strong></td>
<td>{{ material.created_by.username|default:"Anonymous" }}</td>
<td>{{ material.created_at|date:"M d, Y" }}</td>
<td class="text-end">
<div class="btn-group btn-group-sm" role="group">
<a href="{% url 'training_detail' material.pk %}" class="btn btn-outline-primary" title="{% trans 'View' %}">
<i class="fas fa-eye"></i>
</a>
{% if user.is_authenticated and material.created_by == user %}
<a href="{% url 'training_update' material.pk %}" class="btn btn-outline-secondary" title="{% trans 'Edit' %}">
<i class="fas fa-edit"></i>
</a>
<button type="button" class="btn btn-outline-danger" title="{% trans 'Delete' %}"
data-bs-toggle="modal" data-bs-target="#deleteModal"
data-delete-url="{% url 'training_delete' material.pk %}"
data-item-name="{{ material.title }}">
<i class="fas fa-trash-alt"></i>
</button>
{% endif %}
</div>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
{# Pagination (Standardized to Reference) #}
{% if is_paginated %}
<nav aria-label="Page navigation" class="mt-4">
<ul class="pagination justify-content-center">
{% if page_obj.has_previous %}
<li class="page-item">
<a class="page-link" href="?page=1{% if search_query %}&q={{ search_query }}{% endif %}">First</a>
</li>
<li class="page-item">
<a class="page-link" href="?page={{ page_obj.previous_page_number }}{% if search_query %}&q={{ search_query }}{% endif %}">Previous</a>
</li>
{% endif %}
{% if materials %}
<div id="training-materials-list">
{# View Switcher #}
{% include "includes/_list_view_switcher.html" with list_id="training-materials-list" %}
<li class="page-item active">
<span class="page-link">{{ page_obj.number }} of {{ page_obj.paginator.num_pages }}</span>
</li>
{# Table View (Default) #}
<div class="table-view active">
<div class="table-responsive">
<table class="table table-hover align-middle mb-0">
<thead>
<tr>
<th scope="col">{% trans "Title" %}</th>
<th scope="col">{% trans "Created By" %}</th>
<th scope="col">{% trans "Created" %}</th>
<th scope="col" class="text-center">{% trans "Actions" %}</th>
</tr>
</thead>
<tbody>
{% for material in materials %}
<tr>
<td><strong class="text-primary">{{ material.title }}</strong></td>
<td>{{ material.created_by.username|default:"Anonymous" }}</td>
<td>{{ material.created_at|date:"M d, Y" }}</td>
<td class="text-center">
<div class="btn-group btn-group-sm" role="group">
<a href="{% url 'training_detail' material.pk %}" class="btn btn-outline-primary" title="{% trans 'View' %}">
<i class="fas fa-eye"></i>
</a>
{% if user.is_authenticated and material.created_by == user %}
<a href="{% url 'training_update' material.pk %}" class="btn btn-outline-secondary" title="{% trans 'Edit' %}">
<i class="fas fa-edit"></i>
</a>
<button type="button" class="btn btn-outline-danger" title="{% trans 'Delete' %}"
data-bs-toggle="deleteModal"
data-delete-url="{% url 'training_delete' material.pk %}"
data-item-name="{{ material.title }}">
<i class="fas fa-trash-alt"></i>
</button>
{% endif %}
</div>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
{# Card View #}
<div class="card-view">
<div class="row g-4">
{% for material in materials %}
<div class="col-md-6 col-lg-4">
<div class="card h-100">
<div class="card-header">
<h5 class="h5 mb-1">{{ material.title }}</h5>
<small class="text-white-50">{{ material.created_by.username|default:"Anonymous" }}</small>
</div>
<div class="card-body">
<p class="card-text">
<strong>{% trans "Created" %}:</strong> {{ material.created_at|date:"M d, Y" }}
</p>
</div>
<div class="card-footer">
<div class="d-flex gap-2">
<a href="{% url 'training_detail' material.pk %}" class="btn btn-sm btn-outline-primary w-100">
<i class="fas fa-eye"></i> {% trans "View" %}
</a>
{% if user.is_authenticated and material.created_by == user %}
<div class="btn-group w-100" role="group">
<a href="{% url 'training_update' material.pk %}" class="btn btn-sm btn-outline-secondary" title="{% trans 'Edit' %}">
<i class="fas fa-edit"></i>
</a>
<button type="button" class="btn btn-outline-danger btn-sm" title="{% trans 'Delete' %}"
data-bs-toggle="deleteModal"
data-delete-url="{% url 'training_delete' material.pk %}"
data-item-name="{{ material.title }}">
<i class="fas fa-trash-alt"></i>
</button>
</div>
{% endif %}
</div>
</div>
</div>
</div>
{% endfor %}
</div>
</div>
</div>
{% if is_paginated %}
<div class="card-footer bg-light border-top">
<nav aria-label="Page navigation">
<ul class="pagination justify-content-center mb-0">
{% if page_obj.has_previous %}
<li class="page-item">
<a class="page-link" href="?page={{ page_obj.previous_page_number }}" aria-label="Previous">
<span aria-hidden="true">&laquo;</span>
</a>
</li>
{% endif %}
{% for num in page_obj.paginator.page_range %}
{% if page_obj.number == num %}
<li class="page-item active"><span class="page-link">{{ num }}</span></li>
{% elif num > page_obj.number|add:'-3' and num < page_obj.number|add:'3' %}
<li class="page-item">
<a class="page-link" href="?page={{ num }}">{{ num }}</a>
</li>
{% endif %}
{% endfor %}
{% if page_obj.has_next %}
<li class="page-item">
<a class="page-link" href="?page={{ page_obj.next_page_number }}" aria-label="Next">
<span aria-hidden="true">&raquo;</span>
</a>
</li>
{% endif %}
</ul>
</nav>
</div>
{% endif %}
{% else %}
<div class="text-center py-5">
<i class="fas fa-book-open fa-3x text-muted mb-3"></i>
<h5 class="mb-3">{% trans "No training materials found." %}</h5>
<p class="text-muted mb-4">{% trans "It looks like there are no materials yet. Start by adding one!" %}</p>
{% if page_obj.has_next %}
<li class="page-item">
<a class="page-link" href="?page={{ page_obj.next_page_number }}{% if search_query %}&q={{ search_query }}{% endif %}">Next</a>
</li>
<li class="page-item">
<a class="page-link" href="?page={{ page_obj.paginator.num_pages }}{% if search_query %}&q={{ search_query }}{% endif %}">Last</a>
</li>
{% endif %}
</ul>
</nav>
{% endif %}
{% else %}
<div class="text-center py-5 card shadow-sm">
<div class="card-body">
<i class="fas fa-graduation-cap fa-3x mb-3" style="color: var(--kaauh-teal-dark);"></i>
<h3>{% trans "No training materials found" %}</h3>
<p class="text-muted">{% trans "It looks like there are no materials yet. Start by adding one!" %}</p>
{% if user.is_authenticated %}
<a href="{% url 'training_create' %}" class="btn btn-main-action">
<i class="fas fa-plus me-1"></i>
{% trans "Create Your First Material" %}
<a href="{% url 'training_create' %}" class="btn btn-main-action mt-3">
<i class="fas fa-plus me-1"></i> {% trans "Create Your First Material" %}
</a>
{% endif %}
</div>
{% endif %}
</div>
</div>
{% endif %}
</div>
{% endblock %}
{% endblock %}