add contact pages and blocks

This commit is contained in:
2024-06-24 05:11:55 +02:00
parent 944506cc2f
commit 15e4e70806
30 changed files with 1448 additions and 51 deletions

View File

@ -4,6 +4,9 @@ import { ImageSliderBlock } from "./ImageSliderBlock";
import { HorizontalRuleBlock } from "./HorizontalRuleBlock";
import { FeaturedBlock } from "./FeaturedBlock";
import { PageSectionBlock, PageSectionNavigationBlock } from "./PageSection";
import { ContactSectionBlock, ContactSubsectionBlock } from "./ContactSection";
import { ContactListBlock } from "./ContactListBlock";
import { ContactEntityBlock } from "./ContactEntityBlock";
export const Blocks = ({ blocks }: any) => {
const sections = blocks.filter(
@ -33,6 +36,18 @@ export const Blocks = ({ blocks }: any) => {
case "PageSectionNavigationBlock":
return <PageSectionNavigationBlock sections={sections} />;
break;
case "ContactSectionBlock":
return <ContactSectionBlock block={block} />;
break;
case "ContactSubsectionBlock":
return <ContactSubsectionBlock block={block} />;
break;
case "ContactListBlock":
return <ContactListBlock block={block} />;
break;
case "ContactEntityBlock":
return <ContactEntityBlock block={block} />;
break;
default:
return <div>Unsupported block type {block.blockType}</div>;
console.log("unsupported block", block);

View File

@ -0,0 +1,50 @@
import { ContactEntityBlock as ContactEntityBlockType } from "@/gql/graphql";
import styles from "./contactEntityBlock.module.scss";
import { formatNorwegianPhoneNumber, formatPhoneE164 } from "@/lib/common";
export const ContactEntityBlock = ({
block,
}: {
block: ContactEntityBlockType;
}) => {
// TODO: image
const contact = block?.contactEntity;
if (!contact) {
return <></>;
}
const phoneE164 = contact.phoneNumber && formatPhoneE164(contact.phoneNumber);
const phoneFormatted = phoneE164 && formatNorwegianPhoneNumber(phoneE164);
return (
<li className={styles.contactItem}>
<div className={styles.image}></div>
<div className={styles.text}>
<h1 className={styles.name}>{contact.name}</h1>
{contact.title && <p className={styles.role}>{contact.title}</p>}
{(contact.email || phoneE164) && (
<ul className={styles.contact}>
{contact.email && (
<li>
<span className={styles.icon}>&#9993;&nbsp;</span>
<a href={`mailto:${contact.email}`} target="_blank">
{contact.email}
</a>
</li>
)}
{phoneE164 && (
<li>
<span className={styles.icon}>&#9742;&nbsp;</span>
<a href={`tel:${phoneE164}`} target="_blank">
{phoneFormatted}
</a>
</li>
)}
</ul>
)}
</div>
</li>
);
};

View File

@ -0,0 +1,15 @@
import { ContactListBlock as ContactListBlockType } from "@/gql/graphql";
import styles from "./contactListBlock.module.scss";
import { Blocks } from "./Blocks";
export const ContactListBlock = ({
block,
}: {
block: ContactListBlockType;
}) => {
return (
<ul className={styles.contactList}>
<Blocks blocks={block.items} />
</ul>
);
};

View File

@ -0,0 +1,41 @@
import { ContactSectionBlock as ContactSectionBlockType } from "@/gql/graphql";
import styles from "./contactSection.module.scss";
import { Blocks } from "./Blocks";
export const ContactSectionBlock = ({
block,
}: {
block: ContactSectionBlockType;
}) => {
return (
<section className={styles.contactSection}>
<h2 className={styles.heading}>{block.title}</h2>
{block.text && (
<p
className={styles.intro}
dangerouslySetInnerHTML={{ __html: block.text }}
/>
)}
<Blocks blocks={block.blocks} />
</section>
);
};
export const ContactSubsectionBlock = ({
block,
}: {
block: ContactSectionBlockType;
}) => {
return (
<section className={styles.contactSubsection}>
<h3 className={styles.heading}>{block.title}</h3>
{block.text && (
<p
className={styles.intro}
dangerouslySetInnerHTML={{ __html: block.text }}
/>
)}
<Blocks blocks={block.blocks} />
</section>
);
};

View File

@ -0,0 +1,43 @@
.contactItem {
position: relative;
list-style: none;
display: flex;
align-items: center;
gap: var(--spacing-s);
}
.image {
flex: none;
width: 7rem;
height: 7rem;
background: var(--color-placeholder);
border-radius: 100%;
}
.text {
padding: 0;
}
.name,
.role {
font-size: var(--spacing-s);
}
.role {
font-family: var(--font-serif);
}
.contact {
list-style: none;
margin: .6rem 0;
font-size: var(--font-size-caption);
font-weight: 500;
line-height: 1.7;
}
.icon {
display: inline-block;
width: var(--size-icon);
text-align: center;
margin-right: .4rem;
}

View File

@ -0,0 +1,19 @@
.contactList {
display: grid;
grid-template-columns: 1fr;
column-gap: var(--spacing-gap-column);
row-gap: var(--spacing-gap-row);
padding-bottom: var(--spacing-section-bottom);
}
@media (min-width: 740px) {
.contactList {
grid-template-columns: repeat(2, 1fr);
}
}
@media (min-width: 1340px) {
.contactList {
grid-template-columns: repeat(3, 1fr);
}
}

View File

@ -0,0 +1,26 @@
.contactSection {
background: var(--color-background-secondary);
margin: calc(var(--spacing-sitepadding-block) * 2)
calc(var(--spacing-sitepadding-inline) * -1);
padding: var(--spacing-sitepadding-block) var(--spacing-sitepadding-inline);
+ .contactSection {
margin-top: calc(var(--spacing-sitepadding-block) * -2);
}
&:nth-of-type(even) {
background: var(--color-background);
}
&:last-child {
margin-bottom: 0;
}
}
.heading {
margin: 0 0 1.6rem;
}
.intro {
margin-bottom: 3rem;
}