@jjlmoya/utils-diy 1.13.0 → 1.14.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 +238 -0
  9. package/src/tool/pythagoreanRightAngleCalculator/entry.ts +24 -0
  10. package/src/tool/pythagoreanRightAngleCalculator/i18n/de.ts +127 -0
  11. package/src/tool/pythagoreanRightAngleCalculator/i18n/en.ts +129 -0
  12. package/src/tool/pythagoreanRightAngleCalculator/i18n/es.ts +127 -0
  13. package/src/tool/pythagoreanRightAngleCalculator/i18n/fr.ts +127 -0
  14. package/src/tool/pythagoreanRightAngleCalculator/i18n/id.ts +127 -0
  15. package/src/tool/pythagoreanRightAngleCalculator/i18n/it.ts +127 -0
  16. package/src/tool/pythagoreanRightAngleCalculator/i18n/ja.ts +127 -0
  17. package/src/tool/pythagoreanRightAngleCalculator/i18n/ko.ts +129 -0
  18. package/src/tool/pythagoreanRightAngleCalculator/i18n/nl.ts +127 -0
  19. package/src/tool/pythagoreanRightAngleCalculator/i18n/pl.ts +127 -0
  20. package/src/tool/pythagoreanRightAngleCalculator/i18n/pt.ts +127 -0
  21. package/src/tool/pythagoreanRightAngleCalculator/i18n/ru.ts +127 -0
  22. package/src/tool/pythagoreanRightAngleCalculator/i18n/sv.ts +127 -0
  23. package/src/tool/pythagoreanRightAngleCalculator/i18n/tr.ts +127 -0
  24. package/src/tool/pythagoreanRightAngleCalculator/i18n/zh.ts +127 -0
  25. package/src/tool/pythagoreanRightAngleCalculator/index.ts +11 -0
  26. package/src/tool/pythagoreanRightAngleCalculator/logic.ts +96 -0
  27. package/src/tool/pythagoreanRightAngleCalculator/pythagorean-right-angle-calculator.css +378 -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,378 @@
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
+ font-weight: 700;
150
+ cursor: pointer;
151
+ font-size: 0.9rem;
152
+ transition: all 200ms ease;
153
+ text-transform: uppercase;
154
+ letter-spacing: 0.5px;
155
+ }
156
+
157
+ .prac-btn:hover {
158
+ border-color: var(--prac-primary);
159
+ background: var(--prac-bg-lighter);
160
+ transform: translateY(-2px);
161
+ }
162
+
163
+ .prac-btn:active {
164
+ transform: translateY(0);
165
+ }
166
+
167
+ .prac-presets {
168
+ display: grid;
169
+ grid-template-columns: 1fr 1fr;
170
+ gap: 0.75rem;
171
+ margin-top: 1.5rem;
172
+ padding-top: 1.5rem;
173
+ border-top: 2.5px solid var(--prac-border);
174
+ }
175
+
176
+ .prac-preset {
177
+ padding: 0.875rem 1rem;
178
+ border: 2.5px solid var(--prac-primary);
179
+ border-radius: 0.5rem;
180
+ background: var(--prac-bg-lighter);
181
+ color: var(--prac-neutral);
182
+ font-weight: 800;
183
+ cursor: pointer;
184
+ font-size: 0.9rem;
185
+ transition: all 200ms ease;
186
+ }
187
+
188
+ .prac-preset:hover {
189
+ background: var(--prac-primary);
190
+ color: #fff;
191
+ transform: translateY(-2px);
192
+ box-shadow: 0 6px 20px rgba(99, 102, 241, 0.3);
193
+ }
194
+
195
+ .prac-display {
196
+ padding: 1.5rem;
197
+ display: flex;
198
+ flex-direction: column;
199
+ gap: 1.25rem;
200
+ }
201
+
202
+ .prac-status {
203
+ padding: 1.25rem;
204
+ border-radius: 0.75rem;
205
+ border: 2.5px solid var(--prac-border);
206
+ background: var(--prac-bg-light);
207
+ display: grid;
208
+ grid-template-columns: 50px 1fr;
209
+ gap: 1rem;
210
+ align-items: center;
211
+ transition: all 200ms ease;
212
+ }
213
+
214
+ .prac-status-indicator {
215
+ width: 50px;
216
+ height: 50px;
217
+ border-radius: 50%;
218
+ background: #e5e7eb;
219
+ box-shadow: inset 0 0 0 2px #9ca3af;
220
+ }
221
+
222
+ .prac-status.perfect .prac-status-indicator {
223
+ background: var(--prac-success);
224
+ box-shadow: 0 0 16px rgba(16, 185, 129, 0.5);
225
+ }
226
+
227
+ .prac-status.acceptable .prac-status-indicator {
228
+ background: var(--prac-success);
229
+ box-shadow: 0 0 16px rgba(16, 185, 129, 0.5);
230
+ }
231
+
232
+ .prac-status.warning .prac-status-indicator {
233
+ background: var(--prac-warning);
234
+ box-shadow: 0 0 16px rgba(245, 158, 11, 0.5);
235
+ }
236
+
237
+ .prac-status.error .prac-status-indicator {
238
+ background: var(--prac-error);
239
+ box-shadow: 0 0 16px rgba(239, 68, 68, 0.5);
240
+ }
241
+
242
+ .prac-status-content {
243
+ display: flex;
244
+ flex-direction: column;
245
+ gap: 0.35rem;
246
+ }
247
+
248
+ .prac-status-title {
249
+ font-weight: 800;
250
+ font-size: 1.05rem;
251
+ color: var(--prac-neutral);
252
+ }
253
+
254
+ .prac-status-value {
255
+ font-size: 0.9rem;
256
+ color: var(--prac-neutral-light);
257
+ font-weight: 700;
258
+ }
259
+
260
+ .prac-results-grid {
261
+ display: grid;
262
+ grid-template-columns: 1fr 1fr;
263
+ gap: 1rem;
264
+ }
265
+
266
+ .prac-result-box {
267
+ padding: 1.25rem;
268
+ background: rgba(255, 255, 255, 0.5);
269
+ border-radius: 0.75rem;
270
+ border: 2.5px solid var(--prac-primary);
271
+ text-align: center;
272
+ transition: all 200ms ease;
273
+ }
274
+
275
+ :root.theme-dark .prac-result-box {
276
+ background: rgba(129, 140, 248, 0.1);
277
+ border-color: rgba(129, 140, 248, 0.6);
278
+ }
279
+
280
+ .prac-result-box:hover {
281
+ transform: translateY(-2px);
282
+ box-shadow: 0 8px 24px rgba(99, 102, 241, 0.15);
283
+ }
284
+
285
+ .prac-result-label {
286
+ display: block;
287
+ font-size: 0.75rem;
288
+ font-weight: 800;
289
+ color: var(--prac-neutral-light);
290
+ text-transform: uppercase;
291
+ letter-spacing: 0.8px;
292
+ margin-bottom: 0.5rem;
293
+ }
294
+
295
+ .prac-result-value {
296
+ display: block;
297
+ font-size: 2rem;
298
+ font-weight: 900;
299
+ color: var(--prac-primary);
300
+ margin-bottom: 0.35rem;
301
+ }
302
+
303
+ .prac-result-unit {
304
+ display: block;
305
+ font-size: 0.85rem;
306
+ color: var(--prac-neutral-light);
307
+ font-weight: 700;
308
+ }
309
+
310
+ .prac-svg {
311
+ width: 100%;
312
+ height: auto;
313
+ min-height: 180px;
314
+ max-height: 200px;
315
+ margin: 0.5rem 0;
316
+ }
317
+
318
+ .prac-label {
319
+ font-size: 12px;
320
+ font-weight: 800;
321
+ fill: var(--prac-primary);
322
+ text-anchor: middle;
323
+ }
324
+
325
+ .prac-label-hyp {
326
+ fill: var(--prac-primary);
327
+ font-weight: 900;
328
+ font-size: 13px;
329
+ }
330
+
331
+ .prac-message {
332
+ font-size: 0.95rem;
333
+ line-height: 1.5;
334
+ color: var(--prac-neutral);
335
+ font-weight: 700;
336
+ min-height: 1.5rem;
337
+ padding: 1rem;
338
+ background: rgba(245, 158, 11, 0.2);
339
+ border-left: 5px solid var(--prac-warning);
340
+ border-radius: 0.375rem;
341
+ }
342
+
343
+ .prac-status.error ~ .prac-message {
344
+ background: rgba(239, 68, 68, 0.2);
345
+ border-left-color: var(--prac-error);
346
+ }
347
+
348
+ .prac-status.perfect ~ .prac-message,
349
+ .prac-status.acceptable ~ .prac-message {
350
+ background: rgba(16, 185, 129, 0.2);
351
+ border-left-color: var(--prac-success);
352
+ }
353
+
354
+ .prac-status.idle ~ .prac-message {
355
+ background: transparent;
356
+ border: none;
357
+ min-height: auto;
358
+ padding: 0;
359
+ }
360
+
361
+ @media (max-width: 640px) {
362
+ .prac-inputs {
363
+ padding: 1.25rem;
364
+ }
365
+
366
+ .prac-display {
367
+ padding: 1.25rem;
368
+ }
369
+
370
+ .prac-result-value {
371
+ font-size: 1.75rem;
372
+ }
373
+
374
+ .prac-svg {
375
+ min-height: 160px;
376
+ max-height: 180px;
377
+ }
378
+ }
@@ -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