@kitconcept/volto-light-theme 7.0.0-alpha.22 → 7.0.0-alpha.23

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/.changelog.draft CHANGED
@@ -1,11 +1,16 @@
1
- ## 7.0.0-alpha.22 (2025-08-15)
1
+ ## 7.0.0-alpha.23 (2025-08-25)
2
+
3
+ ### Breaking
4
+
5
+ - By default, the Person images for teasers and listings are rounded (1:1).
6
+ Added a body tag classname to change them to be squared and 4/5 aspect ratio. @sneridagh
2
7
 
3
8
  ### Feature
4
9
 
5
- - Add styles for RSS block (note: full functionality requires RSS addon and templates available in kitconcept.intranet). @danalvrz
10
+ - Added Simple Side Slider Variation @Tishasoumya-02 [#sliderVariation](https://github.com/kitconcept/volto-light-theme/pull/sliderVariation)
6
11
 
7
- ### Internal
12
+ ### Bugfix
8
13
 
9
- - Fix Logos SVG size issue. @Tishasoumya-02
14
+ - Fix navigation menu misalignment in Intranet mobile view @iRohitSingh [#627](https://github.com/kitconcept/volto-light-theme/pull/627)
10
15
 
11
16
 
package/CHANGELOG.md CHANGED
@@ -8,6 +8,21 @@
8
8
 
9
9
  <!-- towncrier release notes start -->
10
10
 
11
+ ## 7.0.0-alpha.23 (2025-08-25)
12
+
13
+ ### Breaking
14
+
15
+ - By default, the Person images for teasers and listings are rounded (1:1).
16
+ Added a body tag classname to change them to be squared and 4/5 aspect ratio. @sneridagh
17
+
18
+ ### Feature
19
+
20
+ - Added Simple Side Slider Variation @Tishasoumya-02 [#sliderVariation](https://github.com/kitconcept/volto-light-theme/pull/sliderVariation)
21
+
22
+ ### Bugfix
23
+
24
+ - Fix navigation menu misalignment in Intranet mobile view @iRohitSingh [#627](https://github.com/kitconcept/volto-light-theme/pull/627)
25
+
11
26
  ## 7.0.0-alpha.22 (2025-08-15)
12
27
 
13
28
  ### Feature
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kitconcept/volto-light-theme",
3
- "version": "7.0.0-alpha.22",
3
+ "version": "7.0.0-alpha.23",
4
4
  "description": "Volto Light Theme by kitconcept",
5
5
  "main": "src/index.ts",
6
6
  "types": "src/index.ts",
@@ -42,7 +42,7 @@
42
42
  "typescript": "^5.7.3",
43
43
  "release-it": "^19.0.3",
44
44
  "vitest": "^3.1.2",
45
- "@plone/types": "1.4.1"
45
+ "@plone/types": "1.4.5"
46
46
  },
47
47
  "dependencies": {
48
48
  "@dnd-kit/core": "6.0.8",
@@ -52,6 +52,8 @@
52
52
  "react-aria-components": "^1.7.0",
53
53
  "react-colorful": "^5.6.1",
54
54
  "uuid": "^11.0.0",
55
+ "embla-carousel-autoplay": "^8.0.0",
56
+ "embla-carousel-react": "^8.0.0",
55
57
  "@plone/components": "^3.0.2"
56
58
  },
57
59
  "peerDependencies": {
@@ -0,0 +1,152 @@
1
+ import React from 'react';
2
+ import { useIntl, defineMessages } from 'react-intl';
3
+ import Icon from '@plone/volto/components/theme/Icon/Icon';
4
+ import MaybeWrap from '@plone/volto/components/manage/MaybeWrap/MaybeWrap';
5
+ import UniversalLink from '@plone/volto/components/manage/UniversalLink/UniversalLink';
6
+ import { Input, Button, Message } from 'semantic-ui-react';
7
+ import { isInternalURL } from '@plone/volto/helpers/Url/Url';
8
+ import cx from 'classnames';
9
+ import navTreeSVG from '@plone/volto/icons/nav.svg';
10
+ import imageBlockSVG from '@plone/volto/components/manage/Blocks/Image/block-image.svg';
11
+ import config from '@plone/volto/registry';
12
+
13
+ const messages = defineMessages({
14
+ PleaseChooseContent: {
15
+ id: 'Please choose an existing content as source for this element',
16
+ defaultMessage:
17
+ 'Please choose an existing content as source for this element',
18
+ },
19
+ moreInfo: {
20
+ id: 'moreInfo',
21
+ defaultMessage: 'More info',
22
+ },
23
+ source: {
24
+ id: 'Source',
25
+ defaultMessage: 'Source',
26
+ },
27
+ ButtonText: {
28
+ id: 'Continue reading',
29
+ defaultMessage: 'Continue reading',
30
+ },
31
+ });
32
+
33
+ const DefaultImage = (props) => <img {...props} alt={props.alt || ''} />;
34
+
35
+ const SliderVariants = ({
36
+ index,
37
+ onChangeBlock,
38
+ block,
39
+ data,
40
+ dataBlock,
41
+ isEditMode,
42
+ openObjectBrowser,
43
+ }) => {
44
+ const intl = useIntl();
45
+ const href = data.href?.[0];
46
+ const image = data.preview_image?.[0];
47
+
48
+ const Image = config.getComponent('Image').component || DefaultImage;
49
+ const { openExternalLinkInNewTab } = config.settings;
50
+
51
+ const handleClick = () => {
52
+ openObjectBrowser({
53
+ onSelectItem: (url, document) => {
54
+ dataBlock.slides[index].title = document.Title;
55
+ dataBlock.slides[index].description = document.Description;
56
+ dataBlock.slides[index].href = [
57
+ {
58
+ '@id': document['@id'],
59
+ Title: document.Title,
60
+ Description: document.Description,
61
+ title: document.Title,
62
+ image_field: document.image_field,
63
+ hasPreviewImage: document.hasPreviewImage,
64
+ },
65
+ ];
66
+ onChangeBlock(block, dataBlock);
67
+ },
68
+ mode: 'link',
69
+ });
70
+ };
71
+
72
+ return (
73
+ <div
74
+ className={cx('grid-teaser-item top', {
75
+ 'empty-slide': !href && isEditMode,
76
+ })}
77
+ >
78
+ {!href && isEditMode && (
79
+ <Message>
80
+ <div className="grid-teaser-item default">
81
+ <img src={imageBlockSVG} alt="" />
82
+ <p>{intl.formatMessage(messages.PleaseChooseContent)}</p>
83
+ <div className="toolbar-inner">
84
+ <Button.Group>
85
+ <Button onClick={handleClick} icon basic>
86
+ <Icon name={navTreeSVG} size="24px" />
87
+ </Button>
88
+ </Button.Group>
89
+ <Input
90
+ placeholder={`${intl.formatMessage(messages.source)}...`}
91
+ onClick={handleClick}
92
+ onFocus={(e) => e.target.blur()}
93
+ />
94
+ </div>
95
+ </div>
96
+ </Message>
97
+ )}
98
+ {href && (
99
+ <MaybeWrap
100
+ condition={!isEditMode}
101
+ as={UniversalLink}
102
+ href={href['@id']}
103
+ className="link-container"
104
+ target={
105
+ data.openLinkInNewTab ||
106
+ (openExternalLinkInNewTab && !isInternalURL(href['@id']))
107
+ ? '_blank'
108
+ : null
109
+ }
110
+ tabIndex="-1"
111
+ >
112
+ <div
113
+ className={cx(
114
+ 'teaser-item top',
115
+ `has--slider--flagAlign--${data.flagAlign}`,
116
+ dataBlock.variation,
117
+ )}
118
+ >
119
+ {(href?.hasPreviewImage || href.image_field || image) && (
120
+ <div className="highlight-image-wrapper gradient">
121
+ <Image
122
+ item={image || href}
123
+ imageField={image ? image.image_field : href.image_field}
124
+ alt=""
125
+ loading="lazy"
126
+ responsive={true}
127
+ />
128
+ </div>
129
+ )}
130
+ <div className="teaser-item-title fix-width-issue">
131
+ <div className="title">
132
+ {data?.head_title && (
133
+ <span className="supertitle">{data?.head_title}</span>
134
+ )}
135
+ <h2>{data?.nav_title || data?.title}</h2>
136
+ </div>
137
+ <p className="slider-description">{data?.description}</p>
138
+
139
+ {!data.hideButton && (
140
+ <Button tabIndex={'-1'}>
141
+ {data.buttonText || intl.formatMessage(messages.ButtonText)}
142
+ </Button>
143
+ )}
144
+ </div>
145
+ </div>
146
+ </MaybeWrap>
147
+ )}
148
+ </div>
149
+ );
150
+ };
151
+
152
+ export default SliderVariants;
@@ -0,0 +1,179 @@
1
+ import React, { useCallback, useEffect, useState } from 'react';
2
+ import { Message } from 'semantic-ui-react';
3
+ import useEmblaCarousel from 'embla-carousel-react';
4
+ import Autoplay from 'embla-carousel-autoplay';
5
+ import cx from 'classnames';
6
+ import { defineMessages, useIntl } from 'react-intl';
7
+ import Body from '@kitconcept/volto-slider-block/components/Body';
8
+ import withBlockExtensions from '@plone/volto/helpers/Extensions/withBlockExtensions';
9
+ import {
10
+ DotButton,
11
+ NextButton,
12
+ PrevButton,
13
+ } from '@kitconcept/volto-slider-block/components/DotsAndArrows';
14
+ import teaserTemplate from '@kitconcept/volto-slider-block/icons/teaser-template.svg';
15
+
16
+ const messages = defineMessages({
17
+ PleaseChooseContent: {
18
+ id: 'Please choose an existing content as source for this element',
19
+ defaultMessage:
20
+ 'Please choose an existing content as source for this element',
21
+ },
22
+ });
23
+
24
+ const SliderView = (props) => {
25
+ const {
26
+ className,
27
+ data,
28
+ isEditMode = false,
29
+ block,
30
+ openObjectBrowser,
31
+ onChangeBlock,
32
+ slideIndex,
33
+ setSlideIndex,
34
+ } = props;
35
+ const intl = useIntl();
36
+
37
+ const [prevBtnDisabled, setPrevBtnDisabled] = useState(true);
38
+ const [nextBtnDisabled, setNextBtnDisabled] = useState(true);
39
+ const [selectedIndex, setSelectedIndex] = useState(0);
40
+ const [scrollSnaps, setScrollSnaps] = useState([]);
41
+ const autoplay =
42
+ data.autoplayEnabled !== undefined ? data.autoplayEnabled : false;
43
+ const autoplayOptions = {
44
+ delay: data.autoplayDelay,
45
+ jump: data.autoplayJump,
46
+ };
47
+ const plugins = isEditMode ? [] : autoplay ? [Autoplay(autoplayOptions)] : [];
48
+
49
+ const [emblaRef, emblaApi] = useEmblaCarousel({ loop: true }, plugins);
50
+
51
+ const scrollPrev = useCallback(() => {
52
+ if (emblaApi) {
53
+ emblaApi.scrollPrev();
54
+ setSlideIndex && setSlideIndex(selectedIndex - 1);
55
+ }
56
+ }, [emblaApi, selectedIndex, setSlideIndex]);
57
+
58
+ const scrollNext = useCallback(() => {
59
+ if (emblaApi) {
60
+ emblaApi.scrollNext();
61
+ setSlideIndex && setSlideIndex(selectedIndex + 1);
62
+ }
63
+ }, [emblaApi, selectedIndex, setSlideIndex]);
64
+
65
+ const scrollTo = useCallback(
66
+ (index) => {
67
+ if (emblaApi) {
68
+ emblaApi.scrollTo(index);
69
+ setSlideIndex && setSlideIndex(index);
70
+ }
71
+ },
72
+ [emblaApi, setSlideIndex],
73
+ );
74
+
75
+ const onInit = useCallback((emblaApi) => {
76
+ setScrollSnaps(emblaApi.scrollSnapList());
77
+ }, []);
78
+
79
+ const onSelect = useCallback((emblaApi) => {
80
+ setSelectedIndex(emblaApi.selectedScrollSnap());
81
+ setPrevBtnDisabled(!emblaApi.canScrollPrev());
82
+ setNextBtnDisabled(!emblaApi.canScrollNext());
83
+ }, []);
84
+
85
+ useEffect(() => {
86
+ if (!emblaApi) return;
87
+
88
+ onInit(emblaApi);
89
+ onSelect(emblaApi);
90
+ emblaApi.on('reInit', onInit);
91
+ emblaApi.on('reInit', onSelect);
92
+ emblaApi.on('select', onSelect);
93
+ }, [emblaApi, onInit, onSelect]);
94
+
95
+ useEffect(() => {
96
+ // This syncs the current slide with the objectwidget (or other sources
97
+ // able to access the slider context)
98
+ // that can modify the SliderContext (and come here via props slideIndex)
99
+ if (isEditMode) {
100
+ scrollTo(slideIndex);
101
+ }
102
+ }, [slideIndex, scrollTo, isEditMode]);
103
+
104
+ const sliderContainerWidth = emblaApi
105
+ ?.rootNode()
106
+ .getBoundingClientRect().width;
107
+
108
+ return (
109
+ <>
110
+ {/* START CUSTOMIZATION */}
111
+ <div
112
+ className={cx('block slider', data.variation || 'default', className)}
113
+ style={{ '--slider-container-width': `${sliderContainerWidth}px` }}
114
+ >
115
+ {/* END CUSTOMIZATION */}
116
+ {(data.slides?.length === 0 || !data.slides) && isEditMode && (
117
+ <Message>
118
+ <div className="teaser-item default">
119
+ <img src={teaserTemplate} alt="" />
120
+ <p>{intl.formatMessage(messages.PleaseChooseContent)}</p>
121
+ </div>
122
+ </Message>
123
+ )}
124
+ {data.slides?.length > 0 && (
125
+ <>
126
+ <div className="slider-wrapper">
127
+ {!data.hideArrows && data.slides?.length > 1 && (
128
+ <>
129
+ <PrevButton onClick={scrollPrev} disabled={prevBtnDisabled} />
130
+ <NextButton onClick={scrollNext} disabled={nextBtnDisabled} />
131
+ </>
132
+ )}
133
+
134
+ <div className="slider-viewport" ref={emblaRef}>
135
+ <div className="slider-container">
136
+ {data.slides &&
137
+ data.slides.map((item, index) => {
138
+ return (
139
+ <div key={item['@id']} className="slider-slide">
140
+ <Body
141
+ {...props}
142
+ key={item['@id']}
143
+ data={item}
144
+ isEditMode={isEditMode}
145
+ dataBlock={data}
146
+ index={index}
147
+ block={block}
148
+ openObjectBrowser={openObjectBrowser}
149
+ onChangeBlock={onChangeBlock}
150
+ isActive={selectedIndex === index}
151
+ />
152
+ </div>
153
+ );
154
+ })}
155
+ </div>
156
+ </div>
157
+ </div>
158
+ {data.slides?.length > 1 && (
159
+ <div className="slider-dots">
160
+ {scrollSnaps.map((_, index) => (
161
+ <DotButton
162
+ key={index}
163
+ index={index}
164
+ onClick={() => scrollTo(index)}
165
+ className={'slider-dot'.concat(
166
+ index === selectedIndex ? ' slider-dot--selected' : '',
167
+ )}
168
+ />
169
+ ))}
170
+ </div>
171
+ )}
172
+ </>
173
+ )}
174
+ </div>
175
+ </>
176
+ );
177
+ };
178
+
179
+ export default withBlockExtensions(SliderView);
@@ -45,6 +45,8 @@ import SearchBlockViewEvent from '../components/Blocks/EventCalendar/Search/Sear
45
45
  import SearchBlockEditEvent from '../components/Blocks/EventCalendar/Search/SearchBlockEdit';
46
46
  import SearchBlockSchemaEvent from '../components/Blocks/EventCalendar/Search/schema';
47
47
  import EventCalenderTemplate from '../components/Blocks/EventCalendar/Search/components/EventTemplate';
48
+ import SliderVariants from '../components/Blocks/Slider/SliderVariants';
49
+ import DefaultBody from '../customizations/@kitconcept/volto-slider-block/components/DefaultBody';
48
50
 
49
51
  declare module '@plone/types' {
50
52
  export interface BlocksConfigData {
@@ -414,6 +416,20 @@ export default function install(config: ConfigType) {
414
416
  // Slider Block
415
417
  config.blocks.blocksConfig.slider = {
416
418
  ...config.blocks.blocksConfig.slider,
419
+ variations: [
420
+ {
421
+ id: 'default',
422
+ title: 'Default',
423
+ isDefault: true,
424
+ view: DefaultBody,
425
+ },
426
+
427
+ {
428
+ id: 'simple',
429
+ title: 'Simple',
430
+ view: SliderVariants,
431
+ },
432
+ ],
417
433
  schemaEnhancer: sliderBlockSchemaEnhancer,
418
434
  };
419
435
 
@@ -0,0 +1,11 @@
1
+ /**
2
+ * OVERRIDE View.jsx
3
+ * REASON: Adding variants.
4
+ * VERSION: 6.3.1
5
+ * DATE: 2025-07-18
6
+ * DEVELOPER: @Tishasoumya-02
7
+ */
8
+
9
+ import View from '../../../../components/Blocks/Slider/View';
10
+
11
+ export default View;
@@ -324,3 +324,129 @@ export const FourPerson: Story = {
324
324
  data: gridBlockFourPerson,
325
325
  },
326
326
  };
327
+
328
+ export const OnePersonSquared: Story = {
329
+ render: (args) => (
330
+ <Wrapper>
331
+ <div
332
+ className="person-squared-images"
333
+ style={{
334
+ containerType: 'inline-size',
335
+ width: 'var(--default-container-width)',
336
+ }}
337
+ >
338
+ <BlockWrapper {...args}>
339
+ <GridBlockView {...args} />
340
+ </BlockWrapper>
341
+ </div>
342
+ </Wrapper>
343
+ ),
344
+ args: {
345
+ data: gridBlockOnePerson,
346
+ },
347
+ };
348
+
349
+ export const TwoPersonSquared: Story = {
350
+ render: (args) => (
351
+ <Wrapper>
352
+ <div
353
+ className="person-squared-images"
354
+ style={{
355
+ containerType: 'inline-size',
356
+ width: 'var(--default-container-width)',
357
+ }}
358
+ >
359
+ <BlockWrapper {...args}>
360
+ <GridBlockView {...args} />
361
+ </BlockWrapper>
362
+ </div>
363
+ </Wrapper>
364
+ ),
365
+ args: {
366
+ data: gridBlockTwoPerson,
367
+ },
368
+ };
369
+
370
+ export const TwoDocumentAndPersonSquared: Story = {
371
+ render: (args) => (
372
+ <Wrapper>
373
+ <div
374
+ className="person-squared-images"
375
+ style={{
376
+ containerType: 'inline-size',
377
+ width: 'var(--default-container-width)',
378
+ }}
379
+ >
380
+ <BlockWrapper {...args}>
381
+ <GridBlockView {...args} />
382
+ </BlockWrapper>
383
+ </div>
384
+ </Wrapper>
385
+ ),
386
+ args: {
387
+ data: gridBlockTwoDocumentPerson,
388
+ },
389
+ };
390
+
391
+ export const TwoPersonsDifferentImageRatioSquared: Story = {
392
+ render: (args) => (
393
+ <Wrapper>
394
+ <div
395
+ className="person-squared-images"
396
+ style={{
397
+ containerType: 'inline-size',
398
+ width: 'var(--default-container-width)',
399
+ }}
400
+ >
401
+ <BlockWrapper {...args}>
402
+ <GridBlockView {...args} />
403
+ </BlockWrapper>
404
+ </div>
405
+ </Wrapper>
406
+ ),
407
+ args: {
408
+ data: gridBlockTwoPersonDifferentRatio,
409
+ },
410
+ };
411
+
412
+ export const ThreePersonSquared: Story = {
413
+ render: (args) => (
414
+ <Wrapper>
415
+ <div
416
+ className="person-squared-images"
417
+ style={{
418
+ containerType: 'inline-size',
419
+ width: 'var(--default-container-width)',
420
+ }}
421
+ >
422
+ <BlockWrapper {...args}>
423
+ <GridBlockView {...args} />
424
+ </BlockWrapper>
425
+ </div>
426
+ </Wrapper>
427
+ ),
428
+ args: {
429
+ data: gridBlockThreePerson,
430
+ },
431
+ };
432
+
433
+ export const FourPersonSquared: Story = {
434
+ render: (args) => (
435
+ <Wrapper>
436
+ <div
437
+ className="person-squared-images"
438
+ style={{
439
+ containerType: 'inline-size',
440
+ width: 'var(--default-container-width)',
441
+ }}
442
+ >
443
+ <BlockWrapper {...args}>
444
+ <GridBlockView {...args} />
445
+ </BlockWrapper>
446
+ </div>
447
+ </Wrapper>
448
+ ),
449
+ args: {
450
+ data: gridBlockFourPerson,
451
+ },
452
+ };
@@ -71,3 +71,113 @@ export const PersonSummary: Story = {
71
71
  ),
72
72
  ],
73
73
  };
74
+
75
+ export const PersonSummaryWithBigDescription: Story = {
76
+ render: (args) => (
77
+ <BlockWrapper {...args}>
78
+ <div className="block listing summary">
79
+ <ListingBody {...args} />
80
+ </div>
81
+ </BlockWrapper>
82
+ ),
83
+ args: {
84
+ data: {
85
+ ...listingBlockPerson,
86
+ items: [
87
+ {
88
+ ...listingBlockPerson.items[0],
89
+ description:
90
+ 'USS Voyager Captain from the 24th century. She is known for her strong leadership skills and her ability to make tough decisions in difficult situations. USS Voyager Captain from the 24th century. She is known for her strong leadership skills and her ability to make tough decisions in difficult situations. USS Voyager Captain from the 24th century. She is known for her strong leadership skills and her ability to make tough decisions in difficult situations. USS Voyager Captain from the 24th century. She is known for her strong leadership skills and her ability to make tough decisions in difficult situations.',
91
+ },
92
+ ],
93
+ },
94
+ listingItems: listingBlockPerson.items,
95
+ variation: {
96
+ id: 'summary',
97
+ template: SummaryTemplate,
98
+ title: 'List with images',
99
+ },
100
+ },
101
+ decorators: [
102
+ (Story) => (
103
+ <Wrapper>
104
+ <div style={{ width: 'var(--default-container-width)' }}>
105
+ <Story />
106
+ </div>
107
+ </Wrapper>
108
+ ),
109
+ ],
110
+ };
111
+
112
+ export const PersonSummarySquared: Story = {
113
+ render: (args) => (
114
+ <BlockWrapper {...args}>
115
+ <div className="block listing summary">
116
+ <ListingBody {...args} />
117
+ </div>
118
+ </BlockWrapper>
119
+ ),
120
+ args: {
121
+ data: {
122
+ ...listingBlockPerson,
123
+ },
124
+ listingItems: listingBlockPerson.items,
125
+ variation: {
126
+ id: 'summary',
127
+ template: SummaryTemplate,
128
+ title: 'List with images',
129
+ },
130
+ },
131
+ decorators: [
132
+ (Story) => (
133
+ <Wrapper>
134
+ <div
135
+ className="person-squared-images"
136
+ style={{ width: 'var(--default-container-width)' }}
137
+ >
138
+ <Story />
139
+ </div>
140
+ </Wrapper>
141
+ ),
142
+ ],
143
+ };
144
+
145
+ export const PersonSummarySquaredWithBigDescription: Story = {
146
+ render: (args) => (
147
+ <BlockWrapper {...args}>
148
+ <div className="block listing summary">
149
+ <ListingBody {...args} />
150
+ </div>
151
+ </BlockWrapper>
152
+ ),
153
+ args: {
154
+ data: {
155
+ ...listingBlockPerson,
156
+ items: [
157
+ {
158
+ ...listingBlockPerson.items[0],
159
+ description:
160
+ 'USS Voyager Captain from the 24th century. She is known for her strong leadership skills and her ability to make tough decisions in difficult situations. USS Voyager Captain from the 24th century. She is known for her strong leadership skills and her ability to make tough decisions in difficult situations. USS Voyager Captain from the 24th century. She is known for her strong leadership skills and her ability to make tough decisions in difficult situations. USS Voyager Captain from the 24th century. She is known for her strong leadership skills and her ability to make tough decisions in difficult situations.',
161
+ },
162
+ ],
163
+ },
164
+ listingItems: listingBlockPerson.items,
165
+ variation: {
166
+ id: 'summary',
167
+ template: SummaryTemplate,
168
+ title: 'List with images',
169
+ },
170
+ },
171
+ decorators: [
172
+ (Story) => (
173
+ <Wrapper>
174
+ <div
175
+ className="person-squared-images"
176
+ style={{ width: 'var(--default-container-width)' }}
177
+ >
178
+ <Story />
179
+ </div>
180
+ </Wrapper>
181
+ ),
182
+ ],
183
+ };
@@ -127,3 +127,67 @@ export const PersonTeaserRight: Story = {
127
127
  },
128
128
  },
129
129
  };
130
+
131
+ export const PersonTeaserLeftSquared: Story = {
132
+ render: (args) => (
133
+ <Wrapper>
134
+ <div
135
+ className="person-squared-images"
136
+ style={{ width: 'var(--default-container-width)' }}
137
+ >
138
+ <BlockWrapper {...args}>
139
+ <TeaserBody {...args} />
140
+ </BlockWrapper>
141
+ </div>
142
+ </Wrapper>
143
+ ),
144
+ args: {
145
+ data: personBlock,
146
+ },
147
+ };
148
+
149
+ export const PersonTeaserTopSquared: Story = {
150
+ render: (args) => (
151
+ <Wrapper>
152
+ <div
153
+ className="person-squared-images"
154
+ style={{ width: 'calc(var(--default-container-width) / 2)' }}
155
+ >
156
+ <BlockWrapper {...args}>
157
+ <TeaserBody {...args} />
158
+ </BlockWrapper>
159
+ </div>
160
+ </Wrapper>
161
+ ),
162
+ args: {
163
+ data: {
164
+ ...personBlock,
165
+ styles: {
166
+ align: 'center',
167
+ },
168
+ },
169
+ },
170
+ };
171
+
172
+ export const PersonTeaserRightSquared: Story = {
173
+ render: (args) => (
174
+ <Wrapper>
175
+ <div
176
+ className="person-squared-images"
177
+ style={{ width: 'var(--default-container-width)' }}
178
+ >
179
+ <BlockWrapper {...args}>
180
+ <TeaserBody {...args} />
181
+ </BlockWrapper>
182
+ </div>
183
+ </Wrapper>
184
+ ),
185
+ args: {
186
+ data: {
187
+ ...personBlock,
188
+ styles: {
189
+ align: 'right',
190
+ },
191
+ },
192
+ },
193
+ };
@@ -335,13 +335,21 @@
335
335
  }
336
336
 
337
337
  .menu-drawer {
338
- @media only screen and (max-width: $computer-breakpoint) {
339
- top: 210px;
338
+ @media only screen and (max-width: 961px) {
339
+ top: 208px;
340
340
 
341
341
  .search-button {
342
342
  display: none;
343
343
  }
344
344
  }
345
+
346
+ @media only screen and (max-width: $tablet-breakpoint) {
347
+ top: 168px;
348
+ }
349
+
350
+ @media only screen and (max-width: 620px) {
351
+ top: 225px;
352
+ }
345
353
  }
346
354
  }
347
355
  .logo {
@@ -8,32 +8,41 @@ $sliderImagesAspectRatio: var(--slider-images-aspect-ratio, 16/9);
8
8
  }
9
9
 
10
10
  .slider-viewport {
11
- margin-bottom: 0;
11
+ margin-bottom: $spacing-medium;
12
12
  }
13
13
 
14
14
  .slider-dots {
15
- padding-bottom: 40px;
16
- }
17
-
18
- .highlight-image-wrapper {
19
- display: flex; // Small gap was appearing between the wrapper and the image (??)
20
-
21
- img {
22
- // Override Volto's Image Component inline style aspect ratio.
23
- aspect-ratio: var(
24
- --image-aspect-ratio,
25
- $sliderImagesAspectRatio
26
- ) !important;
27
- }
15
+ padding-bottom: $spacing-medium;
28
16
  }
29
17
 
30
18
  .teaser-item,
31
19
  .grid-teaser-item {
32
20
  flex-direction: column;
21
+ @media only screen and (max-width: $computer-width) {
22
+ height: 100%;
23
+ }
33
24
  }
25
+ .link-container {
26
+ @media only screen and (max-width: $computer-width) {
27
+ height: 100%;
28
+ }
29
+ }
30
+
34
31
  .teaser-item {
35
- padding-bottom: $spacing-medium;
32
+ .highlight-image-wrapper {
33
+ display: flex; // Small gap was appearing between the wrapper and the image (??)
36
34
 
35
+ img {
36
+ // Override Volto's Image Component inline style aspect ratio.
37
+ aspect-ratio: var(
38
+ --image-aspect-ratio,
39
+ $sliderImagesAspectRatio
40
+ ) !important;
41
+ }
42
+ }
43
+ @media only screen and (max-width: $computer-width) {
44
+ display: flex;
45
+ }
37
46
  .teaser-item-title {
38
47
  position: absolute;
39
48
  top: 50%;
@@ -51,6 +60,7 @@ $sliderImagesAspectRatio: var(--slider-images-aspect-ratio, 16/9);
51
60
  @media only screen and (max-width: $computer-width) {
52
61
  position: static;
53
62
  width: 100%;
63
+ height: 100%;
54
64
  padding: 60px 20px;
55
65
  background: $black;
56
66
  transform: none;
@@ -112,4 +122,114 @@ $sliderImagesAspectRatio: var(--slider-images-aspect-ratio, 16/9);
112
122
  line-height: 20px;
113
123
  text-align: center;
114
124
  }
125
+
126
+ &.simple {
127
+ .slider-viewport {
128
+ margin-bottom: 0;
129
+ }
130
+ .teaser-item {
131
+ display: grid;
132
+ align-items: center;
133
+ padding: 0 130px;
134
+ aspect-ratio: 2/1;
135
+ background-color: var(--theme-color);
136
+ gap: clamp(30px, 4vw, 60px);
137
+ grid-template-areas: 'images content';
138
+ grid-template-rows: auto;
139
+ @media only screen and (max-width: $computer-width) {
140
+ display: flex;
141
+ padding: 0 0;
142
+ aspect-ratio: auto;
143
+ gap: 0;
144
+ }
145
+
146
+ &.has--slider--flagAlign--right {
147
+ grid-template-areas: 'images content';
148
+ grid-template-columns: clamp(300px, 40vw, 600px) auto;
149
+ }
150
+ &.has--slider--flagAlign--left {
151
+ grid-template-areas: 'content images';
152
+ grid-template-columns: auto clamp(300px, 40vw, 600px);
153
+ }
154
+
155
+ .highlight-image-wrapper {
156
+ grid-area: images;
157
+
158
+ img {
159
+ aspect-ratio: var(
160
+ --image-aspect-ratio,
161
+ $sliderImagesAspectRatio
162
+ ) !important;
163
+
164
+ @media only screen and (max-width: $computer-width) {
165
+ width: 100%;
166
+ }
167
+ }
168
+ }
169
+ .teaser-item-title {
170
+ position: relative;
171
+ top: 0;
172
+ width: 100%;
173
+ align-content: center;
174
+ padding: 0;
175
+ background: none;
176
+ color: var(--theme-foreground-color);
177
+ grid-area: content;
178
+ transform: none;
179
+
180
+ @media only screen and (max-width: $computer-width) {
181
+ position: relative;
182
+ width: 100%;
183
+ height: 100%;
184
+ padding: 60px 20px;
185
+ background: var(--theme-foreground-color);
186
+ color: $white;
187
+ transform: none;
188
+ .ui.button,
189
+ .title > h2,
190
+ p.slider-description {
191
+ color: $white !important;
192
+ }
193
+ p.slider-description {
194
+ -webkit-line-clamp: 8;
195
+ line-clamp: 8;
196
+ }
197
+ }
198
+
199
+ .title {
200
+ h2 {
201
+ color: var(--theme-foreground-color);
202
+ }
203
+ }
204
+ p {
205
+ color: var(--theme-foreground-color);
206
+ -webkit-line-clamp: 10;
207
+ line-clamp: 10;
208
+ }
209
+ }
210
+ .slider-description {
211
+ margin-bottom: $spacing-large;
212
+ font-size: 18px;
213
+ font-weight: 300;
214
+ line-height: 24px;
215
+ }
216
+ }
217
+ .slider-button {
218
+ display: flex;
219
+ width: 130px;
220
+ height: 100%;
221
+ align-items: center;
222
+ background: none;
223
+ opacity: 1;
224
+ svg.icon {
225
+ width: 50px !important;
226
+ height: 50px !important;
227
+ padding: 40px;
228
+ color: var(--theme-foreground-color);
229
+ }
230
+ }
231
+ .ui.button {
232
+ color: var(--theme-foreground-color);
233
+ }
234
+ }
115
235
  }
@@ -8,23 +8,23 @@
8
8
  .person-teaser.has--align--right:not(.contained) & {
9
9
  .card-inner {
10
10
  .image-wrapper {
11
- --person-image-max-width: 220px;
12
- --person-image-max-height: 285px;
13
11
  overflow: hidden;
14
- aspect-ratio: 4 / 5;
12
+ align-self: center;
13
+ border-radius: var(--person-image-border-radius, 10000px);
14
+ aspect-ratio: var(--person-image-aspect-ratio, 1 / 1);
15
15
  block-size: auto; // derived from `aspect-ratio`
16
16
 
17
17
  /* We allow the browser to adjust the real size within the maximums without
18
18
  distorting the aspect ratio */
19
19
  inline-size: 100%;
20
- max-block-size: var(--person-image-max-height);
21
- max-inline-size: var(--person-image-max-width);
20
+ max-block-size: var(--person-image-max-height, 220px);
21
+ max-inline-size: var(--person-image-max-width, 220px);
22
22
 
23
23
  img {
24
24
  width: 100%;
25
25
  height: 100%;
26
26
  object-fit: cover;
27
- object-position: top center;
27
+ object-position: center;
28
28
  }
29
29
  }
30
30
  }
@@ -68,29 +68,30 @@
68
68
 
69
69
  // Teaser in Grid
70
70
  .contained.person-teaser & {
71
- // Exploration for rounded images in person-teasers
72
- // --person-image-height: auto;
73
- // --person-image-border-radius: 10000px;
74
- // --person-image-aspect-ratio: 1/1;
71
+ // Settings for BRH:
72
+ // --person-image-aspect-ratio: 4 / 5;
73
+ // --person-image-border-radius: 0;
74
+ // --person-image-max-height: 285px;
75
+ // .image-wrapper img { object-position: top center; }
76
+
75
77
  .image-wrapper {
76
- --person-image-max-width: 220px;
77
- --person-image-max-height: 285px;
78
78
  overflow: hidden;
79
+ border-radius: var(--person-image-border-radius, 10000px);
79
80
  margin: 0 auto;
80
- aspect-ratio: 4 / 5;
81
+ aspect-ratio: var(--person-image-aspect-ratio, 1 / 1);
81
82
  block-size: auto; // derived from `aspect-ratio`
82
83
 
83
84
  /* We allow the browser to adjust the real size within the maximums without
84
85
  distorting the aspect ratio */
85
86
  inline-size: 100%;
86
- max-block-size: var(--person-image-max-height);
87
- max-inline-size: var(--person-image-max-width);
87
+ max-block-size: var(--person-image-max-height, 220px);
88
+ max-inline-size: var(--person-image-max-width, 220px);
88
89
 
89
90
  img {
90
91
  width: 100%;
91
92
  height: 100%;
92
93
  object-fit: cover;
93
- object-position: top center;
94
+ object-position: center;
94
95
  }
95
96
  }
96
97
  }
@@ -173,7 +174,7 @@ body .block.gridBlock .block.teaser.contained.person-teaser .card-inner {
173
174
  margin-left: auto;
174
175
  }
175
176
 
176
- // Listings (no card)
177
+ // Listings
177
178
  .block.listing {
178
179
  .listing-item.person-listing {
179
180
  &,
@@ -189,6 +190,37 @@ body .block.gridBlock .block.teaser.contained.person-teaser .card-inner {
189
190
  img {
190
191
  aspect-ratio: initial !important;
191
192
  }
193
+
194
+ .card-inner {
195
+ .image-wrapper {
196
+ overflow: hidden;
197
+ align-self: center;
198
+ border-radius: var(--person-image-border-radius, 10000px);
199
+ aspect-ratio: var(--person-image-aspect-ratio, 1 / 1);
200
+ block-size: auto; // derived from `aspect-ratio`
201
+
202
+ /* We allow the browser to adjust the real size within the maximums without
203
+ distorting the aspect ratio */
204
+ inline-size: 100%;
205
+ max-block-size: var(--person-image-max-height, 220px);
206
+ max-inline-size: var(--person-image-max-width, 220px);
207
+
208
+ img {
209
+ width: 100%;
210
+ height: 100%;
211
+ object-fit: cover;
212
+ object-position: center;
213
+ }
214
+ }
215
+ }
216
+
217
+ .card-summary {
218
+ align-self: center;
219
+
220
+ .description {
221
+ margin-bottom: $spacing-small;
222
+ }
223
+ }
192
224
  }
193
225
  }
194
226
 
@@ -201,3 +233,25 @@ body .block.gridBlock .block.teaser.contained.person-teaser .card-inner {
201
233
  .block-editor-search.summary .listing-item.person-listing img {
202
234
  aspect-ratio: initial !important;
203
235
  }
236
+
237
+ // Squared images
238
+ // Custom TTW CSS in case of squared images
239
+ // :root {--person-image-max-height: 285px;--person-image-aspect-ratio: 4 / 5;
240
+ // --person-image-border-radius: 0;}
241
+
242
+ // .contained.person-teaser .card {
243
+ // .image-wrapper img { object-position: top center !important; }
244
+ // }
245
+
246
+ body.person-squared-images,
247
+ .person-squared-images {
248
+ --person-image-max-height: 285px;
249
+ --person-image-aspect-ratio: 4 / 5;
250
+ --person-image-border-radius: 0;
251
+
252
+ .contained.person-teaser .card {
253
+ .image-wrapper img {
254
+ object-position: top center !important;
255
+ }
256
+ }
257
+ }