zik try dis

This commit is contained in:
firestarsdog
2026-09-09 01:45:06 -04:00
parent a33bec1ca4
commit a08065f282
4 changed files with 236 additions and 16 deletions
@@ -36,6 +36,7 @@
--glass-border-light: rgba(255, 255, 255, 0.2);
--glass-shadow: 0 8px 24px 0 rgba(0, 0, 0, 0.35);
--glass-blur: blur(4px);
--card-scroll-bg: rgba(22, 18, 38, 0.95);
--glass-text: #f3f2f8;
--glass-accent: #9d72ff;
@@ -105,6 +106,7 @@
--surface-container: rgba(255, 255, 255, 0.75);
--surface-container-high: rgba(255, 255, 255, 0.95);
--surface-container-low: rgba(240, 243, 252, 0.75);
--card-scroll-bg: rgba(245, 246, 252, 0.96);
--on-surface: #171526;
--on-surface-variant: #5f5b7d;
@@ -186,6 +188,8 @@ body {
pointer-events: none;
transform: translateZ(0);
will-change: transform;
isolation: isolate;
contain: strict;
}
#galaxy-bg::before {
@@ -204,7 +208,6 @@ body {
opacity: 0.5;
will-change: transform;
transform: translate3d(var(--gx-para-x), 0, 0);
animation: galaxy-drift-smooth 160s linear infinite;
}
#galaxy-bg::after {
@@ -221,7 +224,6 @@ body {
opacity: 0.6;
will-change: transform;
transform: translate3d(var(--gx-para-x), 0, 0);
animation: galaxy-drift-smooth 100s linear infinite;
}
#galaxy-bg .galaxy-hero {
@@ -234,18 +236,14 @@ body {
animation: galaxy-twinkle 6s ease-in-out infinite alternate;
}
@keyframes galaxy-drift-smooth {
from { transform: translate3d(0, 0, 0); }
to { transform: translate3d(0, -400px, 0); }
}
@keyframes galaxy-twinkle {
0%, 100% { opacity: 0.3; transform: scale(0.9); }
50% { opacity: 1; transform: scale(1.2); }
}
@media (prefers-reduced-motion: reduce) {
#galaxy-bg, #galaxy-bg::before, #galaxy-bg::after, #galaxy-bg .galaxy-hero {
#galaxy-bg, #galaxy-bg::before, #galaxy-bg::after, #galaxy-bg .galaxy-hero,
#galaxy-stars, #galaxy-stars .galaxy-hero {
animation: none !important;
}
}
@@ -306,6 +304,8 @@ ul { list-style: none; margin: 0; padding: 0; }
position: sticky;
top: 0;
z-index: var(--z-appbar);
transform: translateZ(0);
isolation: isolate;
}
.gx-appbar__pill {
@@ -513,7 +513,10 @@ ul { list-style: none; margin: 0; padding: 0; }
position: fixed;
bottom: calc(18px + env(safe-area-inset-bottom, 0px));
left: 50%;
transform: translateX(-50%);
transform: translateX(-50%) translateZ(0);
will-change: transform;
isolation: isolate;
contain: layout style;
z-index: 1000;
display: flex;
@@ -589,7 +592,81 @@ ul { list-style: none; margin: 0; padding: 0; }
box-shadow: var(--elev-1);
margin-bottom: var(--sp-4);
overflow: hidden;
transition: transform var(--motion-fast), box-shadow var(--motion-fast);
transition: transform var(--motion-fast), box-shadow var(--motion-fast), background-color 0.15s ease-out;
}
/* Surgical content-visibility for top-level non-collapsible cards */
.dh-card:not(.dh-stat),
.gx-content > div > .gx-card {
content-visibility: auto;
contain-intrinsic-size: 280px;
contain-intrinsic-size: auto 280px;
}
.dh-stat {
content-visibility: auto;
contain-intrinsic-size: 110px;
contain-intrinsic-size: auto 110px;
}
/* Disarm containment on collapsible sections and nested cards */
.gx-card:has(.gx-section__body),
.gx-card .gx-card,
.gx-tree-node .gx-card {
content-visibility: visible !important;
contain-intrinsic-size: none !important;
}
/* Velocity-Adaptive Glass: bypass blur on scrolling cards with contrast boost */
body.is-scrolling .gx-card,
body.is-scrolling .gx-tile {
backdrop-filter: none !important;
-webkit-backdrop-filter: none !important;
background: var(--card-scroll-bg) !important;
}
/* Layer 2: Celestial Starlight Canopy */
#galaxy-stars {
position: fixed;
inset: 0;
z-index: 20;
pointer-events: none;
overflow: hidden;
contain: strict;
transform: translateZ(0);
}
#galaxy-stars .galaxy-hero {
position: absolute;
border-radius: 50%;
background: radial-gradient(
circle,
rgba(255, 255, 255, 0.95) 0%,
rgba(157, 114, 255, 0.65) 35%,
rgba(77, 232, 232, 0.2) 65%,
transparent 100%
);
box-shadow:
0 0 8px rgba(157, 114, 255, 0.4),
0 0 3px rgba(255, 255, 255, 0.8);
mix-blend-mode: screen;
will-change: transform, opacity;
animation: galaxy-twinkle 6s ease-in-out infinite alternate;
}
/* Keep decorative animation out of modal backdrops and drawer content. */
body:has(.gx-scrim, .gx-underlay, .gx-drawer.open) #galaxy-stars {
display: none;
}
[data-theme="light"] #galaxy-stars {
opacity: 0.4;
}
[data-theme="light"] #galaxy-stars .galaxy-hero {
background: radial-gradient(circle at center, #7849e8 0%, #b38fff 60%, rgba(120, 73, 232, 0) 100%);
box-shadow: 0 0 4px rgba(120, 73, 232, 0.45), 0 0 8px rgba(77, 232, 232, 0.3);
mix-blend-mode: normal;
}
.gx-unit-note {
@@ -1459,6 +1536,9 @@ input[type="color"].gx-color {
.gx-fade-enter-active, .gx-fade-leave-active { transition: opacity var(--motion-base); }
.gx-fade-enter-from, .gx-fade-leave-to { opacity: 0; }
/* Keep the underlay (and star suppression) until the drawer finishes closing. */
.gx-underlay.gx-fade-leave-active { transition: opacity var(--motion-slow); }
.gx-slide-enter-active, .gx-slide-leave-active {
transition: transform var(--motion-base), opacity var(--motion-base);
}
@@ -34,6 +34,7 @@
<div id="galaxy-app" v-cloak>
<app-shell></app-shell>
</div>
<div id="galaxy-stars" aria-hidden="true"></div>
<!-- Snackbar for messages -->
<div id="snackbar_wrapper"></div>
<script type="module" src="/assets/mobile/js/app.js"></script>
@@ -90,17 +90,82 @@ app.mount("#galaxy-app")
initRouter()
// Disable card blur during document scrolling.
;(() => {
const bg = document.getElementById("galaxy-bg")
if (!bg) return
let timer = null
let scrollEnded = true
const touches = new Set()
const nativeScrollEnd = "onscrollend" in document
const body = document.body
const isModalEvent = (e) => {
const t = e.target
return t instanceof Element && t.closest(".gx-scrim, .gx-sheet, .gx-dialog, .gx-drawer") !== null
}
const setScrolling = (active) => {
if (active) {
if (!body.classList.contains("is-scrolling")) body.classList.add("is-scrolling")
} else if (!touches.size && body.classList.contains("is-scrolling")) {
body.classList.remove("is-scrolling")
}
}
const scheduleRestore = () => {
clearTimeout(timer)
timer = setTimeout(() => setScrolling(false), 120)
}
document.addEventListener("scroll", () => {
scrollEnded = false
setScrolling(true)
if (!nativeScrollEnd) scheduleRestore()
}, { passive: true })
document.addEventListener("scrollend", () => {
scrollEnded = true
clearTimeout(timer)
setScrolling(false)
}, { passive: true })
window.addEventListener("touchstart", (e) => {
if (isModalEvent(e)) return
for (const touch of e.changedTouches) touches.add(touch.identifier)
}, { passive: true })
const releaseTouches = (e) => {
for (const touch of e.changedTouches) touches.delete(touch.identifier)
if (scrollEnded) setScrolling(false)
else if (!nativeScrollEnd && !touches.size) scheduleRestore()
}
window.addEventListener("touchend", releaseTouches, { passive: true })
window.addEventListener("touchcancel", releaseTouches, { passive: true })
window.addEventListener("hashchange", () => {
scrollEnded = true
touches.clear()
clearTimeout(timer)
body.classList.remove("is-scrolling")
}, { passive: true })
})()
// Layer 2 Celestial Starlight Canopy Spawner
;(() => {
const container = document.getElementById("galaxy-stars") || document.getElementById("galaxy-bg")
if (!container) return
for (let i = 0; i < 14; i++) {
const s = document.createElement("i")
s.className = "galaxy-hero"
s.style.left = (Math.random() * 100).toFixed(2) + "%"
s.style.top = (Math.random() * 100).toFixed(2) + "%"
const inTopCanopy = Math.random() < 0.7
const topPercent = inTopCanopy ? Math.random() * 28 : Math.random() * 95
const leftPercent = inTopCanopy
? Math.random() * 96 + 2
: Math.random() < 0.5 ? Math.random() * 12 + 2 : Math.random() * 12 + 86
s.style.left = leftPercent.toFixed(2) + "%"
s.style.top = topPercent.toFixed(2) + "%"
s.style.animationDelay = (Math.random() * 4).toFixed(2) + "s"
const size = Math.random() > 0.6 ? 3 : 2
const size = Math.random() > 0.5 ? 6 : 4
s.style.width = s.style.height = size + "px"
bg.appendChild(s)
container.appendChild(s)
}
})()
@@ -538,6 +538,80 @@ def test_ui_mobile_polish_regressions():
assert 'tr("Longitudinal Maneuver Mode")' not in c4_developer
@pytest.mark.parametrize("native_scrollend", [False, True])
def test_scroll_coordinator_gesture_lifecycle(native_scrollend):
node = _node_exe()
if node is None:
pytest.skip("no node.js runtime available")
script = r"""
const assert = require('node:assert/strict');
const fs = require('node:fs');
const vm = require('node:vm');
const native = process.argv[2] === 'true';
const source = fs.readFileSync(process.argv[1], 'utf8');
const handlers = { document: {}, window: {} };
const classes = new Set();
const timers = new Map();
let nextTimer = 0;
class Element {
constructor(modal = false) { this.modal = modal; }
closest() { return this.modal ? this : null; }
}
const document = {
body: { classList: {
contains: k => classes.has(k), add: k => classes.add(k), remove: k => classes.delete(k),
} },
addEventListener: (name, fn) => { handlers.document[name] = fn; },
};
if (native) document.onscrollend = null;
vm.runInNewContext(source.slice(source.indexOf('// Disable card blur'), source.indexOf('// Layer 2')), {
document, Element,
window: { addEventListener: (name, fn) => { handlers.window[name] = fn; } },
setTimeout: fn => { timers.set(++nextTimer, fn); return nextTimer; },
clearTimeout: id => timers.delete(id),
});
const fire = (scope, name, ids = [], modal = false) => handlers[scope][name]?.({
target: new Element(modal), changedTouches: ids.map(identifier => ({ identifier })),
});
const tick = () => { const pending = [...timers.values()]; timers.clear(); pending.forEach(fn => fn()); };
const active = () => classes.has('is-scrolling');
fire('window', 'wheel');
assert.equal(active(), false, 'wheel without document movement');
fire('window', 'touchstart', [1, 2]);
fire('document', 'scroll');
fire('window', 'touchend', [1]);
fire('window', 'touchstart', [3], true);
fire('window', 'touchend', [3], true);
tick();
assert.equal(active(), true, 'remaining page finger holds blur disabled');
fire('window', 'touchcancel', [2]);
tick();
assert.equal(active(), native, 'native completion must be authoritative');
fire('document', 'scrollend');
assert.equal(active(), false);
fire('window', 'touchstart', [4]);
fire('document', 'scroll');
fire('document', 'scrollend');
assert.equal(active(), true, 'hold survives completion');
fire('window', 'touchend', [4]);
assert.equal(active(), false, 'release after completion cannot leave state stuck');
fire('document', 'scroll');
fire('window', 'hashchange');
tick();
assert.equal(active(), false, 'navigation clears pending gesture');
fire('document', 'scroll');
tick();
assert.equal(active(), native, 'fallback only on unsupported browsers');
fire('document', 'scrollend');
assert.equal(active(), false);
"""
result = subprocess.run(
[node, "-e", script, str(UI_ROOT / "js/app.js"), str(native_scrollend).lower()],
capture_output=True, text=True,
)
assert result.returncode == 0, result.stdout + result.stderr
def _node_exe():
candidates = [
shutil.which("node"),