Merged in feat/responsiveness (pull request #26)

[WEB-87] Feat/responsiveness
This commit is contained in:
Christel Westerberg
2024-02-14 09:41:23 +00:00
29 changed files with 361 additions and 112 deletions

View File

@@ -1,21 +1,21 @@
import { previewRequest } from "@/lib/previewRequest"
import { GetCurrentBlockPage } from "@/lib/graphql/Query/CurrentBlockPage.graphql"
import type { PageArgs, LangParams, UriParams } from "@/types/params"
import type { PageArgs, LangParams, PreviewParams } from "@/types/params"
import type { GetCurrentBlockPageData } from "@/types/requests/currentBlockPage"
import ContentstackLivePreview from "@contentstack/live-preview-utils"
import LoadingPreview from "@/components/Current/LoadingPreview"
import LoadingSpinner from "@/components/Current/LoadingSpinner"
import ContentPage from "@/components/Current/ContentPage"
export default async function CurrentContentPage({
params,
searchParams,
}: PageArgs<LangParams, UriParams>) {
}: PageArgs<LangParams, PreviewParams>) {
try {
ContentstackLivePreview.setConfigFromParams(searchParams)
if (!searchParams.uri) {
return <LoadingPreview />
if (!searchParams.uri || !searchParams.live_preview) {
return <LoadingSpinner />
}
const response = await previewRequest<GetCurrentBlockPageData>(

View File

@@ -0,0 +1,82 @@
import styles from "./contact.module.css"
import { langEnum } from "@/types/lang"
import type { Lang } from "@/types/lang"
import type { ContactNode } from "@/types/requests/asides/contact"
export default function Contact({
title,
mailing_address,
visiting_address,
phone,
system: { locale },
}: ContactNode) {
const visitingAddressMessage = getVisitingAddressMessage(locale)
return (
<div>
<div>
<div>
<div>
<h2 className={styles.heading}>{title}</h2>
<p>
{mailing_address.name}
<br />
{mailing_address.street}
<br />
{mailing_address.zip} {mailing_address.city}
<br />
{mailing_address.country}
</p>
<p>
{visitingAddressMessage}: {visiting_address.street}{" "}
</p>
</div>
</div>
<div>
<div className={styles.highlightBlock}>
<h3>{phone.title}</h3>
<div className={styles.phoneContainer}>
<svg
focusable="false"
className={styles.phoneIcon}
viewBox="0 0 32 32"
>
<use
xmlnsXlink="http://www.w3.org/1999/xlink"
xlinkHref="/Static/img/icons/sprites.svg#icon-phone"
></use>
</svg>
<a
href={phone.number}
itemProp="telephone"
className={styles.phoneNumberLink}
>
{phone.number}
</a>
</div>
</div>
</div>
</div>
</div>
)
}
function getVisitingAddressMessage(lang: Lang) {
switch (lang) {
case langEnum.sv:
return "Besöksadress"
case langEnum.en:
return "Visiting address"
case langEnum.da:
return "Besøgsadresse"
case langEnum.de:
return "Besuchsadresse"
case langEnum.fi:
return "Vierailuosoite"
case langEnum.no:
return "Besøksadresse"
default:
return ""
}
}

View File

@@ -0,0 +1,62 @@
.highlightBlock {
padding: 10px 10px 15px;
background: #fff;
overflow: hidden;
}
.heading {
font-family: BrandonText-Bold, Arial, Helvetica, sans-serif;
font-size: 1.375rem;
line-height: 1.1em;
text-transform: uppercase;
font-weight: 400;
color: #483729;
margin-bottom: 1rem;
}
.phoneContainer {
display: flex;
gap: 10px;
align-items: center;
}
.phoneNumberLink {
line-height: 1.1em;
font-family: Helvetica, Arial, sans-serif;
font-weight: 400;
text-transform: none;
font-size: 1.125rem;
color: #00838e;
text-decoration: none;
cursor: pointer;
}
.phoneIcon {
width: 42px;
height: 42px;
fill: #00838e;
}
.p {
color: #333;
line-height: 1.3;
margin-bottom: 1em;
padding-top: 7px;
text-decoration: none;
}
.phoneNumberLink:active,
.phoneNumberLink:hover {
outline: 0;
text-decoration: underline;
}
@media screen and (min-width: 950px) {
.heading {
font-size: 1.625rem;
}
.phoneNumberLink {
line-height: 1.1em;
font-size: 1.375rem;
}
}

View File

@@ -0,0 +1,8 @@
import type { ContactsProps } from "@/types/components/current/asides/contact"
import Contact from "./Contact"
export default function Contacts({ contacts }: ContactsProps) {
return contacts.map((contact) => (
<Contact key={contact.node.system.uid} {...contact.node} />
))
}

View File

@@ -8,7 +8,14 @@ import styles from "./puff.module.css"
import type { PuffProps } from "@/types/components/current/asides/puff"
import Image from "@/components/Image"
export default function Puff({ imageConnection, is_internal, link, pageConnection, text, title }: PuffProps) {
export default function Puff({
imageConnection,
is_internal,
link,
pageConnection,
text,
title,
}: PuffProps) {
if (is_internal) {
const page = pageConnection.edges[0]
if (!page?.node?.url) {
@@ -35,11 +42,14 @@ export default function Puff({ imageConnection, is_internal, link, pageConnectio
)
}
function PuffContent({ imageConnection, text, title }: Pick<PuffProps, "imageConnection" | "text" | "title">) {
function PuffContent({
imageConnection,
text,
title,
}: Pick<PuffProps, "imageConnection" | "text" | "title">) {
return (
<article>
{imageConnection.edges.map(image => (
{imageConnection.edges.map((image) => (
<Image
alt={image.node.title}
className={styles.image}
@@ -50,10 +60,8 @@ function PuffContent({ imageConnection, text, title }: Pick<PuffProps, "imageCon
/>
))}
<section className={styles.content}>
<header className="content-teaser__body-wrapper">
<h3 className={styles.heading}>
{title}
</h3>
<header>
<h3 className={styles.heading}>{title}</h3>
</header>
<JsonToHtml
embeds={text.embedded_itemsConnection.edges}
@@ -63,4 +71,4 @@ function PuffContent({ imageConnection, text, title }: Pick<PuffProps, "imageCon
</section>
</article>
)
}
}

View File

@@ -12,10 +12,12 @@
height: auto;
object-fit: contain;
object-position: center;
width: 100%;
}
.content {
padding: 20px 0px;
padding: 10px;
background-color: #fff;
}
.heading {
@@ -40,6 +42,12 @@
text-decoration: none;
}
@media screen and (min-width: 740px) {
.content {
padding: 20px 0px;
}
}
@media screen and (min-width: 950px) {
.heading {
font-size: 1.375rem;

View File

@@ -0,0 +1,3 @@
.wrapper {
padding: 20px 10px 5px;
}

View File

@@ -1,22 +1,35 @@
import Puffs from "./Asides/Puffs"
import Puffs from "./Puffs"
import Contacts from "./Contacts"
import { AsideTypenameEnum } from "@/types/requests/utils/typename"
import type { AsideProps } from "@/types/components/current/aside"
import styles from "./aside.module.css"
export default function Aside({ blocks }: AsideProps) {
if (!blocks?.length) {
return null
}
return (
<aside>
<aside className={styles.wrapper}>
{blocks.map((block, idx) => {
const type = block.__typename
switch (type) {
case AsideTypenameEnum.CurrentBlocksPageAsideContact:
return null
return (
<Contacts
contacts={block.contact.contactConnection.edges}
key={`block-${idx}`}
/>
)
case AsideTypenameEnum.CurrentBlocksPageAsidePuff:
return <Puffs key={`block-${idx}`} puffs={block.puff.puffConnection.edges} />
return (
<Puffs
key={`block-${idx}`}
puffs={block.puff.puffConnection.edges}
/>
)
default:
return null
}

View File

@@ -1,7 +1,9 @@
import Link from "next/link"
import { cva } from "class-variance-authority"
import { BlockListItemsEnum } from "@/types/requests/blocks/list"
import type { ListItem } from "@/types/requests/blocks/list"
import styles from "./list.module.css"
const config = {

View File

@@ -1,11 +1,11 @@
.title {
font-family: Helvetica, Arial, sans-serif;
font-family: BrandonText-Bold,Arial,Helvetica,sans-serif;
font-size: 1.375rem;
line-height: 1.1em;
text-transform: uppercase;
font-weight: 400;
line-height: normal;
margin-top: 2rem;
color: #483729;
margin-bottom: 1rem;
text-decoration: none;
text-transform: none;
}
.ul {
@@ -60,6 +60,6 @@
@media screen and (min-width: 950px) {
.title {
font-size: 1.375rem;
font-size: 1.625rem;
}
}

View File

@@ -0,0 +1,11 @@
.wrapper {
background-color: #fff;
padding: 20px 10px 5px;
}
@media screen and (min-width: 740px) {
.wrapper {
padding:20px 0 0;
}
}

View File

@@ -1,8 +1,10 @@
import List from "./Blocks/List"
import Puffs from "./Blocks/Puffs"
import Text from "./Blocks/Text"
import List from "./List"
import Puffs from "./Puffs"
import Text from "./Text"
import { BlocksTypenameEnum } from "@/types/requests/utils/typename"
import styles from "./blocks.module.css"
import type { BlocksProps } from "@/types/components/current/blocks"
export default function Blocks({ blocks }: BlocksProps) {
@@ -11,8 +13,8 @@ export default function Blocks({ blocks }: BlocksProps) {
}
return (
<section id="mainbody_personalized">
{blocks.map(block => {
<section className={styles.wrapper}>
{blocks.map((block) => {
const type = block.__typename
switch (type) {
case BlocksTypenameEnum.CurrentBlocksPageBlocksList:

View File

@@ -0,0 +1,8 @@
.wrapper {
width: 100%;
position: relative;
z-index: 10;
padding-bottom: 50px;
background: #f3f2f1;
display: block;
}

View File

@@ -6,8 +6,9 @@ import Preamble from "@/components/Current/Preamble"
import Section from "@/components/Current/Section"
import SubnavMobile from "@/components/Current/SubnavMobile"
import type { ContentPageProps } from "@/types/components/current/contentPage"
import styles from "./contentPage.module.css"
import type { ContentPageProps } from "@/types/components/current/contentPage"
export default function ContentPage({ data, lang, uri }: ContentPageProps) {
const page = data.all_current_blocks_page.items[0]
@@ -19,7 +20,7 @@ export default function ContentPage({ data, lang, uri }: ContentPageProps) {
<>
<Header lang={lang} pathname={uri} />
{images?.totalCount ? <Hero images={images.edges} /> : null}
<main className="main l-sections-wrapper" id="maincontent" role="main">
<main className={styles.wrapper} id="maincontent" role="main">
<input
id="lbl-personalized-areas"
name="lbl-personalized-areas"

View File

@@ -14,7 +14,6 @@ export default async function Footer({ lang }: LangParams) {
})
const footerData = response.data.all_footer.items[0]
return (
<footer className="global-footer">
<div className="global-footer__content">

View File

@@ -1,4 +1,26 @@
.wrapper {
z-index: 0;
}
.picture {
visibility: visible;
opacity: 1;
transition: opacity 400ms ease-in-out 0s;
transform: translate(-50%, -50%) !important;
}
.heroImage {
object-fit: cover;
width: 100%;
}
height: auto;
max-height: 600px;
min-height: 100px;
object-fit: cover;
object-position: center;
aspect-ratio: 1/1;
}
@media screen and (min-width: 740px) {
.heroImage {
aspect-ratio: auto;
}
}

View File

@@ -1,5 +1,3 @@
"use client"
import Image from "@/components/Image"
import styles from "./hero.module.css"
@@ -8,47 +6,18 @@ import type { HeroProps } from "@/types/components/current/hero"
export default function Hero({ images }: HeroProps) {
return (
<div className="hero-content-overlay hero-content-widget">
<div className="hero-content-overlay__img-container">
<div className="hero-fixed hero-fixed--deemphasized" style={{ marginTop: "0px" }}>
<div className="hero" style={{ top: "113px" }}>
<div className="hero__img-container">
<div id="full-width-slider" className="royalSlider royalSlider--hero rsDefault rsHor rsFade rsWithBullets" data-js="hero-slider" tabIndex={0} aria-label="Carousel. Change slides with keyboard left and right arrows." style={{ touchAction: "pan-y" }}>
<div className="rsOverflow" style={{ width: "1555px", height: "650px" }}>
<div className="rsContainer">
<div style={{ zIndex: 0 }} className="rsSlide ">
<picture style={{ visibility: "visible", opacity: 1, transition: "opacity 400ms ease-in-out 0s" }}>
{images.map(({ node: image }) => (
<Image
alt={image.title}
className={`rsImg-x slider-plchldr ${styles.heroImage}`}
data-aspectratio="1.50"
height={image.dimension.height}
key={image.title}
src={image.url}
width={image.dimension.width}
/>
))}
</picture>
</div>
</div>
<div className="rsArrow rsArrowLeft" style={{ display: "none" }}>
<div className="rsArrowIcn" tabIndex={0} />
</div>
<div className="rsArrow rsArrowRight" style={{ display: "none" }}>
<div className="rsArrowIcn" tabIndex={0} />
</div>
</div>
<div className="rsNav rsBullets">
<div className="rsNavItem rsBullet rsNavSelected">
<span></span>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div className={styles.wrapper} aria-label="Hero" tabIndex={0}>
{images.map(({ node: image }) => (
<picture className={styles.picture} key={image.title}>
<Image
alt={image.title}
className={styles.heroImage}
height={image.dimension.height}
src={image.url}
width={image.dimension.width}
/>
</picture>
))}
</div>
)
}

View File

@@ -1,6 +1,6 @@
import styles from "./loading.module.css"
export default function LoadingPreview() {
export default function LoadingSpinner() {
return (
<div className={styles.container}>
<div className={styles.spinner}>

View File

@@ -1,7 +1,12 @@
.nav {
display: none;
padding-bottom: 8px;
}
.parent {
display: none;
}
.list {
align-items: center;
display: grid;
@@ -29,4 +34,11 @@
.currentPage::before {
content: "";
margin-right: 4px;
}
@media (min-width: 740px){
.nav {
display: block;
}
}

View File

@@ -9,14 +9,18 @@ export default function Breadcrumbs({ breadcrumbs, parent, title }: BreadcrumbsP
<nav className={styles.nav}>
<ul className={styles.list}>
{parent ? (
<li className="breadcrumb-list__parent hidden-medium hidden-large">
<li className={styles.parent}>
<Link href={parent.node.url}>
{parent.node.breadcrumbs?.title ?? parent.node.title}
</Link>
</li>
) : null}
{breadcrumbs.edges.map(breadcrumb => (
<li className={styles.li} itemProp="breadcrumb" key={breadcrumb.node.title}>
{breadcrumbs.edges.map((breadcrumb) => (
<li
className={styles.li}
itemProp="breadcrumb"
key={breadcrumb.node.title}
>
<Link className={styles.link} href={breadcrumb.node.url}>
{breadcrumb.node.breadcrumbs?.title ?? breadcrumb.node.title}
</Link>

View File

@@ -1,10 +1,10 @@
.container {
display: grid;
gap: 60px;
grid-template-columns: 2fr 1fr;
margin: 0 auto;
max-width: 1200px;
padding: 30px 0px 45px;
padding: 20px 10px 25px;
background: #fff;
}
.preamble {
@@ -13,8 +13,16 @@
font-size: 1.25rem;
font-weight: 300;
line-height: normal;
margin-bottom: 0px;
text-transform: none;
margin-bottom: 0;
}
@media (min-width: 740px){
.container {
background: transparent;
padding: 20px 30px 35px;
grid-template-columns: 2fr 1fr;
}
}
@media screen and (min-width: 950px) {
@@ -22,4 +30,5 @@
font-size: 1.5rem;
line-height: 2.25rem;
}
}
}

View File

@@ -1,20 +1,20 @@
.wrapper {
background-color: #fff;
}
.section {
box-sizing: content-box;
display: grid;
gap: 70px;
grid-template-columns: 2fr 1fr;
margin: 0 auto;
max-width: 1200px;
padding: 20px 10px 5px;
}
@media screen and (min-width: 740px) {
.section {
padding: 30px 30px 15px;
grid-template-columns: 2fr 1fr;
display: grid;
gap: 70px;
max-width: 1200px;
}
.wrapper {
background-color: #fff;
}
}

View File

@@ -6,7 +6,14 @@ fragment Contact on ContactBlock {
street
zip
}
phone
system {
uid
locale
}
phone {
number
title
}
title
visiting_address {
city

View File

@@ -0,0 +1,4 @@
import type { ContactNode } from "@/types/requests/asides/contact"
import type { Node } from "@/types/requests/utils/edges"
export type ContactsProps = { contacts: Node<ContactNode>[] }

View File

@@ -16,6 +16,11 @@ export type UriParams = {
uri?: string;
};
export type PreviewParams = {
uri?: string
live_preview?: string
}
export type LayoutArgs<P = undefined> = P extends undefined ? {} : Params<P>;
export type PageArgs<P = undefined, S = undefined> = LayoutArgs<P> &

View File

@@ -1,23 +1,33 @@
import { Lang } from "@/types/lang"
import type { Edges } from "../utils/edges"
export type ContactNode = {
mailing_address: {
city: string
country: string
name: string
street: string
zip: string
}
system: {
uid: string
locale: Lang
}
phone: {
number: string
title: string
}
title: string
visiting_address: {
city: string
country: string
street: string
zip: string
}
}
export type Contact = {
contact: {
contactConnection: Edges<{
mailing_address: {
city: string
country: string
name: string
street: string
zip: string
}
phone: string
title: string
visiting_address: {
city: string
country: string
street: string
zip: string
}
}>
contactConnection: Edges<ContactNode>
}
}