@kitconcept/volto-light-theme 7.0.0-alpha.10 → 7.0.0-alpha.12

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,13 @@
1
- ## 7.0.0-alpha.10 (2025-06-10)
1
+ ## 7.0.0-alpha.12 (2025-06-18)
2
+
3
+ ### Feature
4
+
5
+ - Reintroduce an improved `Anontools` using `portal_actions`. @sneridagh [#581](https://github.com/kitconcept/volto-light-theme/pull/581)
2
6
 
3
7
  ### Bugfix
4
8
 
5
- - Fixed Person Teaser top variant. Added Storybook. @sneridagh
9
+ - Fix sticky menu precedence in z-index with the fat menu. @sneridagh [#582](https://github.com/kitconcept/volto-light-theme/pull/582)
10
+ - Fixed listing in grids variations to match the standalone ones (except Grid). @sneridagh [#582](https://github.com/kitconcept/volto-light-theme/pull/582)
11
+ - Fixed Person CSS in Search block. @sneridagh [#584](https://github.com/kitconcept/volto-light-theme/pull/584)
6
12
 
7
13
 
package/CHANGELOG.md CHANGED
@@ -8,6 +8,32 @@
8
8
 
9
9
  <!-- towncrier release notes start -->
10
10
 
11
+ ## 7.0.0-alpha.12 (2025-06-18)
12
+
13
+ ### Feature
14
+
15
+ - Reintroduce an improved `Anontools` using `portal_actions`. @sneridagh [#581](https://github.com/kitconcept/volto-light-theme/pull/581)
16
+
17
+ ### Bugfix
18
+
19
+ - Fix sticky menu precedence in z-index with the fat menu. @sneridagh [#582](https://github.com/kitconcept/volto-light-theme/pull/582)
20
+ - Fixed listing in grids variations to match the standalone ones (except Grid). @sneridagh [#582](https://github.com/kitconcept/volto-light-theme/pull/582)
21
+ - Fixed Person CSS in Search block. @sneridagh [#584](https://github.com/kitconcept/volto-light-theme/pull/584)
22
+
23
+ ## 7.0.0-alpha.11 (2025-06-12)
24
+
25
+ ### Bugfix
26
+
27
+ - Do not show sticky menu in add view. @sneridagh
28
+ - Fix aspect ratio for images in file grid teaser block @iRohitSingh
29
+ - Fixed position of sticky menu for small screens. @sneridagh
30
+
31
+ ### Internal
32
+
33
+ - Added visual regression tests for Storybook stories. @sneridagh [#576](https://github.com/kitconcept/volto-light-theme/pull/576)
34
+ - Upgrade to Volto 18.23.0 @sneridagh
35
+ - Use `vitest` for unit tests. @sneridagh
36
+
11
37
  ## 7.0.0-alpha.10 (2025-06-10)
12
38
 
13
39
  ### Bugfix
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kitconcept/volto-light-theme",
3
- "version": "7.0.0-alpha.10",
3
+ "version": "7.0.0-alpha.12",
4
4
  "description": "Volto Light Theme by kitconcept",
5
5
  "main": "src/index.ts",
6
6
  "types": "src/index.ts",
@@ -32,11 +32,16 @@
32
32
  "devDependencies": {
33
33
  "@plone/scripts": "^3.6.2",
34
34
  "@storybook/react": "^8.6.12",
35
+ "@testing-library/cypress": "10.0.3",
36
+ "@testing-library/react": "^16.2.0",
35
37
  "@types/jest": "^29.5.8",
36
38
  "@types/lodash": "^4.14.201",
39
+ "@types/node": "^22",
37
40
  "@types/react": "^18.3.12",
38
41
  "@types/react-dom": "^18.3.1",
42
+ "typescript": "^5.7.3",
39
43
  "release-it": "^19.0.3",
44
+ "vitest": "^3.1.2",
40
45
  "@plone/types": "1.4.5"
41
46
  },
42
47
  "dependencies": {
@@ -0,0 +1,59 @@
1
+ // SemanticUI-free pre-@plone/components
2
+ import { Link } from 'react-router-dom';
3
+ import { FormattedMessage } from 'react-intl';
4
+ import { flattenToAppURL } from '@plone/volto/helpers/Url/Url';
5
+ import { useSelector, shallowEqual } from 'react-redux';
6
+ import type { ActionsResponse, Content } from '@plone/types';
7
+
8
+ type FormState = {
9
+ content: {
10
+ data: Content;
11
+ };
12
+ actions: {
13
+ actions: ActionsResponse;
14
+ };
15
+ };
16
+
17
+ const Anontools = () => {
18
+ const content = useSelector<FormState, Content>(
19
+ (state) => state.content.data,
20
+ shallowEqual,
21
+ );
22
+ const actions = useSelector<FormState, ActionsResponse>(
23
+ (state) => state.actions.actions,
24
+ shallowEqual,
25
+ );
26
+
27
+ const loginAction = actions.user?.find((o) => o.id === 'login');
28
+ const registerAction = actions.user?.find((o) => o.id === 'join');
29
+ const logoutAction = actions.user?.find((o) => o.id === 'logout');
30
+
31
+ return (
32
+ <>
33
+ {registerAction && (
34
+ <Link aria-label="register" to="/register">
35
+ <FormattedMessage id="Register" defaultMessage="Register" />
36
+ </Link>
37
+ )}
38
+ {loginAction && (
39
+ <Link
40
+ aria-label="login"
41
+ to={`/login${
42
+ content?.['@id']
43
+ ? `?return_url=${flattenToAppURL(content['@id'])}`
44
+ : ''
45
+ }`}
46
+ >
47
+ <FormattedMessage id="Log in" defaultMessage="Log in" />
48
+ </Link>
49
+ )}
50
+ {logoutAction && (
51
+ <Link aria-label="logout" to="/logout">
52
+ <FormattedMessage id="Log out" defaultMessage="Log out" />
53
+ </Link>
54
+ )}
55
+ </>
56
+ );
57
+ };
58
+
59
+ export default Anontools;
@@ -75,6 +75,8 @@ const InternetHeader = ({ pathname, content }) => {
75
75
  <LanguageSelector />
76
76
 
77
77
  <div className="tools">
78
+ <SlotRenderer name="headerTools" content={content} />
79
+
78
80
  {header_actions &&
79
81
  Array.isArray(header_actions) &&
80
82
  header_actions.map((item) => (
@@ -277,6 +277,11 @@ export default function install(config: ConfigType) {
277
277
  config.blocks.blocksConfig.gridBlock.blocksConfig.listing.allowed_headline_tags =
278
278
  [['h2', 'h2']];
279
279
 
280
+ config.blocks.blocksConfig.gridBlock.blocksConfig.listing.variations =
281
+ cloneDeep(
282
+ listingBlockVariations.filter((variation) => variation.id !== 'grid'),
283
+ );
284
+
280
285
  config.blocks.blocksConfig.introduction = {
281
286
  ...config.blocks.blocksConfig.introduction,
282
287
  unwantedButtons: ['heading-three', 'blockquote'],
@@ -5,6 +5,7 @@ import FollowUsLogoAndLinks from '../components/Footer/slots/FollowUsLogoAndLink
5
5
  import Colophon from '../components/Footer/slots/Colophon';
6
6
  import CoreFooter from '../components/Footer/slots/CoreFooter';
7
7
  import StickyMenu from '../components/StickyMenu/StickyMenu';
8
+ import Anontools from '../components/Anontools/Anontools';
8
9
  import type { Content } from '@plone/types';
9
10
 
10
11
  export function hasInheritedBehavior(behavior: string) {
@@ -25,6 +26,12 @@ export default function install(config: ConfigType) {
25
26
  component: StickyMenu,
26
27
  });
27
28
 
29
+ config.registerSlotComponent({
30
+ slot: 'headerTools',
31
+ name: 'Anontools',
32
+ component: Anontools,
33
+ });
34
+
28
35
  config.registerSlotComponent({
29
36
  name: 'footerLogos',
30
37
  slot: 'preFooter',
@@ -6,6 +6,7 @@ import {
6
6
  gridBlockThree,
7
7
  gridBlockFour,
8
8
  gridBlockTwoDocumentPerson,
9
+ gridBlockTwoPersonDifferentRatio,
9
10
  gridBlockOnePerson,
10
11
  gridBlockTwoPerson,
11
12
  gridBlockThreePerson,
@@ -31,7 +32,12 @@ type Story = StoryObj<typeof meta>;
31
32
  export const One: Story = {
32
33
  render: (args) => (
33
34
  <Wrapper>
34
- <div style={{ width: 'var(--default-container-width)' }}>
35
+ <div
36
+ style={{
37
+ containerType: 'inline-size',
38
+ width: 'var(--default-container-width)',
39
+ }}
40
+ >
35
41
  <BlockWrapper {...args}>
36
42
  <GridBlockView {...args} />
37
43
  </BlockWrapper>
@@ -46,7 +52,12 @@ export const One: Story = {
46
52
  export const Two: Story = {
47
53
  render: (args) => (
48
54
  <Wrapper>
49
- <div style={{ width: 'var(--default-container-width)' }}>
55
+ <div
56
+ style={{
57
+ containerType: 'inline-size',
58
+ width: 'var(--default-container-width)',
59
+ }}
60
+ >
50
61
  <BlockWrapper {...args}>
51
62
  <GridBlockView {...args} />
52
63
  </BlockWrapper>
@@ -61,7 +72,12 @@ export const Two: Story = {
61
72
  export const Three: Story = {
62
73
  render: (args) => (
63
74
  <Wrapper>
64
- <div style={{ width: 'var(--default-container-width)' }}>
75
+ <div
76
+ style={{
77
+ containerType: 'inline-size',
78
+ width: 'var(--default-container-width)',
79
+ }}
80
+ >
65
81
  <BlockWrapper {...args}>
66
82
  <GridBlockView {...args} />
67
83
  </BlockWrapper>
@@ -76,7 +92,12 @@ export const Three: Story = {
76
92
  export const Four: Story = {
77
93
  render: (args) => (
78
94
  <Wrapper>
79
- <div style={{ width: 'var(--default-container-width)' }}>
95
+ <div
96
+ style={{
97
+ containerType: 'inline-size',
98
+ width: 'var(--default-container-width)',
99
+ }}
100
+ >
80
101
  <BlockWrapper {...args}>
81
102
  <GridBlockView {...args} />
82
103
  </BlockWrapper>
@@ -94,7 +115,13 @@ export const OneInversed: Story = {
94
115
  },
95
116
  render: (args) => (
96
117
  <Wrapper>
97
- <div style={{ padding: '40px', backgroundColor: '#ecebeb' }}>
118
+ <div
119
+ style={{
120
+ containerType: 'inline-size',
121
+ padding: '40px',
122
+ backgroundColor: '#ecebeb',
123
+ }}
124
+ >
98
125
  <BlockWrapper {...args}>
99
126
  <GridBlockView {...args} />
100
127
  </BlockWrapper>
@@ -112,7 +139,13 @@ export const TwoInversed: Story = {
112
139
  },
113
140
  render: (args) => (
114
141
  <Wrapper>
115
- <div style={{ padding: '40px', backgroundColor: '#ecebeb' }}>
142
+ <div
143
+ style={{
144
+ containerType: 'inline-size',
145
+ padding: '40px',
146
+ backgroundColor: '#ecebeb',
147
+ }}
148
+ >
116
149
  <BlockWrapper {...args}>
117
150
  <GridBlockView {...args} />
118
151
  </BlockWrapper>
@@ -130,7 +163,13 @@ export const ThreeInversed: Story = {
130
163
  },
131
164
  render: (args) => (
132
165
  <Wrapper>
133
- <div style={{ padding: '40px', backgroundColor: '#ecebeb' }}>
166
+ <div
167
+ style={{
168
+ containerType: 'inline-size',
169
+ padding: '40px',
170
+ backgroundColor: '#ecebeb',
171
+ }}
172
+ >
134
173
  <BlockWrapper {...args}>
135
174
  <GridBlockView {...args} />
136
175
  </BlockWrapper>
@@ -148,7 +187,13 @@ export const FourInversed: Story = {
148
187
  },
149
188
  render: (args) => (
150
189
  <Wrapper>
151
- <div style={{ padding: '40px', backgroundColor: '#ecebeb' }}>
190
+ <div
191
+ style={{
192
+ containerType: 'inline-size',
193
+ padding: '40px',
194
+ backgroundColor: '#ecebeb',
195
+ }}
196
+ >
152
197
  <BlockWrapper {...args}>
153
198
  <GridBlockView {...args} />
154
199
  </BlockWrapper>
@@ -163,7 +208,12 @@ export const FourInversed: Story = {
163
208
  export const OnePerson: Story = {
164
209
  render: (args) => (
165
210
  <Wrapper>
166
- <div style={{ width: 'var(--default-container-width)' }}>
211
+ <div
212
+ style={{
213
+ containerType: 'inline-size',
214
+ width: 'var(--default-container-width)',
215
+ }}
216
+ >
167
217
  <BlockWrapper {...args}>
168
218
  <GridBlockView {...args} />
169
219
  </BlockWrapper>
@@ -175,10 +225,35 @@ export const OnePerson: Story = {
175
225
  },
176
226
  };
177
227
 
178
- export const TwoDocumentPerson: Story = {
228
+ export const TwoPerson: Story = {
229
+ render: (args) => (
230
+ <Wrapper>
231
+ <div
232
+ style={{
233
+ containerType: 'inline-size',
234
+ width: 'var(--default-container-width)',
235
+ }}
236
+ >
237
+ <BlockWrapper {...args}>
238
+ <GridBlockView {...args} />
239
+ </BlockWrapper>
240
+ </div>
241
+ </Wrapper>
242
+ ),
243
+ args: {
244
+ data: gridBlockTwoPerson,
245
+ },
246
+ };
247
+
248
+ export const TwoDocumentAndPerson: Story = {
179
249
  render: (args) => (
180
250
  <Wrapper>
181
- <div style={{ width: 'var(--default-container-width)' }}>
251
+ <div
252
+ style={{
253
+ containerType: 'inline-size',
254
+ width: 'var(--default-container-width)',
255
+ }}
256
+ >
182
257
  <BlockWrapper {...args}>
183
258
  <GridBlockView {...args} />
184
259
  </BlockWrapper>
@@ -190,10 +265,15 @@ export const TwoDocumentPerson: Story = {
190
265
  },
191
266
  };
192
267
 
193
- export const TwoPerson: Story = {
268
+ export const TwoPersonsDifferentImageRatio: Story = {
194
269
  render: (args) => (
195
270
  <Wrapper>
196
- <div style={{ width: 'var(--default-container-width)' }}>
271
+ <div
272
+ style={{
273
+ containerType: 'inline-size',
274
+ width: 'var(--default-container-width)',
275
+ }}
276
+ >
197
277
  <BlockWrapper {...args}>
198
278
  <GridBlockView {...args} />
199
279
  </BlockWrapper>
@@ -201,14 +281,19 @@ export const TwoPerson: Story = {
201
281
  </Wrapper>
202
282
  ),
203
283
  args: {
204
- data: gridBlockTwoPerson,
284
+ data: gridBlockTwoPersonDifferentRatio,
205
285
  },
206
286
  };
207
287
 
208
288
  export const ThreePerson: Story = {
209
289
  render: (args) => (
210
290
  <Wrapper>
211
- <div style={{ width: 'var(--default-container-width)' }}>
291
+ <div
292
+ style={{
293
+ containerType: 'inline-size',
294
+ width: 'var(--default-container-width)',
295
+ }}
296
+ >
212
297
  <BlockWrapper {...args}>
213
298
  <GridBlockView {...args} />
214
299
  </BlockWrapper>
@@ -223,7 +308,12 @@ export const ThreePerson: Story = {
223
308
  export const FourPerson: Story = {
224
309
  render: (args) => (
225
310
  <Wrapper>
226
- <div style={{ width: 'var(--default-container-width)' }}>
311
+ <div
312
+ style={{
313
+ containerType: 'inline-size',
314
+ width: 'var(--default-container-width)',
315
+ }}
316
+ >
227
317
  <BlockWrapper {...args}>
228
318
  <GridBlockView {...args} />
229
319
  </BlockWrapper>
@@ -19,35 +19,36 @@ const meta = {
19
19
  export default meta;
20
20
  type Story = StoryObj<typeof meta>;
21
21
 
22
- export const PersonListing: Story = {
22
+ export const Person: Story = {
23
23
  render: (args) => (
24
- <Wrapper>
25
- <div style={{ width: 'var(--default-container-width)' }}>
26
- <BlockWrapper {...args}>
27
- <div className="block listing">
28
- <ListingBody {...args} />
29
- </div>
30
- </BlockWrapper>
24
+ <BlockWrapper {...args}>
25
+ <div className="block listing">
26
+ <ListingBody {...args} />
31
27
  </div>
32
- </Wrapper>
28
+ </BlockWrapper>
33
29
  ),
34
30
  args: {
35
31
  data: listingBlockPerson,
36
32
  listingItems: listingBlockPerson.items,
37
33
  },
34
+ decorators: [
35
+ (Story) => (
36
+ <Wrapper>
37
+ <div style={{ width: 'var(--default-container-width)' }}>
38
+ <Story />
39
+ </div>
40
+ </Wrapper>
41
+ ),
42
+ ],
38
43
  };
39
44
 
40
- export const PersonListingSummary: Story = {
45
+ export const PersonSummary: Story = {
41
46
  render: (args) => (
42
- <Wrapper>
43
- <div style={{ width: 'var(--default-container-width)' }}>
44
- <BlockWrapper {...args}>
45
- <div className="block listing summary">
46
- <ListingBody {...args} />
47
- </div>
48
- </BlockWrapper>
47
+ <BlockWrapper {...args}>
48
+ <div className="block listing summary">
49
+ <ListingBody {...args} />
49
50
  </div>
50
- </Wrapper>
51
+ </BlockWrapper>
51
52
  ),
52
53
  args: {
53
54
  data: {
@@ -60,4 +61,13 @@ export const PersonListingSummary: Story = {
60
61
  title: 'List with images',
61
62
  },
62
63
  },
64
+ decorators: [
65
+ (Story) => (
66
+ <Wrapper>
67
+ <div style={{ width: 'var(--default-container-width)' }}>
68
+ <Story />
69
+ </div>
70
+ </Wrapper>
71
+ ),
72
+ ],
63
73
  };
@@ -1,3 +1,5 @@
1
+ import cloneDeep from 'lodash/cloneDeep';
2
+
1
3
  const demoImage = 'black-starry-night.jpg';
2
4
  const personImage = 'person.png';
3
5
 
@@ -262,6 +264,69 @@ export const personBlock = {
262
264
  title: 'Headline H2',
263
265
  };
264
266
 
267
+ const altPersonBlock = cloneDeep(personBlock);
268
+
269
+ altPersonBlock.href[0].image_scales.preview_image[0] = {
270
+ 'content-type': 'image/jpeg',
271
+ download: demoImage,
272
+ filename: 'black-starry-night.jpg',
273
+ height: 286,
274
+ scales: {
275
+ great: {
276
+ download: demoImage,
277
+ height: 854,
278
+ width: 1200,
279
+ },
280
+ huge: {
281
+ download: demoImage,
282
+ height: 1138,
283
+ width: 1600,
284
+ },
285
+ icon: {
286
+ download: demoImage,
287
+ height: 22,
288
+ width: 32,
289
+ },
290
+ large: {
291
+ download: demoImage,
292
+ height: 569,
293
+ width: 800,
294
+ },
295
+ larger: {
296
+ download: demoImage,
297
+ height: 711,
298
+ width: 1000,
299
+ },
300
+ mini: {
301
+ download: demoImage,
302
+ height: 142,
303
+ width: 200,
304
+ },
305
+ preview: {
306
+ download: demoImage,
307
+ height: 284,
308
+ width: 400,
309
+ },
310
+ teaser: {
311
+ download: demoImage,
312
+ height: 427,
313
+ width: 600,
314
+ },
315
+ thumb: {
316
+ download: demoImage,
317
+ height: 91,
318
+ width: 128,
319
+ },
320
+ tile: {
321
+ download: demoImage,
322
+ height: 45,
323
+ width: 64,
324
+ },
325
+ },
326
+ size: 693013,
327
+ width: 200,
328
+ };
329
+
265
330
  export const gridBlockOne = {
266
331
  '@type': 'gridBlock',
267
332
  blocks: {
@@ -644,6 +709,24 @@ export const gridBlockTwoPerson = {
644
709
  },
645
710
  };
646
711
 
712
+ export const gridBlockTwoPersonDifferentRatio = {
713
+ '@type': 'gridBlock',
714
+ blocks: {
715
+ '281a22fb-c353-4b91-b2bc-88e6a52ed65a': {
716
+ ...personBlock,
717
+ },
718
+ 'f34fa7dd-ce59-4f7f-b795-7d7f1e388df1': {
719
+ ...altPersonBlock,
720
+ },
721
+ },
722
+ blocks_layout: {
723
+ items: [
724
+ '281a22fb-c353-4b91-b2bc-88e6a52ed65a',
725
+ 'f34fa7dd-ce59-4f7f-b795-7d7f1e388df1',
726
+ ],
727
+ },
728
+ };
729
+
647
730
  export const gridBlockThreePerson = {
648
731
  '@type': 'gridBlock',
649
732
  blocks: {
@@ -53,7 +53,7 @@ export const Right: Story = {
53
53
  },
54
54
  };
55
55
 
56
- export const Center: Story = {
56
+ export const Top: Story = {
57
57
  render: (args) => (
58
58
  <Wrapper>
59
59
  <div style={{ width: 'var(--default-container-width)' }}>
@@ -73,7 +73,7 @@ export const Center: Story = {
73
73
  },
74
74
  };
75
75
 
76
- export const PersonTeaser: Story = {
76
+ export const PersonTeaserLeft: Story = {
77
77
  render: (args) => (
78
78
  <Wrapper>
79
79
  <div style={{ width: 'var(--default-container-width)' }}>
@@ -585,7 +585,7 @@ body.has-toolbar.has-sidebar {
585
585
 
586
586
  .submenu-wrapper {
587
587
  position: absolute;
588
- z-index: 11;
588
+ z-index: 12;
589
589
  right: 50%;
590
590
  left: 50%;
591
591
  width: 100vw;
@@ -47,6 +47,14 @@
47
47
  a {
48
48
  text-decoration: none;
49
49
  }
50
+ &.file-teaser .card .card-inner .image-wrapper {
51
+ img {
52
+ aspect-ratio: var(
53
+ --file-image-aspect-ratio,
54
+ $aspect-ratio-A4
55
+ ) !important;
56
+ }
57
+ }
50
58
 
51
59
  .teaser-item {
52
60
  height: 100%;
@@ -1,4 +1,5 @@
1
1
  .card {
2
+ // Person teaser
2
3
  .person-teaser.has--align--left:not(.contained) &,
3
4
  .has--align--left:not(.contained) .person-teaser &,
4
5
  .has--align--center:not(.contained) .person-teaser &,
@@ -7,9 +8,23 @@
7
8
  .person-teaser.has--align--right:not(.contained) & {
8
9
  .card-inner {
9
10
  .image-wrapper {
10
- flex: 0 1 var(--card-listing-image-size, 220px);
11
+ --person-image-max-width: 220px;
12
+ --person-image-max-height: 285px;
13
+ overflow: hidden;
14
+ aspect-ratio: 4 / 5;
15
+ block-size: auto; // derived from `aspect-ratio`
16
+
17
+ /* We allow the browser to adjust the real size within the maximums without
18
+ distorting the aspect ratio */
19
+ inline-size: 100%;
20
+ max-block-size: var(--person-image-max-height);
21
+ max-inline-size: var(--person-image-max-width);
22
+
11
23
  img {
12
- aspect-ratio: initial !important;
24
+ width: 100%;
25
+ height: 100%;
26
+ object-fit: cover;
27
+ object-position: top center;
13
28
  }
14
29
  }
15
30
  }
@@ -35,12 +50,9 @@
35
50
  .has--align--center:not(.contained) .person-teaser &,
36
51
  .person-teaser.has--align--center:not(.contained) & {
37
52
  width: calc(var(--default-container-width) / 2);
38
- margin-right: auto;
39
- margin-left: auto;
40
53
 
41
54
  .image-wrapper {
42
- display: flex;
43
- justify-content: center;
55
+ margin: 0 auto;
44
56
  }
45
57
  .card-summary {
46
58
  padding-right: 0px;
@@ -61,24 +73,40 @@
61
73
  // --person-image-border-radius: 10000px;
62
74
  // --person-image-aspect-ratio: 1/1;
63
75
  .image-wrapper {
64
- display: flex;
65
- height: var(--person-image-height, 255px);
66
- justify-content: center;
67
- // Removed since it was causing the cards to have more width than the available container
68
- // for +2 columns
69
- // aspect-ratio: var(--image-aspect-ratio, 1.7777777778);
76
+ --person-image-max-width: 220px;
77
+ --person-image-max-height: 285px;
78
+ overflow: hidden;
79
+ margin: 0 auto;
80
+ aspect-ratio: 4 / 5;
81
+ block-size: auto; // derived from `aspect-ratio`
82
+
83
+ /* We allow the browser to adjust the real size within the maximums without
84
+ distorting the aspect ratio */
85
+ inline-size: 100%;
86
+ max-block-size: var(--person-image-max-height);
87
+ max-inline-size: var(--person-image-max-width);
70
88
 
71
89
  img {
72
- max-width: 198px; // 255x198px Roughly 3:4 (enough to cover the 16:9 portrait height)
90
+ width: 100%;
73
91
  height: 100%;
74
- flex: 0 1 auto;
75
- border-radius: var(--person-image-border-radius, 0px);
76
- aspect-ratio: var(--person-image-aspect-ratio, initial) !important;
77
92
  object-fit: cover;
78
93
  object-position: top center;
79
94
  }
80
95
  }
81
96
  }
97
+
98
+ .two .contained.person-teaser & {
99
+ .image-wrapper {
100
+ --person-image-max-width: 175px;
101
+ }
102
+ }
103
+
104
+ .three .contained.person-teaser &,
105
+ .four .contained.person-teaser & {
106
+ .image-wrapper {
107
+ --person-image-max-width: 138px;
108
+ }
109
+ }
82
110
  }
83
111
 
84
112
  // One column exception for contained person-teasers
@@ -107,6 +135,7 @@
107
135
  }
108
136
 
109
137
  // contained person-teasers do not have background color, so we need to set it to --theme-color
138
+ body .block.gridBlock .block.teaser.contained.person-teaser,
110
139
  body .block.gridBlock .block.teaser.contained.person-teaser .card-inner {
111
140
  background: var(--theme-color);
112
141
  }
@@ -162,3 +191,13 @@ body .block.gridBlock .block.teaser.contained.person-teaser .card-inner {
162
191
  }
163
192
  }
164
193
  }
194
+
195
+ // Person in search block
196
+ .block.search.summary .listing-item.person-listing .listing-body {
197
+ align-self: center;
198
+ }
199
+
200
+ .block.search.summary .listing-item.person-listing img,
201
+ .block-editor-search.summary .listing-item.person-listing img {
202
+ aspect-ratio: initial !important;
203
+ }
@@ -1,8 +1,15 @@
1
1
  .sticky-menu {
2
2
  position: fixed;
3
- z-index: 1000;
4
- top: 373px;
3
+ z-index: 11;
4
+ top: 50vh;
5
5
  right: 0;
6
+ transform: translateY(-50%);
7
+ transition: all 0.2s linear;
8
+
9
+ @media (min-height: 920px) {
10
+ top: 373px;
11
+ transform: none;
12
+ }
6
13
 
7
14
  ul {
8
15
  display: flex;
@@ -45,6 +52,7 @@
45
52
  }
46
53
  }
47
54
 
55
+ body.view-addview .sticky-menu,
48
56
  body.view-editview .sticky-menu {
49
57
  display: none;
50
58
  }
@@ -0,0 +1,13 @@
1
+ import { defineConfig } from 'vitest/config';
2
+ import voltoVitestConfig from '@plone/volto/vitest.config.mjs';
3
+ import path from 'path';
4
+
5
+ export default defineConfig({
6
+ ...voltoVitestConfig,
7
+ resolve: {
8
+ alias: {
9
+ '@plone/volto': path.resolve(__dirname, '../../core/packages/volto/src'), // Add paths accordingly
10
+ // 'promise-file-reader': require.resolve('promise-file-reader') // Add to identify dependency from package
11
+ },
12
+ },
13
+ });
@@ -1,53 +0,0 @@
1
- // SemanticUI-free pre-@plone/components
2
- import PropTypes from 'prop-types';
3
- import { Link } from 'react-router-dom';
4
- import { FormattedMessage } from 'react-intl';
5
- import { flattenToAppURL } from '@plone/volto/helpers/Url/Url';
6
- import config from '@plone/volto/registry';
7
- import { useSelector, shallowEqual } from 'react-redux';
8
-
9
- const Anontools = () => {
10
- const token = useSelector((state) => state.userSession.token, shallowEqual);
11
- const content = useSelector((state) => state.content.data, shallowEqual);
12
-
13
- const { settings } = config;
14
-
15
- return (
16
- !token && (
17
- <div className="anontools">
18
- {settings.showSelfRegistration && (
19
- <Link aria-label="register" to="/register">
20
- <FormattedMessage id="Register" defaultMessage="Register" />
21
- </Link>
22
- )}
23
-
24
- <Link
25
- aria-label="login"
26
- to={`/login${
27
- content?.['@id']
28
- ? `?return_url=${flattenToAppURL(content['@id'])}`
29
- : ''
30
- }`}
31
- >
32
- <FormattedMessage id="Log in" defaultMessage="Log in" />
33
- </Link>
34
- </div>
35
- )
36
- );
37
- };
38
-
39
- export default Anontools;
40
-
41
- Anontools.propTypes = {
42
- token: PropTypes.string,
43
- content: PropTypes.shape({
44
- '@id': PropTypes.string,
45
- }),
46
- };
47
-
48
- Anontools.defaultProps = {
49
- token: null,
50
- content: {
51
- '@id': null,
52
- },
53
- };