Spaces:
Running
Running
User commited on
Commit ·
e184579
1
Parent(s): 234e219
Deploy theme persistence and navigation fix
Browse files
TaskTrackingSystem.WebApp/Components/App.razor
CHANGED
|
@@ -325,7 +325,7 @@
|
|
| 325 |
<script src="https://cdn.tailwindcss.com"></script>
|
| 326 |
<link rel="stylesheet" href="TaskTrackingSystem.WebApp.styles.css" />
|
| 327 |
<link rel="stylesheet" href="app.css" />
|
| 328 |
-
<script src="theme-toggle.js?v=20260720-
|
| 329 |
<script src="https://code.highcharts.com/highcharts.js"></script>
|
| 330 |
<script src="https://code.highcharts.com/gantt/modules/gantt.js"></script>
|
| 331 |
<script src="https://unpkg.com/lucide@latest"></script>
|
|
@@ -544,65 +544,6 @@
|
|
| 544 |
initFlatpickr();
|
| 545 |
}
|
| 546 |
}
|
| 547 |
-
const themePreferenceStorageKey = 'tts-theme';
|
| 548 |
-
const normalizeThemePreference = theme =>
|
| 549 |
-
theme === 'dark' || theme === 'light' ? theme : 'light';
|
| 550 |
-
|
| 551 |
-
window.themePreference = {
|
| 552 |
-
apply(theme) {
|
| 553 |
-
const normalizedTheme = normalizeThemePreference(theme);
|
| 554 |
-
const isDark = normalizedTheme === 'dark';
|
| 555 |
-
const root = document.documentElement;
|
| 556 |
-
root.classList.toggle('dark', isDark);
|
| 557 |
-
root.dataset.theme = normalizedTheme;
|
| 558 |
-
if (document.body) {
|
| 559 |
-
document.body.classList.toggle('dark', isDark);
|
| 560 |
-
document.body.dataset.theme = normalizedTheme;
|
| 561 |
-
}
|
| 562 |
-
try {
|
| 563 |
-
localStorage.setItem(themePreferenceStorageKey, normalizedTheme);
|
| 564 |
-
} catch {
|
| 565 |
-
}
|
| 566 |
-
return isDark;
|
| 567 |
-
},
|
| 568 |
-
init() {
|
| 569 |
-
let theme = 'light';
|
| 570 |
-
try {
|
| 571 |
-
theme = normalizeThemePreference(localStorage.getItem(themePreferenceStorageKey));
|
| 572 |
-
} catch {
|
| 573 |
-
}
|
| 574 |
-
return this.apply(theme);
|
| 575 |
-
},
|
| 576 |
-
toggle() {
|
| 577 |
-
const currentTheme = document.documentElement.dataset.theme ||
|
| 578 |
-
(document.documentElement.classList.contains('dark') ? 'dark' : 'light');
|
| 579 |
-
return this.apply(currentTheme === 'dark' ? 'light' : 'dark');
|
| 580 |
-
}
|
| 581 |
-
};
|
| 582 |
-
window.updateTaskifyThemeControls = function () {
|
| 583 |
-
const isDark = document.documentElement.dataset.theme === 'dark' ||
|
| 584 |
-
document.documentElement.classList.contains('dark');
|
| 585 |
-
const title = isDark ? 'Switch to light mode' : 'Switch to dark mode';
|
| 586 |
-
const iconName = isDark ? 'sun' : 'moon';
|
| 587 |
-
document.querySelectorAll('[data-theme-toggle]').forEach(button => {
|
| 588 |
-
button.setAttribute('aria-pressed', String(isDark));
|
| 589 |
-
button.setAttribute('aria-label', title);
|
| 590 |
-
button.setAttribute('title', title);
|
| 591 |
-
const icon = button.querySelector('[data-lucide]');
|
| 592 |
-
if (icon) {
|
| 593 |
-
icon.setAttribute('data-lucide', iconName);
|
| 594 |
-
}
|
| 595 |
-
});
|
| 596 |
-
initIcons();
|
| 597 |
-
};
|
| 598 |
-
window.toggleTaskifyThemeButton = function () {
|
| 599 |
-
if (!window.themePreference) {
|
| 600 |
-
return false;
|
| 601 |
-
}
|
| 602 |
-
window.themePreference.toggle();
|
| 603 |
-
window.updateTaskifyThemeControls();
|
| 604 |
-
return false;
|
| 605 |
-
};
|
| 606 |
function downloadFile(filename, contentType, content) {
|
| 607 |
const file = new Blob([content], {type: contentType});
|
| 608 |
const exportUrl = URL.createObjectURL(file);
|
|
@@ -642,9 +583,6 @@
|
|
| 642 |
}
|
| 643 |
}
|
| 644 |
function refreshClientEnhancements() {
|
| 645 |
-
if (window.themePreference && typeof window.themePreference.init === 'function') {
|
| 646 |
-
window.themePreference.init();
|
| 647 |
-
}
|
| 648 |
if (window.updateTaskifyThemeControls) {
|
| 649 |
window.updateTaskifyThemeControls();
|
| 650 |
}
|
|
|
|
| 325 |
<script src="https://cdn.tailwindcss.com"></script>
|
| 326 |
<link rel="stylesheet" href="TaskTrackingSystem.WebApp.styles.css" />
|
| 327 |
<link rel="stylesheet" href="app.css" />
|
| 328 |
+
<script src="theme-toggle.js?v=20260720-3" defer></script>
|
| 329 |
<script src="https://code.highcharts.com/highcharts.js"></script>
|
| 330 |
<script src="https://code.highcharts.com/gantt/modules/gantt.js"></script>
|
| 331 |
<script src="https://unpkg.com/lucide@latest"></script>
|
|
|
|
| 544 |
initFlatpickr();
|
| 545 |
}
|
| 546 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 547 |
function downloadFile(filename, contentType, content) {
|
| 548 |
const file = new Blob([content], {type: contentType});
|
| 549 |
const exportUrl = URL.createObjectURL(file);
|
|
|
|
| 583 |
}
|
| 584 |
}
|
| 585 |
function refreshClientEnhancements() {
|
|
|
|
|
|
|
|
|
|
| 586 |
if (window.updateTaskifyThemeControls) {
|
| 587 |
window.updateTaskifyThemeControls();
|
| 588 |
}
|
TaskTrackingSystem.WebApp/Components/Layout/MainLayout.razor
CHANGED
|
@@ -254,21 +254,6 @@
|
|
| 254 |
var menus = await MenuAuthorization.GetUserMenusAsync(user);
|
| 255 |
dashboardHref = ResolveDashboardHref(menus);
|
| 256 |
var allowed = MenuAuthorization.IsRouteAllowed(user, relativePath);
|
| 257 |
-
Console.WriteLine($"[DEBUG MainLayout] User: {user.Identity?.Name}, Path: {relativePath}, Allowed: {allowed}");
|
| 258 |
-
if (menus != null)
|
| 259 |
-
{
|
| 260 |
-
foreach (var m in menus)
|
| 261 |
-
{
|
| 262 |
-
Console.WriteLine($" Menu: {m.MenuCode} (Url: {m.MenuUrl})");
|
| 263 |
-
if (m.SubMenus != null)
|
| 264 |
-
{
|
| 265 |
-
foreach (var s in m.SubMenus)
|
| 266 |
-
{
|
| 267 |
-
Console.WriteLine($" SubMenu: {s.MenuCode} (Url: {s.MenuUrl})");
|
| 268 |
-
}
|
| 269 |
-
}
|
| 270 |
-
}
|
| 271 |
-
}
|
| 272 |
isAuthorizedPage = allowed;
|
| 273 |
await InvokeAsync(StateHasChanged);
|
| 274 |
}
|
|
|
|
| 254 |
var menus = await MenuAuthorization.GetUserMenusAsync(user);
|
| 255 |
dashboardHref = ResolveDashboardHref(menus);
|
| 256 |
var allowed = MenuAuthorization.IsRouteAllowed(user, relativePath);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 257 |
isAuthorizedPage = allowed;
|
| 258 |
await InvokeAsync(StateHasChanged);
|
| 259 |
}
|
TaskTrackingSystem.WebApp/MenuAuthorizationService.cs
CHANGED
|
@@ -171,8 +171,7 @@ public class MenuAuthorizationService
|
|
| 171 |
|
| 172 |
if (_sessionState.CachedAccessRoleId == roleKey && _sessionState.CachedAccessItems != null)
|
| 173 |
{
|
| 174 |
-
|
| 175 |
-
return LoadAccessItemsWithVersionCheckAsync(user, roleKey);
|
| 176 |
}
|
| 177 |
|
| 178 |
return LoadAccessItemsAsync(user, roleKey);
|
|
@@ -200,7 +199,7 @@ public class MenuAuthorizationService
|
|
| 200 |
|
| 201 |
if (_sessionState.CachedAccessRoleId == roleKey && _sessionState.CachedAccessCodes != null)
|
| 202 |
{
|
| 203 |
-
return
|
| 204 |
}
|
| 205 |
|
| 206 |
return LoadAccessCodesAsync(user, roleKey);
|
|
|
|
| 171 |
|
| 172 |
if (_sessionState.CachedAccessRoleId == roleKey && _sessionState.CachedAccessItems != null)
|
| 173 |
{
|
| 174 |
+
return Task.FromResult(_sessionState.CachedAccessItems);
|
|
|
|
| 175 |
}
|
| 176 |
|
| 177 |
return LoadAccessItemsAsync(user, roleKey);
|
|
|
|
| 199 |
|
| 200 |
if (_sessionState.CachedAccessRoleId == roleKey && _sessionState.CachedAccessCodes != null)
|
| 201 |
{
|
| 202 |
+
return Task.FromResult(_sessionState.CachedAccessCodes);
|
| 203 |
}
|
| 204 |
|
| 205 |
return LoadAccessCodesAsync(user, roleKey);
|
TaskTrackingSystem.WebApp/wwwroot/app.css
CHANGED
|
@@ -495,9 +495,7 @@ html.dark .flatpickr-day.endRange {
|
|
| 495 |
--app-sidebar-width: 18rem;
|
| 496 |
display: flex;
|
| 497 |
min-height: 100vh;
|
| 498 |
-
background:
|
| 499 |
-
linear-gradient(180deg, rgba(37, 99, 235, 0.035), transparent 18rem),
|
| 500 |
-
var(--app-bg);
|
| 501 |
color: var(--text-primary);
|
| 502 |
overflow: hidden;
|
| 503 |
}
|
|
@@ -520,9 +518,7 @@ html.dark .flatpickr-day.endRange {
|
|
| 520 |
inset: 0;
|
| 521 |
pointer-events: none;
|
| 522 |
content: "";
|
| 523 |
-
background:
|
| 524 |
-
radial-gradient(circle at top left, rgba(37, 99, 235, 0.22), transparent 18rem),
|
| 525 |
-
linear-gradient(180deg, rgba(255, 255, 255, 0.04), transparent 42%);
|
| 526 |
}
|
| 527 |
|
| 528 |
.app-sidebar > * {
|
|
@@ -545,7 +541,7 @@ html.dark .flatpickr-day.endRange {
|
|
| 545 |
align-items: center;
|
| 546 |
justify-content: center;
|
| 547 |
border-radius: var(--radius-lg);
|
| 548 |
-
background:
|
| 549 |
color: #FFFFFF;
|
| 550 |
box-shadow: 0 10px 28px rgba(37, 99, 235, 0.28);
|
| 551 |
}
|
|
@@ -1070,9 +1066,7 @@ html.dark .form-select {
|
|
| 1070 |
PROFESSIONAL UI REFRESH
|
| 1071 |
========================================== */
|
| 1072 |
body {
|
| 1073 |
-
background:
|
| 1074 |
-
linear-gradient(180deg, rgba(15, 118, 110, 0.035), transparent 22rem),
|
| 1075 |
-
var(--app-bg);
|
| 1076 |
}
|
| 1077 |
|
| 1078 |
::selection {
|
|
@@ -1081,26 +1075,19 @@ body {
|
|
| 1081 |
}
|
| 1082 |
|
| 1083 |
.app-shell {
|
| 1084 |
-
background:
|
| 1085 |
-
linear-gradient(180deg, rgba(15, 118, 110, 0.045), transparent 19rem),
|
| 1086 |
-
radial-gradient(circle at 100% 0, rgba(180, 83, 9, 0.05), transparent 18rem),
|
| 1087 |
-
var(--app-bg);
|
| 1088 |
}
|
| 1089 |
|
| 1090 |
.app-shell .app-sidebar {
|
| 1091 |
-
background:
|
| 1092 |
-
linear-gradient(180deg, rgba(255, 255, 255, 0.035), transparent 36%),
|
| 1093 |
-
var(--sidebar-bg);
|
| 1094 |
}
|
| 1095 |
|
| 1096 |
.app-sidebar::before {
|
| 1097 |
-
background:
|
| 1098 |
-
linear-gradient(90deg, rgba(94, 234, 212, 0.14), transparent 0.45rem),
|
| 1099 |
-
radial-gradient(circle at top left, rgba(15, 118, 110, 0.20), transparent 17rem);
|
| 1100 |
}
|
| 1101 |
|
| 1102 |
.app-sidebar-logo {
|
| 1103 |
-
background:
|
| 1104 |
box-shadow: 0 12px 28px rgba(15, 118, 110, 0.24);
|
| 1105 |
}
|
| 1106 |
|
|
@@ -1344,15 +1331,11 @@ html.dark .app-content {
|
|
| 1344 |
}
|
| 1345 |
|
| 1346 |
html.dark body {
|
| 1347 |
-
background:
|
| 1348 |
-
linear-gradient(180deg, rgba(94, 234, 212, 0.04), transparent 22rem),
|
| 1349 |
-
var(--app-bg);
|
| 1350 |
}
|
| 1351 |
|
| 1352 |
html.dark .app-shell {
|
| 1353 |
-
background:
|
| 1354 |
-
linear-gradient(180deg, rgba(94, 234, 212, 0.045), transparent 18rem),
|
| 1355 |
-
var(--app-bg);
|
| 1356 |
}
|
| 1357 |
|
| 1358 |
html.dark main .bg-white,
|
|
@@ -1493,9 +1476,7 @@ body.tts-sidebar-open {
|
|
| 1493 |
gap: 1rem !important;
|
| 1494 |
min-width: 0 !important;
|
| 1495 |
width: 100% !important;
|
| 1496 |
-
background:
|
| 1497 |
-
linear-gradient(180deg, rgba(15, 118, 110, 0.035), transparent 14rem),
|
| 1498 |
-
var(--app-bg) !important;
|
| 1499 |
}
|
| 1500 |
|
| 1501 |
.app-shell .app-sidebar {
|
|
@@ -1507,9 +1488,7 @@ body.tts-sidebar-open {
|
|
| 1507 |
min-height: 100dvh !important;
|
| 1508 |
max-width: var(--app-sidebar-width) !important;
|
| 1509 |
transform: translateX(0) !important;
|
| 1510 |
-
background:
|
| 1511 |
-
linear-gradient(180deg, rgba(255, 255, 255, 0.035), transparent 36%),
|
| 1512 |
-
var(--sidebar-bg) !important;
|
| 1513 |
}
|
| 1514 |
|
| 1515 |
.app-main {
|
|
@@ -1569,9 +1548,7 @@ main :is(.rounded-xl.border, .rounded-lg.border, .surface-panel) {
|
|
| 1569 |
}
|
| 1570 |
|
| 1571 |
main :is(.rounded-xl.border.border-slate-200.bg-white, .rounded-lg.border.border-slate-200.bg-white) {
|
| 1572 |
-
background:
|
| 1573 |
-
linear-gradient(180deg, rgba(255, 255, 255, 0.72), rgba(255, 255, 255, 0)),
|
| 1574 |
-
var(--surface) !important;
|
| 1575 |
}
|
| 1576 |
|
| 1577 |
main :is(h2, h3) {
|
|
|
|
| 495 |
--app-sidebar-width: 18rem;
|
| 496 |
display: flex;
|
| 497 |
min-height: 100vh;
|
| 498 |
+
background: var(--app-bg);
|
|
|
|
|
|
|
| 499 |
color: var(--text-primary);
|
| 500 |
overflow: hidden;
|
| 501 |
}
|
|
|
|
| 518 |
inset: 0;
|
| 519 |
pointer-events: none;
|
| 520 |
content: "";
|
| 521 |
+
background: transparent;
|
|
|
|
|
|
|
| 522 |
}
|
| 523 |
|
| 524 |
.app-sidebar > * {
|
|
|
|
| 541 |
align-items: center;
|
| 542 |
justify-content: center;
|
| 543 |
border-radius: var(--radius-lg);
|
| 544 |
+
background: var(--brand-primary);
|
| 545 |
color: #FFFFFF;
|
| 546 |
box-shadow: 0 10px 28px rgba(37, 99, 235, 0.28);
|
| 547 |
}
|
|
|
|
| 1066 |
PROFESSIONAL UI REFRESH
|
| 1067 |
========================================== */
|
| 1068 |
body {
|
| 1069 |
+
background: var(--app-bg);
|
|
|
|
|
|
|
| 1070 |
}
|
| 1071 |
|
| 1072 |
::selection {
|
|
|
|
| 1075 |
}
|
| 1076 |
|
| 1077 |
.app-shell {
|
| 1078 |
+
background: var(--app-bg);
|
|
|
|
|
|
|
|
|
|
| 1079 |
}
|
| 1080 |
|
| 1081 |
.app-shell .app-sidebar {
|
| 1082 |
+
background: var(--sidebar-bg);
|
|
|
|
|
|
|
| 1083 |
}
|
| 1084 |
|
| 1085 |
.app-sidebar::before {
|
| 1086 |
+
background: transparent;
|
|
|
|
|
|
|
| 1087 |
}
|
| 1088 |
|
| 1089 |
.app-sidebar-logo {
|
| 1090 |
+
background: #0F766E;
|
| 1091 |
box-shadow: 0 12px 28px rgba(15, 118, 110, 0.24);
|
| 1092 |
}
|
| 1093 |
|
|
|
|
| 1331 |
}
|
| 1332 |
|
| 1333 |
html.dark body {
|
| 1334 |
+
background: var(--app-bg);
|
|
|
|
|
|
|
| 1335 |
}
|
| 1336 |
|
| 1337 |
html.dark .app-shell {
|
| 1338 |
+
background: var(--app-bg);
|
|
|
|
|
|
|
| 1339 |
}
|
| 1340 |
|
| 1341 |
html.dark main .bg-white,
|
|
|
|
| 1476 |
gap: 1rem !important;
|
| 1477 |
min-width: 0 !important;
|
| 1478 |
width: 100% !important;
|
| 1479 |
+
background: var(--app-bg) !important;
|
|
|
|
|
|
|
| 1480 |
}
|
| 1481 |
|
| 1482 |
.app-shell .app-sidebar {
|
|
|
|
| 1488 |
min-height: 100dvh !important;
|
| 1489 |
max-width: var(--app-sidebar-width) !important;
|
| 1490 |
transform: translateX(0) !important;
|
| 1491 |
+
background: var(--sidebar-bg) !important;
|
|
|
|
|
|
|
| 1492 |
}
|
| 1493 |
|
| 1494 |
.app-main {
|
|
|
|
| 1548 |
}
|
| 1549 |
|
| 1550 |
main :is(.rounded-xl.border.border-slate-200.bg-white, .rounded-lg.border.border-slate-200.bg-white) {
|
| 1551 |
+
background: var(--surface) !important;
|
|
|
|
|
|
|
| 1552 |
}
|
| 1553 |
|
| 1554 |
main :is(h2, h3) {
|
TaskTrackingSystem.WebApp/wwwroot/theme-toggle.js
CHANGED
|
@@ -56,9 +56,9 @@
|
|
| 56 |
}
|
| 57 |
|
| 58 |
function initTheme() {
|
| 59 |
-
let storedTheme =
|
| 60 |
try {
|
| 61 |
-
storedTheme = normalize(localStorage.getItem(storageKey));
|
| 62 |
} catch {
|
| 63 |
}
|
| 64 |
|
|
@@ -101,4 +101,8 @@
|
|
| 101 |
}
|
| 102 |
|
| 103 |
window.addEventListener("pageshow", updateControls);
|
|
|
|
|
|
|
|
|
|
|
|
|
| 104 |
})();
|
|
|
|
| 56 |
}
|
| 57 |
|
| 58 |
function initTheme() {
|
| 59 |
+
let storedTheme = currentTheme();
|
| 60 |
try {
|
| 61 |
+
storedTheme = normalize(localStorage.getItem(storageKey) || storedTheme);
|
| 62 |
} catch {
|
| 63 |
}
|
| 64 |
|
|
|
|
| 101 |
}
|
| 102 |
|
| 103 |
window.addEventListener("pageshow", updateControls);
|
| 104 |
+
|
| 105 |
+
if (window.Blazor && typeof window.Blazor.addEventListener === "function") {
|
| 106 |
+
window.Blazor.addEventListener("enhancedload", updateControls);
|
| 107 |
+
}
|
| 108 |
})();
|