design-comuni-plone-theme 11.29.0 → 11.29.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.
Binary file
package/CHANGELOG.md CHANGED
@@ -1,5 +1,22 @@
1
1
 
2
2
 
3
+ ## [11.29.1](https://github.com/RedTurtle/design-comuni-plone-theme/compare/v11.29.0...v11.29.1) (2025-03-24)
4
+
5
+
6
+ ### Bug Fixes
7
+
8
+ * document cards layout for ct persona ([#921](https://github.com/RedTurtle/design-comuni-plone-theme/issues/921)) ([63ae761](https://github.com/RedTurtle/design-comuni-plone-theme/commit/63ae7618d7202800538d650ee36a174ffe80a204))
9
+ * focus of buttons + focus of inputs + contrast of buttons ([#915](https://github.com/RedTurtle/design-comuni-plone-theme/issues/915)) ([327b7d1](https://github.com/RedTurtle/design-comuni-plone-theme/commit/327b7d1907bfb0ec0f5c7d5e4c688fb4a5cb1dd6))
10
+ * handle slash in search params in url regex ([#914](https://github.com/RedTurtle/design-comuni-plone-theme/issues/914)) ([6a8744d](https://github.com/RedTurtle/design-comuni-plone-theme/commit/6a8744d32f8250d25604789cae06528178822329))
11
+ * link view redirects when user cannot edit, also redirects server side ([#919](https://github.com/RedTurtle/design-comuni-plone-theme/issues/919)) ([fee3622](https://github.com/RedTurtle/design-comuni-plone-theme/commit/fee362265f34069ad4ec4fbc8d096a12dc6294a3))
12
+ * restored original end of assignment label ([#910](https://github.com/RedTurtle/design-comuni-plone-theme/issues/910)) ([472f264](https://github.com/RedTurtle/design-comuni-plone-theme/commit/472f2647d0043e85c820868dc3886966da43219a))
13
+ * title link margin with no category + title style and bg gradient ([#917](https://github.com/RedTurtle/design-comuni-plone-theme/issues/917)) ([1f831c5](https://github.com/RedTurtle/design-comuni-plone-theme/commit/1f831c5cad258b631f13f681c550dc2101977905))
14
+
15
+
16
+ ### Documentation
17
+
18
+ * updated publiccode and release log ([5be2bd3](https://github.com/RedTurtle/design-comuni-plone-theme/commit/5be2bd3e4931a943369e07c34aea96b4e7c0fcbc))
19
+
3
20
  ## [11.29.0](https://github.com/RedTurtle/design-comuni-plone-theme/compare/v11.28.0...v11.29.0) (2025-03-07)
4
21
 
5
22
 
package/RELEASE.md CHANGED
@@ -41,6 +41,19 @@
41
41
  - ...
42
42
  -->
43
43
 
44
+ ## Versione 11.29.1 (24/03/2025)
45
+
46
+ ### Migliorie
47
+
48
+ - Il CT Collegamento identifica meglio i permessi dell'utente e di conseguenza il reindirizzamento automatico è più preciso.
49
+
50
+ ### Fix
51
+
52
+ - I bottoni presentano un contrasto corretto quando selezionati, e il bottone "scroll to top" può essere selezionato tramite navigazione da tastiera.
53
+ - Nel titolo e nel testo del campo "Data di fine dell'incarico" è stato rimosso il riferimento al nome dell'incarico.
54
+ - Risolto un problema con la validazione dei link inseriti nei campi url (ad es. URL del CT Collegamento).
55
+ - Risolto un problema con il template del blocco Elenco, variazione Card con testo animato.
56
+
44
57
  ## Versione 11.29.0 (07/03/2025)
45
58
 
46
59
  ### Migliorie
@@ -1526,8 +1526,7 @@ msgid "data_conclusione"
1526
1526
  msgstr ""
1527
1527
 
1528
1528
  #: components/ItaliaTheme/View/IncaricoView/IncaricoView
1529
- #: components/ItaliaTheme/View/PersonaView/PersonaRuolo
1530
- # defaultMessage: Ha fatto parte dell'organizzazione comunale come {incarico} fino al
1529
+ # defaultMessage: Data di fine dell'incarico
1531
1530
  msgid "data_conclusione_incarico"
1532
1531
  msgstr ""
1533
1532
 
@@ -1511,8 +1511,7 @@ msgid "data_conclusione"
1511
1511
  msgstr "Assignment start date"
1512
1512
 
1513
1513
  #: components/ItaliaTheme/View/IncaricoView/IncaricoView
1514
- #: components/ItaliaTheme/View/PersonaView/PersonaRuolo
1515
- # defaultMessage: Ha fatto parte dell'organizzazione comunale come {incarico} fino al
1514
+ # defaultMessage: Data di fine dell'incarico
1516
1515
  msgid "data_conclusione_incarico"
1517
1516
  msgstr "He was part of the municipal organization until"
1518
1517
 
@@ -1520,8 +1520,7 @@ msgid "data_conclusione"
1520
1520
  msgstr ""
1521
1521
 
1522
1522
  #: components/ItaliaTheme/View/IncaricoView/IncaricoView
1523
- #: components/ItaliaTheme/View/PersonaView/PersonaRuolo
1524
- # defaultMessage: Ha fatto parte dell'organizzazione comunale come {incarico} fino al
1523
+ # defaultMessage: Data di fine dell'incarico
1525
1524
  msgid "data_conclusione_incarico"
1526
1525
  msgstr "Formó parte de la organización municipal hasta"
1527
1526
 
@@ -1528,8 +1528,7 @@ msgid "data_conclusione"
1528
1528
  msgstr ""
1529
1529
 
1530
1530
  #: components/ItaliaTheme/View/IncaricoView/IncaricoView
1531
- #: components/ItaliaTheme/View/PersonaView/PersonaRuolo
1532
- # defaultMessage: Ha fatto parte dell'organizzazione comunale come {incarico} fino al
1531
+ # defaultMessage: Data di fine dell'incarico
1533
1532
  msgid "data_conclusione_incarico"
1534
1533
  msgstr "Date de conclusion de la mission"
1535
1534
 
@@ -1511,15 +1511,14 @@ msgid "data_conclusione"
1511
1511
  msgstr "Data conclusione incarico"
1512
1512
 
1513
1513
  #: components/ItaliaTheme/View/IncaricoView/IncaricoView
1514
- #: components/ItaliaTheme/View/PersonaView/PersonaRuolo
1515
- # defaultMessage: Ha fatto parte dell'organizzazione comunale come {incarico} fino al
1514
+ # defaultMessage: Data di fine dell'incarico
1516
1515
  msgid "data_conclusione_incarico"
1517
- msgstr "Ha fatto parte dell'organizzazione comunale come {incarico} fino al"
1516
+ msgstr "Data di fine dell'incarico"
1518
1517
 
1519
1518
  #: components/ItaliaTheme/View/PersonaView/PersonaRuolo
1520
1519
  # defaultMessage: Data di fine dell'incarico
1521
1520
  msgid "data_conclusione_incarico_label"
1522
- msgstr "Data di conclusione dell'incarico"
1521
+ msgstr "Data di fine dell'incarico"
1523
1522
 
1524
1523
  #: components/ItaliaTheme/View/IncaricoView/IncaricoView
1525
1524
  # defaultMessage: Data inizio incarico
package/locales/volto.pot CHANGED
@@ -1,7 +1,7 @@
1
1
  msgid ""
2
2
  msgstr ""
3
3
  "Project-Id-Version: Plone\n"
4
- "POT-Creation-Date: 2025-03-04T14:31:20.722Z\n"
4
+ "POT-Creation-Date: 2025-03-11T15:48:06.811Z\n"
5
5
  "Last-Translator: Plone i18n <plone-i18n@lists.sourceforge.net>\n"
6
6
  "Language-Team: Plone i18n <plone-i18n@lists.sourceforge.net>\n"
7
7
  "MIME-Version: 1.0\n"
@@ -1513,8 +1513,7 @@ msgid "data_conclusione"
1513
1513
  msgstr ""
1514
1514
 
1515
1515
  #: components/ItaliaTheme/View/IncaricoView/IncaricoView
1516
- #: components/ItaliaTheme/View/PersonaView/PersonaRuolo
1517
- # defaultMessage: Ha fatto parte dell'organizzazione comunale come {incarico} fino al
1516
+ # defaultMessage: Data di fine dell'incarico
1518
1517
  msgid "data_conclusione_incarico"
1519
1518
  msgstr ""
1520
1519
 
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "design-comuni-plone-theme",
3
3
  "description": "Volto Theme for Italia design guidelines",
4
4
  "license": "GPL-v3",
5
- "version": "11.29.0",
5
+ "version": "11.29.1",
6
6
  "main": "src/index.js",
7
7
  "repository": {
8
8
  "type": "git",
package/publiccode.yml CHANGED
@@ -227,9 +227,9 @@ maintenance:
227
227
  name: io-Comune - Il sito AgID per Comuni ed Enti Pubblici
228
228
  platforms:
229
229
  - web
230
- releaseDate: '2025-03-07'
230
+ releaseDate: '2025-03-24'
231
231
  softwareType: standalone/web
232
- softwareVersion: 11.29.0
232
+ softwareVersion: 11.29.1
233
233
  url: 'https://github.com/italia/design-comuni-plone-theme'
234
234
  usedBy:
235
235
  - ASP Comuni Modenesi Area Nord
@@ -90,6 +90,9 @@ const CardWithSlideUpTextTemplate = (props) => {
90
90
  href={isEditMode ? '#' : null}
91
91
  key={index}
92
92
  data-element={id_lighthouse}
93
+ className={cx('title-link', {
94
+ 'auto-margin-link': !category && !date,
95
+ })}
93
96
  >
94
97
  <h3
95
98
  className={cx('title', {
@@ -50,7 +50,6 @@ const ScrollToTop = () => {
50
50
  title={intl.formatMessage(messages.scrollToTop)}
51
51
  onClick={scrollToTop}
52
52
  aria-hidden="true"
53
- tabIndex={-1}
54
53
  >
55
54
  <Icon icon="it-arrow-up" padding={false} size="sm" />
56
55
  </Button>
@@ -36,8 +36,7 @@ const messages = defineMessages({
36
36
  },
37
37
  data_conclusione_incarico: {
38
38
  id: 'data_conclusione_incarico',
39
- defaultMessage:
40
- "Ha fatto parte dell'organizzazione comunale come {incarico} fino al",
39
+ defaultMessage: "Data di fine dell'incarico",
41
40
  },
42
41
  data_insediamento: {
43
42
  id: 'data_insediamento',
@@ -116,9 +115,7 @@ const IncaricoView = ({ content, moment: momentlib }) => {
116
115
  {content.data_conclusione_incarico && (
117
116
  <RichTextSection
118
117
  tag_id="data_conclusione_incarico"
119
- title={intl.formatMessage(messages.data_conclusione_incarico, {
120
- incarico: content.title,
121
- })}
118
+ title={intl.formatMessage(messages.data_conclusione_incarico)}
122
119
  >
123
120
  <div className="font-serif">
124
121
  {moment(content.data_conclusione_incarico).format('D-MM-YYYY')}
@@ -240,19 +240,19 @@ const PersonaDocumenti = ({ content }) => {
240
240
  }
241
241
  />
242
242
  )}
243
- {contentFolderHasItems(
244
- content,
245
- 'dichiarazione-insussistenza-cause-di-inconferibilita-e-incompatibilita',
246
- ) && (
247
- <Attachments
248
- content={content}
249
- folder_name={
250
- 'dichiarazione-insussistenza-cause-di-inconferibilita-e-incompatibilita'
251
- }
252
- as_section={false}
253
- />
254
- )}
255
243
  </div>
244
+ {contentFolderHasItems(
245
+ content,
246
+ 'dichiarazione-insussistenza-cause-di-inconferibilita-e-incompatibilita',
247
+ ) && (
248
+ <Attachments
249
+ content={content}
250
+ folder_name={
251
+ 'dichiarazione-insussistenza-cause-di-inconferibilita-e-incompatibilita'
252
+ }
253
+ as_section={false}
254
+ />
255
+ )}
256
256
  </RichTextSection>
257
257
  )}
258
258
  {(content.emolumenti_a_carico_della_finanza_pubblica?.download ||
@@ -277,19 +277,19 @@ const PersonaDocumenti = ({ content }) => {
277
277
  }
278
278
  />
279
279
  )}
280
- {contentFolderHasItems(
281
- content,
282
- 'emolumenti-complessivi-percepiti-a-carico-della-finanza-pubblica',
283
- ) && (
284
- <Attachments
285
- content={content}
286
- folder_name={
287
- 'emolumenti-complessivi-percepiti-a-carico-della-finanza-pubblica'
288
- }
289
- as_section={false}
290
- />
291
- )}
292
280
  </div>
281
+ {contentFolderHasItems(
282
+ content,
283
+ 'emolumenti-complessivi-percepiti-a-carico-della-finanza-pubblica',
284
+ ) && (
285
+ <Attachments
286
+ content={content}
287
+ folder_name={
288
+ 'emolumenti-complessivi-percepiti-a-carico-della-finanza-pubblica'
289
+ }
290
+ as_section={false}
291
+ />
292
+ )}
293
293
  </RichTextSection>
294
294
  )}
295
295
  </>
@@ -74,11 +74,6 @@ const messages = defineMessages({
74
74
  id: 'data_conclusione_incarico_label',
75
75
  defaultMessage: "Data di fine dell'incarico",
76
76
  },
77
- data_conclusione_incarico: {
78
- id: 'data_conclusione_incarico',
79
- defaultMessage:
80
- "Ha fatto parte dell'organizzazione comunale come {incarico} fino al",
81
- },
82
77
  altri_incarichi: {
83
78
  id: 'altri_incarichi',
84
79
  defaultMessage: 'Altri incarichi',
@@ -129,13 +124,11 @@ const PersonaRuolo = ({ content }) => {
129
124
  )}
130
125
  >
131
126
  <div className="font-serif">
132
- {`${intl.formatMessage(messages.data_conclusione_incarico, {
133
- incarico: content.incarichi_persona[0].title,
134
- })} ${viewDate(
127
+ {viewDate(
135
128
  intl.locale,
136
129
  content.incarichi_persona[0].data_conclusione_incarico,
137
130
  'DD MMMM Y',
138
- )}`}
131
+ )}
139
132
  </div>
140
133
  </RichTextSection>
141
134
  )}
@@ -0,0 +1,132 @@
1
+ import FormValidation from '@plone/volto/helpers/FormValidation/FormValidation';
2
+ import { messages } from '@plone/volto/helpers/MessageLabels/MessageLabels';
3
+
4
+ // copied over and tweaked from
5
+ // https://github.com/plone/volto/blob/17.x.x/src/helpers/FormValidation/FormValidation.test.js
6
+ const schema = {
7
+ properties: {
8
+ username: { title: 'Username', type: 'string', description: '' },
9
+ email: { title: 'Email', type: 'string', widget: 'email', description: '' },
10
+ url: { title: 'url', type: 'string', widget: 'url', description: '' },
11
+ },
12
+ fieldsets: [
13
+ { id: 'default', title: 'FIXME: User Data', fields: ['username'] },
14
+ { id: 'second', title: 'Second: User Data', fields: ['email'] },
15
+ ],
16
+ required: ['username'],
17
+ };
18
+ // const errors = { email: ['The specified email is not valid.'] };
19
+ const formData = { username: 'test username', email: 'test@example.com' };
20
+ const formatMessage = (messageObj) => {
21
+ return messageObj?.defaultMessage;
22
+ };
23
+ const errorJSON =
24
+ "[{'message': 'The specified email is not valid.', 'field': 'email', 'error': 'ValidationError'}]";
25
+ // end copied section
26
+
27
+ describe('FormValidation', () => {
28
+ describe('validateFieldsPerFieldset', () => {
29
+ // Tests copied over from Volto
30
+ it('validates incorrect url', () => {
31
+ formData.url = 'foo';
32
+ expect(
33
+ FormValidation.validateFieldsPerFieldset({
34
+ schema,
35
+ formData,
36
+ formatMessage,
37
+ }),
38
+ ).toEqual({ url: [messages.isValidURL.defaultMessage] });
39
+ });
40
+ it('validates url', () => {
41
+ formData.url = 'https://plone.org/';
42
+ expect(
43
+ FormValidation.validateFieldsPerFieldset({
44
+ schema,
45
+ formData,
46
+ formatMessage,
47
+ }),
48
+ ).toEqual({});
49
+ });
50
+ it('validates url with ip', () => {
51
+ formData.url = 'http://127.0.0.1:8080/Plone';
52
+ expect(
53
+ FormValidation.validateFieldsPerFieldset({
54
+ schema,
55
+ formData,
56
+ formatMessage,
57
+ }),
58
+ ).toEqual({});
59
+ });
60
+ it('validates url with localhost', () => {
61
+ formData.url = 'http://localhost:8080/Plone';
62
+ expect(
63
+ FormValidation.validateFieldsPerFieldset({
64
+ schema,
65
+ formData,
66
+ formatMessage,
67
+ }),
68
+ ).toEqual({});
69
+ });
70
+ // Our additional tests
71
+ it('validates url with path', () => {
72
+ formData.url = 'https://plone.org/Plone';
73
+ expect(
74
+ FormValidation.validateFieldsPerFieldset({
75
+ schema,
76
+ formData,
77
+ formatMessage,
78
+ }),
79
+ ).toEqual({});
80
+ });
81
+ it('validates url with port', () => {
82
+ formData.url = 'https://plone.org:8080/Plone';
83
+ expect(
84
+ FormValidation.validateFieldsPerFieldset({
85
+ schema,
86
+ formData,
87
+ formatMessage,
88
+ }),
89
+ ).toEqual({});
90
+ });
91
+ it('validates url with query', () => {
92
+ formData.url = 'https://plone.org/Plone?query=1';
93
+ expect(
94
+ FormValidation.validateFieldsPerFieldset({
95
+ schema,
96
+ formData,
97
+ formatMessage,
98
+ }),
99
+ ).toEqual({});
100
+ });
101
+ it('validates url with query with slashes', () => {
102
+ formData.url = 'https://plone.org/Plone?query=1/2/3';
103
+ expect(
104
+ FormValidation.validateFieldsPerFieldset({
105
+ schema,
106
+ formData,
107
+ formatMessage,
108
+ }),
109
+ ).toEqual({});
110
+ });
111
+ it('validates url with fragment', () => {
112
+ formData.url = 'https://plone.org/Plone#fragment';
113
+ expect(
114
+ FormValidation.validateFieldsPerFieldset({
115
+ schema,
116
+ formData,
117
+ formatMessage,
118
+ }),
119
+ ).toEqual({});
120
+ });
121
+ it('validates url with query and fragment', () => {
122
+ formData.url = 'https://plone.org/Plone?query=1#fragment';
123
+ expect(
124
+ FormValidation.validateFieldsPerFieldset({
125
+ schema,
126
+ formData,
127
+ formatMessage,
128
+ }),
129
+ ).toEqual({});
130
+ });
131
+ });
132
+ });
@@ -1,24 +1,27 @@
1
1
  // CUSTOMIZATION:
2
- // - Added condition to check if user is SPID user (16-18 and 21)
2
+ // - Added condition to check if the user can edit the link (18-21 and 24)
3
+ // - Backported optimizations from volto 18 (lines 33-35 and more specific imports)
3
4
 
4
5
  import { useEffect } from 'react';
5
6
  import { useSelector } from 'react-redux';
6
7
  import PropTypes from 'prop-types';
7
8
  import { useHistory } from 'react-router-dom';
8
- import { isInternalURL, flattenToAppURL } from '@plone/volto/helpers';
9
+ import { isInternalURL, flattenToAppURL } from '@plone/volto/helpers/Url/Url';
9
10
  import { Container as SemanticContainer } from 'semantic-ui-react';
10
- import { UniversalLink } from '@plone/volto/components';
11
+ import UniversalLink from '@plone/volto/components/manage/UniversalLink/UniversalLink';
12
+ import { Redirect } from 'react-router-dom';
11
13
  import { FormattedMessage } from 'react-intl';
12
14
  import config from '@plone/volto/registry';
13
15
 
14
- const LinkView = ({ token, content }) => {
16
+ const LinkView = ({ content }) => {
15
17
  const history = useHistory();
16
- const userWithoutRoles = useSelector((state) =>
17
- state.users?.user ? state.users.user?.roles?.length === 0 : true,
18
+ const userCanEdit = useSelector(
19
+ (state) =>
20
+ !!state.actions.actions.object.find((action) => action.id === 'edit'),
18
21
  );
19
22
 
20
23
  useEffect(() => {
21
- if (!token || userWithoutRoles) {
24
+ if (!userCanEdit) {
22
25
  const { remoteUrl } = content;
23
26
  if (isInternalURL(remoteUrl)) {
24
27
  history.replace(flattenToAppURL(remoteUrl));
@@ -26,7 +29,10 @@ const LinkView = ({ token, content }) => {
26
29
  window.location.href = flattenToAppURL(remoteUrl);
27
30
  }
28
31
  }
29
- }, [content, history, token, userWithoutRoles]);
32
+ }, [content, history, userCanEdit]);
33
+ if (__SERVER__ && !userCanEdit && content.remoteUrl) {
34
+ return <Redirect to={content.remoteUrl} />;
35
+ }
30
36
  const { title, description, remoteUrl } = content;
31
37
  const { openExternalLinkInNewTab } = config.settings;
32
38
  const Container =
@@ -108,7 +108,7 @@ const widgetValidation = {
108
108
  ')' +
109
109
  '(\\:\\d+)?' + // optional port
110
110
  '(\\/[-a-z\\d%_.~+]*)*' + // path
111
- '(\\?[;&a-z\\d%_.~+=-]*)?' + // validate query string
111
+ '(\\?[;&a-z\\d%_.~+\\/=-]*)?' + // validate query string
112
112
  '(\\#[-a-z\\d_]*)?$', // validate fragment locator
113
113
  'i',
114
114
  );
@@ -25,6 +25,10 @@
25
25
  padding: 1.2rem;
26
26
  text-decoration: none;
27
27
 
28
+ .title-link {
29
+ text-decoration: none;
30
+ }
31
+
28
32
  .title {
29
33
  z-index: 2;
30
34
  overflow: hidden;
@@ -43,6 +47,10 @@
43
47
  margin-top: auto !important;
44
48
  }
45
49
 
50
+ .auto-margin-link {
51
+ margin-top: auto;
52
+ }
53
+
46
54
  .category + .title {
47
55
  margin-top: 0 !important;
48
56
  }
@@ -104,7 +112,7 @@
104
112
  height: 100%;
105
113
  --bs-gradient: linear-gradient(
106
114
  to bottom,
107
- rgba(0, 0, 0, 0.3) 0%,
115
+ rgba(0, 0, 0, 0.5) 0%,
108
116
  #000 100%
109
117
  );
110
118
  opacity: 0.4;
@@ -10,8 +10,10 @@
10
10
  outline: 2px solid $outer-focus-outline !important;
11
11
  outline-offset: 2px;
12
12
 
13
- border: none !important;
14
13
  box-shadow: 0 0 0 2px $inner-focus-shadow !important;
14
+
15
+ // adds additional internal black border to buttons
16
+ border: 2px solid $outer-focus-outline !important;
15
17
  }
16
18
  }
17
19
 
@@ -40,6 +42,9 @@
40
42
  0 1px 1px $focus-outline-color,
41
43
  0 0 0 0.2rem $focus-outline-color;
42
44
  outline: none;
45
+
46
+ // adds additional black internal border to tertiary buttons
47
+ border: 2px solid $focus-outline-color !important;
43
48
  }
44
49
  }
45
50
 
@@ -6,3 +6,21 @@ button.btn.btn-primary:focus-visible,
6
6
  }
7
7
  }
8
8
  }
9
+
10
+ button.btn.btn-primary:focus-visible {
11
+ // fix for primary buttons to ensure contrast upon focus
12
+ background-color: darken($color: $primary, $amount: 5%);
13
+ color: color-contrast($primary);
14
+ }
15
+
16
+ button.btn.btn-secondary:focus-visible {
17
+ // fix for secondary buttons to ensure contrast upon focus
18
+ background-color: darken($color: $secondary, $amount: 5%);
19
+ color: color-contrast($secondary);
20
+ }
21
+
22
+ button.btn.btn-tertiary:focus-visible {
23
+ // fix for tertiary buttons to ensure contrast upon focus
24
+ background-color: darken($color: $tertiary, $amount: 5%);
25
+ color: color-contrast($tertiary);
26
+ }
@@ -7,6 +7,20 @@
7
7
  box-shadow: 0 0 0 2px $inner-focus-shadow !important;
8
8
  }
9
9
 
10
+ input:focus:not(.focus--mouse) {
11
+ // only add border to input besides default double outline
12
+ border: 2px solid $outer-focus-outline !important;
13
+ }
14
+
10
15
  .skiplinks a:focus:not(.focus--mouse) {
11
16
  border: 2px solid;
12
17
  }
18
+
19
+ .gdpr-privacy-show-banner:focus:not(.focus--mouse) {
20
+ // invert general :focus rule since button is always white
21
+ outline: 2px solid $inner-focus-shadow !important;
22
+ outline-offset: 2px;
23
+
24
+ border: none !important;
25
+ box-shadow: 0 0 0 2px $outer-focus-outline !important;
26
+ }
@@ -23,6 +23,11 @@
23
23
 
24
24
  border: none !important;
25
25
  box-shadow: 0 0 0 2px $inner-focus-shadow !important;
26
+
27
+ //adds border to ensure correct contrast on all bg
28
+ // dark bg + light button --> internal dark border + outer white shadow
29
+ // light bg + dark button --> external dark border + inner white shadow
30
+ border: 2px solid $outer-focus-outline !important;
26
31
  }
27
32
  }
28
33
  }