diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000..bde7eef Binary files /dev/null and b/.DS_Store differ diff --git a/_xibo-cms-clone b/_xibo-cms-clone deleted file mode 160000 index 56c98da..0000000 --- a/_xibo-cms-clone +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 56c98da0b586da18d5f39a9e78177f9164bc0de6 diff --git a/custom/otssignange/css/override-dark.css b/custom/otssignange/css/override-dark.css index f9e158b..0ff512a 100644 --- a/custom/otssignange/css/override-dark.css +++ b/custom/otssignange/css/override-dark.css @@ -970,6 +970,104 @@ textarea:focus { outline: none !important; } +/* --- Bootstrap Tagsinput / Tokenfield inside modals --- */ +.modal-body .bootstrap-tagsinput, +.modal-body .tagsinput, +.modal-body .tokenfield { + background-color: var(--modal-input-bg, var(--ots-bg)) !important; + border: 1px solid var(--modal-input-border, var(--ots-border)) !important; + border-radius: var(--ots-radius-sm) !important; + color: var(--modal-input-text, var(--ots-text)) !important; + min-height: 36px; + padding: 4px 8px !important; + box-shadow: none !important; + display: flex; + flex-wrap: wrap; + align-items: center; + gap: 4px; +} + +.modal-body .bootstrap-tagsinput:focus-within, +.modal-body .tagsinput:focus-within, +.modal-body .tokenfield:focus-within { + border-color: var(--modal-input-focus-border, var(--ots-primary)) !important; + box-shadow: 0 0 0 3px var(--modal-input-focus-ring, rgba(79, 140, 255, 0.2)) !important; +} + +.modal-body .bootstrap-tagsinput input, +.modal-body .tagsinput input, +.modal-body .tokenfield input.token-input { + background: transparent !important; + color: var(--modal-input-text, var(--ots-text)) !important; + border: none !important; + box-shadow: none !important; + outline: none !important; + margin: 0 !important; + padding: 2px 4px !important; +} + +.modal-body .bootstrap-tagsinput input::placeholder, +.modal-body .tagsinput input::placeholder, +.modal-body .tokenfield input.token-input::placeholder { + color: var(--ots-text-faint, #7f8aa3) !important; +} + +.modal-body .bootstrap-tagsinput .tag, +.modal-body .bootstrap-tagsinput .badge, +.modal-body .tagsinput .tag, +.modal-body .tokenfield .token { + background: rgba(79, 140, 255, 0.18) !important; + border: 1px solid rgba(79, 140, 255, 0.35) !important; + color: var(--ots-primary, #4f8cff) !important; + border-radius: 999px !important; + padding: 2px 8px !important; + font-size: 0.8rem; + line-height: 1.5; +} + +.modal-body .bootstrap-tagsinput .tag [data-role="remove"], +.modal-body .bootstrap-tagsinput .badge [data-role="remove"], +.modal-body .tokenfield .token .close { + color: var(--ots-primary, #4f8cff) !important; + opacity: 0.7; + margin-left: 4px; + cursor: pointer; +} + +.modal-body .bootstrap-tagsinput .tag [data-role="remove"]:hover, +.modal-body .bootstrap-tagsinput .badge [data-role="remove"]:hover, +.modal-body .tokenfield .token .close:hover { + opacity: 1; +} + +/* Global bootstrap-tagsinput theming (outside modals too) */ +.bootstrap-tagsinput, +.tagsinput, +.tokenfield { + background-color: var(--modal-input-bg, var(--ots-bg)) !important; + border: 1px solid var(--modal-input-border, var(--ots-border)) !important; + border-radius: var(--ots-radius-sm) !important; + color: var(--modal-input-text, var(--ots-text)) !important; + box-shadow: none !important; +} + +.bootstrap-tagsinput input, +.tagsinput input, +.tokenfield input.token-input { + background: transparent !important; + color: var(--modal-input-text, var(--ots-text)) !important; +} + +.bootstrap-tagsinput .tag, +.bootstrap-tagsinput .badge, +.tagsinput .tag, +.tokenfield .token { + background: rgba(79, 140, 255, 0.18) !important; + border: 1px solid rgba(79, 140, 255, 0.35) !important; + color: var(--ots-primary, #4f8cff) !important; + border-radius: 999px !important; +} + /* --- Close button --- */ .modal-header .close, .modal-header [data-dismiss="modal"] { @@ -1369,3 +1467,66 @@ html[style], body[style] { background-color: var(--color-background) !important; } +/* ============================================================================= + OTS UPLOAD MODAL – Dark-mode refinements + Supplements override-styles.twig which uses CSS variables for auto theming. + These rules guarantee the upload modal stays dark when override-dark.css loads. + ============================================================================= */ +.ots-upload-content { + background: var(--ots-surface, #141c2b); + border-color: var(--ots-border, #2c3a54); +} +.ots-upload-header { + background: var(--ots-bg, #0b111a); + border-bottom-color: var(--ots-border, #2c3a54); +} +.ots-upload-title { + color: var(--ots-text, #e6eefb); +} +.ots-upload-body { + background: var(--ots-surface, #141c2b); + color: var(--ots-text, #e6eefb); +} +.ots-upload-dropzone { + border-color: var(--ots-border, #2c3a54); + background: rgba(79,140,255,0.03); +} +.ots-upload-dropzone:hover, +.ots-upload-dropzone:focus-visible { + border-color: var(--ots-primary, #4f8cff); + background: rgba(79,140,255,0.07); +} +.ots-upload-dropzone--over { + border-color: var(--ots-primary, #4f8cff) !important; + background: rgba(79,140,255,0.12) !important; +} +.ots-upload-file-item { + background: var(--ots-bg, #0b111a); + border-color: var(--ots-border-soft, #243047); +} +.ots-upload-file-name { + color: var(--ots-text, #e6eefb); +} +.ots-upload-file-meta { + color: var(--ots-text-muted, #a9b6cc); +} +.ots-upload-footer { + background: var(--ots-bg, #0b111a); + border-top-color: var(--ots-border, #2c3a54); +} +.ots-upload-btn-cancel { + color: var(--ots-text-muted, #a9b6cc); + border-color: var(--ots-border, #2c3a54); +} +.ots-upload-btn-cancel:hover { + background: rgba(255,255,255,0.06); + color: var(--ots-text, #e6eefb); +} +.ots-upload-option { + background: rgba(79,140,255,0.04); + border-color: rgba(79,140,255,0.08); + color: var(--ots-text, #e6eefb); +} +.ots-upload-option small { + color: var(--ots-text-muted, #a9b6cc); +} diff --git a/custom/otssignange/css/override.css b/custom/otssignange/css/override.css index 97e3cbb..0660c29 100644 --- a/custom/otssignange/css/override.css +++ b/custom/otssignange/css/override.css @@ -186,15 +186,31 @@ body { pointer-events: auto !important; } -/* Hide the rowMenu column header completely */ -th.rowMenu, -td.rowMenu { - display: none !important; - visibility: hidden !important; - width: 0 !important; - padding: 0 !important; - margin: 0 !important; - border: 0 !important; +/* The rowMenu th is the empty header for the per-row action dropdown. + Keep it in flow so column count matches tbody, but make it minimal. + The matching td (last-child) holds the action button and must stay visible. + NOTE: No background set here — inherits from .ots-table-card .table thead th rules. */ +th.rowMenu { + width: 40px !important; + min-width: 40px !important; + max-width: 40px !important; + padding: 4px !important; + text-align: center !important; + box-sizing: border-box !important; + border-left: none !important; + border-right: none !important; + border-top: none !important; +} + +/* Style the action-button td to match the header width */ +table:has(th.rowMenu) > tbody > tr > td:last-child { + width: 40px !important; + min-width: 40px !important; + max-width: 40px !important; + padding: 4px !important; + text-align: center !important; + box-sizing: border-box !important; + overflow: visible !important; } /* Ensure floating menu children aren't clipped (scoped to floated menus only) */ @@ -3784,14 +3800,40 @@ body.ots-sidebar-open .ots-topbar { overflow: hidden; } -.dashboard-card { - transition: transform var(--transition-base), box-shadow var(--transition-base), border-color var(--transition-base); + +/* Card hover behavior is handled in override-styles.twig (loaded last) */ + +/* ── .ots-static-page: kill card hover on non-dashboard pages (backup) ────── */ +.ots-static-page .dashboard-card, +.ots-static-page .content-card, +.ots-static-page .action-card, +.ots-static-page .action-card--modern, +.ots-static-page .kpi-card, +.ots-static-page .dashboard-chart-card, +.ots-static-page .widget, +.ots-static-page .card, +.ots-static-page .panel, +.ots-static-page .media-item, +.ots-static-page [class*="-card"], +.ots-static-page [class*="card-"] { + transition: none !important; + transform: none !important; } -.dashboard-card:hover { - transform: translateY(-2px); - box-shadow: 0 22px 50px rgba(8, 15, 30, 0.45); - border-color: rgba(59, 130, 246, 0.45); +.ots-static-page .dashboard-card:hover, +.ots-static-page .content-card:hover, +.ots-static-page .action-card:hover, +.ots-static-page .action-card--modern:hover, +.ots-static-page .kpi-card:hover, +.ots-static-page .dashboard-chart-card:hover, +.ots-static-page .widget:hover, +.ots-static-page .card:hover, +.ots-static-page .panel:hover, +.ots-static-page .media-item:hover, +.ots-static-page [class*="-card"]:hover, +.ots-static-page [class*="card-"]:hover { + transform: none !important; + transition: none !important; } .dashboard-card .panel-header, @@ -3837,6 +3879,15 @@ body.ots-sidebar-open .ots-topbar { min-width: 0; flex: 1; overflow: visible; + background-color: transparent !important; +} + +/* Force XiboData card variant to be transparent */ +.XiboData.card, +.XiboData.card.py-3, +div.XiboData { + background-color: transparent !important; + background: transparent !important; } .kpi-card--modern { @@ -3874,11 +3925,7 @@ body.ots-sidebar-open .ots-topbar { box-shadow: 0 14px 30px rgba(8, 15, 30, 0.35); } -.action-card--modern:hover { - transform: translateY(-4px); - border-color: rgba(59, 130, 246, 0.45); - box-shadow: 0 20px 36px rgba(8, 15, 30, 0.45); -} +/* Hover effect moved to dashboard-page specific rules at end of file */ /* OTS dashboard message (theme-dashboard-message.twig) */ .ots-dashboard-message { @@ -3938,13 +3985,10 @@ body.ots-sidebar-open .ots-topbar { border: 1px solid var(--color-border); border-radius: 8px; padding: 20px; - transition: all var(--transition-base); + transition: none; } -.kpi-card:hover { - border-color: var(--color-primary); - box-shadow: 0 0 0 1px var(--color-primary); -} +/* Hover effect moved to dashboard-page specific rules at end of file */ .kpi-header { display: flex; @@ -4220,14 +4264,11 @@ body.ots-sidebar-open .ots-topbar { /* Enhanced chart container styling */ .dashboard-chart-card { - transition: all 300ms cubic-bezier(0.4, 0, 0.2, 1) !important; + transition: none !important; box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15) !important; } -.dashboard-chart-card:hover { - box-shadow: 0 8px 24px rgba(0, 0, 0, 0.25) !important; - transform: translateY(-2px); -} +/* Hover effect moved to dashboard-page specific rules at end of file */ /* Chart action improvements */ .dashboard-chart-actions { @@ -4464,16 +4505,11 @@ body.ots-sidebar-open .ots-topbar { border-radius: 8px; text-decoration: none; color: var(--color-text-primary); - transition: all var(--transition-base); + transition: none; cursor: pointer; } -.action-card:hover { - border-color: var(--color-primary); - background-color: rgba(59, 130, 246, 0.05); - transform: translateY(-2px); - box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15); -} +/* Hover effect moved to dashboard-page specific rules at end of file */ .action-icon { width: 40px; @@ -4535,15 +4571,13 @@ body.ots-sidebar-open .ots-topbar { box-shadow: var(--ots-shadow-md, 0 8px 18px rgba(0,0,0,0.12)); margin-bottom: 0; border-radius: 12px; - overflow: hidden; + overflow: visible !important; } /* Strongly remove any remaining gradients / shadows inside filters */ -.ots-filter-card *, .ots-filter-card *::before, .ots-filter-card *::after { background-image: none !important; - background: transparent !important; box-shadow: none !important; } @@ -4631,8 +4665,8 @@ body.ots-sidebar-open .ots-topbar { align-items: center; justify-content: space-between; padding: 14px 16px; - border-bottom: none; - background: transparent; + border-bottom: 1px solid var(--color-border); + background: var(--color-surface-elevated); } .ots-filter-title { @@ -4669,6 +4703,7 @@ body.ots-sidebar-open .ots-topbar { overflow: visible; transition: max-height 300ms ease-out, padding 300ms ease-out; display: block; + background: var(--color-surface-elevated) !important; } .ots-filter-content.collapsed { @@ -4679,6 +4714,22 @@ body.ots-sidebar-open .ots-topbar { display: none; } +/* Ensure FilterDiv and all nested card-body elements inherit the filter background */ +.ots-filter-card .FilterDiv, +.ots-filter-card .card-body, +.ots-filter-card .FilterDiv.card-body { + background: var(--color-surface-elevated) !important; + background-color: var(--color-surface-elevated) !important; +} + +/* Ensure form elements have proper container backgrounds */ +.ots-filter-card form, +.ots-filter-card .form-inline, +.ots-filter-card .tab-content, +.ots-filter-card .tab-pane { + background: transparent !important; +} + .ots-filter-card .nav-tabs { border-bottom: 1px solid var(--color-border); gap: 8px; @@ -4846,6 +4897,7 @@ body.ots-sidebar-open .ots-topbar { gap: 32px; align-items: start; width: 100%; + min-width: 0; transition: grid-template-columns 200ms ease-out; } @@ -4912,6 +4964,7 @@ body.ots-sidebar-open .ots-topbar { /* DataTables controls */ .dataTables_wrapper { color: var(--color-text-primary) !important; + background: transparent !important; } .dataTables_wrapper .dataTables_length, @@ -4919,6 +4972,17 @@ body.ots-sidebar-open .ots-topbar { .dataTables_wrapper .dataTables_info, .dataTables_wrapper .dataTables_paginate { color: var(--color-text-secondary) !important; + background: transparent !important; +} + +/* Ensure all DataTables control wrappers and button areas have transparent backgrounds */ +.dataTables_wrapper > *, +.dataTables_wrapper .dataTables_buttons, +.dataTables_buttons, +.dt-buttons, +.buttons-collection { + background: transparent !important; + background-color: transparent !important; } .dataTables_wrapper .dataTables_filter input, @@ -4935,11 +4999,36 @@ body.ots-sidebar-open .ots-topbar { flex: 1; min-width: 0; overflow: hidden; + background: transparent !important; +} + +/* Ensure XiboData cards are transparent */ +.XiboData.card, +.XiboData.card.py-3, +div.XiboData.card { + background: transparent !important; + background-color: transparent !important; + border: none !important; + box-shadow: none !important; } #datatable-container { width: 100%; + min-width: 0; overflow-x: auto; + overflow-y: visible; + background: transparent !important; +} + +/* Ensure all child elements of datatable-container have transparent backgrounds */ +#datatable-container > *, +#datatable-container .XiboData, +#datatable-container .XiboData > *, +#datatable-container .card, +#datatable-container .dataTables_wrapper, +#datatable-container .dataTables_wrapper > * { + background: transparent !important; + background-color: transparent !important; } .ots-table-card .table thead th { @@ -5077,6 +5166,77 @@ body.ots-light-mode .ots-table-toolbar .btn-primary { color: #ffffff !important; } +/* Map and list view toggle buttons */ +#map_button, +#list_button { + background-color: var(--color-primary) !important; + border-color: var(--color-primary) !important; + color: #ffffff !important; + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2) !important; + transition: all 0.15s ease !important; +} + +#map_button:hover, +#list_button:hover { + background-color: var(--color-primary-light) !important; + border-color: var(--color-primary-light) !important; + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3) !important; + transform: translateY(-1px); +} + +#map_button:active, +#list_button:active { + transform: translateY(0); +} + +/* Active state for map/list toggle buttons */ +#map_button.active, +#list_button.active { + background-color: #0c7a2a !important; + border-color: #0c7a2a !important; + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.4) inset !important; +} + +/* Dark mode toolbar button styles - ensure consistent colors across all pages */ +.ots-table-toolbar .btn-success { + background-color: #10b981 !important; + border-color: #10b981 !important; + color: #ffffff !important; + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2) !important; +} + +.ots-table-toolbar .btn-success:hover { + background-color: #059669 !important; + border-color: #059669 !important; + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3) !important; +} + +.ots-table-toolbar .btn-primary { + background-color: #3b82f6 !important; + border-color: #3b82f6 !important; + color: #ffffff !important; + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2) !important; +} + +.ots-table-toolbar .btn-primary:hover { + background-color: #2563eb !important; + border-color: #2563eb !important; + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3) !important; +} + +.ots-table-toolbar .btn-warning { + background-color: #f59e0b !important; + border-color: #f59e0b !important; + color: #ffffff !important; + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2) !important; +} + +.ots-table-toolbar .btn-warning:hover { + background-color: #d97706 !important; + border-color: #d97706 !important; + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3) !important; +} + .ots-table-card .dataTables_wrapper, .ots-table-card .dataTables_wrapper * { color: #e2e8f0 !important; @@ -5134,6 +5294,7 @@ body.ots-light-mode .ots-table-toolbar .btn-primary { .ots-map-card { margin-top: 16px; + height: 600px; min-height: 360px; background: rgba(15, 23, 42, 0.6); border: 1px solid rgba(148, 163, 184, 0.2); @@ -5254,6 +5415,7 @@ body.ots-light-mode .ots-displays-page #datatable-container .XiboData table.data width: 18px; height: 18px; flex-shrink: 0; + color: yellow; } .folder-name { @@ -5970,9 +6132,16 @@ textarea { .panel, .panel-body, .table-wrapper, +.dataTables_wrapper, +.dataTables_wrapper *, +.dataTables_wrapper .dataTables_scroll, +.dataTables_wrapper .dataTables_scroll *, .dataTables_wrapper .dataTables_scrollBody, .dataTables_wrapper .dataTables_scrollHead, -.dataTables_wrapper .dataTables_scrollHead table { +.dataTables_wrapper .dataTables_scrollHeadInner, +.dataTables_wrapper .dataTables_scrollHeadInner *, +.dataTables_wrapper .dataTables_scrollHead table, +.dataTables_wrapper .dataTables_scrollHead table * { opacity: 1 !important; background: transparent !important; } @@ -6142,13 +6311,29 @@ legend { /* Dropdowns, modals, and popovers */ .dropdown-menu, -.dropdown-toggle, .popover { background-color: var(--color-surface) !important; color: var(--color-text-primary) !important; border: 1px solid var(--color-border) !important; } +/* Dropdown toggles: only style those NOT inside tables or topbar. + Table action buttons should inherit their row background. + Topbar nav links have their own styling. */ +.dropdown-toggle:not(table .dropdown-toggle):not(.ots-table-card .dropdown-toggle):not(.ots-topbar .dropdown-toggle):not(.navbar-nav .dropdown-toggle) { + background-color: var(--color-surface) !important; + color: var(--color-text-primary) !important; + border: 1px solid var(--color-border) !important; +} + +/* DataTable row action buttons — no background box */ +.ots-table-card .dropdown-toggle, +table .btn-group .dropdown-toggle, +.dataTables_wrapper .dropdown-toggle { + background-color: transparent !important; + border: none !important; +} + .modal, .modal-body, .modal-footer { @@ -6622,6 +6807,20 @@ a.text-muted { color: var(--color-text-secondary) !important; } +/* Folder tree icons - tan color like Windows Explorer */ +#container-folder-tree .fa, +#grid-folder-filter .fa, +.grid-folder-tree-container .fa { + color: #D4AF85 !important; + font-size: 1.5em !important; +} + +/* Folder action button icon - match folder tree tan color */ +#folder-tree-select-folder-button .fa, +#folder-tree-select-folder-button .fas { + color: #D4AF85 !important; +} + /* Tidy (library) button - broom icon and amber colouring */ .btn-tidy { background-color: var(--color-warning) !important; @@ -6788,52 +6987,7 @@ body.ots-light-mode .ots-displays-page #datatable-container .XiboData table.data -/* ============================================================================ - Remove hover animations inside the page wrapper - This prevents elements inside `#page-wrapper` from animating on hover - while keeping other site transitions intact. - ============================================================================ */ - -#page-wrapper *:hover { - transition: none !important; - transform: none !important; - animation: none !important; - box-shadow: none !important; -} - -#page-wrapper, -#page-wrapper * { - will-change: auto !important; -} - -/* Re-enable hover/transform/animation behavior inside dashboard areas only */ -#page-wrapper .dashboard-page *:hover, -#page-wrapper .dashboard-card *:hover, -#page-wrapper .dashboard-panels *:hover, -#page-wrapper .dashboard-chart-card *:hover { - transition: initial !important; - transform: initial !important; - animation: initial !important; - box-shadow: initial !important; -} - -#page-wrapper .dashboard-page, -#page-wrapper .dashboard-card, -#page-wrapper .dashboard-panels, -#page-wrapper .dashboard-chart-card { - will-change: auto !important; -} - -/* Content cards are static – no hover animation */ -.content-card { - transition: none !important; -} - -.content-card:hover { - transform: none !important; - box-shadow: 0 18px 40px rgba(8, 15, 30, 0.35) !important; - border-color: rgba(148, 163, 184, 0.18) !important; -} +/* Card hover behavior is handled in override-styles.twig (loaded last) */ /* Ensure the very bottom of the page follows the theme variables (light/dark) by forcing html/body and shell containers to use the variable-driven @@ -7478,6 +7632,76 @@ body.ots-light-mode .modal-header .btn-close:hover { box-shadow: 0 0 0 3px var(--modal-input-focus-ring) !important; } +/* ---------- Bootstrap Tagsinput / Tokenfield inside modals ----------------- */ +.modal-body .bootstrap-tagsinput, +.modal-body .tagsinput, +.modal-body .tokenfield { + background-color: var(--modal-input-bg) !important; + border: 1px solid var(--modal-input-border) !important; + border-radius: var(--ots-radius-sm) !important; + color: var(--modal-input-text) !important; + min-height: 36px; + padding: 4px 8px !important; + box-shadow: none !important; + display: flex; + flex-wrap: wrap; + align-items: center; + gap: 4px; +} + +.modal-body .bootstrap-tagsinput:focus-within, +.modal-body .tagsinput:focus-within, +.modal-body .tokenfield:focus-within { + border-color: var(--modal-input-focus-border) !important; + box-shadow: 0 0 0 3px var(--modal-input-focus-ring) !important; +} + +.modal-body .bootstrap-tagsinput input, +.modal-body .tagsinput input, +.modal-body .tokenfield input.token-input { + background: transparent !important; + color: var(--modal-input-text) !important; + border: none !important; + box-shadow: none !important; + outline: none !important; + margin: 0 !important; + padding: 2px 4px !important; +} + +.modal-body .bootstrap-tagsinput input::placeholder, +.modal-body .tagsinput input::placeholder, +.modal-body .tokenfield input.token-input::placeholder { + color: var(--ots-text-faint, #64748b) !important; +} + +.modal-body .bootstrap-tagsinput .tag, +.modal-body .bootstrap-tagsinput .badge, +.modal-body .tagsinput .tag, +.modal-body .tokenfield .token { + background: rgba(79, 140, 255, 0.15) !important; + border: 1px solid rgba(79, 140, 255, 0.3) !important; + color: var(--ots-primary, #3b82f6) !important; + border-radius: 999px !important; + padding: 2px 8px !important; + font-size: 0.8rem; + line-height: 1.5; +} + +.modal-body .bootstrap-tagsinput .tag [data-role="remove"], +.modal-body .bootstrap-tagsinput .badge [data-role="remove"], +.modal-body .tokenfield .token .close { + color: var(--ots-primary, #3b82f6) !important; + opacity: 0.7; + margin-left: 4px; + cursor: pointer; +} + +.modal-body .bootstrap-tagsinput .tag [data-role="remove"]:hover, +.modal-body .bootstrap-tagsinput .badge [data-role="remove"]:hover, +.modal-body .tokenfield .token .close:hover { + opacity: 1; +} + /* ---------- Tabs inside modals --------------------------------------------- */ .modal-body .nav-tabs { border-bottom: 1px solid var(--modal-border) !important; diff --git a/custom/otssignange/js/theme.js b/custom/otssignange/js/theme.js index ac09245..b8df07f 100644 --- a/custom/otssignange/js/theme.js +++ b/custom/otssignange/js/theme.js @@ -664,12 +664,94 @@ }); } + /** + * Close every open dropdown / popover on the page. + * Covers: Bootstrap 4 native dropdowns, OTS custom dropdowns, + * the user-menu, notification drawer, and DataTable row menus. + */ + function closeAllDropdowns() { + try { + // Row dropdown menus appended to body + document.querySelectorAll('.ots-row-dropdown').forEach(function(m) { + m.classList.remove('show', 'ots-row-dropdown'); + m.style.cssText = ''; + }); + + document.querySelectorAll('.dropdown.show, .btn-group.show').forEach(function(el) { + el.classList.remove('show'); + var m = el.querySelector('.dropdown-menu.show'); + if (m) m.classList.remove('show'); + }); + document.querySelectorAll('.dropdown-menu.show').forEach(function(m) { + m.classList.remove('show'); + }); + document.querySelectorAll('.dropdown.active, .ots-topbar-action .dropdown.active, .ots-page-actions .dropdown.active').forEach(function(el) { + el.classList.remove('active'); + }); + var userMenu = document.querySelector('.ots-user-menu-body.ots-user-menu-open'); + if (userMenu) { + userMenu.classList.remove('ots-user-menu-open'); + var userToggle = document.querySelector('#navbarUserMenu'); + if (userToggle) { + var dd = userToggle.closest('.dropdown'); + if (dd) dd.classList.remove('active', 'show'); + } + } + document.querySelectorAll('.dt-buttons.active').forEach(function(w) { w.classList.remove('active'); }); + document.querySelectorAll('.dt-button-collection.show').forEach(function(c) { c.classList.remove('show'); c.style.display = 'none'; }); + if (window.jQuery) { + window.jQuery('.dropdown-toggle[aria-expanded="true"]').attr('aria-expanded', 'false'); + window.jQuery('.dropdown-menu.show').removeClass('show'); + window.jQuery('.dropdown.show, .btn-group.show').removeClass('show'); + } + } catch (err) {} + } + + /** + * Wire up global listeners that trigger closeAllDropdowns(). + */ + function initGlobalDropdownDismiss() { + document.addEventListener('show.bs.modal', closeAllDropdowns, true); + try { + if (window.jQuery) { + window.jQuery(document).on('show.bs.modal', closeAllDropdowns); + window.jQuery(document).on('click', '.XiboFormButton, .XiboAjaxSubmit, .XiboFormRender', function() { + closeAllDropdowns(); + }); + } + } catch (e) {} + + document.addEventListener('click', function(e) { + var link = e.target.closest('.dropdown-menu a, .ots-topbar a.nav-link, .ots-topbar a.dropdown-item, .XiboFormButton'); + if (link && !e.defaultPrevented) { + closeAllDropdowns(); + } + }); + + window.addEventListener('popstate', closeAllDropdowns); + try { + var origPush = history.pushState; + var origReplace = history.replaceState; + history.pushState = function() { origPush.apply(this, arguments); closeAllDropdowns(); }; + history.replaceState = function() { origReplace.apply(this, arguments); closeAllDropdowns(); }; + } catch (e) {} + + try { + var content = document.getElementById('content') || document.querySelector('.ots-content'); + if (content) { + var contentObs = new MutationObserver(debounce(closeAllDropdowns, 80)); + contentObs.observe(content, { childList: true }); + } + } catch (e) {} + } + /** * Initialize all features when DOM is ready */ function init() { initSidebarToggle(); initDropdowns(); + initGlobalDropdownDismiss(); initSearch(); initPageInteractions(); initDataTables(); diff --git a/custom/otssignange/views/applications-page.twig b/custom/otssignange/views/applications-page.twig index 59f6fe8..788f977 100644 --- a/custom/otssignange/views/applications-page.twig +++ b/custom/otssignange/views/applications-page.twig @@ -12,7 +12,7 @@ {% block actionMenu %}{% endblock %} {% block pageContent %} -
{% trans "Manage API applications and connectors." %}
diff --git a/custom/otssignange/views/authed.twig b/custom/otssignange/views/authed.twig index 6056498..4fb9680 100644 --- a/custom/otssignange/views/authed.twig +++ b/custom/otssignange/views/authed.twig @@ -28,7 +28,7 @@ try{ var stored = localStorage.getItem('ots-theme-mode'); var prefersLight = window.matchMedia && window.matchMedia('(prefers-color-scheme: light)').matches; - var mode = stored || (prefersLight ? 'light' : 'light'); + var mode = stored || (prefersLight ? 'light' : 'dark'); if(mode === 'light') document.documentElement.classList.add('ots-light-mode'); else document.documentElement.classList.remove('ots-light-mode'); }catch(e){} diff --git a/custom/otssignange/views/campaign-page.twig b/custom/otssignange/views/campaign-page.twig index 1e8e1ed..caa8e50 100644 --- a/custom/otssignange/views/campaign-page.twig +++ b/custom/otssignange/views/campaign-page.twig @@ -28,7 +28,7 @@ {% block actionMenu %}{% endblock %} {% block pageContent %} -{% trans "Manage your campaigns and ad campaigns." %}
diff --git a/custom/otssignange/views/command-page.twig b/custom/otssignange/views/command-page.twig index c22dab3..b455290 100644 --- a/custom/otssignange/views/command-page.twig +++ b/custom/otssignange/views/command-page.twig @@ -29,7 +29,7 @@ {% block pageContent %} -{% trans "Create and manage commands for Displays." %}
diff --git a/custom/otssignange/views/dataset-page.twig b/custom/otssignange/views/dataset-page.twig index 2953a2c..6b4db29 100644 --- a/custom/otssignange/views/dataset-page.twig +++ b/custom/otssignange/views/dataset-page.twig @@ -29,7 +29,7 @@ {% block actionMenu %}{% endblock %} {% block pageContent %} -{% trans "Manage structured data sources." %}
diff --git a/custom/otssignange/views/daypart-page.twig b/custom/otssignange/views/daypart-page.twig index 2aa92b9..5a9df29 100644 --- a/custom/otssignange/views/daypart-page.twig +++ b/custom/otssignange/views/daypart-page.twig @@ -28,7 +28,7 @@ {% block actionMenu %}{% endblock %} {% block pageContent %} -{% trans "Manage time-based scheduling rules." %}
diff --git a/custom/otssignange/views/display-page.twig b/custom/otssignange/views/display-page.twig index 357813c..0b2c76e 100644 --- a/custom/otssignange/views/display-page.twig +++ b/custom/otssignange/views/display-page.twig @@ -65,7 +65,7 @@ {% endblock %} {% block pageContent %} -{% trans "Manage your player fleet and status." %}
@@ -337,7 +337,7 @@ -