From d5f324915556c4659c5932f44c68f5241b1c87a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Erik=20Bryd=C3=B8y=20Savland?= Date: Fri, 23 Oct 2026 15:18:10 +0200 Subject: [PATCH 1/4] feat: improve responsive navigation and venue details --- client/src/App.css | 207 ++++++++++++++++-- client/src/components/FeaturedPlace.tsx | 17 +- client/src/components/MainNav.tsx | 5 +- client/src/components/MenuButton.tsx | 15 +- client/src/components/PlaceList.tsx | 1 + client/src/components/SiteHeader.tsx | 43 +++- .../__snapshots__/SiteHeader.test.tsx.snap | 5 +- client/src/pages/ChallengesPage.css | 2 +- client/src/pages/HomePage.tsx | 103 ++++++--- client/src/pages/MapPage.css | 12 +- client/src/pages/UserPage.css | 2 +- 11 files changed, 346 insertions(+), 66 deletions(-) diff --git a/client/src/App.css b/client/src/App.css index 080f6ba..61ecc49 100644 --- a/client/src/App.css +++ b/client/src/App.css @@ -3,11 +3,13 @@ .site-header { --header-end: #1b6a8c; - position: relative; + position: sticky; + top: 0; z-index: 5; padding: 1.25rem 1rem 1.8rem; background: linear-gradient(var(--navy-900), #0f3d68 45%, var(--header-end)); color: var(--eggshell); + transition: padding 0.35s ease; } .site-header :focus-visible { @@ -29,6 +31,7 @@ mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 96 8'%3E%3Cpath d='M0 4q12-8 24 0t24 0 24 0 24 0V0H0Z'/%3E%3C/svg%3E") repeat-x top / 6rem 0.5rem; animation: wave-drift 24s linear infinite; + transition: height 0.35s ease; } /* Bølgen glir sidelengs. Den ene bølgelengden er 6rem, så løkken er sømløs. */ @@ -46,8 +49,17 @@ /* Sidemargen holder tittelen unna hjørneknappene. */ .site-title { + max-height: 8rem; + overflow: hidden; padding-inline: 3.25rem; + pointer-events: none; text-align: center; + opacity: 1; + transform: translateY(0); + transition: + max-height 0.35s ease, + opacity 0.2s ease, + transform 0.35s ease; } /* Tittelen har fast høyde og én linje, så toppen er like høy på alle sider. */ @@ -58,7 +70,7 @@ gap: 0.6rem; height: 1.4em; margin: 0; - font-size: clamp(2rem, 5vw, 2.85rem); + font-size: 2.5rem; line-height: 1.4; } @@ -95,13 +107,13 @@ gap: 0.6rem; margin: 0.4rem 0 0; color: var(--blue-100); - font-size: clamp(0.95rem, 2.5vw, 1.2rem); + font-size: 1.1rem; } .site-title p::before, .site-title p::after { content: ''; - width: clamp(0.75rem, 5vw, 2.5rem); + width: 1.5rem; height: 1px; background: var(--blue-300); opacity: 0.7; @@ -145,6 +157,7 @@ display: grid; position: absolute; top: 0.5rem; + z-index: 2; place-items: center; width: 2.75rem; height: 2.75rem; @@ -166,6 +179,10 @@ left: 0.5rem; } +.menu-button { + display: none; +} + .help-button { right: 0.5rem; } @@ -242,7 +259,7 @@ .map-control:hover:not(:disabled) { background: var(--navy-900); color: var(--eggshell); - transform: translateY(-2px); + transform: translateY(-0.125rem); box-shadow: 0 0.35rem 0.75rem rgb(10 34 64 / 0.25); } @@ -270,12 +287,13 @@ .main-nav ul { display: grid; - grid-template-columns: repeat(auto-fit, minmax(6.25rem, 1fr)); - gap: 0.4rem; - max-width: 44rem; - margin: 0.85rem auto 0; + grid-template-columns: repeat(5, minmax(0, 1fr)); + gap: 0.5rem; + max-width: 48rem; + margin: 1rem auto 0; padding: 0; list-style: none; + transition: margin 0.35s ease; } .main-nav a { @@ -283,11 +301,12 @@ align-items: center; justify-content: center; gap: 0.4rem; - padding: 0.3rem 0.55rem; + min-height: 2.75rem; + padding: 0.45rem 0.6rem; border-radius: 0.5rem; background: rgb(10 34 64 / 0.6); color: var(--eggshell); - font-size: 0.85rem; + font-size: 0.9rem; font-weight: 600; text-decoration: none; transition: @@ -305,7 +324,7 @@ .main-nav a:hover { background: var(--blue-300); color: var(--navy-900); - transform: translateY(-2px); + transform: translateY(-0.125rem); } /* Siden vi står på: lys «dekk»-markering. */ @@ -439,10 +458,11 @@ @media (min-width: 56rem) { .featured { position: sticky; - top: 1rem; + /* Keep the card below the compact sticky navigation bar. */ + top: 4.25rem; /* Bildet får all ledig plass, men aldri mindre enn dette. */ grid-template-rows: auto minmax(max(9rem, 24vh), 1fr) auto auto auto auto; - height: calc(100vh - 2rem); + height: calc(100vh - 5.25rem); /* Boksen skrumpes aldri: i lave vinduer er den like høy som innholdet. */ min-height: min-content; } @@ -479,7 +499,7 @@ .button:hover:not(:disabled) { background: var(--blue-300); color: var(--navy-900); - transform: translateY(-2px); + transform: translateY(-0.125rem); box-shadow: 0 0.35rem 0.75rem rgb(10 34 64 / 0.2); } @@ -706,7 +726,7 @@ .suggestion:hover { border-color: var(--navy-500); box-shadow: 0 0.5rem 1rem rgb(10 34 64 / 0.15); - transform: translateY(-2px); + transform: translateY(-0.125rem); } .suggestion:active { @@ -741,12 +761,6 @@ color: var(--muted); } -@media (max-width: 30rem) { - .suggestion { - grid-template-columns: minmax(0, 1fr) 6rem; - } -} - /* Markerer stedet som vises som fremhevet. */ .suggestion-active, .suggestion-active:hover { @@ -826,3 +840,152 @@ main { font-size: 0.75rem; font-style: normal; } + +/* Compact sticky bar after the reader has moved past the page title. */ +.site-header-compact { + background: var(--navy-900); + padding-block: 0.35rem 0.65rem; +} + +.site-header-compact::after { + content: none; + display: none; +} + +.site-header-compact .site-title { + max-height: 0; + opacity: 0; + transform: translateY(-0.75rem); +} + +.site-header-compact .main-nav ul { + margin-block-start: 0; +} + +.site-header-compact .gulls { + visibility: hidden; + opacity: 0; + transition: + opacity 0.2s ease, + visibility 0s linear 0.2s; +} + +.site-header-compact .help-button { + visibility: visible; + opacity: 1; + transition: opacity 0.2s ease; +} + +/* Felles mobiloppsett: færre trange rader og navigasjon i sticky header. */ +@media (max-width: 56rem) { + .site-header { + padding: 0.75rem 0.75rem 1rem; + } + + .site-title { + padding-inline: 3rem; + } + + .site-title h1 { + height: auto; + min-height: 2.75rem; + font-size: 2rem; + } + + .site-title p { + font-size: 1rem; + } + + .menu-button { + display: grid; + } + + .site-header-compact { + min-height: 3.5rem; + padding-block: 0.35rem 0.55rem; + } + + .site-header-compact .menu-button { + top: 0.35rem; + } + + .main-nav { + display: none; + position: absolute; + top: 100%; + right: 0.75rem; + left: 0.75rem; + z-index: 1; + padding: 0.75rem; + border: 1px solid var(--blue-300); + border-radius: 0 0 0.75rem 0.75rem; + background: var(--navy-900); + box-shadow: 0 0.75rem 1.5rem rgb(10 34 64 / 0.25); + } + + .site-header.menu-open .main-nav { + display: block; + } + + .main-nav ul { + grid-template-columns: minmax(0, 1fr); + gap: 0.5rem; + margin: 0; + } + + .main-nav a { + justify-content: flex-start; + min-height: 2.75rem; + padding: 0.65rem 0.75rem; + font-size: 1rem; + } + + .help-popover { + inset-block-start: 3.5rem; + } + + .page.mobile-detail { + grid-template-columns: minmax(0, 1fr); + } + + .page.mobile-detail > .place-filter, + .page.mobile-detail > .suggestions { + display: none; + } + + .featured-back { + justify-self: start; + width: auto; + } +} + +@media (max-width: 40rem) { + .page { + gap: 1.5rem; + padding: 1.25rem 0.75rem 2rem; + } + + .place-filter { + align-items: stretch; + gap: 0.5rem; + } + + .place-filter input, + .place-filter select, + .place-filter > .button { + min-height: 2.75rem; + } + + .place-filter input { + flex-basis: 100%; + } + + .suggestion { + grid-template-columns: minmax(0, 1fr) 7rem; + gap: 0.75rem; + } + + .featured-actions { + gap: 0.5rem; + } +} diff --git a/client/src/components/FeaturedPlace.tsx b/client/src/components/FeaturedPlace.tsx index 2401135..2e39607 100644 --- a/client/src/components/FeaturedPlace.tsx +++ b/client/src/components/FeaturedPlace.tsx @@ -7,6 +7,8 @@ type FeaturedPlaceProps = { now: Date onPrevious: () => void onNext: () => void + onBack?: () => void + showBack?: boolean } /** Lite kompass som lenker til stedets nettside. */ @@ -34,16 +36,29 @@ export function FeaturedPlace({ now, onPrevious, onNext, + onBack, + showBack = false, }: FeaturedPlaceProps) { return (