micro-sidebar 1.2.2__py3-none-any.whl → 2.2.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,165 @@
1
+
2
+ .current-theme-indicator {
3
+ width: 25px;
4
+ height: 25px;
5
+ border-radius: 50%;
6
+ cursor: pointer;
7
+ border: 2px solid white;
8
+ box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15);
9
+ transition: all 0.2s cubic-bezier(0.25, 0.8, 0.25, 1);
10
+ margin: 5px; /* Spacing from bottom-left corner */
11
+ justify-self: end;
12
+ display: flex;
13
+ align-items: center;
14
+ justify-content: center;
15
+ pointer-events: auto; /* Enable clicks since parent toolbar is none */
16
+ }
17
+
18
+ .theme-arrow {
19
+ position: absolute;
20
+ bottom: 36px; /* Space above indicator */
21
+ left: 50%;
22
+ transform: translateX(-50%);
23
+ color: var(--primal);
24
+ font-size: 1.3rem; /* Even bigger arrow */
25
+ opacity: 0;
26
+ visibility: hidden;
27
+ transition: all 0.2s ease;
28
+ pointer-events: none;
29
+ z-index: 10;
30
+ }
31
+
32
+ .sidebar.collapsed .theme-arrow.visible {
33
+ opacity: 1;
34
+ visibility: visible;
35
+ }
36
+
37
+ .sidebar.collapsed .theme-arrow {
38
+ bottom: 36px;
39
+ left: 50%;
40
+ transform: translateX(-50%);
41
+ }
42
+
43
+ .sidebar.collapsed .current-theme-indicator {
44
+ margin: 5px auto; /* Centered in narrow sidebar */
45
+ }
46
+
47
+ .current-theme-indicator:hover {
48
+ transform: scale(1.15);
49
+ box-shadow: 0 6px 12px rgba(0, 0, 0, 0.2);
50
+ }
51
+
52
+ /* Theme Popup Menu */
53
+ .theme-popup {
54
+ display: none;
55
+ position: absolute;
56
+ bottom: 45px;
57
+ left: 10px; /* Fixed to left in RTL too for specific bottom-left request */
58
+ background: white;
59
+ border-radius: 12px;
60
+ box-shadow: 0 10px 30px rgba(0, 0, 0, 0.25);
61
+ padding: 10px;
62
+ z-index: 1100;
63
+ min-width: 110px;
64
+ border: 1px solid rgba(0, 0, 0, 0.08);
65
+ animation: popupIn 0.2s ease-out;
66
+ pointer-events: auto;
67
+ }
68
+
69
+ .sidebar.collapsed .theme-popup {
70
+ left: 5px;
71
+ right: 5px;
72
+ bottom: 65px; /* More space to accommodate larger arrow and breathing room */
73
+ min-width: auto;
74
+ width: auto;
75
+ background: transparent !important;
76
+ border: none !important;
77
+ box-shadow: none !important;
78
+ padding: 0 !important;
79
+ }
80
+
81
+ .sidebar.collapsed .theme-popup .small {
82
+ display: none; /* Hide "Select Color" text in narrow view */
83
+ }
84
+
85
+ .sidebar.collapsed .theme-options-grid {
86
+ grid-template-columns: 1fr; /* Vertical column */
87
+ gap: 8px;
88
+ justify-items: center;
89
+ }
90
+
91
+ /* Staggered Animations for items */
92
+ .theme-option-circle {
93
+ opacity: 0;
94
+ transform: translateY(10px);
95
+ transition: all 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
96
+ }
97
+
98
+ .theme-popup.show .theme-option-circle {
99
+ opacity: 1;
100
+ transform: translateY(0);
101
+ }
102
+
103
+ /* Staggered delays */
104
+ .theme-popup.show .theme-option-circle:nth-child(1) { transition-delay: 0.05s; }
105
+ .theme-popup.show .theme-option-circle:nth-child(2) { transition-delay: 0.1s; }
106
+ .theme-popup.show .theme-option-circle:nth-child(3) { transition-delay: 0.15s; }
107
+ .theme-popup.show .theme-option-circle:nth-child(4) { transition-delay: 0.2s; }
108
+ .theme-popup.show .theme-option-circle:nth-child(5) { transition-delay: 0.25s; }
109
+ .theme-popup.show .theme-option-circle:nth-child(6) { transition-delay: 0.3s; }
110
+
111
+ @keyframes popupIn {
112
+ from { opacity: 0; transform: translateY(10px); }
113
+ to { opacity: 1; transform: translateY(0); }
114
+ }
115
+
116
+ .theme-popup.show {
117
+ display: block;
118
+ }
119
+
120
+ .theme-options-grid {
121
+ display: grid;
122
+ grid-template-columns: repeat(3, 1fr);
123
+ gap: 12px;
124
+ }
125
+
126
+ .theme-option-circle {
127
+ width: 25px;
128
+ height: 25px;
129
+ border-radius: 50%;
130
+ cursor: pointer;
131
+ border: 2px solid transparent;
132
+ transition: all 0.2s ease;
133
+ box-shadow: inset 0 0 0 1px rgba(0,0,0,0.1);
134
+ pointer-events: auto;
135
+ }
136
+
137
+ .theme-option-circle:hover {
138
+ transform: scale(1.2);
139
+ }
140
+
141
+ .theme-option-circle.active {
142
+ border-color: #3b82f6;
143
+ box-shadow: 0 0 0 2px white, 0 0 0 4px #3b82f6 !important;
144
+ }
145
+
146
+ /* Theme Colors for circles */
147
+ .theme-circle-light { background: #f6f7f9; }
148
+ .theme-circle-blue { background: #2363c3; }
149
+ .theme-circle-gold { background: #d97706; }
150
+ .theme-circle-green { background: #166534; }
151
+ .theme-circle-red { background: #7f1d1d; }
152
+ .theme-circle-dark { background: #0f172a; }
153
+
154
+ /* Dark Mode Overrides for the Popup */
155
+ :root.theme-dark .theme-popup {
156
+ background: #1e293b;
157
+ border-color: rgba(255, 255, 255, 0.1);
158
+ color: white;
159
+ }
160
+ :root.theme-dark .sidebar-toolbar {
161
+ border-top-color: rgba(255, 255, 255, 0.05);
162
+ }
163
+ :root.theme-dark .theme-option-circle.active {
164
+ box-shadow: 0 0 0 2px #1e293b, 0 0 0 4px #3b82f6 !important;
165
+ }
@@ -0,0 +1,267 @@
1
+ (function() {
2
+ 'use strict';
3
+
4
+ const STORAGE_KEY_AUTO = 'sidebar_auto_order';
5
+ const STORAGE_KEY_PREFIX_EXTRA = 'sidebar_extra_';
6
+
7
+ let isReorderMode = false;
8
+ let draggedElement = null;
9
+ let dropIndicator = null;
10
+
11
+ // Expose restore function globally for immediate FOUC fix
12
+ window.restoreSidebarOrder = restoreOrder;
13
+
14
+ document.addEventListener('DOMContentLoaded', () => {
15
+ const sidebar = document.getElementById('sidebar');
16
+ const reorderToggle = document.getElementById('sidebarReorderToggle');
17
+
18
+ if (!sidebar || !reorderToggle) return;
19
+
20
+ // Create drop indicator element
21
+ dropIndicator = document.createElement('div');
22
+ dropIndicator.className = 'drop-indicator';
23
+ dropIndicator.style.display = 'none';
24
+
25
+ // Restore is now called immediately via inline script for FOUC prevention
26
+ // But call again here as fallback if inline script didn't run
27
+ if (!window._sidebarOrderRestored) {
28
+ restoreOrder();
29
+ }
30
+
31
+ // Toggle reorder mode
32
+ reorderToggle.addEventListener('click', (e) => {
33
+ e.stopPropagation();
34
+ isReorderMode = !isReorderMode;
35
+ reorderToggle.classList.toggle('active', isReorderMode);
36
+ sidebar.classList.toggle('reorder-mode', isReorderMode);
37
+
38
+ if (isReorderMode) {
39
+ enableDragAndDrop();
40
+ } else {
41
+ disableDragAndDrop();
42
+ }
43
+ });
44
+
45
+ // Close reorder mode when clicking outside
46
+ document.addEventListener('click', (e) => {
47
+ if (isReorderMode && !sidebar.contains(e.target)) {
48
+ isReorderMode = false;
49
+ reorderToggle.classList.remove('active');
50
+ sidebar.classList.remove('reorder-mode');
51
+ disableDragAndDrop();
52
+ }
53
+ });
54
+ });
55
+
56
+ function enableDragAndDrop() {
57
+ // Auto items in .sidebar-auto-items or direct .list-group children
58
+ const autoContainer = document.getElementById('sidebarAutoItems') ||
59
+ document.querySelector('.sidebar .list-group');
60
+ if (autoContainer) {
61
+ setupDraggableContainer(autoContainer, STORAGE_KEY_AUTO);
62
+ }
63
+
64
+ // Extra group items in accordion bodies
65
+ const accordionBodies = document.querySelectorAll('.sidebar .accordion-body');
66
+ accordionBodies.forEach(body => {
67
+ const groupName = body.dataset.groupName || body.closest('.accordion-item')?.querySelector('.accordion-button span')?.textContent?.trim();
68
+ if (groupName) {
69
+ const key = STORAGE_KEY_PREFIX_EXTRA + slugify(groupName);
70
+ setupDraggableContainer(body, key);
71
+ }
72
+ });
73
+ }
74
+
75
+ function disableDragAndDrop() {
76
+ const items = document.querySelectorAll('.sidebar .list-group-item[draggable="true"]');
77
+ items.forEach(item => {
78
+ item.removeAttribute('draggable');
79
+ item.removeEventListener('dragstart', handleDragStart);
80
+ item.removeEventListener('dragend', handleDragEnd);
81
+ item.removeEventListener('dragover', handleDragOver);
82
+ item.removeEventListener('drop', handleDrop);
83
+ });
84
+
85
+ // Hide drop indicator
86
+ if (dropIndicator) {
87
+ dropIndicator.style.display = 'none';
88
+ if (dropIndicator.parentNode) {
89
+ dropIndicator.parentNode.removeChild(dropIndicator);
90
+ }
91
+ }
92
+ }
93
+
94
+ function setupDraggableContainer(container, storageKey) {
95
+ const items = container.querySelectorAll(':scope > .list-group-item');
96
+
97
+ items.forEach(item => {
98
+ // Skip accordion buttons - they're not reorderable
99
+ if (item.classList.contains('accordion-button')) return;
100
+
101
+ item.setAttribute('draggable', 'true');
102
+ item.dataset.storageKey = storageKey;
103
+
104
+ item.addEventListener('dragstart', handleDragStart);
105
+ item.addEventListener('dragend', handleDragEnd);
106
+ item.addEventListener('dragover', handleDragOver);
107
+ item.addEventListener('drop', handleDrop);
108
+ });
109
+
110
+ // Add event listeners to container for drag events
111
+ container.addEventListener('dragover', handleContainerDragOver);
112
+ container.addEventListener('drop', handleContainerDrop);
113
+ }
114
+
115
+ function handleDragStart(e) {
116
+ draggedElement = this;
117
+ this.classList.add('dragging');
118
+ e.dataTransfer.effectAllowed = 'move';
119
+ e.dataTransfer.setData('text/plain', ''); // Required for Firefox
120
+
121
+ // Add drop indicator to DOM
122
+ if (dropIndicator && this.parentNode) {
123
+ this.parentNode.appendChild(dropIndicator);
124
+ }
125
+ }
126
+
127
+ function handleDragEnd(e) {
128
+ this.classList.remove('dragging');
129
+
130
+ // Hide drop indicator
131
+ if (dropIndicator) {
132
+ dropIndicator.style.display = 'none';
133
+ }
134
+
135
+ // Save new order
136
+ if (draggedElement) {
137
+ saveOrder(draggedElement.parentNode, draggedElement.dataset.storageKey);
138
+ }
139
+
140
+ draggedElement = null;
141
+ }
142
+
143
+ function handleDragOver(e) {
144
+ e.preventDefault();
145
+ e.dataTransfer.dropEffect = 'move';
146
+
147
+ if (!draggedElement || draggedElement === this) return;
148
+ if (draggedElement.dataset.storageKey !== this.dataset.storageKey) return;
149
+
150
+ const rect = this.getBoundingClientRect();
151
+ const midY = rect.top + rect.height / 2;
152
+
153
+ // Show drop indicator
154
+ if (dropIndicator) {
155
+ dropIndicator.style.display = 'block';
156
+ if (e.clientY < midY) {
157
+ this.parentNode.insertBefore(dropIndicator, this);
158
+ } else {
159
+ this.parentNode.insertBefore(dropIndicator, this.nextSibling);
160
+ }
161
+ }
162
+ }
163
+
164
+ function handleContainerDragOver(e) {
165
+ e.preventDefault();
166
+ }
167
+
168
+ function handleDrop(e) {
169
+ e.preventDefault();
170
+ e.stopPropagation();
171
+
172
+ if (!draggedElement || draggedElement === this) return;
173
+ if (draggedElement.dataset.storageKey !== this.dataset.storageKey) return;
174
+
175
+ const rect = this.getBoundingClientRect();
176
+ const midY = rect.top + rect.height / 2;
177
+
178
+ if (e.clientY < midY) {
179
+ this.parentNode.insertBefore(draggedElement, this);
180
+ } else {
181
+ this.parentNode.insertBefore(draggedElement, this.nextSibling);
182
+ }
183
+ }
184
+
185
+ function handleContainerDrop(e) {
186
+ e.preventDefault();
187
+ // Item drops are handled by individual items
188
+ }
189
+
190
+ function saveOrder(container, storageKey) {
191
+ if (!container || !storageKey) return;
192
+
193
+ const items = container.querySelectorAll(':scope > .list-group-item[data-url-name]');
194
+ const order = Array.from(items).map(item => item.dataset.urlName);
195
+
196
+ try {
197
+ localStorage.setItem(storageKey, JSON.stringify(order));
198
+ } catch (e) {
199
+ console.warn('Could not save sidebar order:', e);
200
+ }
201
+ }
202
+
203
+ function restoreOrder() {
204
+ // Restore auto items order
205
+ const autoContainer = document.getElementById('sidebarAutoItems') ||
206
+ document.querySelector('.sidebar .list-group');
207
+ if (autoContainer) {
208
+ restoreContainerOrder(autoContainer, STORAGE_KEY_AUTO);
209
+ }
210
+
211
+ // Restore extra group items order
212
+ const accordionBodies = document.querySelectorAll('.sidebar .accordion-body');
213
+ accordionBodies.forEach(body => {
214
+ const groupName = body.dataset.groupName || body.closest('.accordion-item')?.querySelector('.accordion-button span')?.textContent?.trim();
215
+ if (groupName) {
216
+ const key = STORAGE_KEY_PREFIX_EXTRA + slugify(groupName);
217
+ restoreContainerOrder(body, key);
218
+ }
219
+ });
220
+
221
+ // Mark as restored
222
+ window._sidebarOrderRestored = true;
223
+ }
224
+
225
+ function restoreContainerOrder(container, storageKey) {
226
+ let savedOrder;
227
+ try {
228
+ const saved = localStorage.getItem(storageKey);
229
+ if (!saved) return; // No saved order, use default
230
+ savedOrder = JSON.parse(saved);
231
+ } catch (e) {
232
+ return; // Invalid JSON, use default
233
+ }
234
+
235
+ if (!Array.isArray(savedOrder) || savedOrder.length === 0) return;
236
+
237
+ const items = container.querySelectorAll(':scope > .list-group-item[data-url-name]');
238
+ const itemMap = new Map();
239
+ items.forEach(item => {
240
+ itemMap.set(item.dataset.urlName, item);
241
+ });
242
+
243
+ // Reorder based on saved order
244
+ savedOrder.forEach(urlName => {
245
+ const item = itemMap.get(urlName);
246
+ if (item) {
247
+ container.appendChild(item);
248
+ itemMap.delete(urlName);
249
+ }
250
+ });
251
+
252
+ // Append any remaining items (new items not in saved order)
253
+ itemMap.forEach(item => {
254
+ container.appendChild(item);
255
+ });
256
+ }
257
+
258
+ function slugify(text) {
259
+ return text
260
+ .toString()
261
+ .toLowerCase()
262
+ .trim()
263
+ .replace(/\s+/g, '-')
264
+ .replace(/[^\w\-]+/g, '')
265
+ .replace(/\-\-+/g, '-');
266
+ }
267
+ })();
@@ -0,0 +1,58 @@
1
+ (function() {
2
+ document.addEventListener('DOMContentLoaded', () => {
3
+ const indicator = document.getElementById('sidebarThemeIndicator');
4
+ const popup = document.getElementById('sidebarThemePopup');
5
+ const options = document.querySelectorAll('.theme-option-circle');
6
+ const arrow = document.getElementById('sidebarThemeArrow');
7
+
8
+ if (!indicator || !popup) return;
9
+
10
+ // Toggle Popup
11
+ indicator.addEventListener('click', (e) => {
12
+ e.stopPropagation();
13
+ const isOpen = popup.classList.toggle('show');
14
+ indicator.classList.toggle('open', isOpen);
15
+ if (arrow) arrow.classList.toggle('visible', isOpen);
16
+ });
17
+
18
+ // Close when clicking outside
19
+ document.addEventListener('click', (e) => {
20
+ if (!popup.contains(e.target) && e.target !== indicator) {
21
+ popup.classList.remove('show');
22
+ indicator.classList.remove('open');
23
+ if (arrow) arrow.classList.remove('visible');
24
+ }
25
+ });
26
+
27
+ // Theme selection
28
+ options.forEach(opt => {
29
+ opt.addEventListener('click', () => {
30
+ const theme = opt.getAttribute('data-theme');
31
+ if (window.setTheme) {
32
+ window.setTheme(theme);
33
+ updateCurrentThemeIndicator(theme);
34
+ popup.classList.remove('show');
35
+ indicator.classList.remove('open');
36
+ if (arrow) arrow.classList.remove('visible');
37
+ }
38
+ });
39
+ });
40
+
41
+ function updateCurrentThemeIndicator(theme) {
42
+ // Update the main indicator circle's color class
43
+ indicator.className = 'current-theme-indicator theme-circle-' + (theme || 'light');
44
+
45
+ // Highlight active option in popup
46
+ options.forEach(opt => {
47
+ opt.classList.remove('active');
48
+ if (opt.getAttribute('data-theme') === (theme || 'light')) {
49
+ opt.classList.add('active');
50
+ }
51
+ });
52
+ }
53
+
54
+ // Initialize indicator color
55
+ const savedTheme = localStorage.getItem('appTheme') || 'light';
56
+ updateCurrentThemeIndicator(savedTheme);
57
+ });
58
+ })();
@@ -47,20 +47,31 @@
47
47
  white-space: nowrap;
48
48
  }
49
49
 
50
- .sidebar.collapsed .accordion-button::after {
50
+ /* .sidebar.collapsed .accordion-button::after {
51
51
  display: none !important;
52
+ } */
53
+
54
+ /* Hide accordion body content when sidebar is collapsed */
55
+ /* .sidebar.collapsed .accordion-collapse {
56
+ display: none !important;
57
+ } */
58
+
59
+ /* Also hide any expanded accordion body items text */
60
+ .sidebar.collapsed .accordion-body .list-group-item span {
61
+ opacity: 0;
62
+ visibility: hidden;
63
+ width: 0;
52
64
  }
53
65
 
54
- .sidebar-ghost {
66
+ /* .sidebar-ghost {
55
67
  display: none;
56
- width: 52px;
57
68
  flex-shrink: 0;
58
- }
69
+ } */
59
70
 
60
71
  @media (max-width: 1100px) {
61
- .sidebar-ghost {
62
- display: block;
63
- }
72
+ /* .sidebar-ghost {
73
+ display: none !important;
74
+ } */
64
75
 
65
76
  .sidebar {
66
77
  position: fixed;
@@ -74,7 +85,9 @@
74
85
  }
75
86
 
76
87
  .sidebar.collapsed {
77
- width: 52px !important;
88
+ width: 0 !important; /* Completely hide when collapsed on mobile */
89
+ border: none !important;
90
+ overflow: hidden !important;
78
91
  right: 0;
79
92
  position: fixed;
80
93
  }
@@ -108,6 +121,7 @@
108
121
  color: var(--primal) !important;
109
122
  font-weight: 700 !important;
110
123
  box-shadow: 0 4px 12px rgba(35, 99, 195, 0.08) !important;
124
+ transform: translateX(-4px);
111
125
  }
112
126
 
113
127
  .sidebar .list-group-item i,
@@ -203,4 +217,16 @@
203
217
  color: white;
204
218
  padding: 8px 12px;
205
219
  border-radius: 5px;
220
+ }
221
+
222
+ .sidebar-toolbar {
223
+ padding: 10px;
224
+ position: absolute;
225
+ bottom: 0;
226
+ left: 0;
227
+ width: 100%;
228
+ background: transparent;
229
+ pointer-events: none; /* Let clicks pass through to content if needed, but we override for items */
230
+ display: flex;
231
+ justify-content: flex-end
206
232
  }
@@ -66,40 +66,24 @@ document.addEventListener("DOMContentLoaded", function () {
66
66
  deinitializeTooltips();
67
67
  }
68
68
 
69
- // Only update session if screen width is >= 1100px
70
- if (window.innerWidth >= 1100) {
71
- fetch(toggleUrl, {
72
- method: "POST",
73
- headers: {
74
- "X-CSRFToken": csrfToken,
75
- "Content-Type": "application/x-www-form-urlencoded",
76
- },
77
- body: `collapsed=${isCollapsed}`
78
- }).then(response => response.json())
79
- .then(data => {
80
- if (data.status === "success") {
81
- isSessionCollapsed = isCollapsed; // Update local state
82
- }
83
- }).catch(error => console.error("Error updating sidebar state:", error));
84
- }
85
-
86
- setTimeout(triggerAutoscale, 250);
69
+ // Update session
70
+ fetch(toggleUrl, {
71
+ method: "POST",
72
+ headers: {
73
+ "X-CSRFToken": csrfToken,
74
+ "Content-Type": "application/x-www-form-urlencoded",
75
+ },
76
+ body: `collapsed=${isCollapsed}`
77
+ }).then(response => response.json())
78
+ .then(data => {
79
+ if (data.status === "success") {
80
+ isSessionCollapsed = isCollapsed; // Update local state
81
+ }
82
+ }).catch(error => console.error("Error updating sidebar state:", error));
87
83
  });
88
84
  }
89
85
 
90
- // Proactively hide tooltips when any sidebar click occurs
91
- // This fixes the "sticking to top of screen" glitch during transitions
92
- sidebar.addEventListener("click", function (event) {
93
- // Find all tooltips in the sidebar and dispose them immediately
94
- // This ensures they are completely removed from the DOM before any transition
95
- const sidebarItems = sidebar.querySelectorAll(".list-group-item, .accordion-button");
96
- sidebarItems.forEach(item => {
97
- if (item._tooltip) {
98
- item._tooltip.dispose();
99
- delete item._tooltip;
100
- }
101
- });
102
- });
86
+
103
87
  });
104
88
 
105
89
  // Close sidebar when clicking outside (only for small screens)
@@ -154,12 +138,3 @@ function deinitializeTooltips() {
154
138
  }
155
139
  });
156
140
  }
157
-
158
- function triggerAutoscale() {
159
- if (window.innerWidth > 1100) {
160
- const autoscaleButton = document.querySelector('.modebar-btn[data-title="Reset axes"]');
161
- if (autoscaleButton) {
162
- autoscaleButton.click();
163
- }
164
- }
165
- }
@@ -0,0 +1,51 @@
1
+ /* --- Blue Theme (Aqua - Formerly Light) --- */
2
+ :root.theme-blue {
3
+ --title: #1e4f99;
4
+ --body: #f6f7f98b;
5
+ --htitle: #256cb2;
6
+ --hbody: #dee8ffdb;
7
+ --table-row: #e7f1fb;
8
+ --table-row-hover: #dfeaf5;
9
+ --primal: #2363c3;
10
+ --primal_dark: #1e4f99;
11
+ --primal-rgb: 35, 99, 195;
12
+ --btn-primary-shadow: rgba(35, 99, 195, 0.4);
13
+
14
+ /* Login Theme Variables */
15
+ --bg-gradient: linear-gradient(135deg, #f6f7f9 0%, #dee8ff 100%);
16
+ --right-bg: var(--title);
17
+ --primary-color: var(--primal);
18
+
19
+ /* Bootstrap Overrides */
20
+ --bs-primary: var(--primal);
21
+ --bs-primary-rgb: var(--primal-rgb);
22
+ --bs-btn-bg: var(--primal);
23
+ --bs-btn-border-color: var(--primal);
24
+ --bs-btn-hover-bg: var(--primal_dark);
25
+ --bs-btn-hover-border-color: var(--primal_dark);
26
+ --bs-link-color: var(--primal);
27
+ --bs-link-hover-color: var(--primal_dark);
28
+ }
29
+ :root.theme-blue .titlebar {
30
+ background: linear-gradient(90deg, #ffffff 10%, #e7f1fb 90%) !important;
31
+ }
32
+ :root.theme-blue #sidebar {
33
+ background: linear-gradient(180deg, #ffffff 10%, #e7f1fb 100%) !important;
34
+ border-left: 1px solid #dfeaf5 !important;
35
+ }
36
+
37
+ :root.theme-blue .page .right {
38
+ background: var(--htitle) !important; /* Darker logo container */
39
+ box-shadow: 0 8px 32px 0 rgba(0, 0, 0, 0.3) !important;
40
+ color: #e2e8f0 !important;
41
+ }
42
+
43
+ /* Dropdown & Button Overrides for Blue */
44
+ :root.theme-blue .dropdown-item:hover {
45
+ background-color: rgba(35, 99, 195, 0.08) !important;
46
+ color: #1e4f99 !important;
47
+ }
48
+ :root.theme-blue .titlebar .btn-light:hover {
49
+ background-color: rgba(35, 99, 195, 0.08) !important;
50
+ color: #1e4f99 !important;
51
+ }