openvibers/openvibe.games Commits

Games' front page on a phone: the games are a row you swipe, the featured one first (13.1 screens -> about 6) (#206)

OP OpenVibers committed 15 days ago · d5e60e3993 · 3 files, +30 −19

On a phone the numbers, the five games (their art kept, the text four lines) and the achievements are rows you swipe; the steps are a compact list; the three Steam lists leave the home (the On Steam right now card links them; steamSection is exported for that page); the closing sign-in panel that repeated the hero is gone. Desktop keeps its grid.

Changes

ddiff --git a/apps/client/index.html b/apps/client/index.html
iindex 36e27a9..951aaec 100644
---- a/apps/client/index.html
++++ b/apps/client/index.html
@@@ -779,6 +779,24 @@
#navbar-mount:not(:empty) + .ov-nav-fallback {
display: none;
}
++ /* Phones (2026-10-29): a taste and a door, not every card stacked. The numbers, the games and the achievements are
++ rows you swipe, the featured game first; a card says four lines; the steps are a compact list. */
++ @media (max-width: 599px) {
++ .home-stats { display: flex; overflow-x: auto; scrollbar-width: none; margin: 22px -16px 0; padding: 0 16px; gap: 8px; }
++ .home-stats::-webkit-scrollbar { display: none; }
++ .home-stats li { flex: 0 0 auto; min-width: 118px; padding: 10px 12px; }
++ .home-stats b { font-size: 22px; }
++ .games { display: grid; grid-template-columns: none; grid-auto-flow: column; grid-auto-columns: 86%; overflow-x: auto; scroll-snap-type: x mandatory; scroll-padding-inline: 16px; scrollbar-width: none; margin: 18px 0 36px; padding: 0 16px 8px; gap: 12px; }
++ .games::-webkit-scrollbar { display: none; }
++ .games > .game-card, .games > .game-card.featured, .games > .game-card.wide { grid-column: auto; grid-template-columns: 1fr; scroll-snap-align: start; }
++ .game-card:hover { transform: none; }
++ .game-body > p { display: -webkit-box; -webkit-line-clamp: 4; -webkit-box-orient: vertical; overflow: hidden; }
++ .ach-grid { display: grid; grid-template-columns: none; grid-auto-flow: column; grid-auto-columns: 72%; overflow-x: auto; scroll-snap-type: x proximity; scrollbar-width: none; gap: 10px; padding-bottom: 6px; }
++ .ach-grid::-webkit-scrollbar { display: none; }
++ .ach-grid > * { scroll-snap-align: start; }
++ .how-steps { gap: 0; }
++ .how-steps li { padding: 10px 0; border: 0; border-bottom: 1px solid var(--border); border-radius: 0; background: none; }
++ }
</style>
</head>
<body>
@@@ -1214,18 +1232,6 @@
<!--ov:home-sections-->
-- <section class="account">
-- <div class="account-inner">
-- <h2>Play as a guest. <b>Keep everything</b> with an OpenVibe account.</h2>
-- <p>
-- Jump into any game instantly as a guest: your characters live in this browser. Sign in
-- with your <b>OpenVibe</b> account to keep them and your progress on every device, and to
-- carry one identity across openvibe.live, openvibe.tools and every game here.
-- </p>
-- <a class="signin" href="/auth/login?next=%2F">Sign in with OpenVibe</a>
-- <div class="fine">One account. All of OpenVibe.</div>
-- </div>
-- </section>
<!-- What shipped on OpenVibe.Games: the network's shared "shipped" views (openvibe-shared
shipped.js, which the shared footer loads), the same on every OpenVibe site. -->
ddiff --git a/apps/server/src/net/portalHome.test.ts b/apps/server/src/net/portalHome.test.ts
iindex a6ab670..6306c9b 100644
---- a/apps/server/src/net/portalHome.test.ts
++++ b/apps/server/src/net/portalHome.test.ts
@@@ -10,6 +10,7 @@ import {
createPortalHome,
readPlayTitles,
renderHome,
++ steamSection,
renderStats,
yourStuffSection,
type HomeData,
@@@ -125,10 +126,13 @@ describe('the home page live sections', () => {
expect(parts.sections).toContain('Most visited')
expect(parts.sections).toContain('40 visits')
expect(parts.stats).toContain('<b>7</b><span>creator worlds published</span>')
-- expect(parts.sections).toContain('https://store.steampowered.com/app/2/')
-- expect(parts.sections).toContain('−50%')
-- expect(parts.sections).toContain('checked 2 hours ago')
-- expect(parts.sections).not.toContain('home-steam-new')
++ // The Steam lists left the home (2026-10-29: the "On Steam right now" card links them); they render on their own.
++ expect(parts.sections).not.toContain('store.steampowered.com')
++ const steam = steamSection(d, NOW)
++ expect(steam).toContain('https://store.steampowered.com/app/2/')
++ expect(steam).toContain('−50%')
++ expect(steam).toContain('checked 2 hours ago')
++ expect(steam).not.toContain('home-steam-new')
})
it('a stat with nothing to say is left out', () => {
@@@ -181,7 +185,8 @@ describe('the home page live sections', () => {
const home = createPortalHome(src, { now: () => now, log: { warn: (m) => warnings.push(m) } })
const first = await home()
expect(first.stats).toContain('player online now')
-- expect(first.sections).toContain('id="home-steam"')
++ expect(first.sections).toContain('id="home-how"')
++ expect(first.sections).not.toContain('id="home-steam"')
expect(first.sections).not.toContain('home-achievements')
now += 30_000
await home()
ddiff --git a/apps/server/src/net/portalHome.ts b/apps/server/src/net/portalHome.ts
iindex df2736c..df6df71 100644
---- a/apps/server/src/net/portalHome.ts
++++ b/apps/server/src/net/portalHome.ts
@@@ -319,7 +319,8 @@ function steamRow(g: SteamGame): string {
}<span class="steam-text"><b>${esc(g.name)}</b>${price ? `<span class="steam-price">${price}</span>` : ''}</span></a></li>`
}
--function steamSection(d: HomeData, now: number): string {
++/** The Steam lists (off the home since 2026-10-29: the "On Steam right now" card links them). */
++export function steamSection(d: HomeData, now: number): string {
const s = d.steam
if (!s) return ''
const deals = [...s.sale].sort((a, b) => b.discount_percent - a.discount_percent)
@@@ -468,7 +469,6 @@ export function renderHome(
boardsSection(d),
achievementsSection(d),
worldsSection(d, now),
-- steamSection(d, now),
howSection(),
faqSection(),
]