design-comuni-plone-theme 11.25.4 → 11.26.1

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.
Files changed (47) hide show
  1. package/.github/workflows/npm.yml +1 -1
  2. package/.yarn/cache/cross-spawn-npm-7.0.6-264bddf921-8d306efaca.zip +0 -0
  3. package/.yarn/cache/nanoid-npm-3.3.8-d22226208b-dfe0adbc0c.zip +0 -0
  4. package/.yarn/cache/{volto-blocks-widget-npm-3.4.1-c4d451e2c2-4f5c183698.zip → volto-blocks-widget-npm-3.4.3-d7e305af36-68490569a4.zip} +0 -0
  5. package/.yarn/cache/{volto-feedback-npm-0.3.2-ff5b075c7c-bfc7951ca5.zip → volto-feedback-npm-0.5.2-c3471099a1-48c0763678.zip} +0 -0
  6. package/.yarn/cache/volto-gdpr-privacy-npm-2.2.12-fbc24c3b6f-ba1b9c0127.zip +0 -0
  7. package/.yarn/install-state.gz +0 -0
  8. package/CHANGELOG.md +50 -0
  9. package/RELEASE.md +25 -0
  10. package/locales/de/LC_MESSAGES/volto.po +5 -0
  11. package/locales/en/LC_MESSAGES/volto.po +5 -0
  12. package/locales/es/LC_MESSAGES/volto.po +5 -0
  13. package/locales/fr/LC_MESSAGES/volto.po +5 -0
  14. package/locales/it/LC_MESSAGES/volto.po +5 -0
  15. package/locales/volto.pot +6 -1
  16. package/package.json +4 -4
  17. package/publiccode.yml +2 -2
  18. package/src/components/ItaliaTheme/Blocks/Calendar/Body.jsx +1 -0
  19. package/src/components/ItaliaTheme/Blocks/Common/SearchFilters/SelectFilter.jsx +9 -3
  20. package/src/components/ItaliaTheme/Blocks/EventSearch/DefaultFilters.js +1 -0
  21. package/src/components/ItaliaTheme/Cards/CardCategory.jsx +2 -3
  22. package/src/components/ItaliaTheme/View/Commons/Dates.jsx +16 -16
  23. package/src/components/ItaliaTheme/View/Commons/PageHeader/PageHeaderEventDates.jsx +30 -8
  24. package/src/customizations/volto/actions/vocabularies/vocabularies.js +6 -2
  25. package/src/customizations/volto/components/manage/Blocks/Search/SearchBlockView.jsx +9 -15
  26. package/src/customizations/volto/components/manage/Blocks/Search/schema.js +16 -0
  27. package/src/customizations/volto/components/manage/Widgets/RecurrenceWidget/RecurrenceWidget.jsx +4 -7
  28. package/src/customizations/volto-form-block/components/View.jsx +11 -10
  29. package/src/helpers/dates.js +21 -1
  30. package/src/helpers/files.js +10 -3
  31. package/src/helpers/files.test.js +90 -0
  32. package/src/helpers/index.js +1 -0
  33. package/src/theme/ItaliaTheme/Blocks/_contacts.scss +5 -12
  34. package/src/theme/ItaliaTheme/Print/_all_pages.scss +98 -15
  35. package/src/theme/ItaliaTheme/Print/_blocks.scss +903 -8
  36. package/src/theme/ItaliaTheme/Print/_page.scss +0 -6
  37. package/src/theme/ItaliaTheme/_main.scss +3 -0
  38. package/src/theme/_cms-ui.scss +58 -0
  39. package/src/theme/bootstrap-override/bootstrap/_print.scss +1 -0
  40. package/src/theme/bootstrap-override/bootstrap-italia/_card.scss +12 -2
  41. package/src/theme/extras/_tables.scss +12 -13
  42. package/src/theme/site.scss +0 -2
  43. package/.yarn/cache/cross-spawn-npm-7.0.3-e4ff3e65b3-671cc7c728.zip +0 -0
  44. package/.yarn/cache/nanoid-npm-3.3.6-e6d6ae7e71-7d0eda6570.zip +0 -0
  45. package/.yarn/cache/volto-gdpr-privacy-npm-2.2.9-a1e4258e06-fe530fe8ee.zip +0 -0
  46. package/src/theme/ItaliaTheme/Print/_bandi.scss +0 -9
  47. package/src/theme/ItaliaTheme/Print/_news_items.scss +0 -19
@@ -1,5 +1,6 @@
1
1
  // CUSTOMIZATION:
2
2
  // - added warning state to form
3
+ // - backport for https://github.com/collective/volto-form-block/pull/122
3
4
 
4
5
  import React, { useState, useEffect, useReducer, useRef } from 'react';
5
6
  import { useSelector, useDispatch } from 'react-redux';
@@ -8,7 +9,6 @@ import { useIntl, defineMessages } from 'react-intl';
8
9
  import { submitForm, resetOTP } from 'volto-form-block/actions';
9
10
  import { getFieldName } from 'volto-form-block/components/utils';
10
11
  import FormView from 'volto-form-block/components/FormView';
11
- import { formatDate } from '@plone/volto/helpers/Utils/Date';
12
12
  import config from '@plone/volto/registry';
13
13
  import { Captcha } from 'volto-form-block/components/Widget';
14
14
  import { isValidEmail } from 'volto-form-block/helpers/validators';
@@ -260,20 +260,21 @@ const View = ({ data, id, path }) => {
260
260
  config.blocks.blocksConfig.form.attachment_fields.includes(
261
261
  subblock.field_type,
262
262
  );
263
- const isDate = subblock.field_type === 'date';
263
+ // const isDate = subblock.field_type === 'date';
264
264
 
265
265
  if (isAttachment) {
266
266
  attachments[name] = formattedFormData[name].value;
267
267
  delete formattedFormData[name];
268
268
  }
269
269
 
270
- if (isDate) {
271
- formattedFormData[name].value = formatDate({
272
- date: formattedFormData[name].value,
273
- format: 'DD-MM-YYYY',
274
- locale: intl.locale,
275
- });
276
- }
270
+ // XXX: dates should be sent as ISO format, not DD-MM-YYYY !
271
+ // if (isDate) {
272
+ // formattedFormData[name].value = formatDate({
273
+ // date: formattedFormData[name].value,
274
+ // format: 'DD-MM-YYYY',
275
+ // locale: intl.locale,
276
+ // });
277
+ // }
277
278
  }
278
279
  });
279
280
  dispatch(
@@ -323,7 +324,7 @@ const View = ({ data, id, path }) => {
323
324
 
324
325
  useEffect(() => {
325
326
  if (submitResults?.loaded) {
326
- if (submitResults?.result?.data?.waiting_list) {
327
+ if (submitResults?.result?.waiting_list) {
327
328
  setFormState({
328
329
  type: FORM_STATES.warning,
329
330
  result: {
@@ -48,8 +48,28 @@ export const getRealStartAndEndWithRecurrence = (
48
48
 
49
49
  export const getRealEventEnd = (content, rruleSet) => {
50
50
  let actualEndDate = content.end;
51
- if (content.recurrence) {
51
+
52
+ if (content.recurrence && rruleSet.rrules()[0].options.until) {
52
53
  actualEndDate = rruleSet.rrules()[0].options.until;
53
54
  }
54
55
  return actualEndDate;
55
56
  };
57
+
58
+ export const getRecurrenceExceptionDates = (rruleSet) => {
59
+ const rdates = rruleSet?.rdates() ?? [];
60
+ const exdates = rruleSet?.exdates() ?? [];
61
+
62
+ const additionalDates = rdates.reduce((acc, curr) => {
63
+ const isExdate = exdates.some((b) => b.toString() === curr.toString());
64
+ if (!isExdate) {
65
+ return [...acc, curr];
66
+ } else return acc;
67
+ }, []);
68
+
69
+ const exceptionDates = {
70
+ additionalDates: additionalDates,
71
+ removedDates: exdates,
72
+ };
73
+
74
+ return exceptionDates;
75
+ };
@@ -119,12 +119,19 @@ export const FILE_EXTENSIONS = {
119
119
  icon: { lib: '', name: faFileOdp, svg_format: true },
120
120
  format_name: 'ODP',
121
121
  },
122
+ pdf: {
123
+ icon: { lib: 'far', name: 'file-pdf' },
124
+ format_name: 'PDF',
125
+ },
122
126
  };
123
127
 
124
128
  export const getFileViewFormat = (file) => {
125
- const regexEx = /(?:\.([^.]+))?$/;
126
- const fileExtension = regexEx.exec(file.filename)[1];
127
- const typeOfContent = file['content-type'];
129
+ const cleanedFilename = (file.filename || '').split(/\/[@?#]/)[0];
130
+ const regexEx = /\.([a-zA-Z0-9]+)$/;
131
+
132
+ const match = regexEx.exec(cleanedFilename);
133
+ const fileExtension = match ? match[1] : null;
134
+ const typeOfContent = file['content-type'] ?? file['mime_type'];
128
135
 
129
136
  const viewFormat = {
130
137
  icon: null,
@@ -0,0 +1,90 @@
1
+ import { getFileViewFormat, FILE_EXTENSIONS, FILE_FORMATS } from './files';
2
+
3
+ describe('getFileViewFormat', () => {
4
+ test('should correctly extract the extension and match the icon for a valid PDF URL with multiple segments after the extension', () => {
5
+ const file = {
6
+ filename:
7
+ 'https://example.com/amministrazione/documenti-e-dati/modulistica/area-servizi-educativi-e-scolastici/intestazione-ripartizione-rette/modulo_intestazione_ripartizione_rette_nona_784_9690.pdf/@@download/file_principale',
8
+ 'content-type': 'application/pdf',
9
+ };
10
+
11
+ const result = getFileViewFormat(file);
12
+
13
+ expect(result.icon).toEqual(FILE_EXTENSIONS.pdf.icon); // Verifica che l'icona sia corretta
14
+ expect(result.label).toEqual(FILE_EXTENSIONS.pdf.format_name); // Verifica che il formato sia corretto
15
+ });
16
+
17
+ test('should correctly handle a PDF URL without multiple segments after the extension', () => {
18
+ const file = {
19
+ filename:
20
+ 'https://example.com/amministrazione/documenti-e-dati/modulistica/area-servizi-educativi-e-scolastici/intestazione-ripartizione-rette/modulo_intestazione_ripartizione_rette_nona_784_9690.pdf/@@download/filehttps://example.com/amministrazione/documenti-e-dati/modulistica/area-servizi-educativi-e-scolastici/intestazione-ripartizione-rette/modulo_intestazione_ripartizione_rette_nona_784_9690.pdf',
21
+ 'content-type': 'application/pdf',
22
+ };
23
+
24
+ const result = getFileViewFormat(file);
25
+
26
+ expect(result.icon).toEqual(FILE_EXTENSIONS.pdf.icon);
27
+ expect(result.label).toEqual(FILE_EXTENSIONS.pdf.format_name);
28
+ });
29
+
30
+ test('should return correct format for a non-PDF file extension', () => {
31
+ const file = {
32
+ filename: 'https://example.com/file/example.xsd',
33
+ 'content-type': 'application/xml',
34
+ };
35
+
36
+ const result = getFileViewFormat(file);
37
+
38
+ expect(result.icon).toEqual(FILE_EXTENSIONS.xsd.icon);
39
+ expect(result.label).toEqual(FILE_EXTENSIONS.xsd.format_name);
40
+ });
41
+
42
+ test('should return correct format for a non-PDF content-type', () => {
43
+ const file = {
44
+ filename: 'https://example.com/file/example.xml',
45
+ 'content-type': 'application/xml',
46
+ };
47
+
48
+ const result = getFileViewFormat(file);
49
+
50
+ expect(result.icon).toEqual(FILE_FORMATS['application/xml'].icon);
51
+ expect(result.label).toEqual(FILE_FORMATS['application/xml'].format_name);
52
+ });
53
+
54
+ test('should return null format when extension or content-type is not found', () => {
55
+ const file = {
56
+ filename: 'https://example.com/file/unknown.xyz',
57
+ 'content-type': 'application/unknown',
58
+ };
59
+
60
+ const result = getFileViewFormat(file);
61
+
62
+ expect(result.icon).toBeNull();
63
+ expect(result.label).toBeNull();
64
+ });
65
+
66
+ test('should handle file URLs without an extension', () => {
67
+ const file = {
68
+ filename: 'https://example.com/file/no-extension/',
69
+ 'content-type': 'text/plain',
70
+ };
71
+
72
+ const result = getFileViewFormat(file);
73
+
74
+ expect(result.icon).toEqual(FILE_FORMATS['text/plain'].icon);
75
+ expect(result.label).toEqual(FILE_FORMATS['text/plain'].format_name);
76
+ });
77
+
78
+ test('should handle case where URL is .pdf but content-type is text/plain', () => {
79
+ const file = {
80
+ filename: 'https://example.com/file/example.pdf',
81
+ 'content-type': 'text/plain',
82
+ };
83
+
84
+ const result = getFileViewFormat(file);
85
+
86
+ // La funzione dovrebbe comunque dare priorità all'estensione ".pdf" rispetto al content-type "text/plain"
87
+ expect(result.icon).toEqual(FILE_EXTENSIONS.pdf.icon); // Verifica che l'icona PDF venga restituita
88
+ expect(result.label).toEqual(FILE_EXTENSIONS.pdf.format_name); // Verifica che il formato PDF venga restituito
89
+ });
90
+ });
@@ -22,6 +22,7 @@ export {
22
22
  viewDate,
23
23
  getRealStartAndEndWithRecurrence,
24
24
  getRealEventEnd,
25
+ getRecurrenceExceptionDates,
25
26
  } from 'design-comuni-plone-theme/helpers/dates';
26
27
  export { getSiteProperty } from 'design-comuni-plone-theme/helpers/config';
27
28
  export { useDebouncedEffect } from 'design-comuni-plone-theme/helpers/debounce';
@@ -112,6 +112,8 @@
112
112
  }
113
113
 
114
114
  .contact-title {
115
+
116
+ margin-bottom: 1rem;
115
117
  font-size: 1.35rem;
116
118
  font-weight: bold;
117
119
  line-height: 1.4em;
@@ -123,20 +125,11 @@
123
125
 
124
126
  .contact-info {
125
127
  display: flex;
126
-
127
- &:first-of-type {
128
- align-items: center;
129
-
130
- .icon-wrapper {
131
- margin-top: 0;
132
- }
133
- }
134
-
135
- &:not(:last-of-type) {
136
- margin-bottom: 1rem;
137
- }
128
+ align-items: center;
138
129
 
139
130
  .icon-wrapper {
131
+ display: flex;
132
+ align-items: center;
140
133
  margin-top: 0.2rem;
141
134
  margin-right: 1rem;
142
135
  }
@@ -1,13 +1,26 @@
1
1
  @media print {
2
+ @page {
3
+ margin: 0 !important;
4
+ }
5
+
2
6
  body {
3
7
  display: block !important;
4
8
  }
5
9
 
6
10
  .public-ui {
7
- // removed underlining from links
8
11
  a {
9
12
  font-weight: 600 !important;
10
- text-decoration: none !important;
13
+ // text-decoration: none !important;
14
+ /* i link che non devono essere sottolineati hanno già regole specifiche,
15
+ a video è necessario mostare che i tag a sono link */
16
+
17
+ &.read-more {
18
+ display: none !important; // omesso il read more nelle card
19
+ }
20
+ }
21
+
22
+ .text-secondary {
23
+ color: $body-color !important;
11
24
  }
12
25
 
13
26
  .content-area,
@@ -17,6 +30,24 @@
17
30
  page-break-inside: avoid;
18
31
  }
19
32
 
33
+ .container {
34
+ max-width: 98%;
35
+ }
36
+
37
+ // padding/margin
38
+ .py-5 {
39
+ padding-top: 20px !important;
40
+ padding-bottom: 20px !important;
41
+ }
42
+
43
+ .pb-5 {
44
+ padding-bottom: 20px !important;
45
+ }
46
+
47
+ .pt-5 {
48
+ padding-top: 20px !important;
49
+ }
50
+
20
51
  // removed part of header header
21
52
  .it-header-slim-wrapper {
22
53
  display: none;
@@ -41,10 +72,8 @@
41
72
  }
42
73
 
43
74
  .it-brand-text {
44
- .no_toc {
45
- color: $link-color;
46
- font-size: 2rem !important;
47
- }
75
+ color: $link-color;
76
+ font-size: 2rem !important;
48
77
  }
49
78
  }
50
79
  }
@@ -76,6 +105,10 @@
76
105
  }
77
106
  }
78
107
 
108
+ .section {
109
+ padding: 1.2rem;
110
+ }
111
+
79
112
  /* Removed shadow and card's padding. Add border*/
80
113
  .card {
81
114
  border: 1px solid $gray-border !important;
@@ -89,15 +122,34 @@
89
122
  border: none !important;
90
123
  border-left-width: 0 !important;
91
124
  }
125
+
126
+ &::after {
127
+ display: none;
128
+ }
129
+
130
+ &.card-bg {
131
+ background-color: white !important;
132
+ color: $body-color !important;
133
+ }
92
134
  }
93
135
 
94
- //card teaser 3
136
+ // Card teaser
95
137
  .card-wrapper.card-teaser-wrapper.card-teaser-block-3 {
96
138
  > .card-teaser {
97
- flex: 0 0 32%;
139
+ flex: 0 0 32.5%;
98
140
  }
99
141
  }
100
142
 
143
+ .card.card-teaser.simple-card-default-item .card-body .card-title a,
144
+ .card.card-teaser .card-body .card-title a,
145
+ .card .card-title a {
146
+ font-size: 1.1rem !important;
147
+ }
148
+
149
+ .card .card-body .category-top {
150
+ flex-wrap: wrap;
151
+ }
152
+
101
153
  #text-tempi_e_scadenze > div > p {
102
154
  padding: 1rem 0 0 0 !important;
103
155
  box-shadow: none !important;
@@ -155,7 +207,7 @@
155
207
  .it-page-sections-container {
156
208
  border-top: none;
157
209
 
158
- .it-carousel-wrapper {
210
+ .it-carousel-wrapper:not(#galleria) {
159
211
  display: none;
160
212
  }
161
213
 
@@ -223,18 +275,49 @@
223
275
  box-shadow: none;
224
276
  font-size: 1rem;
225
277
  }
278
+
279
+ .callout {
280
+ page-break-inside: avoid;
281
+
282
+ .callout-inner {
283
+ // padding-top: 0px;
284
+ p {
285
+ margin-top: -2rem;
286
+ }
287
+ }
288
+ }
289
+ // buttons
290
+ button.btn,
291
+ .btn.btn-primary,
292
+ .draftjs-buttons a {
293
+ padding: 0.5rem 1rem;
294
+ border: 1px solid $link-color;
295
+ background-color: white;
296
+ color: $link-color;
297
+
298
+ svg.icon {
299
+ color: $link-color;
300
+ fill: $link-color;
301
+ }
302
+ }
303
+
304
+ // blockquote text
305
+ blockquote.blockquote-card.dark,
306
+ .blockquote.blockquote-card.dark {
307
+ border: 1px solid $body-color;
308
+ background-color: white;
309
+ color: $body-color;
310
+
311
+ a:not(.btn) {
312
+ color: $body-color;
313
+ }
314
+ }
226
315
  }
227
316
 
228
317
  .draft-text-larger {
229
318
  font-size: 1.2rem;
230
319
  }
231
320
 
232
- .public-ui .draftjs-buttons a {
233
- padding: 0rem;
234
- background-color: white;
235
- color: $link-color;
236
- }
237
-
238
321
  //external link icon
239
322
  svg.external-link {
240
323
  display: none;