@kitconcept/volto-light-theme 7.0.0-alpha.21 → 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,7 +1,16 @@
1
- ## 7.0.0-alpha.21 (2025-07-31)
1
+ ## 7.0.0-alpha.23 (2025-08-25)
2
2
 
3
- ### Internal
3
+ ### Breaking
4
4
 
5
- - Revert the new slider variation. @iFlameing [#623](https://github.com/kitconcept/volto-light-theme/pull/623)
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
7
+
8
+ ### Feature
9
+
10
+ - Added Simple Side Slider Variation @Tishasoumya-02 [#sliderVariation](https://github.com/kitconcept/volto-light-theme/pull/sliderVariation)
11
+
12
+ ### Bugfix
13
+
14
+ - Fix navigation menu misalignment in Intranet mobile view @iRohitSingh [#627](https://github.com/kitconcept/volto-light-theme/pull/627)
6
15
 
7
16
 
package/CHANGELOG.md CHANGED
@@ -8,6 +8,31 @@
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
+
26
+ ## 7.0.0-alpha.22 (2025-08-15)
27
+
28
+ ### Feature
29
+
30
+ - Add styles for RSS block (note: full functionality requires RSS addon and templates available in kitconcept.intranet). @danalvrz
31
+
32
+ ### Internal
33
+
34
+ - Fix Logos SVG size issue. @Tishasoumya-02
35
+
11
36
  ## 7.0.0-alpha.21 (2025-07-31)
12
37
 
13
38
  ### Internal
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kitconcept/volto-light-theme",
3
- "version": "7.0.0-alpha.21",
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);
@@ -56,11 +56,16 @@ const LogosContainer = (props: LogosContainerProps) => {
56
56
  {/* @ts-ignore */}
57
57
  <ConditionalLink
58
58
  condition={logoInfo.href}
59
+ className="logo-link"
59
60
  to={logoInfo.href}
60
61
  title={logoInfo.hrefTitle || logoInfo.srcAlt}
61
62
  openLinkInNewTab={logo.openInNewTab}
62
63
  >
63
- <img src={logoInfo.src} alt={logoInfo.srcAlt} />
64
+ <img
65
+ className="logo-image"
66
+ src={logoInfo.src}
67
+ alt={logoInfo.srcAlt}
68
+ />
64
69
  </ConditionalLink>
65
70
  </li>
66
71
  );
@@ -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
+ };
@@ -490,7 +490,8 @@
490
490
 
491
491
  // Listing
492
492
  &.listing,
493
- &.search {
493
+ &.search,
494
+ &.rssBlock {
494
495
  h2.headline {
495
496
  color: var(--theme-foreground-color);
496
497
  }
@@ -530,7 +531,8 @@
530
531
  /* I have removed the .card-container className that's why I have to write this css
531
532
  * I will remove all the .card-container className from repo.
532
533
  */
533
- &.grid .card {
534
+ &.grid .card,
535
+ & .grid-variation .card {
534
536
  background-color: var(--theme-high-contrast-color);
535
537
 
536
538
  .content,
@@ -355,17 +355,39 @@ ul.logos-container {
355
355
  grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
356
356
  list-style: none;
357
357
 
358
+ .logo-image {
359
+ display: block;
360
+ width: 100%;
361
+ height: auto;
362
+ object-fit: contain !important;
363
+ //using !important because in layout.scss it targets img , so to override it for logo-image, class specificity did'nt work
364
+ }
365
+
366
+ .logo-link {
367
+ display: block;
368
+ width: 100%;
369
+ height: 100%;
370
+ }
371
+
358
372
  &.s {
359
- grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
373
+ .logo-link,
374
+ .logo-image {
375
+ max-width: min(100%, 175px);
376
+ max-height: 120px;
377
+ }
360
378
  }
361
379
 
362
- &.l img {
363
- max-width: min(100%, 240px);
364
- max-height: 165px;
380
+ &.l {
381
+ .logo-link,
382
+ .logo-image {
383
+ max-width: min(100%, 240px);
384
+ max-height: 165px;
385
+ }
365
386
  }
366
387
 
367
- &.s img {
368
- max-width: min(100%, 175px);
369
- max-height: 120px;
388
+ .item {
389
+ display: flex;
390
+ align-items: center;
391
+ justify-content: center;
370
392
  }
371
393
  }
@@ -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 {
@@ -239,6 +239,7 @@ External link removal for all the blocks.
239
239
  & > .block.listing .image-gallery,
240
240
  & > .block.listing.grid,
241
241
  & > .block.search.grid,
242
+ & > .block.rssBlock,
242
243
  & > .block.search .searchBlock-container,
243
244
  &> .block.eventsearch .search-block-event,
244
245
  & > .block h2.headline,
@@ -361,6 +362,7 @@ External link removal for all the blocks.
361
362
  .block.heading .heading-wrapper,
362
363
  .block-editor-listing .items,
363
364
  .block-editor-listing .listing.message,
365
+ .block-editor-rssBlock .items,
364
366
  .block-editor-search .searchBlock-container,
365
367
  .block-editor-eventsearch .search-block-event,
366
368
  .block.teaser.has--align--center,
@@ -12,7 +12,9 @@
12
12
  .block.listing,
13
13
  .column > .block.listing,
14
14
  .block.search,
15
- .block-editor-search {
15
+ .block-editor-search,
16
+ .block.rssBlock,
17
+ .block-editor-rssBlock {
16
18
  &.next--has--same--backgroundColor.next--is--same--block-type,
17
19
  &.next--is--__button {
18
20
  .listing-item:last-child {
@@ -58,7 +60,8 @@
58
60
  }
59
61
 
60
62
  // Default variation
61
- &.default {
63
+ &.default,
64
+ & .default-variation {
62
65
  .headline {
63
66
  @include block-title();
64
67
  }
@@ -90,7 +93,8 @@
90
93
  }
91
94
 
92
95
  // Summary variation
93
- &.summary {
96
+ &.summary,
97
+ & .summary-variation {
94
98
  .listing-item {
95
99
  padding-top: 0 !important;
96
100
 
@@ -134,7 +138,8 @@
134
138
  }
135
139
 
136
140
  // Grid variation
137
- &.grid {
141
+ &.grid,
142
+ & .grid-variation {
138
143
  &.next--has--same--backgroundColor.next--is--same--block-type,
139
144
  &.next--is--__button {
140
145
  .listing-item:last-child {
@@ -427,8 +432,11 @@
427
432
  }
428
433
 
429
434
  #page-add .block-editor-listing,
430
- #page-edit .block-editor-listing {
431
- .block.listing {
435
+ #page-edit .block-editor-listing,
436
+ #page-add .block-editor-rssBlock,
437
+ #page-edit .block-editor-rssBlock {
438
+ .block.listing,
439
+ .block.rssBlock {
432
440
  margin-top: 0;
433
441
  .items {
434
442
  margin-right: auto;
@@ -0,0 +1,17 @@
1
+ .block.rssBlock {
2
+ .card {
3
+ width: 100%;
4
+ a.external::after {
5
+ position: absolute !important;
6
+ top: $spacing-small;
7
+ right: 0;
8
+ }
9
+ }
10
+ .grid-variation {
11
+ .card a.external::after {
12
+ top: unset;
13
+ right: 1rem;
14
+ bottom: 1rem;
15
+ }
16
+ }
17
+ }
@@ -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
  }
@@ -34,6 +34,7 @@
34
34
  @import 'blocks/maps';
35
35
  @import 'blocks-chooser';
36
36
  @import 'blocks/eventMetadata';
37
+ @import 'blocks/rss';
37
38
  @import 'blocks/eventSearch';
38
39
  @import 'sticky-menu';
39
40
  @import 'card';
@@ -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
+ }