add featured block
This commit is contained in:
@ -1,6 +1,7 @@
|
|||||||
from grapple.helpers import register_streamfield_block
|
from grapple.helpers import register_streamfield_block
|
||||||
from grapple.models import (
|
from grapple.models import (
|
||||||
GraphQLImage,
|
GraphQLImage,
|
||||||
|
GraphQLPage,
|
||||||
GraphQLStreamfield,
|
GraphQLStreamfield,
|
||||||
GraphQLString,
|
GraphQLString,
|
||||||
)
|
)
|
||||||
@ -90,3 +91,48 @@ class HorizontalRuleBlock(blocks.StructBlock):
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
icon = "minus"
|
icon = "minus"
|
||||||
|
|
||||||
|
|
||||||
|
@register_streamfield_block
|
||||||
|
class FeaturedBlock(blocks.StructBlock):
|
||||||
|
IMAGE_POSITION_CHOICES = (
|
||||||
|
("left", "Venstre"),
|
||||||
|
("right", "Høyre"),
|
||||||
|
)
|
||||||
|
|
||||||
|
title = blocks.CharBlock(max_length=64, required=True, label="Tittel")
|
||||||
|
text = blocks.RichTextBlock(features=["bold", "italic", "link"], required=True, label="Tekst")
|
||||||
|
featured_page = blocks.PageChooserBlock(header="Fremhevet side", required=True)
|
||||||
|
link_text = blocks.CharBlock(
|
||||||
|
max_length=64,
|
||||||
|
label="Lenketekst",
|
||||||
|
default="Les mer",
|
||||||
|
required=True,
|
||||||
|
help_text='Lenketeksten som tar deg videre til siden. Tips: Ikke start med "Trykk her"',
|
||||||
|
)
|
||||||
|
image_position = blocks.ChoiceBlock(
|
||||||
|
required=True,
|
||||||
|
choices=IMAGE_POSITION_CHOICES,
|
||||||
|
label="Bildeplassering",
|
||||||
|
)
|
||||||
|
featured_image_override = ImageChooserBlock(
|
||||||
|
header="Overstyr bilde",
|
||||||
|
help_text=(
|
||||||
|
"Bildet som er tilknyttet undersiden du vil fremheve, vil automatisk brukes. "
|
||||||
|
"Om det mangler eller du vil overstyre hvilket bilde som et brukes, "
|
||||||
|
"kan du velge et her."
|
||||||
|
),
|
||||||
|
required=False,
|
||||||
|
)
|
||||||
|
|
||||||
|
graphql_fields = [
|
||||||
|
GraphQLString("title", required=True),
|
||||||
|
GraphQLString("text", required=True),
|
||||||
|
GraphQLString("link_text", required=True),
|
||||||
|
GraphQLString("image_position", required=True),
|
||||||
|
GraphQLImage("featured_image_override"),
|
||||||
|
GraphQLPage("featured_page", required=True),
|
||||||
|
]
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
icon = "arrow-right-full"
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
from wagtail import blocks
|
from wagtail import blocks
|
||||||
from wagtail.fields import StreamField
|
from wagtail.fields import StreamField
|
||||||
|
|
||||||
from dnscms.blocks import HorizontalRuleBlock, ImageSliderBlock, ImageWithTextBlock
|
from dnscms.blocks import FeaturedBlock, HorizontalRuleBlock, ImageSliderBlock, ImageWithTextBlock
|
||||||
|
|
||||||
CommonStreamField = StreamField(
|
CommonStreamField = StreamField(
|
||||||
[
|
[
|
||||||
@ -9,6 +9,7 @@ CommonStreamField = StreamField(
|
|||||||
("image", ImageWithTextBlock(label="Bilde")),
|
("image", ImageWithTextBlock(label="Bilde")),
|
||||||
("image_slider", ImageSliderBlock(label="Bildegalleri")),
|
("image_slider", ImageSliderBlock(label="Bildegalleri")),
|
||||||
("horizontal_rule", HorizontalRuleBlock(label="Skillelinje")),
|
("horizontal_rule", HorizontalRuleBlock(label="Skillelinje")),
|
||||||
|
("featured", FeaturedBlock(label="Fremhevet underside")),
|
||||||
],
|
],
|
||||||
default=[("paragraph", "")],
|
default=[("paragraph", "")],
|
||||||
)
|
)
|
||||||
|
12
dnscms/poetry.lock
generated
12
dnscms/poetry.lock
generated
@ -721,13 +721,13 @@ files = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "requests"
|
name = "requests"
|
||||||
version = "2.32.0"
|
version = "2.32.2"
|
||||||
description = "Python HTTP for Humans."
|
description = "Python HTTP for Humans."
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.8"
|
python-versions = ">=3.8"
|
||||||
files = [
|
files = [
|
||||||
{file = "requests-2.32.0-py3-none-any.whl", hash = "sha256:f2c3881dddb70d056c5bd7600a4fae312b2a300e39be6a118d30b90bd27262b5"},
|
{file = "requests-2.32.2-py3-none-any.whl", hash = "sha256:fc06670dd0ed212426dfeb94fc1b983d917c4f9847c863f313c9dfaaffb7c23c"},
|
||||||
{file = "requests-2.32.0.tar.gz", hash = "sha256:fa5490319474c82ef1d2c9bc459d3652e3ae4ef4c4ebdd18a21145a47ca4b6b8"},
|
{file = "requests-2.32.2.tar.gz", hash = "sha256:dd951ff5ecf3e3b3aa26b40703ba77495dab41da839ae72ef3c8e5d8e2433289"},
|
||||||
]
|
]
|
||||||
|
|
||||||
[package.dependencies]
|
[package.dependencies]
|
||||||
@ -858,13 +858,13 @@ zstd = ["zstandard (>=0.18.0)"]
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wagtail"
|
name = "wagtail"
|
||||||
version = "6.1"
|
version = "6.1.1"
|
||||||
description = "A Django content management system."
|
description = "A Django content management system."
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.8"
|
python-versions = ">=3.8"
|
||||||
files = [
|
files = [
|
||||||
{file = "wagtail-6.1-py3-none-any.whl", hash = "sha256:6c5ccabc5ac1701e4107241077a880f3fabd34c4ac20bdc412e8961e7b17b4a8"},
|
{file = "wagtail-6.1.1-py3-none-any.whl", hash = "sha256:084f5911ddc742d4e7797cc40ea53ec6f696b06b91cd0857c1e28a944eceddda"},
|
||||||
{file = "wagtail-6.1.tar.gz", hash = "sha256:ad33ed1ccad1f9f1b4faba216c6cc92ba1a2dfefdbfd97c23ffbf7db99dd93c5"},
|
{file = "wagtail-6.1.1.tar.gz", hash = "sha256:d7b6e5e09970dd74efb63953c42a26fe6c25902e2a6dca4ad7e74ae00facb394"},
|
||||||
]
|
]
|
||||||
|
|
||||||
[package.dependencies]
|
[package.dependencies]
|
||||||
|
@ -7,7 +7,6 @@ import { FeaturedEvents } from "@/components/events/FeaturedEvents";
|
|||||||
import { NewsList } from "@/components/news/NewsList";
|
import { NewsList } from "@/components/news/NewsList";
|
||||||
import { UpcomingEvents } from "@/components/events/UpcomingEvents";
|
import { UpcomingEvents } from "@/components/events/UpcomingEvents";
|
||||||
import { IconListBlock } from "@/components/blocks/IconListBlock";
|
import { IconListBlock } from "@/components/blocks/IconListBlock";
|
||||||
import { FeaturedBlock } from "@/components/blocks/FeaturedBlock";
|
|
||||||
|
|
||||||
const HomeFragmentDefinition = graphql(`
|
const HomeFragmentDefinition = graphql(`
|
||||||
fragment Home on HomePage {
|
fragment Home on HomePage {
|
||||||
|
@ -2,6 +2,7 @@ import { RichTextBlock } from "./RichTextBlock";
|
|||||||
import { ImageWithTextBlock } from "./ImageWithTextBlock";
|
import { ImageWithTextBlock } from "./ImageWithTextBlock";
|
||||||
import { ImageSliderBlock } from "./ImageSliderBlock";
|
import { ImageSliderBlock } from "./ImageSliderBlock";
|
||||||
import { HorizontalRuleBlock } from "./HorizontalRuleBlock";
|
import { HorizontalRuleBlock } from "./HorizontalRuleBlock";
|
||||||
|
import { FeaturedBlock } from "./FeaturedBlock";
|
||||||
|
|
||||||
export const Blocks = ({ blocks }: any) => {
|
export const Blocks = ({ blocks }: any) => {
|
||||||
return blocks.map((block: any) => {
|
return blocks.map((block: any) => {
|
||||||
@ -18,37 +19,12 @@ export const Blocks = ({ blocks }: any) => {
|
|||||||
case "HorizontalRuleBlock":
|
case "HorizontalRuleBlock":
|
||||||
return <HorizontalRuleBlock block={block} />;
|
return <HorizontalRuleBlock block={block} />;
|
||||||
break;
|
break;
|
||||||
|
case "FeaturedBlock":
|
||||||
|
return <FeaturedBlock block={block} />;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
return <div>Unsupported block type {block.blockType}</div>;
|
return <div>Unsupported block type {block.blockType}</div>;
|
||||||
console.log("unsupported block", block);
|
console.log("unsupported block", block);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
|
||||||
StreamFieldBlock
|
|
||||||
CharBlock
|
|
||||||
TextBlock
|
|
||||||
EmailBlock
|
|
||||||
IntegerBlock
|
|
||||||
FloatBlock
|
|
||||||
DecimalBlock
|
|
||||||
RegexBlock
|
|
||||||
URLBlock
|
|
||||||
BooleanBlock
|
|
||||||
DateBlock
|
|
||||||
TimeBlock
|
|
||||||
DateTimeBlock
|
|
||||||
RichTextBlock
|
|
||||||
RawHTMLBlock
|
|
||||||
BlockQuoteBlock
|
|
||||||
ChoiceBlock
|
|
||||||
StreamBlock
|
|
||||||
StructBlock
|
|
||||||
StaticBlock
|
|
||||||
ListBlock
|
|
||||||
EmbedBlock
|
|
||||||
PageChooserBlock
|
|
||||||
DocumentChooserBlock
|
|
||||||
ImageChooserBlock
|
|
||||||
*/
|
|
||||||
|
@ -1,18 +1,36 @@
|
|||||||
|
import { FeaturedBlock as FeaturedBlockType } from "@/gql/graphql";
|
||||||
|
import Link from "next/link";
|
||||||
|
import Image from "../general/Image";
|
||||||
import styles from "./featuredBlock.module.scss";
|
import styles from "./featuredBlock.module.scss";
|
||||||
|
|
||||||
export const FeaturedBlock = ({ block }: any) => {
|
export const FeaturedBlock = ({ block }: { block: FeaturedBlockType }) => {
|
||||||
|
const image = !!block.featuredImageOverride
|
||||||
|
? block.featuredImageOverride
|
||||||
|
: null;
|
||||||
|
// TODO: fetch image from target page
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.featuredBlock}>
|
<div className={styles.featuredBlock}>
|
||||||
<div className={styles.text}>
|
<div className={styles.text}>
|
||||||
<h2>En fremhevet artikkel eller side</h2>
|
<h2>{block.title}</h2>
|
||||||
<p>
|
<div dangerouslySetInnerHTML={{ __html: block.featuredBlockText }} />
|
||||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut molestie
|
<Link href={block.featuredPage.url ?? "#"}>
|
||||||
tortor a interdum blandit. Sed ac purus sit amet libero posuere
|
{block.linkText} →
|
||||||
molestie.
|
</Link>
|
||||||
</p>
|
|
||||||
<a href="#">Mer om denne saken →</a>
|
|
||||||
</div>
|
</div>
|
||||||
<div className={styles.image}></div>
|
{image && (
|
||||||
|
<div className={styles.image}>
|
||||||
|
{" "}
|
||||||
|
<Image
|
||||||
|
src={image.url}
|
||||||
|
alt={image.alt ?? ""}
|
||||||
|
width={image.width}
|
||||||
|
height={image.height}
|
||||||
|
sizes="20vw"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{!image && <div className={styles.placeholderImage} />}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -54,6 +54,20 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.image {
|
.image {
|
||||||
|
width: 100%;
|
||||||
|
padding-top: 60%;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
img {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
object-fit: cover;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.placeholderImage {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
padding-top: 60%;
|
padding-top: 60%;
|
||||||
background: var(--color-placeholder);
|
background: var(--color-placeholder);
|
||||||
|
@ -31,7 +31,7 @@ const documents = {
|
|||||||
"\n query allVenues {\n venues: pages(contentType: \"venues.VenuePage\") {\n ... on VenuePage {\n ...Venue\n }\n }\n }\n ": types.AllVenuesDocument,
|
"\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 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 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 }\n": types.BlocksFragmentDoc,
|
"\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 Image on CustomImage {\n id\n url\n width\n height\n alt\n attribution\n }\n": types.ImageFragmentDoc,
|
"\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 facebookUrl\n ticketUrl\n priceRegular\n priceMember\n priceStudent\n categories {\n ... on EventCategory {\n name\n slug\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 }\n }\n }\n }\n": types.EventFragmentDoc,
|
"\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 facebookUrl\n ticketUrl\n priceRegular\n priceMember\n priceStudent\n categories {\n ... on EventCategory {\n name\n slug\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 }\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 }\n": types.FutureEventsDocument,
|
"\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 }\n": types.FutureEventsDocument,
|
||||||
@ -129,7 +129,7 @@ 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.
|
* 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 }\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 }\n"];
|
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"];
|
||||||
/**
|
/**
|
||||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
* 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
@ -29,6 +29,30 @@ const BlockFragmentDefinition = graphql(`
|
|||||||
... on HorizontalRuleBlock {
|
... on HorizontalRuleBlock {
|
||||||
color
|
color
|
||||||
}
|
}
|
||||||
|
... on FeaturedBlock {
|
||||||
|
title
|
||||||
|
featuredBlockText: text
|
||||||
|
linkText
|
||||||
|
imagePosition
|
||||||
|
featuredPage {
|
||||||
|
contentType
|
||||||
|
pageType
|
||||||
|
url
|
||||||
|
... on EventPage {
|
||||||
|
featuredImage {
|
||||||
|
...Image
|
||||||
|
}
|
||||||
|
}
|
||||||
|
... on NewsPage {
|
||||||
|
featuredImage {
|
||||||
|
...Image
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
featuredImageOverride {
|
||||||
|
...Image
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
`);
|
`);
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user