Skip to content

Commit 151e2e9

Browse files
landing page: simplify scroll and minor prose tweaks
1 parent 6b4485c commit 151e2e9

5 files changed

Lines changed: 67 additions & 82 deletions

File tree

uapi/app/(root)/components/MarketingLandingPage.tsx

Lines changed: 10 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -386,8 +386,8 @@ const ComingSoonMicroPost = memo(function ComingSoonMicroPost() {
386386
<span className={heroHighlightClass}>$ENGI</span>
387387
<span>&apos;s purpose is to hoard valuable technical information and compensate contributors
388388
fairly. Provable knowledge measuring algorithms build the foundations for collection and
389-
issuance. Ideal long-term partners for asset management, infrastructure, and legal will be
390-
finalized to empower the safe and secure future of a thriving </span>
389+
issuance. Ideal long-term partnerships for asset management and infrastructure will be
390+
finalized to empower the secure and thriving future of </span>
391391
<span className={heroHighlightClass}>$ENGI</span>
392392
<span>.</span>
393393
</p>
@@ -397,24 +397,10 @@ const ComingSoonMicroPost = memo(function ComingSoonMicroPost() {
397397

398398
export default function MarketingLandingPage() {
399399
const containerRef = useRef<HTMLDivElement>(null);
400-
const stageRef = useRef<HTMLDivElement>(null);
401-
402-
useEffect(() => {
403-
const html = document.documentElement;
404-
const body = document.body;
405-
html.classList.add('soft-launch');
406-
body.classList.add('soft-launch');
407-
408-
return () => {
409-
html.classList.remove('soft-launch');
410-
body.classList.remove('soft-launch');
411-
};
412-
}, []);
413400

414401
useEffect(() => {
415402
const container = containerRef.current;
416-
const stage = stageRef.current;
417-
if (!container || !stage) {
403+
if (!container) {
418404
return;
419405
}
420406

@@ -443,9 +429,9 @@ export default function MarketingLandingPage() {
443429

444430
const handlePointerMove = (event: PointerEvent) => {
445431
const rect = container.getBoundingClientRect();
446-
const stageHeight = stage.offsetHeight || container.scrollHeight || rect.height;
432+
const stageHeight = container.offsetHeight || container.scrollHeight || rect.height;
447433
nextX = ((event.clientX - rect.left) / rect.width) * 100;
448-
nextY = ((event.clientY - rect.top + container.scrollTop) / stageHeight) * 100;
434+
nextY = ((event.clientY - rect.top) / stageHeight) * 100;
449435
scheduleCommit();
450436
};
451437

@@ -467,39 +453,6 @@ export default function MarketingLandingPage() {
467453
};
468454
}, []);
469455

470-
useEffect(() => {
471-
const container = containerRef.current;
472-
const stage = stageRef.current;
473-
if (!container || !stage) {
474-
return;
475-
}
476-
477-
const updateStageHeight = () => {
478-
const stageHeight = Math.max(
479-
container.scrollHeight,
480-
container.clientHeight,
481-
stage.scrollHeight,
482-
stage.offsetHeight,
483-
);
484-
container.style.setProperty('--stage-height-px', `${stageHeight}px`);
485-
};
486-
487-
updateStageHeight();
488-
489-
const resizeObserver = new ResizeObserver(() => {
490-
updateStageHeight();
491-
});
492-
493-
resizeObserver.observe(container);
494-
resizeObserver.observe(stage);
495-
window.addEventListener('resize', updateStageHeight);
496-
497-
return () => {
498-
resizeObserver.disconnect();
499-
window.removeEventListener('resize', updateStageHeight);
500-
};
501-
}, []);
502-
503456
return (
504457
<>
505458
<svg width="0" height="0" style={{ position: 'absolute', top: '-9999px' }}>
@@ -518,21 +471,14 @@ export default function MarketingLandingPage() {
518471

519472
<div
520473
ref={containerRef}
521-
className="coming-soon-container relative flex w-full flex-col overflow-x-hidden overflow-y-auto bg-[#030816] text-white"
474+
className="coming-soon-container relative flex w-full flex-col bg-[#030816] text-white"
522475
style={{
523-
height: '100svh',
524476
minHeight: '100svh',
525-
overscrollBehaviorY: 'contain',
526-
'--stage-height-px': '100svh',
527477
'--mouse-x': '50%',
528478
'--mouse-y': '50%',
529479
} as React.CSSProperties}
530480
>
531-
<div
532-
ref={stageRef}
533-
className="relative flex w-full flex-col"
534-
style={{ minHeight: 'var(--stage-height-px)' }}
535-
>
481+
<div className="relative flex min-h-[100svh] w-full flex-col">
536482
<div className="absolute inset-0 bg-[radial-gradient(circle_at_top,rgba(103,254,183,0.14),transparent_34%),linear-gradient(180deg,#07131d_0%,#030816_45%,#02060d_100%)]" />
537483
<div className="absolute inset-0 opacity-20 [background-image:linear-gradient(rgba(103,254,183,0.09)_1px,transparent_1px),linear-gradient(90deg,rgba(103,254,183,0.09)_1px,transparent_1px)] [background-size:160px_160px]" />
538484

@@ -570,9 +516,8 @@ export default function MarketingLandingPage() {
570516
))}
571517

572518
<div
573-
className="pointer-events-none absolute inset-x-0 top-0 transition-opacity duration-300"
519+
className="pointer-events-none absolute inset-0 transition-opacity duration-300"
574520
style={{
575-
height: 'var(--stage-height-px)',
576521
background:
577522
'radial-gradient(circle at var(--mouse-x, 50%) var(--mouse-y, 50%), rgba(103, 254, 183, 0.16) 0%, rgba(103, 254, 183, 0.08) 16%, transparent 44%)',
578523
willChange: 'background',
@@ -924,11 +869,11 @@ export default function MarketingLandingPage() {
924869
<span className="h-2.5 w-2.5 rounded-full bg-emerald-300/70" />
925870
</div>
926871
<div className="flex flex-wrap items-center justify-end gap-x-2 gap-y-1 text-[11px] uppercase tracking-[0.22em] text-emerald-200/60">
927-
<span>read</span>
872+
<span>write</span>
928873
<ArrowRightIcon className="h-3.5 w-3.5 shrink-0 text-emerald-200/42" />
929874
<span>measure</span>
930875
<ArrowRightIcon className="h-3.5 w-3.5 shrink-0 text-emerald-200/42" />
931-
<span>write</span>
876+
<span>read</span>
932877
</div>
933878
</div>
934879

uapi/app/globals.css

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -416,13 +416,6 @@ nextjs-portal {
416416
--chart-5: 27 87% 67%;
417417
}
418418

419-
/* Soft-launch mode: lock viewport to prevent scrolling */
420-
html.soft-launch,
421-
body.soft-launch {
422-
overflow: hidden !important;
423-
height: 100vh !important;
424-
}
425-
426419
.dark {
427420
--background: 222.2 84% 4.9%;
428421
--foreground: 210 40% 98%;

uapi/styles/coming-soon-fix.css

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,23 @@
11
/* Coming Soon Component - Specific Fixes */
22

3-
/* Ensure the container allows overflow for glow effects but prevents scrollbars */
3+
/* Use normal document scrolling while keeping horizontal overflow clipped. */
44
.coming-soon-container {
55
position: relative;
6-
overflow-x: hidden;
7-
overflow-y: auto;
6+
overflow-x: clip;
7+
overflow-y: visible;
88
background-color: #030816;
99
min-height: 100svh;
1010
width: 100%;
1111
display: flex;
1212
align-items: stretch;
1313
justify-content: flex-start;
14-
-webkit-overflow-scrolling: touch;
1514
}
1615

1716
/* Create a wrapper to prevent scrollbars while allowing overflow for visual effects */
1817
.coming-soon-container::before {
1918
content: "";
2019
position: absolute;
21-
top: -20px;
22-
left: -20px;
23-
right: -20px;
24-
bottom: -20px;
20+
inset: 0;
2521
pointer-events: none;
2622
}
2723

uapi/styles/coming-soon-glow-fix.css

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,9 +60,10 @@
6060
overflow: visible !important;
6161
}
6262

63-
/* Ensure the coming soon container doesn't clip */
63+
/* Keep natural document scrolling on mobile. */
6464
.coming-soon-container {
65-
overflow: visible !important;
65+
overflow-x: clip !important;
66+
overflow-y: visible !important;
6667
}
6768

6869
/* Smoother animation for the glow effect with more keyframes for smoother transitions */
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import { expect, test } from '@playwright/test';
2+
3+
test.describe('Landing page mobile scrolling', () => {
4+
test('uses natural document scroll instead of an inner mobile scroll root', async ({ page }, testInfo) => {
5+
test.skip(testInfo.project.name !== 'phone', 'mobile-only landing regression');
6+
7+
await page.goto('/');
8+
9+
const container = page.locator('.coming-soon-container');
10+
await expect(container).toBeVisible();
11+
12+
const beforeScroll = await container.evaluate((element) => {
13+
const containerElement = element as HTMLElement;
14+
15+
return {
16+
htmlOverflowY: window.getComputedStyle(document.documentElement).overflowY,
17+
bodyOverflowY: window.getComputedStyle(document.body).overflowY,
18+
containerOverflowX: window.getComputedStyle(containerElement).overflowX,
19+
containerOverflowY: window.getComputedStyle(containerElement).overflowY,
20+
windowInnerHeight: window.innerHeight,
21+
documentScrollHeight: document.documentElement.scrollHeight,
22+
};
23+
});
24+
25+
expect(beforeScroll.htmlOverflowY).not.toBe('hidden');
26+
expect(beforeScroll.bodyOverflowY).not.toBe('hidden');
27+
expect(beforeScroll.containerOverflowX).toBe('clip');
28+
expect(beforeScroll.containerOverflowY).not.toBe('auto');
29+
expect(beforeScroll.containerOverflowY).not.toBe('scroll');
30+
expect(beforeScroll.documentScrollHeight).toBeGreaterThan(beforeScroll.windowInnerHeight);
31+
32+
await page.evaluate(() => {
33+
window.scrollTo({ top: 480, behavior: 'auto' });
34+
});
35+
36+
const afterScroll = await container.evaluate((element) => {
37+
const containerElement = element as HTMLElement;
38+
39+
return {
40+
containerScrollTop: containerElement.scrollTop,
41+
windowScrollY: window.scrollY,
42+
documentScrollTop: document.documentElement.scrollTop + document.body.scrollTop,
43+
};
44+
});
45+
46+
expect(afterScroll.containerScrollTop).toBe(0);
47+
expect(afterScroll.windowScrollY).toBeGreaterThan(0);
48+
expect(afterScroll.documentScrollTop).toBeGreaterThan(0);
49+
});
50+
});

0 commit comments

Comments
 (0)