@itfin/components 1.3.4 → 1.3.6
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/package.json +18 -3
- package/src/components/editor/Editor.vue +218 -0
- package/src/components/editor/index.stories.js +101 -0
- package/src/components/editor/tools/drawing/drawing.js +152 -0
- package/src/components/editor/tools/drawing/drawing.scss +63 -0
- package/src/components/editor/tools/drawing/library.json +59570 -0
- package/src/components/editor/tools/highlightcode/codecup.css +56 -0
- package/src/components/editor/tools/highlightcode/codecup.js +298 -0
- package/src/components/editor/tools/highlightcode/codecup.svg +3 -0
- package/src/components/modal/modalSrc.js +1 -1
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
.editorjs-codeCup_Wrapper {
|
|
2
|
+
height: max-content !important;
|
|
3
|
+
border-radius: 5px;
|
|
4
|
+
margin-bottom: 10px;
|
|
5
|
+
position: relative;
|
|
6
|
+
z-index: 0;
|
|
7
|
+
min-height: 100px;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
.editorjs-codeCup_Wrapper .codeCup {
|
|
11
|
+
border-radius: 5px;
|
|
12
|
+
background: none;
|
|
13
|
+
}
|
|
14
|
+
.editorjs-codeCup_Wrapper .codecup {
|
|
15
|
+
min-height: 100px;
|
|
16
|
+
}
|
|
17
|
+
.codecup__copyButton svg {
|
|
18
|
+
display: block;
|
|
19
|
+
}
|
|
20
|
+
.codecup-language-select {
|
|
21
|
+
display: block;
|
|
22
|
+
padding: 3px;
|
|
23
|
+
width: 100%;
|
|
24
|
+
margin-bottom: 5px;
|
|
25
|
+
}
|
|
26
|
+
.codecup-toggle-linenumbers {
|
|
27
|
+
display: flex;
|
|
28
|
+
padding: 3px;
|
|
29
|
+
width: 100%;
|
|
30
|
+
align-items: center;
|
|
31
|
+
justify-content: start;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
.editorjs-codeCup_Wrapper .editorjs-codeCup_LangDisplay {
|
|
35
|
+
position: absolute;
|
|
36
|
+
line-height: 20px;
|
|
37
|
+
font-size: 10px;
|
|
38
|
+
color: #999;
|
|
39
|
+
background-color: #dcdfe6;
|
|
40
|
+
padding: 2px 7px;
|
|
41
|
+
right: 0;
|
|
42
|
+
bottom: 0;
|
|
43
|
+
border-bottom-right-radius: 5px;
|
|
44
|
+
border-top-left-radius: 5px;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
.editorjs-codeCup_Wrapper .codeCup.codeCup--has-line-numbers:before{
|
|
48
|
+
background-color: #dcdfe6;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/* .wide{
|
|
52
|
+
width: 100%;
|
|
53
|
+
|
|
54
|
+
z-index: 10;
|
|
55
|
+
position: inherit;
|
|
56
|
+
} */
|
|
@@ -0,0 +1,298 @@
|
|
|
1
|
+
|
|
2
|
+
/**
|
|
3
|
+
* EditorJsCodeCup Block for the Editor.js.
|
|
4
|
+
*
|
|
5
|
+
* @author Calum Knott (calum@calumk.com)
|
|
6
|
+
* @license The MIT License (MIT)
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* @typedef {object} EditorJsCodeCupConfig
|
|
11
|
+
* @property {string} placeholder - placeholder for the empty EditorJsCodeCup
|
|
12
|
+
* @property {boolean} preserveBlank - Whether or not to keep blank EditorJsCodeCups when saving editor data
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* @typedef {Object} EditorJsCodeCupData
|
|
17
|
+
* @description Tool's input and output data format
|
|
18
|
+
* @property {String} text — EditorJsCodeCup's content. Can include HTML tags: <a><b><i>
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
import style from './codecup.css'
|
|
22
|
+
|
|
23
|
+
import codecup from '@calumk/codecup/dist/codecup.bundle.js';
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class EditorJsCodeCup {
|
|
28
|
+
/**
|
|
29
|
+
* Default placeholder for EditorJsCodeCup Tool
|
|
30
|
+
*
|
|
31
|
+
* @return {string}
|
|
32
|
+
* @constructor
|
|
33
|
+
*/
|
|
34
|
+
static get DEFAULT_PLACEHOLDER() {
|
|
35
|
+
return '// Hello';
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
static get enableLineBreaks() {
|
|
39
|
+
return true;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Render plugin`s main Element and fill it with saved data
|
|
44
|
+
*
|
|
45
|
+
* @param {object} params - constructor params
|
|
46
|
+
* @param {EditorJsCodeCupData} params.data - previously saved data
|
|
47
|
+
* @param {EditorJsCodeCupConfig} params.config - user config for Tool
|
|
48
|
+
* @param {object} params.api - editor.js api
|
|
49
|
+
* @param {boolean} readOnly - read only mode flag
|
|
50
|
+
*/
|
|
51
|
+
constructor({data, config, api, readOnly}) {
|
|
52
|
+
// console.log(data)
|
|
53
|
+
this.api = api;
|
|
54
|
+
this.readOnly = readOnly;
|
|
55
|
+
|
|
56
|
+
this._CSS = {
|
|
57
|
+
block: this.api.styles.block,
|
|
58
|
+
wrapper: 'ce-EditorJsCodeCup',
|
|
59
|
+
settingsButton: this.api.styles.settingsButton,
|
|
60
|
+
settingsButtonActive: this.api.styles.settingsButtonActive,
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
if (!this.readOnly) {
|
|
64
|
+
this.onKeyUp = this.onKeyUp.bind(this);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Placeholder for EditorJsCodeCup if it is first Block
|
|
69
|
+
* @type {string}
|
|
70
|
+
*/
|
|
71
|
+
this._placeholder = config.placeholder ? config.placeholder : EditorJsCodeCup.DEFAULT_PLACEHOLDER;
|
|
72
|
+
|
|
73
|
+
this._preserveBlank = config.preserveBlank !== undefined ? config.preserveBlank : false;
|
|
74
|
+
|
|
75
|
+
this._element; // used to hold the wrapper div, as a point of reference
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
// let x = (x === undefined) ? your_default_value : x;
|
|
80
|
+
this.data = {}
|
|
81
|
+
this.data.code = (data.code === undefined) ? '// Hello World' : data.code;
|
|
82
|
+
this.data.language = (data.language === undefined) ? 'plain' : data.language;
|
|
83
|
+
this.data.showlinenumbers = (data.showlinenumbers === undefined) ? true : data.showlinenumbers;
|
|
84
|
+
this.data.showCopyButton = (data.showCopyButton === undefined) ? true : data.showCopyButton;
|
|
85
|
+
this.data.editorInstance = {}
|
|
86
|
+
|
|
87
|
+
// console.log(this.data)
|
|
88
|
+
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Check if text content is empty and set empty string to inner html.
|
|
93
|
+
* We need this because some browsers (e.g. Safari) insert <br> into empty contenteditanle elements
|
|
94
|
+
*
|
|
95
|
+
* @param {KeyboardEvent} e - key up event
|
|
96
|
+
*/
|
|
97
|
+
onKeyUp(e) {
|
|
98
|
+
if (e.code !== 'Backspace' && e.code !== 'Delete') {
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
console.log(e)
|
|
103
|
+
|
|
104
|
+
const {textContent} = this._element;
|
|
105
|
+
|
|
106
|
+
if (textContent === '') {
|
|
107
|
+
this._element.innerHTML = '';
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Return Tool's view
|
|
114
|
+
*
|
|
115
|
+
* @returns {HTMLDivElement}
|
|
116
|
+
*/
|
|
117
|
+
render() {
|
|
118
|
+
|
|
119
|
+
this._element = document.createElement('div');
|
|
120
|
+
this._element.classList.add('editorjs-codeCup_Wrapper')
|
|
121
|
+
let editorElem = document.createElement('div');
|
|
122
|
+
editorElem.classList.add('editorjs-codeCup_Editor')
|
|
123
|
+
let langdisplay = document.createElement('div');
|
|
124
|
+
langdisplay.classList.add('editorjs-codeCup_LangDisplay')
|
|
125
|
+
|
|
126
|
+
langdisplay.innerHTML = this.data.language
|
|
127
|
+
|
|
128
|
+
this._element.appendChild(editorElem)
|
|
129
|
+
this._element.appendChild(langdisplay)
|
|
130
|
+
|
|
131
|
+
// console.log(this.data.editorInstance)
|
|
132
|
+
|
|
133
|
+
this.data.editorInstance = new codecup(editorElem, {
|
|
134
|
+
language: this.data.language,
|
|
135
|
+
lineNumbers : this.data.showlinenumbers,
|
|
136
|
+
readonly : this.readOnly,
|
|
137
|
+
copyButton : this.data.showCopyButton,
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
// console.log(this.data.editorInstance)
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
this.data.editorInstance.onUpdate((code) => {
|
|
144
|
+
// console.log("onUpdate fired")
|
|
145
|
+
// console.log(code)
|
|
146
|
+
let _length = code.split('\n').length
|
|
147
|
+
this._debounce(this._updateEditorHeight(_length))
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
// this.data.editorInstance.addLanguage(this.data.language, Prism.languages[this.data.language]);
|
|
152
|
+
this.data.editorInstance.updateCode(this.data.code);
|
|
153
|
+
|
|
154
|
+
// console.log(this.data.code)
|
|
155
|
+
// console.log(this.data.editorInstance.getCode())
|
|
156
|
+
// console.log(this._element)
|
|
157
|
+
|
|
158
|
+
return this._element
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
_updateEditorHeight(length){
|
|
162
|
+
|
|
163
|
+
let _height = (length * 21) + 10
|
|
164
|
+
if (_height < 60){ _height = 60 }
|
|
165
|
+
|
|
166
|
+
this._element.style.height = _height + 'px';
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
_debounce(func, timeout = 500){
|
|
171
|
+
let timer;
|
|
172
|
+
return (...args) => {
|
|
173
|
+
clearTimeout(timer);
|
|
174
|
+
timer = setTimeout(() => { func.apply(this, args); }, timeout);
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
renderSettings() {
|
|
179
|
+
const settingsContainer = document.createElement('div');
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
let languagesSelect = document.createElement("select");
|
|
185
|
+
languagesSelect.classList.add("codecup-language-select")
|
|
186
|
+
|
|
187
|
+
//sort available languages alphabetically (ignore case)
|
|
188
|
+
let languages = Object.keys(Prism.languages).sort(function (a, b) {
|
|
189
|
+
return a.toLowerCase().localeCompare(b.toLowerCase());
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
//Create and append the options
|
|
193
|
+
for (var i = 0; i < languages.length; i++) {
|
|
194
|
+
// Weirdly PrismJS doesnt expose a list of installed languages, or rather it does, but it is mixed with helper functions, which i have to clear here.
|
|
195
|
+
if (languages[i] == "extend" || languages[i] == "insertBefore" || languages[i] == "DFS") {
|
|
196
|
+
continue;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
var option = document.createElement("option");
|
|
200
|
+
option.value = languages[i];
|
|
201
|
+
option.text = languages[i];
|
|
202
|
+
if(languages[i] == this.data.language){
|
|
203
|
+
option.selected="selected"
|
|
204
|
+
}
|
|
205
|
+
languagesSelect.appendChild(option);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
languagesSelect.addEventListener('change', (event) => {
|
|
209
|
+
this._updateLanguage(event.target.value)
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
// Disabled until codeCup supports toggle of line numbers
|
|
213
|
+
const toggleButton = document.createElement('label');
|
|
214
|
+
toggleButton.classList.add(this._CSS.settingsButton);
|
|
215
|
+
toggleButton.classList.add('codecup-toggle-linenumbers');
|
|
216
|
+
toggleButton.classList.add('ce-popover-item__title');
|
|
217
|
+
toggleButton.innerHTML = '<div class="ce-popover-item__icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="-8 -8 40 40" width="512" height="512"><path style="stroke: none !important;" d="M13,24c-.552,0-1-.448-1-1V2.011l-5.215,6.608c-.342,.434-.972,.507-1.405,.166-.434-.342-.507-.971-.166-1.405,0,0,5.343-6.767,5.371-6.794C11.16,.012,12.016-.157,12.766,.152c.75,.311,1.234,1.036,1.234,1.848V23c0,.552-.448,1-1,1Z"/></svg></div> Show line numbers'
|
|
218
|
+
if(this.data.showlinenumbers){
|
|
219
|
+
toggleButton.classList.toggle(this._CSS.settingsButtonActive)
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
toggleButton.addEventListener('click', (e) => {
|
|
223
|
+
e.preventDefault();
|
|
224
|
+
e.stopPropagation();
|
|
225
|
+
e.target.classList.toggle(this._CSS.settingsButtonActive)
|
|
226
|
+
this._toggleLineNumbers()
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
|
|
230
|
+
|
|
231
|
+
settingsContainer.appendChild(languagesSelect);
|
|
232
|
+
settingsContainer.appendChild(toggleButton);
|
|
233
|
+
|
|
234
|
+
return settingsContainer;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
_toggleLineNumbers = (thing) => {
|
|
238
|
+
this.data.showlinenumbers = !this.data.showlinenumbers
|
|
239
|
+
this.data.editorInstance.toggleLineNumbers()
|
|
240
|
+
|
|
241
|
+
// console.log(this.data.editorInstance)
|
|
242
|
+
// replace this with a native method for codeCup, if it gets implemented.
|
|
243
|
+
// for now, we will completely destroy the codeCup instance, and rebuild it - lazy but effective
|
|
244
|
+
|
|
245
|
+
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
_updateLanguage = (lang) => {
|
|
249
|
+
this.data.language = lang
|
|
250
|
+
this._element.querySelector('.editorjs-codeCup_LangDisplay').innerHTML = this.data.language
|
|
251
|
+
this.data.editorInstance.updateLanguage(this.data.language)
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
|
|
255
|
+
|
|
256
|
+
/**
|
|
257
|
+
* Extract Tool's data from the view
|
|
258
|
+
* @param {HTMLDivElement} toolsContent - EditorJsCodeCup tools rendered view
|
|
259
|
+
* @returns {EditorJsCodeCupData} - saved data
|
|
260
|
+
* @public
|
|
261
|
+
*/
|
|
262
|
+
save(toolsContent) {
|
|
263
|
+
let resp = {
|
|
264
|
+
code : this.data.editorInstance.getCode(),
|
|
265
|
+
language : this.data.language,
|
|
266
|
+
showlinenumbers : this.data.showlinenumbers,
|
|
267
|
+
showCopyButton : this.data.showCopyButton
|
|
268
|
+
};
|
|
269
|
+
|
|
270
|
+
return resp
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
/**
|
|
274
|
+
* Returns true to notify the core that read-only mode is supported
|
|
275
|
+
*
|
|
276
|
+
* @return {boolean}
|
|
277
|
+
*/
|
|
278
|
+
static get isReadOnlySupported() {
|
|
279
|
+
return true;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
|
|
283
|
+
/**
|
|
284
|
+
* Icon and title for displaying at the Toolbox
|
|
285
|
+
*
|
|
286
|
+
* @return {{icon: string, title: string}}
|
|
287
|
+
*/
|
|
288
|
+
static get toolbox() {
|
|
289
|
+
return {
|
|
290
|
+
icon: '<svg width="24" height="24" viewBox="-5 -6 24 24" xmlns="http://www.w3.org/2000/svg">\n' +
|
|
291
|
+
' <path style="stroke: none !important;" d="M3.177 6.852c.205.253.347.572.427.954.078.372.117.844.117 1.417 0 .418.01.725.03.92.02.18.057.314.107.396.046.075.093.117.14.134.075.027.218.056.42.083a.855.855 0 0 1 .56.297c.145.167.215.38.215.636 0 .612-.432.934-1.216.934-.457 0-.87-.087-1.233-.262a1.995 1.995 0 0 1-.853-.751 2.09 2.09 0 0 1-.305-1.097c-.014-.648-.029-1.168-.043-1.56-.013-.383-.034-.631-.06-.733-.064-.263-.158-.455-.276-.578a2.163 2.163 0 0 0-.505-.376c-.238-.134-.41-.256-.519-.371C.058 6.76 0 6.567 0 6.315c0-.37.166-.657.493-.846.329-.186.56-.342.693-.466a.942.942 0 0 0 .26-.447c.056-.2.088-.42.097-.658.01-.25.024-.85.043-1.802.015-.629.239-1.14.672-1.522C2.691.19 3.268 0 3.977 0c.783 0 1.216.317 1.216.921 0 .264-.069.48-.211.643a.858.858 0 0 1-.563.29c-.249.03-.417.076-.498.126-.062.04-.112.134-.139.291-.031.187-.052.562-.061 1.119a8.828 8.828 0 0 1-.112 1.378 2.24 2.24 0 0 1-.404.963c-.159.212-.373.406-.64.583.25.163.454.342.612.538zm7.34 0c.157-.196.362-.375.612-.538a2.544 2.544 0 0 1-.641-.583 2.24 2.24 0 0 1-.404-.963 8.828 8.828 0 0 1-.112-1.378c-.009-.557-.03-.932-.061-1.119-.027-.157-.077-.251-.14-.29-.08-.051-.248-.096-.496-.127a.858.858 0 0 1-.564-.29C8.57 1.401 8.5 1.185 8.5.921 8.5.317 8.933 0 9.716 0c.71 0 1.286.19 1.72.574.432.382.656.893.671 1.522.02.952.033 1.553.043 1.802.009.238.041.458.097.658a.942.942 0 0 0 .26.447c.133.124.364.28.693.466a.926.926 0 0 1 .493.846c0 .252-.058.446-.183.58-.109.115-.281.237-.52.371-.21.118-.377.244-.504.376-.118.123-.212.315-.277.578-.025.102-.045.35-.06.733-.013.392-.027.912-.042 1.56a2.09 2.09 0 0 1-.305 1.097c-.2.323-.486.574-.853.75a2.811 2.811 0 0 1-1.233.263c-.784 0-1.216-.322-1.216-.934 0-.256.07-.47.214-.636a.855.855 0 0 1 .562-.297c.201-.027.344-.056.418-.083.048-.017.096-.06.14-.134a.996.996 0 0 0 .107-.396c.02-.195.031-.502.031-.92 0-.573.039-1.045.117-1.417.08-.382.222-.701.427-.954z"></path>\n' +
|
|
292
|
+
'</svg>\n',
|
|
293
|
+
title: 'CodeCup'
|
|
294
|
+
};
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
export { EditorJsCodeCup as default }
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
<svg width="24" height="24" viewBox="-10 -10 34 34" xmlns="http://www.w3.org/2000/svg">
|
|
2
|
+
<path d="M3.177 6.852c.205.253.347.572.427.954.078.372.117.844.117 1.417 0 .418.01.725.03.92.02.18.057.314.107.396.046.075.093.117.14.134.075.027.218.056.42.083a.855.855 0 0 1 .56.297c.145.167.215.38.215.636 0 .612-.432.934-1.216.934-.457 0-.87-.087-1.233-.262a1.995 1.995 0 0 1-.853-.751 2.09 2.09 0 0 1-.305-1.097c-.014-.648-.029-1.168-.043-1.56-.013-.383-.034-.631-.06-.733-.064-.263-.158-.455-.276-.578a2.163 2.163 0 0 0-.505-.376c-.238-.134-.41-.256-.519-.371C.058 6.76 0 6.567 0 6.315c0-.37.166-.657.493-.846.329-.186.56-.342.693-.466a.942.942 0 0 0 .26-.447c.056-.2.088-.42.097-.658.01-.25.024-.85.043-1.802.015-.629.239-1.14.672-1.522C2.691.19 3.268 0 3.977 0c.783 0 1.216.317 1.216.921 0 .264-.069.48-.211.643a.858.858 0 0 1-.563.29c-.249.03-.417.076-.498.126-.062.04-.112.134-.139.291-.031.187-.052.562-.061 1.119a8.828 8.828 0 0 1-.112 1.378 2.24 2.24 0 0 1-.404.963c-.159.212-.373.406-.64.583.25.163.454.342.612.538zm7.34 0c.157-.196.362-.375.612-.538a2.544 2.544 0 0 1-.641-.583 2.24 2.24 0 0 1-.404-.963 8.828 8.828 0 0 1-.112-1.378c-.009-.557-.03-.932-.061-1.119-.027-.157-.077-.251-.14-.29-.08-.051-.248-.096-.496-.127a.858.858 0 0 1-.564-.29C8.57 1.401 8.5 1.185 8.5.921 8.5.317 8.933 0 9.716 0c.71 0 1.286.19 1.72.574.432.382.656.893.671 1.522.02.952.033 1.553.043 1.802.009.238.041.458.097.658a.942.942 0 0 0 .26.447c.133.124.364.28.693.466a.926.926 0 0 1 .493.846c0 .252-.058.446-.183.58-.109.115-.281.237-.52.371-.21.118-.377.244-.504.376-.118.123-.212.315-.277.578-.025.102-.045.35-.06.733-.013.392-.027.912-.042 1.56a2.09 2.09 0 0 1-.305 1.097c-.2.323-.486.574-.853.75a2.811 2.811 0 0 1-1.233.263c-.784 0-1.216-.322-1.216-.934 0-.256.07-.47.214-.636a.855.855 0 0 1 .562-.297c.201-.027.344-.056.418-.083.048-.017.096-.06.14-.134a.996.996 0 0 0 .107-.396c.02-.195.031-.502.031-.92 0-.573.039-1.045.117-1.417.08-.382.222-.701.427-.954z"></path>
|
|
3
|
+
</svg>
|