Fix(Admin): Force Date Filter to be horizontal using JS DOM restructuring

This commit is contained in:
Flatlogic Bot 2026-02-01 07:55:13 +00:00
parent a3ff664ed9
commit 608119b06c
2 changed files with 165 additions and 322 deletions

View File

@ -20,6 +20,34 @@ h1, h2, h3, h4, h5, h6 {
font-weight: 700;
}
/* --- Masar Date Filter Row (Dynamic Wrapper) --- */
.masar-date-filter-row {
display: flex !important;
flex-direction: row !important;
align-items: center !important;
gap: 3px !important;
width: 100% !important;
}
.masar-date-filter-row select {
width: 32% !important;
min-width: 50px !important;
font-size: 11px !important;
padding: 2px !important;
height: 30px !important;
}
.masar-date-filter-row input {
width: 33% !important;
min-width: 50px !important;
font-size: 11px !important;
padding: 2px !important;
height: 30px !important;
margin: 0 !important;
}
/* --- Other Admin Tweaks --- */
.hero-section {
background: linear-gradient(135deg, var(--primary-dark) 0%, #2D2D30 100%);
padding: 100px 0;
@ -28,18 +56,6 @@ h1, h2, h3, h4, h5, h6 {
overflow: hidden;
}
.hero-section::before {
content: '';
position: absolute;
top: -50px;
right: -50px;
width: 200px;
height: 200px;
background: var(--accent-orange);
filter: blur(80px);
opacity: 0.2;
}
.glass-card {
background: rgba(255, 255, 255, 0.05);
backdrop-filter: blur(15px);
@ -65,46 +81,6 @@ h1, h2, h3, h4, h5, h6 {
color: white;
}
.tracking-input {
background: rgba(255, 255, 255, 0.1);
border: 1px solid rgba(255, 255, 255, 0.2);
color: white;
border-radius: 12px 0 0 12px;
padding: 15px 20px;
}
.tracking-input:focus {
background: rgba(255, 255, 255, 0.15);
border-color: var(--accent-orange);
box-shadow: none;
color: white;
}
.feature-icon {
width: 60px;
height: 60px;
background: var(--accent-orange);
border-radius: 15px;
display: flex;
align-items: center;
justify-content: center;
margin-bottom: 20px;
color: white;
font-size: 24px;
}
.parcel-status-badge {
padding: 8px 16px;
border-radius: 50px;
font-size: 14px;
font-weight: 600;
}
.status-pending { background: #FFE8CC; color: #D9480F; }
.status-picked_up { background: #E3FAFC; color: #0B7285; }
.status-in_transit { background: #E7F5FF; color: #1864AB; }
.status-delivered { background: #EBFBEE; color: #2B8A3E; }
/* Chat Widget */
#masar-chat-widget {
position: fixed;
@ -132,10 +108,6 @@ h1, h2, h3, h4, h5, h6 {
transition: transform 0.2s;
}
#masar-chat-toggle:hover {
transform: scale(1.05);
}
/* RTL Support for Chat */
[dir="rtl"] #masar-chat-widget {
right: auto;
@ -146,163 +118,14 @@ h1, h2, h3, h4, h5, h6 {
left: 20px;
}
.typing-dots span {
display: inline-block;
width: 8px;
height: 8px;
background-color: #adb5bd;
border-radius: 50%;
margin: 0 2px;
animation: typing 1s infinite;
}
.typing-dots span:nth-child(2) { animation-delay: 0.2s; }
.typing-dots span:nth-child(3) { animation-delay: 0.4s; }
@keyframes typing {
0%, 100% { transform: translateY(0); }
50% { transform: translateY(-5px); }
}
/* --- Admin Panel Customizations --- */
/* Fix: Prevent accidental file dialog open when clicking labels for logos/favicons */
body.model-platformprofile label[for="id_logo"],
body.model-platformprofile label[for="id_favicon"],
body.model-platformprofile label[for="id_admin_panel_logo"] {
pointer-events: none;
cursor: default;
}
/* Improve Admin Form Spacing */
.form-row {
padding: 15px 10px;
border-bottom: 1px solid #f0f0f0;
}
/* --- Fix Admin Search Box & Filter Layout --- */
/* Target the search form container in Jazzmin/AdminLTE */
#changelist-search .input-group {
display: flex !important;
flex-wrap: nowrap !important;
max-width: 300px !important;
}
/* Make the input field take available space */
#changelist-search input[type="text"] {
flex-grow: 1 !important;
width: auto !important;
}
/* Ensure the button stays inline */
#changelist-search button[type="submit"],
#changelist-search .btn {
white-space: nowrap !important;
}
/* Force filters to sit nicely in a row */
.filter-wrapper .form-group,
.filter-wrapper select,
.filter-wrapper .select2-container {
margin-bottom: 0 !important;
display: inline-block !important;
width: auto !important;
}
/* --- Date Range Filter Styling (Compact & Horizontal) --- */
/*
We want the [Select] [Start] [End] to all appear on ONE line in the sidebar.
This requires aggressive flex styling and width control.
*/
/* 1. Flex Container */
.admindatefilter .controls.date-filter-controls {
display: flex !important;
flex-direction: row !important;
align-items: center !important;
flex-wrap: nowrap !important;
gap: 2px !important;
width: 100% !important;
padding: 0 !important;
border: none !important;
font-size: 0 !important; /* Hide text nodes (dashes/spaces) between inputs */
}
/* 2. Dropdown (Quick Select) */
.admindatefilter select.admin-date-dropdown {
width: 32% !important;
min-width: 0 !important;
height: 30px !important;
padding: 0px 4px !important;
font-size: 11px !important;
margin: 0 !important;
display: inline-block !important;
flex-shrink: 0 !important;
}
/* 3. Inputs (From / To) */
.admindatefilter .date-input {
width: 33% !important;
min-width: 0 !important;
height: 30px !important;
padding: 4px !important;
font-size: 11px !important;
margin: 0 !important;
display: inline-block !important;
flex-shrink: 1 !important;
}
/* Hide any <br> tags injected by admin templates */
.admindatefilter br {
display: none !important;
}
/* Ensure the wrapper allows full width */
.admindatefilter {
width: 100% !important;
display: block !important;
box-sizing: border-box !important;
}
/* --- Search Box RTL/LTR Border Radius Handling --- */
/* LTR (Default) */
.masar-search-input {
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}
.masar-search-btn {
border-top-left-radius: 0;
border-bottom-left-radius: 0;
}
/* RTL Override for Search Box */
[dir="rtl"] .masar-search-input {
border-top-right-radius: 0.25rem !important;
border-bottom-right-radius: 0.25rem !important;
border-top-left-radius: 0 !important;
border-bottom-left-radius: 0 !important;
}
[dir="rtl"] .masar-search-btn {
border-top-left-radius: 0.25rem !important;
border-bottom-left-radius: 0.25rem !important;
border-top-right-radius: 0 !important;
border-bottom-right-radius: 0 !important;
}
/* --- Admin Panel RTL Sidebar Override (Agresive) --- */
@media (min-width: 992px) {
/* Main Sidebar */
[dir="rtl"] .main-sidebar {
left: auto !important;
right: 0 !important;
border-right: none !important;
border-left: 1px solid rgba(0,0,0,0.1) !important;
}
/* Content Wrapper & Headers */
[dir="rtl"] .content-wrapper,
[dir="rtl"] .main-header,
[dir="rtl"] .main-footer {
@ -310,22 +133,17 @@ body.model-platformprofile label[for="id_admin_panel_logo"] {
margin-right: 250px !important;
transition: margin-right .3s ease-in-out !important;
}
/* Collapsed Sidebar State */
[dir="rtl"].sidebar-collapse .main-sidebar {
margin-left: 0 !important;
margin-right: 0 !important;
width: 4.6rem !important;
}
[dir="rtl"].sidebar-collapse .content-wrapper,
[dir="rtl"].sidebar-collapse .main-header,
[dir="rtl"].sidebar-collapse .main-footer {
margin-left: 0 !important;
margin-right: 4.6rem !important;
}
/* Fix Brand Logo Area */
[dir="rtl"] .brand-link {
float: right !important;
width: 100% !important;
@ -336,53 +154,41 @@ body.model-platformprofile label[for="id_admin_panel_logo"] {
margin-right: 0.8rem !important;
margin-left: 0.5rem !important;
}
/* Navbar alignment */
[dir="rtl"] .navbar-nav {
flex-direction: row;
}
[dir="rtl"] .navbar-nav .nav-item {
float: right;
}
[dir="rtl"] .ml-auto {
margin-left: 0 !important;
margin-right: auto !important;
}
[dir="rtl"] .mr-auto {
margin-right: 0 !important;
margin-left: auto !important;
}
}
/* Sidebar Navigation Items RTL */
[dir="rtl"] .nav-sidebar .nav-item > .nav-link {
display: flex !important;
flex-direction: row !important;
align-items: center !important;
}
[dir="rtl"] .nav-sidebar .nav-icon {
margin-left: 0.5rem !important;
margin-right: 0 !important;
}
[dir="rtl"] .nav-sidebar .nav-link p {
display: inline-block !important;
margin-right: 0 !important;
text-align: right !important;
width: 100% !important;
}
/* Fix sidebar angle icon */
[dir="rtl"] .nav-sidebar .nav-icon.fa-angle-left {
transform: rotate(180deg);
margin-left: 0 !important;
margin-right: auto !important;
}
/* General Utils */
[dir="rtl"] .float-right {
float: left !important;
}
@ -394,4 +200,4 @@ body.model-platformprofile label[for="id_admin_panel_logo"] {
}
[dir="rtl"] .text-left {
text-align: right !important;
}
}

View File

@ -1,121 +1,158 @@
(function($) {
$(document).ready(function() {
// Helper to format date as YYYY-MM-DD
function formatDate(d) {
var year = d.getFullYear();
var month = ('0' + (d.getMonth() + 1)).slice(-2);
var day = ('0' + d.getDate()).slice(-2);
return year + '-' + month + '-' + day;
// Masar Date Range Filter Layout Fix v3
// Forces a horizontal layout for the Date Range Filter in Django Admin Sidebar
function initDateRangeDropdown() {
console.log("Masar Date Filter: Initializing v3...");
// Find all "Greater Than or Equal" inputs (the start date of the range)
var $gteInputs = $('input[name$="__gte"]');
if ($gteInputs.length === 0) {
return; // Not found yet
}
function initDateRangeDropdown() {
var $gteInputs = $('input[name$="__gte"]');
$gteInputs.each(function() {
var $gte = $(this);
if ($gte.data('masar-processed')) return;
$gte.data('masar-processed', true);
$gteInputs.each(function() {
var $gte = $(this);
// Prevent double init
if ($gte.data('dropdown-processed')) return;
$gte.data('dropdown-processed', true);
var name = $gte.attr('name');
var prefix = name.substring(0, name.lastIndexOf('__gte'));
var $lte = $('input[name="' + prefix + '__lte"]');
var name = $gte.attr('name');
var prefix = name.substring(0, name.lastIndexOf('__gte'));
var $lte = $('input[name="' + prefix + '__lte"]');
if ($lte.length === 0) return;
if ($lte.length === 0) return;
// Locate the container in the sidebar.
// Usually it's inside a <li class="... field-created_at ..."> or similar.
// We want to find the direct parent that holds these inputs.
var $parent = $gte.parent();
var $container = $gte.closest('.admindatefilter');
if ($container.length === 0) {
$container = $gte.closest('div[data-filter-name], li, .form-row, .card-body, .filter-wrapper');
}
if ($container.length === 0) $container = $gte.parent();
// Create our custom flex wrapper
var $wrapper = $('<div class="masar-date-filter-row"></div>');
$wrapper.css({
'display': 'flex',
'flex-direction': 'row',
'align-items': 'center',
'gap': '3px',
'width': '100%',
'margin-bottom': '10px'
});
// Find the direct wrapper of the inputs (usually .controls)
var $controls = $gte.closest('.controls');
if ($controls.length === 0) {
$controls = $gte.parent();
}
$controls.addClass('date-filter-controls'); // Hook for CSS
// --- Dropdown ---
var $select = $('<select class="form-control custom-select admin-date-dropdown">' +
'<option value="any">Any</option>' + // Shortened text
'<option value="today">Today</option>' +
'<option value="7days">7 Days</option>' +
'<option value="month">Month</option>' +
'<option value="custom">Custom</option>' +
'</select>');
// Create the Quick Select Dropdown
var $select = $('<select class="form-control custom-select admin-date-dropdown">' +
'<option value="any">Any</option>' +
'<option value="today">Today</option>' +
'<option value="7days">7 Days</option>' +
'<option value="month">Month</option>' +
'<option value="custom">Custom</option>' +
'</select>');
$select.css({
'width': '34%',
'min-width': '60px',
'height': '30px',
'padding': '0 4px',
'font-size': '11px'
});
// --- Inputs Styling ---
$gte.addClass('form-control form-control-sm date-input');
$lte.addClass('form-control form-control-sm date-input');
$gte.attr('placeholder', 'Start'); // Short placeholder
$lte.attr('placeholder', 'End');
// Style inputs
var inputStyle = {
'width': '33%',
'min-width': '0',
'height': '30px',
'padding': '4px',
'font-size': '11px'
};
$gte.css(inputStyle).attr('placeholder', 'Start');
$lte.css(inputStyle).attr('placeholder', 'End');
// Insert Dropdown INSIDE the flex container (at start)
if ($controls.length) {
$controls.prepend($select);
// --- RESTRUCTURING DOM ---
// 1. Insert wrapper before the start input
$gte.before($wrapper);
// 2. Move elements into wrapper
$wrapper.append($select);
$wrapper.append($gte);
$wrapper.append($lte);
// 3. Cleanup: Hide any left-over text nodes (like "-", "From", "To") or <br> in the parent
$parent.contents().filter(function() {
return (this.nodeType === 3 && $.trim($(this).text()) !== '') || this.tagName === 'BR';
}).remove();
// Logic for Dropdown Changes
// Helper to format date as YYYY-MM-DD
function formatDate(d) {
var year = d.getFullYear();
var month = ('0' + (d.getMonth() + 1)).slice(-2);
var day = ('0' + d.getDate()).slice(-2);
return year + '-' + month + '-' + day;
}
var gteVal = $gte.val();
var lteVal = $lte.val();
if (gteVal || lteVal) {
$select.val('custom');
} else {
$select.val('any');
}
$select.on('change', function() {
var val = $(this).val();
var today = new Date();
if (val === 'custom') {
// Do nothing, let user edit
} else {
$gte.before($select);
}
// Initial State
var gteVal = $gte.val();
var lteVal = $lte.val();
if (gteVal || lteVal) {
$select.val('custom');
} else {
$select.val('any');
}
// Event Listener
$select.on('change', function() {
var val = $(this).val();
var today = new Date();
if (val === 'custom') {
// Inputs are always visible in our new layout, just ensure they are enabled/cleared if needed
if (val === 'any') {
$gte.val('');
$lte.val('');
} else {
if (val === 'any') {
$gte.val('');
$lte.val('');
} else {
var startStr = '';
var endStr = formatDate(today);
var startStr = '';
var endStr = formatDate(today);
if (val === 'today') {
startStr = formatDate(today);
} else if (val === '7days') {
var past = new Date();
past.setDate(today.getDate() - 7);
startStr = formatDate(past);
} else if (val === 'month') {
var firstDay = new Date(today.getFullYear(), today.getMonth(), 1);
startStr = formatDate(firstDay);
} else if (val === 'year') {
var firstDay = new Date(today.getFullYear(), 0, 1);
startStr = formatDate(firstDay);
}
$gte.val(startStr);
$lte.val(endStr);
if (val === 'today') {
startStr = formatDate(today);
} else if (val === '7days') {
var past = new Date();
past.setDate(today.getDate() - 7);
startStr = formatDate(past);
} else if (val === 'month') {
var firstDay = new Date(today.getFullYear(), today.getMonth(), 1);
startStr = formatDate(firstDay);
}
// Auto-submit
var $form = $gte.closest('form');
if ($form.length) {
$form.submit();
$gte.val(startStr);
$lte.val(endStr);
}
// Trigger Form Submit (Changes URL)
// Try to find the filter form
var $form = $gte.closest('form'); // Usually #changelist-search
if ($form.length) {
$form.submit();
} else {
// Sometimes filters are links, but date range usually has a button or relies on form
// If there is an "Apply" button nearby?
var $applyBtn = $parent.closest('.admindatefilter').find('input[type="submit"], button');
if ($applyBtn.length) {
$applyBtn.click();
} else {
var $btn = $container.find('input[type="submit"], button[type="submit"]');
if ($btn.length) $btn.click();
// Fallback: reload page with query params (complex, skip for now, rely on standard form)
}
}
});
}
});
}
});
}
$(document).ready(function() {
// Run immediately
initDateRangeDropdown();
// Re-run safely for dynamic content
// And retry a few times to catch slow rendering
setTimeout(initDateRangeDropdown, 200);
setTimeout(initDateRangeDropdown, 500);
setTimeout(initDateRangeDropdown, 1000);
});
})(django.jQuery);
})(django.jQuery);