From 13417e558b2e2fee359c833b3339fe6a2fbc1a39 Mon Sep 17 00:00:00 2001 From: Mari Zhevagin Date: Wed, 14 Oct 2026 21:14:52 +0200 Subject: [PATCH 1/5] knapper til header --- client/src/components/layout/NavMenu.tsx | 98 +++++++++++++++++++ .../src/components/layout/NewRecipeButton.tsx | 37 +++++++ 2 files changed, 135 insertions(+) create mode 100644 client/src/components/layout/NavMenu.tsx create mode 100644 client/src/components/layout/NewRecipeButton.tsx diff --git a/client/src/components/layout/NavMenu.tsx b/client/src/components/layout/NavMenu.tsx new file mode 100644 index 0000000..36c0865 --- /dev/null +++ b/client/src/components/layout/NavMenu.tsx @@ -0,0 +1,98 @@ +import { NavLink } from 'react-router'; +import BookIcon from '@mui/icons-material/Book'; +import MenuBookIcon from '@mui/icons-material/MenuBook'; +import FavoriteBorderIcon from '@mui/icons-material/FavoriteBorder'; +import FavoriteIcon from '@mui/icons-material/Favorite'; +import ShoppingCartIcon from '@mui/icons-material/ShoppingCart'; +import AddShoppingCartIcon from '@mui/icons-material/AddShoppingCart'; +import type { SvgIconComponent } from '@mui/icons-material'; +import { useCurrentUser } from '../../lib/useCurrentUser'; +import { LoginRequiredDialog } from './LoginRequiredDialog'; + +// rosa fokusring +const FOCUS_RING = + 'focus-visible:outline-2 focus-visible:outline-offset-4 focus-visible:outline-pink-light'; + +// ikon og tekst ved siden av hverandre, rødt når aktiv +function linkClass({ isActive }: { isActive: boolean }) { + return `flex items-center gap-2 whitespace-nowrap transition-colors ${FOCUS_RING} ${ + isActive ? 'text-primary' : 'text-text hover:text-primary' + }`; +} + +type MenuLinkProps = { + to: string; + label: string; + icon: SvgIconComponent; + activeIcon: SvgIconComponent; +}; + +// bytter ikon og understreker teksten på aktiv side +function MenuLink({ to, label, icon: Icon, activeIcon: ActiveIcon }: MenuLinkProps) { + return ( + + {({ isActive }) => ( + <> + {isActive ? + ); +} + +// menyen som brukes i begge headerne på desktop +export function NavMenu() { + const { user } = useCurrentUser(); + + // ser ut som menylenken men åpner innloggingspopupen + const favoritesButton = ( + + ); + + return ( + + ); +} \ No newline at end of file diff --git a/client/src/components/layout/NewRecipeButton.tsx b/client/src/components/layout/NewRecipeButton.tsx new file mode 100644 index 0000000..12e18ea --- /dev/null +++ b/client/src/components/layout/NewRecipeButton.tsx @@ -0,0 +1,37 @@ +import { useState, type ReactNode } from 'react'; +import { Dialog } from '../ui/Dialog'; +import NewRecipePage from '../../routes/NewRecipePage'; +import { RecipeStepIndicator } from '../new-recipe/RecipeStepIndicator'; +import { useCurrentUser } from '../../lib/useCurrentUser'; +import { LoginRequiredDialog } from './LoginRequiredDialog'; + +type NewRecipeButtonProps = { + // knappen som vises, er forskjellig på pc og mobil + trigger: ReactNode; +}; + +// åpner ny oppskrift eller innloggingspopup hvis man ikke er logget inn +export function NewRecipeButton({ trigger }: NewRecipeButtonProps) { + const { user } = useCurrentUser(); + // hvordan steg i ny oppskrift man er på + const [currentStep, setCurrentStep] = useState(1); + + if (!user) { + return ( + + ); + } + + return ( + } + > + + + ); +} \ No newline at end of file From 01805e641eef36663e0e51834bcb529a5574ee41 Mon Sep 17 00:00:00 2001 From: Mari Zhevagin Date: Wed, 14 Oct 2026 22:24:40 +0200 Subject: [PATCH 2/5] pc header --- client/src/components/layout/Header.tsx | 151 +++--------------- client/src/components/layout/NavMenu.tsx | 34 +++- client/src/components/layout/SearchBar.tsx | 42 +++-- client/src/components/layout/StickyHeader.tsx | 50 ++++++ client/src/components/layout/TopHeader.tsx | 80 ++++++++++ client/src/components/layout/UserLink.tsx | 28 ++++ client/src/index.css | 3 + 7 files changed, 238 insertions(+), 150 deletions(-) create mode 100644 client/src/components/layout/StickyHeader.tsx create mode 100644 client/src/components/layout/TopHeader.tsx create mode 100644 client/src/components/layout/UserLink.tsx diff --git a/client/src/components/layout/Header.tsx b/client/src/components/layout/Header.tsx index 579c141..b8910cc 100644 --- a/client/src/components/layout/Header.tsx +++ b/client/src/components/layout/Header.tsx @@ -1,139 +1,36 @@ -import { useState } from 'react'; -import { Link, NavLink, useSearchParams } from 'react-router'; -import SearchBar from './SearchBar'; -import { Button } from '../ui/Button'; -import { Dialog } from '../ui/Dialog'; -import NewRecipePage from '../../routes/NewRecipePage'; -import { RecipeStepIndicator } from '../new-recipe/RecipeStepIndicator'; -import { useCurrentUser } from '../../lib/useCurrentUser'; -import { LoginRequiredDialog } from './LoginRequiredDialog'; +import { useEffect, useState } from 'react'; +import { useSearchParams } from 'react-router'; +import { TopHeader } from './TopHeader'; +import { StickyHeader } from './StickyHeader'; -// Fokusmarkering ved tastaturnavigasjon -const focusRing = - 'focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary'; - -// Aktiv lenke markeres med både farge og understrek -function navLinkClass({ isActive }: { isActive: boolean }) { - const base = `whitespace-nowrap font-body transition-colors hover:text-primary ${focusRing}`; - - return isActive - ? `${base} text-primary underline underline-offset-4` - : `${base} text-text`; -} - -// Styling for knapper/lenker i header -const buttonBase = `whitespace-nowrap rounded-medium px-3 py-2 text-sm font-body transition-colors ${focusRing}`; - -// Brukerknapp -function userClass({ isActive }: { isActive: boolean }) { - const base = `${buttonBase} border border-primary`; - - return isActive - ? `${base} bg-primary text-background` - : `${base} text-primary hover:bg-pink-light`; -} +// hvor langt man scroller før den lille headeren vises +const SCROLL_LIMIT = 160; export default function Header() { - // hvem som er logget inn - const { user } = useCurrentUser(); - // Søkeordet fra URL-en + // Søkeordet fra URL const [searchParams] = useSearchParams(); const query = searchParams.get('q') ?? ''; - // holder styr på hvilket steg i Ny oppskrift brukeren er på - const [currentStep, setCurrentStep] = useState(1); - - // knapp som åpner ny oppskrift eller innloggingspopup hvis man ikke er logget inn - const newRecipeButton = ( - - ); - - // åpner innloggings popupen - const favoritesButton = ( - - ); - - return ( -
-
- {/* Logo */} - - Oppskriftsbok - - - {/* Søkefelt */} - + // om man har scrollet forbi den store headeren + const [scrolled, setScrolled] = useState(false); - {/* Navigasjon */} - -
-
+ return ( + <> + + + ); } diff --git a/client/src/components/layout/NavMenu.tsx b/client/src/components/layout/NavMenu.tsx index 36c0865..5a5acd7 100644 --- a/client/src/components/layout/NavMenu.tsx +++ b/client/src/components/layout/NavMenu.tsx @@ -20,21 +20,36 @@ function linkClass({ isActive }: { isActive: boolean }) { }`; } +// gjør at det bare blir ikoner på smale skjermer (gjelder ikke mobil eller skjermlesere) +const COMPACT_LABEL = 'sr-only lg:not-sr-only'; + type MenuLinkProps = { to: string; label: string; icon: SvgIconComponent; activeIcon: SvgIconComponent; + // bare ikon på smale skjermer + compact: boolean; }; // bytter ikon og understreker teksten på aktiv side -function MenuLink({ to, label, icon: Icon, activeIcon: ActiveIcon }: MenuLinkProps) { +function MenuLink({ + to, + label, + icon: Icon, + activeIcon: ActiveIcon, + compact, +}: MenuLinkProps) { return ( {({ isActive }) => ( <> {isActive ?