@openeventkit/event-site 2.1.18 → 2.1.21

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 (86) hide show
  1. package/.github/workflows/jest.yml +1 -1
  2. package/babel.config.json +9 -9
  3. package/gatsby-node.js +67 -125
  4. package/jest.setup.js +2 -0
  5. package/netlify.toml +1 -1
  6. package/package.json +25 -16
  7. package/src/__mocks__/@mdx-js/mdx.js +32 -0
  8. package/src/__mocks__/@mdx-js/react.js +15 -0
  9. package/src/__mocks__/rehype-external-links.js +3 -0
  10. package/src/__mocks__/remark-gfm.js +3 -0
  11. package/src/actions/fetch-entities-actions.js +45 -87
  12. package/src/actions/update-data-actions.js +2 -2
  13. package/src/actions/user-actions.js +578 -430
  14. package/src/cms/config/collections/configurationsCollection/siteSettings/index.js +2 -0
  15. package/src/cms/config/collections/configurationsCollection/siteSettings/typeDefs.js +10 -0
  16. package/src/cms/preview-templates/ContentPagePreview.js +27 -29
  17. package/src/components/AvatarEditorModal/index.js +10 -0
  18. package/src/components/CertificatePDF.js +313 -0
  19. package/src/components/CertificateSection.js +139 -0
  20. package/src/components/FullSchedule.js +83 -66
  21. package/src/components/Mdx.js +39 -0
  22. package/src/components/__tests__/Mdx.test.jsx +70 -0
  23. package/src/content/site-settings/index.json +1 -1
  24. package/src/content/sponsors.json +1 -1
  25. package/src/i18n/locales/en.json +9 -1
  26. package/src/pages/a/[...].js +3 -0
  27. package/src/reducers/user-reducer.js +89 -27
  28. package/src/routes/authorization-callback-route.js +20 -2
  29. package/src/styles/rsvp-page.module.scss +63 -0
  30. package/src/templates/full-profile-page.js +61 -2
  31. package/src/templates/marketing-page-template/MainColumn.js +40 -42
  32. package/src/templates/rsvp-page.js +144 -0
  33. package/src/utils/alerts.js +1 -1
  34. package/src/utils/build-json/BaseAPIRequest.js +25 -0
  35. package/src/utils/build-json/EventsAPIRequest.js +171 -0
  36. package/src/utils/build-json/SpeakersAPIRequest.js +62 -0
  37. package/src/utils/build-json/SummitAPIRequest.js +115 -0
  38. package/src/utils/build-json/constants.js +5 -0
  39. package/src/utils/certificateSettings.js +45 -0
  40. package/src/utils/customErrorHandler.js +40 -1
  41. package/src/utils/rsvpConstants.js +7 -0
  42. package/src/utils/useMarketingSettings.js +48 -1
  43. package/src/utils/useSiteSettings.js +11 -0
  44. package/src/workers/feeds.worker.js +85 -90
  45. package/src/workers/sync_strategies/activity_synch_strategy.js +147 -102
  46. package/src/workers/sync_strategies/speaker_synch_strategy.js +3 -3
  47. package/src/workers/sync_strategies/track_synch_strategy.js +149 -48
  48. package/src/workers/synch.worker.js +123 -88
  49. package/static/fonts/fonts.css +120 -20
  50. package/static/fonts/nunito-sans/nunito-sans-v18-latin-200.woff2 +0 -0
  51. package/static/fonts/nunito-sans/nunito-sans-v18-latin-200italic.ttf +0 -0
  52. package/static/fonts/nunito-sans/nunito-sans-v18-latin-200italic.woff2 +0 -0
  53. package/static/fonts/nunito-sans/nunito-sans-v18-latin-300.woff2 +0 -0
  54. package/static/fonts/nunito-sans/nunito-sans-v18-latin-300italic.ttf +0 -0
  55. package/static/fonts/nunito-sans/nunito-sans-v18-latin-300italic.woff2 +0 -0
  56. package/static/fonts/nunito-sans/nunito-sans-v18-latin-400.ttf +0 -0
  57. package/static/fonts/nunito-sans/nunito-sans-v18-latin-400.woff2 +0 -0
  58. package/static/fonts/nunito-sans/nunito-sans-v18-latin-400italic.ttf +0 -0
  59. package/static/fonts/nunito-sans/nunito-sans-v18-latin-400italic.woff2 +0 -0
  60. package/static/fonts/nunito-sans/nunito-sans-v18-latin-500.ttf +0 -0
  61. package/static/fonts/nunito-sans/nunito-sans-v18-latin-500.woff2 +0 -0
  62. package/static/fonts/nunito-sans/nunito-sans-v18-latin-500italic.ttf +0 -0
  63. package/static/fonts/nunito-sans/nunito-sans-v18-latin-500italic.woff2 +0 -0
  64. package/static/fonts/nunito-sans/nunito-sans-v18-latin-600.woff2 +0 -0
  65. package/static/fonts/nunito-sans/nunito-sans-v18-latin-600italic.woff2 +0 -0
  66. package/static/fonts/nunito-sans/nunito-sans-v18-latin-700.ttf +0 -0
  67. package/static/fonts/nunito-sans/nunito-sans-v18-latin-700.woff2 +0 -0
  68. package/static/fonts/nunito-sans/nunito-sans-v18-latin-700italic.woff2 +0 -0
  69. package/static/fonts/nunito-sans/nunito-sans-v18-latin-800.ttf +0 -0
  70. package/static/fonts/nunito-sans/nunito-sans-v18-latin-800.woff2 +0 -0
  71. package/static/fonts/nunito-sans/nunito-sans-v18-latin-800italic.woff2 +0 -0
  72. package/static/fonts/nunito-sans/nunito-sans-v18-latin-900.ttf +0 -0
  73. package/static/fonts/nunito-sans/nunito-sans-v18-latin-900.woff2 +0 -0
  74. package/static/fonts/nunito-sans/nunito-sans-v18-latin-900italic.woff2 +0 -0
  75. package/static/fonts/nunito-sans/nunito-sans-v12-latin-300.woff +0 -0
  76. package/static/fonts/nunito-sans/nunito-sans-v12-latin-300.woff2 +0 -0
  77. package/static/fonts/nunito-sans/nunito-sans-v12-latin-300italic.woff +0 -0
  78. package/static/fonts/nunito-sans/nunito-sans-v12-latin-300italic.woff2 +0 -0
  79. package/static/fonts/nunito-sans/nunito-sans-v12-latin-600.woff +0 -0
  80. package/static/fonts/nunito-sans/nunito-sans-v12-latin-600.woff2 +0 -0
  81. package/static/fonts/nunito-sans/nunito-sans-v12-latin-600italic.woff +0 -0
  82. package/static/fonts/nunito-sans/nunito-sans-v12-latin-600italic.woff2 +0 -0
  83. package/static/fonts/nunito-sans/nunito-sans-v12-latin-700.woff +0 -0
  84. package/static/fonts/nunito-sans/nunito-sans-v12-latin-700.woff2 +0 -0
  85. package/static/fonts/nunito-sans/nunito-sans-v12-latin-700italic.woff +0 -0
  86. package/static/fonts/nunito-sans/nunito-sans-v12-latin-700italic.woff2 +0 -0
@@ -1,125 +1,160 @@
1
1
  import SynchStrategyFactory from "./sync_strategies/synch_strategy_factory";
2
- // internal state
3
- const queue = [];
2
+
3
+ // ---- Internal state (persisted across messages while draining) ----
4
4
  let busy = false;
5
5
  let localSummit = null;
6
6
  let localAllEvents = null;
7
7
  let localAllIDXEvents = null;
8
8
  let localAllSpeakers = null;
9
9
  let localAllIDXSpeakers = null;
10
+ let currentAccessToken = null;
10
11
 
11
- /* eslint-disable-next-line no-restricted-globals */
12
- self.onmessage = async (e) => {
13
- if(busy) {
14
- // wait
15
- queue.push(e);
16
- return;
17
- }
18
- // run
19
- busy = true;
20
- await run(e);
21
- };
12
+ // Dedup/backpressure pool: key -> { payload, seq }
13
+ const pool = new Map();
14
+ let seq = 0;
22
15
 
23
- const run = async ( {
24
- data: {
25
- accessToken,
26
- noveltiesArray,
27
- summit,
28
- allEvents,
29
- allIDXEvents,
30
- allSpeakers,
31
- allIDXSpeakers
32
- }
33
- } ) => {
16
+ // Helper: coalescing precedence
17
+ function mergePayload(oldEntry, newPayload) {
18
+ if (!oldEntry) return newPayload; // nothing to merge
19
+ const oldOp = oldEntry.entity_operator;
20
+ const newOp = newPayload.entity_operator;
34
21
 
35
- noveltiesArray = JSON.parse(noveltiesArray);
22
+ // DELETE always wins
23
+ if (newOp === "DELETE") return newPayload;
24
+ if (oldOp === "DELETE") return oldEntry;
36
25
 
37
- if(localSummit === null)
38
- localSummit = JSON.parse(summit);
26
+ // Otherwise, last write wins (INSERT/UPDATE)
27
+ return newPayload;
28
+ }
39
29
 
40
- if(localAllEvents === null)
41
- localAllEvents = JSON.parse(allEvents);
30
+ // Helper: parse value only if it's a string
31
+ function maybeParseJSON(val) {
32
+ return typeof val === "string" ? JSON.parse(val) : val;
33
+ }
42
34
 
43
- if(localAllIDXEvents === null)
44
- localAllIDXEvents = JSON.parse(allIDXEvents);
35
+ /* eslint-disable-next-line no-restricted-globals */
36
+ self.onmessage = (e) => {
37
+ const {
38
+ accessToken,
39
+ noveltiesArray,
40
+ summit,
41
+ allEvents,
42
+ allIDXEvents,
43
+ allSpeakers,
44
+ allIDXSpeakers,
45
+ } = e.data || {};
46
+
47
+ // Initialize persistent state once
48
+ if (localSummit === null) localSummit = maybeParseJSON(summit);
49
+ if (localAllEvents === null) localAllEvents = maybeParseJSON(allEvents);
50
+ if (localAllIDXEvents === null)localAllIDXEvents = maybeParseJSON(allIDXEvents);
51
+ if (localAllSpeakers === null) localAllSpeakers = maybeParseJSON(allSpeakers);
52
+ if (localAllIDXSpeakers === null) localAllIDXSpeakers = maybeParseJSON(allIDXSpeakers);
53
+
54
+ currentAccessToken = accessToken ?? currentAccessToken;
55
+
56
+ // Coalesce incoming payloads into the pool (backpressure)
57
+ const items = maybeParseJSON(noveltiesArray) || [];
58
+ for (const payload of items) {
59
+ const key = `${payload.entity_type}|${payload.entity_id}`;
60
+ const existing = pool.get(key)?.payload;
61
+ const merged = mergePayload(existing, payload);
62
+ // Assign new seq if it's a new key or we changed the payload
63
+ if (!existing || merged !== existing) {
64
+ pool.set(key, { payload: merged, seq: ++seq });
65
+ }
66
+ }
45
67
 
46
- if(localAllSpeakers === null)
47
- localAllSpeakers = JSON.parse(allSpeakers);
68
+ if (!busy) void drain();
69
+ };
48
70
 
49
- if(localAllIDXSpeakers === null)
50
- localAllIDXSpeakers = JSON.parse(allIDXSpeakers);
71
+ async function drain() {
72
+ busy = true;
73
+ try {
74
+ // Keep draining while there is work (new messages can keep adding to pool)
75
+ // We snapshot-and-clear each iteration to process a stable batch.
76
+ while (pool.size) {
77
+ const batch = Array.from(pool.values())
78
+ .sort((a, b) => a.seq - b.seq) // stable arrival order
79
+ .map((e) => e.payload);
51
80
 
52
- console.log(`synch worker running for ${localSummit.id} ....`)
81
+ pool.clear();
53
82
 
54
- let lastPayload = null;
83
+ await runBatch(batch);
84
+ }
85
+ console.log("synch worker: pool empty");
86
+ } catch (err) {
87
+ console.log("synch worker fatal error", err);
88
+ } finally {
89
+ // Reset after everything in the pool is processed (or on fatal error)
90
+ busy = false;
91
+ localSummit = null;
92
+ localAllEvents = null;
93
+ localAllIDXEvents = null;
94
+ localAllSpeakers = null;
95
+ localAllIDXSpeakers = null;
96
+ // keep currentAccessToken as-is; next message can refresh it
97
+ }
98
+ }
55
99
 
56
- for (const payload of noveltiesArray) {
100
+ async function runBatch(batch) {
101
+ if (!batch || !batch.length) return;
57
102
 
58
- console.log(`synch worker processing payload `, payload);
103
+ console.log(`synch worker running for ${localSummit?.id} ... batch size=${batch.length}`);
59
104
 
60
- const {entity_operator, entity_type, entity_id} = payload;
105
+ let lastPayload = null;
61
106
 
107
+ for (const payload of batch) {
108
+ // Skip exact adjacent duplicates (cheap guard)
62
109
  if (
63
110
  lastPayload &&
64
- lastPayload.entity_type === entity_type &&
65
- lastPayload.entity_operator === entity_operator &&
66
- lastPayload.entity_id === entity_id) {
67
- console.log('synch worker skipping payload (already processed)');
111
+ lastPayload.entity_type === payload.entity_type &&
112
+ lastPayload.entity_operator === payload.entity_operator &&
113
+ lastPayload.entity_id === payload.entity_id
114
+ ) {
115
+ console.log("synch worker: skip adjacent duplicate", payload);
68
116
  continue;
69
117
  }
70
118
 
71
- // micro updates logic goes here ...
72
- console.log(`synch worker trying to create process strategy for payload `, payload);
73
-
74
- let s = SynchStrategyFactory.build(localSummit, localAllEvents, localAllIDXEvents, localAllSpeakers, localAllIDXSpeakers, accessToken, payload);
119
+ console.log("synch worker: building strategy for", payload);
120
+ const s = SynchStrategyFactory.build(
121
+ localSummit,
122
+ localAllEvents,
123
+ localAllIDXEvents,
124
+ localAllSpeakers,
125
+ localAllIDXSpeakers,
126
+ currentAccessToken,
127
+ payload
128
+ );
75
129
  lastPayload = payload;
76
- if (s === null) {
77
- console.log(`synch worker missing process strategy for payload`, payload);
130
+
131
+ if (!s) {
132
+ console.log("synch worker: missing strategy, skipping", payload);
78
133
  continue;
79
134
  }
80
135
 
81
136
  try {
82
- let res = await s.process(payload);
83
- console.log(`synch worker postMessage`);
84
- let {
85
- summit : resSummit,
86
- eventsData: resAllEvents,
87
- allIDXEvents : resAllIDXEvents,
88
- allSpeakers : resAllSpeakers,
89
- allIDXSpeakers : resAllIDXSpeakers
90
- } = res;
91
-
92
- // update internal state for next run
93
- if(resSummit)
94
- localSummit = resSummit;
95
- if(resAllEvents)
96
- localAllEvents = resAllEvents;
97
- if(resAllIDXEvents)
98
- localAllIDXEvents = resAllIDXEvents;
99
- if(resAllSpeakers)
100
- localAllSpeakers = resAllSpeakers;
101
- if(resAllIDXSpeakers)
102
- localAllIDXSpeakers = resAllIDXSpeakers;
137
+ const res = await s.process(payload);
138
+ const {
139
+ summit: resSummit,
140
+ eventsData: resAllEvents,
141
+ allIDXEvents: resAllIDXEvents,
142
+ allSpeakers: resAllSpeakers,
143
+ allIDXSpeakers:resAllIDXSpeakers,
144
+ } = res || {};
145
+
146
+ // Carry state forward
147
+ if (resSummit) localSummit = resSummit;
148
+ if (resAllEvents) localAllEvents = resAllEvents;
149
+ if (resAllIDXEvents) localAllIDXEvents = resAllIDXEvents;
150
+ if (resAllSpeakers) localAllSpeakers = resAllSpeakers;
151
+ if (resAllIDXSpeakers)localAllIDXSpeakers = resAllIDXSpeakers;
103
152
 
104
153
  /* eslint-disable-next-line no-restricted-globals */
105
154
  self.postMessage(res);
106
- } catch (error) {
107
- console.log(error);
155
+ } catch (err) {
156
+ console.log("synch worker payload error", payload, err);
157
+ // keep going with next payload
108
158
  }
109
159
  }
110
-
111
- if(queue.length) {
112
- // run the next queued item
113
- await run(queue.shift());
114
- return;
115
- }
116
-
117
- console.log('synch worker queue is empty!.')
118
- // reset internal state
119
- busy = false;
120
- localSummit = null;
121
- localAllEvents = null;
122
- localAllIDXEvents = null;
123
- localAllSpeakers = null;
124
- localAllIDXSpeakers = null;
125
160
  }
@@ -1,65 +1,165 @@
1
1
  /**
2
- * Generated using google-webfonts-helper
3
- * @see http://google-webfonts-helper.herokuapp.com/fonts/nunito-sans?subsets=latin
2
+ * Nunito Sans Font Family - Version 18
3
+ * Weights: 200, 300, 400, 500, 600, 700, 800, 900
4
+ * Styles: normal, italic
4
5
  */
5
6
 
7
+ /* nunito-sans-200 - latin */
8
+ @font-face {
9
+ font-family: "Nunito Sans";
10
+ font-style: normal;
11
+ font-weight: 200;
12
+ font-display: swap;
13
+ src: local(""),
14
+ url("nunito-sans/nunito-sans-v18-latin-200.woff2") format("woff2");
15
+ }
16
+
17
+ /* nunito-sans-200italic - latin */
18
+ @font-face {
19
+ font-family: "Nunito Sans";
20
+ font-style: italic;
21
+ font-weight: 200;
22
+ font-display: swap;
23
+ src: local(""),
24
+ url("nunito-sans/nunito-sans-v18-latin-200italic.woff2") format("woff2");
25
+ }
26
+
6
27
  /* nunito-sans-300 - latin */
7
28
  @font-face {
8
29
  font-family: "Nunito Sans";
9
30
  font-style: normal;
10
31
  font-weight: 300;
32
+ font-display: swap;
11
33
  src: local(""),
12
- url("nunito-sans/nunito-sans-v12-latin-300.woff2") format("woff2"),
13
- /* Chrome 26+, Opera 23+, Firefox 39+ */
14
- url("nunito-sans/nunito-sans-v12-latin-300.woff") format("woff"); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
34
+ url("nunito-sans/nunito-sans-v18-latin-300.woff2") format("woff2");
15
35
  }
36
+
16
37
  /* nunito-sans-300italic - latin */
17
38
  @font-face {
18
39
  font-family: "Nunito Sans";
19
40
  font-style: italic;
20
41
  font-weight: 300;
42
+ font-display: swap;
43
+ src: local(""),
44
+ url("nunito-sans/nunito-sans-v18-latin-300italic.woff2") format("woff2");
45
+ }
46
+
47
+ /* nunito-sans-400 - latin */
48
+ @font-face {
49
+ font-family: "Nunito Sans";
50
+ font-style: normal;
51
+ font-weight: 400;
52
+ font-display: swap;
53
+ src: local(""),
54
+ url("nunito-sans/nunito-sans-v18-latin-400.woff2") format("woff2");
55
+ }
56
+
57
+ /* nunito-sans-400italic - latin */
58
+ @font-face {
59
+ font-family: "Nunito Sans";
60
+ font-style: italic;
61
+ font-weight: 400;
62
+ font-display: swap;
63
+ src: local(""),
64
+ url("nunito-sans/nunito-sans-v18-latin-400italic.woff2") format("woff2");
65
+ }
66
+
67
+ /* nunito-sans-500 - latin */
68
+ @font-face {
69
+ font-family: "Nunito Sans";
70
+ font-style: normal;
71
+ font-weight: 500;
72
+ font-display: swap;
73
+ src: local(""),
74
+ url("nunito-sans/nunito-sans-v18-latin-500.woff2") format("woff2");
75
+ }
76
+
77
+ /* nunito-sans-500italic - latin */
78
+ @font-face {
79
+ font-family: "Nunito Sans";
80
+ font-style: italic;
81
+ font-weight: 500;
82
+ font-display: swap;
21
83
  src: local(""),
22
- url("nunito-sans/nunito-sans-v12-latin-300italic.woff2") format("woff2"),
23
- /* Chrome 26+, Opera 23+, Firefox 39+ */
24
- url("nunito-sans/nunito-sans-v12-latin-300italic.woff") format("woff"); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
84
+ url("nunito-sans/nunito-sans-v18-latin-500italic.woff2") format("woff2");
25
85
  }
86
+
26
87
  /* nunito-sans-600 - latin */
27
88
  @font-face {
28
89
  font-family: "Nunito Sans";
29
90
  font-style: normal;
30
91
  font-weight: 600;
92
+ font-display: swap;
31
93
  src: local(""),
32
- url("nunito-sans/nunito-sans-v12-latin-600.woff2") format("woff2"),
33
- /* Chrome 26+, Opera 23+, Firefox 39+ */
34
- url("nunito-sans/nunito-sans-v12-latin-600.woff") format("woff"); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
94
+ url("nunito-sans/nunito-sans-v18-latin-600.woff2") format("woff2");
35
95
  }
96
+
36
97
  /* nunito-sans-600italic - latin */
37
98
  @font-face {
38
99
  font-family: "Nunito Sans";
39
100
  font-style: italic;
40
101
  font-weight: 600;
102
+ font-display: swap;
41
103
  src: local(""),
42
- url("nunito-sans/nunito-sans-v12-latin-600italic.woff2") format("woff2"),
43
- /* Chrome 26+, Opera 23+, Firefox 39+ */
44
- url("nunito-sans/nunito-sans-v12-latin-600italic.woff") format("woff"); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
104
+ url("nunito-sans/nunito-sans-v18-latin-600italic.woff2") format("woff2");
45
105
  }
106
+
46
107
  /* nunito-sans-700 - latin */
47
108
  @font-face {
48
109
  font-family: "Nunito Sans";
49
110
  font-style: normal;
50
111
  font-weight: 700;
112
+ font-display: swap;
51
113
  src: local(""),
52
- url("nunito-sans/nunito-sans-v12-latin-700.woff2") format("woff2"),
53
- /* Chrome 26+, Opera 23+, Firefox 39+ */
54
- url("nunito-sans/nunito-sans-v12-latin-700.woff") format("woff"); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
114
+ url("nunito-sans/nunito-sans-v18-latin-700.woff2") format("woff2");
55
115
  }
116
+
56
117
  /* nunito-sans-700italic - latin */
57
118
  @font-face {
58
119
  font-family: "Nunito Sans";
59
120
  font-style: italic;
60
121
  font-weight: 700;
122
+ font-display: swap;
123
+ src: local(""),
124
+ url("nunito-sans/nunito-sans-v18-latin-700italic.woff2") format("woff2");
125
+ }
126
+
127
+ /* nunito-sans-800 - latin */
128
+ @font-face {
129
+ font-family: "Nunito Sans";
130
+ font-style: normal;
131
+ font-weight: 800;
132
+ font-display: swap;
133
+ src: local(""),
134
+ url("nunito-sans/nunito-sans-v18-latin-800.woff2") format("woff2");
135
+ }
136
+
137
+ /* nunito-sans-800italic - latin */
138
+ @font-face {
139
+ font-family: "Nunito Sans";
140
+ font-style: italic;
141
+ font-weight: 800;
142
+ font-display: swap;
143
+ src: local(""),
144
+ url("nunito-sans/nunito-sans-v18-latin-800italic.woff2") format("woff2");
145
+ }
146
+
147
+ /* nunito-sans-900 - latin */
148
+ @font-face {
149
+ font-family: "Nunito Sans";
150
+ font-style: normal;
151
+ font-weight: 900;
152
+ font-display: swap;
61
153
  src: local(""),
62
- url("nunito-sans/nunito-sans-v12-latin-700italic.woff2") format("woff2"),
63
- /* Chrome 26+, Opera 23+, Firefox 39+ */
64
- url("nunito-sans/nunito-sans-v12-latin-700italic.woff") format("woff"); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
154
+ url("nunito-sans/nunito-sans-v18-latin-900.woff2") format("woff2");
65
155
  }
156
+
157
+ /* nunito-sans-900italic - latin */
158
+ @font-face {
159
+ font-family: "Nunito Sans";
160
+ font-style: italic;
161
+ font-weight: 900;
162
+ font-display: swap;
163
+ src: local(""),
164
+ url("nunito-sans/nunito-sans-v18-latin-900italic.woff2") format("woff2");
165
+ }