From 74e61e9591d412ef67a87c40c4279393a8ae0812 Mon Sep 17 00:00:00 2001 From: Christophe Jossart Date: Fri, 3 May 2024 11:11:10 +0200 Subject: [PATCH 01/15] feat(SLB-300): add accordion block --- .../src/blocks/accordion-item-text.tsx | 90 +++++++++++++++++++ .../gutenberg_blocks/src/blocks/accordion.tsx | 25 ++++++ packages/drupal/gutenberg_blocks/src/index.ts | 2 + 3 files changed, 117 insertions(+) create mode 100644 packages/drupal/gutenberg_blocks/src/blocks/accordion-item-text.tsx create mode 100644 packages/drupal/gutenberg_blocks/src/blocks/accordion.tsx diff --git a/packages/drupal/gutenberg_blocks/src/blocks/accordion-item-text.tsx b/packages/drupal/gutenberg_blocks/src/blocks/accordion-item-text.tsx new file mode 100644 index 000000000..774c0a96c --- /dev/null +++ b/packages/drupal/gutenberg_blocks/src/blocks/accordion-item-text.tsx @@ -0,0 +1,90 @@ +import React, { Fragment } from 'react'; +import { InspectorControls, RichText } from 'wordpress__block-editor'; +import { registerBlockType } from 'wordpress__blocks'; +import { PanelBody, SelectControl } from 'wordpress__components'; +import { compose, withState } from 'wordpress__compose'; + +// @ts-ignore +const { t: __ } = Drupal; +// @ts-ignore +registerBlockType('custom/accordion-item-text', { + title: 'Accordion Item Text', + icon: 'text', + category: 'layout', + parent: ['custom/accordion'], + attributes: { + title: { + type: 'string', + }, + text: { + type: 'string', + }, + icon: { + type: 'string', + }, + }, + // @ts-ignore + edit: compose(withState())((props) => { + const { attributes, setAttributes } = props; + const icons = [ + { label: __('- Select an optional icon -'), value: '' }, + { label: __('Checkmark'), value: 'checkmark' }, + { label: __('Questionmark'), value: 'questionmark' }, + { label: __('Arrow'), value: 'arrow' }, + ]; + setAttributes({ + icon: attributes.icon === undefined ? '' : attributes.icon, + }); + + return ( + + + + { + setAttributes({ + icon: newValue, + }); + }} + /> + + +
+
{__('Accordion Item Text')}
+
+ { + setAttributes({ title: newValue }); + }} + /> + { + setAttributes({ text: newValue }); + }} + /> +
+
+
+ ); + }), + + save() { + return null; + }, +}); diff --git a/packages/drupal/gutenberg_blocks/src/blocks/accordion.tsx b/packages/drupal/gutenberg_blocks/src/blocks/accordion.tsx new file mode 100644 index 000000000..924746dd8 --- /dev/null +++ b/packages/drupal/gutenberg_blocks/src/blocks/accordion.tsx @@ -0,0 +1,25 @@ +import { InnerBlocks } from 'wordpress__block-editor'; +import { registerBlockType } from 'wordpress__blocks'; + +// @ts-ignore +const { t: __ } = Drupal; + +registerBlockType('custom/accordion', { + title: __('Accordion'), + icon: 'menu', + category: 'layout', + attributes: {}, + edit: () => { + return ( +
+
{__('Accordion')}
+ +
+ ); + }, + save: () => , +}); diff --git a/packages/drupal/gutenberg_blocks/src/index.ts b/packages/drupal/gutenberg_blocks/src/index.ts index 2763bdad8..1a936eb57 100644 --- a/packages/drupal/gutenberg_blocks/src/index.ts +++ b/packages/drupal/gutenberg_blocks/src/index.ts @@ -9,3 +9,5 @@ import './blocks/image-with-text'; import './filters/list'; import './blocks/cta'; import './blocks/quote'; +import './blocks/accordion'; +import './blocks/accordion-item-text'; From abec41f839406203bf54cb7c061a80be6e2b32d5 Mon Sep 17 00:00:00 2001 From: Christophe Jossart Date: Fri, 3 May 2024 11:30:28 +0200 Subject: [PATCH 02/15] feat(SLB-300): accordion validators --- .../AccordionItemTextValidator.php | 37 ++++++++++++++++++ .../GutenbergValidator/AccordionValidator.php | 39 +++++++++++++++++++ 2 files changed, 76 insertions(+) create mode 100644 packages/drupal/gutenberg_blocks/src/Plugin/Validation/GutenbergValidator/AccordionItemTextValidator.php create mode 100644 packages/drupal/gutenberg_blocks/src/Plugin/Validation/GutenbergValidator/AccordionValidator.php diff --git a/packages/drupal/gutenberg_blocks/src/Plugin/Validation/GutenbergValidator/AccordionItemTextValidator.php b/packages/drupal/gutenberg_blocks/src/Plugin/Validation/GutenbergValidator/AccordionItemTextValidator.php new file mode 100644 index 000000000..6f9a6dcee --- /dev/null +++ b/packages/drupal/gutenberg_blocks/src/Plugin/Validation/GutenbergValidator/AccordionItemTextValidator.php @@ -0,0 +1,37 @@ + [ + 'field_label' => $this->t('Title'), + 'rules' => ['required'], + ], + // @todo check if we want text as rich text or inner blocks. + ]; + } + +} diff --git a/packages/drupal/gutenberg_blocks/src/Plugin/Validation/GutenbergValidator/AccordionValidator.php b/packages/drupal/gutenberg_blocks/src/Plugin/Validation/GutenbergValidator/AccordionValidator.php new file mode 100644 index 000000000..6e7443e53 --- /dev/null +++ b/packages/drupal/gutenberg_blocks/src/Plugin/Validation/GutenbergValidator/AccordionValidator.php @@ -0,0 +1,39 @@ + 'custom/accordion-item-text', + 'blockLabel' => $this->t('Accordion'), + 'min' => 1, + 'max' => GutenbergCardinalityValidatorInterface::CARDINALITY_UNLIMITED, + ], + ]; + return $this->validateCardinality($block, $expectedChildren); + } + +} From b6a65f4f4f489e858c1025fa0812df13ffa74f4a Mon Sep 17 00:00:00 2001 From: Christophe Jossart Date: Fri, 3 May 2024 11:43:19 +0200 Subject: [PATCH 03/15] feat(SLB-300): accordion schema --- packages/schema/src/schema.graphql | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/packages/schema/src/schema.graphql b/packages/schema/src/schema.graphql index ca52d0ef3..1114a2cea 100644 --- a/packages/schema/src/schema.graphql +++ b/packages/schema/src/schema.graphql @@ -206,6 +206,7 @@ union PageContent @resolveEditorBlockType = | BlockCta | BlockImageWithText | BlockQuote + | BlockAccordion type BlockForm @type(id: "custom/form") { url: Url @resolveEditorBlockAttribute(key: "formId") @webformIdToUrl(id: "$") @@ -245,6 +246,24 @@ type BlockImageTeaser @default @value { ctaUrl: Url @resolveEditorBlockAttribute(key: "ctaUrl") } +type BlockAccordion @type(id: "custom/accordion") { + items: [BlockAccordionItem]! @resolveEditorBlockChildren +} + +interface BlockAccordionItemInterface { + title: String! +} + +union BlockAccordionItem @resolveEditorBlockType = BlockAccordionItemText + +type BlockAccordionItemText implements BlockAccordionItemInterface + @type(id: "custom/accordion-item-text") { + title: String! @resolveEditorBlockAttribute(key: "title") + icon: String! @resolveEditorBlockAttribute(key: "icon") + # @todo check if we want inner blocks here. + text: String! @resolveEditorBlockAttribute(key: "text") +} + type BlockCta @type(id: "custom/cta") { url: Url @resolveEditorBlockAttribute(key: "url") text: String @resolveEditorBlockAttribute(key: "text") From cca79348f01e9356df9fc7778abe414f93f5555a Mon Sep 17 00:00:00 2001 From: Christophe Jossart Date: Fri, 3 May 2024 12:38:36 +0200 Subject: [PATCH 04/15] chore(SLB-300): add placeholder for storybook integration --- packages/ui/src/components/Organisms/PageDisplay.tsx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/ui/src/components/Organisms/PageDisplay.tsx b/packages/ui/src/components/Organisms/PageDisplay.tsx index 86813de03..6369f68f6 100644 --- a/packages/ui/src/components/Organisms/PageDisplay.tsx +++ b/packages/ui/src/components/Organisms/PageDisplay.tsx @@ -60,6 +60,10 @@ export function PageDisplay(page: PageFragment) { ); case 'BlockQuote': return
; + case 'BlockAccordion': + // @todo implement. + // eslint-disable-next-line react/jsx-no-literals + return
BlockAccordion goes here
; default: throw new UnreachableCaseError(block); } From 7d5cd0674ae4b7dbcf62ab553752e271a03439d5 Mon Sep 17 00:00:00 2001 From: Christophe Jossart Date: Fri, 3 May 2024 13:09:06 +0200 Subject: [PATCH 05/15] feat(SLB-300): add accordion fragments --- packages/schema/src/fragments/Page.gql | 1 + .../src/fragments/PageContent/BlockAccordion.gql | 11 +++++++++++ 2 files changed, 12 insertions(+) create mode 100644 packages/schema/src/fragments/PageContent/BlockAccordion.gql diff --git a/packages/schema/src/fragments/Page.gql b/packages/schema/src/fragments/Page.gql index cbf2227eb..53a741be7 100644 --- a/packages/schema/src/fragments/Page.gql +++ b/packages/schema/src/fragments/Page.gql @@ -35,6 +35,7 @@ fragment Page on Page { ...BlockCta ...BlockImageWithText ...BlockQuote + ...BlockAccordion } metaTags { tag diff --git a/packages/schema/src/fragments/PageContent/BlockAccordion.gql b/packages/schema/src/fragments/PageContent/BlockAccordion.gql new file mode 100644 index 000000000..d98beaa51 --- /dev/null +++ b/packages/schema/src/fragments/PageContent/BlockAccordion.gql @@ -0,0 +1,11 @@ +fragment BlockAccordion on BlockAccordion { + items { + ...BlockAccordionItemText + } +} + +fragment BlockAccordionItemText on BlockAccordionItemText { + title + icon + text +} From 8b75635e9e001b1ed6b7f7755d85458e5b5566f0 Mon Sep 17 00:00:00 2001 From: Christophe Jossart Date: Fri, 3 May 2024 14:16:18 +0200 Subject: [PATCH 06/15] fix(SLB-300): don't use union for now Types implementing queryable interfaces must also implement the Node interface. --- packages/schema/src/schema.graphql | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/packages/schema/src/schema.graphql b/packages/schema/src/schema.graphql index 1114a2cea..c65d6f320 100644 --- a/packages/schema/src/schema.graphql +++ b/packages/schema/src/schema.graphql @@ -247,17 +247,10 @@ type BlockImageTeaser @default @value { } type BlockAccordion @type(id: "custom/accordion") { - items: [BlockAccordionItem]! @resolveEditorBlockChildren + items: [BlockAccordionItemText]! @resolveEditorBlockChildren } -interface BlockAccordionItemInterface { - title: String! -} - -union BlockAccordionItem @resolveEditorBlockType = BlockAccordionItemText - -type BlockAccordionItemText implements BlockAccordionItemInterface - @type(id: "custom/accordion-item-text") { +type BlockAccordionItemText @default @value { title: String! @resolveEditorBlockAttribute(key: "title") icon: String! @resolveEditorBlockAttribute(key: "icon") # @todo check if we want inner blocks here. From f93cc5e0fbe8ca4a99c0d3118bb49dc9fd0c2c1c Mon Sep 17 00:00:00 2001 From: Christophe Jossart Date: Fri, 3 May 2024 15:31:00 +0200 Subject: [PATCH 07/15] refactor(SLB-300): use InnerBlocks instead of RichText --- .../AccordionItemTextValidator.php | 16 ++++++++++- .../GutenbergValidator/AccordionValidator.php | 3 +++ .../src/blocks/accordion-item-text.tsx | 27 ++++++++----------- .../fragments/PageContent/BlockAccordion.gql | 4 ++- packages/schema/src/schema.graphql | 3 +-- 5 files changed, 33 insertions(+), 20 deletions(-) diff --git a/packages/drupal/gutenberg_blocks/src/Plugin/Validation/GutenbergValidator/AccordionItemTextValidator.php b/packages/drupal/gutenberg_blocks/src/Plugin/Validation/GutenbergValidator/AccordionItemTextValidator.php index 6f9a6dcee..4ab6b31ab 100644 --- a/packages/drupal/gutenberg_blocks/src/Plugin/Validation/GutenbergValidator/AccordionItemTextValidator.php +++ b/packages/drupal/gutenberg_blocks/src/Plugin/Validation/GutenbergValidator/AccordionItemTextValidator.php @@ -3,6 +3,8 @@ namespace Drupal\gutenberg_blocks\Plugin\Validation\GutenbergValidator; use Drupal\Core\StringTranslation\StringTranslationTrait; +use Drupal\silverback_gutenberg\GutenbergValidation\GutenbergCardinalityValidatorInterface; +use Drupal\silverback_gutenberg\GutenbergValidation\GutenbergCardinalityValidatorTrait; use Drupal\silverback_gutenberg\GutenbergValidation\GutenbergValidatorBase; /** @@ -12,6 +14,7 @@ * ) */ class AccordionItemTextValidator extends GutenbergValidatorBase { + use GutenbergCardinalityValidatorTrait; use StringTranslationTrait; /** @@ -30,8 +33,19 @@ public function validatedFields($block = []): array { 'field_label' => $this->t('Title'), 'rules' => ['required'], ], - // @todo check if we want text as rich text or inner blocks. ]; } + /** + * {@inheritDoc} + */ + public function validateContent($block = []): array { + $expectedChildren = [ + 'validationType' => GutenbergCardinalityValidatorInterface::CARDINALITY_ANY, + 'min' => 1, + 'max' => GutenbergCardinalityValidatorInterface::CARDINALITY_UNLIMITED, + ]; + return $this->validateCardinality($block, $expectedChildren); + } + } diff --git a/packages/drupal/gutenberg_blocks/src/Plugin/Validation/GutenbergValidator/AccordionValidator.php b/packages/drupal/gutenberg_blocks/src/Plugin/Validation/GutenbergValidator/AccordionValidator.php index 6e7443e53..d0bae38b0 100644 --- a/packages/drupal/gutenberg_blocks/src/Plugin/Validation/GutenbergValidator/AccordionValidator.php +++ b/packages/drupal/gutenberg_blocks/src/Plugin/Validation/GutenbergValidator/AccordionValidator.php @@ -24,6 +24,9 @@ public function applies(array $block): bool { return $block['blockName'] === 'custom/accordion'; } + /** + * {@inheritDoc} + */ public function validateContent($block = []): array { $expectedChildren = [ [ diff --git a/packages/drupal/gutenberg_blocks/src/blocks/accordion-item-text.tsx b/packages/drupal/gutenberg_blocks/src/blocks/accordion-item-text.tsx index 774c0a96c..dd50cd99e 100644 --- a/packages/drupal/gutenberg_blocks/src/blocks/accordion-item-text.tsx +++ b/packages/drupal/gutenberg_blocks/src/blocks/accordion-item-text.tsx @@ -1,5 +1,9 @@ import React, { Fragment } from 'react'; -import { InspectorControls, RichText } from 'wordpress__block-editor'; +import { + InnerBlocks, + InspectorControls, + RichText, +} from 'wordpress__block-editor'; import { registerBlockType } from 'wordpress__blocks'; import { PanelBody, SelectControl } from 'wordpress__components'; import { compose, withState } from 'wordpress__compose'; @@ -16,9 +20,6 @@ registerBlockType('custom/accordion-item-text', { title: { type: 'string', }, - text: { - type: 'string', - }, icon: { type: 'string', }, @@ -67,16 +68,10 @@ registerBlockType('custom/accordion-item-text', { setAttributes({ title: newValue }); }} /> - { - setAttributes({ text: newValue }); - }} + @@ -84,7 +79,7 @@ registerBlockType('custom/accordion-item-text', { ); }), - save() { - return null; + save: () => { + return ; }, }); diff --git a/packages/schema/src/fragments/PageContent/BlockAccordion.gql b/packages/schema/src/fragments/PageContent/BlockAccordion.gql index d98beaa51..0f77b257d 100644 --- a/packages/schema/src/fragments/PageContent/BlockAccordion.gql +++ b/packages/schema/src/fragments/PageContent/BlockAccordion.gql @@ -7,5 +7,7 @@ fragment BlockAccordion on BlockAccordion { fragment BlockAccordionItemText on BlockAccordionItemText { title icon - text + textContent { + markup + } } diff --git a/packages/schema/src/schema.graphql b/packages/schema/src/schema.graphql index c65d6f320..28a5f02ce 100644 --- a/packages/schema/src/schema.graphql +++ b/packages/schema/src/schema.graphql @@ -253,8 +253,7 @@ type BlockAccordion @type(id: "custom/accordion") { type BlockAccordionItemText @default @value { title: String! @resolveEditorBlockAttribute(key: "title") icon: String! @resolveEditorBlockAttribute(key: "icon") - # @todo check if we want inner blocks here. - text: String! @resolveEditorBlockAttribute(key: "text") + textContent: BlockMarkup @resolveEditorBlockChildren @seek(pos: 0) } type BlockCta @type(id: "custom/cta") { From 6835bb619c4aed89f017f8ca82ab2d79267750b9 Mon Sep 17 00:00:00 2001 From: Christophe Jossart Date: Fri, 3 May 2024 15:44:40 +0200 Subject: [PATCH 08/15] test(SLB-300): accordion block --- .../a397ca48-8fad-411e-8901-0eba2feb989c.yml | 16 +++++++- tests/schema/specs/blocks.spec.ts | 40 +++++++++++++++++-- 2 files changed, 52 insertions(+), 4 deletions(-) diff --git a/packages/drupal/test_content/content/node/a397ca48-8fad-411e-8901-0eba2feb989c.yml b/packages/drupal/test_content/content/node/a397ca48-8fad-411e-8901-0eba2feb989c.yml index ebd66747b..50a8cccb2 100644 --- a/packages/drupal/test_content/content/node/a397ca48-8fad-411e-8901-0eba2feb989c.yml +++ b/packages/drupal/test_content/content/node/a397ca48-8fad-411e-8901-0eba2feb989c.yml @@ -117,9 +117,23 @@ default: + + -

+

Incididunt laborum velit non proident nostrud velit. Minim excepteur ut aliqua nisi. Culpa laboris consectetur proident. Tempor esse ullamco et dolor proident id officia laborum voluptate nostrud elit dolore qui amet. Ex Lorem irure eu anim ipsum officia.

+ + + + + +
  • Moitié-moitié
  • Fribourgeoise
+ + + +

Incididunt laborum velit non proident nostrud velit. Minim excepteur ut aliqua nisi. Culpa laboris consectetur proident. Tempor esse ullamco et dolor proident id officia laborum voluptate nostrud elit dolore qui amet. Ex Lorem irure eu anim ipsum officia.

+ + format: gutenberg summary: '' diff --git a/tests/schema/specs/blocks.spec.ts b/tests/schema/specs/blocks.spec.ts index 4730f8d2a..a7fa91331 100644 --- a/tests/schema/specs/blocks.spec.ts +++ b/tests/schema/specs/blocks.spec.ts @@ -71,6 +71,19 @@ test('Blocks', async () => { __typename } } + ... on BlockAccordion { + items { + __typename + ... on BlockAccordionItemText { + __typename + title + icon + textContent { + markup + } + } + } + } } } { @@ -210,10 +223,31 @@ test('Blocks', async () => { "role": "Project manager", }, { - "__typename": "BlockMarkup", - "markup": " -

+ "__typename": "BlockAccordion", + "items": [ + { + "__typename": "BlockAccordionItemText", + "icon": "", + "textContent": { + "markup": " +

Incididunt laborum velit non proident nostrud velit. Minim excepteur ut aliqua nisi. Culpa laboris consectetur proident. Tempor esse ullamco et dolor proident id officia laborum voluptate nostrud elit dolore qui amet. Ex Lorem irure eu anim ipsum officia.

+ ", + }, + "title": "With a single paragraph and no icon", + }, + { + "__typename": "BlockAccordionItemText", + "icon": "arrow", + "textContent": { + "markup": " +
  • Moitié-moitié
  • Fribourgeoise
+ +

Incididunt laborum velit non proident nostrud velit. Minim excepteur ut aliqua nisi. Culpa laboris consectetur proident. Tempor esse ullamco et dolor proident id officia laborum voluptate nostrud elit dolore qui amet. Ex Lorem irure eu anim ipsum officia.

", + }, + "title": "With a list and a paragraph and arrow icon", + }, + ], }, ], "hero": { From 18d3aa51cfb0365e95a689a9e3281cacc49eb8d5 Mon Sep 17 00:00:00 2001 From: Christophe Jossart Date: Fri, 3 May 2024 18:03:29 +0200 Subject: [PATCH 09/15] feat(SLB-301): accordion storybook --- packages/schema/src/schema.graphql | 2 +- .../PageContent/BlockAccordion.stories.tsx | 56 +++++++++++++++ .../Organisms/PageContent/BlockAccordion.tsx | 68 +++++++++++++++++++ .../src/components/Organisms/PageDisplay.tsx | 5 +- 4 files changed, 127 insertions(+), 4 deletions(-) create mode 100644 packages/ui/src/components/Organisms/PageContent/BlockAccordion.stories.tsx create mode 100644 packages/ui/src/components/Organisms/PageContent/BlockAccordion.tsx diff --git a/packages/schema/src/schema.graphql b/packages/schema/src/schema.graphql index 28a5f02ce..e41512dcb 100644 --- a/packages/schema/src/schema.graphql +++ b/packages/schema/src/schema.graphql @@ -247,7 +247,7 @@ type BlockImageTeaser @default @value { } type BlockAccordion @type(id: "custom/accordion") { - items: [BlockAccordionItemText]! @resolveEditorBlockChildren + items: [BlockAccordionItemText!]! @resolveEditorBlockChildren } type BlockAccordionItemText @default @value { diff --git a/packages/ui/src/components/Organisms/PageContent/BlockAccordion.stories.tsx b/packages/ui/src/components/Organisms/PageContent/BlockAccordion.stories.tsx new file mode 100644 index 000000000..867eaef1b --- /dev/null +++ b/packages/ui/src/components/Organisms/PageContent/BlockAccordion.stories.tsx @@ -0,0 +1,56 @@ +import { Markup } from '@custom/schema'; +import { Meta, StoryObj } from '@storybook/react'; + +import { BlockAccordion } from './BlockAccordion'; + +export default { + component: BlockAccordion, +} satisfies Meta; + +export const AccordionItemText = { + args: { + items: [ + { + title: 'Cheese Fondue', + icon: '', + textContent: { + markup: ` +

The earliest known recipe for the modern form of cheese fondue comes from a 1699 book published in Zürich, under the name "Käss mit Wein zu kochen" 'to cook cheese with wine'. It calls for grated or cut-up cheese to be melted with wine, and for bread to be dipped in it.

+
    +
  • Fribourgeoise
  • +
  • Moitié-Moitié
  • +
+ ` as Markup, + }, + }, + { + title: 'Rösti', + icon: 'questionmark', + textContent: { + markup: ` +

Rösti is a kind of fried potato cake served as a main course or side dish.

+

As a main dish, rösti is usually accompanied with cheese, onions and cold meat or eggs. This dish, originally from Zürich, was first simply made by frying grated raw potatoes in a pan. It has then spread towards Bern where it is made with boiled potatoes instead. This is where it took the name Rösti.[20] There are many variants in Switzerland and outside the borders.[21] This culinary specialty gives its name to the röstigraben, which designates the cultural differences between the German- and French-speaking parts of the country.

+ ` as Markup, + }, + }, + { + title: 'Älplermagronen', + icon: 'checkmark', + textContent: { + markup: ` +

Älplermagronen are now regarded as a traditional dish of the Swiss Alps and a classic of Swiss comfort foods. According to a popular theory, pasta became widespread in northern Switzerland in the late 19th century, when the Gotthard Tunnel was built, partly by Italian workers who brought dry pasta with them.

+ ` as Markup, + }, + }, + { + title: 'Meringue with double cream', + icon: 'arrow', + textContent: { + markup: ` +

The Oxford English Dictionary states that the French word is of unknown origin. The name meringue for this confection first appeared in print in François Massialot's cookbook of 1692.

+ ` as Markup, + }, + }, + ], + }, +} satisfies StoryObj; diff --git a/packages/ui/src/components/Organisms/PageContent/BlockAccordion.tsx b/packages/ui/src/components/Organisms/PageContent/BlockAccordion.tsx new file mode 100644 index 000000000..4fa234038 --- /dev/null +++ b/packages/ui/src/components/Organisms/PageContent/BlockAccordion.tsx @@ -0,0 +1,68 @@ +import { + BlockAccordionFragment, + BlockAccordionItemTextFragment, +} from '@custom/schema'; +import { + ArrowRightCircleIcon, + CheckCircleIcon, + QuestionMarkCircleIcon, +} from '@heroicons/react/20/solid'; +import React from 'react'; + +import { BlockMarkup } from './BlockMarkup'; + +export function BlockAccordion(props: BlockAccordionFragment) { + return ( +
+ {props.items.map((item, index) => ( + + ))} +
+ ); +} + +function AccordionItemText( + props: BlockAccordionItemTextFragment & { + id: number; + }, +) { + return ( + <> +

+ +

+
+
+ {props.textContent?.markup && } +
+
+ + ); +} + +function AccordionIcon({ icon }: { icon: string }) { + switch (icon) { + case 'questionmark': + return ; + case 'checkmark': + return ; + case 'arrow': + return ; + default: + return null; + } +} diff --git a/packages/ui/src/components/Organisms/PageDisplay.tsx b/packages/ui/src/components/Organisms/PageDisplay.tsx index 6369f68f6..1e01edf5b 100644 --- a/packages/ui/src/components/Organisms/PageDisplay.tsx +++ b/packages/ui/src/components/Organisms/PageDisplay.tsx @@ -4,6 +4,7 @@ import React from 'react'; import { isTruthy } from '../../utils/isTruthy'; import { UnreachableCaseError } from '../../utils/unreachable-case-error'; import { PageTransition } from '../Molecules/PageTransition'; +import { BlockAccordion } from './PageContent/BlockAccordion'; import { BlockCta } from './PageContent/BlockCta'; import { BlockForm } from './PageContent/BlockForm'; import { BlockMarkup } from './PageContent/BlockMarkup'; @@ -61,9 +62,7 @@ export function PageDisplay(page: PageFragment) { case 'BlockQuote': return
; case 'BlockAccordion': - // @todo implement. - // eslint-disable-next-line react/jsx-no-literals - return
BlockAccordion goes here
; + return ; default: throw new UnreachableCaseError(block); } From 46520712f9ab7548a26f47bc772ef8de8d98b847 Mon Sep 17 00:00:00 2001 From: Christophe Jossart Date: Fri, 3 May 2024 19:05:16 +0200 Subject: [PATCH 10/15] refactor(SLB-301): use custom theme --- packages/ui/package.json | 1 + .../Organisms/PageContent/BlockAccordion.tsx | 108 ++++--- pnpm-lock.yaml | 276 +++++++++++++++--- 3 files changed, 293 insertions(+), 92 deletions(-) diff --git a/packages/ui/package.json b/packages/ui/package.json index f3320b5ce..967e148ea 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -44,6 +44,7 @@ "@heroicons/react": "^2.1.1", "@hookform/resolvers": "^3.3.3", "clsx": "^2.1.0", + "flowbite-react": "^0.9.0", "framer-motion": "^10.17.4", "hast-util-is-element": "^2.1.3", "hast-util-select": "^5.0.5", diff --git a/packages/ui/src/components/Organisms/PageContent/BlockAccordion.tsx b/packages/ui/src/components/Organisms/PageContent/BlockAccordion.tsx index 4fa234038..d9838dce7 100644 --- a/packages/ui/src/components/Organisms/PageContent/BlockAccordion.tsx +++ b/packages/ui/src/components/Organisms/PageContent/BlockAccordion.tsx @@ -1,67 +1,85 @@ -import { - BlockAccordionFragment, - BlockAccordionItemTextFragment, -} from '@custom/schema'; +import { BlockAccordionFragment } from '@custom/schema'; import { ArrowRightCircleIcon, CheckCircleIcon, QuestionMarkCircleIcon, } from '@heroicons/react/20/solid'; +import { Accordion, CustomFlowbiteTheme, Flowbite } from 'flowbite-react'; import React from 'react'; import { BlockMarkup } from './BlockMarkup'; -export function BlockAccordion(props: BlockAccordionFragment) { - return ( -
- {props.items.map((item, index) => ( - - ))} -
- ); -} - -function AccordionItemText( - props: BlockAccordionItemTextFragment & { - id: number; +const accordionTheme: CustomFlowbiteTheme['accordion'] = { + root: { + base: 'divide-y divide-gray-200 border-gray-200 dark:divide-gray-700 dark:border-gray-700', + flush: { + off: 'border-b', + on: 'border-b', + }, }, -) { + content: { + base: 'p-2 m-0 text-gray-200 dark:bg-gray-900', + }, + title: { + arrow: { + base: 'h-0 w-0', + }, + base: 'flex w-full items-center justify-between p-5 text-left font-medium text-gray-500 dark:text-gray-400', + flush: { + off: 'hover:bg-gray-100 dark:hover:bg-gray-800 dark:focus:ring-gray-800', + on: 'bg-transparent dark:bg-transparent', + }, + heading: '', + open: { + off: '', + on: 'text-gray-900 dark:text-gray-100', + }, + }, +}; + +// Applying the custom theme to the Accordion component +// doesn't work out, wrapping it in a Flowbite component. +const theme: CustomFlowbiteTheme = { + accordion: accordionTheme, +}; + +export function BlockAccordion(props: BlockAccordionFragment) { return ( - <> -

- -

-
-
- {props.textContent?.markup && } -
-
- + + + {props.items.map((item, index) => ( + + + + {item.icon && } {item.title} + + + + {item.textContent?.markup && ( + + )} + + + ))} + + ); } function AccordionIcon({ icon }: { icon: string }) { switch (icon) { case 'questionmark': - return ; + return ( + + ); case 'checkmark': - return ; + return ( + + ); case 'arrow': - return ; + return ( + + ); default: return null; } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 05006d49f..2d882578c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -16,7 +16,7 @@ importers: devDependencies: '@commitlint/cli': specifier: ^18.4.3 - version: 18.4.3(@types/node@18.19.31)(typescript@5.3.3) + version: 18.4.3(@types/node@20.11.17)(typescript@5.3.3) '@commitlint/config-conventional': specifier: ^18.4.3 version: 18.4.3 @@ -64,7 +64,7 @@ importers: version: 5.3.3 vitest: specifier: ^1.1.1 - version: 1.1.1(@types/node@18.19.31) + version: 1.1.1(@types/node@20.11.17) apps/cms: dependencies: @@ -532,6 +532,9 @@ importers: clsx: specifier: ^2.1.0 version: 2.1.0 + flowbite-react: + specifier: ^0.9.0 + version: 0.9.0(react-dom@18.2.0)(react@18.2.0)(tailwindcss@3.4.0) framer-motion: specifier: ^10.17.4 version: 10.17.4(react-dom@18.2.0)(react@18.2.0) @@ -601,7 +604,7 @@ importers: version: 8.0.0-alpha.14(jest@29.7.0)(vitest@1.1.1) '@storybook/test-runner': specifier: ^0.16.0 - version: 0.16.0(@types/node@18.19.31) + version: 0.16.0(@types/node@20.11.17) '@swc/cli': specifier: ^0.1.63 version: 0.1.63(@swc/core@1.3.102) @@ -694,7 +697,7 @@ importers: version: 5.3.3 vite: specifier: ^5.0.10 - version: 5.0.10(@types/node@18.19.31) + version: 5.0.10(@types/node@20.11.17) vite-imagetools: specifier: ^6.2.9 version: 6.2.9 @@ -703,7 +706,7 @@ importers: version: 1.0.3 vitest: specifier: ^1.1.1 - version: 1.1.1(@types/node@18.19.31)(happy-dom@12.10.3) + version: 1.1.1(@types/node@20.11.17)(happy-dom@12.10.3) tests/e2e: devDependencies: @@ -2687,14 +2690,14 @@ packages: resolution: {integrity: sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA==} engines: {node: '>=0.1.90'} - /@commitlint/cli@18.4.3(@types/node@18.19.31)(typescript@5.3.3): + /@commitlint/cli@18.4.3(@types/node@20.11.17)(typescript@5.3.3): resolution: {integrity: sha512-zop98yfB3A6NveYAZ3P1Mb6bIXuCeWgnUfVNkH4yhIMQpQfzFwseadazOuSn0OOfTt0lWuFauehpm9GcqM5lww==} engines: {node: '>=v18'} hasBin: true dependencies: '@commitlint/format': 18.6.1 '@commitlint/lint': 18.6.1 - '@commitlint/load': 18.6.1(@types/node@18.19.31)(typescript@5.3.3) + '@commitlint/load': 18.6.1(@types/node@20.11.17)(typescript@5.3.3) '@commitlint/read': 18.6.1 '@commitlint/types': 18.6.1 execa: 5.1.1 @@ -2765,7 +2768,7 @@ packages: '@commitlint/types': 18.6.1 dev: true - /@commitlint/load@18.6.1(@types/node@18.19.31)(typescript@5.3.3): + /@commitlint/load@18.6.1(@types/node@20.11.17)(typescript@5.3.3): resolution: {integrity: sha512-p26x8734tSXUHoAw0ERIiHyW4RaI4Bj99D8YgUlVV9SedLf8hlWAfyIFhHRIhfPngLlCe0QYOdRKYFt8gy56TA==} engines: {node: '>=v18'} dependencies: @@ -2775,7 +2778,7 @@ packages: '@commitlint/types': 18.6.1 chalk: 4.1.2 cosmiconfig: 8.3.6(typescript@5.3.3) - cosmiconfig-typescript-loader: 5.0.0(@types/node@18.19.31)(cosmiconfig@8.3.6)(typescript@5.3.3) + cosmiconfig-typescript-loader: 5.0.0(@types/node@20.11.17)(cosmiconfig@8.3.6)(typescript@5.3.3) lodash.isplainobject: 4.0.6 lodash.merge: 4.6.2 lodash.uniq: 4.5.0 @@ -4158,14 +4161,12 @@ packages: resolution: {integrity: sha512-PcF++MykgmTj3CIyOQbKA/hDzOAiqI3mhuoN44WRCopIs1sgoDoU4oty4Jtqaj/y3oDU6fnVSm4QG0a3t5i0+g==} dependencies: '@floating-ui/utils': 0.2.1 - dev: true /@floating-ui/dom@1.6.3: resolution: {integrity: sha512-RnDthu3mzPlQ31Ss/BTwQ1zjzIhr3lk1gZB1OC56h/1vEtaXkESrOqL5fQVMfXpwGtRwX+YsZBdyHtJMQnkArw==} dependencies: '@floating-ui/core': 1.6.0 '@floating-ui/utils': 0.2.1 - dev: true /@floating-ui/react-dom@2.0.8(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-HOdqOt3R3OGeTKidaLvJKcgg75S6tibQ3Tif4eyd91QnIJWr0NLvoXFpJA/j8HqkFSL68GDca9AuyWEHlhyClw==} @@ -4176,11 +4177,22 @@ packages: '@floating-ui/dom': 1.6.3 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - dev: true + + /@floating-ui/react@0.26.10(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-sh6f9gVvWQdEzLObrWbJ97c0clJObiALsFe0LiR/kb3tDRKwEhObASEH2QyfdoO/ZBPzwxa9j+nYFo+sqgbioA==} + peerDependencies: + react: '>=16.8.0' + react-dom: '>=16.8.0' + dependencies: + '@floating-ui/react-dom': 2.0.8(react-dom@18.2.0)(react@18.2.0) + '@floating-ui/utils': 0.2.1 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + tabbable: 6.2.0 + dev: false /@floating-ui/utils@0.2.1: resolution: {integrity: sha512-9TANp6GPoMtYzQdt54kfAyMmz1+osLlXdg2ENroU7zzrtflTLrrC/lgrIfaSe+Wu0b89GKccT7vxXA0MoAIO+Q==} - dev: true /@formatjs/cli@6.2.4: resolution: {integrity: sha512-g1o9O143F5TGB55skib3fKbyjifPa9YoDcX9L07hVJocRKngCcu4JhKViyUSN55KGcN2ttfBomM+wihN6wtBSQ==} @@ -5683,7 +5695,7 @@ packages: magic-string: 0.27.0 react-docgen-typescript: 2.2.2(typescript@5.3.3) typescript: 5.3.3 - vite: 5.0.10(@types/node@18.19.31) + vite: 5.0.10(@types/node@20.11.17) dev: true /@jridgewell/gen-mapping@0.3.5: @@ -7273,6 +7285,10 @@ packages: resolution: {integrity: sha512-j7P6Rgr3mmtdkeDGTe0E/aYyWEWVtc5yFXtHCRHs28/jptDEWfaVOc5T7cblqy1XKPPfCxJc/8DwQ5YgLOZOVQ==} dev: true + /@popperjs/core@2.11.8: + resolution: {integrity: sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==} + dev: false + /@radix-ui/number@1.0.1: resolution: {integrity: sha512-T5gIdVO2mmPW3NNhjNgEP3cqMXjXL9UbO0BzWcXfvdBs+BohbQxvd/K5hSVKmn9/lbTdsQVKbUcP5WLCwvUbBg==} dependencies: @@ -8352,7 +8368,7 @@ packages: magic-string: 0.30.9 rollup: 3.29.4 typescript: 5.3.3 - vite: 5.0.10(@types/node@18.19.31) + vite: 5.0.10(@types/node@20.11.17) transitivePeerDependencies: - encoding - supports-color @@ -8861,7 +8877,7 @@ packages: react: 18.2.0 react-docgen: 7.0.3 react-dom: 18.2.0(react@18.2.0) - vite: 5.0.10(@types/node@18.19.31) + vite: 5.0.10(@types/node@20.11.17) transitivePeerDependencies: - '@preact/preset-vite' - encoding @@ -8935,7 +8951,7 @@ packages: - supports-color dev: true - /@storybook/test-runner@0.16.0(@types/node@18.19.31): + /@storybook/test-runner@0.16.0(@types/node@20.11.17): resolution: {integrity: sha512-LDmNbKFoEDW/VS9o6KR8e1r5MnbCc5ZojUfi5yqLdq80gFD7BvilgKgV0lUh/xWHryzoy+Ids5LYgrPJZmU2dQ==} engines: {node: ^16.10.0 || ^18.0.0 || >=20.0.0} hasBin: true @@ -8955,7 +8971,7 @@ packages: commander: 9.5.0 expect-playwright: 0.8.0 glob: 10.3.12 - jest: 29.7.0(@types/node@18.19.31) + jest: 29.7.0(@types/node@20.11.17) jest-circus: 29.7.0 jest-environment-node: 29.7.0 jest-junit: 16.0.0 @@ -9413,10 +9429,10 @@ packages: chalk: 3.0.0 css.escape: 1.5.1 dom-accessibility-api: 0.6.3 - jest: 29.7.0(@types/node@18.19.31) + jest: 29.7.0(@types/node@20.11.17) lodash: 4.17.21 redent: 3.0.0 - vitest: 1.1.1(@types/node@18.19.31)(happy-dom@12.10.3) + vitest: 1.1.1(@types/node@20.11.17)(happy-dom@12.10.3) dev: true /@testing-library/react@14.1.2(react-dom@18.2.0)(react@18.2.0): @@ -11017,7 +11033,7 @@ packages: vite: ^4 || ^5 dependencies: '@swc/core': 1.4.13 - vite: 5.0.10(@types/node@18.0.0) + vite: 5.0.10(@types/node@20.11.17) transitivePeerDependencies: - '@swc/helpers' dev: true @@ -11044,7 +11060,7 @@ packages: '@babel/plugin-transform-react-jsx-source': 7.24.1(@babel/core@7.24.4) magic-string: 0.27.0 react-refresh: 0.14.0 - vite: 5.0.10(@types/node@18.19.31) + vite: 5.0.10(@types/node@20.11.17) transitivePeerDependencies: - supports-color dev: true @@ -13793,6 +13809,10 @@ packages: static-extend: 0.1.2 dev: false + /classnames@2.5.1: + resolution: {integrity: sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==} + dev: false + /clean-deep@3.4.0: resolution: {integrity: sha512-Lo78NV5ItJL/jl+B5w0BycAisaieJGXK1qYi/9m4SjR8zbqmrUtO7Yhro40wEShGmmxs/aJLI/A+jNhdkXK8mw==} engines: {node: '>=4'} @@ -14425,7 +14445,7 @@ packages: object-assign: 4.1.1 vary: 1.1.2 - /cosmiconfig-typescript-loader@5.0.0(@types/node@18.19.31)(cosmiconfig@8.3.6)(typescript@5.3.3): + /cosmiconfig-typescript-loader@5.0.0(@types/node@20.11.17)(cosmiconfig@8.3.6)(typescript@5.3.3): resolution: {integrity: sha512-+8cK7jRAReYkMwMiG+bxhcNKiHJDM6bR9FD/nGBXOWdMLuYawjF5cGrtLilJ+LGd3ZjCXnJjR5DkfWPoIVlqJA==} engines: {node: '>=v16'} peerDependencies: @@ -14433,7 +14453,7 @@ packages: cosmiconfig: '>=8.2' typescript: '>=4' dependencies: - '@types/node': 18.19.31 + '@types/node': 20.11.17 cosmiconfig: 8.3.6(typescript@5.3.3) jiti: 1.21.0 typescript: 5.3.3 @@ -14559,7 +14579,7 @@ packages: dependencies: '@babel/runtime': 7.24.4 - /create-jest@29.7.0(@types/node@18.19.31): + /create-jest@29.7.0(@types/node@20.11.17): resolution: {integrity: sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} hasBin: true @@ -14568,7 +14588,7 @@ packages: chalk: 4.1.2 exit: 0.1.2 graceful-fs: 4.2.11 - jest-config: 29.7.0(@types/node@18.19.31) + jest-config: 29.7.0(@types/node@20.11.17) jest-util: 29.7.0 prompts: 2.4.2 transitivePeerDependencies: @@ -14981,6 +15001,11 @@ packages: resolution: {integrity: sha512-XRRe6Glud4rd/ZGQfiV1ruXSfbvfJedlV9Y6zOlP+2K04vBYiJEte6stfFkCP03aMnY5tsipamumUjL14fofug==} dev: true + /debounce@2.0.0: + resolution: {integrity: sha512-xRetU6gL1VJbs85Mc4FoEGSjQxzpdxRyFhe3lmWFyy2EzydIcD4xzUvRJMD+NPDfMwKNhxa3PvsIOU32luIWeA==} + engines: {node: '>=18'} + dev: false + /debug@2.6.9: resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==} peerDependencies: @@ -18577,6 +18602,32 @@ packages: engines: {node: '>=0.4.0'} dev: true + /flowbite-react@0.9.0(react-dom@18.2.0)(react@18.2.0)(tailwindcss@3.4.0): + resolution: {integrity: sha512-wRGzTPHaEuRSXiAFhdTuksezABE/AjI/iyOOBGZpsFAz/sq7zuorAqjRud9FWgy3TlFPtldl7kL93wNY2nOnKQ==} + peerDependencies: + react: '>=18' + react-dom: '>=18' + tailwindcss: ^3 + dependencies: + '@floating-ui/core': 1.6.0 + '@floating-ui/react': 0.26.10(react-dom@18.2.0)(react@18.2.0) + classnames: 2.5.1 + debounce: 2.0.0 + flowbite: 2.3.0 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + react-icons: 5.0.1(react@18.2.0) + tailwind-merge: 2.2.2 + tailwindcss: 3.4.0 + dev: false + + /flowbite@2.3.0: + resolution: {integrity: sha512-pm3JRo8OIJHGfFYWgaGpPv8E+UdWy0Z3gEAGufw+G/1dusaU/P1zoBLiQpf2/+bYAi+GBQtPVG86KYlV0W+AFQ==} + dependencies: + '@popperjs/core': 2.11.8 + mini-svg-data-uri: 1.4.4 + dev: false + /flush-write-stream@2.0.0: resolution: {integrity: sha512-uXClqPxT4xW0lcdSBheb2ObVU+kuqUk3Jk64EwieirEXZx9XUrVwp/JuBfKAWaM4T5Td/VL7QLDWPXp/MvGm/g==} dependencies: @@ -22480,7 +22531,7 @@ packages: - supports-color dev: true - /jest-cli@29.7.0(@types/node@18.19.31): + /jest-cli@29.7.0(@types/node@20.11.17): resolution: {integrity: sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} hasBin: true @@ -22494,10 +22545,10 @@ packages: '@jest/test-result': 29.7.0 '@jest/types': 29.6.3 chalk: 4.1.2 - create-jest: 29.7.0(@types/node@18.19.31) + create-jest: 29.7.0(@types/node@20.11.17) exit: 0.1.2 import-local: 3.1.0 - jest-config: 29.7.0(@types/node@18.19.31) + jest-config: 29.7.0(@types/node@20.11.17) jest-util: 29.7.0 jest-validate: 29.7.0 yargs: 17.7.2 @@ -22548,6 +22599,46 @@ packages: - supports-color dev: true + /jest-config@29.7.0(@types/node@20.11.17): + resolution: {integrity: sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + peerDependencies: + '@types/node': '*' + ts-node: '>=9.0.0' + peerDependenciesMeta: + '@types/node': + optional: true + ts-node: + optional: true + dependencies: + '@babel/core': 7.24.4 + '@jest/test-sequencer': 29.7.0 + '@jest/types': 29.6.3 + '@types/node': 20.11.17 + babel-jest: 29.7.0(@babel/core@7.24.4) + chalk: 4.1.2 + ci-info: 3.9.0 + deepmerge: 4.3.1 + glob: 7.2.3 + graceful-fs: 4.2.11 + jest-circus: 29.7.0 + jest-environment-node: 29.7.0 + jest-get-type: 29.6.3 + jest-regex-util: 29.6.3 + jest-resolve: 29.7.0 + jest-runner: 29.7.0 + jest-util: 29.7.0 + jest-validate: 29.7.0 + micromatch: 4.0.5 + parse-json: 5.2.0 + pretty-format: 29.7.0 + slash: 3.0.0 + strip-json-comments: 3.1.1 + transitivePeerDependencies: + - babel-plugin-macros + - supports-color + dev: true + /jest-diff@29.7.0: resolution: {integrity: sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} @@ -22686,7 +22777,7 @@ packages: jest-runner: ^29.3.1 dependencies: expect-playwright: 0.8.0 - jest: 29.7.0(@types/node@18.19.31) + jest: 29.7.0(@types/node@20.11.17) jest-circus: 29.7.0 jest-environment-node: 29.7.0 jest-process-manager: 0.4.0 @@ -22897,7 +22988,7 @@ packages: dependencies: ansi-escapes: 6.2.1 chalk: 5.3.0 - jest: 29.7.0(@types/node@18.19.31) + jest: 29.7.0(@types/node@20.11.17) jest-regex-util: 29.6.3 jest-watcher: 29.7.0 slash: 5.1.0 @@ -22945,7 +23036,7 @@ packages: supports-color: 8.1.1 dev: true - /jest@29.7.0(@types/node@18.19.31): + /jest@29.7.0(@types/node@20.11.17): resolution: {integrity: sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} hasBin: true @@ -22958,7 +23049,7 @@ packages: '@jest/core': 29.7.0 '@jest/types': 29.6.3 import-local: 3.1.0 - jest-cli: 29.7.0(@types/node@18.19.31) + jest-cli: 29.7.0(@types/node@20.11.17) transitivePeerDependencies: - '@types/node' - babel-plugin-macros @@ -24667,7 +24758,6 @@ packages: /mini-svg-data-uri@1.4.4: resolution: {integrity: sha512-r9deDe9p5FJUPZAk3A59wGH7Ii9YrjjWw0jmw/liSbHl2CHiyXj6FcDXDu2K3TjVAXqiJdaw3xxwlZZr9E6nHg==} hasBin: true - dev: true /minimatch@3.1.2: resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} @@ -25903,6 +25993,7 @@ packages: /p-limit@4.0.0: resolution: {integrity: sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + requiresBuild: true dependencies: yocto-queue: 1.0.0 @@ -26660,7 +26751,6 @@ packages: postcss-value-parser: 4.2.0 read-cache: 1.0.0 resolve: 1.22.8 - dev: true /postcss-import@15.1.0(postcss@8.4.38): resolution: {integrity: sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==} @@ -26695,7 +26785,6 @@ packages: dependencies: camelcase-css: 2.0.1 postcss: 8.4.32 - dev: true /postcss-js@4.0.1(postcss@8.4.38): resolution: {integrity: sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==} @@ -26723,7 +26812,6 @@ packages: lilconfig: 3.1.1 postcss: 8.4.32 yaml: 2.3.4 - dev: true /postcss-load-config@4.0.2(postcss@8.4.38): resolution: {integrity: sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==} @@ -26946,7 +27034,6 @@ packages: dependencies: postcss: 8.4.32 postcss-selector-parser: 6.0.16 - dev: true /postcss-nested@6.0.1(postcss@8.4.38): resolution: {integrity: sha512-mEp4xPMi5bSWiMbsgoPfcP74lsWLHkQbZc3sY+jWYd65CUwXrUaTp0fmNpa01ZcETKlIgUdFN/MpS2xZtqL9dQ==} @@ -27288,7 +27375,6 @@ packages: nanoid: 3.3.7 picocolors: 1.0.0 source-map-js: 1.2.0 - dev: true /postcss@8.4.38: resolution: {integrity: sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==} @@ -28112,6 +28198,14 @@ packages: source-map: 0.7.4 dev: false + /react-icons@5.0.1(react@18.2.0): + resolution: {integrity: sha512-WqLZJ4bLzlhmsvme6iFdgO8gfZP17rfjYEJ2m9RsZjZ+cc4k1hTzknEz63YS1MeT50kVzoa1Nz36f4BEx+Wigw==} + peerDependencies: + react: '*' + dependencies: + react: 18.2.0 + dev: false + /react-immutable-proptypes@2.2.0(immutable@3.8.2): resolution: {integrity: sha512-Vf4gBsePlwdGvSZoLSBfd4HAP93HDauMY4fDjXhreg/vg6F3Fj/MXDNyTbltPC/xZKmZc+cjLu3598DdYK6sgQ==} peerDependencies: @@ -30871,6 +30965,10 @@ packages: resolution: {integrity: sha512-ulAk51I9UVUyJgxlv9M6lFot2WP3e7t8Kz9+IS6D4rVba1tR9kON+Ey69f+1R4Q8cd45Lod6a4IcJIxnzGc/zA==} engines: {node: '>=18'} + /tabbable@6.2.0: + resolution: {integrity: sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew==} + dev: false + /table@5.4.6: resolution: {integrity: sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug==} engines: {node: '>=6.0.0'} @@ -30904,6 +31002,12 @@ packages: - supports-color dev: false + /tailwind-merge@2.2.2: + resolution: {integrity: sha512-tWANXsnmJzgw6mQ07nE3aCDkCK4QdT3ThPMCzawoYA2Pws7vSTCvz3Vrjg61jVUGfFZPJzxEP+NimbcW+EdaDw==} + dependencies: + '@babel/runtime': 7.24.4 + dev: false + /tailwindcss@3.4.0: resolution: {integrity: sha512-VigzymniH77knD1dryXbyxR+ePHihHociZbXnLZHUyzf2MMs2ZVqlUrZ3FvpXP8pno9JzmILt1sZPD19M3IxtA==} engines: {node: '>=14.0.0'} @@ -30933,7 +31037,6 @@ packages: sucrase: 3.35.0 transitivePeerDependencies: - ts-node - dev: true /tailwindcss@3.4.3: resolution: {integrity: sha512-U7sxQk/n397Bmx4JHbJx/iSOOv5G+II3f1kpLpY2QeUv5DcPdcTsYLlusZfq1NthHS1c1cZoyFmmkex1rzke0A==} @@ -32640,6 +32743,27 @@ packages: - terser dev: true + /vite-node@1.1.1(@types/node@20.11.17): + resolution: {integrity: sha512-2bGE5w4jvym5v8llF6Gu1oBrmImoNSs4WmRVcavnG2me6+8UQntTqLiAMFyiAobp+ZXhj5ZFhI7SmLiFr/jrow==} + engines: {node: ^18.0.0 || >=20.0.0} + hasBin: true + dependencies: + cac: 6.7.14 + debug: 4.3.4 + pathe: 1.1.2 + picocolors: 1.0.0 + vite: 5.2.8(@types/node@20.11.17) + transitivePeerDependencies: + - '@types/node' + - less + - lightningcss + - sass + - stylus + - sugarss + - supports-color + - terser + dev: true + /vite-plugin-istanbul@3.0.4: resolution: {integrity: sha512-DJy3cq6yOFbsM3gLQf/3zeuaJNJsfBv5dLFdZdv8sUV30xLtZI+66QeYfHUyP/5vBUYyLA+xNUCSG5uHY6w+5g==} dependencies: @@ -32691,7 +32815,7 @@ packages: fsevents: 2.3.3 dev: true - /vite@5.0.10(@types/node@18.19.31): + /vite@5.0.10(@types/node@20.11.17): resolution: {integrity: sha512-2P8J7WWgmc355HUMlFrwofacvr98DAjoE52BfdbwQtyLH06XKwaL/FMnmKM2crF0iX4MpmMKoDlNCB1ok7zHCw==} engines: {node: ^18.0.0 || >=20.0.0} hasBin: true @@ -32719,7 +32843,7 @@ packages: terser: optional: true dependencies: - '@types/node': 18.19.31 + '@types/node': 20.11.17 esbuild: 0.19.12 postcss: 8.4.32 rollup: 4.14.1 @@ -33026,7 +33150,7 @@ packages: - terser dev: true - /vitest@1.1.1(@types/node@18.19.31): + /vitest@1.1.1(@types/node@18.19.31)(happy-dom@12.10.3): resolution: {integrity: sha512-Ry2qs4UOu/KjpXVfOCfQkTnwSXYGrqTbBZxw6reIYEFjSy1QUARRg5pxiI5BEXy+kBVntxUYNMlq4Co+2vD3fQ==} engines: {node: ^18.0.0 || >=20.0.0} hasBin: true @@ -33062,6 +33186,7 @@ packages: chai: 4.4.1 debug: 4.3.4 execa: 8.0.1 + happy-dom: 12.10.3 local-pkg: 0.5.0 magic-string: 0.30.9 pathe: 1.1.2 @@ -33083,7 +33208,7 @@ packages: - terser dev: true - /vitest@1.1.1(@types/node@18.19.31)(happy-dom@12.10.3): + /vitest@1.1.1(@types/node@20.11.17): resolution: {integrity: sha512-Ry2qs4UOu/KjpXVfOCfQkTnwSXYGrqTbBZxw6reIYEFjSy1QUARRg5pxiI5BEXy+kBVntxUYNMlq4Co+2vD3fQ==} engines: {node: ^18.0.0 || >=20.0.0} hasBin: true @@ -33108,7 +33233,64 @@ packages: jsdom: optional: true dependencies: - '@types/node': 18.19.31 + '@types/node': 20.11.17 + '@vitest/expect': 1.1.1 + '@vitest/runner': 1.1.1 + '@vitest/snapshot': 1.1.1 + '@vitest/spy': 1.1.1 + '@vitest/utils': 1.1.1 + acorn-walk: 8.3.2 + cac: 6.7.14 + chai: 4.4.1 + debug: 4.3.4 + execa: 8.0.1 + local-pkg: 0.5.0 + magic-string: 0.30.9 + pathe: 1.1.2 + picocolors: 1.0.0 + std-env: 3.7.0 + strip-literal: 1.3.0 + tinybench: 2.6.0 + tinypool: 0.8.3 + vite: 5.2.8(@types/node@20.11.17) + vite-node: 1.1.1(@types/node@20.11.17) + why-is-node-running: 2.2.2 + transitivePeerDependencies: + - less + - lightningcss + - sass + - stylus + - sugarss + - supports-color + - terser + dev: true + + /vitest@1.1.1(@types/node@20.11.17)(happy-dom@12.10.3): + resolution: {integrity: sha512-Ry2qs4UOu/KjpXVfOCfQkTnwSXYGrqTbBZxw6reIYEFjSy1QUARRg5pxiI5BEXy+kBVntxUYNMlq4Co+2vD3fQ==} + engines: {node: ^18.0.0 || >=20.0.0} + hasBin: true + peerDependencies: + '@edge-runtime/vm': '*' + '@types/node': ^18.0.0 || >=20.0.0 + '@vitest/browser': ^1.0.0 + '@vitest/ui': ^1.0.0 + happy-dom: '*' + jsdom: '*' + peerDependenciesMeta: + '@edge-runtime/vm': + optional: true + '@types/node': + optional: true + '@vitest/browser': + optional: true + '@vitest/ui': + optional: true + happy-dom: + optional: true + jsdom: + optional: true + dependencies: + '@types/node': 20.11.17 '@vitest/expect': 1.1.1 '@vitest/runner': 1.1.1 '@vitest/snapshot': 1.1.1 @@ -33128,8 +33310,8 @@ packages: strip-literal: 1.3.0 tinybench: 2.6.0 tinypool: 0.8.3 - vite: 5.2.8(@types/node@18.19.31) - vite-node: 1.1.1(@types/node@18.19.31) + vite: 5.2.8(@types/node@20.11.17) + vite-node: 1.1.1(@types/node@20.11.17) why-is-node-running: 2.2.2 transitivePeerDependencies: - less From 0186299000c585a002cb9f65f5c497d5e4ff5dd5 Mon Sep 17 00:00:00 2001 From: Christophe Jossart Date: Fri, 3 May 2024 20:00:05 +0200 Subject: [PATCH 11/15] refactor(SLB-301): styling --- .../Organisms/PageContent/BlockAccordion.tsx | 43 ++++++++++++++++--- 1 file changed, 38 insertions(+), 5 deletions(-) diff --git a/packages/ui/src/components/Organisms/PageContent/BlockAccordion.tsx b/packages/ui/src/components/Organisms/PageContent/BlockAccordion.tsx index d9838dce7..da90274c1 100644 --- a/packages/ui/src/components/Organisms/PageContent/BlockAccordion.tsx +++ b/packages/ui/src/components/Organisms/PageContent/BlockAccordion.tsx @@ -1,13 +1,21 @@ -import { BlockAccordionFragment } from '@custom/schema'; +import { BlockAccordionFragment, Html } from '@custom/schema'; import { ArrowRightCircleIcon, CheckCircleIcon, QuestionMarkCircleIcon, } from '@heroicons/react/20/solid'; +import clsx from 'clsx'; import { Accordion, CustomFlowbiteTheme, Flowbite } from 'flowbite-react'; -import React from 'react'; +import type { Element } from 'hast'; +import { selectAll } from 'hast-util-select'; +import React, { PropsWithChildren } from 'react'; +import { Plugin } from 'unified'; -import { BlockMarkup } from './BlockMarkup'; +const unorderedItems: Plugin<[], Element> = () => (tree) => { + selectAll('ul > li', tree).forEach((node) => { + node.properties!.unordered = true; + }); +}; const accordionTheme: CustomFlowbiteTheme['accordion'] = { root: { @@ -18,7 +26,7 @@ const accordionTheme: CustomFlowbiteTheme['accordion'] = { }, }, content: { - base: 'p-2 m-0 text-gray-200 dark:bg-gray-900', + base: 'pb-5 pt-5 text-base font-normal text-gray-500 dark:bg-gray-900 dark:text-gray-100', }, title: { arrow: { @@ -56,7 +64,32 @@ export function BlockAccordion(props: BlockAccordionFragment) { {item.textContent?.markup && ( - + ) => { + return ( +
  • + {children} +
  • + ); + }, + }} + markup={item.textContent.markup} + /> )}
    From faf98ca890dc826058aef89bd0e2e84d881f28db Mon Sep 17 00:00:00 2001 From: Christophe Jossart Date: Fri, 3 May 2024 20:52:51 +0200 Subject: [PATCH 12/15] refactor(SLB-301): styling --- .../ui/src/components/Organisms/PageContent/BlockAccordion.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ui/src/components/Organisms/PageContent/BlockAccordion.tsx b/packages/ui/src/components/Organisms/PageContent/BlockAccordion.tsx index da90274c1..0d357e500 100644 --- a/packages/ui/src/components/Organisms/PageContent/BlockAccordion.tsx +++ b/packages/ui/src/components/Organisms/PageContent/BlockAccordion.tsx @@ -26,7 +26,7 @@ const accordionTheme: CustomFlowbiteTheme['accordion'] = { }, }, content: { - base: 'pb-5 pt-5 text-base font-normal text-gray-500 dark:bg-gray-900 dark:text-gray-100', + base: 'pb-5 pt-5 text-base font-light text-gray-500 dark:bg-gray-900 dark:text-gray-100', }, title: { arrow: { From c3da87c3c0f1e7a02056a848402379b15cdc0bec Mon Sep 17 00:00:00 2001 From: Christophe Jossart Date: Fri, 3 May 2024 21:13:27 +0200 Subject: [PATCH 13/15] refactor(SLB-301): styling --- .../Organisms/PageContent/BlockAccordion.stories.tsx | 2 +- .../components/Organisms/PageContent/BlockAccordion.tsx | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/ui/src/components/Organisms/PageContent/BlockAccordion.stories.tsx b/packages/ui/src/components/Organisms/PageContent/BlockAccordion.stories.tsx index 867eaef1b..6f7be4e00 100644 --- a/packages/ui/src/components/Organisms/PageContent/BlockAccordion.stories.tsx +++ b/packages/ui/src/components/Organisms/PageContent/BlockAccordion.stories.tsx @@ -29,7 +29,7 @@ export const AccordionItemText = { textContent: { markup: `

    Rösti is a kind of fried potato cake served as a main course or side dish.

    -

    As a main dish, rösti is usually accompanied with cheese, onions and cold meat or eggs. This dish, originally from Zürich, was first simply made by frying grated raw potatoes in a pan. It has then spread towards Bern where it is made with boiled potatoes instead. This is where it took the name Rösti.[20] There are many variants in Switzerland and outside the borders.[21] This culinary specialty gives its name to the röstigraben, which designates the cultural differences between the German- and French-speaking parts of the country.

    +

    As a main dish, rösti is usually accompanied with cheese, onions and cold meat or eggs. This dish, originally from Zürich, was first simply made by frying grated raw potatoes in a pan. It has then spread towards Bern where it is made with boiled potatoes instead. This is where it took the name Rösti. There are many variants in Switzerland and outside the borders. This culinary specialty gives its name to the röstigraben, which designates the cultural differences between the German- and French-speaking parts of the country.

    ` as Markup, }, }, diff --git a/packages/ui/src/components/Organisms/PageContent/BlockAccordion.tsx b/packages/ui/src/components/Organisms/PageContent/BlockAccordion.tsx index 0d357e500..c53495d9a 100644 --- a/packages/ui/src/components/Organisms/PageContent/BlockAccordion.tsx +++ b/packages/ui/src/components/Organisms/PageContent/BlockAccordion.tsx @@ -21,8 +21,8 @@ const accordionTheme: CustomFlowbiteTheme['accordion'] = { root: { base: 'divide-y divide-gray-200 border-gray-200 dark:divide-gray-700 dark:border-gray-700', flush: { - off: 'border-b', - on: 'border-b', + off: 'border-b last:border-0', + on: 'border-b last:border-0', }, }, content: { @@ -32,7 +32,7 @@ const accordionTheme: CustomFlowbiteTheme['accordion'] = { arrow: { base: 'h-0 w-0', }, - base: 'flex w-full items-center justify-between p-5 text-left font-medium text-gray-500 dark:text-gray-400', + base: 'flex w-full items-center justify-between p-4 pl-1 text-left font-normal text-lg text-gray-500 dark:text-gray-400', flush: { off: 'hover:bg-gray-100 dark:hover:bg-gray-800 dark:focus:ring-gray-800', on: 'bg-transparent dark:bg-transparent', @@ -62,7 +62,7 @@ export function BlockAccordion(props: BlockAccordionFragment) { {item.icon && } {item.title} - + {item.textContent?.markup && ( Date: Fri, 3 May 2024 22:11:41 +0200 Subject: [PATCH 14/15] fix(SLB-301): adjust width --- .../Organisms/PageContent/BlockAccordion.tsx | 58 ++++++++++--------- 1 file changed, 30 insertions(+), 28 deletions(-) diff --git a/packages/ui/src/components/Organisms/PageContent/BlockAccordion.tsx b/packages/ui/src/components/Organisms/PageContent/BlockAccordion.tsx index c53495d9a..b1434696f 100644 --- a/packages/ui/src/components/Organisms/PageContent/BlockAccordion.tsx +++ b/packages/ui/src/components/Organisms/PageContent/BlockAccordion.tsx @@ -63,34 +63,36 @@ export function BlockAccordion(props: BlockAccordionFragment) { - {item.textContent?.markup && ( - ) => { - return ( -
  • - {children} -
  • - ); - }, - }} - markup={item.textContent.markup} - /> - )} +
    + {item.textContent?.markup && ( + ) => { + return ( +
  • + {children} +
  • + ); + }, + }} + markup={item.textContent.markup} + /> + )} +
    ))} From bc0ba2ba1f23a41baf07d49fd335a6bd7079b8f2 Mon Sep 17 00:00:00 2001 From: Christophe Jossart Date: Mon, 6 May 2024 10:03:08 +0200 Subject: [PATCH 15/15] feat(SLB-299): adjust accordion style, add to page story --- .../src/components/Organisms/PageContent/BlockAccordion.tsx | 4 ++-- packages/ui/src/components/Routes/Page.stories.tsx | 5 +++++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/packages/ui/src/components/Organisms/PageContent/BlockAccordion.tsx b/packages/ui/src/components/Organisms/PageContent/BlockAccordion.tsx index b1434696f..5f4e19453 100644 --- a/packages/ui/src/components/Organisms/PageContent/BlockAccordion.tsx +++ b/packages/ui/src/components/Organisms/PageContent/BlockAccordion.tsx @@ -19,7 +19,7 @@ const unorderedItems: Plugin<[], Element> = () => (tree) => { const accordionTheme: CustomFlowbiteTheme['accordion'] = { root: { - base: 'divide-y divide-gray-200 border-gray-200 dark:divide-gray-700 dark:border-gray-700', + base: 'mt-10 divide-y divide-gray-200 border-gray-200 dark:divide-gray-700 dark:border-gray-700', flush: { off: 'border-b last:border-0', on: 'border-b last:border-0', @@ -63,7 +63,7 @@ export function BlockAccordion(props: BlockAccordionFragment) { -
    +
    {item.textContent?.markup && ( ['content'], }, },