Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { BlockEventbrite } from '~content-blocks/BlockEventbrite';
import { BlockHeading } from '~content-blocks/BlockHeading';
import { BlockHetArchiefHeaderSearch } from '~content-blocks/BlockHetArchiefHeaderSearch/BlockHetArchiefHeaderSearch';
import { BlockHetArchiefImageTextBackground } from '~content-blocks/BlockHetArchiefImageTextBackground';
import { BlockHighlightText } from '~content-blocks/BlockHighlightText';
import { BlockHomepageBanner } from '~content-blocks/BlockHomepageBanner';
import { BlockIFrame } from '~content-blocks/BlockIFrame';
import { BlockImage } from '~content-blocks/BlockImage';
Expand Down Expand Up @@ -89,6 +90,7 @@ export function GET_BLOCK_COMPONENT(
[ContentBlockType.HetArchiefImageTextBackground]: BlockHetArchiefImageTextBackground,
[ContentBlockType.OverviewWithCarousel]: BlockOverviewWithCarousel,
[ContentBlockType.HomepageBanner]: BlockHomepageBanner,
[ContentBlockType.HighlightText]: BlockHighlightText,

// Avo specific blocks
[ContentBlockType.MediaGrid]: loadComponentFromConfig(ContentBlockType.MediaGrid),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { BLOCK_FIELD_DEFAULTS, BLOCK_STATE_DEFAULTS, TEXT_FIELD } from '~content-blocks/defaults';
import { GET_BACKGROUND_COLOR_OPTIONS_ARCHIEF } from '~modules/content-page/const/get-color-options.ts';
import {
Color,
type ContentBlockConfig,
ContentBlockEditor,
ContentBlockType,
type DefaultContentBlockState,
} from '~modules/content-page/types/content-block.types';
import { RICH_TEXT_EDITOR_OPTIONS_FULL } from '~shared/consts/rich-text-editor.consts.ts';
import { tText } from '~shared/helpers/translation-functions';
import { validateRequiredValue } from '~shared/helpers/validation.ts';
import { HET_ARCHIEF } from '~shared/types';

const INITIAL_CONTENT_HIGHLIGHT_TEXT_COMPONENTS_STATE = () => ({
content: '',
backgroundColor: Color.Transparent,
highlightColor: Color.OceanGreen,
});

export const INITIAL_CONTENT_HIGHLIGHT_TEXT_BLOCK_STATE = (): DefaultContentBlockState => ({
...BLOCK_STATE_DEFAULTS(),
fullWidth: true,
});

export const CONTENT_HIGHLIGHT_TEXT_CONFIG = (position = 0): ContentBlockConfig => ({
position,
name: tText('Highlight text'),
type: ContentBlockType.HighlightText,
components: {
state: INITIAL_CONTENT_HIGHLIGHT_TEXT_COMPONENTS_STATE(),
fields: {
content: TEXT_FIELD({
editorType: ContentBlockEditor.RICH_TEXT_EDITOR,
editorProps: {
controls: RICH_TEXT_EDITOR_OPTIONS_FULL,
},
validator: (value: string) =>
validateRequiredValue(value, tText('Tekst is verplicht', undefined, [HET_ARCHIEF])),
}),
highlightColor: {
label: tText('Highlightkleur', undefined, [HET_ARCHIEF]),
editorType: ContentBlockEditor.ColorSelect,
editorProps: {
options: GET_BACKGROUND_COLOR_OPTIONS_ARCHIEF(),
defaultValue: GET_BACKGROUND_COLOR_OPTIONS_ARCHIEF()[2],
},
},
},
},
block: {
state: INITIAL_CONTENT_HIGHLIGHT_TEXT_BLOCK_STATE(),
fields: {
...BLOCK_FIELD_DEFAULTS(),
},
},
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import React, { type CSSProperties, type FunctionComponent, type ReactElement } from 'react';
import type { DefaultComponentProps } from '~modules/shared/types/components';
import './BlockHighligtText.scss';
import { Container } from '@viaa/avo2-components';
import clsx from 'clsx';
import { ContentPageWidth } from '~modules/content-page/types/content-pages.types.ts';
import Html from '~shared/components/Html/Html.tsx';

export interface BlockHighlightTextProps extends DefaultComponentProps {
content: string;
highlightColor: string;
backgroundColor: string;
pageWidth?: string;
}

export const BlockHighlightText: FunctionComponent<BlockHighlightTextProps> = ({
content,
highlightColor,
backgroundColor,
pageWidth,
}): ReactElement => {
return (
<article
className={clsx('c-block-highlight-text', 'o-container')}
style={
{
background: backgroundColor,
'--pattern-color': highlightColor,
} as CSSProperties
}
>
<Container
mode="horizontal"
size={
pageWidth?.toUpperCase() === ContentPageWidth.EXTRA_LARGE
? undefined
: (pageWidth?.toLowerCase() as 'medium' | 'large')
}
className={clsx('c-block-highlight-text__content')}
>
<div className="c-block-highlight-text__pattern-slot c-block-highlight-text__pattern-slot--top">
<div
className="c-block-highlight-text__pattern c-block-highlight-text__pattern--left"
aria-hidden="true"
/>
</div>
<Html className="c-block-highlight-text__content-text" content={content} type="p"></Html>
<div className="c-block-highlight-text__pattern-slot c-block-highlight-text__pattern-slot--bottom">
<div
className="c-block-highlight-text__pattern c-block-highlight-text__pattern--right"
aria-hidden="true"
/>
</div>
</Container>
</article>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
@use "../../../../shared/styles/settings/variables" as variables;
@use "../../../../shared/styles/mixins/pattern" as pattern;
@use "../../../../shared/styles/mixins/typography" as typography;

$pattern-height: 12rem;
$pattern-height-mobile: 8rem;
$pattern-repeat-count: 20;
// How far the mobile pattern slots overshoot &__content's edge - see &__pattern-slot.
$pattern-mobile-overshoot: 15rem;

.c-block-highlight-text {
// clip-path (not overflow-x: hidden) avoids the overflow-x/y coupling rule that would
// otherwise turn overflow-y into "auto" and risk a vertical scrollbar.
clip-path: inset(0);
width: 100% !important;
max-width: none !important;

@media (max-width: variables.$g-bp4) {
padding: 0 calc(#{variables.$g-spacer-unit} * 2.5) !important;
}

// Reservation box only - carries no background of its own, so the space it reserves for
// the patterns (mobile only, see &-text and &__pattern-slot) reads as "outside" &-text,
// which is what the patterns need to touch.
&__content {
position: relative;
width: 100%;
display: flex;
flex-direction: column;
padding: 0;

@media (max-width: variables.$g-bp4) {
// Sized to match &__pattern-slot's height exactly so the patterns touch &-text with
// no gap - without this, .c-block-highlight-text's clip-path would cut the slots away.
padding: $pattern-height-mobile 0;
}

// The actual highlighted box - its own padding gives the text breathing room from the
// box's edges, independent of &__content's (pattern-reservation-only) padding above.
&-text {
position: relative;
min-height: $pattern-height;
background-color: var(--pattern-color, transparent);
padding: variables.$g-spacer-unit * 6;
@include typography.sofia-pro-body();

@media (max-width: variables.$g-bp4) {
padding: calc(#{variables.$g-spacer-unit} * 3) calc(#{variables.$g-spacer-unit} * 2.5) !important;
}
}
}

// The strip is always the same 5-shape cycle - rect, circle, circle, rect, circle - just
// entered at a different point per side (see pattern.pattern-side):
// - left: enters at shape 5, nearest text -> circle, rect, circle, circle, rect
// - right: enters at shape 2, nearest text -> circle, circle, rect, circle, rect
&__pattern {
@include pattern.pattern-strip($pattern-height, $pattern-repeat-count);
height: $pattern-height;

// Aligned to &-text's top edge, not stretched to &__content's full (padded) height.
&--left {
top: 0;
right: 100%;
background-position-x: right;
@include pattern.pattern-side(left, 5, $pattern-height);
}

// Aligned to &-text's bottom edge, not stretched from &__content's full (padded) height.
&--right {
bottom: 0;
left: 100%;
background-position-x: left;
@include pattern.pattern-side(right, 2, $pattern-height);
}

// Below $g-bp4 the pattern moves from beside the text to above/below it (see &__pattern-slot).
@media (max-width: variables.$g-bp4) {
@include pattern.pattern-strip($pattern-height-mobile, $pattern-repeat-count);
height: $pattern-height-mobile;

&--left {
right: 0;
left: auto;
@include pattern.pattern-side(left, 5, $pattern-height-mobile);
}

&--right {
left: 0;
right: auto;
@include pattern.pattern-side(right, 2, $pattern-height-mobile);
}
}
}

// No-op on desktop. Below $g-bp4 it's the positioned, overflow-clipping box that caps
// &__pattern at 40% (top) / 30% (bottom) of &__content's width - the cap can't live on
// &__pattern itself without breaking the Chrome tiling-bug workaround above.
&__pattern-slot {
@media (max-width: variables.$g-bp4) {
position: absolute;
overflow: hidden;
height: $pattern-height-mobile;

// left/right overshoot to reach past avo2 Container's gutter to the true screen
// edge; width compensates so the inner (anchor) edge stays exactly at 40% / 30%.
&--top {
top: 0;
left: -$pattern-mobile-overshoot;
width: calc(40% + #{$pattern-mobile-overshoot});
}

&--bottom {
bottom: 0;
right: -$pattern-mobile-overshoot;
width: calc(30% + #{$pattern-mobile-overshoot});
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './BlockHighlightText.editorconfig.ts';
export { BlockHighlightText } from './BlockHighlightText.tsx';
Loading