fix(ui): stop canvas top bar :has() rule from blocking chart pages

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Andras Bacsai
2026-10-23 22:07:37 +02:00
co-authored by Claude Opus 5.5
parent 582399c382
commit adacb764f9
4 changed files with 12 additions and 5 deletions
+3
View File
@@ -135,3 +135,6 @@
## Session writes are last-writer-wins
- Laravel saves the whole session payload at the end of every request, and pages run concurrent `wire:poll` requests. A value that one request changes can be overwritten by a request that started earlier. `KeepConcurrentTeamSwitch` protects `currentTeam`; protect any new session value that changes mid-session the same way, or keep it out of the session.
## Keep `:has()` off page-wide ancestors
- A `:has()` on `html`, `body`, `.app-shell`, or a sibling of `<main>` (for example `html:has(.x) .y`) makes Chrome restyle the page on every DOM change. Chart libraries read layout many times per render, so one ApexCharts render took ~400 ms and blocked navigation. Use a class set by the Blade layout instead, and keep `:has()` on small, local subjects.
+4 -2
View File
@@ -6441,12 +6441,14 @@ html.dark.is-scrolled:not([data-nav-style="floating"]) .app-topbar > div:not(.ap
background-image: none;
}
html:not([data-nav-style="floating"]):has(.app-main-full :is([data-ec-root], .cv-root)) .app-topbar {
/* A layout class, not html:has(): an html-level :has() restyles the whole
page on every DOM change, which made chart renders take seconds. */
html:not([data-nav-style="floating"]) .app-shell-canvas > .app-topbar {
background-color: transparent;
backdrop-filter: none;
}
html:not([data-nav-style="floating"]):has(.app-main-full :is([data-ec-root], .cv-root)) .app-topbar > div:not(.app-topbar-brand) {
html:not([data-nav-style="floating"]) .app-shell-canvas > .app-topbar > div:not(.app-topbar-brand) {
border-bottom-color: transparent;
}
}
+1 -1
View File
@@ -34,7 +34,7 @@
}
}" @open-global-search.window="open = false" @page-width-changed.window="pageWidth = $event.detail"
:style="{ '--sidebar-w': collapsed ? '4rem' : '14rem' }" x-cloak
@class(['app-shell dark:text-inherit text-black', 'flex h-dvh flex-col' => $fullBleed ?? false])>
@class(['app-shell dark:text-inherit text-black', 'app-shell-canvas flex h-dvh flex-col' => $fullBleed ?? false])>
{{-- ============ DESKTOP TOP BAR ============ --}}
<header
x-data="{ resourceActionsOpen: false }"
@@ -42,7 +42,8 @@
if (!el) { return; }
const cssVar = name => getComputedStyle(document.documentElement).getPropertyValue(name).trim();
const accent = () => cssVar('--chart-status-3xx') || '#3b82f6';
const gridColor = () => cssVar('--chart-geo-empty') || 'rgba(128,128,128,0.15)';
const compactNumber = new Intl.NumberFormat(undefined, { notation: 'compact', maximumFractionDigits: 1 });
const gridColor = () =>cssVar('--chart-geo-empty') || 'rgba(128,128,128,0.15)';
// `24h` buckets are hourly, `7d`/`30d` daily — pick a matching axis/tooltip format.
const timeFormat = range => (range === '24h' ? 'HH:mm' : 'dd MMM');
@@ -84,7 +85,8 @@
minWidth: 28,
maxWidth: 28,
style: { colors: textColor },
formatter: value => Math.round(value).toLocaleString(),
// Compact (1K, 1.2M) so large counts fit the fixed label width.
formatter: value => compactNumber.format(Math.round(value)),
},
},
grid: {