@kitconcept/volto-light-theme 8.0.0-alpha.29 → 8.0.0-alpha.30

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,28 +1,14 @@
1
- ## 8.0.0-alpha.29 (2026-06-09)
2
-
3
- ### Breaking
4
-
5
- - Footer: Removed the "Follow us" literal above the social icons. @iRohitSingh [#838](https://github.com/kitconcept/volto-light-theme/pull/838)
1
+ ## 8.0.0-alpha.30 (2026-06-11)
6
2
 
7
3
  ### Feature
8
4
 
9
- - Provide proper image sizes to the `Image` component. @davisagli @sneridagh [#664](https://github.com/kitconcept/volto-light-theme/pull/664)
10
- - Translate the package to the languages provided by Polyglot project @erral
11
- - Unify css and alignment/width data handling for floating image, map and video blocks. @TimoBroeskamp @danalvrz
12
- - Update Highlight block version to 5.x. @danalvrz
13
- - Update de translation from Polyglot @erral
14
- - Update es translation from Polyglot @erral
15
- - Update eu translation from Polyglot @erral
5
+ - Add basic VLT styles for Form Block. @danalvrz
6
+ - Add link icon to Card component @Tishasoumya-02
16
7
 
17
8
  ### Bugfix
18
9
 
19
- - Fix Footer aligned with content @iRohitSingh [#838](https://github.com/kitconcept/volto-light-theme/pull/838)
20
- - Upgrade playwright and latest Volto 19.1.0 @sneridagh [#873](https://github.com/kitconcept/volto-light-theme/pull/873)
21
- - Fix last item of a listing with no pagination padding is broken @iRohitSingh [#874](https://github.com/kitconcept/volto-light-theme/pull/874)
22
- - Remove underline regression from Slider block Simple variation. @danalvrz
23
-
24
- ### Internal
25
-
26
- - Upgrade Volto 19 final. @sneridagh
10
+ - refactor closing logic for fatnav to ignore all clicks on scrollbar @jackahl [#834](https://github.com/kitconcept/volto-light-theme/pull/834)
11
+ - Fix icon in search @iRohitSingh [#879](https://github.com/kitconcept/volto-light-theme/pull/879)
12
+ - Fix top margin for floated images when following an H2. @danlavrz
27
13
 
28
14
 
package/CHANGELOG.md CHANGED
@@ -8,6 +8,19 @@
8
8
 
9
9
  <!-- towncrier release notes start -->
10
10
 
11
+ ## 8.0.0-alpha.30 (2026-06-11)
12
+
13
+ ### Feature
14
+
15
+ - Add basic VLT styles for Form Block. @danalvrz
16
+ - Add link icon to Card component @Tishasoumya-02
17
+
18
+ ### Bugfix
19
+
20
+ - refactor closing logic for fatnav to ignore all clicks on scrollbar @jackahl [#834](https://github.com/kitconcept/volto-light-theme/pull/834)
21
+ - Fix icon in search @iRohitSingh [#879](https://github.com/kitconcept/volto-light-theme/pull/879)
22
+ - Fix top margin for floated images when following an H2. @danlavrz
23
+
11
24
  ## 8.0.0-alpha.29 (2026-06-09)
12
25
 
13
26
  ### Breaking
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kitconcept/volto-light-theme",
3
- "version": "8.0.0-alpha.29",
3
+ "version": "8.0.0-alpha.30",
4
4
  "description": "Volto Light Theme by kitconcept",
5
5
  "main": "src/index.ts",
6
6
  "types": "src/index.ts",
@@ -1,4 +1,4 @@
1
- import React, { useState, useEffect, useRef } from 'react';
1
+ import React, { useState, useEffect, useRef, useCallback } from 'react';
2
2
  import isEmpty from 'lodash/isEmpty';
3
3
  import { useDispatch, useSelector, shallowEqual } from 'react-redux';
4
4
  import { NavLink } from 'react-router-dom';
@@ -98,40 +98,30 @@ const Navigation = ({ pathname }: NavigationProps) => {
98
98
  shallowEqual,
99
99
  );
100
100
 
101
- const closeMenu = () => {
101
+ const closeMenu = useCallback(() => {
102
102
  setDesktopMenuOpen(null);
103
103
  setCurrentOpenIndex(null);
104
- };
105
-
106
- // this function doesn't close the navigation when clicking the scrollbar
107
- const doesScrollbarContainClick = (event: MouseEvent): boolean => {
108
- const clickedVerticalScrollbar =
109
- event.clientX >= document.documentElement.clientWidth &&
110
- event.clientX <= window.innerWidth;
111
-
112
- const clickedHorizontalScrollbar =
113
- event.clientY >= document.documentElement.clientHeight &&
114
- event.clientY <= window.innerHeight;
104
+ }, [setDesktopMenuOpen, setCurrentOpenIndex]);
115
105
 
116
- return clickedVerticalScrollbar || clickedHorizontalScrollbar;
117
- };
118
-
119
- useEffect(() => {
120
- const handleClickOutside = (event: MouseEvent) => {
121
- if (navigation.current && doesNodeContainClick(navigation.current, event))
106
+ const handleClickOutside = useCallback(
107
+ (e: MouseEvent) => {
108
+ const target = e.target;
109
+ if (
110
+ (navigation.current && doesNodeContainClick(navigation.current, e)) ||
111
+ (target instanceof Element && target.parentElement === null)
112
+ )
122
113
  return;
123
- // check if scrollbar is clicked
124
- if (doesScrollbarContainClick(event)) return;
125
-
126
114
  closeMenu();
127
- };
115
+ },
116
+ [closeMenu],
117
+ );
128
118
 
119
+ useEffect(() => {
129
120
  document.addEventListener('mousedown', handleClickOutside, false);
130
-
131
121
  return () => {
132
122
  document.removeEventListener('mousedown', handleClickOutside, false);
133
123
  };
134
- }, []);
124
+ }, [handleClickOutside]);
135
125
 
136
126
  useEffect(() => {
137
127
  if (!hasApiExpander('navigation', getBaseUrl(pathname))) {
@@ -164,6 +154,7 @@ const Navigation = ({ pathname }: NavigationProps) => {
164
154
  return () => {
165
155
  window.removeEventListener('keydown', handleEsc);
166
156
  };
157
+ // eslint-disable-next-line react-hooks/exhaustive-deps
167
158
  }, []);
168
159
 
169
160
  return (
@@ -0,0 +1,52 @@
1
+ import { useSelector } from 'react-redux';
2
+ import { useLocation, useHistory } from 'react-router-dom';
3
+ import type { ObjectBrowserItem, GetSiteResponse } from '@plone/types';
4
+ import linkSVG from '@plone/volto/icons/link.svg';
5
+ import Icon from '@plone/volto/components/theme/Icon/Icon';
6
+ import { Button } from '@plone/components';
7
+ import { flattenToAppURL } from '@plone/volto/helpers/Url/Url';
8
+
9
+ type FormState = {
10
+ site: { data: GetSiteResponse };
11
+ };
12
+
13
+ const useLinkIconNavigation = (item?: Partial<ObjectBrowserItem>) => {
14
+ const location = useLocation();
15
+ const history = useHistory();
16
+
17
+ const handleLinkIconClick = (e: React.MouseEvent<HTMLButtonElement>) => {
18
+ e.preventDefault();
19
+ e.stopPropagation();
20
+
21
+ const targetUrl = item?.['@id'];
22
+ if (targetUrl) {
23
+ const flattenedTargetUrl = flattenToAppURL(targetUrl);
24
+ const searchParams = new URLSearchParams();
25
+ searchParams.set('return_to', location.pathname);
26
+
27
+ history.push({
28
+ pathname: flattenedTargetUrl,
29
+ search: searchParams.toString(),
30
+ });
31
+ }
32
+ };
33
+ return handleLinkIconClick;
34
+ };
35
+ const LinkIconButton = ({ item }: { item?: Partial<ObjectBrowserItem> }) => {
36
+ const site = useSelector<FormState, GetSiteResponse>(
37
+ (state) => state.site?.data,
38
+ );
39
+ const hideProfileLinks = site?.['kitconcept.disable_profile_links'];
40
+ const handleLinkIconClick = useLinkIconNavigation(item);
41
+ return (
42
+ hideProfileLinks && (
43
+ <div className="card-link-icon">
44
+ <Button aria-label="link" onClick={handleLinkIconClick}>
45
+ <Icon name={linkSVG} size="33px" />
46
+ </Button>
47
+ </div>
48
+ )
49
+ );
50
+ };
51
+
52
+ export default LinkIconButton;
@@ -450,6 +450,10 @@
450
450
  border-color: var(--theme-foreground-color);
451
451
  background-color: var(--theme-foreground-color);
452
452
  color: var(--theme-color);
453
+
454
+ &::after {
455
+ background-color: var(--theme-color);
456
+ }
453
457
  }
454
458
  }
455
459
  }
@@ -74,6 +74,7 @@
74
74
  }
75
75
  }
76
76
  svg {
77
+ display: inline;
77
78
  margin-right: 5px;
78
79
  vertical-align: bottom;
79
80
  }
@@ -0,0 +1,350 @@
1
+ %form-outlined-button {
2
+ display: inline-flex;
3
+ align-items: center;
4
+ padding: 8px 20px;
5
+ border: 1px solid var(--theme-foreground-color);
6
+ border-radius: 0;
7
+ margin: 0;
8
+ background-color: var(--theme-color);
9
+ color: var(--theme-foreground-color);
10
+
11
+ @include body-text-bold();
12
+
13
+ &:hover,
14
+ &:active,
15
+ &:focus {
16
+ border-color: var(--theme-foreground-color);
17
+ background-color: var(--theme-foreground-color);
18
+ color: var(--theme-color);
19
+ }
20
+ }
21
+
22
+ .block.schemaForm {
23
+ --form-error-foreground: #cc0000;
24
+ --form-error-background: #f2cecd;
25
+
26
+ & > h2,
27
+ & > p,
28
+ & > .formDescription,
29
+ & > .container {
30
+ @include default-container-width();
31
+ @include adjustMarginsToContainer($default-container-width);
32
+ }
33
+
34
+ h2 {
35
+ @include block-title();
36
+
37
+ margin-bottom: $spacing-small;
38
+ }
39
+
40
+ .formDescription {
41
+ margin-bottom: $spacing-medium;
42
+ }
43
+
44
+ form.ui.form {
45
+ fieldset {
46
+ padding: 0;
47
+ border: 0;
48
+ margin: 0;
49
+ }
50
+
51
+ .ui.segments,
52
+ .ui.raised.segments,
53
+ .ui.segment {
54
+ padding: 0;
55
+ border: 0;
56
+ border-radius: 0;
57
+ margin: 0;
58
+ background: none;
59
+ box-shadow: none;
60
+
61
+ &::before,
62
+ &::after {
63
+ display: none;
64
+ }
65
+ }
66
+
67
+ .field {
68
+ padding-bottom: 0 !important;
69
+ margin-bottom: $spacing-small;
70
+
71
+ .ui.grid {
72
+ display: block;
73
+ margin: 0;
74
+
75
+ > .row {
76
+ display: block;
77
+ padding: 0;
78
+ }
79
+
80
+ > .row > .column {
81
+ width: 100% !important;
82
+ padding: 0;
83
+ }
84
+ }
85
+
86
+ .wrapper > label {
87
+ display: block;
88
+ margin-bottom: 0;
89
+
90
+ @include add(size, xs);
91
+ @include add(height, s);
92
+ @include add(weight, bold);
93
+
94
+ color: var(--theme-low-contrast-foreground-color);
95
+ opacity: 0.9;
96
+ }
97
+
98
+ &:focus-within .wrapper > label {
99
+ color: var(--theme-foreground-color);
100
+ opacity: 1;
101
+ }
102
+
103
+ &.required .wrapper > label::after {
104
+ margin-left: 2px;
105
+ background: none;
106
+ content: '*';
107
+ }
108
+
109
+ &.required .wrapper .ui.checkbox::after {
110
+ margin-left: 2px;
111
+ background: none;
112
+ content: '*';
113
+ }
114
+
115
+ .help {
116
+ border-bottom: none;
117
+ margin: 0;
118
+
119
+ color: var(--theme-low-contrast-foreground-color);
120
+
121
+ @include add(size, xs);
122
+ @include add(height, m);
123
+ }
124
+
125
+ &.error {
126
+ .wrapper > label,
127
+ .help {
128
+ color: var(--form-error-foreground);
129
+ }
130
+
131
+ .ui.input > input,
132
+ input[type='text'],
133
+ input[type='email'],
134
+ input[type='number'],
135
+ input[type='password'],
136
+ textarea,
137
+ .react-select__control,
138
+ .DateInput_input,
139
+ .rc-time-picker-input {
140
+ background: var(--form-error-background);
141
+ color: var(--form-error-foreground);
142
+
143
+ &::placeholder {
144
+ color: var(--form-error-foreground);
145
+ }
146
+ }
147
+ }
148
+
149
+ &.textarea .wrapper {
150
+ margin-top: 0;
151
+ }
152
+ }
153
+
154
+ .ui.input {
155
+ width: 100%;
156
+ }
157
+
158
+ .ui.input > input,
159
+ input[type='text'],
160
+ input[type='email'],
161
+ input[type='number'],
162
+ input[type='password'],
163
+ textarea,
164
+ .react-select__control,
165
+ .DateInput_input,
166
+ .rc-time-picker-input {
167
+ width: 100%;
168
+ padding: $spacing-small;
169
+ border: 0;
170
+ border-radius: 0;
171
+ background: var(--theme-high-contrast-color);
172
+ box-shadow: none;
173
+ color: var(--theme-foreground-color);
174
+
175
+ @include body-text();
176
+
177
+ &::placeholder {
178
+ color: var(--theme-low-contrast-foreground-color);
179
+ opacity: 0.6;
180
+ }
181
+
182
+ &:focus,
183
+ &:focus-visible {
184
+ outline: 2px solid var(--theme-foreground-color);
185
+ outline-offset: -2px;
186
+ }
187
+ }
188
+
189
+ textarea {
190
+ min-height: 180px;
191
+ margin-top: 5px;
192
+ resize: vertical;
193
+ }
194
+
195
+ .react-select__control {
196
+ display: flex;
197
+ min-height: auto;
198
+ padding: $spacing-small;
199
+
200
+ .react-select__value-container {
201
+ padding: 0;
202
+ }
203
+
204
+ .react-select__single-value {
205
+ color: var(--theme-foreground-color);
206
+ }
207
+
208
+ .react-select__placeholder {
209
+ color: var(--theme-low-contrast-foreground-color);
210
+ opacity: 0.6;
211
+ }
212
+
213
+ .react-select__indicator-separator {
214
+ display: none;
215
+ }
216
+
217
+ .react-select__indicator svg path {
218
+ fill: var(--theme-foreground-color);
219
+ }
220
+ }
221
+
222
+ .react-select__menu {
223
+ border-radius: 0;
224
+ margin: 0;
225
+ background: var(--theme-high-contrast-color);
226
+ box-shadow: 0 5px 20px 0 rgba(0, 0, 0, 0.25);
227
+ }
228
+
229
+ .react-select__menu-list {
230
+ padding: 0;
231
+ }
232
+
233
+ .react-select__option {
234
+ padding: 12px $spacing-small;
235
+ background: transparent;
236
+ color: var(--theme-foreground-color);
237
+ cursor: pointer;
238
+
239
+ @include body-text();
240
+
241
+ &.react-select__option--is-focused,
242
+ &.react-select__option--is-selected {
243
+ background: var(--theme-foreground-color);
244
+ color: var(--theme-high-contrast-color);
245
+ }
246
+ }
247
+
248
+ .date-time-widget-wrapper {
249
+ display: flex;
250
+ flex-wrap: wrap;
251
+ align-items: center;
252
+ gap: $spacing-small;
253
+
254
+ .DateInput {
255
+ width: 140px;
256
+ }
257
+ .time-input input {
258
+ width: 90px !important;
259
+ }
260
+ }
261
+
262
+ .file-widget-dropzone {
263
+ display: flex;
264
+ flex-direction: column;
265
+ align-items: flex-start;
266
+ margin-bottom: $spacing-small;
267
+ cursor: pointer;
268
+ gap: $spacing-small;
269
+
270
+ .dropzone-placeholder {
271
+ width: 100%;
272
+ padding: $spacing-medium;
273
+ margin-top: 0;
274
+ background: var(--theme-high-contrast-color);
275
+ }
276
+
277
+ .dropzone-text {
278
+ margin: 0;
279
+
280
+ @include body-text();
281
+
282
+ color: var(--theme-low-contrast-foreground-color);
283
+ }
284
+
285
+ .label-file-widget-input {
286
+ @extend %form-outlined-button;
287
+ }
288
+ }
289
+
290
+ .field.help .file-widget-dropzone {
291
+ margin-bottom: 0;
292
+ }
293
+
294
+ .ui.segment.actions {
295
+ display: flex;
296
+ padding: 0;
297
+ margin-top: $spacing-xlarge;
298
+ gap: $spacing-small;
299
+
300
+ &::after {
301
+ display: none;
302
+ }
303
+
304
+ button {
305
+ @extend %form-outlined-button;
306
+
307
+ float: none !important;
308
+
309
+ &:not(.primary) {
310
+ border-color: var(--theme-low-contrast-foreground-color);
311
+ color: var(--theme-low-contrast-foreground-color);
312
+
313
+ &:hover,
314
+ &:active,
315
+ &:focus {
316
+ border-color: var(--theme-low-contrast-foreground-color);
317
+ background-color: var(--theme-low-contrast-foreground-color);
318
+ color: var(--theme-color);
319
+ }
320
+ }
321
+ }
322
+ }
323
+ }
324
+
325
+ .inline.field .wrapper {
326
+ min-height: auto;
327
+ border-bottom: none;
328
+ }
329
+
330
+ .field-file-name:empty {
331
+ display: none;
332
+ }
333
+
334
+ .negative.attached.message {
335
+ flex-direction: row;
336
+ }
337
+ }
338
+
339
+ #page-edit,
340
+ #page-add {
341
+ .block.schemaForm {
342
+ .field {
343
+ .toolbar {
344
+ display: flex;
345
+ align-items: flex-start;
346
+ margin-top: 15px;
347
+ }
348
+ }
349
+ }
350
+ }
@@ -32,6 +32,11 @@ figure {
32
32
  &.has--block-alignment--left,
33
33
  &.has--block-alignment--right {
34
34
  margin-bottom: 0 !important;
35
+
36
+ &:has(+ h2) {
37
+ margin-top: $spacing-xlarge;
38
+ }
39
+
35
40
  figure {
36
41
  margin-top: 0 !important;
37
42
  margin-bottom: $spacing-small;
@@ -79,6 +79,30 @@
79
79
  }
80
80
  }
81
81
  }
82
+
83
+ // Common styles for link icon overlay
84
+ .card-link-icon {
85
+ position: absolute;
86
+ z-index: 10;
87
+ top: 0px;
88
+ right: 0px;
89
+ filter: drop-shadow(3px 3px 12px rgba(0, 0, 0, 0.5));
90
+ opacity: 0;
91
+ transition: opacity 0.2s ease;
92
+
93
+ button {
94
+ border: none;
95
+ border-radius: 50%;
96
+ background: rgba(236, 235, 235, 0.75);
97
+ cursor: pointer;
98
+ }
99
+ }
100
+
101
+ &:hover .card-link-icon,
102
+ &:focus-within .card-link-icon {
103
+ opacity: 1;
104
+ }
105
+
82
106
  // Additional links within the card
83
107
  a:not(.card-primary-link) {
84
108
  position: relative;
@@ -165,6 +189,12 @@
165
189
  }
166
190
  }
167
191
 
192
+ // Hides the link icon in edit and add page
193
+ #page-edit .card-link-icon,
194
+ #page-add .card-link-icon {
195
+ display: none;
196
+ }
197
+
168
198
  // Cards in columns
169
199
  @container (min-width: #{$largest-mobile-screen}) {
170
200
  .card {
@@ -36,6 +36,7 @@
36
36
  @import 'blocks/eventMetadata';
37
37
  @import 'blocks/rss';
38
38
  @import 'blocks/eventSearch';
39
+ @import 'blocks/form';
39
40
  @import 'blocks/error-boundary';
40
41
  @import 'sticky-menu';
41
42
  @import 'mobile-sticky-menu';