From 46b43cf0a4a63120a4e020a1dcd2bb5db2c845c7 Mon Sep 17 00:00:00 2001 From: Kasper Date: Fri, 9 Oct 2026 16:37:01 +0200 Subject: [PATCH] refactor: share one persistent site header and add sailing quotes --- client/src/App.css | 149 ++++++++++++++++------ client/src/App.tsx | 19 ++- client/src/components/HomeLink.tsx | 23 ---- client/src/components/MainNav.tsx | 20 ++- client/src/components/PageFooter.tsx | 37 ++++++ client/src/components/PageHeader.tsx | 71 +++++++++++ client/src/components/SiteHeader.tsx | 37 ++++-- client/src/components/wheel/SpinWheel.tsx | 12 +- client/src/hooks/useCurrentUser.ts | 28 +--- client/src/hooks/useFetch.ts | 19 ++- client/src/hooks/usePlaces.ts | 14 +- client/src/index.css | 1 + client/src/pages/ChallengesPage.css | 44 ++----- client/src/pages/ChallengesPage.tsx | 23 ---- client/src/pages/HomePage.tsx | 64 +++++----- client/src/pages/MapPage.css | 18 +-- client/src/pages/MapPage.tsx | 52 +------- client/src/pages/UserPage.css | 19 --- client/src/pages/UserPage.tsx | 91 +++++-------- 19 files changed, 389 insertions(+), 352 deletions(-) delete mode 100644 client/src/components/HomeLink.tsx create mode 100644 client/src/components/PageFooter.tsx create mode 100644 client/src/components/PageHeader.tsx diff --git a/client/src/App.css b/client/src/App.css index cead6c1..8cafc3d 100644 --- a/client/src/App.css +++ b/client/src/App.css @@ -1,9 +1,12 @@ /* ---------- Header ---------- */ .site-header { + --header-end: #1b6a8c; + position: relative; - padding: 1rem 1rem 2.75rem; - background: linear-gradient(var(--navy-900), #0d2d54); + z-index: 5; + padding: 1.25rem 1rem 1.8rem; + background: linear-gradient(var(--navy-900), #0f3d68 45%, var(--header-end)); color: var(--eggshell); } @@ -11,16 +14,20 @@ outline-color: var(--blue-100); } -/* Bølgekant mot eggeskall-bakgrunnen. Fargen må være skrevet inn i SVG-en. */ +/* + * Bølgekanten henger under toppen i samme farge som bunnen av den, så den + * passer mot alt som ligger under, både eggeskallbakgrunnen og kartet. + */ .site-header::after { content: ''; position: absolute; + top: 100%; right: 0; - bottom: -1px; left: 0; - height: 1.25rem; - background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 96 20'%3E%3Cpath fill='%23f6f2e7' d='M0 20v-8q12-8 24 0t24 0 24 0 24 0v8Z'/%3E%3C/svg%3E") - repeat-x bottom / 6rem 1.25rem; + height: 0.5rem; + background: var(--header-end); + 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; } /* Sidemargen holder tittelen unna hjørneknappene. */ @@ -29,10 +36,41 @@ text-align: center; } +/* Tittelen har fast høyde og én linje, så toppen er like høy på alle sider. */ .site-title h1 { + display: flex; + align-items: center; + justify-content: center; + gap: 0.6rem; + height: 1.4em; margin: 0; - font-size: clamp(2rem, 5vw, 3rem); - line-height: 1.1; + font-size: clamp(2rem, 5vw, 2.85rem); + line-height: 1.4; +} + +.site-title h1 > :first-child { + min-width: 0; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.site-title h1 > :last-child:not(:first-child) { + display: flex; + flex: none; +} + +.site-title .avatar { + width: 1em; + height: 1em; + border-width: 2px; +} + +/* På smale skjermer kan undertittelen gå over to linjer, og plassen er alltid satt av. */ +@media (max-width: 40rem) { + .site-title p { + min-height: 3em; + } } /* Tagline med tynne streker på hver side. */ @@ -40,16 +78,16 @@ display: flex; align-items: center; justify-content: center; - gap: 0.75rem; - margin: 0.25rem 0 0; + gap: 0.6rem; + margin: 0.4rem 0 0; color: var(--blue-100); - font-size: clamp(1rem, 2.5vw, 1.25rem); + font-size: clamp(0.95rem, 2.5vw, 1.2rem); } .site-title p::before, .site-title p::after { content: ''; - width: clamp(1rem, 6vw, 3rem); + width: clamp(0.75rem, 5vw, 2.5rem); height: 1px; background: var(--blue-300); opacity: 0.7; @@ -199,24 +237,6 @@ box-shadow: none; } -.home-link { - position: absolute; - top: 0.5rem; - left: 3.75rem; - z-index: 3; - grid-auto-flow: column; - gap: 0.5rem; - height: 2.75rem; - padding-inline: 1rem; - border-radius: 999px; - text-decoration: none; -} - -.home-link svg { - width: 1.25rem; - height: 1.25rem; -} - .map-control:disabled { opacity: 0.4; cursor: default; @@ -236,10 +256,10 @@ .main-nav ul { display: grid; - grid-template-columns: repeat(auto-fit, minmax(7.5rem, 1fr)); - gap: 0.5rem; - max-width: 52rem; - margin: 1rem auto 0; + grid-template-columns: repeat(auto-fit, minmax(6.25rem, 1fr)); + gap: 0.4rem; + max-width: 44rem; + margin: 0.85rem auto 0; padding: 0; list-style: none; } @@ -248,11 +268,12 @@ display: flex; align-items: center; justify-content: center; - gap: 0.45rem; - padding: 0.6rem 0.75rem; - border-radius: 0.6rem; - background: var(--navy-700); + gap: 0.4rem; + padding: 0.3rem 0.55rem; + border-radius: 0.5rem; + background: rgb(10 34 64 / 0.6); color: var(--eggshell); + font-size: 0.85rem; font-weight: 600; text-decoration: none; transition: @@ -263,8 +284,8 @@ .nav-icon { flex: none; - width: 1.2rem; - height: 1.2rem; + width: 1rem; + height: 1rem; } .main-nav a:hover { @@ -643,3 +664,49 @@ .status-closed { color: var(--closed); } + +/* Innholdet tones inn når man bytter side, så overgangen blir myk. */ +@keyframes page-in { + from { + opacity: 0; + } +} + +main { + animation: page-in 0.2s ease-out; +} + +/* ---------- Bunn ---------- */ + +/* Rotfeltet fyller vinduet, så sitatet havner nederst også på korte sider. */ +#root { + display: flex; + flex-direction: column; + min-height: 100dvh; +} + +.site-footer { + margin-top: auto; + padding: 3.5rem 1.5rem 2.5rem; + color: #8f765a; + font-family: Georgia, 'Times New Roman', serif; + font-size: 0.85rem; + font-style: italic; + text-align: center; +} + +.site-footer figure, +.site-footer blockquote, +.site-footer p { + margin: 0; +} + +.site-footer figure { + max-width: 32rem; + margin-inline: auto; +} + +.site-footer figcaption { + margin-top: 0.3rem; + font-size: 0.8rem; +} diff --git a/client/src/App.tsx b/client/src/App.tsx index a33c6e4..1b135d9 100644 --- a/client/src/App.tsx +++ b/client/src/App.tsx @@ -1,4 +1,7 @@ +import { useEffect } from 'react' import './App.css' +import { PageFooter } from './components/PageFooter' +import { PageHeader } from './components/PageHeader' import { useRoute } from './hooks/useRoute' import { ChallengesPage } from './pages/ChallengesPage' import { HomePage } from './pages/HomePage' @@ -13,9 +16,21 @@ const pages = { } function App() { - const Page = pages[useRoute()] + const route = useRoute() + const Page = pages[route] - return + // Hver side starter øverst, ikke der forrige side var rullet til. + useEffect(() => { + window.scrollTo(0, 0) + }, [route]) + + return ( + <> + + + + + ) } export default App diff --git a/client/src/components/HomeLink.tsx b/client/src/components/HomeLink.tsx deleted file mode 100644 index cecb09d..0000000 --- a/client/src/components/HomeLink.tsx +++ /dev/null @@ -1,23 +0,0 @@ -import { HOME_HREF } from '../hooks/useRoute' - -/** Knappen øverst til venstre som tar deg tilbake til hovedsiden. */ -export function HomeLink() { - return ( - - - Hovedside - - ) -} diff --git a/client/src/components/MainNav.tsx b/client/src/components/MainNav.tsx index 0ef9132..e2acfb4 100644 --- a/client/src/components/MainNav.tsx +++ b/client/src/components/MainNav.tsx @@ -4,7 +4,9 @@ import { HOME_HREF, MAP_HREF, USER_HREF, + useRoute, } from '../hooks/useRoute' +import type { Route } from '../hooks/useRoute' /** Felles tegning for ikonene: små, enkle strek-ikoner. */ function Icon({ children }: { children: ReactNode }) { @@ -25,16 +27,17 @@ function Icon({ children }: { children: ReactNode }) { ) } -/** Foreløpige lenker. «Hjem» er siden vi står på. */ +/** Lenkene i hovednavigasjonen. «Ruter» har ingen side ennå. */ const links: { label: string icon: ReactNode href?: string - current?: boolean + route?: Route }[] = [ { label: 'Utforsk', href: MAP_HREF, + route: 'map', // Kompass icon: ( @@ -57,7 +60,7 @@ const links: { { label: 'Hjem', href: HOME_HREF, - current: true, + route: 'home', // Anker icon: ( @@ -69,6 +72,7 @@ const links: { { label: 'Utfordringer', href: CHALLENGES_HREF, + route: 'challenges', // Flagg icon: ( @@ -79,6 +83,7 @@ const links: { { label: 'Bruker', href: USER_HREF, + route: 'user', // Person icon: ( @@ -90,12 +95,17 @@ const links: { ] export function MainNav() { + const current = useRoute() + return (