@jjlmoya/utils-diy 1.13.0 → 1.15.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 (30) hide show
  1. package/package.json +1 -1
  2. package/src/entries.ts +3 -1
  3. package/src/index.ts +2 -0
  4. package/src/tests/locale_completeness.test.ts +2 -2
  5. package/src/tests/tool_validation.test.ts +2 -2
  6. package/src/tool/pythagoreanRightAngleCalculator/bibliography.astro +6 -0
  7. package/src/tool/pythagoreanRightAngleCalculator/bibliography.ts +12 -0
  8. package/src/tool/pythagoreanRightAngleCalculator/component.astro +243 -0
  9. package/src/tool/pythagoreanRightAngleCalculator/entry.ts +24 -0
  10. package/src/tool/pythagoreanRightAngleCalculator/i18n/de.ts +129 -0
  11. package/src/tool/pythagoreanRightAngleCalculator/i18n/en.ts +129 -0
  12. package/src/tool/pythagoreanRightAngleCalculator/i18n/es.ts +129 -0
  13. package/src/tool/pythagoreanRightAngleCalculator/i18n/fr.ts +129 -0
  14. package/src/tool/pythagoreanRightAngleCalculator/i18n/id.ts +129 -0
  15. package/src/tool/pythagoreanRightAngleCalculator/i18n/it.ts +129 -0
  16. package/src/tool/pythagoreanRightAngleCalculator/i18n/ja.ts +129 -0
  17. package/src/tool/pythagoreanRightAngleCalculator/i18n/ko.ts +129 -0
  18. package/src/tool/pythagoreanRightAngleCalculator/i18n/nl.ts +129 -0
  19. package/src/tool/pythagoreanRightAngleCalculator/i18n/pl.ts +129 -0
  20. package/src/tool/pythagoreanRightAngleCalculator/i18n/pt.ts +129 -0
  21. package/src/tool/pythagoreanRightAngleCalculator/i18n/ru.ts +129 -0
  22. package/src/tool/pythagoreanRightAngleCalculator/i18n/sv.ts +129 -0
  23. package/src/tool/pythagoreanRightAngleCalculator/i18n/tr.ts +129 -0
  24. package/src/tool/pythagoreanRightAngleCalculator/i18n/zh.ts +129 -0
  25. package/src/tool/pythagoreanRightAngleCalculator/index.ts +11 -0
  26. package/src/tool/pythagoreanRightAngleCalculator/logic.ts +102 -0
  27. package/src/tool/pythagoreanRightAngleCalculator/pythagorean-right-angle-calculator.css +387 -0
  28. package/src/tool/pythagoreanRightAngleCalculator/seo.astro +15 -0
  29. package/src/tool/pythagoreanRightAngleCalculator/ui.ts +71 -0
  30. package/src/tools.ts +2 -1
@@ -0,0 +1,387 @@
1
+ :root {
2
+ --prac-primary: #6366f1;
3
+ --prac-primary-dark: #4f46e5;
4
+ --prac-primary-light: #818cf8;
5
+ --prac-neutral: #1e293b;
6
+ --prac-neutral-light: #64748b;
7
+ --prac-success: #10b981;
8
+ --prac-warning: #f59e0b;
9
+ --prac-error: #ef4444;
10
+ --prac-border: #e2e8f0;
11
+ --prac-bg-light: #f8fafc;
12
+ --prac-bg-lighter: #f1f5f9;
13
+ --prac-bg: #fff;
14
+ }
15
+
16
+ :root.theme-dark {
17
+ --prac-primary: #818cf8;
18
+ --prac-primary-dark: #6366f1;
19
+ --prac-primary-light: #a5b4fc;
20
+ --prac-neutral: #f1f5f9;
21
+ --prac-neutral-light: #9ca3af;
22
+ --prac-success: #34d399;
23
+ --prac-warning: #fbbf24;
24
+ --prac-error: #f87171;
25
+ --prac-border: rgba(255, 255, 255, 0.1);
26
+ --prac-bg-light: rgba(255, 255, 255, 0.04);
27
+ --prac-bg-lighter: rgba(255, 255, 255, 0.02);
28
+ --prac-bg: rgba(255, 255, 255, 0.01);
29
+ }
30
+
31
+ .prac-root {
32
+ width: 100%;
33
+ color: var(--prac-neutral);
34
+ -webkit-font-smoothing: antialiased;
35
+ -moz-osx-font-smoothing: grayscale;
36
+ }
37
+
38
+ .prac-container {
39
+ display: grid;
40
+ grid-template-columns: 1fr;
41
+ gap: 0;
42
+ background: var(--prac-bg);
43
+ }
44
+
45
+ @media (min-width: 768px) {
46
+ .prac-container {
47
+ grid-template-columns: 280px 1fr;
48
+ gap: 2rem;
49
+ padding: 2rem;
50
+ }
51
+ }
52
+
53
+ .prac-inputs {
54
+ padding: 1.5rem;
55
+ border-bottom: 4px solid var(--prac-primary);
56
+ display: flex;
57
+ flex-direction: column;
58
+ gap: 1.25rem;
59
+ background: var(--prac-bg-light);
60
+ }
61
+
62
+ @media (min-width: 768px) {
63
+ .prac-inputs {
64
+ border-bottom: none;
65
+ border-right: 4px solid var(--prac-primary);
66
+ padding: 1.5rem;
67
+ background: var(--prac-bg);
68
+ }
69
+ }
70
+
71
+ .prac-unit-selector {
72
+ display: grid;
73
+ grid-template-columns: 1fr 1fr;
74
+ gap: 0.75rem;
75
+ }
76
+
77
+ .prac-unit-btn {
78
+ padding: 0.875rem 1rem;
79
+ border: 2.5px solid var(--prac-border);
80
+ border-radius: 0.5rem;
81
+ background: var(--prac-bg);
82
+ color: var(--prac-neutral);
83
+ font-weight: 700;
84
+ cursor: pointer;
85
+ transition: all 200ms ease;
86
+ font-size: 0.95rem;
87
+ letter-spacing: 0.5px;
88
+ }
89
+
90
+ .prac-unit-btn:hover {
91
+ border-color: var(--prac-primary);
92
+ background: var(--prac-bg-lighter);
93
+ transform: translateY(-2px);
94
+ box-shadow: 0 4px 12px rgba(99, 102, 241, 0.15);
95
+ }
96
+
97
+ .prac-unit-btn.active {
98
+ background: var(--prac-primary);
99
+ color: #fff;
100
+ border-color: var(--prac-primary);
101
+ box-shadow: 0 6px 20px rgba(99, 102, 241, 0.3);
102
+ }
103
+
104
+ .prac-input-group {
105
+ display: flex;
106
+ flex-direction: column;
107
+ gap: 0.5rem;
108
+ }
109
+
110
+ .prac-input-group label {
111
+ font-size: 0.8rem;
112
+ font-weight: 800;
113
+ color: var(--prac-neutral);
114
+ text-transform: uppercase;
115
+ letter-spacing: 0.8px;
116
+ }
117
+
118
+ .prac-input-group input {
119
+ padding: 0.875rem 1rem;
120
+ border: 2.5px solid var(--prac-border);
121
+ border-radius: 0.5rem;
122
+ font-size: 1.1rem;
123
+ font-weight: 700;
124
+ background: var(--prac-bg);
125
+ color: var(--prac-neutral);
126
+ transition: all 200ms ease;
127
+ }
128
+
129
+ .prac-input-group input:focus {
130
+ outline: none;
131
+ border-color: var(--prac-primary);
132
+ box-shadow: 0 0 0 4px rgba(99, 102, 241, 0.1);
133
+ background: var(--prac-bg-lighter);
134
+ }
135
+
136
+ .prac-button-group {
137
+ display: grid;
138
+ grid-template-columns: 1fr 1fr;
139
+ gap: 0.75rem;
140
+ margin-top: 0.5rem;
141
+ }
142
+
143
+ .prac-btn {
144
+ padding: 0.875rem 1rem;
145
+ border: 2.5px solid var(--prac-border);
146
+ border-radius: 0.5rem;
147
+ background: var(--prac-bg);
148
+ color: var(--prac-neutral);
149
+ cursor: pointer;
150
+ transition: all 200ms ease;
151
+ display: flex;
152
+ align-items: center;
153
+ justify-content: center;
154
+ }
155
+
156
+ .prac-btn-icon {
157
+ font-size: 1.25rem;
158
+ line-height: 1;
159
+ }
160
+
161
+ .prac-btn-icon svg {
162
+ width: 1.25rem;
163
+ height: 1.25rem;
164
+ }
165
+
166
+ .prac-btn:hover {
167
+ border-color: var(--prac-primary);
168
+ background: var(--prac-bg-lighter);
169
+ transform: translateY(-2px);
170
+ }
171
+
172
+ .prac-btn:active {
173
+ transform: translateY(0);
174
+ }
175
+
176
+ .prac-presets {
177
+ display: grid;
178
+ grid-template-columns: 1fr 1fr;
179
+ gap: 0.75rem;
180
+ margin-top: 1.5rem;
181
+ padding-top: 1.5rem;
182
+ border-top: 2.5px solid var(--prac-border);
183
+ }
184
+
185
+ .prac-preset {
186
+ padding: 0.875rem 1rem;
187
+ border: 2.5px solid var(--prac-primary);
188
+ border-radius: 0.5rem;
189
+ background: var(--prac-bg-lighter);
190
+ color: var(--prac-neutral);
191
+ font-weight: 800;
192
+ cursor: pointer;
193
+ font-size: 0.9rem;
194
+ transition: all 200ms ease;
195
+ }
196
+
197
+ .prac-preset:hover {
198
+ background: var(--prac-primary);
199
+ color: #fff;
200
+ transform: translateY(-2px);
201
+ box-shadow: 0 6px 20px rgba(99, 102, 241, 0.3);
202
+ }
203
+
204
+ .prac-display {
205
+ padding: 1.5rem;
206
+ display: flex;
207
+ flex-direction: column;
208
+ gap: 1.25rem;
209
+ }
210
+
211
+ .prac-status {
212
+ padding: 1.25rem;
213
+ border-radius: 0.75rem;
214
+ border: 2.5px solid var(--prac-border);
215
+ background: var(--prac-bg-light);
216
+ display: grid;
217
+ grid-template-columns: 50px 1fr;
218
+ gap: 1rem;
219
+ align-items: center;
220
+ transition: all 200ms ease;
221
+ }
222
+
223
+ .prac-status-indicator {
224
+ width: 50px;
225
+ height: 50px;
226
+ border-radius: 50%;
227
+ background: #e5e7eb;
228
+ box-shadow: inset 0 0 0 2px #9ca3af;
229
+ }
230
+
231
+ .prac-status.perfect .prac-status-indicator {
232
+ background: var(--prac-success);
233
+ box-shadow: 0 0 16px rgba(16, 185, 129, 0.5);
234
+ }
235
+
236
+ .prac-status.acceptable .prac-status-indicator {
237
+ background: var(--prac-success);
238
+ box-shadow: 0 0 16px rgba(16, 185, 129, 0.5);
239
+ }
240
+
241
+ .prac-status.warning .prac-status-indicator {
242
+ background: var(--prac-warning);
243
+ box-shadow: 0 0 16px rgba(245, 158, 11, 0.5);
244
+ }
245
+
246
+ .prac-status.error .prac-status-indicator {
247
+ background: var(--prac-error);
248
+ box-shadow: 0 0 16px rgba(239, 68, 68, 0.5);
249
+ }
250
+
251
+ .prac-status-content {
252
+ display: flex;
253
+ flex-direction: column;
254
+ gap: 0.35rem;
255
+ }
256
+
257
+ .prac-status-title {
258
+ font-weight: 800;
259
+ font-size: 1.05rem;
260
+ color: var(--prac-neutral);
261
+ }
262
+
263
+ .prac-status-value {
264
+ font-size: 0.9rem;
265
+ color: var(--prac-neutral-light);
266
+ font-weight: 700;
267
+ }
268
+
269
+ .prac-results-grid {
270
+ display: grid;
271
+ grid-template-columns: 1fr 1fr;
272
+ gap: 1rem;
273
+ }
274
+
275
+ .prac-result-box {
276
+ padding: 1.25rem;
277
+ background: rgba(255, 255, 255, 0.5);
278
+ border-radius: 0.75rem;
279
+ border: 2.5px solid var(--prac-primary);
280
+ text-align: center;
281
+ transition: all 200ms ease;
282
+ }
283
+
284
+ :root.theme-dark .prac-result-box {
285
+ background: rgba(129, 140, 248, 0.1);
286
+ border-color: rgba(129, 140, 248, 0.6);
287
+ }
288
+
289
+ .prac-result-box:hover {
290
+ transform: translateY(-2px);
291
+ box-shadow: 0 8px 24px rgba(99, 102, 241, 0.15);
292
+ }
293
+
294
+ .prac-result-label {
295
+ display: block;
296
+ font-size: 0.75rem;
297
+ font-weight: 800;
298
+ color: var(--prac-neutral-light);
299
+ text-transform: uppercase;
300
+ letter-spacing: 0.8px;
301
+ margin-bottom: 0.5rem;
302
+ }
303
+
304
+ .prac-result-value {
305
+ display: block;
306
+ font-size: 2rem;
307
+ font-weight: 900;
308
+ color: var(--prac-primary);
309
+ margin-bottom: 0.35rem;
310
+ }
311
+
312
+ .prac-result-unit {
313
+ display: block;
314
+ font-size: 0.85rem;
315
+ color: var(--prac-neutral-light);
316
+ font-weight: 700;
317
+ }
318
+
319
+ .prac-svg {
320
+ width: 100%;
321
+ height: auto;
322
+ min-height: 180px;
323
+ max-height: 200px;
324
+ margin: 0.5rem 0;
325
+ }
326
+
327
+ .prac-label {
328
+ font-size: 12px;
329
+ font-weight: 800;
330
+ fill: var(--prac-primary);
331
+ text-anchor: middle;
332
+ }
333
+
334
+ .prac-label-hyp {
335
+ fill: var(--prac-primary);
336
+ font-weight: 900;
337
+ font-size: 13px;
338
+ }
339
+
340
+ .prac-message {
341
+ font-size: 0.95rem;
342
+ line-height: 1.5;
343
+ color: var(--prac-neutral);
344
+ font-weight: 700;
345
+ min-height: 1.5rem;
346
+ padding: 1rem;
347
+ background: rgba(245, 158, 11, 0.2);
348
+ border-left: 5px solid var(--prac-warning);
349
+ border-radius: 0.375rem;
350
+ }
351
+
352
+ .prac-status.error ~ .prac-message {
353
+ background: rgba(239, 68, 68, 0.2);
354
+ border-left-color: var(--prac-error);
355
+ }
356
+
357
+ .prac-status.perfect ~ .prac-message,
358
+ .prac-status.acceptable ~ .prac-message {
359
+ background: rgba(16, 185, 129, 0.2);
360
+ border-left-color: var(--prac-success);
361
+ }
362
+
363
+ .prac-status.idle ~ .prac-message {
364
+ background: transparent;
365
+ border: none;
366
+ min-height: auto;
367
+ padding: 0;
368
+ }
369
+
370
+ @media (max-width: 640px) {
371
+ .prac-inputs {
372
+ padding: 1.25rem;
373
+ }
374
+
375
+ .prac-display {
376
+ padding: 1.25rem;
377
+ }
378
+
379
+ .prac-result-value {
380
+ font-size: 1.75rem;
381
+ }
382
+
383
+ .prac-svg {
384
+ min-height: 160px;
385
+ max-height: 180px;
386
+ }
387
+ }
@@ -0,0 +1,15 @@
1
+ ---
2
+ import { SEORenderer } from '@jjlmoya/utils-shared';
3
+ import { pythagoreanRightAngleCalculator } from './index';
4
+ import type { KnownLocale } from '../../types';
5
+
6
+ interface Props {
7
+ locale?: KnownLocale;
8
+ }
9
+
10
+ const { locale = 'en' } = Astro.props;
11
+ const content = await pythagoreanRightAngleCalculator.i18n[locale]?.();
12
+ if (!content) return null;
13
+ ---
14
+
15
+ {content.seo?.length > 0 && <SEORenderer content={{ locale, sections: content.seo }} />}
@@ -0,0 +1,71 @@
1
+ export interface PythagoreanRightAngleCalculatorUI extends Record<string, string> {
2
+ titleMain: string;
3
+ labelInputData: string;
4
+ labelUnitSelection: string;
5
+ btnUnitInches: string;
6
+ btnUnitFeet: string;
7
+ btnUnitCentimeters: string;
8
+ labelSideA: string;
9
+ labelSideB: string;
10
+ labelMeasuredDiagonal: string;
11
+ labelResults: string;
12
+ labelIdealDiagonal: string;
13
+ labelDeviation: string;
14
+ labelStatus: string;
15
+ labelVerification: string;
16
+ btnClear: string;
17
+ btnCopyResults: string;
18
+ labelPresets: string;
19
+ unitInches: string;
20
+ unitFeet: string;
21
+ unitCentimeters: string;
22
+ tooltipOptional: string;
23
+ tooltipPresets: string;
24
+ statusPerfect: string;
25
+ statusAcceptable: string;
26
+ statusWarning: string;
27
+ statusError: string;
28
+ statusReady: string;
29
+ msgIdealCalculated: string;
30
+ actionOpen: string;
31
+ actionClose: string;
32
+ descLarger: string;
33
+ descSmaller: string;
34
+ descCorrection: string;
35
+ }
36
+
37
+ export const pythagoreanRightAngleCalculatorUI: PythagoreanRightAngleCalculatorUI = {
38
+ titleMain: 'Pythagorean Right Angle Calculator',
39
+ labelInputData: 'Measurements',
40
+ labelUnitSelection: 'Unit',
41
+ btnUnitInches: 'inches',
42
+ btnUnitFeet: 'feet',
43
+ btnUnitCentimeters: 'centimeters',
44
+ labelSideA: 'Side A',
45
+ labelSideB: 'Side B',
46
+ labelMeasuredDiagonal: 'Measured diagonal (optional)',
47
+ labelResults: 'Results',
48
+ labelIdealDiagonal: 'Ideal diagonal',
49
+ labelDeviation: 'Deviation',
50
+ labelStatus: 'Status',
51
+ labelVerification: 'Square verification',
52
+ btnClear: 'Clear',
53
+ btnCopyResults: 'Copy results',
54
+ labelPresets: 'Quick presets',
55
+ unitInches: 'in',
56
+ unitFeet: 'ft',
57
+ unitCentimeters: 'cm',
58
+ tooltipOptional: 'Enter your measured diagonal to verify perfect 90 degrees',
59
+ tooltipPresets: '3-4-5 rule in different scales',
60
+ statusPerfect: 'Perfect 90 degree angle',
61
+ statusAcceptable: 'Acceptable deviation',
62
+ statusWarning: 'Minor deviation',
63
+ statusError: 'Out of square',
64
+ statusReady: 'Ready',
65
+ msgIdealCalculated: 'Diagonal ideal calculated',
66
+ actionOpen: 'Open',
67
+ actionClose: 'Close',
68
+ descLarger: 'larger',
69
+ descSmaller: 'smaller',
70
+ descCorrection: 'Correction needed'
71
+ };
package/src/tools.ts CHANGED
@@ -14,6 +14,7 @@ import { DRILL_CALCULATOR_TOOL } from './tool/drillCalculator/index';
14
14
  import { STAIR_CALCULATOR_TOOL } from './tool/stairCalculator/index';
15
15
  import { DRILL_SHARPENER_TOOL } from './tool/drillSharpener/index';
16
16
  import { WORKSHOP_FRACTION_CONVERTER_TOOL } from './tool/workshopFractionConverter/index';
17
+ import { PYTHAGOREAN_RIGHT_ANGLE_CALCULATOR_TOOL } from './tool/pythagoreanRightAngleCalculator/index';
17
18
 
18
- export const ALL_TOOLS: ToolDefinition[] = [CLAY_CALCULATOR_TOOL, EPOXY_CALCULATOR_TOOL, BALUSTER_CALCULATOR_TOOL, MORTAR_CALCULATOR_TOOL, PASSEPARTOUT_CALCULATOR_TOOL, CONCRETE_CALCULATOR_TOOL, CUT_OPTIMIZER_TOOL, VOLTAGE_DROP_CALCULATOR_TOOL, FURNITURE_FIT_TOOL, THERMAL_EXPANSION_CALCULATOR_TOOL, DRILL_CALCULATOR_TOOL, STAIR_CALCULATOR_TOOL, DRILL_SHARPENER_TOOL, WORKSHOP_FRACTION_CONVERTER_TOOL];
19
+ export const ALL_TOOLS: ToolDefinition[] = [CLAY_CALCULATOR_TOOL, EPOXY_CALCULATOR_TOOL, BALUSTER_CALCULATOR_TOOL, MORTAR_CALCULATOR_TOOL, PASSEPARTOUT_CALCULATOR_TOOL, CONCRETE_CALCULATOR_TOOL, CUT_OPTIMIZER_TOOL, VOLTAGE_DROP_CALCULATOR_TOOL, FURNITURE_FIT_TOOL, THERMAL_EXPANSION_CALCULATOR_TOOL, DRILL_CALCULATOR_TOOL, STAIR_CALCULATOR_TOOL, DRILL_SHARPENER_TOOL, WORKSHOP_FRACTION_CONVERTER_TOOL, PYTHAGOREAN_RIGHT_ANGLE_CALCULATOR_TOOL];
19
20