@jjlmoya/utils-diy 1.15.0 → 1.17.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 +5 -5
- package/src/entries.ts +3 -1
- package/src/index.ts +2 -0
- package/src/layouts/PreviewLayout.astro +1 -0
- package/src/tests/diacritics_density.test.ts +118 -0
- package/src/tests/inverted_punctuation.test.ts +84 -0
- package/src/tests/locale_completeness.test.ts +2 -2
- package/src/tests/no_en_dash.test.ts +70 -0
- package/src/tests/script_density.test.ts +94 -0
- package/src/tests/tool_validation.test.ts +2 -2
- package/src/tool/balusterCalculator/i18n/de.ts +7 -7
- package/src/tool/balusterCalculator/i18n/en.ts +4 -4
- package/src/tool/balusterCalculator/i18n/es.ts +2 -2
- package/src/tool/balusterCalculator/i18n/fr.ts +3 -3
- package/src/tool/balusterCalculator/i18n/it.ts +16 -16
- package/src/tool/balusterCalculator/i18n/ru.ts +14 -14
- package/src/tool/balusterCalculator/i18n/tr.ts +5 -5
- package/src/tool/clayCalculator/i18n/fr.ts +3 -3
- package/src/tool/clayCalculator/i18n/ru.ts +3 -3
- package/src/tool/concreteCalculator/i18n/en.ts +4 -4
- package/src/tool/concreteCalculator/i18n/fr.ts +2 -2
- package/src/tool/concreteCalculator/i18n/ko.ts +2 -2
- package/src/tool/concreteCalculator/i18n/ru.ts +3 -3
- package/src/tool/cutOptimizer/i18n/en.ts +4 -4
- package/src/tool/cutOptimizer/i18n/fr.ts +2 -2
- package/src/tool/cutOptimizer/i18n/ru.ts +2 -2
- package/src/tool/drillCalculator/bibliography.ts +2 -2
- package/src/tool/drillCalculator/i18n/ru.ts +5 -5
- package/src/tool/drillCalculator/i18n/zh.ts +2 -2
- package/src/tool/drillSharpener/i18n/ru.ts +3 -3
- package/src/tool/epoxyCalculator/epoxy-resin-calculator.css +81 -1
- package/src/tool/epoxyCalculator/i18n/de.ts +2 -2
- package/src/tool/epoxyCalculator/i18n/en.ts +2 -2
- package/src/tool/epoxyCalculator/i18n/es.ts +2 -2
- package/src/tool/epoxyCalculator/i18n/fr.ts +3 -3
- package/src/tool/epoxyCalculator/i18n/id.ts +2 -2
- package/src/tool/epoxyCalculator/i18n/it.ts +2 -2
- package/src/tool/epoxyCalculator/i18n/ja.ts +2 -2
- package/src/tool/epoxyCalculator/i18n/ko.ts +2 -2
- package/src/tool/epoxyCalculator/i18n/nl.ts +2 -2
- package/src/tool/epoxyCalculator/i18n/pl.ts +2 -2
- package/src/tool/epoxyCalculator/i18n/pt.ts +2 -2
- package/src/tool/epoxyCalculator/i18n/ru.ts +5 -5
- package/src/tool/epoxyCalculator/i18n/sv.ts +2 -2
- package/src/tool/epoxyCalculator/i18n/tr.ts +2 -2
- package/src/tool/epoxyCalculator/i18n/zh.ts +4 -4
- package/src/tool/furnitureFit/i18n/de.ts +2 -2
- package/src/tool/furnitureFit/i18n/en.ts +4 -4
- package/src/tool/furnitureFit/i18n/es.ts +2 -2
- package/src/tool/furnitureFit/i18n/fr.ts +3 -3
- package/src/tool/furnitureFit/i18n/id.ts +2 -2
- package/src/tool/furnitureFit/i18n/it.ts +2 -2
- package/src/tool/furnitureFit/i18n/ja.ts +2 -2
- package/src/tool/furnitureFit/i18n/ko.ts +2 -2
- package/src/tool/furnitureFit/i18n/nl.ts +2 -2
- package/src/tool/furnitureFit/i18n/pl.ts +2 -2
- package/src/tool/furnitureFit/i18n/pt.ts +2 -2
- package/src/tool/furnitureFit/i18n/ru.ts +6 -6
- package/src/tool/furnitureFit/i18n/sv.ts +2 -2
- package/src/tool/furnitureFit/i18n/tr.ts +2 -2
- package/src/tool/furnitureFit/i18n/zh.ts +2 -2
- package/src/tool/mortarCalculator/i18n/en.ts +3 -3
- package/src/tool/mortarCalculator/i18n/ru.ts +6 -6
- package/src/tool/mortarCalculator/i18n/zh.ts +3 -3
- package/src/tool/passepartoutCalculator/i18n/en.ts +4 -4
- package/src/tool/passepartoutCalculator/i18n/ru.ts +7 -7
- package/src/tool/passepartoutCalculator/i18n/zh.ts +6 -6
- package/src/tool/passepartoutCalculator/passepartout-calculator.css +99 -3
- package/src/tool/pythagoreanRightAngleCalculator/i18n/fr.ts +3 -3
- package/src/tool/pythagoreanRightAngleCalculator/i18n/pl.ts +2 -2
- package/src/tool/pythagoreanRightAngleCalculator/i18n/ru.ts +5 -5
- package/src/tool/stairCalculator/i18n/ru.ts +6 -6
- package/src/tool/stairCalculator/stair-calculator.css +76 -5
- package/src/tool/thermalExpansionCalculator/bibliography.ts +4 -4
- package/src/tool/thermalExpansionCalculator/i18n/en.ts +2 -2
- package/src/tool/thermalExpansionCalculator/i18n/fr.ts +3 -3
- package/src/tool/thermalExpansionCalculator/i18n/ru.ts +4 -4
- package/src/tool/twoStrokeMixtureCalculator/bibliography.astro +6 -0
- package/src/tool/twoStrokeMixtureCalculator/bibliography.ts +12 -0
- package/src/tool/twoStrokeMixtureCalculator/component.astro +266 -0
- package/src/tool/twoStrokeMixtureCalculator/entry.ts +24 -0
- package/src/tool/twoStrokeMixtureCalculator/i18n/de.ts +194 -0
- package/src/tool/twoStrokeMixtureCalculator/i18n/en.ts +194 -0
- package/src/tool/twoStrokeMixtureCalculator/i18n/es.ts +194 -0
- package/src/tool/twoStrokeMixtureCalculator/i18n/fr.ts +194 -0
- package/src/tool/twoStrokeMixtureCalculator/i18n/id.ts +194 -0
- package/src/tool/twoStrokeMixtureCalculator/i18n/it.ts +194 -0
- package/src/tool/twoStrokeMixtureCalculator/i18n/ja.ts +194 -0
- package/src/tool/twoStrokeMixtureCalculator/i18n/ko.ts +194 -0
- package/src/tool/twoStrokeMixtureCalculator/i18n/nl.ts +194 -0
- package/src/tool/twoStrokeMixtureCalculator/i18n/pl.ts +194 -0
- package/src/tool/twoStrokeMixtureCalculator/i18n/pt.ts +194 -0
- package/src/tool/twoStrokeMixtureCalculator/i18n/ru.ts +194 -0
- package/src/tool/twoStrokeMixtureCalculator/i18n/sv.ts +194 -0
- package/src/tool/twoStrokeMixtureCalculator/i18n/tr.ts +194 -0
- package/src/tool/twoStrokeMixtureCalculator/i18n/zh.ts +194 -0
- package/src/tool/twoStrokeMixtureCalculator/index.ts +11 -0
- package/src/tool/twoStrokeMixtureCalculator/logic.ts +92 -0
- package/src/tool/twoStrokeMixtureCalculator/seo.astro +15 -0
- package/src/tool/twoStrokeMixtureCalculator/two-stroke-fuel-mixture-calculator.css +405 -0
- package/src/tool/twoStrokeMixtureCalculator/ui.ts +81 -0
- package/src/tool/voltageDropCalculator/i18n/en.ts +2 -2
- package/src/tool/voltageDropCalculator/i18n/es.ts +4 -4
- package/src/tool/voltageDropCalculator/i18n/ru.ts +4 -4
- package/src/tool/workshopFractionConverter/bibliography.ts +2 -2
- package/src/tool/workshopFractionConverter/i18n/de.ts +2 -2
- package/src/tool/workshopFractionConverter/i18n/es.ts +2 -2
- package/src/tool/workshopFractionConverter/i18n/fr.ts +2 -2
- package/src/tool/workshopFractionConverter/i18n/ru.ts +9 -9
- package/src/tool/workshopFractionConverter/i18n/zh.ts +6 -6
- package/src/tools.ts +2 -1
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
export interface MixtureCalculation {
|
|
2
|
+
fuelVolume: number;
|
|
3
|
+
ratio: number;
|
|
4
|
+
oilRequired: number;
|
|
5
|
+
displayUnit: 'ml' | 'l';
|
|
6
|
+
richness: 'lean' | 'balanced' | 'rich';
|
|
7
|
+
totalMixture: number;
|
|
8
|
+
status: 'idle' | 'calculated';
|
|
9
|
+
message: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface PresetRatio {
|
|
13
|
+
label: string;
|
|
14
|
+
ratio: number;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function determineRichness(ratio: number): 'lean' | 'balanced' | 'rich' {
|
|
18
|
+
if (ratio <= 40) return 'rich';
|
|
19
|
+
if (ratio <= 50) return 'balanced';
|
|
20
|
+
return 'lean';
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function formatOilVolume(oilMl: number): { value: number; unit: 'ml' | 'l' } {
|
|
24
|
+
return oilMl < 1000 ? { value: oilMl, unit: 'ml' } : { value: oilMl / 1000, unit: 'l' };
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function createIdleResult(ui: Record<string, string>, fuelLiters: number, ratio: number): MixtureCalculation {
|
|
28
|
+
return {
|
|
29
|
+
fuelVolume: fuelLiters,
|
|
30
|
+
ratio,
|
|
31
|
+
oilRequired: 0,
|
|
32
|
+
displayUnit: 'ml',
|
|
33
|
+
richness: 'balanced',
|
|
34
|
+
totalMixture: 0,
|
|
35
|
+
status: 'idle',
|
|
36
|
+
message: ui.msgReady || 'Ready to calculate',
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export function calculateMixture(
|
|
41
|
+
fuelVolumeLiters: number,
|
|
42
|
+
ratioValue: number,
|
|
43
|
+
ui: Record<string, string> = {}
|
|
44
|
+
): MixtureCalculation {
|
|
45
|
+
const fuelLiters = parseFloat(String(fuelVolumeLiters)) || 0;
|
|
46
|
+
const ratio = parseFloat(String(ratioValue)) || 0;
|
|
47
|
+
|
|
48
|
+
if (fuelLiters <= 0 || ratio <= 0) {
|
|
49
|
+
return createIdleResult(ui, fuelLiters, ratio);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const oilRequiredMl = (fuelLiters * 1000) / ratio;
|
|
53
|
+
const { value: displayValue, unit: displayUnit } = formatOilVolume(oilRequiredMl);
|
|
54
|
+
|
|
55
|
+
return {
|
|
56
|
+
fuelVolume: fuelLiters,
|
|
57
|
+
ratio,
|
|
58
|
+
oilRequired: displayValue,
|
|
59
|
+
displayUnit,
|
|
60
|
+
richness: determineRichness(ratio),
|
|
61
|
+
totalMixture: fuelLiters + oilRequiredMl / 1000,
|
|
62
|
+
status: 'calculated',
|
|
63
|
+
message: ui.msgMixtureReady || 'Mixture calculated',
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export function calculateReverseRatio(
|
|
68
|
+
oilVolumeMl: number,
|
|
69
|
+
ratioValue: number
|
|
70
|
+
): { fuelRequired: number; unit: string } {
|
|
71
|
+
const oil = parseFloat(String(oilVolumeMl)) || 0;
|
|
72
|
+
const ratio = parseFloat(String(ratioValue)) || 0;
|
|
73
|
+
|
|
74
|
+
if (oil <= 0 || ratio <= 0) {
|
|
75
|
+
return { fuelRequired: 0, unit: 'L' };
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const fuelRequiredMl = oil * ratio;
|
|
79
|
+
const fuelRequiredL = fuelRequiredMl / 1000;
|
|
80
|
+
|
|
81
|
+
return {
|
|
82
|
+
fuelRequired: fuelRequiredL > 1 ? fuelRequiredL : fuelRequiredMl,
|
|
83
|
+
unit: fuelRequiredL > 1 ? 'L' : 'ml',
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export const PRESET_RATIOS: PresetRatio[] = [
|
|
88
|
+
{ label: '1:25', ratio: 25 },
|
|
89
|
+
{ label: '1:33', ratio: 33 },
|
|
90
|
+
{ label: '1:40', ratio: 40 },
|
|
91
|
+
{ label: '1:50', ratio: 50 },
|
|
92
|
+
];
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
---
|
|
2
|
+
import { SEORenderer } from '@jjlmoya/utils-shared';
|
|
3
|
+
import { twoStrokeMixtureCalculator } 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 twoStrokeMixtureCalculator.i18n[locale]?.();
|
|
12
|
+
if (!content) return null;
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
{content.seo?.length > 0 && <SEORenderer content={{ locale, sections: content.seo }} />}
|
|
@@ -0,0 +1,405 @@
|
|
|
1
|
+
:root {
|
|
2
|
+
--tsmc-primary: #ea580c;
|
|
3
|
+
--tsmc-secondary: #fbbf24;
|
|
4
|
+
--tsmc-accent-oil: #dc2626;
|
|
5
|
+
--tsmc-neutral: #1e293b;
|
|
6
|
+
--tsmc-neutral-light: #64748b;
|
|
7
|
+
--tsmc-border: #e2e8f0;
|
|
8
|
+
--tsmc-bg: #fff;
|
|
9
|
+
--tsmc-bg-light: #f8fafc;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
:root.theme-dark {
|
|
13
|
+
--tsmc-primary: #f97316;
|
|
14
|
+
--tsmc-secondary: #fcd34d;
|
|
15
|
+
--tsmc-accent-oil: #ef4444;
|
|
16
|
+
--tsmc-neutral: #f1f5f9;
|
|
17
|
+
--tsmc-neutral-light: #9ca3af;
|
|
18
|
+
--tsmc-border: rgba(255, 255, 255, 0.1);
|
|
19
|
+
--tsmc-bg: #0f172a;
|
|
20
|
+
--tsmc-bg-light: rgba(15, 23, 42, 0.8);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
.tsmc-root {
|
|
24
|
+
width: 100%;
|
|
25
|
+
color: var(--tsmc-neutral);
|
|
26
|
+
-webkit-font-smoothing: antialiased;
|
|
27
|
+
-moz-osx-font-smoothing: grayscale;
|
|
28
|
+
background: var(--tsmc-bg);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
.tsmc-mission-selector {
|
|
32
|
+
display: grid;
|
|
33
|
+
grid-template-columns: 1fr 1fr;
|
|
34
|
+
gap: 0.4rem;
|
|
35
|
+
padding: 0.75rem;
|
|
36
|
+
background: var(--tsmc-bg-light);
|
|
37
|
+
border-bottom: 2px solid var(--tsmc-primary);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
.tsmc-mission-btn {
|
|
41
|
+
display: flex;
|
|
42
|
+
align-items: center;
|
|
43
|
+
justify-content: center;
|
|
44
|
+
gap: 0.4rem;
|
|
45
|
+
padding: 0.6rem;
|
|
46
|
+
border: 2px solid var(--tsmc-border);
|
|
47
|
+
border-radius: 0.5rem;
|
|
48
|
+
background: var(--tsmc-bg);
|
|
49
|
+
color: var(--tsmc-neutral-light);
|
|
50
|
+
font-weight: 700;
|
|
51
|
+
font-size: 0.85rem;
|
|
52
|
+
cursor: pointer;
|
|
53
|
+
transition: all 150ms ease;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
.tsmc-mission-btn.active {
|
|
57
|
+
border-color: var(--tsmc-primary);
|
|
58
|
+
background: var(--tsmc-primary);
|
|
59
|
+
color: #fff;
|
|
60
|
+
box-shadow: 0 4px 8px rgba(234, 88, 12, 0.25);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
.tsmc-mission-btn svg {
|
|
64
|
+
width: 18px;
|
|
65
|
+
height: 18px;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
.tsmc-container {
|
|
69
|
+
display: flex;
|
|
70
|
+
flex-direction: column;
|
|
71
|
+
gap: 1rem;
|
|
72
|
+
padding: 1rem;
|
|
73
|
+
max-width: 100%;
|
|
74
|
+
transition: background-color 300ms ease;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
.tsmc-container.tsmc-oil-mode {
|
|
78
|
+
background: linear-gradient(135deg, rgba(34, 197, 94, 0.08) 0%, rgba(34, 197, 94, 0.04) 100%);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
.tsmc-oil-mode .tsmc-mission-selector {
|
|
82
|
+
background: rgba(34, 197, 94, 0.1);
|
|
83
|
+
border-bottom-color: #22c55e;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
.tsmc-oil-mode .tsmc-mission-btn.active {
|
|
87
|
+
background: #22c55e;
|
|
88
|
+
border-color: #22c55e;
|
|
89
|
+
box-shadow: 0 4px 8px rgba(34, 197, 94, 0.25);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
.tsmc-oil-mode .tsmc-slider {
|
|
93
|
+
background: linear-gradient(to right, #86efac, #22c55e);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
.tsmc-oil-mode .tsmc-slider::-webkit-slider-thumb {
|
|
97
|
+
background: #22c55e;
|
|
98
|
+
box-shadow: 0 2px 6px rgba(34, 197, 94, 0.4);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
.tsmc-oil-mode .tsmc-slider::-moz-range-thumb {
|
|
102
|
+
background: #22c55e;
|
|
103
|
+
box-shadow: 0 2px 6px rgba(34, 197, 94, 0.4);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
.tsmc-oil-mode .tsmc-slider-value-display {
|
|
107
|
+
color: #22c55e;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
.tsmc-oil-mode .tsmc-quick-btn.active {
|
|
111
|
+
background: #22c55e;
|
|
112
|
+
border-color: #22c55e;
|
|
113
|
+
box-shadow: 0 3px 8px rgba(34, 197, 94, 0.25);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
.tsmc-oil-mode .tsmc-mega-result {
|
|
117
|
+
border-color: #22c55e;
|
|
118
|
+
background: linear-gradient(135deg, rgba(34, 197, 94, 0.12) 0%, rgba(34, 197, 94, 0.06) 100%);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
.tsmc-oil-mode .tsmc-result-label,
|
|
122
|
+
.tsmc-oil-mode .tsmc-result-big {
|
|
123
|
+
color: #22c55e;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
.tsmc-oil-mode .tsmc-reset-btn {
|
|
127
|
+
border-color: #22c55e;
|
|
128
|
+
color: #22c55e;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
.tsmc-oil-mode .tsmc-reset-btn:hover {
|
|
132
|
+
background: #22c55e;
|
|
133
|
+
color: #fff;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
.tsmc-input-section,
|
|
137
|
+
.tsmc-ratio-section {
|
|
138
|
+
display: flex;
|
|
139
|
+
flex-direction: column;
|
|
140
|
+
gap: 0.6rem;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
.tsmc-section-label {
|
|
144
|
+
font-size: 0.65rem;
|
|
145
|
+
font-weight: 800;
|
|
146
|
+
color: var(--tsmc-neutral);
|
|
147
|
+
text-transform: uppercase;
|
|
148
|
+
letter-spacing: 0.6px;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
.tsmc-slider-container {
|
|
152
|
+
display: flex;
|
|
153
|
+
flex-direction: column;
|
|
154
|
+
gap: 0.6rem;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
.tsmc-slider {
|
|
158
|
+
width: 100%;
|
|
159
|
+
height: 10px;
|
|
160
|
+
border-radius: 5px;
|
|
161
|
+
background: linear-gradient(to right, #fcd34d, #f97316);
|
|
162
|
+
outline: none;
|
|
163
|
+
-webkit-appearance: none;
|
|
164
|
+
appearance: none;
|
|
165
|
+
cursor: pointer;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
.tsmc-slider::-webkit-slider-thumb {
|
|
169
|
+
-webkit-appearance: none;
|
|
170
|
+
appearance: none;
|
|
171
|
+
width: 24px;
|
|
172
|
+
height: 24px;
|
|
173
|
+
border-radius: 50%;
|
|
174
|
+
background: var(--tsmc-primary);
|
|
175
|
+
cursor: grab;
|
|
176
|
+
box-shadow: 0 2px 6px rgba(234, 88, 12, 0.4);
|
|
177
|
+
border: 2px solid var(--tsmc-bg);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
.tsmc-slider::-moz-range-thumb {
|
|
181
|
+
width: 24px;
|
|
182
|
+
height: 24px;
|
|
183
|
+
border-radius: 50%;
|
|
184
|
+
background: var(--tsmc-primary);
|
|
185
|
+
cursor: grab;
|
|
186
|
+
box-shadow: 0 2px 6px rgba(234, 88, 12, 0.4);
|
|
187
|
+
border: 2px solid var(--tsmc-bg);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
.tsmc-slider-value-display {
|
|
191
|
+
text-align: center;
|
|
192
|
+
font-size: 1.8rem;
|
|
193
|
+
font-weight: 800;
|
|
194
|
+
color: var(--tsmc-primary);
|
|
195
|
+
line-height: 1;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
.tsmc-unit {
|
|
199
|
+
font-size: 1rem;
|
|
200
|
+
margin-left: 0.3rem;
|
|
201
|
+
color: var(--tsmc-neutral);
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
.tsmc-quick-buttons {
|
|
205
|
+
display: grid;
|
|
206
|
+
grid-template-columns: 1fr 1fr 1fr;
|
|
207
|
+
gap: 0.4rem;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
.tsmc-quick-btn {
|
|
211
|
+
padding: 0.6rem 0.5rem;
|
|
212
|
+
border: 2px solid var(--tsmc-border);
|
|
213
|
+
border-radius: 0.4rem;
|
|
214
|
+
background: var(--tsmc-bg-light);
|
|
215
|
+
color: var(--tsmc-neutral);
|
|
216
|
+
font-weight: 700;
|
|
217
|
+
font-size: 0.8rem;
|
|
218
|
+
cursor: pointer;
|
|
219
|
+
transition: all 120ms ease;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
.tsmc-quick-btn:active {
|
|
223
|
+
transform: scale(0.95);
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
.tsmc-quick-btn.active {
|
|
227
|
+
background: var(--tsmc-primary);
|
|
228
|
+
color: #fff;
|
|
229
|
+
border-color: var(--tsmc-primary);
|
|
230
|
+
box-shadow: 0 3px 8px rgba(234, 88, 12, 0.25);
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
.tsmc-quick-btn.hidden {
|
|
234
|
+
display: none;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
.tsmc-ratio-cards {
|
|
238
|
+
display: grid;
|
|
239
|
+
grid-template-columns: 1fr 1fr;
|
|
240
|
+
gap: 0.5rem;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
.tsmc-ratio-card {
|
|
244
|
+
padding: 0.75rem;
|
|
245
|
+
border: 2px solid var(--tsmc-border);
|
|
246
|
+
border-radius: 0.5rem;
|
|
247
|
+
background: var(--tsmc-bg-light);
|
|
248
|
+
color: var(--tsmc-neutral);
|
|
249
|
+
cursor: pointer;
|
|
250
|
+
transition: all 150ms ease;
|
|
251
|
+
display: flex;
|
|
252
|
+
flex-direction: column;
|
|
253
|
+
gap: 0.3rem;
|
|
254
|
+
align-items: center;
|
|
255
|
+
text-align: center;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
.tsmc-ratio-card:hover {
|
|
259
|
+
border-color: var(--tsmc-primary);
|
|
260
|
+
background: var(--tsmc-bg);
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
.tsmc-ratio-card.active {
|
|
264
|
+
background: var(--tsmc-primary);
|
|
265
|
+
color: #fff;
|
|
266
|
+
border-color: var(--tsmc-primary);
|
|
267
|
+
box-shadow: 0 4px 10px rgba(234, 88, 12, 0.25);
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
.tsmc-ratio-value {
|
|
271
|
+
font-size: 1rem;
|
|
272
|
+
font-weight: 800;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
.tsmc-ratio-desc {
|
|
276
|
+
font-size: 0.7rem;
|
|
277
|
+
font-weight: 700;
|
|
278
|
+
opacity: 0.9;
|
|
279
|
+
line-height: 1.3;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
.tsmc-mega-result {
|
|
283
|
+
background: linear-gradient(135deg, rgba(234, 88, 12, 0.12) 0%, rgba(251, 191, 36, 0.06) 100%);
|
|
284
|
+
border: 2.5px solid var(--tsmc-primary);
|
|
285
|
+
border-radius: 0.75rem;
|
|
286
|
+
padding: 1rem;
|
|
287
|
+
display: flex;
|
|
288
|
+
flex-direction: column;
|
|
289
|
+
gap: 0.8rem;
|
|
290
|
+
align-items: center;
|
|
291
|
+
text-align: center;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
.tsmc-result-label {
|
|
295
|
+
font-size: 0.65rem;
|
|
296
|
+
font-weight: 800;
|
|
297
|
+
color: var(--tsmc-primary);
|
|
298
|
+
text-transform: uppercase;
|
|
299
|
+
letter-spacing: 0.5px;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
.tsmc-result-display {
|
|
303
|
+
display: flex;
|
|
304
|
+
align-items: baseline;
|
|
305
|
+
justify-content: center;
|
|
306
|
+
gap: 0.3rem;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
.tsmc-result-big {
|
|
310
|
+
font-size: 2.8rem;
|
|
311
|
+
font-weight: 900;
|
|
312
|
+
color: var(--tsmc-primary);
|
|
313
|
+
line-height: 1;
|
|
314
|
+
letter-spacing: -1px;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
.tsmc-result-unit {
|
|
318
|
+
font-size: 1rem;
|
|
319
|
+
font-weight: 700;
|
|
320
|
+
color: var(--tsmc-neutral);
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
.tsmc-container-visual {
|
|
324
|
+
width: 100%;
|
|
325
|
+
max-width: 120px;
|
|
326
|
+
height: auto;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
.tsmc-share-btn {
|
|
330
|
+
padding: 0.6rem;
|
|
331
|
+
border: 2px solid var(--tsmc-primary);
|
|
332
|
+
border-radius: 0.4rem;
|
|
333
|
+
background: var(--tsmc-bg);
|
|
334
|
+
color: var(--tsmc-primary);
|
|
335
|
+
cursor: pointer;
|
|
336
|
+
transition: all 150ms ease;
|
|
337
|
+
width: 100%;
|
|
338
|
+
display: flex;
|
|
339
|
+
align-items: center;
|
|
340
|
+
justify-content: center;
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
.tsmc-share-btn:hover {
|
|
344
|
+
background: var(--tsmc-primary);
|
|
345
|
+
color: #fff;
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
.tsmc-share-btn svg {
|
|
349
|
+
width: 20px;
|
|
350
|
+
height: 20px;
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
.tsmc-oil-mode .tsmc-share-btn {
|
|
354
|
+
border-color: #22c55e;
|
|
355
|
+
color: #22c55e;
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
.tsmc-oil-mode .tsmc-share-btn:hover {
|
|
359
|
+
background: #22c55e;
|
|
360
|
+
color: #fff;
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
.tsmc-checklist {
|
|
364
|
+
display: flex;
|
|
365
|
+
flex-direction: column;
|
|
366
|
+
gap: 0.5rem;
|
|
367
|
+
padding: 0.75rem;
|
|
368
|
+
background: var(--tsmc-bg-light);
|
|
369
|
+
border-radius: 0.5rem;
|
|
370
|
+
border: 1.5px solid var(--tsmc-border);
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
.tsmc-checklist-item {
|
|
374
|
+
display: flex;
|
|
375
|
+
align-items: center;
|
|
376
|
+
gap: 0.6rem;
|
|
377
|
+
font-weight: 600;
|
|
378
|
+
font-size: 0.8rem;
|
|
379
|
+
color: var(--tsmc-neutral);
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
.tsmc-checklist-item svg {
|
|
383
|
+
width: 18px;
|
|
384
|
+
height: 18px;
|
|
385
|
+
color: var(--tsmc-primary);
|
|
386
|
+
flex-shrink: 0;
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
@media (min-width: 480px) {
|
|
390
|
+
.tsmc-quick-buttons {
|
|
391
|
+
grid-template-columns: repeat(5, 1fr);
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
@media (min-width: 768px) {
|
|
396
|
+
.tsmc-container {
|
|
397
|
+
padding: 1.5rem;
|
|
398
|
+
max-width: 500px;
|
|
399
|
+
margin: 0 auto;
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
.tsmc-ratio-cards {
|
|
403
|
+
grid-template-columns: repeat(4, 1fr);
|
|
404
|
+
}
|
|
405
|
+
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
export interface TwoStrokeMixtureCalculatorUI extends Record<string, string> {
|
|
2
|
+
titleMain: string;
|
|
3
|
+
labelFuelVolume: string;
|
|
4
|
+
labelRatio: string;
|
|
5
|
+
labelOilRequired: string;
|
|
6
|
+
labelTotalMixture: string;
|
|
7
|
+
labelRichness: string;
|
|
8
|
+
labelPresets: string;
|
|
9
|
+
labelCustomRatio: string;
|
|
10
|
+
btnClear: string;
|
|
11
|
+
btnCopyResults: string;
|
|
12
|
+
btnSwitchMode: string;
|
|
13
|
+
unitLiters: string;
|
|
14
|
+
unitMilliliters: string;
|
|
15
|
+
richLean: string;
|
|
16
|
+
richBalanced: string;
|
|
17
|
+
richRich: string;
|
|
18
|
+
msgReady: string;
|
|
19
|
+
msgMixtureReady: string;
|
|
20
|
+
tooltipFuelVolume: string;
|
|
21
|
+
tooltipRatio: string;
|
|
22
|
+
recipientLabel: string;
|
|
23
|
+
oilPercentage: string;
|
|
24
|
+
labelVolume: string;
|
|
25
|
+
labelRatioShort: string;
|
|
26
|
+
labelOilTip: string;
|
|
27
|
+
labelMixingTips: string;
|
|
28
|
+
labelMixingTipsDesc: string;
|
|
29
|
+
recipePrefix: string;
|
|
30
|
+
recipeAt: string;
|
|
31
|
+
recipeAdd: string;
|
|
32
|
+
recipeOfOil: string;
|
|
33
|
+
copyTextPrefix: string;
|
|
34
|
+
copyTextFuel: string;
|
|
35
|
+
copyTextOil: string;
|
|
36
|
+
ratio25Desc: string;
|
|
37
|
+
ratio33Desc: string;
|
|
38
|
+
ratio40Desc: string;
|
|
39
|
+
ratio50Desc: string;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export const twoStrokeMixtureCalculatorUI: TwoStrokeMixtureCalculatorUI = {
|
|
43
|
+
titleMain: 'Two Stroke Fuel Mixture Calculator',
|
|
44
|
+
labelFuelVolume: 'Fuel Volume',
|
|
45
|
+
labelRatio: 'Mix Ratio',
|
|
46
|
+
labelOilRequired: 'Oil Required',
|
|
47
|
+
labelTotalMixture: 'Total Mixture',
|
|
48
|
+
labelRichness: 'Mixture Richness',
|
|
49
|
+
labelPresets: 'Common Ratios',
|
|
50
|
+
labelCustomRatio: 'Custom Ratio (1:X)',
|
|
51
|
+
btnClear: 'Clear',
|
|
52
|
+
btnCopyResults: 'Copy Results',
|
|
53
|
+
btnSwitchMode: 'Switch Mode',
|
|
54
|
+
unitLiters: 'L',
|
|
55
|
+
unitMilliliters: 'ml',
|
|
56
|
+
richLean: 'Lean (less oil, risk of seizure)',
|
|
57
|
+
richBalanced: 'Balanced (standard mix)',
|
|
58
|
+
richRich: 'Rich (more oil, more smoke, engine protection)',
|
|
59
|
+
msgReady: 'Ready',
|
|
60
|
+
msgMixtureReady: 'Mixture calculated',
|
|
61
|
+
tooltipFuelVolume: 'Enter the amount of gasoline',
|
|
62
|
+
tooltipRatio: 'Enter ratio as 25, 33, 40, or 50 (for 1:25, 1:33, etc.)',
|
|
63
|
+
recipientLabel: 'Mixture Container',
|
|
64
|
+
oilPercentage: 'Oil %',
|
|
65
|
+
labelVolume: 'Volume',
|
|
66
|
+
labelRatioShort: 'Ratio',
|
|
67
|
+
labelOilTip: '2% oil mix = 1:50 ratio',
|
|
68
|
+
labelMixingTips: 'Mixing Tips',
|
|
69
|
+
labelMixingTipsDesc: 'Mix in a clean container—gasoline first, add measured oil, then remaining fuel. Shake well (1-2 minutes) for homogeneous blend. Label with date and ratio.',
|
|
70
|
+
recipePrefix: 'For',
|
|
71
|
+
recipeAt: 'of fuel at',
|
|
72
|
+
recipeAdd: 'add exactly',
|
|
73
|
+
recipeOfOil: 'of 2-stroke oil.',
|
|
74
|
+
copyTextPrefix: '2-Stroke Mix',
|
|
75
|
+
copyTextFuel: 'fuel',
|
|
76
|
+
copyTextOil: 'oil',
|
|
77
|
+
ratio25Desc: 'Old machines',
|
|
78
|
+
ratio33Desc: 'Classic models',
|
|
79
|
+
ratio40Desc: 'Standard recommended',
|
|
80
|
+
ratio50Desc: 'Modern chainsaws',
|
|
81
|
+
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { WithContext, FAQPage, HowToThing, SoftwareApplication } from 'schema-dts';
|
|
1
|
+
import type { WithContext, FAQPage, HowToThing, SoftwareApplication } from 'schema-dts';
|
|
2
2
|
import type { ToolLocaleContent } from '../../../types';
|
|
3
3
|
import type { VoltageDropCalculatorUI } from '../ui';
|
|
4
4
|
import { bibliography } from '../bibliography';
|
|
@@ -97,7 +97,7 @@ export const content: ToolLocaleContent<VoltageDropCalculatorUI> = {
|
|
|
97
97
|
{ type: 'title', text: 'Complete Guide to Voltage Drop in DC and AC Systems', level: 2 },
|
|
98
98
|
{
|
|
99
99
|
type: 'paragraph',
|
|
100
|
-
html: 'Whether you are wiring a camper van, designing an off-grid solar system or running cable for garden lighting, there is one invisible enemy that can ruin your project before it starts: <strong>voltage drop</strong>. It is not just a technical nuance
|
|
100
|
+
html: 'Whether you are wiring a camper van, designing an off-grid solar system or running cable for garden lighting, there is one invisible enemy that can ruin your project before it starts: <strong>voltage drop</strong>. It is not just a technical nuance - it is the difference between a fridge that cools and one that shuts off, or between a safe installation and a fire hazard.',
|
|
101
101
|
},
|
|
102
102
|
{ type: 'title', text: 'The Ohm\'s Law Formula Behind the Calculator', level: 3 },
|
|
103
103
|
{
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { WithContext, FAQPage, HowToThing, SoftwareApplication } from 'schema-dts';
|
|
1
|
+
import type { WithContext, FAQPage, HowToThing, SoftwareApplication } from 'schema-dts';
|
|
2
2
|
import type { ToolLocaleContent } from '../../../types';
|
|
3
3
|
import type { VoltageDropCalculatorUI } from '../ui';
|
|
4
4
|
import { bibliography } from '../bibliography';
|
|
@@ -17,12 +17,12 @@ const faqData = [
|
|
|
17
17
|
{
|
|
18
18
|
question: '¿Qué sección de cable necesito para 12V a 10 metros?',
|
|
19
19
|
answer:
|
|
20
|
-
'Depende de la potencia. Para 12V y 10A a 10m, necesitas mínimo 2
|
|
20
|
+
'Depende de la potencia. Para 12V y 10A a 10m, necesitas mínimo 2,5mm². Para 20A, necesitas 6mm². A bajo voltaje (12V/24V), la caída es mucho más crítica que a 230V.',
|
|
21
21
|
},
|
|
22
22
|
{
|
|
23
|
-
question: '¿Puedo usar cable de 1
|
|
23
|
+
question: '¿Puedo usar cable de 1,5mm² para toda mi instalación?',
|
|
24
24
|
answer:
|
|
25
|
-
'No. 1
|
|
25
|
+
'No. 1,5mm² es para circuitos de iluminación (máx 10A). Para enchufes necesitas 2,5mm². Para cocina o lavadora necesitas 4mm² o 6mm². Usar cable fino es peligroso y puede causar incendios.',
|
|
26
26
|
},
|
|
27
27
|
{
|
|
28
28
|
question: '¿Cuál es la caída de tensión máxima permitida?',
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { WithContext, FAQPage, HowToThing, SoftwareApplication } from 'schema-dts';
|
|
1
|
+
import type { WithContext, FAQPage, HowToThing, SoftwareApplication } from 'schema-dts';
|
|
2
2
|
import type { ToolLocaleContent } from '../../../types';
|
|
3
3
|
import type { VoltageDropCalculatorUI } from '../ui';
|
|
4
4
|
import { bibliography } from '../bibliography';
|
|
@@ -14,11 +14,11 @@ const faqData = [
|
|
|
14
14
|
},
|
|
15
15
|
{
|
|
16
16
|
question: 'Какое сечение кабеля нужно для 12В на 10 метров?',
|
|
17
|
-
answer: 'Зависит от мощности. Для 12В и 10А на 10 м нужно минимум 2.5 мм². Для 20А
|
|
17
|
+
answer: 'Зависит от мощности. Для 12В и 10А на 10 м нужно минимум 2.5 мм². Для 20А - 6 мм². При низком напряжении (12В/24В) падение гораздо критичнее, чем при 230В.',
|
|
18
18
|
},
|
|
19
19
|
{
|
|
20
20
|
question: 'Можно ли использовать кабель 1.5 мм² для всей проводки?',
|
|
21
|
-
answer: 'Нет. 1.5 мм²
|
|
21
|
+
answer: 'Нет. 1.5 мм² - для цепей освещения (макс. 10А). Для розеток нужно 2.5 мм². Для плиты или стиральной машины - 4 мм² или 6 мм². Использование тонкого кабеля опасно и может привести к пожару.',
|
|
22
22
|
},
|
|
23
23
|
{
|
|
24
24
|
question: 'Какое максимально допустимое падение напряжения?',
|
|
@@ -80,7 +80,7 @@ export const content: ToolLocaleContent<VoltageDropCalculatorUI> = {
|
|
|
80
80
|
{ type: 'title', text: 'Полное руководство по падению напряжения', level: 2 },
|
|
81
81
|
{ type: 'paragraph', html: 'Если вы строите автодом, проектируете солнечную электростанцию или тянете кабель для освещения сада, у вас есть невидимый враг: <strong>падение напряжения</strong>. Это не просто технический нюанс; это разница между работающим холодильником и неисправным оборудованием, между безопасностью и риском пожара.' },
|
|
82
82
|
{ type: 'title', text: 'Формула падения напряжения', level: 3 },
|
|
83
|
-
{ type: 'card', icon: 'mdi:function-variant', title: 'Точный расчет по закону Ома', html: '<p>Формула: <strong>ΔV = (2 × L × I × ρ) / S</strong>, где L
|
|
83
|
+
{ type: 'card', icon: 'mdi:function-variant', title: 'Точный расчет по закону Ома', html: '<p>Формула: <strong>ΔV = (2 × L × I × ρ) / S</strong>, где L - длина в одну сторону, I - сила тока, ρ - удельное сопротивление (0.0178 для меди), S - сечение кабеля.</p>' },
|
|
84
84
|
],
|
|
85
85
|
ui: {
|
|
86
86
|
heroDropLabel: 'Общее падение напряжения',
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import type { BibliographyEntry } from '../../types';
|
|
1
|
+
import type { BibliographyEntry } from '../../types';
|
|
2
2
|
|
|
3
3
|
export const bibliography: BibliographyEntry[] = [
|
|
4
4
|
{
|
|
5
|
-
name: 'ISO 4759-1: Fasteners
|
|
5
|
+
name: 'ISO 4759-1: Fasteners - Technical conditions of delivery - Part 1: Bolts, screws and studs',
|
|
6
6
|
url: 'https://www.iso.org/standard/40895.html',
|
|
7
7
|
},
|
|
8
8
|
{
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { WithContext, FAQPage, HowToThing, SoftwareApplication } from 'schema-dts';
|
|
1
|
+
import type { WithContext, FAQPage, HowToThing, SoftwareApplication } from 'schema-dts';
|
|
2
2
|
import type { ToolLocaleContent } from '../../../types';
|
|
3
3
|
import type { WorkshopFractionConverterUI } from '../ui';
|
|
4
4
|
import { bibliography } from '../bibliography';
|
|
@@ -26,7 +26,7 @@ const faqData = [
|
|
|
26
26
|
},
|
|
27
27
|
{
|
|
28
28
|
question: 'Kann ich dieses Tool offline verwenden?',
|
|
29
|
-
answer: 'Ja. Alle Berechnungen finden in Ihrem Browser statt. Nach dem ersten Laden funktioniert das Tool komplett offline
|
|
29
|
+
answer: 'Ja. Alle Berechnungen finden in Ihrem Browser statt. Nach dem ersten Laden funktioniert das Tool komplett offline - perfekt für den Einsatz in der Werkstatt ohne WLAN.',
|
|
30
30
|
},
|
|
31
31
|
{
|
|
32
32
|
question: 'Warum enthält das Tool einen Verlauf?',
|