add support for page sections on generic pages

This commit is contained in:
2024-06-21 23:13:15 +02:00
parent 82f451cb14
commit 41f5297a12
16 changed files with 683 additions and 93 deletions

View File

@ -3,6 +3,7 @@ import { GenericFragment } from "@/gql/graphql";
import { getClient } from "@/app/client";
import { Blocks } from "@/components/blocks/Blocks";
import { notFound } from "next/navigation";
import { PageHeader } from "@/components/general/PageHeader";
export const dynamicParams = false;
@ -12,6 +13,7 @@ const GenericFragmentDefinition = graphql(`
id
urlPath
title
lead
body {
...Blocks
}
@ -70,12 +72,13 @@ export default async function Page({ params }: { params: { url: string[] } }) {
if (!page) {
return notFound();
}
return (
<main className="site-main" id="main">
<section className="page-header">
<h1>{page.title}</h1>
</section>
<PageHeader
heading={page.title}
lead={page.lead}
/>
<Blocks blocks={page.body} />
</main>
);

View File

@ -4,7 +4,7 @@ import { getClient } from "@/app/client";
import Link from "next/link";
import { PageHeader } from "@/components/general/PageHeader";
import { IconListBlock } from "@/components/blocks/IconListBlock";
import { PageSection } from "@/components/blocks/PageSection";
import { PageSectionBlock } from "@/components/blocks/PageSection";
export default async function Page() {
return (
@ -61,12 +61,11 @@ export default async function Page() {
</li>
</ul>
</div>
<PageSection
heading="Adkomst"
subheading="Hvordan kommer man seg til Neuf?"
<PageSectionBlock
block={{ title: "Adkomst" } as any}
// subheading="Hvordan kommer man seg til Neuf?"
/>
<PageSection heading="Åpningstider" />
<PageSection />
<PageSectionBlock block={{ title: "Åpningstider" } as any} />
<section className="pageSection" id="adkomst">
<h1>Adkomst</h1>
<div className="pageSectionGroup">

View File

@ -3,9 +3,15 @@ import { ImageWithTextBlock } from "./ImageWithTextBlock";
import { ImageSliderBlock } from "./ImageSliderBlock";
import { HorizontalRuleBlock } from "./HorizontalRuleBlock";
import { FeaturedBlock } from "./FeaturedBlock";
import { PageSectionBlock, PageSectionNavigationBlock } from "./PageSection";
export const Blocks = ({ blocks }: any) => {
const sections = blocks.filter(
(block: any) => block.__typename === "PageSectionBlock"
);
return blocks.map((block: any) => {
console.log("block aaa", block);
switch (block.blockType) {
case "RichTextBlock":
return <RichTextBlock block={block} />;
@ -22,9 +28,15 @@ export const Blocks = ({ blocks }: any) => {
case "FeaturedBlock":
return <FeaturedBlock block={block} />;
break;
case "PageSectionBlock":
return <PageSectionBlock block={block} />;
break;
case "PageSectionNavigationBlock":
return <PageSectionNavigationBlock sections={sections} />;
break;
default:
return <div>Unsupported block type {block.blockType}</div>;
console.log("unsupported block", block);
}
});
};
};

View File

@ -1,14 +1,55 @@
import { PageSectionBlock as PageSectionBlockType } from "@/gql/graphql";
import styles from "./pageSection.module.scss";
import { Blocks } from "./Blocks";
import slugify from "@sindresorhus/slugify";
export const PageSectionBlock = ({
block,
}: {
block: PageSectionBlockType;
}) => {
// TODO: add icon selection to model
// TODO: there's a block.backgroundColor
const anchor = slugify(block.title);
export const PageSection = ({ heading }: any) => {
return (
<section className={styles.pageSection}>
<section className={styles.pageSection} id={anchor}>
<div className={styles.sectionHeader}>
<div className={styles.icon}>
<img src="/assets/icons/neufneuf.svg" />
</div>
<h1>{heading}</h1>
<h1>{block.title}</h1>
</div>
<Blocks blocks={block.body} />
</section>
);
};
export const PageSectionNavigationBlock = ({
sections,
}: {
sections: PageSectionBlockType[];
}) => {
if (!sections.length) {
return <></>;
}
return (
<div className="anchorLinks">
<span className="suphead">Hopp til</span>
<ul>
{sections.map((section) => {
const anchor = slugify(section.title);
return (
<li key={anchor}>
<a href={`#${anchor}`} className="button">
{section.title}
</a>
</li>
);
})}
</ul>
</div>
);
};

View File

@ -10,7 +10,9 @@ export const PageHeader = ({
return (
<div className={styles.pageHeader}>
<h1 className={styles.title}>{heading}</h1>
{lead && <p className="lead">{lead}</p>}
{lead && (
<p className="lead" dangerouslySetInnerHTML={{ __html: lead }} />
)}
</div>
);
};

View File

@ -13,7 +13,7 @@ import { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/
* Therefore it is highly recommended to use the babel or swc plugin for production.
*/
const documents = {
"\n fragment Generic on GenericPage {\n __typename\n id\n urlPath\n title\n body {\n ...Blocks\n }\n }\n": types.GenericFragmentDoc,
"\n fragment Generic on GenericPage {\n __typename\n id\n urlPath\n title\n lead\n body {\n ...Blocks\n }\n }\n": types.GenericFragmentDoc,
"\n query allGenericSlugs {\n pages(contentType: \"generic.GenericPage\") {\n id\n urlPath\n }\n }\n ": types.AllGenericSlugsDocument,
"\n query genericPageByUrl($urlPath: String!) {\n page: page(contentType: \"generic.GenericPage\", urlPath: $urlPath) {\n ... on GenericPage {\n ...Generic\n }\n }\n }\n ": types.GenericPageByUrlDocument,
"\n query allNewsSlugs {\n pages(contentType: \"news.NewsPage\") {\n id\n slug\n }\n }\n ": types.AllNewsSlugsDocument,
@ -31,7 +31,13 @@ const documents = {
"\n query allVenues {\n venues: pages(contentType: \"venues.VenuePage\") {\n ... on VenuePage {\n ...Venue\n }\n }\n }\n ": types.AllVenuesDocument,
"\n fragment Home on HomePage {\n ... on HomePage {\n featuredEvents {\n id\n }\n }\n }\n": types.HomeFragmentDoc,
"\n query home {\n events: eventIndex {\n ... on EventIndex {\n futureEvents {\n ... on EventPage {\n ...Event\n }\n }\n }\n }\n home: page(contentType: \"home.HomePage\", urlPath: \"/home/\") {\n ... on HomePage {\n ...Home\n }\n }\n news: pages(contentType: \"news.newsPage\", limit: 3) {\n ... on NewsPage {\n ...News\n }\n }\n }\n ": types.HomeDocument,
"\n fragment Blocks on StreamFieldInterface {\n id\n blockType\n field\n ... on RichTextBlock {\n rawValue\n value\n }\n ... on ImageWithTextBlock {\n image {\n ...Image\n }\n imageFormat\n text\n }\n ... on ImageSliderBlock {\n images {\n ... on ImageSliderItemBlock {\n image {\n ...Image\n }\n text\n }\n }\n }\n ... on HorizontalRuleBlock {\n color\n }\n ... on FeaturedBlock {\n title\n featuredBlockText: text\n linkText\n imagePosition\n featuredPage {\n contentType\n pageType\n url\n ... on EventPage {\n featuredImage {\n ...Image\n }\n }\n ... on NewsPage {\n featuredImage {\n ...Image\n }\n }\n }\n featuredImageOverride {\n ...Image\n }\n }\n }\n": types.BlocksFragmentDoc,
"\n fragment RichTextBlock on RichTextBlock {\n rawValue\n value\n }\n": types.RichTextBlockFragmentDoc,
"\n fragment ImageWithTextBlock on ImageWithTextBlock {\n image {\n ...Image\n }\n imageFormat\n text\n }\n": types.ImageWithTextBlockFragmentDoc,
"\n fragment ImageSliderBlock on ImageSliderBlock {\n images {\n ... on ImageSliderItemBlock {\n image {\n ...Image\n }\n text\n }\n }\n }\n": types.ImageSliderBlockFragmentDoc,
"\n fragment HorizontalRuleBlock on HorizontalRuleBlock {\n color\n }\n": types.HorizontalRuleBlockFragmentDoc,
"\n fragment FeaturedBlock on FeaturedBlock {\n title\n featuredBlockText: text\n linkText\n imagePosition\n featuredPage {\n contentType\n pageType\n url\n ... on EventPage {\n featuredImage {\n ...Image\n }\n }\n ... on NewsPage {\n featuredImage {\n ...Image\n }\n }\n }\n featuredImageOverride {\n ...Image\n }\n }\n": types.FeaturedBlockFragmentDoc,
"\n fragment OneLevelOfBlocks on StreamFieldInterface {\n id\n blockType\n field\n ... on RichTextBlock {\n ...RichTextBlock\n }\n ... on ImageWithTextBlock {\n ...ImageWithTextBlock\n }\n ... on ImageSliderBlock {\n ...ImageSliderBlock\n }\n ... on HorizontalRuleBlock {\n ...HorizontalRuleBlock\n }\n ... on FeaturedBlock {\n ...FeaturedBlock\n }\n }\n": types.OneLevelOfBlocksFragmentDoc,
"\n fragment Blocks on StreamFieldInterface {\n ... on PageSectionBlock {\n title\n backgroundColor\n body {\n ...OneLevelOfBlocks\n }\n }\n ...OneLevelOfBlocks\n\n }\n": types.BlocksFragmentDoc,
"\n fragment Image on CustomImage {\n id\n url\n width\n height\n alt\n attribution\n }\n": types.ImageFragmentDoc,
"\n fragment Event on EventPage {\n __typename\n id\n slug\n title\n body {\n id\n blockType\n field\n ... on RichTextBlock {\n rawValue\n value\n }\n }\n featuredImage {\n ...Image\n }\n pig\n facebookUrl\n ticketUrl\n free\n priceRegular\n priceMember\n priceStudent\n categories {\n ... on EventCategory {\n name\n slug\n pig\n }\n }\n occurrences {\n ... on EventOccurrence {\n __typename\n id\n start\n end\n venue {\n __typename\n id\n slug\n title\n preposition\n url\n }\n }\n }\n organizers {\n ... on EventOrganizer {\n id\n name\n slug\n externalUrl\n association {\n ... on AssociationPage {\n url\n }\n }\n }\n }\n }\n": types.EventFragmentDoc,
"\n query futureEvents {\n events: eventIndex {\n ... on EventIndex {\n futureEvents {\n ... on EventPage {\n ...Event\n }\n }\n }\n }\n eventCategories: eventCategories {\n ... on EventCategory {\n name\n slug\n showInFilters\n }\n }\n eventOrganizers: eventOrganizers {\n ... on EventOrganizer {\n id\n name\n slug\n externalUrl\n association {\n ... on AssociationPage {\n url\n }\n }\n }\n }\n }\n": types.FutureEventsDocument,
@ -57,7 +63,7 @@ export function graphql(source: string): unknown;
/**
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
*/
export function graphql(source: "\n fragment Generic on GenericPage {\n __typename\n id\n urlPath\n title\n body {\n ...Blocks\n }\n }\n"): (typeof documents)["\n fragment Generic on GenericPage {\n __typename\n id\n urlPath\n title\n body {\n ...Blocks\n }\n }\n"];
export function graphql(source: "\n fragment Generic on GenericPage {\n __typename\n id\n urlPath\n title\n lead\n body {\n ...Blocks\n }\n }\n"): (typeof documents)["\n fragment Generic on GenericPage {\n __typename\n id\n urlPath\n title\n lead\n body {\n ...Blocks\n }\n }\n"];
/**
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
*/
@ -129,7 +135,31 @@ export function graphql(source: "\n query home {\n events: eventIndex {\
/**
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
*/
export function graphql(source: "\n fragment Blocks on StreamFieldInterface {\n id\n blockType\n field\n ... on RichTextBlock {\n rawValue\n value\n }\n ... on ImageWithTextBlock {\n image {\n ...Image\n }\n imageFormat\n text\n }\n ... on ImageSliderBlock {\n images {\n ... on ImageSliderItemBlock {\n image {\n ...Image\n }\n text\n }\n }\n }\n ... on HorizontalRuleBlock {\n color\n }\n ... on FeaturedBlock {\n title\n featuredBlockText: text\n linkText\n imagePosition\n featuredPage {\n contentType\n pageType\n url\n ... on EventPage {\n featuredImage {\n ...Image\n }\n }\n ... on NewsPage {\n featuredImage {\n ...Image\n }\n }\n }\n featuredImageOverride {\n ...Image\n }\n }\n }\n"): (typeof documents)["\n fragment Blocks on StreamFieldInterface {\n id\n blockType\n field\n ... on RichTextBlock {\n rawValue\n value\n }\n ... on ImageWithTextBlock {\n image {\n ...Image\n }\n imageFormat\n text\n }\n ... on ImageSliderBlock {\n images {\n ... on ImageSliderItemBlock {\n image {\n ...Image\n }\n text\n }\n }\n }\n ... on HorizontalRuleBlock {\n color\n }\n ... on FeaturedBlock {\n title\n featuredBlockText: text\n linkText\n imagePosition\n featuredPage {\n contentType\n pageType\n url\n ... on EventPage {\n featuredImage {\n ...Image\n }\n }\n ... on NewsPage {\n featuredImage {\n ...Image\n }\n }\n }\n featuredImageOverride {\n ...Image\n }\n }\n }\n"];
export function graphql(source: "\n fragment RichTextBlock on RichTextBlock {\n rawValue\n value\n }\n"): (typeof documents)["\n fragment RichTextBlock on RichTextBlock {\n rawValue\n value\n }\n"];
/**
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
*/
export function graphql(source: "\n fragment ImageWithTextBlock on ImageWithTextBlock {\n image {\n ...Image\n }\n imageFormat\n text\n }\n"): (typeof documents)["\n fragment ImageWithTextBlock on ImageWithTextBlock {\n image {\n ...Image\n }\n imageFormat\n text\n }\n"];
/**
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
*/
export function graphql(source: "\n fragment ImageSliderBlock on ImageSliderBlock {\n images {\n ... on ImageSliderItemBlock {\n image {\n ...Image\n }\n text\n }\n }\n }\n"): (typeof documents)["\n fragment ImageSliderBlock on ImageSliderBlock {\n images {\n ... on ImageSliderItemBlock {\n image {\n ...Image\n }\n text\n }\n }\n }\n"];
/**
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
*/
export function graphql(source: "\n fragment HorizontalRuleBlock on HorizontalRuleBlock {\n color\n }\n"): (typeof documents)["\n fragment HorizontalRuleBlock on HorizontalRuleBlock {\n color\n }\n"];
/**
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
*/
export function graphql(source: "\n fragment FeaturedBlock on FeaturedBlock {\n title\n featuredBlockText: text\n linkText\n imagePosition\n featuredPage {\n contentType\n pageType\n url\n ... on EventPage {\n featuredImage {\n ...Image\n }\n }\n ... on NewsPage {\n featuredImage {\n ...Image\n }\n }\n }\n featuredImageOverride {\n ...Image\n }\n }\n"): (typeof documents)["\n fragment FeaturedBlock on FeaturedBlock {\n title\n featuredBlockText: text\n linkText\n imagePosition\n featuredPage {\n contentType\n pageType\n url\n ... on EventPage {\n featuredImage {\n ...Image\n }\n }\n ... on NewsPage {\n featuredImage {\n ...Image\n }\n }\n }\n featuredImageOverride {\n ...Image\n }\n }\n"];
/**
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
*/
export function graphql(source: "\n fragment OneLevelOfBlocks on StreamFieldInterface {\n id\n blockType\n field\n ... on RichTextBlock {\n ...RichTextBlock\n }\n ... on ImageWithTextBlock {\n ...ImageWithTextBlock\n }\n ... on ImageSliderBlock {\n ...ImageSliderBlock\n }\n ... on HorizontalRuleBlock {\n ...HorizontalRuleBlock\n }\n ... on FeaturedBlock {\n ...FeaturedBlock\n }\n }\n"): (typeof documents)["\n fragment OneLevelOfBlocks on StreamFieldInterface {\n id\n blockType\n field\n ... on RichTextBlock {\n ...RichTextBlock\n }\n ... on ImageWithTextBlock {\n ...ImageWithTextBlock\n }\n ... on ImageSliderBlock {\n ...ImageSliderBlock\n }\n ... on HorizontalRuleBlock {\n ...HorizontalRuleBlock\n }\n ... on FeaturedBlock {\n ...FeaturedBlock\n }\n }\n"];
/**
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
*/
export function graphql(source: "\n fragment Blocks on StreamFieldInterface {\n ... on PageSectionBlock {\n title\n backgroundColor\n body {\n ...OneLevelOfBlocks\n }\n }\n ...OneLevelOfBlocks\n\n }\n"): (typeof documents)["\n fragment Blocks on StreamFieldInterface {\n ... on PageSectionBlock {\n title\n backgroundColor\n body {\n ...OneLevelOfBlocks\n }\n }\n ...OneLevelOfBlocks\n\n }\n"];
/**
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
*/

File diff suppressed because one or more lines are too long

View File

@ -37,8 +37,8 @@ export function unique<T>(array: any[]): any[] {
return Array.from(array.reduce((set, item) => set.add(item), new Set()));
}
const BlockFragmentDefinition = graphql(`
fragment Blocks on StreamFieldInterface {
const OneLevelOfBlocksFragmentDefinition = graphql(`
fragment OneLevelOfBlocks on StreamFieldInterface {
id
blockType
field
@ -93,6 +93,19 @@ const BlockFragmentDefinition = graphql(`
}
`);
const BlockFragmentDefinition = graphql(`
fragment Blocks on StreamFieldInterface {
... on PageSectionBlock {
title
backgroundColor
body {
...OneLevelOfBlocks
}
}
...OneLevelOfBlocks
}
`);
const ImageFragmentDefinition = graphql(`
fragment Image on CustomImage {
id