@jjlmoya/utils-textiles 1.9.0 → 1.12.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 (53) hide show
  1. package/package.json +7 -4
  2. package/scripts/postinstall.mjs +27 -0
  3. package/src/category/index.ts +24 -25
  4. package/src/entries.ts +37 -0
  5. package/src/tool/burnTest/component.astro +0 -380
  6. package/src/tool/burnTest/entry.ts +30 -0
  7. package/src/tool/burnTest/index.ts +2 -32
  8. package/src/tool/burnTest/textile-burn-test.css +378 -0
  9. package/src/tool/clothingSizeConverter/clothing-size-converter.css +717 -0
  10. package/src/tool/clothingSizeConverter/component.astro +0 -719
  11. package/src/tool/clothingSizeConverter/entry.ts +30 -0
  12. package/src/tool/clothingSizeConverter/index.ts +2 -32
  13. package/src/tool/fabricProjectCalculator/component.astro +0 -540
  14. package/src/tool/fabricProjectCalculator/entry.ts +30 -0
  15. package/src/tool/fabricProjectCalculator/fabric-project-calculator.css +538 -0
  16. package/src/tool/fabricProjectCalculator/index.ts +2 -32
  17. package/src/tool/fabricTruth/component.astro +0 -428
  18. package/src/tool/fabricTruth/entry.ts +30 -0
  19. package/src/tool/fabricTruth/fabric-truthfulness.css +426 -0
  20. package/src/tool/fabricTruth/index.ts +2 -32
  21. package/src/tool/fiberPrep/component.astro +0 -652
  22. package/src/tool/fiberPrep/entry.ts +30 -0
  23. package/src/tool/fiberPrep/fiber-preparation-natural-dyeing.css +650 -0
  24. package/src/tool/fiberPrep/index.ts +2 -32
  25. package/src/tool/knittingGauge/component.astro +0 -458
  26. package/src/tool/knittingGauge/entry.ts +30 -0
  27. package/src/tool/knittingGauge/index.ts +2 -32
  28. package/src/tool/knittingGauge/knitting-gauge-calculator.css +456 -0
  29. package/src/tool/laundryGuide/component.astro +0 -317
  30. package/src/tool/laundryGuide/entry.ts +25 -0
  31. package/src/tool/laundryGuide/index.ts +2 -27
  32. package/src/tool/laundryGuide/laundry-guide.css +315 -0
  33. package/src/tool/needleConverter/component.astro +0 -344
  34. package/src/tool/needleConverter/entry.ts +30 -0
  35. package/src/tool/needleConverter/index.ts +2 -32
  36. package/src/tool/needleConverter/knitting-needle-converter.css +342 -0
  37. package/src/tool/sewingPatternScaler/component.astro +0 -314
  38. package/src/tool/sewingPatternScaler/entry.ts +30 -0
  39. package/src/tool/sewingPatternScaler/index.ts +2 -32
  40. package/src/tool/sewingPatternScaler/sewing-pattern-scaler.css +313 -0
  41. package/src/tool/shoeSizeConverter/component.astro +0 -255
  42. package/src/tool/shoeSizeConverter/entry.ts +30 -0
  43. package/src/tool/shoeSizeConverter/index.ts +2 -32
  44. package/src/tool/shoeSizeConverter/shoe-size-converter.css +253 -0
  45. package/src/tool/stainChemistry/component.astro +0 -479
  46. package/src/tool/stainChemistry/entry.ts +30 -0
  47. package/src/tool/stainChemistry/index.ts +2 -32
  48. package/src/tool/stainChemistry/stain-chemical-protocol.css +477 -0
  49. package/src/tool/yarnCalculator/component.astro +0 -446
  50. package/src/tool/yarnCalculator/entry.ts +30 -0
  51. package/src/tool/yarnCalculator/index.ts +2 -32
  52. package/src/tool/yarnCalculator/yarn-calculator.css +444 -0
  53. package/src/tools.ts +1 -1
@@ -0,0 +1,313 @@
1
+ .scaler-wrapper {
2
+ padding: 1.5rem 0;
3
+ width: 100%;
4
+ }
5
+
6
+ .scaler-card {
7
+ --sp-p: #4f46e5;
8
+
9
+ background: var(--bg-surface);
10
+ color: var(--text-main);
11
+ width: calc(100% - 24px);
12
+ max-width: 1100px;
13
+ margin: 0 auto;
14
+ border-radius: 24px;
15
+ border: 1px solid var(--border-color);
16
+ display: flex;
17
+ flex-direction: column;
18
+ overflow: hidden;
19
+ }
20
+
21
+ @media (min-width: 1024px) {
22
+ .scaler-card { flex-direction: row; }
23
+ }
24
+
25
+ .card-left {
26
+ flex: 0 0 auto;
27
+ padding: 24px;
28
+ width: 100%;
29
+ background: var(--bg-surface);
30
+ }
31
+
32
+ @media (min-width: 1024px) {
33
+ .card-left {
34
+ width: 380px;
35
+ padding: 40px;
36
+ border-right: 1px solid var(--border-color);
37
+ }
38
+ }
39
+
40
+ .card-right {
41
+ flex: 1 1 auto;
42
+ padding: 24px;
43
+ background: var(--bg-surface);
44
+ display: flex;
45
+ flex-direction: column;
46
+ gap: 24px;
47
+ min-width: 0;
48
+ }
49
+
50
+ @media (min-width: 1024px) {
51
+ .card-right {
52
+ padding: 40px;
53
+ gap: 32px;
54
+ }
55
+ }
56
+
57
+ .label-tiny {
58
+ font-size: 10px;
59
+ font-weight: 700;
60
+ text-transform: uppercase;
61
+ letter-spacing: 0.12em;
62
+ color: var(--text-muted);
63
+ margin-bottom: 10px;
64
+ display: block;
65
+ }
66
+
67
+ .segmented-control {
68
+ display: flex;
69
+ background: var(--bg-muted);
70
+ border-radius: 12px;
71
+ padding: 4px;
72
+ margin-bottom: 24px;
73
+ }
74
+
75
+ .segment-btn {
76
+ flex: 1;
77
+ background: transparent;
78
+ border: none;
79
+ padding: 10px 4px;
80
+ font-size: 10px;
81
+ font-weight: 700;
82
+ text-transform: uppercase;
83
+ letter-spacing: 0.05em;
84
+ color: var(--text-muted);
85
+ cursor: pointer;
86
+ border-radius: 8px;
87
+ transition: all 0.2s ease;
88
+ }
89
+
90
+ .segment-btn.active {
91
+ color: var(--text-main);
92
+ background: var(--bg-surface);
93
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.03);
94
+ }
95
+
96
+ .input-grid {
97
+ display: grid;
98
+ grid-template-columns: repeat(2, 1fr);
99
+ gap: 12px;
100
+ margin-bottom: 16px;
101
+ }
102
+
103
+ .form-input {
104
+ width: 100%;
105
+ background: var(--bg-surface);
106
+ border: 1px solid var(--border-color);
107
+ border-radius: 8px;
108
+ padding: 10px 12px;
109
+ font-size: 14px;
110
+ color: var(--text-main);
111
+ }
112
+
113
+ .form-input:focus {
114
+ outline: none;
115
+ border-color: var(--sp-p);
116
+ box-shadow: 0 0 0 3px rgba(79, 70, 229, 0.06);
117
+ }
118
+
119
+ .form-select {
120
+ cursor: pointer;
121
+ appearance: none;
122
+ background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 24 24' stroke='%2364748b'%3E%3Cpath stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M19 9l-7 7-7-7'%3E%3C/path%3E%3C/svg%3E");
123
+ background-repeat: no-repeat;
124
+ background-position: right 8px center;
125
+ background-size: 12px;
126
+ padding-right: 28px;
127
+ }
128
+
129
+ .target-lbl {
130
+ margin-top: 16px;
131
+ }
132
+
133
+ .ease-group {
134
+ margin-top: 24px;
135
+ border-top: 1px solid var(--border-color);
136
+ padding-top: 24px;
137
+ }
138
+
139
+ .viz-container {
140
+ background: var(--bg-muted);
141
+ background-image:
142
+ linear-gradient(rgba(0, 0, 0, 0.02) 1px, transparent 1px),
143
+ linear-gradient(90deg, rgba(0, 0, 0, 0.02) 1px, transparent 1px);
144
+ background-size: 20px 20px;
145
+ border-radius: 12px;
146
+ aspect-ratio: 1/1;
147
+ display: flex;
148
+ align-items: center;
149
+ justify-content: center;
150
+ position: relative;
151
+ border: 1px solid var(--border-color);
152
+ }
153
+
154
+ @media (min-width: 768px) {
155
+ .viz-container { aspect-ratio: 16/9; }
156
+ }
157
+
158
+ .theme-dark .viz-container {
159
+ background-image:
160
+ linear-gradient(rgba(255, 255, 255, 0.02) 1px, transparent 1px),
161
+ linear-gradient(90deg, rgba(255, 255, 255, 0.02) 1px, transparent 1px);
162
+ }
163
+
164
+ #scaler-canvas {
165
+ position: absolute;
166
+ inset: 0;
167
+ width: 100%;
168
+ height: 100%;
169
+ }
170
+
171
+ .legend-box {
172
+ position: absolute;
173
+ bottom: 12px;
174
+ right: 12px;
175
+ display: flex;
176
+ gap: 12px;
177
+ font-size: 9px;
178
+ font-weight: 700;
179
+ text-transform: uppercase;
180
+ letter-spacing: 0.05em;
181
+ color: var(--text-muted);
182
+ }
183
+
184
+ .legend-item {
185
+ display: flex;
186
+ align-items: center;
187
+ gap: 4px;
188
+ }
189
+
190
+ .ln-o {
191
+ width: 10px;
192
+ height: 1px;
193
+ border: 1px dashed var(--border-color);
194
+ }
195
+
196
+ .ln-s {
197
+ width: 10px;
198
+ height: 2px;
199
+ background: var(--sp-p);
200
+ }
201
+
202
+ .action-strip {
203
+ display: flex;
204
+ flex-direction: column;
205
+ gap: 12px;
206
+ }
207
+
208
+ :global(.action-pill) {
209
+ background: var(--bg-surface);
210
+ border: 1px solid var(--border-color);
211
+ border-radius: 16px;
212
+ padding: 16px 20px;
213
+ display: flex;
214
+ align-items: center;
215
+ gap: 16px;
216
+ }
217
+
218
+ :global(.icon-box) {
219
+ width: 44px;
220
+ height: 44px;
221
+ background: var(--bg-muted);
222
+ border-radius: 12px;
223
+ display: flex;
224
+ align-items: center;
225
+ justify-content: center;
226
+ color: var(--sp-p);
227
+ font-size: 20px;
228
+ flex-shrink: 0;
229
+ }
230
+
231
+ :global(.action-content) { flex: 1; }
232
+
233
+ :global(.action-text) {
234
+ display: block;
235
+ font-size: 14px;
236
+ color: var(--text-muted);
237
+ }
238
+
239
+ :global(.action-text strong) { font-weight: 700; }
240
+
241
+ :global(.action-val-pos) { color: var(--sp-p); }
242
+
243
+ :global(.action-val-neg) { color: #f87171; }
244
+
245
+ :global(.action-note) {
246
+ display: block;
247
+ font-size: 10px;
248
+ color: var(--text-muted);
249
+ margin-top: 2px;
250
+ text-transform: uppercase;
251
+ letter-spacing: 0.05em;
252
+ }
253
+
254
+ .totals-section {
255
+ background: var(--bg-muted);
256
+ border-radius: 10px;
257
+ padding: 24px;
258
+ }
259
+
260
+ .totals-grid {
261
+ display: grid;
262
+ grid-template-columns: repeat(2, 1fr);
263
+ gap: 16px;
264
+ }
265
+
266
+ @media (min-width: 640px) {
267
+ .totals-grid { grid-template-columns: repeat(4, 1fr); }
268
+ }
269
+
270
+ .total-card {
271
+ text-align: center;
272
+ display: flex;
273
+ flex-direction: column;
274
+ gap: 4px;
275
+ }
276
+
277
+ .total-val {
278
+ font-size: 16px;
279
+ font-weight: 700;
280
+ color: var(--text-main);
281
+ }
282
+
283
+ .total-tag {
284
+ font-size: 10px;
285
+ font-weight: 700;
286
+ text-transform: uppercase;
287
+ color: var(--text-muted);
288
+ letter-spacing: 0.08em;
289
+ }
290
+
291
+ .warn-banner {
292
+ background: #fefce8;
293
+ border-left: 3px solid #ca8a04;
294
+ color: #854d0e;
295
+ padding: 16px 20px;
296
+ border-radius: 8px;
297
+ font-size: 11px;
298
+ font-weight: 600;
299
+ margin-bottom: 24px;
300
+ display: flex;
301
+ align-items: center;
302
+ gap: 12px;
303
+ }
304
+
305
+ .theme-dark .warn-banner {
306
+ background: #451a03;
307
+ border-left-color: #fbbf24;
308
+ color: #fbbf24;
309
+ }
310
+
311
+ .hidden {
312
+ display: none;
313
+ }
@@ -180,258 +180,3 @@ const sizeUI = ui as ShoeSizeConverterUI;
180
180
  startInit();
181
181
  </script>
182
182
 
183
- <style>
184
- .shoe-converter {
185
- max-width: 800px;
186
- margin: 0 auto;
187
- padding: 1rem 1rem 4rem;
188
- }
189
-
190
- .converter-card {
191
- background: var(--bg-surface);
192
- border: 1px solid var(--border-color);
193
- border-radius: 2.5rem;
194
- padding: 3rem;
195
- box-shadow: 0 25px 60px rgba(0, 0, 0, 0.05);
196
- display: flex;
197
- flex-direction: column;
198
- gap: 3rem;
199
- }
200
-
201
- .theme-dark .converter-card {
202
- box-shadow: 0 25px 60px rgba(0, 0, 0, 0.3);
203
- }
204
-
205
- .gender-selector {
206
- display: flex;
207
- justify-content: center;
208
- gap: 2rem;
209
- }
210
-
211
- .gender-btn {
212
- width: 80px;
213
- height: 80px;
214
- border-radius: 2rem;
215
- border: 2px solid transparent;
216
- background: var(--bg-page);
217
- cursor: pointer;
218
- transition: all 0.3s;
219
- display: flex;
220
- align-items: center;
221
- justify-content: center;
222
- color: var(--text-muted);
223
- }
224
-
225
- .gender-btn svg {
226
- width: 2.5rem;
227
- height: 2.5rem;
228
- }
229
-
230
- .gender-btn-men.active {
231
- background: rgba(59, 130, 246, 0.08);
232
- border-color: #3b82f6;
233
- color: #3b82f6;
234
- box-shadow: 0 10px 25px rgba(59, 130, 246, 0.2);
235
- transform: translateY(-4px);
236
- }
237
-
238
- .gender-btn-women.active {
239
- background: rgba(244, 63, 94, 0.08);
240
- border-color: #f43f5e;
241
- color: #f43f5e;
242
- box-shadow: 0 10px 25px rgba(244, 63, 94, 0.2);
243
- transform: translateY(-4px);
244
- }
245
-
246
- .size-section {
247
- display: flex;
248
- flex-direction: column;
249
- gap: 1.5rem;
250
- }
251
-
252
- .field-group {
253
- display: flex;
254
- flex-direction: column;
255
- gap: 0.5rem;
256
- }
257
-
258
- .field-label {
259
- font-size: 0.75rem;
260
- font-weight: 800;
261
- color: var(--text-muted);
262
- text-transform: uppercase;
263
- letter-spacing: 0.1em;
264
- }
265
-
266
- .select-wrap {
267
- position: relative;
268
- }
269
-
270
- .select-wrap::after {
271
- content: '▾';
272
- position: absolute;
273
- right: 1.25rem;
274
- top: 50%;
275
- transform: translateY(-50%);
276
- pointer-events: none;
277
- color: var(--text-muted);
278
- font-size: 1rem;
279
- }
280
-
281
- .region-select {
282
- appearance: none;
283
- width: 100%;
284
- background: var(--bg-page);
285
- border: 1.5px solid var(--border-color);
286
- border-radius: 1rem;
287
- padding: 0.875rem 2.75rem 0.875rem 1.25rem;
288
- font-size: 1rem;
289
- font-weight: 600;
290
- color: var(--text-main);
291
- outline: none;
292
- cursor: pointer;
293
- transition: border-color 0.2s;
294
- }
295
-
296
- .region-select:focus {
297
- border-color: #3b82f6;
298
- }
299
-
300
- .size-grid-container {
301
- display: flex;
302
- flex-direction: column;
303
- gap: 1.5rem;
304
- }
305
-
306
- .grid-header {
307
- text-align: center;
308
- }
309
-
310
- .grid-header h3 {
311
- font-size: 1.25rem;
312
- font-weight: 800;
313
- color: var(--text-main);
314
- margin: 0 0 0.5rem;
315
- }
316
-
317
- .grid-header p {
318
- font-size: 0.875rem;
319
- color: var(--text-muted);
320
- margin: 0;
321
- }
322
-
323
- .size-grid {
324
- display: grid;
325
- grid-template-columns: repeat(auto-fill, minmax(65px, 1fr));
326
- gap: 0.75rem;
327
- }
328
-
329
- :global(.size-cell) {
330
- aspect-ratio: 1;
331
- display: flex;
332
- align-items: center;
333
- justify-content: center;
334
- border-radius: 1rem;
335
- background: var(--bg-surface);
336
- border: 1px solid var(--border-color);
337
- font-size: 1.125rem;
338
- font-weight: 700;
339
- color: var(--text-muted);
340
- cursor: pointer;
341
- transition: all 0.2s;
342
- }
343
-
344
- :global(.size-cell:hover) {
345
- border-color: #3b82f6;
346
- color: #3b82f6;
347
- transform: scale(1.05);
348
- }
349
-
350
- :global(.size-cell.active) {
351
- background: #3b82f6;
352
- border-color: #3b82f6;
353
- color: white;
354
- box-shadow: 0 10px 20px rgba(59, 130, 246, 0.25);
355
- }
356
-
357
- .results-container {
358
- display: grid;
359
- grid-template-columns: repeat(3, 1fr);
360
- gap: 1.5rem;
361
- background: var(--bg-page);
362
- padding: 2rem;
363
- border-radius: 2rem;
364
- border: 1px solid var(--border-color);
365
- }
366
-
367
- .result-card {
368
- text-align: center;
369
- display: flex;
370
- flex-direction: column;
371
- gap: 0.5rem;
372
- }
373
-
374
- .result-label {
375
- font-size: 0.75rem;
376
- font-weight: 800;
377
- color: var(--text-muted);
378
- text-transform: uppercase;
379
- letter-spacing: 0.05em;
380
- }
381
-
382
- .result-value {
383
- font-size: 2.5rem;
384
- font-weight: 900;
385
- color: var(--text-main);
386
- line-height: 1;
387
- }
388
-
389
- .result-unit {
390
- font-size: 0.875rem;
391
- font-weight: 700;
392
- color: #3b82f6;
393
- margin-top: 0.25rem;
394
- }
395
-
396
- .result-unit.hidden {
397
- display: none;
398
- }
399
-
400
- .info-banner {
401
- display: flex;
402
- align-items: center;
403
- gap: 1rem;
404
- padding: 1.25rem;
405
- background: rgba(3, 105, 161, 0.06);
406
- border-radius: 1.25rem;
407
- color: #0369a1;
408
- font-size: 0.875rem;
409
- line-height: 1.5;
410
- }
411
-
412
- .theme-dark .info-banner {
413
- background: rgba(3, 105, 161, 0.1);
414
- color: #7dd3fc;
415
- }
416
-
417
- .info-banner svg {
418
- width: 1.5rem;
419
- height: 1.5rem;
420
- flex-shrink: 0;
421
- }
422
-
423
- .info-banner p {
424
- margin: 0;
425
- }
426
-
427
- @media (max-width: 640px) {
428
- .converter-card {
429
- padding: 1.5rem;
430
- gap: 2rem;
431
- }
432
-
433
- .results-container {
434
- grid-template-columns: 1fr;
435
- }
436
- }
437
- </style>
@@ -0,0 +1,30 @@
1
+ import type { TextilesToolEntry, ToolLocaleContent } from '../../types';
2
+
3
+ import type { ShoeSizeConverterUI } from './ui';
4
+
5
+ export type ShoeSizeConverterLocaleContent = ToolLocaleContent<ShoeSizeConverterUI>;
6
+
7
+ export const shoeSizeConverter: TextilesToolEntry<ShoeSizeConverterUI> = {
8
+ id: 'shoe-size-converter',
9
+ icons: {
10
+ bg: 'mdi:shoe-heel',
11
+ fg: 'mdi:ruler',
12
+ },
13
+ i18n: {
14
+ es: () => import('./i18n/es').then((m) => m.content),
15
+ en: () => import('./i18n/en').then((m) => m.content),
16
+ fr: () => import('./i18n/fr').then((m) => m.content),
17
+ de: () => import('./i18n/de').then((m) => m.content),
18
+ id: () => import('./i18n/id').then((m) => m.content),
19
+ it: () => import('./i18n/it').then((m) => m.content),
20
+ ja: () => import('./i18n/ja').then((m) => m.content),
21
+ ko: () => import('./i18n/ko').then((m) => m.content),
22
+ nl: () => import('./i18n/nl').then((m) => m.content),
23
+ pl: () => import('./i18n/pl').then((m) => m.content),
24
+ pt: () => import('./i18n/pt').then((m) => m.content),
25
+ ru: () => import('./i18n/ru').then((m) => m.content),
26
+ sv: () => import('./i18n/sv').then((m) => m.content),
27
+ tr: () => import('./i18n/tr').then((m) => m.content),
28
+ zh: () => import('./i18n/zh').then((m) => m.content),
29
+ },
30
+ };
@@ -1,35 +1,5 @@
1
- import type { TextilesToolEntry, ToolLocaleContent, ToolDefinition } from '../../types';
2
-
3
- import type { ShoeSizeConverterUI } from './ui';
4
-
5
- export type ShoeSizeConverterLocaleContent = ToolLocaleContent<ShoeSizeConverterUI>;
6
-
7
- export const shoeSizeConverter: TextilesToolEntry<ShoeSizeConverterUI> = {
8
- id: 'shoe-size-converter',
9
- icons: {
10
- bg: 'mdi:shoe-heel',
11
- fg: 'mdi:ruler',
12
- },
13
- i18n: {
14
- es: () => import('./i18n/es').then((m) => m.content),
15
- en: () => import('./i18n/en').then((m) => m.content),
16
- fr: () => import('./i18n/fr').then((m) => m.content),
17
- de: () => import('./i18n/de').then((m) => m.content),
18
- id: () => import('./i18n/id').then((m) => m.content),
19
- it: () => import('./i18n/it').then((m) => m.content),
20
- ja: () => import('./i18n/ja').then((m) => m.content),
21
- ko: () => import('./i18n/ko').then((m) => m.content),
22
- nl: () => import('./i18n/nl').then((m) => m.content),
23
- pl: () => import('./i18n/pl').then((m) => m.content),
24
- pt: () => import('./i18n/pt').then((m) => m.content),
25
- ru: () => import('./i18n/ru').then((m) => m.content),
26
- sv: () => import('./i18n/sv').then((m) => m.content),
27
- tr: () => import('./i18n/tr').then((m) => m.content),
28
- zh: () => import('./i18n/zh').then((m) => m.content),
29
- },
30
- };
31
-
32
-
1
+ import { shoeSizeConverter } from './entry';
2
+ export * from './entry';
33
3
  export const SHOE_SIZE_CONVERTER_TOOL: ToolDefinition = {
34
4
  entry: shoeSizeConverter,
35
5
  Component: () => import('./component.astro'),