slide animation
CI/CD Pipeline / Build and Push PocketBase Docker Image (push) Successful in 13s
CI/CD Pipeline / i18n Catalog Check (push) Successful in 31s
CI/CD Pipeline / Build and Push App Docker Image (push) Successful in 3m25s
CI/CD Pipeline / Deploy to Kubernetes (push) Successful in 8m29s

This commit is contained in:
2026-09-11 08:32:42 -07:00
parent c4a9d47180
commit 9ed3f7169e
13 changed files with 120 additions and 65 deletions
+14 -1
View File
@@ -183,7 +183,19 @@ function RootComponent() {
ensureSuperTokensFrontend();
initTelemetry(router);
if (import.meta.env.PROD && 'serviceWorker' in navigator) {
navigator.serviceWorker.register('/sw.js').catch(() => track('sw_register_failed'));
// first install claims the page too; only reload on real updates
const hadController = !!navigator.serviceWorker.controller;
let reloading = false;
navigator.serviceWorker.addEventListener('controllerchange', () => {
if (!hadController || reloading) return;
reloading = true;
window.location.reload();
});
navigator.serviceWorker.register('/sw.js').then((registration) => {
document.addEventListener('visibilitychange', () => {
if (document.visibilityState === 'visible') registration.update().catch(() => {});
});
}).catch(() => track('sw_register_failed'));
}
}, [router]);
@@ -243,6 +255,7 @@ function RootDocument({ children }: { children: React.ReactNode }) {
}}
>
<div className="app">{children}</div>
<div className="flxn-theme-overlay" aria-hidden="true" />
<Scripts />
</body>
</html>
+7 -6
View File
@@ -48,11 +48,9 @@ function SwipeableTabs({
}, [search?.tab, tabs, defaultTab]);
const [activeTab, setActiveTab] = useState(getActiveTabFromUrl);
const [mountAll, setMountAll] = useState(false);
useEffect(() => {
const timeoutId = setTimeout(() => startTransition(() => setMountAll(true)), 400);
return () => clearTimeout(timeoutId);
}, []);
const [visitedTabs, setVisitedTabs] = useState<ReadonlySet<number>>(
() => new Set([getActiveTabFromUrl()])
);
const [stuck, setStuck] = useState(false);
const sentinelRef = useRef<HTMLDivElement>(null);
const [rootRef, setRootRef] = useState<HTMLDivElement | null>(null);
@@ -65,6 +63,9 @@ function SwipeableTabs({
if (index === activeTab || index < 0 || index >= tabs.length) return;
setActiveTab(index);
startTransition(() => {
setVisitedTabs((prev) => (prev.has(index) ? prev : new Set(prev).add(index)));
});
embla?.scrollTo(index);
onTabChange?.(index, tabs[index]);
@@ -230,7 +231,7 @@ function SwipeableTabs({
{tabs.map((tab, index) => (
<Carousel.Slide key={`${tab.label}-content-${index}`}>
<Box ref={setSlideRef(index)} style={{ height: "auto", width: "100%", maxWidth: "100vw", overflow: "hidden" }}>
{(mountAll || index === activeTab) ? tab.content : null}
{(visitedTabs.has(index) || index === activeTab) ? tab.content : null}
</Box>
</Carousel.Slide>
))}
+1 -2
View File
@@ -52,11 +52,10 @@ const Layout: React.FC<PropsWithChildren> = ({ children }) => {
maw='100dvw'
style={{ overflow: 'hidden' }}
>
{/* pane box must be opaque and route-invariant or slides drift */}
{/* pane box must be route-invariant or slides drift */}
<Box
style={{
viewTransitionName: 'page',
backgroundColor: 'var(--mantine-color-body)',
marginTop: 'calc(-1 * var(--app-shell-header-offset, 0px))',
paddingTop: 'var(--app-shell-header-offset, 0px)',
height: 'calc(100% + var(--app-shell-header-offset, 0px))',
+3 -4
View File
@@ -178,15 +178,14 @@
/* 3. Fixed sky backdrop with static bubbles (below all content) */
/* ---------------------------------------------------------------- */
[data-theme="aero"] body::before {
content: "";
[data-theme="aero"] .flxn-theme-overlay {
position: fixed;
inset: 0;
z-index: -1;
pointer-events: none;
}
[data-theme="aero"][data-mantine-color-scheme="light"] body::before {
[data-theme="aero"][data-mantine-color-scheme="light"] .flxn-theme-overlay {
background-color: #e9f6fe;
background-image:
radial-gradient(circle 0.6rem at 13.5% 20%, rgba(255, 255, 255, 0.8), rgba(255, 255, 255, 0) 70%),
@@ -198,7 +197,7 @@
linear-gradient(180deg, #a5daf6 0%, #c9e9fa 32%, #e9f6fe 60%, #ffffff 100%);
}
[data-theme="aero"][data-mantine-color-scheme="dark"] body::before {
[data-theme="aero"][data-mantine-color-scheme="dark"] .flxn-theme-overlay {
background-color: #071e2d;
background-image:
radial-gradient(circle 4rem at 16% 24%, rgba(120, 205, 245, 0) 60%, rgba(120, 205, 245, 0.2) 67%, rgba(120, 205, 245, 0) 74%),
+3 -4
View File
@@ -203,8 +203,7 @@
/* ---------- 4. Backdrop — studio key light + clay grain ---------- */
[data-theme="clay"] body::before {
content: "";
[data-theme="clay"] .flxn-theme-overlay {
position: fixed;
inset: 0;
z-index: -1; /* behind content — never tints text or surfaces */
@@ -212,7 +211,7 @@
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23n)' opacity='0.05'/%3E%3C/svg%3E");
}
[data-theme="clay"][data-mantine-color-scheme="light"] body::before {
[data-theme="clay"][data-mantine-color-scheme="light"] .flxn-theme-overlay {
background-image: radial-gradient(
120% 70% at 50% 0%,
rgba(255, 252, 244, 0.65),
@@ -221,7 +220,7 @@
url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23n)' opacity='0.05'/%3E%3C/svg%3E");
}
[data-theme="clay"][data-mantine-color-scheme="dark"] body::before {
[data-theme="clay"][data-mantine-color-scheme="dark"] .flxn-theme-overlay {
background-image: radial-gradient(
110% 65% at 50% 0%,
rgba(255, 208, 158, 0.09),
+1 -2
View File
@@ -363,8 +363,7 @@
/* ------------------------------------------------------------------ */
/* 4. Sunburst fan — faint gold rays from top center */
/* ------------------------------------------------------------------ */
[data-theme="deco"] body::before {
content: "";
[data-theme="deco"] .flxn-theme-overlay {
position: fixed;
inset: 0;
z-index: 9998;
+1 -2
View File
@@ -409,8 +409,7 @@
* 3. Full-page decoration: candlelit vignette (dark scheme only)
* ---------------------------------------------------------------- */
[data-theme="gothic"][data-mantine-color-scheme="dark"] body::before {
content: "";
[data-theme="gothic"][data-mantine-color-scheme="dark"] .flxn-theme-overlay {
position: fixed;
inset: 0;
z-index: 9998;
+3 -4
View File
@@ -153,8 +153,7 @@
/* 3. Fixed backdrop (below all content) */
/* ---------------------------------------------------------------- */
[data-theme="ocean"] body::before {
content: "";
[data-theme="ocean"] .flxn-theme-overlay {
position: fixed;
inset: 0;
z-index: -1;
@@ -163,7 +162,7 @@
/* Abyssal descent: deep teal fading to ink navy, sparse static bubbles
rising (bigger and brighter near the sea floor, fading toward the top). */
[data-theme="ocean"][data-mantine-color-scheme="dark"] body::before {
[data-theme="ocean"][data-mantine-color-scheme="dark"] .flxn-theme-overlay {
background-color: #062632;
background-image:
url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='260' height='640' viewBox='0 0 260 640'%3E%3Cg fill='none' stroke='%239beee2'%3E%3Ccircle cx='36' cy='584' r='5' stroke-opacity='.13'/%3E%3Ccircle cx='44' cy='512' r='3' stroke-opacity='.1'/%3E%3Ccircle cx='210' cy='612' r='4' stroke-opacity='.12'/%3E%3Ccircle cx='202' cy='540' r='2.5' stroke-opacity='.09'/%3E%3Ccircle cx='128' cy='430' r='3.5' stroke-opacity='.1'/%3E%3Ccircle cx='120' cy='360' r='2' stroke-opacity='.08'/%3E%3Ccircle cx='232' cy='300' r='3' stroke-opacity='.09'/%3E%3Ccircle cx='60' cy='250' r='2.5' stroke-opacity='.08'/%3E%3Ccircle cx='150' cy='160' r='2' stroke-opacity='.07'/%3E%3Ccircle cx='90' cy='80' r='1.5' stroke-opacity='.06'/%3E%3C/g%3E%3Cg fill='%239beee2'%3E%3Ccircle cx='70' cy='470' r='1.2' fill-opacity='.1'/%3E%3Ccircle cx='180' cy='390' r='1' fill-opacity='.09'/%3E%3Ccircle cx='40' cy='330' r='1' fill-opacity='.08'/%3E%3Ccircle cx='222' cy='190' r='1' fill-opacity='.07'/%3E%3Ccircle cx='140' cy='40' r='1' fill-opacity='.05'/%3E%3C/g%3E%3C/svg%3E"),
@@ -175,7 +174,7 @@
/* Sunlit shallows: seafoam fading to a sandy floor, with a faint white
caustic ripple tile — refracted light, kept very subtle. */
[data-theme="ocean"][data-mantine-color-scheme="light"] body::before {
[data-theme="ocean"][data-mantine-color-scheme="light"] .flxn-theme-overlay {
background-color: #eaf6f6;
background-image:
url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='320' height='220' viewBox='0 0 320 220'%3E%3Cg fill='none' stroke='%23ffffff' stroke-width='1.4'%3E%3Cpath d='M0 40 Q 40 10 80 42 T 160 44 T 240 38 T 320 42' stroke-opacity='.4'/%3E%3Cpath d='M0 110 Q 45 82 90 112 T 180 110 T 268 114 T 320 108' stroke-opacity='.3'/%3E%3Cpath d='M0 180 Q 50 152 100 182 T 200 178 T 300 184 T 320 180' stroke-opacity='.35'/%3E%3C/g%3E%3C/svg%3E"),
+2 -4
View File
@@ -414,8 +414,7 @@
* 3. Full-page decoration: worn parchment edges / torchlight
* ---------------------------------------------------------------- */
[data-theme="quest"][data-mantine-color-scheme="light"] body::before {
content: "";
[data-theme="quest"][data-mantine-color-scheme="light"] .flxn-theme-overlay {
position: fixed;
inset: 0;
z-index: 9998;
@@ -426,8 +425,7 @@
radial-gradient(55% 38% at 95% 98%, rgba(122, 91, 42, 0.07), transparent 70%);
}
[data-theme="quest"][data-mantine-color-scheme="dark"] body::before {
content: "";
[data-theme="quest"][data-mantine-color-scheme="dark"] .flxn-theme-overlay {
position: fixed;
inset: 0;
z-index: 9998;
+10 -3
View File
@@ -151,8 +151,7 @@
/* 3. Paper grain / chalk dust — one fixed overlay, feTurbulence */
/* ---------------------------------------------------------------- */
[data-theme="sketch"] body::before {
content: "";
[data-theme="sketch"] .flxn-theme-overlay {
position: fixed;
inset: 0;
z-index: 9998;
@@ -163,11 +162,19 @@
opacity: 0.05;
}
[data-theme="sketch"][data-mantine-color-scheme="dark"] body::before {
[data-theme="sketch"][data-mantine-color-scheme="dark"] .flxn-theme-overlay {
mix-blend-mode: screen;
opacity: 0.07;
}
[data-theme="sketch"]::view-transition-new(theme-overlay) {
mix-blend-mode: multiply;
}
[data-theme="sketch"][data-mantine-color-scheme="dark"]::view-transition-new(theme-overlay) {
mix-blend-mode: screen;
}
/* ---------------------------------------------------------------- */
/* 4. Surfaces — every card its own doodle */
/* ---------------------------------------------------------------- */
+2 -3
View File
@@ -575,8 +575,7 @@
}
/* 4. Decoration: fixed scanline overlay + faint RGB aperture mask */
[data-theme="terminal"] body::before {
content: "";
[data-theme="terminal"] .flxn-theme-overlay {
position: fixed;
inset: 0;
z-index: 9998;
@@ -589,7 +588,7 @@
}
@media (prefers-reduced-motion: no-preference) {
[data-theme="terminal"] body::before {
[data-theme="terminal"] .flxn-theme-overlay {
animation: terminal-phosphor-drift 9s ease-in-out infinite;
}
@keyframes terminal-phosphor-drift {
+1 -2
View File
@@ -150,8 +150,7 @@
/* ---------- 3. Decoration: static perspective floor-grid hint ---------- */
[data-theme="wireframe"] body::before {
content: "";
[data-theme="wireframe"] .flxn-theme-overlay {
position: fixed;
left: -30vw;
right: -30vw;