Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion app/src/app/(home)/loading.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ export default function Loading() {
<div className={HERO.actions}><Sk className="h-12 min-w-0 flex-1 rounded-2xl sm:h-[54px] sm:w-52 sm:flex-none" /><Sk className="h-12 w-[149px] shrink-0 rounded-2xl max-[379px]:w-12 sm:h-[54px] sm:w-56" /></div>
<div className={HERO.proofs}>{["w-[106px] sm:w-[122px]", "w-[96px] sm:w-[170px]", "w-[133px] sm:w-[152px]"].map((w) => <Sk key={w} className={`h-8 rounded-full sm:h-9 ${w}`} />)}</div>
</div>
<div className={hero.stageCol}>
<div className={hero.stage}>
<div className={machine.machine}>
<div className="flex h-9 items-center"><Sk className="h-3 w-44" /></div>
Expand All @@ -56,6 +57,8 @@ export default function Loading() {
<div className="flex h-[53px] items-center px-2 min-[340px]:h-[30px]"><Sk className="h-2.5 w-full" /></div>
</div>
</div>
<div className={hero.tickerStage}><Sk className="h-10 w-full rounded-xl" /></div>
</div>
<div className={hero.totalsArea}>
<div className={totals.panel}>
<div className={totals.readings}>
Expand All @@ -70,8 +73,8 @@ export default function Loading() {
<div className={`${totals.breakdown} flex min-h-11 items-center lg:min-h-9`}><Sk className="h-3 w-64 max-w-full" /></div>
</div>
</div>
<div className={hero.tickerArea}><Sk className="h-10 w-full rounded-xl" /></div>
</div>
<div className={HERO.ticker}><Sk className="h-10 w-full rounded-xl" /></div>
</section>
{/* Trending (TrendingStrip.tsx): a row to swipe below 1024px, a leader over four runners from there. The row's own stylesheet
class is used, so its padding, gap and card width are the real ones. */}
Expand Down
18 changes: 14 additions & 4 deletions app/src/components/launchpad/LaunchHero.module.css
Original file line number Diff line number Diff line change
@@ -1,16 +1,26 @@
/* The hero's grid, in three arrangements. Phones: copy, the locker, then the totals. From 768px the text sits left of the
locker and the totals run under both. From 1024px the totals move up into the left column under the text, and the locker
takes the whole height beside them: copy hugs the bottom of its row and the totals the top of theirs, so the pair stays
together however tall the locker is. */
.layout { display: grid; align-items: center; column-gap: 2.5rem; row-gap: 1.25rem; grid-template-columns: minmax(0, 1fr); grid-template-areas: "copy" "stage" "totals"; }
together however tall the locker is. The live line is the grid's last row up to 1023px (full width). From 1024px it moves
into the locker's column, right under the frame as its caption, and the pair centers together (two renderings of the
line, one shown at each size: the hidden one is display:none, so nothing reads or tabs through it twice). */
.layout { display: grid; align-items: center; column-gap: 2.5rem; row-gap: 1.25rem; grid-template-columns: minmax(0, 1fr); grid-template-areas: "copy" "stage" "totals" "ticker"; }
.copyArea { grid-area: copy; min-width: 0; }
.totalsArea { grid-area: totals; min-width: 0; }
@media (min-width: 640px) { .layout { row-gap: 2rem; } }
@media (min-width: 768px) { .layout { grid-template-columns: minmax(0, 1.06fr) minmax(0, 1fr); grid-template-areas: "copy stage" "totals totals"; } }
/* the line used to sit outside the grid, 16px (phones) or 20px under it: the negative margin keeps that spacing against the row gap */
.tickerArea { grid-area: ticker; min-width: 0; margin-top: -0.25rem; }
/* the locker's column: below 1024px it only wraps the stage (display: contents leaves the stage a grid item, as before) */
.stageCol { display: contents; }
.layout .tickerStage { display: none; }
@media (min-width: 640px) { .layout { row-gap: 2rem; } .tickerArea { margin-top: -0.75rem; } }
@media (min-width: 768px) { .layout { grid-template-columns: minmax(0, 1.06fr) minmax(0, 1fr); grid-template-areas: "copy stage" "totals totals" "ticker ticker"; } }
@media (min-width: 1024px) {
.layout { grid-template-areas: "copy stage" "totals stage"; row-gap: 1.25rem; }
.copyArea { align-self: end; }
.totalsArea { align-self: start; }
.layout .tickerArea { display: none; }
.stageCol { display: flex; flex-direction: column; gap: 0.875rem; grid-area: stage; align-self: center; min-width: 0; }
.layout .tickerStage { display: flex; }
}
@media (min-width: 1280px) { .layout { column-gap: 3.5rem; } }

Expand Down
15 changes: 10 additions & 5 deletions app/src/components/launchpad/LaunchHero.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -74,16 +74,21 @@ export default function LaunchHero({ configured }: { configured: boolean }) {
) : null}
</div>
{/* the stage: a faint plotting grid and four corner marks frame the mechanism like a drawing on a bench */}
<div className={styles.stage}>
<span className={styles.grid} aria-hidden="true" />
{["tl", "tr", "bl", "br"].map((corner) => <span key={corner} className={styles.corner} data-corner={corner} aria-hidden="true" />)}
<div className="relative"><HeroLocker imageBase={coinPicturesEnabled() ? imagePublicBase() : null} /></div>
<div className={styles.stageCol}>
<div className={styles.stage}>
<span className={styles.grid} aria-hidden="true" />
{["tl", "tr", "bl", "br"].map((corner) => <span key={corner} className={styles.corner} data-corner={corner} aria-hidden="true" />)}
<div className="relative"><HeroLocker imageBase={coinPicturesEnabled() ? imagePublicBase() : null} /></div>
</div>
{/* from 1024px the live line is the locker's caption, right under its frame */}
<LiveTicker className={styles.tickerStage} />
</div>
<div className={styles.totalsArea}>
<LaunchMechanism />
</div>
{/* below 1024px the line is the grid's last row, full width */}
<LiveTicker className={styles.tickerArea} />
</div>
<LiveTicker className={HERO.ticker} />
</section>
);
}
4 changes: 2 additions & 2 deletions app/src/components/launchpad/hero-layout.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ test("the headline is stepped so it stays two lines, and the hero grid has three
assert.ok(HERO.section.split(" ").includes("lg:pt-4"), "tight rhythm from 1024px");
// phones: copy, the locker, then the totals. 768px: text beside the locker, totals under both. 1024px: the totals
// move up under the text and the locker spans both rows, with copy hugging its row's bottom and the totals its top
assert.match(heroCss, /\.layout \{[^}]*align-items: center;[^}]*grid-template-columns: minmax\(0, 1fr\); grid-template-areas: "copy" "stage" "totals"; \}/);
assert.match(heroCss, /@media \(min-width: 768px\) \{ \.layout \{ grid-template-columns: minmax\(0, 1\.06fr\) minmax\(0, 1fr\); grid-template-areas: "copy stage" "totals totals"; \} \}/);
assert.match(heroCss, /\.layout \{[^}]*align-items: center;[^}]*grid-template-columns: minmax\(0, 1fr\); grid-template-areas: "copy" "stage" "totals" "ticker"; \}/);
assert.match(heroCss, /@media \(min-width: 768px\) \{ \.layout \{ grid-template-columns: minmax\(0, 1\.06fr\) minmax\(0, 1fr\); grid-template-areas: "copy stage" "totals totals" "ticker ticker"; \} \}/);
assert.match(heroCss, /@media \(min-width: 1024px\) \{\n\s*\.layout \{ grid-template-areas: "copy stage" "totals stage";[^}]*\}\n\s*\.copyArea \{ align-self: end; \}\n\s*\.totalsArea \{ align-self: start; \}/);
assert.match(heroCss, /\.stage \{ grid-area: stage;/);
});
Expand Down
2 changes: 0 additions & 2 deletions app/src/components/launchpad/hero-layout.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,4 @@ export const HERO = {
the page. From 640px the row never wraps, as before: the two-column hero at tablet widths is laid out around one row. */
actions: "mt-6 flex flex-wrap items-center gap-2.5 sm:mt-8 sm:flex-nowrap sm:gap-4 lg:mt-6",
proofs: "mt-5 flex flex-wrap gap-2 lg:mt-4",
/** the live ticker that closes the hero */
ticker: "mt-4 sm:mt-5",
} as const;
17 changes: 15 additions & 2 deletions app/src/components/launchpad/live-ticker.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,19 @@ test("the poll is the clock: no timer, no request, and a new event replays its e
assert.doesNotMatch(css, /infinite/, "no ambient animation");
});

test("the hero ends on the ticker", () => {
assert.match(hero, /<LiveTicker className=\{HERO\.ticker\} \/>\n\s*<\/section>/);
test("the live line is the grid's last row up to 1023px and the locker's caption from 1024px", () => {
// two renderings of the same one-link component, one shown per size: the hidden one is display:none, so nothing reads or tabs twice
assert.match(hero, /<LiveTicker className=\{styles\.tickerStage\} \/>\n\s*<\/div>\n\s*<div className=\{styles\.totalsArea\}>/, "inside the locker's column, right after the stage frame");
assert.match(hero, /<LiveTicker className=\{styles\.tickerArea\} \/>\n\s*<\/div>\n\s*<\/section>/, "and the last child of the grid, which is the last thing in the hero");
const grid = read("./LaunchHero.module.css");
assert.match(grid, /grid-template-areas: "copy" "stage" "totals" "ticker";/);
assert.match(grid, /grid-template-areas: "copy stage" "totals totals" "ticker ticker";/, "tablets: under both columns, as it always was");
assert.match(grid, /@media \(min-width: 1024px\) \{\n\s*\.layout \{ grid-template-areas: "copy stage" "totals stage";/, "laptops: no row of its own, so the hero is a row shorter");
// below 1024px the line sits 16px (phones) or 20px under the grid, as it did when it was outside it: negative margins against the 20px and 32px row gaps
assert.match(grid, /\.tickerArea \{ grid-area: ticker; min-width: 0; margin-top: -0\.25rem; \}/);
assert.match(grid, /\.tickerArea \{ margin-top: -0\.75rem; \}/);
assert.match(grid, /\.stageCol \{ display: contents; \}/, "below 1024px the column only wraps the stage");
assert.match(grid, /\.layout \.tickerStage \{ display: none; \}/);
assert.match(grid, /\.layout \.tickerArea \{ display: none; \}\n\s*\.stageCol \{ display: flex; flex-direction: column; gap: 0\.875rem; grid-area: stage; align-self: center; min-width: 0; \}\n\s*\.layout \.tickerStage \{ display: flex; \}/);
assert.doesNotMatch(read("./hero-layout.ts"), /ticker:/, "no spacing constant outside the grid any more");
});
Loading