feat: sync design of header with current web
This commit is contained in:
@@ -0,0 +1,42 @@
|
|||||||
|
.button {
|
||||||
|
background-color: #02838e;
|
||||||
|
color: #fff;
|
||||||
|
padding: 5px 15px;
|
||||||
|
display: inline-block;
|
||||||
|
line-height: 20px;
|
||||||
|
border: 1px solid transparent;
|
||||||
|
border-radius: 50px;
|
||||||
|
height: 32px;
|
||||||
|
line-height: 20px;
|
||||||
|
font-size: 14px;
|
||||||
|
font-family: Helvetica, Arial, sans-serif;
|
||||||
|
font-weight: 400;
|
||||||
|
font-size: 16px;
|
||||||
|
cursor: pointer;
|
||||||
|
text-decoration: none;
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
-moz-osx-font-smoothing: grayscale;
|
||||||
|
text-rendering: optimizeLegibility;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button:hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button:focus,
|
||||||
|
.button:active {
|
||||||
|
box-shadow: 0 0 1px 2px #b4defa;
|
||||||
|
outline: none;
|
||||||
|
border: 1px solid hsl(0, 0%, 80%);
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media screen and (min-width: 950px) {
|
||||||
|
.button {
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 16px;
|
||||||
|
line-height: 24px;
|
||||||
|
height: auto;
|
||||||
|
padding: 12px 32px;
|
||||||
|
}
|
||||||
|
}
|
||||||
11
components/Current/Header/BookingButton/index.tsx
Normal file
11
components/Current/Header/BookingButton/index.tsx
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
import "@scandic-hotels/design-system/current/style.css"
|
||||||
|
|
||||||
|
import styles from "./bookingButton.module.css"
|
||||||
|
|
||||||
|
export default function BookingButton() {
|
||||||
|
return (
|
||||||
|
<a className={styles.button} href="/">
|
||||||
|
Book
|
||||||
|
</a>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -2,7 +2,8 @@
|
|||||||
import { useState } from "react"
|
import { useState } from "react"
|
||||||
|
|
||||||
import Image from "@/components/Image"
|
import Image from "@/components/Image"
|
||||||
import Button from "@/components/TempDesignSystem/Button"
|
|
||||||
|
import BookingButton from "../BookingButton"
|
||||||
|
|
||||||
import styles from "./mainMenu.module.css"
|
import styles from "./mainMenu.module.css"
|
||||||
|
|
||||||
@@ -82,9 +83,9 @@ export function MainMenu({
|
|||||||
<li className={styles.mobileLi}>{languageSwitcher}</li>
|
<li className={styles.mobileLi}>{languageSwitcher}</li>
|
||||||
) : null}
|
) : null}
|
||||||
</ul>
|
</ul>
|
||||||
{/* <div className={styles.buttonContainer}>
|
<div className={styles.buttonContainer}>
|
||||||
<Button>Book</Button>
|
<BookingButton />
|
||||||
</div> */}
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -25,7 +25,7 @@
|
|||||||
.navBar {
|
.navBar {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: 1fr 80px 1fr;
|
grid-template-columns: 1fr 80px 1fr;
|
||||||
padding-bottom: 1.5px;
|
height: 52.39px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.expanderBtn {
|
.expanderBtn {
|
||||||
@@ -33,8 +33,7 @@
|
|||||||
border: none;
|
border: none;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
justify-self: flex-start;
|
justify-self: flex-start;
|
||||||
left: 0;
|
padding: 11px 8px 16px;
|
||||||
padding: 12px 8px 16px;
|
|
||||||
transition: 0.3s;
|
transition: 0.3s;
|
||||||
user-select: none;
|
user-select: none;
|
||||||
}
|
}
|
||||||
@@ -45,7 +44,7 @@
|
|||||||
background: #757575;
|
background: #757575;
|
||||||
border-radius: 2.3px;
|
border-radius: 2.3px;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
height: 4.6px;
|
height: 5px;
|
||||||
position: relative;
|
position: relative;
|
||||||
transition: 0.3s;
|
transition: 0.3s;
|
||||||
width: 32px;
|
width: 32px;
|
||||||
@@ -178,6 +177,8 @@
|
|||||||
.buttonContainer {
|
.buttonContainer {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: flex-end;
|
justify-content: flex-end;
|
||||||
|
align-items: center;
|
||||||
|
margin-right: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media screen and (min-width: 1367px) {
|
@media screen and (min-width: 1367px) {
|
||||||
@@ -200,6 +201,7 @@
|
|||||||
.navBar {
|
.navBar {
|
||||||
grid-template-columns: 132.18px 1fr auto;
|
grid-template-columns: 132.18px 1fr auto;
|
||||||
align-content: center;
|
align-content: center;
|
||||||
|
height: 85.09px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.expanderBtn {
|
.expanderBtn {
|
||||||
@@ -261,6 +263,7 @@
|
|||||||
@media (min-width: 1200px) {
|
@media (min-width: 1200px) {
|
||||||
.navBar {
|
.navBar {
|
||||||
grid-template-columns: 140px auto 1fr;
|
grid-template-columns: 140px auto 1fr;
|
||||||
|
height: 82.4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.logoLink {
|
.logoLink {
|
||||||
|
|||||||
@@ -1,13 +1,18 @@
|
|||||||
|
import { auth } from "@/auth"
|
||||||
|
|
||||||
import styles from "./topMenu.module.css"
|
import styles from "./topMenu.module.css"
|
||||||
|
|
||||||
import type { TopMenuProps } from "@/types/components/current/header/topMenu"
|
import type { TopMenuProps } from "@/types/components/current/header/topMenu"
|
||||||
|
|
||||||
export default function TopMenu({
|
export default async function TopMenu({
|
||||||
frontpageLinkText,
|
frontpageLinkText,
|
||||||
homeHref,
|
homeHref,
|
||||||
links,
|
links,
|
||||||
languageSwitcher,
|
languageSwitcher,
|
||||||
|
lang,
|
||||||
}: TopMenuProps) {
|
}: TopMenuProps) {
|
||||||
|
const session = await auth()
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.topMenu}>
|
<div className={styles.topMenu}>
|
||||||
<div className={styles.container}>
|
<div className={styles.container}>
|
||||||
@@ -25,6 +30,17 @@ export default function TopMenu({
|
|||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
))}
|
))}
|
||||||
|
<li className={styles.loginContainer}>
|
||||||
|
{session ? (
|
||||||
|
<a href={`${lang}/logout`} className={styles.loginLink}>
|
||||||
|
Log out
|
||||||
|
</a>
|
||||||
|
) : (
|
||||||
|
<a href={`${lang}/login`} className={styles.loginLink}>
|
||||||
|
Log in
|
||||||
|
</a>
|
||||||
|
)}
|
||||||
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -37,12 +37,15 @@
|
|||||||
Arial,
|
Arial,
|
||||||
sans-serif;
|
sans-serif;
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
|
font-weight: 400;
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
-moz-osx-font-smoothing: grayscale;
|
||||||
|
text-rendering: optimizeLegibility;
|
||||||
}
|
}
|
||||||
.langSwitcher {
|
.langSwitcher {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
position: relative;
|
position: relative;
|
||||||
display: block;
|
display: block;
|
||||||
padding: 3px 15px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@media screen and (min-width: 768px) {
|
@media screen and (min-width: 768px) {
|
||||||
@@ -63,6 +66,16 @@
|
|||||||
.link {
|
.link {
|
||||||
padding-top: 4px;
|
padding-top: 4px;
|
||||||
padding-bottom: 4px;
|
padding-bottom: 4px;
|
||||||
font-weight: 300;
|
}
|
||||||
|
|
||||||
|
.loginContainer {
|
||||||
|
margin-left: 10px;
|
||||||
|
background-color: #f3f2f1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.loginLink {
|
||||||
|
padding-left: 30px;
|
||||||
|
padding-right: 30px;
|
||||||
|
color: #000;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ export default async function Header({
|
|||||||
lang,
|
lang,
|
||||||
languageSwitcher,
|
languageSwitcher,
|
||||||
}: LangParams & { languageSwitcher: React.ReactNode }) {
|
}: LangParams & { languageSwitcher: React.ReactNode }) {
|
||||||
const data = await serverClient().contentstack.config.header()
|
const data = await serverClient().contentstack.config.header({ lang })
|
||||||
|
|
||||||
const homeHref = homeHrefs[env.NODE_ENV][lang]
|
const homeHref = homeHrefs[env.NODE_ENV][lang]
|
||||||
const { frontpage_link_text, logo, menu, top_menu } = data
|
const { frontpage_link_text, logo, menu, top_menu } = data
|
||||||
@@ -31,6 +31,7 @@ export default async function Header({
|
|||||||
homeHref={homeHref}
|
homeHref={homeHref}
|
||||||
links={top_menu.links}
|
links={top_menu.links}
|
||||||
languageSwitcher={languageSwitcher}
|
languageSwitcher={languageSwitcher}
|
||||||
|
lang={lang}
|
||||||
/>
|
/>
|
||||||
<MainMenu
|
<MainMenu
|
||||||
frontpageLinkText={frontpage_link_text}
|
frontpageLinkText={frontpage_link_text}
|
||||||
|
|||||||
@@ -1,16 +0,0 @@
|
|||||||
.hamburger {
|
|
||||||
background: none;
|
|
||||||
border: none;
|
|
||||||
cursor: pointer;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
gap: 0.5rem;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.line {
|
|
||||||
background-color: var(--some-black-color, #1c1b1f);
|
|
||||||
border-radius: 0.8rem;
|
|
||||||
height: 0.2rem;
|
|
||||||
width: 2.5rem;
|
|
||||||
}
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
import styles from "./hamburger.module.css"
|
|
||||||
|
|
||||||
export default function Hamburger() {
|
|
||||||
return (
|
|
||||||
<button className={styles.hamburger} type="button">
|
|
||||||
<div className={styles.line} />
|
|
||||||
<div className={styles.line} />
|
|
||||||
<div className={styles.line} />
|
|
||||||
</button>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
import Image from "@/components/Image"
|
|
||||||
|
|
||||||
import styles from "./language.module.css"
|
|
||||||
|
|
||||||
export default function LanguageSwitcher() {
|
|
||||||
return (
|
|
||||||
<div className={styles.switcher}>
|
|
||||||
<Image
|
|
||||||
alt="Swedish flag"
|
|
||||||
height={21}
|
|
||||||
src="/_static/icons/sweden.svg"
|
|
||||||
width={21}
|
|
||||||
/>
|
|
||||||
<span>SV / SEK</span>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
.switcher {
|
|
||||||
align-items: center;
|
|
||||||
display: none;
|
|
||||||
font-family: var(--typography-Body-Regular-fontFamily);
|
|
||||||
font-size: 1.4rem;
|
|
||||||
font-weight: 400;
|
|
||||||
gap: 0.6rem;
|
|
||||||
line-height: 1.6rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media screen and (min-width: 1367px) {
|
|
||||||
.switcher {
|
|
||||||
display: flex;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
import Link from "next/link"
|
|
||||||
|
|
||||||
import Image from "@/components/Image"
|
|
||||||
|
|
||||||
import styles from "./logo.module.css"
|
|
||||||
|
|
||||||
import { LogoProps } from "@/types/components/header/logo"
|
|
||||||
|
|
||||||
export default async function Logo({ title, height, width, src }: LogoProps) {
|
|
||||||
return (
|
|
||||||
<Link className={styles.link} href="#">
|
|
||||||
<Image alt={title} height={height} src={src} width={width} />
|
|
||||||
</Link>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
.link {
|
|
||||||
cursor: pointer;
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
.header {
|
|
||||||
align-items: center;
|
|
||||||
background-color: var(--some-white-color, #fff);
|
|
||||||
box-shadow: 0px 1.0006656646728516px 1.0006656646728516px 0px #0000000d;
|
|
||||||
display: grid;
|
|
||||||
gap: 3rem;
|
|
||||||
grid-template-columns: 1fr auto auto;
|
|
||||||
height: var(--header-height);
|
|
||||||
|
|
||||||
padding: 0 2rem;
|
|
||||||
position: sticky;
|
|
||||||
top: 0;
|
|
||||||
z-index: 999;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media screen and (min-width: 1367px) {
|
|
||||||
.header {
|
|
||||||
background-color: var(--some-grey-color, #ececec);
|
|
||||||
border-bottom: 0.1rem solid var(--some-grey-color, #ccc);
|
|
||||||
box-shadow: none;
|
|
||||||
gap: 3.2rem;
|
|
||||||
grid-template-columns: 1fr 19rem auto auto;
|
|
||||||
padding: 0 2.4rem;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
import { GetHeader } from "@/lib/graphql/Query/Header.graphql"
|
|
||||||
import { request } from "@/lib/graphql/request"
|
|
||||||
|
|
||||||
import Logo from "./Logo"
|
|
||||||
|
|
||||||
import styles from "./header.module.css"
|
|
||||||
|
|
||||||
import type { LangParams } from "@/types/params"
|
|
||||||
import { HeaderQueryData } from "@/types/requests/header"
|
|
||||||
|
|
||||||
export default async function Header({ lang }: LangParams) {
|
|
||||||
const { data } = await request<HeaderQueryData>(GetHeader, {
|
|
||||||
locale: lang,
|
|
||||||
})
|
|
||||||
|
|
||||||
if (
|
|
||||||
!data.all_header.items.length ||
|
|
||||||
!data.all_header.items?.[0].logoConnection.totalCount
|
|
||||||
) {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
const logo = data.all_header.items[0].logoConnection.edges[0]
|
|
||||||
|
|
||||||
return (
|
|
||||||
<header className={styles.header}>
|
|
||||||
<Logo
|
|
||||||
title={logo.node.title}
|
|
||||||
height={logo.node.dimension.height}
|
|
||||||
width={logo.node.dimension.width}
|
|
||||||
src={logo.node.url}
|
|
||||||
/>
|
|
||||||
</header>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
#import "../Fragments/Image.graphql"
|
|
||||||
|
|
||||||
query GetHeader($locale: String!) {
|
|
||||||
all_header(limit: 1, locale: $locale) {
|
|
||||||
items {
|
|
||||||
frontpage_link_text
|
|
||||||
logoConnection {
|
|
||||||
edges {
|
|
||||||
node {
|
|
||||||
...Image
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
menu {
|
|
||||||
links {
|
|
||||||
href
|
|
||||||
title
|
|
||||||
}
|
|
||||||
}
|
|
||||||
top_menu {
|
|
||||||
links {
|
|
||||||
link {
|
|
||||||
href
|
|
||||||
title
|
|
||||||
}
|
|
||||||
show_on_mobile
|
|
||||||
sort_order_mobile
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
9
server/routers/contentstack/config/input.ts
Normal file
9
server/routers/contentstack/config/input.ts
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
import z from "zod"
|
||||||
|
|
||||||
|
import { Lang } from "@/constants/languages"
|
||||||
|
|
||||||
|
export const headerInput = z
|
||||||
|
.object({
|
||||||
|
lang: z.nativeEnum(Lang),
|
||||||
|
})
|
||||||
|
.optional()
|
||||||
@@ -4,6 +4,7 @@ import { request } from "@/lib/graphql/request"
|
|||||||
import { internalServerError, notFound } from "@/server/errors/trpc"
|
import { internalServerError, notFound } from "@/server/errors/trpc"
|
||||||
import { contentstackProcedure, publicProcedure, router } from "@/server/trpc"
|
import { contentstackProcedure, publicProcedure, router } from "@/server/trpc"
|
||||||
|
|
||||||
|
import { headerInput } from "./input"
|
||||||
import {
|
import {
|
||||||
type ContactConfigData,
|
type ContactConfigData,
|
||||||
HeaderData,
|
HeaderData,
|
||||||
@@ -34,11 +35,12 @@ export const configQueryRouter = router({
|
|||||||
|
|
||||||
return validatedContactConfigConfig.data.all_contact_config.items[0]
|
return validatedContactConfigConfig.data.all_contact_config.items[0]
|
||||||
}),
|
}),
|
||||||
header: publicProcedure.query(async ({ ctx }) => {
|
header: publicProcedure.input(headerInput).query(async ({ input, ctx }) => {
|
||||||
|
const locale = input?.lang || ctx.lang
|
||||||
const response = await request<HeaderDataRaw>(
|
const response = await request<HeaderDataRaw>(
|
||||||
GetCurrentHeader,
|
GetCurrentHeader,
|
||||||
{ locale: ctx.lang },
|
{ locale },
|
||||||
{ next: { tags: [`header-${ctx.lang}`] } }
|
{ next: { tags: [`header-${locale}`] } }
|
||||||
)
|
)
|
||||||
|
|
||||||
if (!response.data) {
|
if (!response.data) {
|
||||||
|
|||||||
@@ -1,10 +1,13 @@
|
|||||||
import type { Image } from "@/types/image"
|
import type { Image } from "@/types/image"
|
||||||
import type { HeaderLink, TopMenuHeaderLink } from "@/types/requests/header"
|
import type {
|
||||||
|
CurrentHeaderLink,
|
||||||
|
TopMenuHeaderLink,
|
||||||
|
} from "@/types/requests/currentHeader"
|
||||||
|
|
||||||
export type MainMenuProps = {
|
export type MainMenuProps = {
|
||||||
frontpageLinkText: string
|
frontpageLinkText: string
|
||||||
homeHref: string
|
homeHref: string
|
||||||
links: HeaderLink[]
|
links: CurrentHeaderLink[]
|
||||||
logo: Image
|
logo: Image
|
||||||
topMenuMobileLinks: TopMenuHeaderLink[]
|
topMenuMobileLinks: TopMenuHeaderLink[]
|
||||||
languageSwitcher: React.ReactNode
|
languageSwitcher: React.ReactNode
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
import type { TopMenuHeaderLink } from "@/types/requests/header"
|
import type { TopMenuHeaderLink } from "@/types/requests/currentHeader"
|
||||||
|
|
||||||
export type TopMenuProps = {
|
export type TopMenuProps = {
|
||||||
frontpageLinkText: string
|
frontpageLinkText: string
|
||||||
homeHref: string
|
homeHref: string
|
||||||
links: TopMenuHeaderLink[]
|
links: TopMenuHeaderLink[]
|
||||||
languageSwitcher: React.ReactNode
|
languageSwitcher: React.ReactNode
|
||||||
|
lang: string
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ export type CurrentHeaderLink = {
|
|||||||
title: string
|
title: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export type TopMenuCurrentHeaderLink = {
|
export type TopMenuHeaderLink = {
|
||||||
link: {
|
link: {
|
||||||
href: string
|
href: string
|
||||||
title: string
|
title: string
|
||||||
@@ -21,7 +21,7 @@ export type CurrentHeaderLinks = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export type TopMenuCurrentHeaderLinks = {
|
export type TopMenuCurrentHeaderLinks = {
|
||||||
links: TopMenuCurrentHeaderLink[]
|
links: TopMenuHeaderLink[]
|
||||||
}
|
}
|
||||||
|
|
||||||
export type CurrentHeader = {
|
export type CurrentHeader = {
|
||||||
|
|||||||
@@ -1,35 +0,0 @@
|
|||||||
import type { Image } from "../image"
|
|
||||||
import type { EdgesWithTotalCount } from "./utils/edges"
|
|
||||||
|
|
||||||
export type HeaderLink = {
|
|
||||||
href: string
|
|
||||||
title: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export type TopMenuHeaderLink = {
|
|
||||||
link: {
|
|
||||||
href: string
|
|
||||||
title: string
|
|
||||||
}
|
|
||||||
show_on_mobile: boolean
|
|
||||||
sort_order_mobile: number
|
|
||||||
}
|
|
||||||
|
|
||||||
export type HeaderLinks = {
|
|
||||||
links: HeaderLink[]
|
|
||||||
}
|
|
||||||
|
|
||||||
export type TopMenuHeaderLinks = {
|
|
||||||
links: TopMenuHeaderLink[]
|
|
||||||
}
|
|
||||||
|
|
||||||
export type HeaderQueryData = {
|
|
||||||
all_header: {
|
|
||||||
items: {
|
|
||||||
frontpage_link_text: string
|
|
||||||
logoConnection: EdgesWithTotalCount<Image>
|
|
||||||
menu: HeaderLinks
|
|
||||||
top_menu: TopMenuHeaderLinks
|
|
||||||
}[]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user