0105d9f0ec
Three issues addressed:
1. IconGridSelect popup was clipped/mispositioned because the .panel
ancestor has backdrop-filter, which makes it the containing block
for position:fixed descendants (CSS spec gotcha). Added a tiny
portal action ($lib/portal) that re-parents the popup + backdrop
to document.body, and refreshed the popup styling to be Aurora-
native (solid surface, gradient active state, glass-strong search).
2. Always-visible top search bar: a sticky glass strip at the top of
every page with the search trigger (⌘K), theme cycler, locale
toggle, and a primary 'New tracker' gradient CTA — moved out of
the sidebar to free up rail space and make search reachable from
anywhere. The sidebar's inline search button is gone.
3. Navbar snapped to the mockup:
- Sidebar footer redone as a glass user-card (avatar gradient +
username + role + mint live chip + change-password / docs / logout
row beneath a hairline).
- Section labels above each nav group (Overview / Routing /
Operators / System) with a hairline rule that extends to the
edge — same rhythm as the dashboard mockup.
- Active nav link keeps the gradient bar + glass-elev background
+ inset highlight + soft outer glow.
i18n: nav.section* keys (en + ru), dashboard.newTracker reused for
the topbar CTA. Build clean.
36 lines
1.1 KiB
TypeScript
36 lines
1.1 KiB
TypeScript
/**
|
|
* Svelte action that re-parents a node to document.body (or any selector).
|
|
*
|
|
* Use this for popups / dropdowns / tooltips that rely on
|
|
* `position: fixed` positioning. Any ancestor with `backdrop-filter`,
|
|
* `transform`, `filter`, `perspective`, `contain: paint`, or
|
|
* `will-change: transform` becomes the containing block for fixed
|
|
* descendants — which silently breaks viewport-relative positioning.
|
|
*
|
|
* Portalling sidesteps that by detaching the node from the component
|
|
* tree and appending it to a target outside any such ancestor.
|
|
*
|
|
* Usage:
|
|
* <div use:portal>...</div> // → document.body
|
|
* <div use:portal={'#root'}>...</div> // → custom selector
|
|
*/
|
|
export type PortalTarget = string | HTMLElement;
|
|
|
|
export function portal(node: HTMLElement, target: PortalTarget = 'body') {
|
|
function attach(t: PortalTarget) {
|
|
const el = typeof t === 'string' ? document.querySelector(t) : t;
|
|
if (el instanceof HTMLElement) el.appendChild(node);
|
|
}
|
|
|
|
attach(target);
|
|
|
|
return {
|
|
update(newTarget: PortalTarget) {
|
|
attach(newTarget);
|
|
},
|
|
destroy() {
|
|
node.parentNode?.removeChild(node);
|
|
},
|
|
};
|
|
}
|