@jjlmoya/utils-developer 1.14.0 → 1.16.0
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 +1 -1
- package/src/category/i18n/fr.ts +1 -1
- package/src/category/i18n/ru.ts +1 -1
- package/src/category/index.ts +2 -1
- package/src/entries.ts +4 -1
- package/src/index.ts +2 -0
- package/src/layouts/PreviewLayout.astro +1 -0
- package/src/pages/[locale]/[slug].astro +29 -12
- package/src/tests/diacritics_density.test.ts +118 -0
- package/src/tests/inverted_punctuation.test.ts +113 -0
- package/src/tests/locale_completeness.test.ts +2 -3
- package/src/tests/no_en_dash.test.ts +73 -0
- package/src/tests/pagespeed_best_practices.test.ts +198 -0
- package/src/tests/script_density.test.ts +94 -0
- package/src/tests/shared-test-helpers.ts +56 -0
- package/src/tests/tool_exports.test.ts +34 -0
- package/src/tests/tool_validation.test.ts +2 -2
- package/src/tool/aspectRatio/component.astro +3 -1
- package/src/tool/aspectRatio/i18n/de.ts +1 -1
- package/src/tool/aspectRatio/i18n/fr.ts +1 -1
- package/src/tool/aspectRatio/i18n/pl.ts +2 -2
- package/src/tool/aspectRatio/i18n/ru.ts +4 -4
- package/src/tool/aspectRatio/i18n/zh.ts +1 -1
- package/src/tool/aspectRatio/seo.astro +2 -1
- package/src/tool/calculadoraTiempoDatos/i18n/de.ts +1 -1
- package/src/tool/calculadoraTiempoDatos/i18n/pl.ts +1 -1
- package/src/tool/calculadoraTiempoDatos/i18n/ru.ts +5 -5
- package/src/tool/calculadoraTiempoDatos/i18n/sv.ts +5 -5
- package/src/tool/calculadoraTiempoDatos/i18n/zh.ts +1 -1
- package/src/tool/calculadoraTiempoDatos/seo.astro +2 -1
- package/src/tool/colorConverter/component.astro +3 -3
- package/src/tool/colorConverter/i18n/de.ts +1 -1
- package/src/tool/colorConverter/i18n/ru.ts +2 -2
- package/src/tool/colorConverter/seo.astro +2 -1
- package/src/tool/conversorExcelCsvHtml/i18n/es.ts +1 -1
- package/src/tool/conversorExcelCsvHtml/i18n/pl.ts +1 -1
- package/src/tool/conversorExcelCsvHtml/i18n/ru.ts +2 -2
- package/src/tool/conversorExcelCsvHtml/i18n/zh.ts +2 -2
- package/src/tool/conversorExcelCsvHtml/seo.astro +2 -1
- package/src/tool/cronGenerator/i18n/de.ts +4 -4
- package/src/tool/cronGenerator/i18n/en.ts +1 -1
- package/src/tool/cronGenerator/i18n/es.ts +2 -2
- package/src/tool/cronGenerator/i18n/fr.ts +5 -5
- package/src/tool/cronGenerator/i18n/id.ts +1 -1
- package/src/tool/cronGenerator/i18n/nl.ts +1 -1
- package/src/tool/cronGenerator/i18n/pl.ts +8 -8
- package/src/tool/cronGenerator/i18n/pt.ts +1 -1
- package/src/tool/cronGenerator/i18n/ru.ts +9 -9
- package/src/tool/cronGenerator/i18n/sv.ts +1 -1
- package/src/tool/cronGenerator/i18n/zh.ts +3 -3
- package/src/tool/cronGenerator/seo.astro +2 -1
- package/src/tool/cssSpecificityCalculator/i18n/de.ts +1 -1
- package/src/tool/cssSpecificityCalculator/i18n/fr.ts +3 -3
- package/src/tool/cssSpecificityCalculator/i18n/pl.ts +2 -2
- package/src/tool/cssSpecificityCalculator/i18n/ru.ts +2 -2
- package/src/tool/cssSpecificityCalculator/seo.astro +2 -1
- package/src/tool/cssToInlineConverter/i18n/de.ts +6 -6
- package/src/tool/cssToInlineConverter/i18n/es.ts +1 -1
- package/src/tool/cssToInlineConverter/i18n/fr.ts +3 -3
- package/src/tool/cssToInlineConverter/seo.astro +2 -1
- package/src/tool/duplicateCssRemover/i18n/de.ts +7 -7
- package/src/tool/duplicateCssRemover/i18n/fr.ts +1 -1
- package/src/tool/duplicateCssRemover/i18n/id.ts +1 -1
- package/src/tool/duplicateCssRemover/i18n/nl.ts +1 -1
- package/src/tool/duplicateCssRemover/i18n/pl.ts +1 -1
- package/src/tool/duplicateCssRemover/i18n/pt.ts +1 -1
- package/src/tool/duplicateCssRemover/i18n/ru.ts +3 -3
- package/src/tool/duplicateCssRemover/i18n/sv.ts +1 -1
- package/src/tool/duplicateCssRemover/seo.astro +2 -1
- package/src/tool/generadorSecurityTxt/i18n/de.ts +5 -5
- package/src/tool/generadorSecurityTxt/i18n/ru.ts +2 -2
- package/src/tool/generadorSecurityTxt/seo.astro +2 -1
- package/src/tool/hashGenerator/i18n/ru.ts +5 -5
- package/src/tool/hashGenerator/i18n/zh.ts +2 -2
- package/src/tool/hashGenerator/seo.astro +2 -1
- package/src/tool/inspectorCertificadosSsl/i18n/de.ts +6 -6
- package/src/tool/inspectorCertificadosSsl/i18n/ru.ts +5 -5
- package/src/tool/inspectorCertificadosSsl/seo.astro +2 -1
- package/src/tool/jsonFormatter/i18n/de.ts +4 -4
- package/src/tool/jsonFormatter/i18n/en.ts +4 -4
- package/src/tool/jsonFormatter/i18n/es.ts +4 -4
- package/src/tool/jsonFormatter/i18n/fr.ts +4 -4
- package/src/tool/jsonFormatter/i18n/id.ts +4 -4
- package/src/tool/jsonFormatter/i18n/it.ts +4 -4
- package/src/tool/jsonFormatter/i18n/ja.ts +4 -4
- package/src/tool/jsonFormatter/i18n/ko.ts +4 -4
- package/src/tool/jsonFormatter/i18n/nl.ts +4 -4
- package/src/tool/jsonFormatter/i18n/pl.ts +4 -4
- package/src/tool/jsonFormatter/i18n/pt.ts +4 -4
- package/src/tool/jsonFormatter/i18n/ru.ts +5 -5
- package/src/tool/jsonFormatter/i18n/sv.ts +4 -4
- package/src/tool/jsonFormatter/i18n/tr.ts +4 -4
- package/src/tool/jsonFormatter/i18n/zh.ts +5 -5
- package/src/tool/jsonFormatter/seo.astro +2 -1
- package/src/tool/keycode/i18n/de.ts +7 -7
- package/src/tool/keycode/i18n/en.ts +5 -5
- package/src/tool/keycode/i18n/es.ts +5 -5
- package/src/tool/keycode/i18n/fr.ts +7 -7
- package/src/tool/keycode/i18n/id.ts +5 -5
- package/src/tool/keycode/i18n/it.ts +5 -5
- package/src/tool/keycode/i18n/ja.ts +5 -5
- package/src/tool/keycode/i18n/ko.ts +5 -5
- package/src/tool/keycode/i18n/nl.ts +5 -5
- package/src/tool/keycode/i18n/pl.ts +7 -7
- package/src/tool/keycode/i18n/pt.ts +5 -5
- package/src/tool/keycode/i18n/ru.ts +6 -6
- package/src/tool/keycode/i18n/sv.ts +5 -5
- package/src/tool/keycode/i18n/tr.ts +5 -5
- package/src/tool/keycode/i18n/zh.ts +5 -5
- package/src/tool/keycode/seo.astro +2 -1
- package/src/tool/llmCostCalculator/component.astro +1 -2
- package/src/tool/llmCostCalculator/i18n/de.ts +4 -4
- package/src/tool/llmCostCalculator/i18n/en.ts +3 -3
- package/src/tool/llmCostCalculator/i18n/fr.ts +3 -3
- package/src/tool/llmCostCalculator/i18n/id.ts +3 -3
- package/src/tool/llmCostCalculator/i18n/pt.ts +3 -3
- package/src/tool/llmCostCalculator/i18n/ru.ts +3 -3
- package/src/tool/llmCostCalculator/i18n/sv.ts +3 -3
- package/src/tool/llmCostCalculator/i18n/tr.ts +3 -3
- package/src/tool/llmCostCalculator/i18n/zh.ts +3 -3
- package/src/tool/llmCostCalculator/seo.astro +2 -1
- package/src/tool/mobileMockupGenerator/component.astro +4 -5
- package/src/tool/mobileMockupGenerator/i18n/es.ts +1 -1
- package/src/tool/mobileMockupGenerator/seo.astro +2 -1
- package/src/tool/musicalTypography/i18n/de.ts +1 -1
- package/src/tool/musicalTypography/i18n/fr.ts +1 -1
- package/src/tool/musicalTypography/i18n/id.ts +1 -1
- package/src/tool/musicalTypography/i18n/it.ts +1 -1
- package/src/tool/musicalTypography/i18n/ko.ts +1 -1
- package/src/tool/musicalTypography/i18n/ru.ts +3 -3
- package/src/tool/musicalTypography/seo.astro +2 -1
- package/src/tool/placeholderGenerator/component.astro +2 -2
- package/src/tool/placeholderGenerator/i18n/de.ts +4 -4
- package/src/tool/placeholderGenerator/i18n/ru.ts +1 -1
- package/src/tool/placeholderGenerator/seo.astro +2 -1
- package/src/tool/promptLibrary/i18n/de.ts +1 -1
- package/src/tool/promptLibrary/seo.astro +2 -1
- package/src/tool/readabilityCalculator/component.astro +4 -4
- package/src/tool/readabilityCalculator/i18n/de.ts +2 -2
- package/src/tool/readabilityCalculator/seo.astro +2 -1
- package/src/tool/readabilityCalculator/visual-readability-calculator-wcag-apca.css +87 -3
- package/src/tool/serpPixelSimulator/bibliography.astro +7 -0
- package/src/tool/serpPixelSimulator/bibliography.ts +16 -0
- package/src/tool/serpPixelSimulator/component.astro +84 -0
- package/src/tool/serpPixelSimulator/controller.ts +323 -0
- package/src/tool/serpPixelSimulator/entry.ts +30 -0
- package/src/tool/serpPixelSimulator/i18n/de.ts +214 -0
- package/src/tool/serpPixelSimulator/i18n/en.ts +213 -0
- package/src/tool/serpPixelSimulator/i18n/es.ts +214 -0
- package/src/tool/serpPixelSimulator/i18n/fr.ts +214 -0
- package/src/tool/serpPixelSimulator/i18n/id.ts +214 -0
- package/src/tool/serpPixelSimulator/i18n/it.ts +214 -0
- package/src/tool/serpPixelSimulator/i18n/ja.ts +214 -0
- package/src/tool/serpPixelSimulator/i18n/ko.ts +214 -0
- package/src/tool/serpPixelSimulator/i18n/nl.ts +214 -0
- package/src/tool/serpPixelSimulator/i18n/pl.ts +214 -0
- package/src/tool/serpPixelSimulator/i18n/pt.ts +214 -0
- package/src/tool/serpPixelSimulator/i18n/ru.ts +214 -0
- package/src/tool/serpPixelSimulator/i18n/sv.ts +214 -0
- package/src/tool/serpPixelSimulator/i18n/tr.ts +214 -0
- package/src/tool/serpPixelSimulator/i18n/zh.ts +214 -0
- package/src/tool/serpPixelSimulator/index.ts +12 -0
- package/src/tool/serpPixelSimulator/logic.ts +18 -0
- package/src/tool/serpPixelSimulator/seo.astro +12 -0
- package/src/tool/serpPixelSimulator/serp-pixel-simulator.css +335 -0
- package/src/tool/serpPixelSimulator/ui.ts +33 -0
- package/src/tool/svgSanitizer/i18n/de.ts +2 -2
- package/src/tool/svgSanitizer/i18n/id.ts +1 -1
- package/src/tool/svgSanitizer/i18n/pl.ts +1 -1
- package/src/tool/svgSanitizer/i18n/ru.ts +7 -7
- package/src/tool/svgSanitizer/i18n/sv.ts +3 -3
- package/src/tool/svgSanitizer/i18n/tr.ts +3 -3
- package/src/tool/svgSanitizer/i18n/zh.ts +3 -3
- package/src/tool/svgSanitizer/seo.astro +2 -1
- package/src/tool/svgToCss/i18n/de.ts +2 -2
- package/src/tool/svgToCss/i18n/es.ts +1 -1
- package/src/tool/svgToCss/i18n/fr.ts +1 -1
- package/src/tool/svgToCss/i18n/pl.ts +1 -1
- package/src/tool/svgToCss/i18n/ru.ts +2 -2
- package/src/tool/svgToCss/i18n/zh.ts +2 -2
- package/src/tool/svgToCss/seo.astro +2 -1
- package/src/tool/urlCleaner/component.astro +23 -5
- package/src/tool/urlCleaner/i18n/de.ts +3 -3
- package/src/tool/urlCleaner/i18n/es.ts +1 -1
- package/src/tool/urlCleaner/i18n/id.ts +1 -1
- package/src/tool/urlCleaner/i18n/nl.ts +1 -1
- package/src/tool/urlCleaner/seo.astro +2 -1
- package/src/tool/urlCleaner/url-tracking-cleaner.css +92 -2
- package/src/tool/urlEncoderDecoder/i18n/de.ts +5 -5
- package/src/tool/urlEncoderDecoder/i18n/fr.ts +2 -2
- package/src/tool/urlEncoderDecoder/i18n/pl.ts +5 -5
- package/src/tool/urlEncoderDecoder/i18n/ru.ts +8 -8
- package/src/tool/urlEncoderDecoder/i18n/sv.ts +5 -5
- package/src/tool/urlEncoderDecoder/i18n/zh.ts +5 -5
- package/src/tool/urlEncoderDecoder/seo.astro +2 -1
- package/src/tool/utmGenerator/i18n/de.ts +2 -2
- package/src/tool/utmGenerator/i18n/pl.ts +5 -5
- package/src/tool/utmGenerator/i18n/ru.ts +6 -6
- package/src/tool/utmGenerator/seo.astro +2 -1
- package/src/tools.ts +2 -2
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
---
|
|
2
|
+
import type { SerpPixelSimulatorUI } from './ui';
|
|
3
|
+
|
|
4
|
+
interface Props {
|
|
5
|
+
ui?: Record<string, unknown>;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
const { ui } = Astro.props;
|
|
9
|
+
const t = (ui ?? {}) as SerpPixelSimulatorUI;
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
<section class="tool-seo" aria-label={t.previewLabel}></section>
|
|
@@ -0,0 +1,335 @@
|
|
|
1
|
+
.sps-root {
|
|
2
|
+
--sps-ink: #1f2937;
|
|
3
|
+
--sps-muted: #64748b;
|
|
4
|
+
--sps-line: #d9e2ec;
|
|
5
|
+
--sps-panel: #fff;
|
|
6
|
+
--sps-soft: #f6f8fb;
|
|
7
|
+
--sps-ok: #16875d;
|
|
8
|
+
--sps-warn: #d93025;
|
|
9
|
+
|
|
10
|
+
color: var(--sps-ink);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
.theme-dark .sps-root {
|
|
14
|
+
--sps-ink: #e5edf7;
|
|
15
|
+
--sps-muted: #a8b5c6;
|
|
16
|
+
--sps-line: #2c3a4e;
|
|
17
|
+
--sps-panel: #111827;
|
|
18
|
+
--sps-soft: #0b1120;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
.sps-shell {
|
|
22
|
+
display: grid;
|
|
23
|
+
grid-template-columns: minmax(280px, 0.95fr) minmax(320px, 1.05fr);
|
|
24
|
+
gap: 24px;
|
|
25
|
+
align-items: start;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
.sps-card {
|
|
29
|
+
border: 1px solid var(--sps-line);
|
|
30
|
+
border-radius: 8px;
|
|
31
|
+
background: var(--sps-panel);
|
|
32
|
+
padding: 24px;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
.sps-panel,
|
|
36
|
+
.sps-preview-wrap {
|
|
37
|
+
min-width: 0;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
.sps-field {
|
|
41
|
+
display: grid;
|
|
42
|
+
gap: 8px;
|
|
43
|
+
margin-bottom: 18px;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
.sps-label,
|
|
47
|
+
.sps-device-label,
|
|
48
|
+
.sps-meter-top {
|
|
49
|
+
font-size: 0.86rem;
|
|
50
|
+
font-weight: 700;
|
|
51
|
+
color: #334155;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
.sps-input,
|
|
55
|
+
.sps-textarea {
|
|
56
|
+
width: 100%;
|
|
57
|
+
box-sizing: border-box;
|
|
58
|
+
border: 1px solid #cbd5e1;
|
|
59
|
+
border-radius: 6px;
|
|
60
|
+
padding: 10px 12px;
|
|
61
|
+
font-size: 15px;
|
|
62
|
+
line-height: 1.45;
|
|
63
|
+
color: #172033;
|
|
64
|
+
background: #fff;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
.sps-url-control {
|
|
68
|
+
display: flex;
|
|
69
|
+
align-items: stretch;
|
|
70
|
+
width: 100%;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
.sps-url-input {
|
|
74
|
+
min-width: 0;
|
|
75
|
+
border-top-right-radius: 0;
|
|
76
|
+
border-bottom-right-radius: 0;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
.sps-fetch-button {
|
|
80
|
+
flex: 0 0 auto;
|
|
81
|
+
border: 1px solid #cbd5e1;
|
|
82
|
+
border-left: 0;
|
|
83
|
+
border-radius: 0 6px 6px 0;
|
|
84
|
+
padding: 0 14px;
|
|
85
|
+
background: #174ea6;
|
|
86
|
+
color: #fff;
|
|
87
|
+
font-size: 0.88rem;
|
|
88
|
+
font-weight: 700;
|
|
89
|
+
line-height: 1;
|
|
90
|
+
cursor: pointer;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
.sps-fetch-button:disabled {
|
|
94
|
+
cursor: progress;
|
|
95
|
+
opacity: 0.72;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
.sps-fetch-message {
|
|
99
|
+
min-height: 1.2em;
|
|
100
|
+
margin: 0;
|
|
101
|
+
color: var(--sps-muted);
|
|
102
|
+
font-size: 0.82rem;
|
|
103
|
+
line-height: 1.4;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
.sps-fetch-message[data-tone='success'] {
|
|
107
|
+
color: var(--sps-ok);
|
|
108
|
+
font-weight: 700;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
.sps-fetch-message[data-tone='error'] {
|
|
112
|
+
color: var(--sps-warn);
|
|
113
|
+
font-weight: 700;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
.theme-dark .sps-input,
|
|
117
|
+
.theme-dark .sps-textarea,
|
|
118
|
+
.theme-dark .sps-segment button {
|
|
119
|
+
border-color: #334155;
|
|
120
|
+
background: #0f172a;
|
|
121
|
+
color: #e5edf7;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
.theme-dark .sps-fetch-button {
|
|
125
|
+
border-color: #334155;
|
|
126
|
+
background: #2563eb;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
.theme-dark .sps-label,
|
|
130
|
+
.theme-dark .sps-device-label,
|
|
131
|
+
.theme-dark .sps-meter-top,
|
|
132
|
+
.theme-dark .sps-preview-title {
|
|
133
|
+
color: #d6e1f0;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
.sps-textarea {
|
|
137
|
+
min-height: 108px;
|
|
138
|
+
resize: vertical;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
.sps-device {
|
|
142
|
+
display: flex;
|
|
143
|
+
align-items: center;
|
|
144
|
+
justify-content: space-between;
|
|
145
|
+
gap: 12px;
|
|
146
|
+
margin-bottom: 18px;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
.sps-segment {
|
|
150
|
+
display: inline-grid;
|
|
151
|
+
grid-template-columns: 1fr 1fr;
|
|
152
|
+
border: 1px solid #cbd5e1;
|
|
153
|
+
border-radius: 7px;
|
|
154
|
+
overflow: hidden;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
.sps-segment button {
|
|
158
|
+
border: 0;
|
|
159
|
+
border-right: 1px solid #cbd5e1;
|
|
160
|
+
background: #fff;
|
|
161
|
+
color: #334155;
|
|
162
|
+
padding: 8px 12px;
|
|
163
|
+
font-weight: 700;
|
|
164
|
+
cursor: pointer;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
.sps-segment button:last-child {
|
|
168
|
+
border-right: 0;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
.sps-segment button[aria-pressed='true'] {
|
|
172
|
+
background: #e8f0fe;
|
|
173
|
+
color: #174ea6;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
.theme-dark .sps-segment button[aria-pressed='true'] {
|
|
177
|
+
background: #1e3a5f;
|
|
178
|
+
color: #bfdbfe;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
.sps-meter {
|
|
182
|
+
display: grid;
|
|
183
|
+
gap: 7px;
|
|
184
|
+
margin-top: 14px;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
.sps-meter-top {
|
|
188
|
+
display: flex;
|
|
189
|
+
justify-content: space-between;
|
|
190
|
+
gap: 12px;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
.sps-track {
|
|
194
|
+
height: 10px;
|
|
195
|
+
border-radius: 999px;
|
|
196
|
+
background: #e5eaf1;
|
|
197
|
+
overflow: hidden;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
.sps-fill {
|
|
201
|
+
display: block;
|
|
202
|
+
width: 0%;
|
|
203
|
+
height: 100%;
|
|
204
|
+
border-radius: inherit;
|
|
205
|
+
background: var(--sps-ok);
|
|
206
|
+
transition: width 120ms ease, background-color 120ms ease;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
.sps-meter.sps-over .sps-fill {
|
|
210
|
+
background: var(--sps-warn);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
.sps-meter-status {
|
|
214
|
+
font-size: 0.82rem;
|
|
215
|
+
color: var(--sps-muted);
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
.sps-meter.sps-over .sps-meter-status {
|
|
219
|
+
color: var(--sps-warn);
|
|
220
|
+
font-weight: 700;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
.sps-preview-wrap {
|
|
224
|
+
border-left: 1px solid var(--sps-line);
|
|
225
|
+
background: var(--sps-soft);
|
|
226
|
+
border-radius: 8px;
|
|
227
|
+
padding: 24px;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
.sps-preview-title {
|
|
231
|
+
margin: 0 0 14px;
|
|
232
|
+
color: #334155;
|
|
233
|
+
font-size: 0.92rem;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
.sps-serp {
|
|
237
|
+
width: min(100%, 652px);
|
|
238
|
+
border-radius: 8px;
|
|
239
|
+
background: #fff;
|
|
240
|
+
padding: 18px;
|
|
241
|
+
font-family: Arial, Helvetica, sans-serif;
|
|
242
|
+
box-shadow: 0 1px 2px rgb(60, 64, 67, 0.14), 0 1px 3px 1px rgb(60, 64, 67, 0.08);
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
.theme-dark .sps-serp {
|
|
246
|
+
background: #f8fafc;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
.sps-serp.sps-mobile {
|
|
250
|
+
max-width: 390px;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
.sps-url-line {
|
|
254
|
+
display: flex;
|
|
255
|
+
align-items: center;
|
|
256
|
+
gap: 10px;
|
|
257
|
+
min-width: 0;
|
|
258
|
+
margin-bottom: 6px;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
.sps-favicon {
|
|
262
|
+
display: grid;
|
|
263
|
+
place-items: center;
|
|
264
|
+
width: 28px;
|
|
265
|
+
height: 28px;
|
|
266
|
+
flex: 0 0 auto;
|
|
267
|
+
border-radius: 50%;
|
|
268
|
+
background: #edf2f7;
|
|
269
|
+
color: #5f6368;
|
|
270
|
+
font-size: 14px;
|
|
271
|
+
font-weight: 700;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
.sps-favicon-image {
|
|
275
|
+
width: 28px;
|
|
276
|
+
height: 28px;
|
|
277
|
+
flex: 0 0 auto;
|
|
278
|
+
border-radius: 50%;
|
|
279
|
+
background: #edf2f7;
|
|
280
|
+
object-fit: contain;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
.sps-hidden {
|
|
284
|
+
display: none;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
.sps-url-text {
|
|
288
|
+
min-width: 0;
|
|
289
|
+
color: #202124;
|
|
290
|
+
font-size: 14px;
|
|
291
|
+
line-height: 1.3;
|
|
292
|
+
overflow: hidden;
|
|
293
|
+
text-overflow: ellipsis;
|
|
294
|
+
white-space: nowrap;
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
.sps-serp-title {
|
|
298
|
+
margin: 0 0 4px;
|
|
299
|
+
color: #1a0dab;
|
|
300
|
+
font-size: 20px;
|
|
301
|
+
line-height: 1.3;
|
|
302
|
+
font-weight: 400;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
.sps-description {
|
|
306
|
+
margin: 0;
|
|
307
|
+
color: #4d5156;
|
|
308
|
+
font-size: 14px;
|
|
309
|
+
line-height: 1.58;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
.sps-measure {
|
|
313
|
+
position: fixed;
|
|
314
|
+
inset: auto auto -9999px -9999px;
|
|
315
|
+
visibility: hidden;
|
|
316
|
+
white-space: nowrap;
|
|
317
|
+
pointer-events: none;
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
@media (max-width: 780px) {
|
|
321
|
+
.sps-shell {
|
|
322
|
+
grid-template-columns: 1fr;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
.sps-card {
|
|
326
|
+
padding: 16px;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
.sps-preview-wrap {
|
|
330
|
+
border-left: 0;
|
|
331
|
+
border-top: 1px solid var(--sps-line);
|
|
332
|
+
padding: 18px 0 0;
|
|
333
|
+
background: transparent;
|
|
334
|
+
}
|
|
335
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
export interface SerpPixelSimulatorUI extends Record<string, string> {
|
|
2
|
+
titleLabel: string;
|
|
3
|
+
titlePlaceholder: string;
|
|
4
|
+
urlLabel: string;
|
|
5
|
+
urlPlaceholder: string;
|
|
6
|
+
descriptionLabel: string;
|
|
7
|
+
descriptionPlaceholder: string;
|
|
8
|
+
deviceLabel: string;
|
|
9
|
+
desktopLabel: string;
|
|
10
|
+
mobileLabel: string;
|
|
11
|
+
titlePixelsLabel: string;
|
|
12
|
+
descriptionPixelsLabel: string;
|
|
13
|
+
charactersLabel: string;
|
|
14
|
+
previewLabel: string;
|
|
15
|
+
tooLongLabel: string;
|
|
16
|
+
goodLabel: string;
|
|
17
|
+
emptyTitle: string;
|
|
18
|
+
emptyDescription: string;
|
|
19
|
+
defaultTitle: string;
|
|
20
|
+
defaultUrl: string;
|
|
21
|
+
defaultDescription: string;
|
|
22
|
+
fallbackUrl: string;
|
|
23
|
+
fallbackFaviconText: string;
|
|
24
|
+
pixelUnit: string;
|
|
25
|
+
ellipsis: string;
|
|
26
|
+
fetchButtonLabel: string;
|
|
27
|
+
fetchLoadingLabel: string;
|
|
28
|
+
fetchSuccessLabel: string;
|
|
29
|
+
fetchCorsError: string;
|
|
30
|
+
fetchInvalidUrlError: string;
|
|
31
|
+
fetchNoMetadataError: string;
|
|
32
|
+
fetchGenericError: string;
|
|
33
|
+
}
|
|
@@ -31,7 +31,7 @@ const faqData = [
|
|
|
31
31
|
|
|
32
32
|
const howToData = [
|
|
33
33
|
{ name: 'SVG einfügen', text: 'Füge den SVG-Code aus Figma, Illustrator oder Inkscape in das Textfeld ein.' },
|
|
34
|
-
{ name: 'Optionen konfigurieren', text: 'Aktiviere oder deaktiviere die Optionen: IDs entfernen, width/height entfernen und minifizieren
|
|
34
|
+
{ name: 'Optionen konfigurieren', text: 'Aktiviere oder deaktiviere die Optionen: IDs entfernen, width/height entfernen und minifizieren - je nach Bedarf.' },
|
|
35
35
|
{ name: 'Bereinigen', text: 'Klicke auf SVG bereinigen, um den Code zu verarbeiten und das optimierte Ergebnis zu erhalten.' },
|
|
36
36
|
{ name: 'Kopieren oder herunterladen', text: 'Nutze die Schaltflächen Kopieren oder Herunterladen, um das bereinigte SVG für die Produktion zu sichern.' },
|
|
37
37
|
];
|
|
@@ -108,7 +108,7 @@ export const content: ToolLocaleContent<SvgSanitizerUI> = {
|
|
|
108
108
|
{ type: 'title', text: 'Warum sind exportierte SVGs so unordentlich?', level: 3 },
|
|
109
109
|
{
|
|
110
110
|
type: 'paragraph',
|
|
111
|
-
html: 'Wenn du ein SVG aus Figma exportierst, erhältst du eine Datei voller Attribute, die nur innerhalb der App einen Sinn ergeben: <code>data-name</code>, <code>xml:space</code>, Verweise auf interne Ebenen und Design-Metadaten. Das Ergebnis ist ein SVG, das 40
|
|
111
|
+
html: 'Wenn du ein SVG aus Figma exportierst, erhältst du eine Datei voller Attribute, die nur innerhalb der App einen Sinn ergeben: <code>data-name</code>, <code>xml:space</code>, Verweise auf interne Ebenen und Design-Metadaten. Das Ergebnis ist ein SVG, das 40-70 % größer als nötig sein kann.',
|
|
112
112
|
},
|
|
113
113
|
{ type: 'title', text: 'Was der Bereiniger entfernt', level: 3 },
|
|
114
114
|
{
|
|
@@ -108,7 +108,7 @@ export const content: ToolLocaleContent<SvgSanitizerUI> = {
|
|
|
108
108
|
{ type: 'title', text: 'Mengapa SVG yang diekspor begitu berantakan?', level: 3 },
|
|
109
109
|
{
|
|
110
110
|
type: 'paragraph',
|
|
111
|
-
html: 'Saat kamu mengekspor SVG dari Figma, kamu mendapatkan file yang penuh dengan atribut yang hanya bermakna di dalam aplikasinya: <code>data-name</code>, <code>xml:space</code>, referensi ke layer internal, dan metadata desain. Hasilnya adalah SVG yang bisa 40
|
|
111
|
+
html: 'Saat kamu mengekspor SVG dari Figma, kamu mendapatkan file yang penuh dengan atribut yang hanya bermakna di dalam aplikasinya: <code>data-name</code>, <code>xml:space</code>, referensi ke layer internal, dan metadata desain. Hasilnya adalah SVG yang bisa 40-70% lebih besar dari yang seharusnya.',
|
|
112
112
|
},
|
|
113
113
|
{ type: 'title', text: 'Apa yang dihapus oleh Pembersih', level: 3 },
|
|
114
114
|
{
|
|
@@ -108,7 +108,7 @@ export const content: ToolLocaleContent<SvgSanitizerUI> = {
|
|
|
108
108
|
{ type: 'title', text: 'Dlaczego wyeksportowane pliki SVG są takie brudne?', level: 3 },
|
|
109
109
|
{
|
|
110
110
|
type: 'paragraph',
|
|
111
|
-
html: 'Gdy eksportujesz SVG z Figmy, otrzymujesz plik wypełniony atrybutami, które mają sens tylko wewnątrz aplikacji: <code>data-name</code>, <code>xml:space</code>, odwołania do wewnętrznych warstw i metadane projektu. Efektem jest SVG, który może ważyć o 40
|
|
111
|
+
html: 'Gdy eksportujesz SVG z Figmy, otrzymujesz plik wypełniony atrybutami, które mają sens tylko wewnątrz aplikacji: <code>data-name</code>, <code>xml:space</code>, odwołania do wewnętrznych warstw i metadane projektu. Efektem jest SVG, który może ważyć o 40-70% więcej niż powinien.',
|
|
112
112
|
},
|
|
113
113
|
{ type: 'title', text: 'Co usuwa oczyszczacz', level: 3 },
|
|
114
114
|
{
|
|
@@ -13,7 +13,7 @@ const faqData = [
|
|
|
13
13
|
},
|
|
14
14
|
{
|
|
15
15
|
question: 'Работает ли это с SVG из Illustrator?',
|
|
16
|
-
answer: 'Да. Illustrator экспортирует SVG с XML-объявлениями, метаданными и собственными пространствами имён, которые очиститель удаляет. Результат
|
|
16
|
+
answer: 'Да. Illustrator экспортирует SVG с XML-объявлениями, метаданными и собственными пространствами имён, которые очиститель удаляет. Результат - это SVG, совместимый со всеми современными браузерами.',
|
|
17
17
|
},
|
|
18
18
|
{
|
|
19
19
|
question: 'Какая разница между очисткой и минификацией?',
|
|
@@ -21,7 +21,7 @@ const faqData = [
|
|
|
21
21
|
},
|
|
22
22
|
{
|
|
23
23
|
question: 'Может ли удаление ID-элементов повредить SVG?',
|
|
24
|
-
answer: 'Только если элемент в SVG ссылается на другой по ID, например через fill="url(#gradient)". В этом случае отключите опцию
|
|
24
|
+
answer: 'Только если элемент в SVG ссылается на другой по ID, например через fill="url(#gradient)". В этом случае отключите опцию "Удалить ID". Она отключена по умолчанию именно чтобы избежать этой проблемы.',
|
|
25
25
|
},
|
|
26
26
|
{
|
|
27
27
|
question: 'Передаётся ли код SVG на какой-нибудь сервер?',
|
|
@@ -32,7 +32,7 @@ const faqData = [
|
|
|
32
32
|
const howToData = [
|
|
33
33
|
{ name: 'Вставьте SVG', text: 'Вставьте код SVG, экспортированный из Figma, Illustrator или Inkscape, в текстовое поле.' },
|
|
34
34
|
{ name: 'Настройте параметры', text: 'Включите или отключите опции: удалить ID, убрать ширину/высоту и минифицировать в зависимости от ваших нужд.' },
|
|
35
|
-
{ name: 'Очистите', text: 'Нажмите
|
|
35
|
+
{ name: 'Очистите', text: 'Нажмите "Очистить SVG", чтобы обработать код и получить оптимизированный результат.' },
|
|
36
36
|
{ name: 'Скопируйте или скачайте', text: 'Используйте кнопки копирования или загрузки, чтобы получить чистый SVG, готовый для продакшена.' },
|
|
37
37
|
];
|
|
38
38
|
|
|
@@ -93,9 +93,9 @@ export const content: ToolLocaleContent<SvgSanitizerUI> = {
|
|
|
93
93
|
faq: faqData,
|
|
94
94
|
bibliographyTitle: 'Ссылки',
|
|
95
95
|
bibliography: [
|
|
96
|
-
{ name: 'SVG Specification
|
|
97
|
-
{ name: 'Figma SVG Export
|
|
98
|
-
{ name: 'SVGO
|
|
96
|
+
{ name: 'SVG Specification - W3C', url: 'https://www.w3.org/TR/SVG2/' },
|
|
97
|
+
{ name: 'Figma SVG Export - Official Documentation', url: 'https://help.figma.com/hc/en-us/articles/360040028114-Export-from-Figma' },
|
|
98
|
+
{ name: 'SVGO - SVG Optimizer (open source reference)', url: 'https://github.com/svg/svgo' },
|
|
99
99
|
],
|
|
100
100
|
howTo: howToData,
|
|
101
101
|
schemas: [faqSchema, howToSchema, appSchema],
|
|
@@ -108,7 +108,7 @@ export const content: ToolLocaleContent<SvgSanitizerUI> = {
|
|
|
108
108
|
{ type: 'title', text: 'Почему экспортированные SVG такие грязные?', level: 3 },
|
|
109
109
|
{
|
|
110
110
|
type: 'paragraph',
|
|
111
|
-
html: 'Когда вы экспортируете SVG из Figma, вы получаете файл, перегруженный атрибутами, которые имеют смысл только внутри приложения: <code>data-name</code>, <code>xml:space</code>, ссылки на внутренние слои и метаданные дизайна. Результат
|
|
111
|
+
html: 'Когда вы экспортируете SVG из Figma, вы получаете файл, перегруженный атрибутами, которые имеют смысл только внутри приложения: <code>data-name</code>, <code>xml:space</code>, ссылки на внутренние слои и метаданные дизайна. Результат - это SVG, весящий на 40-70% больше необходимого.',
|
|
112
112
|
},
|
|
113
113
|
{ type: 'title', text: 'Что удаляет очиститель', level: 3 },
|
|
114
114
|
{
|
|
@@ -93,9 +93,9 @@ export const content: ToolLocaleContent<SvgSanitizerUI> = {
|
|
|
93
93
|
faq: faqData,
|
|
94
94
|
bibliographyTitle: 'Referenser',
|
|
95
95
|
bibliography: [
|
|
96
|
-
{ name: 'SVG Specification
|
|
97
|
-
{ name: 'Figma SVG Export
|
|
98
|
-
{ name: 'SVGO
|
|
96
|
+
{ name: 'SVG Specification - W3C', url: 'https://www.w3.org/TR/SVG2/' },
|
|
97
|
+
{ name: 'Figma SVG Export - Official Documentation', url: 'https://help.figma.com/hc/en-us/articles/360040028114-Export-from-Figma' },
|
|
98
|
+
{ name: 'SVGO - SVG Optimizer (open source reference)', url: 'https://github.com/svg/svgo' },
|
|
99
99
|
],
|
|
100
100
|
howTo: howToData,
|
|
101
101
|
schemas: [faqSchema, howToSchema, appSchema],
|
|
@@ -93,9 +93,9 @@ export const content: ToolLocaleContent<SvgSanitizerUI> = {
|
|
|
93
93
|
faq: faqData,
|
|
94
94
|
bibliographyTitle: 'Referanslar',
|
|
95
95
|
bibliography: [
|
|
96
|
-
{ name: 'SVG Specification
|
|
97
|
-
{ name: 'Figma SVG Export
|
|
98
|
-
{ name: 'SVGO
|
|
96
|
+
{ name: 'SVG Specification - W3C', url: 'https://www.w3.org/TR/SVG2/' },
|
|
97
|
+
{ name: 'Figma SVG Export - Official Documentation', url: 'https://help.figma.com/hc/en-us/articles/360040028114-Export-from-Figma' },
|
|
98
|
+
{ name: 'SVGO - SVG Optimizer (open source reference)', url: 'https://github.com/svg/svgo' },
|
|
99
99
|
],
|
|
100
100
|
howTo: howToData,
|
|
101
101
|
schemas: [faqSchema, howToSchema, appSchema],
|
|
@@ -93,9 +93,9 @@ export const content: ToolLocaleContent<SvgSanitizerUI> = {
|
|
|
93
93
|
faq: faqData,
|
|
94
94
|
bibliographyTitle: '参考资料',
|
|
95
95
|
bibliography: [
|
|
96
|
-
{ name: 'SVG Specification
|
|
97
|
-
{ name: 'Figma SVG Export
|
|
98
|
-
{ name: 'SVGO
|
|
96
|
+
{ name: 'SVG Specification - W3C', url: 'https://www.w3.org/TR/SVG2/' },
|
|
97
|
+
{ name: 'Figma SVG Export - Official Documentation', url: 'https://help.figma.com/hc/en-us/articles/360040028114-Export-from-Figma' },
|
|
98
|
+
{ name: 'SVGO - SVG Optimizer (open source reference)', url: 'https://github.com/svg/svgo' },
|
|
99
99
|
],
|
|
100
100
|
howTo: howToData,
|
|
101
101
|
schemas: [faqSchema, howToSchema, appSchema],
|
|
@@ -9,6 +9,7 @@ interface Props {
|
|
|
9
9
|
|
|
10
10
|
const { locale = 'es' } = Astro.props;
|
|
11
11
|
const content = await svgSanitizer.i18n[locale]?.();
|
|
12
|
+
if (!content) return null;
|
|
12
13
|
---
|
|
13
14
|
|
|
14
|
-
{content && <SEORenderer content={{ locale, sections: content.seo }} />}
|
|
15
|
+
{content.seo?.length > 0 && <SEORenderer content={{ locale, sections: content.seo }} />}
|
|
@@ -16,7 +16,7 @@ const faqData = [
|
|
|
16
16
|
{
|
|
17
17
|
question: 'Wie ändere ich die Farbe eines in CSS eingebetteten SVGs?',
|
|
18
18
|
answer:
|
|
19
|
-
'Der beste Weg ist über
|
|
19
|
+
'Der beste Weg ist über "mask-image". Indem Sie das SVG als Maske definieren, können Sie die "background-color" verwenden, um die Farbe dynamisch zu ändern, sogar in :hover-Zuständen.',
|
|
20
20
|
},
|
|
21
21
|
{
|
|
22
22
|
question: 'Welche Browser unterstützen CSS-Masken?',
|
|
@@ -46,7 +46,7 @@ const howToData = [
|
|
|
46
46
|
},
|
|
47
47
|
{
|
|
48
48
|
name: 'Ergebnis kopieren',
|
|
49
|
-
text: 'Klicken Sie auf
|
|
49
|
+
text: 'Klicken Sie auf "Kopieren", um den generierten CSS-Code in Ihre Zwischenablage zu übernehmen.',
|
|
50
50
|
},
|
|
51
51
|
{
|
|
52
52
|
name: 'In Ihr Projekt übernehmen',
|
|
@@ -9,7 +9,7 @@ const description =
|
|
|
9
9
|
|
|
10
10
|
const faqData = [
|
|
11
11
|
{
|
|
12
|
-
question: '¿Es mejor usar Data URI o un archivo
|
|
12
|
+
question: '¿Es mejor usar Data URI o un archivo SVG externo?',
|
|
13
13
|
answer:
|
|
14
14
|
'Depende del uso. Los Data URIs eliminan peticiones HTTP (ideal para iconos pequeños), pero aumentan el tamaño del CSS. Para ilustraciones grandes o ricas en detalles, es preferible un archivo externo.',
|
|
15
15
|
},
|
|
@@ -164,7 +164,7 @@ export const content: ToolLocaleContent<SvgToCssUI> = {
|
|
|
164
164
|
},
|
|
165
165
|
{
|
|
166
166
|
type: 'paragraph',
|
|
167
|
-
html: "Beaucoup de développeurs utilisent simplement <code>background-image</code> pour intégrer des vecteurs, mais cela a une limitation
|
|
167
|
+
html: "Beaucoup de développeurs utilisent simplement <code>background-image</code> pour intégrer des vecteurs, mais cela a une limitation: vous ne pouvez pas changer la couleur du SVG dynamiquement depuis le CSS.",
|
|
168
168
|
},
|
|
169
169
|
{
|
|
170
170
|
type: 'paragraph',
|
|
@@ -16,7 +16,7 @@ const faqData = [
|
|
|
16
16
|
{
|
|
17
17
|
question: 'Как изменить цвет SVG, встроенного в CSS?',
|
|
18
18
|
answer:
|
|
19
|
-
"Лучший способ
|
|
19
|
+
"Лучший способ - через 'mask-image'. Определив SVG как маску, вы можете использовать 'background-color' для динамического изменения его цвета, даже в состояниях :hover.",
|
|
20
20
|
},
|
|
21
21
|
{
|
|
22
22
|
question: ' какие браузеры поддерживают CSS Masks?',
|
|
@@ -46,7 +46,7 @@ const howToData = [
|
|
|
46
46
|
},
|
|
47
47
|
{
|
|
48
48
|
name: 'Скопируйте результат',
|
|
49
|
-
text: 'Нажмите
|
|
49
|
+
text: 'Нажмите "Копировать", чтобы перенести сгенерированный CSS-код в буфер обмена.',
|
|
50
50
|
},
|
|
51
51
|
{
|
|
52
52
|
name: 'Примените в своем проекте',
|
|
@@ -16,7 +16,7 @@ const faqData = [
|
|
|
16
16
|
{
|
|
17
17
|
question: '如何更改嵌入 CSS 的 SVG 的颜色?',
|
|
18
18
|
answer:
|
|
19
|
-
'
|
|
19
|
+
'最好的方法是通过"mask-image"。通过将 SVG 定义为遮罩(mask),您可以使用"background-color"动态更改其颜色,甚至在 :hover 状态下也可以。',
|
|
20
20
|
},
|
|
21
21
|
{
|
|
22
22
|
question: '哪些浏览器支持 CSS 遮罩(Masks)?',
|
|
@@ -46,7 +46,7 @@ const howToData = [
|
|
|
46
46
|
},
|
|
47
47
|
{
|
|
48
48
|
name: '复制结果',
|
|
49
|
-
text: '
|
|
49
|
+
text: '点击"复制"将生成的 CSS 代码获取到剪贴板中。',
|
|
50
50
|
},
|
|
51
51
|
{
|
|
52
52
|
name: '在项目中使用',
|
|
@@ -9,6 +9,7 @@ interface Props {
|
|
|
9
9
|
|
|
10
10
|
const { locale = 'es' } = Astro.props;
|
|
11
11
|
const content = await svgToCss.i18n[locale]?.();
|
|
12
|
+
if (!content) return null;
|
|
12
13
|
---
|
|
13
14
|
|
|
14
|
-
{content && <SEORenderer content={{ locale, sections: content.seo }} />}
|
|
15
|
+
{content.seo?.length > 0 && <SEORenderer content={{ locale, sections: content.seo }} />}
|