@jjlmoya/utils-textiles 1.1.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.
Files changed (134) hide show
  1. package/package.json +60 -0
  2. package/src/category/i18n/en.ts +76 -0
  3. package/src/category/i18n/es.ts +76 -0
  4. package/src/category/i18n/fr.ts +73 -0
  5. package/src/category/index.ts +17 -0
  6. package/src/category/seo.astro +15 -0
  7. package/src/components/PreviewNavSidebar.astro +116 -0
  8. package/src/components/PreviewToolbar.astro +143 -0
  9. package/src/data.ts +11 -0
  10. package/src/env.d.ts +5 -0
  11. package/src/index.ts +32 -0
  12. package/src/layouts/PreviewLayout.astro +117 -0
  13. package/src/pages/[locale]/[slug].astro +146 -0
  14. package/src/pages/[locale].astro +253 -0
  15. package/src/pages/index.astro +4 -0
  16. package/src/tests/faq_count.test.ts +19 -0
  17. package/src/tests/locale_completeness.test.ts +42 -0
  18. package/src/tests/mocks/astro_mock.js +2 -0
  19. package/src/tests/no_h1_in_components.test.ts +48 -0
  20. package/src/tests/seo_length.test.ts +22 -0
  21. package/src/tests/title_separators.test.ts +40 -0
  22. package/src/tests/tool_validation.test.ts +17 -0
  23. package/src/tool/burnTest/bibliography.astro +34 -0
  24. package/src/tool/burnTest/component.astro +602 -0
  25. package/src/tool/burnTest/i18n/en.ts +225 -0
  26. package/src/tool/burnTest/i18n/es.ts +225 -0
  27. package/src/tool/burnTest/i18n/fr.ts +225 -0
  28. package/src/tool/burnTest/index.ts +34 -0
  29. package/src/tool/burnTest/logic.ts +3 -0
  30. package/src/tool/burnTest/seo.astro +40 -0
  31. package/src/tool/burnTest/ui.ts +36 -0
  32. package/src/tool/clothingSizeConverter/bibliography.astro +34 -0
  33. package/src/tool/clothingSizeConverter/component.astro +1226 -0
  34. package/src/tool/clothingSizeConverter/i18n/en.ts +356 -0
  35. package/src/tool/clothingSizeConverter/i18n/es.ts +356 -0
  36. package/src/tool/clothingSizeConverter/i18n/fr.ts +356 -0
  37. package/src/tool/clothingSizeConverter/index.ts +34 -0
  38. package/src/tool/clothingSizeConverter/logic.ts +30 -0
  39. package/src/tool/clothingSizeConverter/seo.astro +40 -0
  40. package/src/tool/clothingSizeConverter/ui.ts +70 -0
  41. package/src/tool/fabricProjectCalculator/bibliography.astro +19 -0
  42. package/src/tool/fabricProjectCalculator/component.astro +914 -0
  43. package/src/tool/fabricProjectCalculator/i18n/en.ts +250 -0
  44. package/src/tool/fabricProjectCalculator/i18n/es.ts +250 -0
  45. package/src/tool/fabricProjectCalculator/i18n/fr.ts +250 -0
  46. package/src/tool/fabricProjectCalculator/index.ts +34 -0
  47. package/src/tool/fabricProjectCalculator/logic.ts +89 -0
  48. package/src/tool/fabricProjectCalculator/seo.astro +40 -0
  49. package/src/tool/fabricProjectCalculator/ui.ts +57 -0
  50. package/src/tool/fabricTruth/bibliography.astro +40 -0
  51. package/src/tool/fabricTruth/component.astro +708 -0
  52. package/src/tool/fabricTruth/i18n/en.ts +282 -0
  53. package/src/tool/fabricTruth/i18n/es.ts +316 -0
  54. package/src/tool/fabricTruth/i18n/fr.ts +282 -0
  55. package/src/tool/fabricTruth/index.ts +34 -0
  56. package/src/tool/fabricTruth/logic.ts +91 -0
  57. package/src/tool/fabricTruth/seo.astro +40 -0
  58. package/src/tool/fabricTruth/ui.ts +28 -0
  59. package/src/tool/fiberPrep/bibliography.astro +33 -0
  60. package/src/tool/fiberPrep/component.astro +987 -0
  61. package/src/tool/fiberPrep/i18n/en.ts +225 -0
  62. package/src/tool/fiberPrep/i18n/es.ts +225 -0
  63. package/src/tool/fiberPrep/i18n/fr.ts +225 -0
  64. package/src/tool/fiberPrep/index.ts +34 -0
  65. package/src/tool/fiberPrep/logic.ts +36 -0
  66. package/src/tool/fiberPrep/seo.astro +40 -0
  67. package/src/tool/fiberPrep/ui.ts +38 -0
  68. package/src/tool/knittingGauge/bibliography.astro +14 -0
  69. package/src/tool/knittingGauge/component.astro +828 -0
  70. package/src/tool/knittingGauge/i18n/en.ts +234 -0
  71. package/src/tool/knittingGauge/i18n/es.ts +234 -0
  72. package/src/tool/knittingGauge/i18n/fr.ts +234 -0
  73. package/src/tool/knittingGauge/index.ts +34 -0
  74. package/src/tool/knittingGauge/logic.ts +28 -0
  75. package/src/tool/knittingGauge/seo.astro +40 -0
  76. package/src/tool/knittingGauge/ui.ts +41 -0
  77. package/src/tool/laundryGuide/bibliography.astro +33 -0
  78. package/src/tool/laundryGuide/component.astro +486 -0
  79. package/src/tool/laundryGuide/data-en.ts +166 -0
  80. package/src/tool/laundryGuide/data-es.ts +166 -0
  81. package/src/tool/laundryGuide/data-fr.ts +103 -0
  82. package/src/tool/laundryGuide/i18n/en.ts +275 -0
  83. package/src/tool/laundryGuide/i18n/es.ts +275 -0
  84. package/src/tool/laundryGuide/i18n/fr.ts +291 -0
  85. package/src/tool/laundryGuide/index.ts +29 -0
  86. package/src/tool/laundryGuide/logic.ts +19 -0
  87. package/src/tool/laundryGuide/seo.astro +40 -0
  88. package/src/tool/needleConverter/bibliography.astro +14 -0
  89. package/src/tool/needleConverter/component.astro +518 -0
  90. package/src/tool/needleConverter/i18n/en.ts +217 -0
  91. package/src/tool/needleConverter/i18n/es.ts +217 -0
  92. package/src/tool/needleConverter/i18n/fr.ts +217 -0
  93. package/src/tool/needleConverter/index.ts +34 -0
  94. package/src/tool/needleConverter/logic.ts +31 -0
  95. package/src/tool/needleConverter/seo.astro +15 -0
  96. package/src/tool/needleConverter/ui.ts +17 -0
  97. package/src/tool/sewingPatternScaler/bibliography.astro +14 -0
  98. package/src/tool/sewingPatternScaler/component.astro +550 -0
  99. package/src/tool/sewingPatternScaler/i18n/en.ts +196 -0
  100. package/src/tool/sewingPatternScaler/i18n/es.ts +231 -0
  101. package/src/tool/sewingPatternScaler/i18n/fr.ts +187 -0
  102. package/src/tool/sewingPatternScaler/index.ts +34 -0
  103. package/src/tool/sewingPatternScaler/logic.ts +35 -0
  104. package/src/tool/sewingPatternScaler/seo.astro +49 -0
  105. package/src/tool/sewingPatternScaler/ui.ts +29 -0
  106. package/src/tool/shoeSizeConverter/bibliography.astro +34 -0
  107. package/src/tool/shoeSizeConverter/component.astro +437 -0
  108. package/src/tool/shoeSizeConverter/i18n/en.ts +188 -0
  109. package/src/tool/shoeSizeConverter/i18n/es.ts +188 -0
  110. package/src/tool/shoeSizeConverter/i18n/fr.ts +188 -0
  111. package/src/tool/shoeSizeConverter/index.ts +34 -0
  112. package/src/tool/shoeSizeConverter/logic.ts +8 -0
  113. package/src/tool/shoeSizeConverter/seo.astro +40 -0
  114. package/src/tool/shoeSizeConverter/ui.ts +21 -0
  115. package/src/tool/stainChemistry/bibliography.astro +40 -0
  116. package/src/tool/stainChemistry/component.astro +717 -0
  117. package/src/tool/stainChemistry/i18n/en.ts +303 -0
  118. package/src/tool/stainChemistry/i18n/es.ts +300 -0
  119. package/src/tool/stainChemistry/i18n/fr.ts +310 -0
  120. package/src/tool/stainChemistry/index.ts +34 -0
  121. package/src/tool/stainChemistry/logic.ts +11 -0
  122. package/src/tool/stainChemistry/seo.astro +40 -0
  123. package/src/tool/stainChemistry/ui.ts +51 -0
  124. package/src/tool/yarnCalculator/bibliography.astro +19 -0
  125. package/src/tool/yarnCalculator/component.astro +792 -0
  126. package/src/tool/yarnCalculator/i18n/en.ts +310 -0
  127. package/src/tool/yarnCalculator/i18n/es.ts +310 -0
  128. package/src/tool/yarnCalculator/i18n/fr.ts +310 -0
  129. package/src/tool/yarnCalculator/index.ts +34 -0
  130. package/src/tool/yarnCalculator/logic.ts +84 -0
  131. package/src/tool/yarnCalculator/seo.astro +14 -0
  132. package/src/tool/yarnCalculator/ui.ts +42 -0
  133. package/src/tools.ts +16 -0
  134. package/src/types.ts +72 -0
@@ -0,0 +1,486 @@
1
+ ---
2
+ import { Icon } from 'astro-icon/components';
3
+ import type { TextileData } from './logic';
4
+
5
+ interface Props {
6
+ ui?: Record<string, unknown>;
7
+ }
8
+
9
+ const { ui = {} } = Astro.props;
10
+ const textileData = (ui.textileData as Record<string, TextileData>) ?? {};
11
+ const fibers = Object.entries(textileData).map(([id, data]) => ({ id, ...data }));
12
+ ---
13
+
14
+ <div class="laundry-guide-container" id="laundry-guide-root">
15
+ <div class="guide-wrapper">
16
+ <div class="fibers-sidebar">
17
+ <h2 class="sidebar-title">
18
+ <Icon name="mdi:washing-machine" />
19
+ {ui.selectMaterialTitle || 'Select Fabric'}
20
+ </h2>
21
+ <div class="fibers-grid" id="fibers-list">
22
+ {fibers.map((fiber) => (
23
+ <button
24
+ class="fiber-btn"
25
+ data-fiber-id={fiber.id}
26
+ style={`--fiber-color: ${fiber.color}`}
27
+ >
28
+ <Icon name={fiber.icon} class="fiber-icon" />
29
+ <span class="fiber-name">{fiber.name}</span>
30
+ </button>
31
+ ))}
32
+ </div>
33
+ </div>
34
+
35
+ <div class="guide-main">
36
+ <div id="welcome-state" class="welcome-message">
37
+ <Icon name="mdi:washing-machine" class="welcome-icon" />
38
+ <h3>{ui.selectMaterialPrompt || 'Select a fabric to see care instructions'}</h3>
39
+ </div>
40
+
41
+ <div id="care-state" class="care-display hidden">
42
+ <div class="care-header">
43
+ <div class="header-icon-bg">
44
+ <Icon id="header-icon" name="mdi:sheep" class="header-icon" />
45
+ </div>
46
+ <div class="header-text">
47
+ <h3 id="fiber-name">Wool</h3>
48
+ <p>{ui.careInstructions || 'Premium care instructions'}</p>
49
+ </div>
50
+ </div>
51
+
52
+ <div class="care-grid">
53
+ <div class="care-card">
54
+ <Icon name="mdi:thermometer" class="care-icon" />
55
+ <span class="care-label">{ui.maxTemp || 'Max Temp'}</span>
56
+ <span id="max-temp" class="care-value">30°C</span>
57
+ </div>
58
+
59
+ <div class="care-card">
60
+ <Icon name="mdi:iron" class="care-icon" />
61
+ <span class="care-label">{ui.ironing || 'Ironing'}</span>
62
+ <span id="ironing-info" class="care-value">Low</span>
63
+ </div>
64
+
65
+ <div class="care-card">
66
+ <Icon name="mdi:weather-sunny" class="care-icon" />
67
+ <span class="care-label">{ui.drying || 'Drying'}</span>
68
+ <span id="drying-info" class="care-value">Flat</span>
69
+ </div>
70
+ </div>
71
+
72
+ <div class="care-sections">
73
+ <div class="care-section">
74
+ <h4 class="section-title avoid-title">
75
+ <Icon name="mdi:close-octagon" />
76
+ {ui.avoidLabel || 'Things to AVOID'}
77
+ </h4>
78
+ <ul id="donts-list" class="dont-list"></ul>
79
+ </div>
80
+
81
+ <div class="care-section sos-section">
82
+ <h4 class="section-title sos-title">
83
+ <Icon name="mdi:lightbulb-outline" />
84
+ {ui.sosLabel || 'Maintenance Tip'}
85
+ </h4>
86
+ <p id="sos-info" class="sos-text">Tips will appear here</p>
87
+ </div>
88
+ </div>
89
+
90
+ <div class="description-box">
91
+ <p id="fiber-description"></p>
92
+ </div>
93
+ </div>
94
+ </div>
95
+ </div>
96
+ </div>
97
+
98
+ <script define:vars={{ textileData }} is:inline>
99
+ window.__textileData = textileData;
100
+ </script>
101
+
102
+ <script>
103
+ import type { TextileData } from './logic';
104
+
105
+ function setText(id: string, value: string) {
106
+ const el = document.getElementById(id);
107
+ if (el) el.textContent = value;
108
+ }
109
+
110
+ function renderFiberIcon(data: TextileData) {
111
+ const fIcon = document.getElementById('header-icon');
112
+ if (!fIcon) return;
113
+ fIcon.setAttribute('name', data.icon);
114
+ (fIcon as HTMLElement).style.color = data.color;
115
+ }
116
+
117
+ function renderDonts(data: TextileData) {
118
+ const fDonts = document.getElementById('donts-list');
119
+ if (!fDonts) return;
120
+ fDonts.innerHTML = data.donts
121
+ .map((d: string) => `<li><span class="dont-bullet"></span>${d}</li>`)
122
+ .join('');
123
+ }
124
+
125
+ function updateCareUI(data: TextileData) {
126
+ document.getElementById('welcome-state')?.classList.add('hidden');
127
+ document.getElementById('care-state')?.classList.remove('hidden');
128
+ renderFiberIcon(data);
129
+ setText('fiber-name', data.name);
130
+ setText('max-temp', data.maxTemp);
131
+ setText('ironing-info', data.ironing);
132
+ setText('drying-info', data.drying);
133
+ setText('sos-info', data.sos);
134
+ setText('fiber-description', data.description);
135
+ renderDonts(data);
136
+ }
137
+
138
+ function initLaundryGuide() {
139
+ const root = document.getElementById('laundry-guide-root');
140
+ if (!root) return;
141
+
142
+ const textileData = (window as unknown as { __textileData: Record<string, TextileData> }).__textileData;
143
+ const fiberBtns = document.querySelectorAll('.fiber-btn');
144
+
145
+ fiberBtns.forEach((btn) => {
146
+ btn.addEventListener('click', () => {
147
+ const id = btn.getAttribute('data-fiber-id');
148
+ if (!id || !textileData[id]) return;
149
+
150
+ fiberBtns.forEach((b) => b.classList.remove('active'));
151
+ btn.classList.add('active');
152
+
153
+ updateCareUI(textileData[id]);
154
+ });
155
+ });
156
+ }
157
+
158
+ function startInit() {
159
+ if (document.readyState === 'loading') {
160
+ document.addEventListener('DOMContentLoaded', initLaundryGuide);
161
+ } else {
162
+ setTimeout(initLaundryGuide, 100);
163
+ }
164
+ document.addEventListener('astro:page-load', initLaundryGuide);
165
+ }
166
+
167
+ startInit();
168
+ </script>
169
+
170
+ <style>
171
+ .laundry-guide-container {
172
+ width: 100%;
173
+ padding: 1rem;
174
+ }
175
+
176
+ .guide-wrapper {
177
+ display: grid;
178
+ grid-template-columns: 250px 1fr;
179
+ gap: 2rem;
180
+ background: var(--bg-surface);
181
+ border: 1px solid var(--border-color);
182
+ border-radius: 1.5rem;
183
+ overflow: hidden;
184
+ box-shadow: 0 10px 25px rgba(0, 0, 0, 0.1);
185
+ }
186
+
187
+ .fibers-sidebar {
188
+ padding: 2rem;
189
+ border-right: 1px solid var(--border-color);
190
+ background: var(--bg-page);
191
+ }
192
+
193
+ .sidebar-title {
194
+ font-size: 0.9rem;
195
+ font-weight: 700;
196
+ text-transform: uppercase;
197
+ letter-spacing: 0.05em;
198
+ color: var(--text-muted);
199
+ margin: 0 0 1.5rem;
200
+ display: flex;
201
+ align-items: center;
202
+ gap: 0.5rem;
203
+ }
204
+
205
+ .sidebar-title svg {
206
+ width: 1rem;
207
+ height: 1rem;
208
+ }
209
+
210
+ .fibers-grid {
211
+ display: flex;
212
+ flex-direction: column;
213
+ gap: 0.75rem;
214
+ }
215
+
216
+ .fiber-btn {
217
+ display: flex;
218
+ align-items: center;
219
+ gap: 0.75rem;
220
+ padding: 0.75rem;
221
+ background: var(--bg-surface);
222
+ border: 1px solid var(--border-color);
223
+ border-radius: 0.75rem;
224
+ color: var(--text-main);
225
+ cursor: pointer;
226
+ transition: all 0.2s;
227
+ }
228
+
229
+ .fiber-btn:hover {
230
+ border-color: #6366f1;
231
+ background: rgba(99, 102, 241, 0.05);
232
+ }
233
+
234
+ .fiber-btn.active {
235
+ background: rgba(99, 102, 241, 0.1);
236
+ border-color: #6366f1;
237
+ font-weight: 600;
238
+ }
239
+
240
+ .fiber-icon {
241
+ width: 1.5rem;
242
+ height: 1.5rem;
243
+ color: var(--fiber-color);
244
+ }
245
+
246
+ .fiber-name {
247
+ font-size: 0.9rem;
248
+ text-align: left;
249
+ flex: 1;
250
+ }
251
+
252
+ .guide-main {
253
+ padding: 2rem;
254
+ display: flex;
255
+ align-items: center;
256
+ justify-content: center;
257
+ }
258
+
259
+ .welcome-message {
260
+ text-align: center;
261
+ color: var(--text-muted);
262
+ }
263
+
264
+ .welcome-message.hidden {
265
+ display: none;
266
+ }
267
+
268
+ .welcome-icon {
269
+ width: 5rem;
270
+ height: 5rem;
271
+ color: var(--border-color);
272
+ margin-bottom: 1rem;
273
+ }
274
+
275
+ .welcome-message h3 {
276
+ font-size: 1.5rem;
277
+ margin: 0;
278
+ color: var(--text-muted);
279
+ }
280
+
281
+ .care-display {
282
+ width: 100%;
283
+ max-width: 600px;
284
+ animation: fade-in 0.3s ease;
285
+ }
286
+
287
+ .care-display.hidden {
288
+ display: none;
289
+ }
290
+
291
+ @keyframes fade-in {
292
+ from { opacity: 0; }
293
+ to { opacity: 1; }
294
+ }
295
+
296
+ .care-header {
297
+ background: linear-gradient(135deg, #6366f1 0%, #8b5cf6 100%);
298
+ color: white;
299
+ padding: 2rem;
300
+ border-radius: 1rem;
301
+ display: flex;
302
+ align-items: center;
303
+ gap: 1.5rem;
304
+ margin-bottom: 2rem;
305
+ }
306
+
307
+ .header-icon-bg {
308
+ background: rgba(255, 255, 255, 0.2);
309
+ padding: 1rem;
310
+ border-radius: 0.75rem;
311
+ backdrop-filter: blur(10px);
312
+ }
313
+
314
+ .header-icon {
315
+ width: 2.5rem;
316
+ height: 2.5rem;
317
+ color: white;
318
+ }
319
+
320
+ .header-text h3 {
321
+ font-size: 1.75rem;
322
+ margin: 0 0 0.25rem;
323
+ font-weight: 900;
324
+ }
325
+
326
+ .header-text p {
327
+ margin: 0;
328
+ opacity: 0.9;
329
+ font-weight: 500;
330
+ }
331
+
332
+ .care-grid {
333
+ display: grid;
334
+ grid-template-columns: repeat(3, 1fr);
335
+ gap: 1rem;
336
+ margin-bottom: 2rem;
337
+ }
338
+
339
+ .care-card {
340
+ background: var(--bg-page);
341
+ padding: 1.5rem;
342
+ border-radius: 0.75rem;
343
+ border: 1px solid var(--border-color);
344
+ text-align: center;
345
+ }
346
+
347
+ .care-icon {
348
+ width: 2rem;
349
+ height: 2rem;
350
+ color: #3b82f6;
351
+ margin-bottom: 0.75rem;
352
+ }
353
+
354
+ .care-label {
355
+ display: block;
356
+ font-size: 0.75rem;
357
+ font-weight: 700;
358
+ text-transform: uppercase;
359
+ letter-spacing: 0.05em;
360
+ color: var(--text-muted);
361
+ margin-bottom: 0.5rem;
362
+ }
363
+
364
+ .care-value {
365
+ display: block;
366
+ font-size: 1.25rem;
367
+ font-weight: bold;
368
+ color: var(--text-main);
369
+ }
370
+
371
+ .care-sections {
372
+ display: grid;
373
+ grid-template-columns: 1fr 1fr;
374
+ gap: 1.5rem;
375
+ margin-bottom: 2rem;
376
+ }
377
+
378
+ .care-section {
379
+ background: var(--bg-page);
380
+ padding: 1.5rem;
381
+ border-radius: 0.75rem;
382
+ border: 1px solid var(--border-color);
383
+ }
384
+
385
+ .care-section.sos-section {
386
+ background: rgba(16, 185, 129, 0.05);
387
+ border-color: rgba(16, 185, 129, 0.2);
388
+ }
389
+
390
+ .section-title {
391
+ display: flex;
392
+ align-items: center;
393
+ gap: 0.5rem;
394
+ font-size: 0.9rem;
395
+ font-weight: 700;
396
+ margin: 0 0 1rem;
397
+ color: var(--text-main);
398
+ }
399
+
400
+ .section-title.avoid-title {
401
+ color: #ef4444;
402
+ }
403
+
404
+ .section-title.sos-title {
405
+ color: #10b981;
406
+ }
407
+
408
+ .section-title svg {
409
+ width: 1.25rem;
410
+ height: 1.25rem;
411
+ }
412
+
413
+ .dont-list {
414
+ list-style: none;
415
+ padding: 0;
416
+ margin: 0;
417
+ display: flex;
418
+ flex-direction: column;
419
+ gap: 0.75rem;
420
+ }
421
+
422
+ .dont-list li {
423
+ display: flex;
424
+ align-items: center;
425
+ gap: 0.75rem;
426
+ font-size: 0.9rem;
427
+ color: var(--text-muted);
428
+ }
429
+
430
+ .dont-bullet {
431
+ width: 0.5rem;
432
+ height: 0.5rem;
433
+ background: #ef4444;
434
+ border-radius: 50%;
435
+ flex-shrink: 0;
436
+ }
437
+
438
+ .sos-text {
439
+ margin: 0;
440
+ font-size: 0.95rem;
441
+ color: #059669;
442
+ font-weight: 500;
443
+ line-height: 1.5;
444
+ }
445
+
446
+ .description-box {
447
+ background: var(--bg-page);
448
+ padding: 1.5rem;
449
+ border-radius: 0.75rem;
450
+ border: 1px solid var(--border-color);
451
+ }
452
+
453
+ .description-box p {
454
+ margin: 0;
455
+ color: var(--text-muted);
456
+ line-height: 1.6;
457
+ }
458
+
459
+ @media (max-width: 768px) {
460
+ .guide-wrapper {
461
+ grid-template-columns: 1fr;
462
+ }
463
+
464
+ .fibers-sidebar {
465
+ border-right: none;
466
+ border-bottom: 1px solid var(--border-color);
467
+ }
468
+
469
+ .fibers-grid {
470
+ flex-direction: row;
471
+ flex-wrap: wrap;
472
+ }
473
+
474
+ .fiber-btn {
475
+ flex: 0 1 calc(50% - 0.375rem);
476
+ }
477
+
478
+ .care-sections {
479
+ grid-template-columns: 1fr;
480
+ }
481
+
482
+ .care-grid {
483
+ grid-template-columns: 1fr;
484
+ }
485
+ }
486
+ </style>
@@ -0,0 +1,166 @@
1
+ import type { TextileData } from './logic';
2
+
3
+ export const TEXTILE_CARE_DATA_EN: Record<string, TextileData> = {
4
+ cotton: {
5
+ name: "Cotton",
6
+ description: "Natural plant fiber, soft and breathable. The king of basics.",
7
+ family: "natural",
8
+ origin: "Cotton plant capsule",
9
+ breathability: 9,
10
+ durability: 7,
11
+ warmth: 4,
12
+ washing: "Cold or lukewarm water (shrinks with heat). Allows strong spinning.",
13
+ drying: "Dryer on medium heat or air dry.",
14
+ ironing: "High heat with steam while still damp.",
15
+ donts: ["Leave wet for long (mold risk)", "Excess bleach (weakens fibers)"],
16
+ sos: "Shrunk? Soak in lukewarm water with hair conditioner and gently stretch.",
17
+ icon: "mdi:tshirt-crew",
18
+ color: "#60A5FA",
19
+ maxTemp: "40-60°C",
20
+ isNoble: false,
21
+ },
22
+ linen: {
23
+ name: "Linen",
24
+ description: "Very strong plant fiber, fresh and with characteristic wrinkle.",
25
+ family: "natural",
26
+ origin: "Linen plant stem",
27
+ breathability: 10,
28
+ durability: 9,
29
+ warmth: 2,
30
+ washing: "Delicate cycle, don't overfill drum (needs water to avoid breaking).",
31
+ drying: "Air dry only. NEVER use dryer (breaks fibers).",
32
+ ironing: "Maximum temperature, always with very damp garment.",
33
+ donts: ["Strong spinning", "Always folding same way (fibers break)"],
34
+ sos: "Shine from ironing? Wipe with cloth dampened in white vinegar.",
35
+ icon: "mdi:leaf",
36
+ color: "#A7F3D0",
37
+ maxTemp: "60°C",
38
+ isNoble: true,
39
+ },
40
+ wool: {
41
+ name: "Wool / Merino",
42
+ description: "Protein fiber, excellent thermal insulator and elastic.",
43
+ family: "natural",
44
+ origin: "Sheep fleece",
45
+ breathability: 8,
46
+ durability: 6,
47
+ warmth: 10,
48
+ washing: "Hand wash or wool cycle. Neutral soap. NEVER hot water (felts).",
49
+ drying: "Flat on towel. Never hang (deforms).",
50
+ ironing: "Vertical steam or medium heat with cloth on top.",
51
+ donts: ["Hot water", "Rubbing or wringing", "Bleach (dissolves)"],
52
+ sos: "Felted? Almost impossible, but soaking with conditioner may help slightly.",
53
+ icon: "mdi:sheep",
54
+ color: "#FCD34D",
55
+ maxTemp: "30°C",
56
+ isNoble: true,
57
+ },
58
+ silk: {
59
+ name: "Silk",
60
+ description: "Continuous filament animal fiber. Natural sheen and dry feel.",
61
+ family: "natural",
62
+ origin: "Silkworm cocoon",
63
+ breathability: 7,
64
+ durability: 5,
65
+ warmth: 6,
66
+ washing: "Hand wash in cold water with neutral shampoo. Don't wring.",
67
+ drying: "Roll in towel to remove moisture. Air dry in shade.",
68
+ ironing: "Low heat, inside out, no direct steam.",
69
+ donts: ["Direct sunlight (burns)", "Perfume/Deodorant (stains)", "Water (water marks)"],
70
+ sos: "Water stain? Gently rub silk against itself.",
71
+ icon: "mdi:ticket-percent",
72
+ color: "#F472B6",
73
+ maxTemp: "20°C",
74
+ isNoble: true,
75
+ },
76
+ cashmere: {
77
+ name: "Cashmere",
78
+ description: "Luxury fiber from Cashmere goat. Extremely soft and warm.",
79
+ family: "natural",
80
+ origin: "Undercoat of Hircus goat",
81
+ breathability: 9,
82
+ durability: 5,
83
+ warmth: 10,
84
+ washing: "STRICTLY hand wash with baby shampoo. Cold water. Never rub.",
85
+ drying: "Flat on towel, shaping as it dries. Never hang.",
86
+ ironing: "Vertical steam without touching or mild heat with cloth.",
87
+ donts: ["Washing machine (even wool cycle)", "Fabric softener", "Continuous friction (pilling)"],
88
+ sos: "Pilling? Use specialized comb or remove by hand.",
89
+ icon: "mdi:crown",
90
+ color: "#F59E0B",
91
+ maxTemp: "20°C",
92
+ isNoble: true,
93
+ },
94
+ polyester: {
95
+ name: "Polyester",
96
+ description: "Synthetic petroleum fiber. Resistant, wrinkle-free, doesn't breathe.",
97
+ family: "synthetic",
98
+ origin: "Petroleum-derived polymers",
99
+ breathability: 2,
100
+ durability: 10,
101
+ warmth: 5,
102
+ washing: "Warm/cold water. Tolerates everything, but traps odors and oils.",
103
+ drying: "Low dryer or air dry. Dries very quickly.",
104
+ ironing: "Low/medium heat. Be careful, it melts.",
105
+ donts: ["Excess heat", "Fabric softener (creates waxy film that traps odor)"],
106
+ sos: "Persistent odor? Soak in water with vinegar before washing.",
107
+ icon: "mdi:oil",
108
+ color: "#94A3B8",
109
+ maxTemp: "40°C",
110
+ isNoble: false,
111
+ },
112
+ viscose: {
113
+ name: "Viscose / Rayon",
114
+ description: "Semi-synthetic regenerated cellulose. Silky feel, very absorbent.",
115
+ family: "artificial",
116
+ origin: "Chemically treated wood pulp",
117
+ breathability: 8,
118
+ durability: 4,
119
+ warmth: 3,
120
+ washing: "Delicate in cold. Becomes very weak when wet.",
121
+ drying: "Flat or padded hanger. No dryer.",
122
+ ironing: "Medium, inside out. No direct steam if possible.",
123
+ donts: ["Wring when wet (breaks)", "Long soaks"],
124
+ sos: "Shrunken and stiff? Iron with lots of steam to relax fibers.",
125
+ icon: "mdi:forest",
126
+ color: "#C084FC",
127
+ maxTemp: "30°C",
128
+ isNoble: false,
129
+ },
130
+ nylon: {
131
+ name: "Nylon (Polyamide)",
132
+ description: "Highly resistant to tension and abrasion.",
133
+ family: "synthetic",
134
+ origin: "Petroleum-derived (polyamide)",
135
+ breathability: 3,
136
+ durability: 10,
137
+ warmth: 4,
138
+ washing: "Normal cycle. Be careful mixing colors (absorbs dyes).",
139
+ drying: "Air dry. Low dryer.",
140
+ ironing: "Very low. Melts quickly.",
141
+ donts: ["Bleach (yellows)", "Direct sunlight (fades)"],
142
+ sos: "Grayish? Wash with oxygen-based whitener.",
143
+ icon: "mdi:parachute",
144
+ color: "#2DD4BF",
145
+ maxTemp: "40°C",
146
+ isNoble: false,
147
+ },
148
+ acrylic: {
149
+ name: "Acrylic",
150
+ description: "Synthetic wool imitation. Soft, warm, pills easily.",
151
+ family: "synthetic",
152
+ origin: "Polyacrylonitrile",
153
+ breathability: 4,
154
+ durability: 6,
155
+ warmth: 8,
156
+ washing: "Lukewarm water. Use fabric softener to reduce static.",
157
+ drying: "Air dry. Heat permanently deforms garment.",
158
+ ironing: "Don't iron",
159
+ donts: ["Fabric softener (breaks fibers)", "Strong wringing", "Heat"],
160
+ sos: "Lost elasticity? It's irreversible (fibers are broken).",
161
+ icon: "mdi:resize",
162
+ color: "#450A0A",
163
+ maxTemp: "30°C",
164
+ isNoble: false,
165
+ },
166
+ };