@jjlmoya/utils-home 1.29.0 → 1.30.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 +4 -1
  3. package/src/index.ts +1 -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/applianceCostCalculator/appliance-cost-calculator.css +635 -0
  7. package/src/tool/applianceCostCalculator/bibliography.astro +14 -0
  8. package/src/tool/applianceCostCalculator/bibliography.ts +14 -0
  9. package/src/tool/applianceCostCalculator/component.astro +322 -0
  10. package/src/tool/applianceCostCalculator/entry.ts +29 -0
  11. package/src/tool/applianceCostCalculator/i18n/de.ts +229 -0
  12. package/src/tool/applianceCostCalculator/i18n/en.ts +229 -0
  13. package/src/tool/applianceCostCalculator/i18n/es.ts +229 -0
  14. package/src/tool/applianceCostCalculator/i18n/fr.ts +229 -0
  15. package/src/tool/applianceCostCalculator/i18n/id.ts +229 -0
  16. package/src/tool/applianceCostCalculator/i18n/it.ts +229 -0
  17. package/src/tool/applianceCostCalculator/i18n/ja.ts +229 -0
  18. package/src/tool/applianceCostCalculator/i18n/ko.ts +229 -0
  19. package/src/tool/applianceCostCalculator/i18n/nl.ts +229 -0
  20. package/src/tool/applianceCostCalculator/i18n/pl.ts +229 -0
  21. package/src/tool/applianceCostCalculator/i18n/pt.ts +229 -0
  22. package/src/tool/applianceCostCalculator/i18n/ru.ts +229 -0
  23. package/src/tool/applianceCostCalculator/i18n/sv.ts +229 -0
  24. package/src/tool/applianceCostCalculator/i18n/tr.ts +229 -0
  25. package/src/tool/applianceCostCalculator/i18n/zh.ts +229 -0
  26. package/src/tool/applianceCostCalculator/index.ts +9 -0
  27. package/src/tool/applianceCostCalculator/logic.ts +122 -0
  28. package/src/tool/applianceCostCalculator/seo.astro +15 -0
  29. package/src/tool/applianceCostCalculator/ui.ts +41 -0
  30. package/src/tools.ts +2 -0
@@ -0,0 +1,322 @@
1
+ ---
2
+ import type { ApplianceCostCalculatorUI } from './ui';
3
+ import { calculateCycleCost, fmt2 } from './logic';
4
+
5
+ interface Props {
6
+ ui?: Record<string, unknown>;
7
+ }
8
+
9
+ const { ui = {} } = Astro.props;
10
+ const aUI = ui as ApplianceCostCalculatorUI;
11
+
12
+ const DEF_APP = 'washer';
13
+ const DEF_CYCLE = 'normal';
14
+ const DEF_ELEC = 0.18;
15
+ const DEF_WATER = 0.003;
16
+ const DEF_DET = true;
17
+ const DEF_HOUR = 12;
18
+ const DEF_CYCLES = 3;
19
+
20
+ const initial = calculateCycleCost(DEF_APP, DEF_CYCLE, DEF_ELEC, DEF_WATER, DEF_DET, DEF_HOUR, DEF_CYCLES);
21
+ const HOURS = Array.from({ length: 24 }, (_, i) => i);
22
+ const PEAK = new Set([8, 9, 10, 11, 18, 19, 20, 21]);
23
+ ---
24
+
25
+ <div class="apc-root">
26
+ <div class="apc-card"
27
+ data-cs={aUI.currencySign}
28
+ data-curr-usd={aUI.btnCurrUSD}
29
+ data-curr-eur={aUI.btnCurrEUR}
30
+ data-curr-gbp={aUI.btnCurrGBP}
31
+ data-curr-jpy={aUI.btnCurrJPY}
32
+ data-pb={aUI.peakBadge}
33
+ data-op={aUI.offPeakBadge}
34
+ data-rpy={aUI.receiptPerYear}
35
+ data-ct={aUI.comparisonText}
36
+ data-csav={aUI.comparisonSavings}
37
+ data-uc={aUI.unitCycles}
38
+ >
39
+ <div class="apc-stage">
40
+ <div class="apc-stage-glow"></div>
41
+ <div class="apc-carousel" id="apc-carousel">
42
+ <button class="apc-appliance apc-active" data-app="washer" type="button">
43
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="4" width="18" height="16" rx="2"/><path d="M3 10h18M12 14v-2"/></svg>
44
+ <span>{aUI.applianceWasher}</span>
45
+ </button>
46
+ <button class="apc-appliance" data-app="dishwasher" type="button">
47
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="4" width="18" height="16" rx="2"/><path d="M3 10h18M8 14h.01M16 14h.01"/></svg>
48
+ <span>{aUI.applianceDishwasher}</span>
49
+ </button>
50
+ <button class="apc-appliance" data-app="dryer" type="button">
51
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="9"/><path d="M12 8v4l2 2"/></svg>
52
+ <span>{aUI.applianceDryer}</span>
53
+ </button>
54
+ </div>
55
+ <div class="apc-hero-num">
56
+ <p class="apc-hero-label">{aUI.receiptTotal}</p>
57
+ <p class="apc-hero-value">
58
+ <span id="apc-total-num">{fmt2(initial.totalCost)}</span>
59
+ <span id="apc-total-unit" class="apc-hero-unit">{aUI.currencySign}</span>
60
+ </p>
61
+ </div>
62
+ <div class="apc-currency-row">
63
+ <span class="apc-currency-label">{aUI.labelCurrency}</span>
64
+ <div class="apc-currency-btns">
65
+ <button class="apc-currency-btn apc-currency-active" data-currency="usd" type="button">{aUI.btnCurrUSD}</button>
66
+ <button class="apc-currency-btn" data-currency="eur" type="button">{aUI.btnCurrEUR}</button>
67
+ <button class="apc-currency-btn" data-currency="gbp" type="button">{aUI.btnCurrGBP}</button>
68
+ <button class="apc-currency-btn" data-currency="jpy" type="button">{aUI.btnCurrJPY}</button>
69
+ </div>
70
+ </div>
71
+ </div>
72
+
73
+ <div class="apc-body">
74
+ <p class="apc-section-label">{aUI.labelCycle}</p>
75
+ <div class="apc-pill-track" id="apc-pill-track">
76
+ <div class="apc-pill-indicator" id="apc-pill-indicator"></div>
77
+ <button class="apc-pill-btn" data-cycle="eco" type="button">{aUI.cycleEco}</button>
78
+ <button class="apc-pill-btn apc-active" data-cycle="normal" type="button">{aUI.cycleNormal}</button>
79
+ <button class="apc-pill-btn" data-cycle="intensive" type="button">{aUI.cycleIntensive}</button>
80
+ </div>
81
+
82
+ <div class="apc-fields">
83
+ <div class="apc-field">
84
+ <label class="apc-field-label" for="apc-elec">{aUI.labelElectricityPrice}</label>
85
+ <div style="display:flex;align-items:baseline;gap:0.4rem">
86
+ <input type="number" id="apc-elec" class="apc-field-input" value={DEF_ELEC} min="0" step="0.01" />
87
+ <span class="apc-field-unit">{aUI.unitPriceKwh}</span>
88
+ </div>
89
+ </div>
90
+ <div class="apc-field">
91
+ <label class="apc-field-label" for="apc-water">{aUI.labelWaterPrice}</label>
92
+ <div style="display:flex;align-items:baseline;gap:0.4rem">
93
+ <input type="number" id="apc-water" class="apc-field-input" value={DEF_WATER} min="0" step="0.001" />
94
+ <span class="apc-field-unit">{aUI.unitPriceLiter}</span>
95
+ </div>
96
+ </div>
97
+ </div>
98
+
99
+ <div class="apc-field">
100
+ <label class="apc-field-label" for="apc-cycles">{aUI.labelCyclesPerWeek}</label>
101
+ <input type="number" id="apc-cycles" class="apc-field-input" value={DEF_CYCLES} min="1" max="50" step="1" style="width:80px" />
102
+ </div>
103
+
104
+ <label class="apc-toggle">
105
+ <input type="checkbox" id="apc-det" checked={DEF_DET} />
106
+ <span class="apc-toggle-track"></span>
107
+ <span class="apc-toggle-text">{aUI.labelDetergentToggle}</span>
108
+ </label>
109
+
110
+ <p class="apc-section-label">{aUI.labelHour}</p>
111
+ <div class="apc-clock">
112
+ <div class="apc-clock-dial">
113
+ <div class="apc-clock-hand" id="apc-hand"></div>
114
+ <div class="apc-clock-center"></div>
115
+ </div>
116
+ <div class="apc-clock-hours" id="apc-hours">
117
+ {HOURS.map((h) => (
118
+ <button
119
+ class={`apc-hour-chip ${h === DEF_HOUR ? 'apc-active' : ''} ${PEAK.has(h) ? 'apc-peak' : ''}`}
120
+ data-hour={h}
121
+ type="button"
122
+ >
123
+ {String(h).padStart(2, '0')}
124
+ </button>
125
+ ))}
126
+ </div>
127
+ </div>
128
+
129
+ <div class="apc-receipt" id="apc-receipt">
130
+ <p class="apc-receipt-title">{aUI.receiptTitle}</p>
131
+ <div class="apc-receipt-row">
132
+ <span class="apc-receipt-name">{aUI.receiptElectricity}</span>
133
+ <span class="apc-receipt-price" id="apc-r-elec">{fmt2(initial.electricityCost)} {aUI.currencySign}</span>
134
+ </div>
135
+ <div class="apc-receipt-row">
136
+ <span class="apc-receipt-name">{aUI.receiptWater}</span>
137
+ <span class="apc-receipt-price" id="apc-r-water">{fmt2(initial.waterCost)} {aUI.currencySign}</span>
138
+ </div>
139
+ <div class="apc-receipt-row" id="apc-r-det-row">
140
+ <span class="apc-receipt-name">{aUI.receiptDetergent}</span>
141
+ <span class="apc-receipt-price" id="apc-r-det">{fmt2(initial.detergentCost)} {aUI.currencySign}</span>
142
+ </div>
143
+ <div class="apc-receipt-total">
144
+ <span class="apc-receipt-total-name">{aUI.receiptTotal}</span>
145
+ <span class="apc-receipt-total-price" id="apc-r-total">{fmt2(initial.totalCost)} {aUI.currencySign}</span>
146
+ </div>
147
+ <p class="apc-receipt-year" id="apc-r-year">{aUI.receiptPerYear}: {fmt2(initial.annualCost)} {aUI.currencySign}</p>
148
+ </div>
149
+ </div>
150
+
151
+ <div class="apc-tip">
152
+ <div class="apc-tip-card">
153
+ <p class="apc-tip-title">{aUI.comparisonTitle}</p>
154
+ <p class="apc-tip-text" id="apc-tip-text">{aUI.comparisonText}</p>
155
+ <span class="apc-tip-badge" id="apc-tip-badge">
156
+ {aUI.comparisonSavings}: {fmt2(initial.ecoSavingsPerYear)} {aUI.currencySign} / {aUI.unitCycles}
157
+ </span>
158
+ </div>
159
+ </div>
160
+ </div>
161
+ </div>
162
+
163
+ <script>
164
+ import { calculateCycleCost, fmt2 } from './logic';
165
+
166
+ const RATES: Record<string, number> = { eur: 1, usd: 1.08, gbp: 0.85, jpy: 160 };
167
+ const LS_KEY_CURRENCY = 'appliance-cost-currency';
168
+ let currency: 'usd' | 'eur' | 'gbp' | 'jpy' = 'eur';
169
+ let baseElec = 0.18;
170
+ let baseWater = 0.003;
171
+
172
+ function el(id: string) { return document.getElementById(id); }
173
+ function setTxt(id: string, val: string) { const e = el(id); if (e) e.textContent = val; }
174
+ function getNum(id: string): number { const e = el(id) as HTMLInputElement | null; return e ? parseFloat(e.value) || 0 : 0; }
175
+ function setVal(id: string, val: number) { const e = el(id) as HTMLInputElement | null; if (e) e.value = String(val); }
176
+ function getChk(id: string): boolean { const e = el(id) as HTMLInputElement | null; return e ? e.checked : false; }
177
+ function ds(card: HTMLElement, k: string): string { return card.dataset[k] ?? ''; }
178
+
179
+ function getCS(card: HTMLElement): string {
180
+ const key = `curr${currency.charAt(0).toUpperCase()}${currency.slice(1)}`;
181
+ return ds(card, key) || ds(card, 'cs') || '€';
182
+ }
183
+
184
+ function toBase(val: number) { return val / RATES[currency]; }
185
+ function fromBase(val: number) { return val * RATES[currency]; }
186
+
187
+ function readState(card: HTMLElement) {
188
+ const a = card.querySelector('.apc-appliance.apc-active') as HTMLElement | null;
189
+ const c = card.querySelector('.apc-pill-btn.apc-active') as HTMLElement | null;
190
+ const ah = card.querySelector('.apc-hour-chip.apc-active') as HTMLElement | null;
191
+ return {
192
+ applianceId: a?.dataset.app || 'washer',
193
+ cycle: (c?.dataset.cycle || 'normal') as 'eco' | 'normal' | 'intensive',
194
+ electricityPrice: getNum('apc-elec'),
195
+ waterPrice: getNum('apc-water'),
196
+ detergentEnabled: getChk('apc-det'),
197
+ hour: parseInt(ah?.dataset.hour || '12', 10),
198
+ cyclesPerWeek: getNum('apc-cycles'),
199
+ };
200
+ }
201
+
202
+ function setHand(hour: number) {
203
+ const hand = el('apc-hand') as HTMLElement | null;
204
+ if (!hand) return;
205
+ hand.style.transform = `translate(-50%, -100%) rotate(${(hour % 12) * 30}deg)`;
206
+ }
207
+
208
+ function moveIndicator(track: HTMLElement, activeBtn: HTMLElement) {
209
+ const ind = el('apc-pill-indicator') as HTMLElement | null;
210
+ if (!ind || !track || !activeBtn) return;
211
+ const tRect = track.getBoundingClientRect();
212
+ const bRect = activeBtn.getBoundingClientRect();
213
+ ind.style.width = `${bRect.width}px`;
214
+ ind.style.transform = `translateX(${bRect.left - tRect.left}px)`;
215
+ }
216
+
217
+ function renderReceipt(card: HTMLElement, r: ReturnType<typeof calculateCycleCost>, cs: string, det: boolean) {
218
+ setTxt('apc-total-num', fmt2(r.totalCost));
219
+ setTxt('apc-total-unit', cs);
220
+ setTxt('apc-r-elec', `${fmt2(r.electricityCost)} ${cs}`);
221
+ setTxt('apc-r-water', `${fmt2(r.waterCost)} ${cs}`);
222
+ setTxt('apc-r-det', `${fmt2(r.detergentCost)} ${cs}`);
223
+ setTxt('apc-r-total', `${fmt2(r.totalCost)} ${cs}`);
224
+ setTxt('apc-r-year', `${ds(card, 'rpy') || 'Per year'}: ${fmt2(r.annualCost)} ${cs}`);
225
+ const dRow = el('apc-r-det-row') as HTMLElement | null;
226
+ if (dRow) dRow.style.display = det ? 'flex' : 'none';
227
+ }
228
+
229
+ function renderTip(card: HTMLElement, r: ReturnType<typeof calculateCycleCost>, cs: string) {
230
+ const tipT = el('apc-tip-text') as HTMLElement | null;
231
+ if (tipT) tipT.textContent = (ds(card, 'ct') || 'Switch to Eco to save') + ` (${fmt2(r.ecoSavingsPerYear)} ${cs}/${ds(card, 'uc') || 'year'})`;
232
+ const tipB = el('apc-tip-badge') as HTMLElement | null;
233
+ if (tipB) tipB.textContent = `${ds(card, 'csav') || 'Savings'}: ${fmt2(r.ecoSavingsPerYear)} ${cs} / ${ds(card, 'uc') || 'year'}`;
234
+ }
235
+
236
+ function update(card: HTMLElement) {
237
+ const s = readState(card);
238
+ const r = calculateCycleCost(s);
239
+ const cs = getCS(card);
240
+ renderReceipt(card, r, cs, s.detergentEnabled);
241
+ renderTip(card, r, cs);
242
+ }
243
+
244
+ function applyCurrency(curr: 'usd' | 'eur' | 'gbp' | 'jpy', card: HTMLElement) {
245
+ baseElec = toBase(getNum('apc-elec'));
246
+ baseWater = toBase(getNum('apc-water'));
247
+ currency = curr;
248
+ localStorage.setItem(LS_KEY_CURRENCY, curr);
249
+ document.querySelectorAll('.apc-currency-btn').forEach((b) => b.classList.toggle('apc-currency-active', (b as HTMLElement).dataset.currency === curr));
250
+ setVal('apc-elec', fromBase(baseElec));
251
+ setVal('apc-water', fromBase(baseWater));
252
+ update(card);
253
+ }
254
+
255
+ function toggle(container: HTMLElement, sel: string, target: HTMLElement, cls: string) {
256
+ container.querySelectorAll(sel).forEach((b) => b.classList.toggle(cls, b === target));
257
+ }
258
+
259
+ function bindInputs(card: HTMLElement) {
260
+ ['apc-elec', 'apc-water', 'apc-cycles'].forEach((id) => { const i = el(id) as HTMLInputElement | null; if (i) i.addEventListener('input', () => update(card)); });
261
+ const det = el('apc-det') as HTMLInputElement | null;
262
+ if (det) det.addEventListener('change', () => update(card));
263
+ }
264
+
265
+ function bindCarousel(card: HTMLElement) {
266
+ const car = el('apc-carousel');
267
+ if (car) car.querySelectorAll('.apc-appliance').forEach((b) => b.addEventListener('click', () => { toggle(car, '.apc-appliance', b as HTMLElement, 'apc-active'); update(card); }));
268
+ }
269
+
270
+ function bindPills(card: HTMLElement) {
271
+ const track = el('apc-pill-track') as HTMLElement | null;
272
+ if (!track) return;
273
+ const normalBtn = track.querySelector('[data-cycle="normal"]') as HTMLElement | null;
274
+ if (normalBtn) moveIndicator(track, normalBtn);
275
+ track.querySelectorAll('.apc-pill-btn').forEach((b) => b.addEventListener('click', () => {
276
+ toggle(track, '.apc-pill-btn', b as HTMLElement, 'apc-active');
277
+ moveIndicator(track, b as HTMLElement);
278
+ update(card);
279
+ }));
280
+ }
281
+
282
+ function bindHours(card: HTMLElement) {
283
+ const hrs = el('apc-hours');
284
+ if (hrs) hrs.querySelectorAll('.apc-hour-chip').forEach((b) => b.addEventListener('click', () => {
285
+ toggle(hrs, '.apc-hour-chip', b as HTMLElement, 'apc-active');
286
+ setHand(parseInt((b as HTMLElement).dataset.hour || '12', 10));
287
+ update(card);
288
+ }));
289
+ }
290
+
291
+ function bindCurrency(card: HTMLElement) {
292
+ document.querySelectorAll('.apc-currency-btn').forEach((b) => b.addEventListener('click', () => {
293
+ const c = (b as HTMLElement).dataset.currency as 'usd' | 'eur' | 'gbp' | 'jpy';
294
+ if (c) applyCurrency(c, card);
295
+ }));
296
+ }
297
+
298
+ function init() {
299
+ const card = document.querySelector('.apc-card') as HTMLElement | null;
300
+ if (!card) return;
301
+
302
+ const saved = localStorage.getItem(LS_KEY_CURRENCY) as 'usd' | 'eur' | 'gbp' | 'jpy' | null;
303
+ if (saved) {
304
+ currency = saved;
305
+ setVal('apc-elec', fromBase(baseElec));
306
+ setVal('apc-water', fromBase(baseWater));
307
+ }
308
+ document.querySelectorAll('.apc-currency-btn').forEach((b) => b.classList.toggle('apc-currency-active', (b as HTMLElement).dataset.currency === currency));
309
+
310
+ bindCarousel(card);
311
+ bindPills(card);
312
+ bindHours(card);
313
+ bindCurrency(card);
314
+ bindInputs(card);
315
+
316
+ setHand(DEF_HOUR);
317
+ update(card);
318
+ }
319
+
320
+ document.addEventListener('astro:page-load', init);
321
+ init();
322
+ </script>
@@ -0,0 +1,29 @@
1
+ import type { HomeToolEntry, ToolLocaleContent } from '../../types';
2
+ import type { ApplianceCostCalculatorUI } from './ui';
3
+
4
+ export type ApplianceCostCalculatorLocaleContent = ToolLocaleContent<ApplianceCostCalculatorUI>;
5
+
6
+ export const applianceCostCalculator: HomeToolEntry<ApplianceCostCalculatorUI> = {
7
+ id: 'appliance-cost-calculator',
8
+ icons: {
9
+ bg: 'mdi:washing-machine',
10
+ fg: 'mdi:lightning-bolt',
11
+ },
12
+ i18n: {
13
+ en: async () => (await import('./i18n/en')).content,
14
+ es: async () => (await import('./i18n/es')).content,
15
+ de: async () => (await import('./i18n/de')).content,
16
+ fr: async () => (await import('./i18n/fr')).content,
17
+ it: async () => (await import('./i18n/it')).content,
18
+ pt: async () => (await import('./i18n/pt')).content,
19
+ nl: async () => (await import('./i18n/nl')).content,
20
+ pl: async () => (await import('./i18n/pl')).content,
21
+ sv: async () => (await import('./i18n/sv')).content,
22
+ ru: async () => (await import('./i18n/ru')).content,
23
+ tr: async () => (await import('./i18n/tr')).content,
24
+ zh: async () => (await import('./i18n/zh')).content,
25
+ ja: async () => (await import('./i18n/ja')).content,
26
+ ko: async () => (await import('./i18n/ko')).content,
27
+ id: async () => (await import('./i18n/id')).content,
28
+ },
29
+ };
@@ -0,0 +1,229 @@
1
+ import type { WithContext, FAQPage, HowTo, SoftwareApplication } from 'schema-dts';
2
+ import type { ToolLocaleContent } from '../../../types';
3
+ import type { ApplianceCostCalculatorUI } from '../ui';
4
+ import { bibliography } from '../bibliography';
5
+
6
+ const slug = 'geraetekosten-rechner';
7
+ const title = 'Kostenrechner für Wasser und Energie je Waschgang für Haushaltsgeräte';
8
+ const description =
9
+ 'Berechne die wahren Kosten pro Ladung deiner Waschmaschine, deines Geschirrspülers und deines Wäschetrockners. Sieh genau, wie viel Strom, Wasser und Waschmittel jeder Waschgang kostet und entdecke, wie viel du durch den Wechsel in den Eco Modus sparen kannst.';
10
+
11
+ const faqData = [
12
+ {
13
+ question: 'Wie viel kostet ein Waschmaschinengang?',
14
+ answer:
15
+ 'Ein typischer Eco 40C Gang verbraucht etwa 0,45 kWh Strom und 40 Liter Wasser. Bei durchschnittlichen europäischen Preisen kostet das etwa 0,10 bis 0,15 Euro pro Ladung. Ein intensiver 60C Gang kann über 1,2 kWh und 70 Liter verbrauchen und die Kosten auf über 0,30 Euro pro Ladung treiben.',
16
+ },
17
+ {
18
+ question: 'Ist es günstiger, den Geschirrspüler nachts laufen zu lassen?',
19
+ answer:
20
+ 'Wenn dein Stromanbieter Tarife mit Zeitunterscheidung verwendet, kann das Laufenlassen des Geschirrspülers in Schwachlastzeiten die Energiekosten um 30 Prozent oder mehr senken. Spitzenzeiten sind typischerweise an Wochentagen morgens und abends. Prüfe deinen Vertrag oder Daten deines intelligenten Zählers, um dein genaues Schwachlastfenster zu bestätigen.',
21
+ },
22
+ {
23
+ question: 'Verbraucht der Trockner viel Strom?',
24
+ answer:
25
+ 'Ja. Ein Wäschetrockner ist eines der energieintensivsten Haushaltsgeräte. Eine einzelne volle Ladung kann 2,5 bis 3,5 kWh verbrauchen und 0,50 bis 0,80 Euro pro Waschgang kosten. Die Verwendung eines Wärmepumpentrockners oder das Wäschetrocknen im Freien kann diese Kosten um 60 bis 80 Prozent senken.',
26
+ },
27
+ {
28
+ question: 'Wie viel Wasser verbraucht ein Geschirrspüler?',
29
+ answer:
30
+ 'Moderne Geschirrspüler sind erstaunlich effizient. Ein standardmäßiger Eco Gang verwendet nur 8 bis 12 Liter Wasser pro Ladung, während ein Intensivprogramm 14 bis 16 Liter verwenden kann. Das ist viel weniger als das Abwaschen der gleichen Geschirrmenge von Hand unter fließendem Wasser, was typischerweise 40 bis 60 Liter verbraucht.',
31
+ },
32
+ {
33
+ question: 'Wann ist die günstigste Zeit, um Geräte zu benutzen?',
34
+ answer:
35
+ 'Bei Tarifen mit Zeitunterscheidung sind die günstigsten Zeiträume normalerweise spät in der Nacht, sehr früh am Morgen und an Wochenenden. Diese Schwachlastzeiten können 30 bis 50 Prozent günstiger sein als Spitzenzeiten an Wochentagen. Einige Anbieter bieten auch kostenlose Stunden an Wochenenden an.',
36
+ },
37
+ {
38
+ question: 'Spart der Wechsel in den Eco Modus wirklich Geld?',
39
+ answer:
40
+ 'Absolut. Eco Modi verwenden niedrigere Temperaturen, kürzere Heizphasen und weniger Wasser. Über ein ganzes Jahr gesehen kann der Wechsel von Normal zu Eco bei Waschmaschine und Geschirrspüler 50 bis 100 Euro an Strom und Wasser zusammen sparen, je nach Nutzungshäufigkeit und lokalen Preisen.',
41
+ },
42
+ ];
43
+
44
+ const howToData = [
45
+ {
46
+ name: 'Wähle dein Gerät',
47
+ text: 'Tippe auf das Symbol der Waschmaschine, des Geschirrspülers oder des Wäschetrockners oben im Rechner. Jedes Gerät hat unterschiedliche Profile für Energie und Wasserverbrauch.',
48
+ },
49
+ {
50
+ name: 'Wähle einen Waschgang',
51
+ text: 'Verwende den Eco, Normal oder Intensiv Schieberegler, um das Waschprogramm einzustellen. Eco verwendet weniger Energie und Wasser. Intensiv verwendet am meisten.',
52
+ },
53
+ {
54
+ name: 'Gib deine lokalen Preise ein',
55
+ text: 'Tippe deinen Strompreis pro kWh und deinen Wasserpreis pro Liter ein. Du findest diese auf deiner Nebenkostenabrechnung oder der Webseite deines Anbieters.',
56
+ },
57
+ {
58
+ name: 'Lege die Nutzungshäufigkeit fest',
59
+ text: 'Gib an, wie viele Waschgänge du pro Woche machst. Damit kann der Rechner deine jährlichen Kosten und potenziellen Jahresersparnisse schätzen.',
60
+ },
61
+ {
62
+ name: 'Wähle die Nutzungsstunde',
63
+ text: 'Wähle die Stunde, in der du das Gerät laufen lassen möchtest. Spitzenzeiten sind rot markiert. Schwachlastzeiten sind grün und günstiger, wenn du einen Tarif mit Zeitunterscheidung hast.',
64
+ },
65
+ {
66
+ name: 'Schalte Waschmittelkosten zu',
67
+ text: 'Aktiviere den Waschmittel Schalter, wenn du möchtest, dass die Quittung einen Schätzwert für Pulver, Flüssigkeit oder Kapseln pro Waschgang enthält.',
68
+ },
69
+ ];
70
+
71
+ const faqSchema: WithContext<FAQPage> = {
72
+ '@context': 'https://schema.org',
73
+ '@type': 'FAQPage',
74
+ mainEntity: faqData.map((item) => ({
75
+ '@type': 'Question',
76
+ name: item.question,
77
+ acceptedAnswer: { '@type': 'Answer', text: item.answer },
78
+ })),
79
+ };
80
+
81
+ const howToSchema: WithContext<HowTo> = {
82
+ '@context': 'https://schema.org',
83
+ '@type': 'HowTo',
84
+ name: title,
85
+ description,
86
+ step: howToData.map((step) => ({
87
+ '@type': 'HowToStep',
88
+ name: step.name,
89
+ text: step.text,
90
+ })),
91
+ };
92
+
93
+ const appSchema: WithContext<SoftwareApplication> = {
94
+ '@context': 'https://schema.org',
95
+ '@type': 'SoftwareApplication',
96
+ name: title,
97
+ description,
98
+ applicationCategory: 'UtilityApplication',
99
+ operatingSystem: 'All',
100
+ offers: { '@type': 'Offer', price: '0', priceCurrency: 'EUR' },
101
+ inLanguage: 'de',
102
+ };
103
+
104
+ export const content: ToolLocaleContent<ApplianceCostCalculatorUI> = {
105
+ slug,
106
+ title,
107
+ description,
108
+ faq: faqData,
109
+ bibliography,
110
+ howTo: howToData,
111
+ schemas: [faqSchema, howToSchema, appSchema],
112
+ seo: [
113
+ {
114
+ type: 'title',
115
+ text: 'Die verborgenen Kosten jeder Ladung',
116
+ level: 2,
117
+ },
118
+ {
119
+ type: 'paragraph',
120
+ html: 'Die meisten Menschen haben keine Ahnung, wie viel ein einzelner Waschmaschinengang tatsächlich kostet. Sie sehen eine vierteljährliche Stromrechnung und nehmen an, dass Geräte billig im Betrieb sind. In Wirklichkeit kann eine Familie, die fünf Waschgänge pro Woche macht, über 200 Euro pro Jahr nur für Wäsche ausgeben. Addiere den Geschirrspüler drei Mal pro Woche und den Wäschetrockner zwei Mal pro Woche und die Summe steigt auf über 500 Euro jährlich. Dieser Rechner zerlegt jeden Cent, damit du deine Gewohnheiten optimieren kannst.',
121
+ },
122
+ {
123
+ type: 'stats',
124
+ items: [
125
+ { value: '0,45', label: 'kWh Eco Waschgang', icon: 'mdi:washing-machine' },
126
+ { value: '40L', label: 'Wasser Eco Waschgang', icon: 'mdi:water' },
127
+ { value: '30%', label: 'Spitzenaufschlag', icon: 'mdi:lightning-bolt' },
128
+ ],
129
+ columns: 3,
130
+ },
131
+ {
132
+ type: 'title',
133
+ text: 'Warum sich kleine Änderungen multiplizieren',
134
+ level: 3,
135
+ },
136
+ {
137
+ type: 'paragraph',
138
+ html: 'Ein einzelnes Grad Temperatur oder ein paar Liter Wasser erscheinen für einen Waschgang unwichtig. Aber über 250 Waschgänge pro Jahr summieren sich diese kleinen Unterschiede zu einem beträchtlichen Betrag. Das Senken von 60C auf 40C reduziert den Energieverbrauch um etwa 40 Prozent pro Ladung. Der Wechsel von Normal zu Eco bei einem Geschirrspüler spart jedes Mal etwa 3 Liter Wasser und 0,3 kWh. Das sind keine marginalen Gewinne. Das ist der schnellste Weg, deine Nebenkosten zu senken, ohne neue Geräte zu kaufen.',
139
+ },
140
+ {
141
+ type: 'comparative',
142
+ items: [
143
+ {
144
+ title: 'Intensiver Waschgang',
145
+ description: 'Maximale Hitze und Wasser für stark verschmutzte Ladungen.',
146
+ icon: 'mdi:alert',
147
+ points: ['1,2 bis 3,5 kWh pro Ladung', '70 Liter für Waschmaschinen', 'Spitzenzeitaufschlag gilt', 'Höchste Jahreskosten'],
148
+ },
149
+ {
150
+ title: 'Eco Waschgang',
151
+ description: 'Niedrigere Temperatur, optimierte Dauer, minimales Wasser.',
152
+ icon: 'mdi:check-circle',
153
+ points: ['0,45 bis 1,5 kWh pro Ladung', 'Nur 8 bis 40 Liter', 'Schwachlastzeiten nutzbar', 'Niedrigste Jahreskosten'],
154
+ },
155
+ ],
156
+ columns: 2,
157
+ },
158
+ {
159
+ type: 'diagnostic',
160
+ variant: 'info',
161
+ title: 'Schnelle Geräteprüfung',
162
+ icon: 'mdi:clipboard-check',
163
+ badge: 'Aktion',
164
+ html: '<p style="margin:0">Lass die Waschmaschine nur mit voller Ladung laufen. Verwende das Eco Programm für normale Verschmutzung. Stelle deinen Geschirrspüler auf verzögerten Start nach 22:00 Uhr ein, wenn du einen Tarif mit Zeitunterscheidung hast. Reinige das Flusensieb des Trockners nach jedem Waschgang, um die Effizienz zu erhalten. Trockne die Wäsche im Freien oder auf einem Wäscheständer, wann immer das Wetter es erlaubt.</p>',
165
+ },
166
+ {
167
+ type: 'title',
168
+ text: 'Zeitunterscheidung und Spitzenpreise',
169
+ level: 3,
170
+ },
171
+ {
172
+ type: 'paragraph',
173
+ html: 'Viele Stromanbieter berechnen unterschiedliche Tarife je nach Tageszeit. Spitzenperioden, normalerweise an Wochentagen morgens und abends, können 30 bis 50 Prozent mehr kosten als Schwachlastperioden. Eine Ladung, die um 20:00 Uhr läuft, kann 0,18 Euro kosten, während dieselbe Ladung um 02:00 Uhr nur 0,12 Euro kostet. Über ein Jahr richtig geplant kann das 50 bis 100 Euro sparen, ohne sonst etwas zu ändern. Dieser Rechner markiert Spitzenzeiten rot und Schwachlastzeiten grün, damit du im Voraus planen kannst.',
174
+ },
175
+ {
176
+ type: 'summary',
177
+ title: 'So senkst du Gerätekosten',
178
+ items: [
179
+ 'Nutze diesen Rechner, um die wahren Kosten pro Waschgang für deine Geräte zu finden.',
180
+ 'Wechsle wann immer möglich in den Eco Modus, um bis zu 40 Prozent Energie zu sparen.',
181
+ 'Lass volle Ladungen laufen, anstatt Teilladungen, um die Effizienz zu maximieren.',
182
+ 'Verschiebe Waschgänge in Schwachlastzeiten, wenn dein Tarif zeitabhängige Preise unterstützt.',
183
+ 'Trockne die Wäsche im Freien, anstatt den Wäschetrockner zu nutzen, um seine Kosten ganz zu eliminieren.',
184
+ 'Reinige Filter und entkalkte regelmäßig, damit die Geräte mit der angegebenen Effizienz laufen.',
185
+ ],
186
+ },
187
+ ],
188
+ ui: {
189
+ labelAppliance: 'Gerät',
190
+ applianceWasher: 'Waschmaschine',
191
+ applianceDishwasher: 'Geschirrspüler',
192
+ applianceDryer: 'Wäschetrockner',
193
+ labelCycle: 'Programm',
194
+ cycleEco: 'Eco',
195
+ cycleNormal: 'Normal',
196
+ cycleIntensive: 'Intensiv',
197
+ labelElectricityPrice: 'Strompreis',
198
+ unitPriceKwh: '€/kWh',
199
+ labelWaterPrice: 'Wasserpreis',
200
+ unitPriceLiter: '€/L',
201
+ labelDetergent: 'Waschmittel',
202
+ labelDetergentToggle: 'Waschmittelkosten einbeziehen',
203
+ labelHour: 'Geplante Stunde',
204
+ peakBadge: 'Spitzenzeit aktiv',
205
+ offPeakBadge: 'Schwachlastzeit',
206
+ receiptTitle: 'Kostenaufschlüsselung',
207
+ receiptElectricity: 'Strom',
208
+ receiptWater: 'Wasser',
209
+ receiptDetergent: 'Waschmittel',
210
+ receiptTotal: 'Gesamt pro Waschgang',
211
+ receiptPerYear: 'Geschätzt pro Jahr',
212
+ comparisonTitle: 'Intelligenter Wechsel',
213
+ comparisonText: 'Der Wechsel von Normal zu Eco spart bei jeder Ladung Geld.',
214
+ comparisonSavings: 'Jährliche Ersparnis',
215
+ comparisonMonths: 'Monate Waschmittel',
216
+ badgePeak: 'Spitze',
217
+ badgeOffPeak: 'Schwachlast',
218
+ unitKwh: 'kWh',
219
+ unitLiters: 'L',
220
+ unitCycles: 'Jahr',
221
+ labelCyclesPerWeek: 'Waschgänge pro Woche',
222
+ currencySign: '€',
223
+ labelCurrency: 'Währung',
224
+ btnCurrUSD: '$',
225
+ btnCurrEUR: '€',
226
+ btnCurrGBP: '£',
227
+ btnCurrJPY: '¥',
228
+ },
229
+ };