You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
267 lines
11 KiB
267 lines
11 KiB
{% extends "admin/base.html" %}
|
|
|
|
{% block title %}{% if subtitle %}{{ subtitle }} | {% endif %}{{ title }} | {{ site_title|default:_('Django site admin') }}{% endblock %}
|
|
|
|
{% block branding %}
|
|
{% include "unfold/helpers/site_branding.html" %}
|
|
{% endblock %}
|
|
|
|
{% block extrahead %}
|
|
{{ block.super }}
|
|
{% load static %}
|
|
<link rel="stylesheet" href="{% static 'css/styles.css' %}">
|
|
<script defer src="{% static 'js/admin_row_click.js' %}"></script>
|
|
<style>
|
|
/* Clickable admin changelist rows */
|
|
#result_list tbody tr {
|
|
cursor: pointer;
|
|
transition: background-color 0.15s ease-in-out;
|
|
}
|
|
#result_list tbody tr:hover {
|
|
background-color: rgba(99, 102, 241, 0.05) !important;
|
|
}
|
|
#result_list tbody tr input,
|
|
#result_list tbody tr button,
|
|
#result_list tbody tr select,
|
|
#result_list tbody tr label,
|
|
#result_list tbody tr .actions-row {
|
|
cursor: default;
|
|
}
|
|
#result_list tbody tr .action-checkbox input {
|
|
cursor: pointer;
|
|
}
|
|
|
|
/* Clean and spacious filter_horizontal (dual listbox) layout */
|
|
.selector {
|
|
width: 100% !important;
|
|
max-width: 100% !important;
|
|
display: flex !important;
|
|
flex-direction: row !important;
|
|
align-items: stretch !important;
|
|
gap: 1.25rem !important;
|
|
margin-top: 0.5rem !important;
|
|
margin-bottom: 1.5rem !important;
|
|
}
|
|
.selector-available,
|
|
.selector-chosen {
|
|
flex: 1 1 0% !important;
|
|
min-width: 220px !important;
|
|
width: auto !important;
|
|
max-width: none !important;
|
|
display: flex !important;
|
|
flex-direction: column !important;
|
|
border-radius: 0.5rem !important;
|
|
border: 1px solid rgba(203, 213, 225, 0.8) !important;
|
|
background-color: #f8fafc !important;
|
|
box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.05) !important;
|
|
overflow: hidden !important;
|
|
}
|
|
.dark .selector-available,
|
|
.dark .selector-chosen {
|
|
border-color: rgba(51, 65, 85, 0.8) !important;
|
|
background-color: #0f172a !important;
|
|
}
|
|
.selector-available h2,
|
|
.selector-chosen h2 {
|
|
font-size: 0.875rem !important;
|
|
font-weight: 600 !important;
|
|
padding: 0.625rem 0.875rem !important;
|
|
margin: 0 !important;
|
|
border-bottom: 1px solid rgba(203, 213, 225, 0.6) !important;
|
|
background-color: rgba(241, 245, 249, 0.6) !important;
|
|
}
|
|
.dark .selector-available h2,
|
|
.dark .selector-chosen h2 {
|
|
border-color: rgba(51, 65, 85, 0.6) !important;
|
|
background-color: rgba(30, 41, 59, 0.5) !important;
|
|
}
|
|
.selector-filter input {
|
|
width: calc(100% - 1rem) !important;
|
|
margin: 0.5rem !important;
|
|
padding: 0.4rem 0.75rem !important;
|
|
font-size: 0.8125rem !important;
|
|
border: 1px solid rgba(203, 213, 225, 0.8) !important;
|
|
border-radius: 0.375rem !important;
|
|
background-color: #ffffff !important;
|
|
}
|
|
.dark .selector-filter input {
|
|
border-color: rgba(51, 65, 85, 0.8) !important;
|
|
background-color: #1e293b !important;
|
|
color: #f8fafc !important;
|
|
}
|
|
.selector select {
|
|
flex: 1 1 auto !important;
|
|
min-height: 220px !important;
|
|
max-height: 320px !important;
|
|
height: auto !important;
|
|
width: 100% !important;
|
|
padding: 0.5rem !important;
|
|
border: none !important;
|
|
outline: none !important;
|
|
background: transparent !important;
|
|
}
|
|
.selector select option {
|
|
padding: 0.35rem 0.5rem !important;
|
|
border-radius: 0.25rem !important;
|
|
margin-bottom: 1px !important;
|
|
}
|
|
.selector-chooser {
|
|
display: flex !important;
|
|
flex-direction: column !important;
|
|
justify-content: center !important;
|
|
align-items: center !important;
|
|
gap: 0.5rem !important;
|
|
margin: 0 !important;
|
|
padding: 0 0.5rem !important;
|
|
width: 3.5rem !important;
|
|
flex-shrink: 0 !important;
|
|
}
|
|
.selector-chooser li {
|
|
list-style: none !important;
|
|
margin: 0 !important;
|
|
padding: 0 !important;
|
|
}
|
|
.selector-chooser a {
|
|
display: inline-flex !important;
|
|
align-items: center !important;
|
|
justify-content: center !important;
|
|
width: 2.25rem !important;
|
|
height: 2.25rem !important;
|
|
border-radius: 0.375rem !important;
|
|
background-color: #f1f5f9 !important;
|
|
border: 1px solid #cbd5e1 !important;
|
|
color: #334155 !important;
|
|
cursor: pointer !important;
|
|
transition: all 0.15s ease-in-out !important;
|
|
}
|
|
.selector-chooser a:hover {
|
|
background-color: #6366f1 !important;
|
|
border-color: #6366f1 !important;
|
|
color: #ffffff !important;
|
|
}
|
|
.dark .selector-chooser a {
|
|
background-color: #1e293b !important;
|
|
border-color: #334155 !important;
|
|
color: #cbd5e1 !important;
|
|
}
|
|
.dark .selector-chooser a:hover {
|
|
background-color: #6366f1 !important;
|
|
border-color: #6366f1 !important;
|
|
color: #ffffff !important;
|
|
}
|
|
.selector-chooseall,
|
|
.selector-clearall {
|
|
display: block !important;
|
|
padding: 0.4rem !important;
|
|
font-size: 0.75rem !important;
|
|
font-weight: 500 !important;
|
|
text-align: center !important;
|
|
border-top: 1px solid rgba(203, 213, 225, 0.6) !important;
|
|
}
|
|
.dark .selector-chooseall,
|
|
.dark .selector-clearall {
|
|
border-color: rgba(51, 65, 85, 0.6) !important;
|
|
}
|
|
@media (max-width: 768px) {
|
|
.selector {
|
|
flex-direction: column !important;
|
|
}
|
|
.selector-chooser {
|
|
flex-direction: row !important;
|
|
width: 100% !important;
|
|
padding: 0.5rem 0 !important;
|
|
}
|
|
}
|
|
</style>
|
|
<script>
|
|
document.addEventListener('DOMContentLoaded', function () {
|
|
const resultTable = document.getElementById('result_list');
|
|
if (!resultTable) return;
|
|
|
|
resultTable.addEventListener('click', function (e) {
|
|
const target = e.target;
|
|
// Ignore interactive controls like checkboxes, action selects, buttons, and row expanders
|
|
if (target.closest('input, button, select, textarea, label, [data-action], .actions-row, [data-label="Expand row"]')) {
|
|
return;
|
|
}
|
|
|
|
// If user clicks a standard hyperlink, allow native browser navigation
|
|
const clickedLink = target.closest('a');
|
|
if (clickedLink && clickedLink.getAttribute('href') && clickedLink.getAttribute('href') !== '#') {
|
|
return;
|
|
}
|
|
|
|
const tr = target.closest('tbody tr');
|
|
if (!tr) return;
|
|
|
|
// Find the change/details link in this row
|
|
const changeLink = tr.querySelector('a[href*="/change/"], th a, td a.text-font-important-light, td a[href]');
|
|
if (changeLink && changeLink.href) {
|
|
if (e.ctrlKey || e.metaKey) {
|
|
window.open(changeLink.href, '_blank');
|
|
} else {
|
|
window.location.href = changeLink.href;
|
|
}
|
|
}
|
|
});
|
|
});
|
|
|
|
// Modern Dual-Listbox with Real-time Counters and Badges
|
|
(function() {
|
|
function setupListboxEnhancements() {
|
|
const selectors = document.querySelectorAll('.selector');
|
|
if (!selectors.length) return;
|
|
|
|
selectors.forEach(selector => {
|
|
const availableSelect = selector.querySelector('.selector-available select');
|
|
const chosenSelect = selector.querySelector('.selector-chosen select');
|
|
const availableH2 = selector.querySelector('.selector-available h2');
|
|
const chosenH2 = selector.querySelector('.selector-chosen h2');
|
|
|
|
function updateCounters() {
|
|
if (availableSelect && availableH2) {
|
|
const count = availableSelect.options.length;
|
|
let badge = availableH2.querySelector('.counter-badge');
|
|
if (!badge) {
|
|
badge = document.createElement('span');
|
|
badge.className = 'counter-badge text-xs px-2.5 py-0.5 rounded-full font-medium ml-2.5 bg-slate-200 text-slate-700 dark:bg-slate-700 dark:text-slate-300';
|
|
availableH2.appendChild(badge);
|
|
}
|
|
badge.textContent = count + ' available';
|
|
}
|
|
if (chosenSelect && chosenH2) {
|
|
const count = chosenSelect.options.length;
|
|
let badge = chosenH2.querySelector('.counter-badge');
|
|
if (!badge) {
|
|
badge = document.createElement('span');
|
|
badge.className = 'counter-badge text-xs px-2.5 py-0.5 rounded-full font-semibold ml-2.5 bg-indigo-100 text-indigo-700 dark:bg-indigo-900/60 dark:text-indigo-300';
|
|
chosenH2.appendChild(badge);
|
|
}
|
|
badge.textContent = count + ' assigned';
|
|
}
|
|
}
|
|
|
|
updateCounters();
|
|
selector.addEventListener('click', function () {
|
|
setTimeout(updateCounters, 100);
|
|
});
|
|
if (availableSelect) availableSelect.addEventListener('change', updateCounters);
|
|
if (chosenSelect) chosenSelect.addEventListener('change', updateCounters);
|
|
});
|
|
}
|
|
|
|
if (document.readyState === 'loading') {
|
|
document.addEventListener('DOMContentLoaded', setupListboxEnhancements);
|
|
} else {
|
|
setupListboxEnhancements();
|
|
}
|
|
window.addEventListener('load', function() {
|
|
setTimeout(setupListboxEnhancements, 100);
|
|
});
|
|
})();
|
|
</script>
|
|
{% if plausible_domain %}
|
|
<script defer data-domain="{{ plausible_domain }}" src="https://plausible.io/js/script.js"></script>
|
|
{% endif %}
|
|
{% endblock %}
|
|
|