Compare commits
5 Commits
9dff578c15
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 2629ef1f12 | |||
| b5b7866395 | |||
| aff5b2cf12 | |||
| ec56a231e9 | |||
| 04a29ae8cd |
163
REFACTOR.md
Normal file
163
REFACTOR.md
Normal file
@@ -0,0 +1,163 @@
|
||||
# Refactoring-Optionen
|
||||
|
||||
## 1. `prepareValue` reparieren + tote `parseNumber`-Funktion entfernen
|
||||
|
||||
**Dateien:** `hugo/static/js/converter.js`
|
||||
|
||||
`prepareValue()` macht `input.replace(/,/g, '.')`. Bei deutscher Eingabe `1.000,50` wird
|
||||
daraus der ungültige String `1.000.50` – `new Decimal()` wirft einen Fehler und die
|
||||
Reaktivität bricht. Die Funktion `parseNumber()` (wird nirgends verwendet) würde das
|
||||
korrekt parsen.
|
||||
|
||||
**Vorschlag:** Logik von `parseNumber` in `prepareValue` übernehmen, `parseNumber`
|
||||
löschen.
|
||||
|
||||
**Effekt:** Bugfix + Tote-Code-Eliminierung.
|
||||
|
||||
---
|
||||
|
||||
## 2. Überzähliges schließendes `</div>` in Conversion-Seite entfernen
|
||||
|
||||
**Datei:** `hugo/layouts/conversion/single.html`
|
||||
|
||||
Vor dem abschließenden `{{ end }}` steht ein `</div>` ohne zugehöriges öffnendes
|
||||
Element in dieser Template-Datei. Das erzeugt invalides HTML.
|
||||
|
||||
**Effekt:** HTML-Korrektheit, weniger Fragilität.
|
||||
|
||||
---
|
||||
|
||||
## 3. Toten `intermediate`-Engine-Zweig aus Formel-Template entfernen
|
||||
|
||||
**Datei:** `hugo/layouts/partials/conversion-formula.html`
|
||||
|
||||
Keine JSON-Datendatei verwendet `"conversion_engine": "intermediate"`. Der komplette
|
||||
`else if eq .Params.engine "intermediate"`-Block wird niemals ausgeführt.
|
||||
|
||||
**Effekt:** Reduziert Template-Logik um ~20 Zeilen toten Code.
|
||||
|
||||
---
|
||||
|
||||
## 4. Engine-Partial dynamisch statt per `if/else` laden
|
||||
|
||||
**Datei:** `hugo/layouts/conversion/single.html`
|
||||
|
||||
Statt dreier verschachtelter `if/else` zur Auswahl des Data-Partials:
|
||||
|
||||
```html
|
||||
{{ if eq $engine "currencies" }} ... {{ else if eq $engine "temperatures" }} ... {{ else }} ... {{ end }}
|
||||
```
|
||||
|
||||
reicht ein dynamischer Partial-Aufruf:
|
||||
|
||||
```html
|
||||
{{ partial (printf "conversion/%s-data" $engine) . }}
|
||||
```
|
||||
|
||||
**Effekt:** Entfaltet 3 Ebenen verschachtelte Template-Logik.
|
||||
|
||||
---
|
||||
|
||||
## 5. SVG-Ladepattern in eigenes Partial extrahieren
|
||||
|
||||
**Dateien:** `hugo/layouts/index.html`, `hugo/layouts/404.html`,
|
||||
`hugo/layouts/partials/unit-dropdown.html`
|
||||
|
||||
Diese drei Dateien wiederholen identisch:
|
||||
|
||||
```html
|
||||
{{ $svgPath := printf "img/%s.svg" $data.slug }}
|
||||
{{ $svgFile := readFile (printf "static/%s" $svgPath) }}
|
||||
{{ if $svgFile }}{{ $svgFile | safeHTML }}{{ else }}<span></span>{{ end }}
|
||||
```
|
||||
|
||||
**Vorschlag:** `hugo/layouts/partials/icon.html` mit `(dict "slug" $data.slug)`.
|
||||
|
||||
**Effekt:** DRY, Änderungen am Icon-Loading zentral.
|
||||
|
||||
---
|
||||
|
||||
## 6. Wiederholte Select-Optionen-Logik in Partial auslagern
|
||||
|
||||
**Datei:** `hugo/layouts/conversion/single.html`
|
||||
|
||||
Die Dropdowns für „von“ und „in“ enthalten nahezu identische `range`-Schleifen mit
|
||||
nur leicht unterschiedlichen Variablen.
|
||||
|
||||
**Vorschlag:** `hugo/layouts/partials/unit-options.html` via Parameter
|
||||
`(dict "mode" "from" ...)` steuern.
|
||||
|
||||
**Effekt:** Weniger Redundanz, geringere Fehleranfälligkeit bei Änderungen.
|
||||
|
||||
---
|
||||
|
||||
## 7. `category-url.html` entminifizieren
|
||||
|
||||
**Datei:** `hugo/layouts/partials/category-url.html`
|
||||
|
||||
Aktuell 1 Zeile, 260+ Zeichen ohne Umbrüche. Das ist die komplexeste Logik der
|
||||
Seite (Finden des ersten und zweiten verfügbaren Units), aber völlig unlesbar.
|
||||
|
||||
**Effekt:** Deutlich bessere mentale Parsbarkeit.
|
||||
|
||||
---
|
||||
|
||||
## 8. URL-Wert-Normalisierung deduplizieren + `0`-Inkonsistenz fixen
|
||||
|
||||
**Datei:** `hugo/static/js/converter.js`
|
||||
|
||||
`updateUrl` und `navigate` wiederholen die Komma-zu-Punkt-Ersetzung. Zudem verhält
|
||||
sich `updateUrl("0")` anders als `navigate(url, "0")` (ersteres setzt `?v=1`,
|
||||
letzteres `?v=0`).
|
||||
|
||||
**Vorschlag:** Eine gemeinsame Funktion `normalizeUrlValue(value)` extrahieren.
|
||||
|
||||
**Effekt:** DRY + Konsistenzfix.
|
||||
|
||||
---
|
||||
|
||||
## 9. Redundantes `new Decimal(v)` in linear-data entfernen
|
||||
|
||||
**Datei:** `hugo/layouts/partials/conversion/linear-data.html`
|
||||
|
||||
`convert: v => new Decimal(v).times(...)` – `v` kommt bereits als `Decimal` aus
|
||||
`prepareValue`. Temperaturen und Währungen nutzen `v` direkt.
|
||||
|
||||
**Effekt:** Konsistentes Verhalten über alle Engines.
|
||||
|
||||
---
|
||||
|
||||
## 10. `_content.gotmpl` in Teil-Partials splitten
|
||||
|
||||
**Datei:** `hugo/content/_content.gotmpl`
|
||||
|
||||
Die Datei ist 140+ Zeilen lang und mischt drei Konzerne:
|
||||
Währungs-Page-Generierung, Linear-Page-Generierung und Temperaturen-Page-Generierung.
|
||||
|
||||
**Vorschlag:**
|
||||
`hugo/layouts/partials/content-generators/currencies.html`,
|
||||
`linear.html`, `temperatures.html`.
|
||||
|
||||
**Effekt:** Besseres Verständnis des Bauprozesses, leichteres Testen einzelner
|
||||
Generatoren.
|
||||
|
||||
---
|
||||
|
||||
## 11. Stille Fehler bei Währungs-Fetch im Build loggen
|
||||
|
||||
**Datei:** `hugo/layouts/partials/available-currencies.html`
|
||||
|
||||
Der Fehlerfall von `resources.GetRemote` wird abgefangen, aber nicht geloggt
|
||||
(`{{ with .Err }}{{ end }}`). `_content.gotmpl` macht das besser mit `warnf`.
|
||||
|
||||
**Effekt:** Einfacheres Debuggen bei Build-Zeit-Fehlern.
|
||||
|
||||
---
|
||||
|
||||
## Nicht empfohlen
|
||||
|
||||
- **SEO-Text-Partials vereinheitlichen:** 155 Dateien unter `partials/texts/`.
|
||||
Die sind inhaltsgetrieben, keine Code-Redundanz.
|
||||
- **Alle `conversion_engine` Defaults aus JSON entfernen:** Theoretisch
|
||||
defaultbar, aber die explizite Deklaration in jeder Datei ist defensiver und
|
||||
selbsterklärend.
|
||||
@@ -1,7 +1,7 @@
|
||||
services:
|
||||
web:
|
||||
build: .
|
||||
image: umrechner:v1.0.4
|
||||
image: umrechner:v1.0.7
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
- POCKETBASE_URL={$POCKETBASE_URL}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{{/* Generischer Content Adapter fuer Einheitsumrechner */}}
|
||||
{{/* Erzeugt alle from-to Permutationsseiten fuer linear, intermediate und runtime */}}
|
||||
{{/* Erzeugt alle from-to Permutationsseiten fuer linear, temperatures und currencies */}}
|
||||
|
||||
{{ $pbBase := getenv "POCKETBASE_URL" | default site.Params.pocketbase_url }}
|
||||
{{ $pbUrl := printf "%s/api/collections/currencies/records" $pbBase }}
|
||||
@@ -35,7 +35,7 @@
|
||||
{{ $categorySlug := $categoryData.slug }}
|
||||
{{ $units := $categoryData.units }}
|
||||
|
||||
{{ if eq $engine "runtime" }}
|
||||
{{ if eq $engine "currencies" }}
|
||||
{{ if not $pbOk }}{{ continue }}{{ end }}
|
||||
{{ $pbCurrencies := slice }}
|
||||
{{ range $record := $pbData }}
|
||||
@@ -59,8 +59,6 @@
|
||||
{{ $description := printf
|
||||
"Konvertieren Sie %s in %s. Einfache und schnelle Umrechnung mit Einheitsumrechner."
|
||||
$fromName $toName }}
|
||||
{{ $fromCurrency := $fromCode }}
|
||||
{{ $toCurrency := $toCode }}
|
||||
{{ $fromRate := 1 }}
|
||||
{{ if ne $fromCode "eur" }}
|
||||
{{ $fromRate = index $pbRates $fromCode }}
|
||||
@@ -78,9 +76,7 @@
|
||||
"to_name" $toName
|
||||
"slug" $slug
|
||||
"description" $description
|
||||
"engine" "runtime"
|
||||
"currency_from" $fromCurrency
|
||||
"currency_to" $toCurrency
|
||||
"engine" "currencies"
|
||||
"rate" $rate
|
||||
"rates_updated" $latestUpdate
|
||||
}}
|
||||
@@ -125,11 +121,21 @@
|
||||
"from_factor" $fromData.factor
|
||||
"to_factor" $toData.factor
|
||||
) }}
|
||||
{{ else if eq $engine "intermediate" }}
|
||||
{{ else if eq $engine "temperatures" }}
|
||||
{{ $convertFormulas := $categoryData.convertFormulas }}
|
||||
{{ $formula := "" }}
|
||||
{{ with index $convertFormulas $fromUnit }}
|
||||
{{ $formula = index . $toUnit }}
|
||||
{{ end }}
|
||||
{{ $displayFormulas := $categoryData.formulas }}
|
||||
{{ $displayFormula := "" }}
|
||||
{{ with index $displayFormulas $fromUnit }}
|
||||
{{ $displayFormula = index . $toUnit }}
|
||||
{{ end }}
|
||||
{{ $params = merge $params (dict
|
||||
"engine" "intermediate"
|
||||
"from_unit" $fromUnit
|
||||
"to_unit" $toUnit
|
||||
"engine" "temperatures"
|
||||
"convertFormula" $formula
|
||||
"displayFormula" $displayFormula
|
||||
) }}
|
||||
{{ end }}
|
||||
|
||||
|
||||
@@ -1,19 +1,69 @@
|
||||
{
|
||||
"slug": "datenspeicher",
|
||||
"name": "Datenspeicher",
|
||||
"unitOrder": [
|
||||
"bits",
|
||||
"bytes",
|
||||
"kilobytes_si",
|
||||
"kilobytes_binaer",
|
||||
"megabytes_si",
|
||||
"megabytes_binaer",
|
||||
"gigabytes_si",
|
||||
"gigabytes_binaer",
|
||||
"terabytes_si",
|
||||
"terabytes_binaer",
|
||||
"petabytes_si",
|
||||
"petabytes_binaer"
|
||||
],
|
||||
"conversion_engine": "linear",
|
||||
"units": {
|
||||
"bits": { "name": "Bits", "factor": "0.000000125" },
|
||||
"bytes": { "name": "Bytes", "factor": "0.000001" },
|
||||
"kilobytes_si": { "name": "Kilobytes (SI)", "factor": "0.001" },
|
||||
"kilobytes_binaer": { "name": "Kilobytes (binär)", "factor": "0.001024" },
|
||||
"megabytes_si": { "name": "Megabytes (SI)", "factor": "1" },
|
||||
"megabytes_binaer": { "name": "Megabytes (binär)", "factor": "1.048576" },
|
||||
"gigabytes_si": { "name": "Gigabytes (SI)", "factor": "1000" },
|
||||
"gigabytes_binaer": { "name": "Gigabytes (binär)", "factor": "1073.741824" },
|
||||
"terabytes_si": { "name": "Terabytes (SI)", "factor": "1000000" },
|
||||
"terabytes_binaer": { "name": "Terabytes (binär)", "factor": "1099511.627776" },
|
||||
"petabytes_si": { "name": "Petabytes (SI)", "factor": "1000000000" },
|
||||
"petabytes_binaer": { "name": "Petabytes (binär)", "factor": "1125899.906842624" }
|
||||
"bits": {
|
||||
"name": "Bits",
|
||||
"factor": "0.000000125"
|
||||
},
|
||||
"bytes": {
|
||||
"name": "Bytes",
|
||||
"factor": "0.000001"
|
||||
},
|
||||
"kilobytes_si": {
|
||||
"name": "Kilobytes (SI)",
|
||||
"factor": "0.001"
|
||||
},
|
||||
"kilobytes_binaer": {
|
||||
"name": "Kilobytes (binär)",
|
||||
"factor": "0.001024"
|
||||
},
|
||||
"megabytes_si": {
|
||||
"name": "Megabytes (SI)",
|
||||
"factor": "1"
|
||||
},
|
||||
"megabytes_binaer": {
|
||||
"name": "Megabytes (binär)",
|
||||
"factor": "1.048576"
|
||||
},
|
||||
"gigabytes_si": {
|
||||
"name": "Gigabytes (SI)",
|
||||
"factor": "1000"
|
||||
},
|
||||
"gigabytes_binaer": {
|
||||
"name": "Gigabytes (binär)",
|
||||
"factor": "1073.741824"
|
||||
},
|
||||
"terabytes_si": {
|
||||
"name": "Terabytes (SI)",
|
||||
"factor": "1000000"
|
||||
},
|
||||
"terabytes_binaer": {
|
||||
"name": "Terabytes (binär)",
|
||||
"factor": "1099511.627776"
|
||||
},
|
||||
"petabytes_si": {
|
||||
"name": "Petabytes (SI)",
|
||||
"factor": "1000000000"
|
||||
},
|
||||
"petabytes_binaer": {
|
||||
"name": "Petabytes (binär)",
|
||||
"factor": "1125899.906842624"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,15 +1,49 @@
|
||||
{
|
||||
"slug": "druecke",
|
||||
"name": "Drücke",
|
||||
"unitOrder": [
|
||||
"pascal",
|
||||
"hektopascal",
|
||||
"kilopascal",
|
||||
"pfund_pro_quadratzoll",
|
||||
"bar",
|
||||
"atmosphaeren",
|
||||
"torr",
|
||||
"millimeter_quecksilbersaeule"
|
||||
],
|
||||
"conversion_engine": "linear",
|
||||
"units": {
|
||||
"pascal": { "name": "Pascal", "factor": "1" },
|
||||
"hektopascal": { "name": "Hektopascal", "factor": "100" },
|
||||
"kilopascal": { "name": "Kilopascal", "factor": "1000" },
|
||||
"pfund_pro_quadratzoll": { "name": "Pfund pro Quadratzoll", "factor": "6894.75729" },
|
||||
"bar": { "name": "Bar", "factor": "100000" },
|
||||
"atmosphaeren": { "name": "Atmosphären", "factor": "101325" },
|
||||
"torr": { "name": "Torr", "factor": "133.3223684" },
|
||||
"millimeter_quecksilbersaeule": { "name": "Millimeter Quecksilbersäule", "factor": "133.3223684" }
|
||||
"pascal": {
|
||||
"name": "Pascal",
|
||||
"factor": "1"
|
||||
},
|
||||
"hektopascal": {
|
||||
"name": "Hektopascal",
|
||||
"factor": "100"
|
||||
},
|
||||
"kilopascal": {
|
||||
"name": "Kilopascal",
|
||||
"factor": "1000"
|
||||
},
|
||||
"pfund_pro_quadratzoll": {
|
||||
"name": "Pfund pro Quadratzoll",
|
||||
"factor": "6894.75729"
|
||||
},
|
||||
"bar": {
|
||||
"name": "Bar",
|
||||
"factor": "100000"
|
||||
},
|
||||
"atmosphaeren": {
|
||||
"name": "Atmosphären",
|
||||
"factor": "101325"
|
||||
},
|
||||
"torr": {
|
||||
"name": "Torr",
|
||||
"factor": "133.3223684"
|
||||
},
|
||||
"millimeter_quecksilbersaeule": {
|
||||
"name": "Millimeter Quecksilbersäule",
|
||||
"factor": "133.3223684"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,14 +1,44 @@
|
||||
{
|
||||
"slug": "energie",
|
||||
"name": "Energie",
|
||||
"unitOrder": [
|
||||
"joule",
|
||||
"kilojoule",
|
||||
"kalorien_naehrwert",
|
||||
"kalorien_thermisch",
|
||||
"kilowattstunden",
|
||||
"foot_pounds",
|
||||
"britische_waermeeinheiten"
|
||||
],
|
||||
"conversion_engine": "linear",
|
||||
"units": {
|
||||
"joule": { "name": "Joule", "factor": "1" },
|
||||
"kilojoule": { "name": "Kilojoule", "factor": "1000" },
|
||||
"kalorien_naehrwert": { "name": "Kalorien (nährwert)", "factor": "4184" },
|
||||
"kalorien_thermisch": { "name": "Kalorien (thermisch)", "factor": "4.184" },
|
||||
"kilowattstunden": { "name": "Kilowattstunden", "factor": "3600000" },
|
||||
"foot_pounds": { "name": "Foot-Pound", "factor": "1.3558179483314" },
|
||||
"britische_waermeeinheiten": { "name": "Britische Wärmeeinheiten", "factor": "1055.05585262" }
|
||||
"joule": {
|
||||
"name": "Joule",
|
||||
"factor": "1"
|
||||
},
|
||||
"kilojoule": {
|
||||
"name": "Kilojoule",
|
||||
"factor": "1000"
|
||||
},
|
||||
"kalorien_naehrwert": {
|
||||
"name": "Kalorien (nährwert)",
|
||||
"factor": "4184"
|
||||
},
|
||||
"kalorien_thermisch": {
|
||||
"name": "Kalorien (thermisch)",
|
||||
"factor": "4.184"
|
||||
},
|
||||
"kilowattstunden": {
|
||||
"name": "Kilowattstunden",
|
||||
"factor": "3600000"
|
||||
},
|
||||
"foot_pounds": {
|
||||
"name": "Foot-Pound",
|
||||
"factor": "1.3558179483314"
|
||||
},
|
||||
"britische_waermeeinheiten": {
|
||||
"name": "Britische Wärmeeinheiten",
|
||||
"factor": "1055.05585262"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +1,39 @@
|
||||
{
|
||||
"slug": "flaechen",
|
||||
"name": "Flächen",
|
||||
"unitOrder": [
|
||||
"quadratmeter",
|
||||
"quadratkilometer",
|
||||
"quadratmeilen",
|
||||
"quadratfuss",
|
||||
"acres",
|
||||
"hektar"
|
||||
],
|
||||
"conversion_engine": "linear",
|
||||
"units": {
|
||||
"quadratmeter": { "name": "Quadratmeter", "factor": "1" },
|
||||
"quadratkilometer": { "name": "Quadratkilometer", "factor": "1000000" },
|
||||
"quadratmeilen": { "name": "Quadratmeilen", "factor": "2589988.11" },
|
||||
"quadratfuss": { "name": "Quadratfuß", "factor": "0.092903" },
|
||||
"acres": { "name": "Acres", "factor": "4046.86" },
|
||||
"hektar": { "name": "Hektar", "factor": "10000" }
|
||||
"quadratmeter": {
|
||||
"name": "Quadratmeter",
|
||||
"factor": "1"
|
||||
},
|
||||
"quadratkilometer": {
|
||||
"name": "Quadratkilometer",
|
||||
"factor": "1000000"
|
||||
},
|
||||
"quadratmeilen": {
|
||||
"name": "Quadratmeilen",
|
||||
"factor": "2589988.11"
|
||||
},
|
||||
"quadratfuss": {
|
||||
"name": "Quadratfuß",
|
||||
"factor": "0.092903"
|
||||
},
|
||||
"acres": {
|
||||
"name": "Acres",
|
||||
"factor": "4046.86"
|
||||
},
|
||||
"hektar": {
|
||||
"name": "Hektar",
|
||||
"factor": "10000"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,14 +1,44 @@
|
||||
{
|
||||
"slug": "geschwindigkeiten",
|
||||
"name": "Geschwindigkeiten",
|
||||
"unitOrder": [
|
||||
"meter_pro_sekunde",
|
||||
"kilometer_pro_stunde",
|
||||
"fuss_pro_sekunde",
|
||||
"meilen_pro_stunde",
|
||||
"knoten",
|
||||
"mach",
|
||||
"lichtgeschwindigkeit"
|
||||
],
|
||||
"conversion_engine": "linear",
|
||||
"units": {
|
||||
"meter_pro_sekunde": { "name": "Meter pro Sekunde", "factor": "1" },
|
||||
"kilometer_pro_stunde": { "name": "Kilometer pro Stunde", "factor": "0.277778" },
|
||||
"fuss_pro_sekunde": { "name": "Fuß pro Sekunde", "factor": "0.3048" },
|
||||
"meilen_pro_stunde": { "name": "Meilen pro Stunde", "factor": "0.44704" },
|
||||
"knoten": { "name": "Knoten", "factor": "0.514444" },
|
||||
"mach": { "name": "Mach", "factor": "343" },
|
||||
"lichtgeschwindigkeit": { "name": "Lichtgeschwindigkeit", "factor": "299792458" }
|
||||
"meter_pro_sekunde": {
|
||||
"name": "Meter pro Sekunde",
|
||||
"factor": "1"
|
||||
},
|
||||
"kilometer_pro_stunde": {
|
||||
"name": "Kilometer pro Stunde",
|
||||
"factor": "0.277778"
|
||||
},
|
||||
"fuss_pro_sekunde": {
|
||||
"name": "Fuß pro Sekunde",
|
||||
"factor": "0.3048"
|
||||
},
|
||||
"meilen_pro_stunde": {
|
||||
"name": "Meilen pro Stunde",
|
||||
"factor": "0.44704"
|
||||
},
|
||||
"knoten": {
|
||||
"name": "Knoten",
|
||||
"factor": "0.514444"
|
||||
},
|
||||
"mach": {
|
||||
"name": "Mach",
|
||||
"factor": "343"
|
||||
},
|
||||
"lichtgeschwindigkeit": {
|
||||
"name": "Lichtgeschwindigkeit",
|
||||
"factor": "299792458"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,18 +1,64 @@
|
||||
{
|
||||
"slug": "gewichte",
|
||||
"name": "Gewichte",
|
||||
"unitOrder": [
|
||||
"gramm",
|
||||
"kilogramm",
|
||||
"pfund",
|
||||
"unzen",
|
||||
"metrische_tonnen",
|
||||
"kurze_tonnen",
|
||||
"karat",
|
||||
"milligramm",
|
||||
"mikrogramm",
|
||||
"stone",
|
||||
"gran"
|
||||
],
|
||||
"conversion_engine": "linear",
|
||||
"units": {
|
||||
"gramm": { "name": "Gramm", "factor": "1" },
|
||||
"kilogramm": { "name": "Kilogramm", "factor": "1000" },
|
||||
"pfund": { "name": "Pfund", "factor": "453.59237" },
|
||||
"unzen": { "name": "Unzen", "factor": "28.349523125" },
|
||||
"metrische_tonnen": { "name": "Metrische Tonnen", "factor": "1000000" },
|
||||
"kurze_tonnen": { "name": "Kurze Tonnen", "factor": "907184.74" },
|
||||
"karat": { "name": "Karat", "factor": "0.2" },
|
||||
"milligramm": { "name": "Milligramm", "factor": "0.001" },
|
||||
"mikrogramm": { "name": "Mikrogramm", "factor": "0.000001" },
|
||||
"stone": { "name": "Stone", "factor": "6350.29318" },
|
||||
"gran": { "name": "Gran", "factor": "0.06479891" }
|
||||
"gramm": {
|
||||
"name": "Gramm",
|
||||
"factor": "1"
|
||||
},
|
||||
"kilogramm": {
|
||||
"name": "Kilogramm",
|
||||
"factor": "1000"
|
||||
},
|
||||
"pfund": {
|
||||
"name": "Pfund",
|
||||
"factor": "453.59237"
|
||||
},
|
||||
"unzen": {
|
||||
"name": "Unzen",
|
||||
"factor": "28.349523125"
|
||||
},
|
||||
"metrische_tonnen": {
|
||||
"name": "Metrische Tonnen",
|
||||
"factor": "1000000"
|
||||
},
|
||||
"kurze_tonnen": {
|
||||
"name": "Kurze Tonnen",
|
||||
"factor": "907184.74"
|
||||
},
|
||||
"karat": {
|
||||
"name": "Karat",
|
||||
"factor": "0.2"
|
||||
},
|
||||
"milligramm": {
|
||||
"name": "Milligramm",
|
||||
"factor": "0.001"
|
||||
},
|
||||
"mikrogramm": {
|
||||
"name": "Mikrogramm",
|
||||
"factor": "0.000001"
|
||||
},
|
||||
"stone": {
|
||||
"name": "Stone",
|
||||
"factor": "6350.29318"
|
||||
},
|
||||
"gran": {
|
||||
"name": "Gran",
|
||||
"factor": "0.06479891"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,21 +1,79 @@
|
||||
{
|
||||
"slug": "laengen",
|
||||
"name": "Längen",
|
||||
"unitOrder": [
|
||||
"meter",
|
||||
"kilometer",
|
||||
"zentimeter",
|
||||
"millimeter",
|
||||
"mikrometer",
|
||||
"nanometer",
|
||||
"meilen",
|
||||
"yard",
|
||||
"fuss",
|
||||
"zoll",
|
||||
"seemeilen",
|
||||
"lichtjahre",
|
||||
"parsec",
|
||||
"astronomische_einheiten"
|
||||
],
|
||||
"conversion_engine": "linear",
|
||||
"units": {
|
||||
"meter": { "name": "Meter", "factor": "1" },
|
||||
"kilometer": { "name": "Kilometer", "factor": "1000" },
|
||||
"zentimeter": { "name": "Zentimeter", "factor": "0.01" },
|
||||
"millimeter": { "name": "Millimeter", "factor": "0.001" },
|
||||
"mikrometer": { "name": "Mikrometer", "factor": "0.000001" },
|
||||
"nanometer": { "name": "Nanometer", "factor": "0.000000001" },
|
||||
"meilen": { "name": "Meilen", "factor": "1609.34" },
|
||||
"yard": { "name": "Yard", "factor": "0.9144" },
|
||||
"fuss": { "name": "Fuß", "factor": "0.3048" },
|
||||
"zoll": { "name": "Zoll", "factor": "0.0254" },
|
||||
"seemeilen": { "name": "Seemeilen", "factor": "1852" },
|
||||
"lichtjahre": { "name": "Lichtjahre", "factor": "9460730472580800" },
|
||||
"parsec": { "name": "Parsec", "factor": "30856775814913673" },
|
||||
"astronomische_einheiten": { "name": "Astronomische Einheiten", "factor": "149597870700" }
|
||||
"meter": {
|
||||
"name": "Meter",
|
||||
"factor": "1"
|
||||
},
|
||||
"kilometer": {
|
||||
"name": "Kilometer",
|
||||
"factor": "1000"
|
||||
},
|
||||
"zentimeter": {
|
||||
"name": "Zentimeter",
|
||||
"factor": "0.01"
|
||||
},
|
||||
"millimeter": {
|
||||
"name": "Millimeter",
|
||||
"factor": "0.001"
|
||||
},
|
||||
"mikrometer": {
|
||||
"name": "Mikrometer",
|
||||
"factor": "0.000001"
|
||||
},
|
||||
"nanometer": {
|
||||
"name": "Nanometer",
|
||||
"factor": "0.000000001"
|
||||
},
|
||||
"meilen": {
|
||||
"name": "Meilen",
|
||||
"factor": "1609.34"
|
||||
},
|
||||
"yard": {
|
||||
"name": "Yard",
|
||||
"factor": "0.9144"
|
||||
},
|
||||
"fuss": {
|
||||
"name": "Fuß",
|
||||
"factor": "0.3048"
|
||||
},
|
||||
"zoll": {
|
||||
"name": "Zoll",
|
||||
"factor": "0.0254"
|
||||
},
|
||||
"seemeilen": {
|
||||
"name": "Seemeilen",
|
||||
"factor": "1852"
|
||||
},
|
||||
"lichtjahre": {
|
||||
"name": "Lichtjahre",
|
||||
"factor": "9460730472580800"
|
||||
},
|
||||
"parsec": {
|
||||
"name": "Parsec",
|
||||
"factor": "30856775814913673"
|
||||
},
|
||||
"astronomische_einheiten": {
|
||||
"name": "Astronomische Einheiten",
|
||||
"factor": "149597870700"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,24 @@
|
||||
{
|
||||
"slug": "mehrwertsteuer",
|
||||
"name": "Mehrwertsteuer",
|
||||
"unitOrder": [
|
||||
"brutto",
|
||||
"netto_allgemein",
|
||||
"netto_grundbedarf"
|
||||
],
|
||||
"conversion_engine": "linear",
|
||||
"units": {
|
||||
"brutto": { "name": "Brutto", "factor": "1" },
|
||||
"netto_allgemein": { "name": "Netto Allgemein (19%)", "factor": "1.19" },
|
||||
"netto_grundbedarf": { "name": "Netto Grundbedarf (7%)", "factor": "1.07" }
|
||||
"brutto": {
|
||||
"name": "Brutto",
|
||||
"factor": "1"
|
||||
},
|
||||
"netto_allgemein": {
|
||||
"name": "Netto Allgemein (19%)",
|
||||
"factor": "1.19"
|
||||
},
|
||||
"netto_grundbedarf": {
|
||||
"name": "Netto Grundbedarf (7%)",
|
||||
"factor": "1.07"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,25 +1,93 @@
|
||||
{
|
||||
"slug": "temperaturen",
|
||||
"name": "Temperaturen",
|
||||
"conversion_engine": "intermediate",
|
||||
"intermediate_unit": "celsius",
|
||||
"unitOrder": [
|
||||
"celsius",
|
||||
"fahrenheit",
|
||||
"kelvin",
|
||||
"rankine",
|
||||
"reaumur"
|
||||
],
|
||||
"conversion_engine": "temperatures",
|
||||
"units": {
|
||||
"celsius": { "name": "Celsius" },
|
||||
"fahrenheit": { "name": "Fahrenheit" },
|
||||
"kelvin": { "name": "Kelvin" },
|
||||
"rankine": { "name": "Rankine" },
|
||||
"reaumur": { "name": "Réaumur" }
|
||||
"celsius": {
|
||||
"name": "Celsius"
|
||||
},
|
||||
"fahrenheit": {
|
||||
"name": "Fahrenheit"
|
||||
},
|
||||
"kelvin": {
|
||||
"name": "Kelvin"
|
||||
},
|
||||
"rankine": {
|
||||
"name": "Rankine"
|
||||
},
|
||||
"reaumur": {
|
||||
"name": "Réaumur"
|
||||
}
|
||||
},
|
||||
"to_intermediate": {
|
||||
"fahrenheit": "(v - 32) * 5/9",
|
||||
"kelvin": "v - 273.15",
|
||||
"rankine": "(v - 491.67) * 5/9",
|
||||
"reaumur": "v * 5/4"
|
||||
"formulas": {
|
||||
"celsius": {
|
||||
"fahrenheit": "Fahrenheit = Celsius × 9/5 + 32",
|
||||
"kelvin": "Kelvin = Celsius + 273,15",
|
||||
"rankine": "Rankine = (Celsius + 273,15) × 9/5",
|
||||
"reaumur": "Réaumur = Celsius × 4/5"
|
||||
},
|
||||
"fahrenheit": {
|
||||
"celsius": "Celsius = (Fahrenheit − 32) × 5/9",
|
||||
"kelvin": "Kelvin = (Fahrenheit − 32) × 5/9 + 273,15",
|
||||
"rankine": "Rankine = Fahrenheit + 459,67",
|
||||
"reaumur": "Réaumur = (Fahrenheit − 32) × 4/9"
|
||||
},
|
||||
"kelvin": {
|
||||
"celsius": "Celsius = Kelvin − 273,15",
|
||||
"fahrenheit": "Fahrenheit = (Kelvin − 273,15) × 9/5 + 32",
|
||||
"rankine": "Rankine = Kelvin × 9/5",
|
||||
"reaumur": "Réaumur = (Kelvin − 273,15) × 4/5"
|
||||
},
|
||||
"rankine": {
|
||||
"celsius": "Celsius = (Rankine − 491,67) × 5/9",
|
||||
"fahrenheit": "Fahrenheit = Rankine − 459,67",
|
||||
"kelvin": "Kelvin = Rankine × 5/9",
|
||||
"reaumur": "Réaumur = (Rankine − 491,67) × 4/9"
|
||||
},
|
||||
"reaumur": {
|
||||
"celsius": "Celsius = Réaumur × 5/4",
|
||||
"fahrenheit": "Fahrenheit = Réaumur × 9/4 + 32",
|
||||
"kelvin": "Kelvin = Réaumur × 5/4 + 273,15",
|
||||
"rankine": "Rankine = (Réaumur × 5/4 + 273,15) × 9/5"
|
||||
}
|
||||
},
|
||||
"from_intermediate": {
|
||||
"fahrenheit": "v * 9/5 + 32",
|
||||
"kelvin": "v + 273.15",
|
||||
"rankine": "(v + 273.15) * 9/5",
|
||||
"reaumur": "v * 4/5"
|
||||
"convertFormulas": {
|
||||
"celsius": {
|
||||
"fahrenheit": "v => v.times(9).dividedBy(5).plus(32)",
|
||||
"kelvin": "v => v.plus(273.15)",
|
||||
"rankine": "v => v.plus(273.15).times(9).dividedBy(5)",
|
||||
"reaumur": "v => v.times(4).dividedBy(5)"
|
||||
},
|
||||
"fahrenheit": {
|
||||
"celsius": "v => v.minus(32).times(5).dividedBy(9)",
|
||||
"kelvin": "v => v.minus(32).times(5).dividedBy(9).plus(273.15)",
|
||||
"rankine": "v => v.plus(459.67)",
|
||||
"reaumur": "v => v.minus(32).times(4).dividedBy(9)"
|
||||
},
|
||||
"kelvin": {
|
||||
"celsius": "v => v.minus(273.15)",
|
||||
"fahrenheit": "v => v.minus(273.15).times(9).dividedBy(5).plus(32)",
|
||||
"rankine": "v => v.times(9).dividedBy(5)",
|
||||
"reaumur": "v => v.minus(273.15).times(4).dividedBy(5)"
|
||||
},
|
||||
"rankine": {
|
||||
"celsius": "v => v.minus(491.67).times(5).dividedBy(9)",
|
||||
"fahrenheit": "v => v.minus(459.67)",
|
||||
"kelvin": "v => v.times(5).dividedBy(9)",
|
||||
"reaumur": "v => v.minus(491.67).times(4).dividedBy(9)"
|
||||
},
|
||||
"reaumur": {
|
||||
"celsius": "v => v.times(5).dividedBy(4)",
|
||||
"fahrenheit": "v => v.times(9).dividedBy(4).plus(32)",
|
||||
"kelvin": "v => v.times(5).dividedBy(4).plus(273.15)",
|
||||
"rankine": "v => v.times(5).dividedBy(4).plus(273.15).times(9).dividedBy(5)"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,28 +1,114 @@
|
||||
{
|
||||
"slug": "volumen",
|
||||
"name": "Volumen",
|
||||
"unitOrder": [
|
||||
"kubikmeter",
|
||||
"kubikfuss",
|
||||
"kubikzoll",
|
||||
"liter",
|
||||
"milliliter",
|
||||
"gallonen_us",
|
||||
"gallonen_uk",
|
||||
"barrels_us",
|
||||
"barrels_uk",
|
||||
"fluidunzen_us",
|
||||
"fluidunzen_uk",
|
||||
"cups_us",
|
||||
"cups_uk",
|
||||
"pints_us",
|
||||
"pints_uk",
|
||||
"quarts_us",
|
||||
"quarts_uk",
|
||||
"drams_us",
|
||||
"drams_uk",
|
||||
"essloeffel",
|
||||
"teeloeffel"
|
||||
],
|
||||
"conversion_engine": "linear",
|
||||
"units": {
|
||||
"kubikmeter": { "name": "Kubikmeter", "factor": "1000" },
|
||||
"kubikfuss": { "name": "Kubikfuß", "factor": "28.316846592" },
|
||||
"kubikzoll": { "name": "Kubikzoll", "factor": "0.016387064" },
|
||||
"liter": { "name": "Liter", "factor": "1" },
|
||||
"milliliter": { "name": "Milliliter", "factor": "0.001" },
|
||||
"gallonen_us": { "name": "Gallonen (US)", "factor": "3.785411784" },
|
||||
"gallonen_uk": { "name": "Gallonen (UK)", "factor": "4.54609188" },
|
||||
"barrels_us": { "name": "Barrels (US)", "factor": "158.987294928" },
|
||||
"barrels_uk": { "name": "Barrels (UK)", "factor": "163.65923999999998" },
|
||||
"fluidunzen_us": { "name": "Fluidunzen (US)", "factor": "0.0295735295625" },
|
||||
"fluidunzen_uk": { "name": "Fluidunzen (UK)", "factor": "0.0284130625" },
|
||||
"cups_us": { "name": "Cups (US)", "factor": "0.2365882365" },
|
||||
"cups_uk": { "name": "Cups (UK)", "factor": "0.284130625" },
|
||||
"pints_us": { "name": "Pints (US)", "factor": "0.473176473" },
|
||||
"pints_uk": { "name": "Pints (UK)", "factor": "0.56826125" },
|
||||
"quarts_us": { "name": "Quarts (US)", "factor": "0.946352946" },
|
||||
"quarts_uk": { "name": "Quarts (UK)", "factor": "1.1365225" },
|
||||
"drams_us": { "name": "Drams (US)", "factor": "0.0036966911953125" },
|
||||
"drams_uk": { "name": "Drams (UK)", "factor": "0.0035516328125" },
|
||||
"essloeffel": { "name": "Esslöffel", "factor": "0.01478676478125" },
|
||||
"teeloeffel": { "name": "Teelöffel", "factor": "0.00492892159375" }
|
||||
"kubikmeter": {
|
||||
"name": "Kubikmeter",
|
||||
"factor": "1000"
|
||||
},
|
||||
"kubikfuss": {
|
||||
"name": "Kubikfuß",
|
||||
"factor": "28.316846592"
|
||||
},
|
||||
"kubikzoll": {
|
||||
"name": "Kubikzoll",
|
||||
"factor": "0.016387064"
|
||||
},
|
||||
"liter": {
|
||||
"name": "Liter",
|
||||
"factor": "1"
|
||||
},
|
||||
"milliliter": {
|
||||
"name": "Milliliter",
|
||||
"factor": "0.001"
|
||||
},
|
||||
"gallonen_us": {
|
||||
"name": "Gallonen (US)",
|
||||
"factor": "3.785411784"
|
||||
},
|
||||
"gallonen_uk": {
|
||||
"name": "Gallonen (UK)",
|
||||
"factor": "4.54609188"
|
||||
},
|
||||
"barrels_us": {
|
||||
"name": "Barrels (US)",
|
||||
"factor": "158.987294928"
|
||||
},
|
||||
"barrels_uk": {
|
||||
"name": "Barrels (UK)",
|
||||
"factor": "163.65923999999998"
|
||||
},
|
||||
"fluidunzen_us": {
|
||||
"name": "Fluidunzen (US)",
|
||||
"factor": "0.0295735295625"
|
||||
},
|
||||
"fluidunzen_uk": {
|
||||
"name": "Fluidunzen (UK)",
|
||||
"factor": "0.0284130625"
|
||||
},
|
||||
"cups_us": {
|
||||
"name": "Cups (US)",
|
||||
"factor": "0.2365882365"
|
||||
},
|
||||
"cups_uk": {
|
||||
"name": "Cups (UK)",
|
||||
"factor": "0.284130625"
|
||||
},
|
||||
"pints_us": {
|
||||
"name": "Pints (US)",
|
||||
"factor": "0.473176473"
|
||||
},
|
||||
"pints_uk": {
|
||||
"name": "Pints (UK)",
|
||||
"factor": "0.56826125"
|
||||
},
|
||||
"quarts_us": {
|
||||
"name": "Quarts (US)",
|
||||
"factor": "0.946352946"
|
||||
},
|
||||
"quarts_uk": {
|
||||
"name": "Quarts (UK)",
|
||||
"factor": "1.1365225"
|
||||
},
|
||||
"drams_us": {
|
||||
"name": "Drams (US)",
|
||||
"factor": "0.0036966911953125"
|
||||
},
|
||||
"drams_uk": {
|
||||
"name": "Drams (UK)",
|
||||
"factor": "0.0035516328125"
|
||||
},
|
||||
"essloeffel": {
|
||||
"name": "Esslöffel",
|
||||
"factor": "0.01478676478125"
|
||||
},
|
||||
"teeloeffel": {
|
||||
"name": "Teelöffel",
|
||||
"factor": "0.00492892159375"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,37 +1,129 @@
|
||||
{
|
||||
"slug": "waehrungen",
|
||||
"name": "Währungen",
|
||||
"conversion_engine": "runtime",
|
||||
"unitOrder": [
|
||||
"eur",
|
||||
"usd",
|
||||
"gbp",
|
||||
"chf",
|
||||
"jpy",
|
||||
"cad",
|
||||
"aud",
|
||||
"cny",
|
||||
"inr",
|
||||
"brl",
|
||||
"rub",
|
||||
"zar",
|
||||
"mxn",
|
||||
"sgd",
|
||||
"hkd",
|
||||
"nzd",
|
||||
"sek",
|
||||
"nok",
|
||||
"dkk",
|
||||
"pln",
|
||||
"czk",
|
||||
"huf",
|
||||
"try",
|
||||
"aed",
|
||||
"sar",
|
||||
"thb",
|
||||
"idr",
|
||||
"krw",
|
||||
"php",
|
||||
"egp"
|
||||
],
|
||||
"conversion_engine": "currencies",
|
||||
"units": {
|
||||
"eur": { "name": "Euro" },
|
||||
"usd": { "name": "US-Dollar" },
|
||||
"gbp": { "name": "Britisches Pfund" },
|
||||
"chf": { "name": "Schweizer Franken" },
|
||||
"jpy": { "name": "Japanischer Yen" },
|
||||
"cad": { "name": "Kanadischer Dollar" },
|
||||
"aud": { "name": "Australischer Dollar" },
|
||||
"cny": { "name": "Chinesischer Yuan" },
|
||||
"inr": { "name": "Indische Rupie" },
|
||||
"brl": { "name": "Brasilianischer Real" },
|
||||
"rub": { "name": "Russischer Rubel" },
|
||||
"zar": { "name": "Südafrikanischer Rand" },
|
||||
"mxn": { "name": "Mexikanischer Peso" },
|
||||
"sgd": { "name": "Singapur-Dollar" },
|
||||
"hkd": { "name": "Hongkong-Dollar" },
|
||||
"nzd": { "name": "Neuseeland-Dollar" },
|
||||
"sek": { "name": "Schwedische Krone" },
|
||||
"nok": { "name": "Norwegische Krone" },
|
||||
"dkk": { "name": "Dänische Krone" },
|
||||
"pln": { "name": "Polnischer Zloty" },
|
||||
"czk": { "name": "Tschechische Krone" },
|
||||
"huf": { "name": "Ungarischer Forint" },
|
||||
"try": { "name": "Türkische Lira" },
|
||||
"aed": { "name": "VAE-Dirham" },
|
||||
"sar": { "name": "Saudi-Riyal" },
|
||||
"thb": { "name": "Thailändischer Baht" },
|
||||
"idr": { "name": "Indonesische Rupiah" },
|
||||
"krw": { "name": "Südkoreanischer Won" },
|
||||
"php": { "name": "Philippinischer Peso" },
|
||||
"egp": { "name": "Ägyptisches Pfund" }
|
||||
"eur": {
|
||||
"name": "Euro"
|
||||
},
|
||||
"usd": {
|
||||
"name": "US-Dollar"
|
||||
},
|
||||
"gbp": {
|
||||
"name": "Britisches Pfund"
|
||||
},
|
||||
"chf": {
|
||||
"name": "Schweizer Franken"
|
||||
},
|
||||
"jpy": {
|
||||
"name": "Japanischer Yen"
|
||||
},
|
||||
"cad": {
|
||||
"name": "Kanadischer Dollar"
|
||||
},
|
||||
"aud": {
|
||||
"name": "Australischer Dollar"
|
||||
},
|
||||
"cny": {
|
||||
"name": "Chinesischer Yuan"
|
||||
},
|
||||
"inr": {
|
||||
"name": "Indische Rupie"
|
||||
},
|
||||
"brl": {
|
||||
"name": "Brasilianischer Real"
|
||||
},
|
||||
"rub": {
|
||||
"name": "Russischer Rubel"
|
||||
},
|
||||
"zar": {
|
||||
"name": "Südafrikanischer Rand"
|
||||
},
|
||||
"mxn": {
|
||||
"name": "Mexikanischer Peso"
|
||||
},
|
||||
"sgd": {
|
||||
"name": "Singapur-Dollar"
|
||||
},
|
||||
"hkd": {
|
||||
"name": "Hongkong-Dollar"
|
||||
},
|
||||
"nzd": {
|
||||
"name": "Neuseeland-Dollar"
|
||||
},
|
||||
"sek": {
|
||||
"name": "Schwedische Krone"
|
||||
},
|
||||
"nok": {
|
||||
"name": "Norwegische Krone"
|
||||
},
|
||||
"dkk": {
|
||||
"name": "Dänische Krone"
|
||||
},
|
||||
"pln": {
|
||||
"name": "Polnischer Zloty"
|
||||
},
|
||||
"czk": {
|
||||
"name": "Tschechische Krone"
|
||||
},
|
||||
"huf": {
|
||||
"name": "Ungarischer Forint"
|
||||
},
|
||||
"try": {
|
||||
"name": "Türkische Lira"
|
||||
},
|
||||
"aed": {
|
||||
"name": "VAE-Dirham"
|
||||
},
|
||||
"sar": {
|
||||
"name": "Saudi-Riyal"
|
||||
},
|
||||
"thb": {
|
||||
"name": "Thailändischer Baht"
|
||||
},
|
||||
"idr": {
|
||||
"name": "Indonesische Rupiah"
|
||||
},
|
||||
"krw": {
|
||||
"name": "Südkoreanischer Won"
|
||||
},
|
||||
"php": {
|
||||
"name": "Philippinischer Peso"
|
||||
},
|
||||
"egp": {
|
||||
"name": "Ägyptisches Pfund"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,24 @@
|
||||
{
|
||||
"slug": "winkel",
|
||||
"name": "Winkel",
|
||||
"unitOrder": [
|
||||
"grad",
|
||||
"bogenmass",
|
||||
"gon"
|
||||
],
|
||||
"conversion_engine": "linear",
|
||||
"units": {
|
||||
"grad": { "name": "Grad", "factor": "0.017453292519943295" },
|
||||
"bogenmass": { "name": "Bogenmaß", "factor": "1" },
|
||||
"gon": { "name": "Gon", "factor": "0.015707963267948966" }
|
||||
"grad": {
|
||||
"name": "Grad",
|
||||
"factor": "0.017453292519943295"
|
||||
},
|
||||
"bogenmass": {
|
||||
"name": "Bogenmaß",
|
||||
"factor": "1"
|
||||
},
|
||||
"gon": {
|
||||
"name": "Gon",
|
||||
"factor": "0.015707963267948966"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,17 +1,59 @@
|
||||
{
|
||||
"slug": "zeiten",
|
||||
"name": "Zeiten",
|
||||
"unitOrder": [
|
||||
"sekunden",
|
||||
"minuten",
|
||||
"stunden",
|
||||
"tage",
|
||||
"wochen",
|
||||
"monate",
|
||||
"jahre",
|
||||
"millisekunden",
|
||||
"mikrosekunden",
|
||||
"nanosekunden"
|
||||
],
|
||||
"conversion_engine": "linear",
|
||||
"units": {
|
||||
"sekunden": { "name": "Sekunden", "factor": "0.0002777777777777778" },
|
||||
"minuten": { "name": "Minuten", "factor": "0.016666666666666666" },
|
||||
"stunden": { "name": "Stunden", "factor": "1" },
|
||||
"tage": { "name": "Tage", "factor": "24" },
|
||||
"wochen": { "name": "Wochen", "factor": "168" },
|
||||
"monate": { "name": "Monate", "factor": "730.485" },
|
||||
"jahre": { "name": "Jahre", "factor": "8765.82" },
|
||||
"millisekunden": { "name": "Millisekunden", "factor": "0.00000027777777777777777777777777777778" },
|
||||
"mikrosekunden": { "name": "Mikrosekunden", "factor": "0.00000000027777777777777777777777777778" },
|
||||
"nanosekunden": { "name": "Nanosekunden", "factor": "0.00000000000027777777777777777777777778" }
|
||||
"sekunden": {
|
||||
"name": "Sekunden",
|
||||
"factor": "0.0002777777777777778"
|
||||
},
|
||||
"minuten": {
|
||||
"name": "Minuten",
|
||||
"factor": "0.016666666666666666"
|
||||
},
|
||||
"stunden": {
|
||||
"name": "Stunden",
|
||||
"factor": "1"
|
||||
},
|
||||
"tage": {
|
||||
"name": "Tage",
|
||||
"factor": "24"
|
||||
},
|
||||
"wochen": {
|
||||
"name": "Wochen",
|
||||
"factor": "168"
|
||||
},
|
||||
"monate": {
|
||||
"name": "Monate",
|
||||
"factor": "730.485"
|
||||
},
|
||||
"jahre": {
|
||||
"name": "Jahre",
|
||||
"factor": "8765.82"
|
||||
},
|
||||
"millisekunden": {
|
||||
"name": "Millisekunden",
|
||||
"factor": "0.00000027777777777777777777777777777778"
|
||||
},
|
||||
"mikrosekunden": {
|
||||
"name": "Mikrosekunden",
|
||||
"factor": "0.00000000027777777777777777777777777778"
|
||||
},
|
||||
"nanosekunden": {
|
||||
"name": "Nanosekunden",
|
||||
"factor": "0.00000000000027777777777777777777777778"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,184 +1,164 @@
|
||||
{{ define "main" }}
|
||||
{{ $catData := index hugo.Data .Params.category }}
|
||||
{{ $config := "" }}
|
||||
{{ if eq .Params.engine "linear" }}
|
||||
{{ $config = dict "fromFactor" .Params.from_factor
|
||||
"toFactor" .Params.to_factor | jsonify }}
|
||||
{{ else if eq .Params.engine "intermediate" }}
|
||||
{{ $toExpr := index $catData.to_intermediate
|
||||
.Params.from | default "v" }}
|
||||
{{ $fromExpr := index $catData.from_intermediate
|
||||
.Params.to | default "v" }}
|
||||
{{ $config = printf
|
||||
"{ toIntermediate: v => %s, fromIntermediate: v => %s }"
|
||||
$toExpr $fromExpr }}
|
||||
{{ else if eq .Params.engine "runtime" }}
|
||||
{{ $config = dict "fromCurrency" .Params.from
|
||||
"toCurrency" .Params.to | jsonify }}
|
||||
{{ end }}
|
||||
{{ $availableUnits := partial "available-units.html"
|
||||
(dict "category" .Params.category "units" $catData.units) }}
|
||||
|
||||
<div id="conversionform"
|
||||
class="bg-white p-8 rounded-lg shadow-md w-full
|
||||
dark:bg-gray-700 dark:text-grey-200"
|
||||
x-data="navActions()">
|
||||
{{ $engine := .Params.engine | default "linear" }}
|
||||
|
||||
<h1 id="headline"
|
||||
class="text-2xl font-bold mb-6 text-center">
|
||||
{{ .Params.from_name }} in {{ .Params.to_name }}
|
||||
umrechnen
|
||||
</h1>
|
||||
{{ if eq $engine "currencies" }}
|
||||
{{ partial "conversion/currencies-data" . }}
|
||||
{{ else if eq $engine "temperatures" }}
|
||||
{{ partial "conversion/temperatures-data" . }}
|
||||
{{ else }}
|
||||
{{ partial "conversion/linear-data" . }}
|
||||
{{ end }}
|
||||
|
||||
<div>
|
||||
<div id="conversionform"
|
||||
class="bg-white p-8 rounded-lg shadow-md w-full
|
||||
dark:bg-gray-700 dark:text-grey-200">
|
||||
|
||||
<a x-ref="ajaxLink"
|
||||
x-target.push="maincontent"
|
||||
href="/"
|
||||
class="hidden"></a>
|
||||
<h1 id="headline"
|
||||
class="text-2xl font-bold mb-6 text-center">
|
||||
{{ .Params.from_name }} in {{ .Params.to_name }}
|
||||
umrechnen
|
||||
</h1>
|
||||
|
||||
<div>
|
||||
<label for="type"
|
||||
class="block text-sm font-medium opacity-75">
|
||||
Einheitentyp:
|
||||
</label>
|
||||
<select id="type" name="type"
|
||||
@change="navigate($event.target.value)"
|
||||
class="select mt-1 block w-full">
|
||||
{{ range $slug, $data := hugo.Data }}
|
||||
{{ if and $data.slug $data.name }}
|
||||
{{ $catUrl := partial "category-url.html"
|
||||
(dict "category" $data.slug
|
||||
"units" $data.units) }}
|
||||
<option
|
||||
value="{{ $catUrl }}"
|
||||
{{ if eq $data.slug
|
||||
$.Params.category }}selected{{ end }}>
|
||||
{{ $data.name }}
|
||||
</option>
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col sm:flex-row items-center gap-4
|
||||
mt-4">
|
||||
|
||||
<div class="flex-1 w-full">
|
||||
<label for="from"
|
||||
<div>
|
||||
<label for="type"
|
||||
class="block text-sm font-medium opacity-75">
|
||||
Umrechnen von:
|
||||
Einheitentyp:
|
||||
</label>
|
||||
<select id="from" name="from"
|
||||
@change="navigateWithValue($event.target.value)"
|
||||
<select id="type" name="type"
|
||||
@change="navigate($event.target.value, '1')"
|
||||
class="select mt-1 block w-full">
|
||||
{{ range $unit, $unitData := $availableUnits }}
|
||||
{{ if ne $unit $.Params.to }}
|
||||
{{ range $slug, $data := hugo.Data }}
|
||||
{{ if and $data.slug $data.name }}
|
||||
{{ $catUrl := partial "category-url.html"
|
||||
(dict "category" $data.slug
|
||||
"units" $data.units) }}
|
||||
<option
|
||||
value="/{{ $unit }}-in-{{ $.Params.to }}/"
|
||||
{{ if eq $unit
|
||||
$.Params.from }}selected{{ end }}>
|
||||
{{ $unitData.name }}
|
||||
value="{{ $catUrl }}"
|
||||
{{ if eq $data.slug
|
||||
$.Params.category }}selected{{ end }}>
|
||||
{{ $data.name }}
|
||||
</option>
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="text-center sm:pt-6">
|
||||
<button type="button"
|
||||
@click="navigateWithResult(
|
||||
$el.dataset.swapUrl)"
|
||||
data-swap-url="/{{ .Params.to }}-in-{{ .Params.from }}/"
|
||||
class="inline-flex items-center text-sm
|
||||
font-medium text-primary
|
||||
dark:text-primary-light">
|
||||
<svg xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none" viewBox="0 0 24 24"
|
||||
stroke-width="1.5"
|
||||
stroke="currentColor"
|
||||
class="w-6 h-6">
|
||||
<path stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
d="M7.5 21 3 16.5m0 0L7.5 12M3
|
||||
16.5h13.5m0-13.5L21 7.5m0
|
||||
0L16.5 12M21 7.5H7.5" />
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
<div class="flex flex-col sm:flex-row items-center gap-4
|
||||
mt-4">
|
||||
|
||||
<div class="flex-1 w-full">
|
||||
<label for="from"
|
||||
class="block text-sm font-medium
|
||||
opacity-75">
|
||||
Umrechnen von:
|
||||
</label>
|
||||
<select id="from" name="from"
|
||||
@change="navigate(
|
||||
$event.target.value, inputValue)"
|
||||
class="select mt-1 block w-full">
|
||||
{{ range $catData.unitOrder }}
|
||||
{{ $unitData := index $availableUnits . }}
|
||||
{{ if and $unitData (ne . $.Params.to) }}
|
||||
<option
|
||||
value="/{{ . }}-in-{{ $.Params.to }}/"
|
||||
{{ if eq .
|
||||
$.Params.from }}selected{{ end }}>
|
||||
{{ $unitData.name }}
|
||||
</option>
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="text-center sm:pt-6">
|
||||
<button type="button"
|
||||
@click="navigate(
|
||||
$el.dataset.swapUrl, prettyNumber(convert(parseNumber(inputValue))))"
|
||||
data-swap-url="/{{ .Params.to }}-in-{{ .Params.from }}/"
|
||||
class="inline-flex items-center text-sm
|
||||
font-medium text-primary
|
||||
dark:text-primary-light">
|
||||
<svg xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none" viewBox="0 0 24 24"
|
||||
stroke-width="1.5"
|
||||
stroke="currentColor"
|
||||
class="w-6 h-6">
|
||||
<path stroke-linecap="round"
|
||||
stroke-linejoin="round" d="M7.5 21 3 16.5m0 0L7.5 12M3
|
||||
16.5h13.5m0-13.5L21 7.5m0
|
||||
0L16.5 12M21 7.5H7.5" />
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="flex-1 w-full">
|
||||
<label for="to"
|
||||
class="block text-sm font-medium
|
||||
opacity-75">
|
||||
Umrechnen in:
|
||||
</label>
|
||||
<select id="to" name="to"
|
||||
@change="navigate(
|
||||
$event.target.value, inputValue)"
|
||||
class="select mt-1 block w-full">
|
||||
{{ range $catData.unitOrder }}
|
||||
{{ $unitData := index $availableUnits . }}
|
||||
{{ if and $unitData (ne . $.Params.from) }}
|
||||
<option
|
||||
value="/{{ $.Params.from }}-in-{{ . }}/"
|
||||
{{ if eq .
|
||||
$.Params.to }}selected{{ end }}>
|
||||
{{ $unitData.name }}
|
||||
</option>
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="flex-1 w-full">
|
||||
<label for="to"
|
||||
class="block text-sm font-medium opacity-75">
|
||||
Umrechnen in:
|
||||
</label>
|
||||
<select id="to" name="to"
|
||||
@change="navigateWithValue($event.target.value)"
|
||||
class="select mt-1 block w-full">
|
||||
{{ range $unit, $unitData := $availableUnits }}
|
||||
{{ if ne $unit $.Params.from }}
|
||||
<option
|
||||
value="/{{ $.Params.from }}-in-{{ $unit }}/"
|
||||
{{ if eq $unit
|
||||
$.Params.to }}selected{{ end }}>
|
||||
{{ $unitData.name }}
|
||||
</option>
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
</select>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div x-data="createConverter('{{ .Params.engine }}',
|
||||
{{ $config | safeJS }})"
|
||||
x-init="init()">
|
||||
|
||||
<div class="flex flex-col sm:flex-row gap-4 mt-4">
|
||||
<div class="flex-1">
|
||||
<label for="value"
|
||||
class="block text-sm font-medium
|
||||
opacity-75">
|
||||
class="block text-sm font-medium opacity-75">
|
||||
Wert in {{ .Params.from_name }}:
|
||||
</label>
|
||||
<input type="text" id="value"
|
||||
inputmode="decimal"
|
||||
x-model="inputValue"
|
||||
@input="calculate()"
|
||||
@input.debounce.500ms="updateUrl(inputValue)"
|
||||
class="textinput mt-1 block w-full"
|
||||
placeholder="Wert eingeben">
|
||||
</div>
|
||||
<div class="flex-1">
|
||||
<label for="result"
|
||||
class="block text-sm font-medium
|
||||
opacity-75">
|
||||
class="block text-sm font-medium opacity-75">
|
||||
Ergebnis in {{ .Params.to_name }}:
|
||||
</label>
|
||||
<input type="text" id="result"
|
||||
disabled
|
||||
:value="result"
|
||||
:value="prettyNumber(convert(parseNumber(inputValue)))"
|
||||
class="textinput mt-1 block w-full">
|
||||
<p x-show="ratesError"
|
||||
x-cloak
|
||||
class="text-sm text-red-600 mt-1
|
||||
dark:text-red-400"
|
||||
x-text="ratesError"></p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div id="formula" class="mt-4">
|
||||
{{ partial "conversion-formula.html" . }}
|
||||
</div>
|
||||
<div id="info">
|
||||
{{ partial "conversion-seo-texts.html" . }}
|
||||
</div>
|
||||
|
||||
<div id="formula" class="mt-4">
|
||||
{{ partial "conversion-formula.html" . }}
|
||||
</div>
|
||||
<div id="info">
|
||||
{{ partial "conversion-seo-texts.html" . }}
|
||||
</div>
|
||||
|
||||
{{ end }}
|
||||
|
||||
|
||||
|
||||
@@ -1 +1 @@
|
||||
{{- $category := .category }}{{ $units := .units }}{{ $available := partial "available-units.html" (dict "category" $category "units" $units) }}{{ $url := "" }}{{ if gt (len $available) 0 }}{{ $firstUnit := "" }}{{ $secondUnit := "" }}{{ range $u, $_ := $available }}{{ if eq $firstUnit "" }}{{ $firstUnit = $u }}{{ else if eq $secondUnit "" }}{{ $secondUnit = $u }}{{ end }}{{ end }}{{ $url = printf "/%s-in-%s/" $firstUnit $secondUnit }}{{ end }}{{- $url -}}
|
||||
{{- $category := .category }}{{ $units := .units }}{{ $available := partial "available-units.html" (dict "category" $category "units" $units) }}{{ $url := "" }}{{ if gt (len $available) 0 }}{{ $catData := index hugo.Data $category }}{{ $firstUnit := "" }}{{ $secondUnit := "" }}{{ range $catData.unitOrder }}{{ $unitData := index $available . }}{{ if $unitData }}{{ if eq $firstUnit "" }}{{ $firstUnit = . }}{{ else if eq $secondUnit "" }}{{ $secondUnit = . }}{{ end }}{{ end }}{{ end }}{{ $url = printf "/%s-in-%s/" $firstUnit $secondUnit }}{{ end }}{{- $url -}}
|
||||
|
||||
@@ -48,28 +48,49 @@
|
||||
{{ replace $fromI "v" $intermediateName 1 }}</b>
|
||||
</p>
|
||||
{{ end }}
|
||||
{{ else if eq .Params.engine "runtime" }}
|
||||
{{ $rate := float .Params.rate }}
|
||||
{{ else if eq .Params.engine "temperatures" }}
|
||||
<p class="mb-4 mt-8">
|
||||
Die Umrechnung von {{ $fromName }} in {{ $toName }}
|
||||
erfolgt mittels dieser Formel:
|
||||
</p>
|
||||
{{ if ge $rate 1 }}
|
||||
<p class="text-lg text-primary dark:text-primary-light">
|
||||
<b>{{ $toName }} = {{ $fromName }} ×
|
||||
{{ printf "%.12g" $rate }}</b>
|
||||
<p class="text-lg text-primary dark:text-primary-light">
|
||||
<b>{{ .Params.displayFormula }}</b>
|
||||
</p>
|
||||
{{ else if eq .Params.engine "currencies" }}
|
||||
<p class="mb-4 mt-8">
|
||||
Die Umrechnung von {{ $fromName }} in {{ $toName }}
|
||||
erfolgt mittels dieser Formel:
|
||||
</p>
|
||||
<div x-show="rate > 0">
|
||||
<p class="text-lg text-primary dark:text-primary-light"
|
||||
x-show="rate >= 1">
|
||||
<b x-text="'{{ $toName }} = {{ $fromName }} × '
|
||||
+ prettyNumber(rate)"></b>
|
||||
</p>
|
||||
{{ else }}
|
||||
{{ $invRate := div 1 $rate }}
|
||||
<p class="text-lg text-primary dark:text-primary-light">
|
||||
<b>{{ $toName }} = {{ $fromName }} /
|
||||
{{ printf "%.12g" $invRate }}</b>
|
||||
<p class="text-lg text-primary dark:text-primary-light"
|
||||
x-show="rate < 1">
|
||||
<b x-text="'{{ $toName }} = {{ $fromName }} / '
|
||||
+ prettyNumber(1 / rate)"></b>
|
||||
</p>
|
||||
{{ end }}
|
||||
{{ with .Params.rates_updated }}
|
||||
<p class="text-sm text-gray-600 dark:text-gray-400 mt-2">
|
||||
Wechselkurs zuletzt aktualisiert:
|
||||
{{ time.Format "2. Januar 2006, 15:04" . }}
|
||||
</p>
|
||||
{{ end }}
|
||||
</div>
|
||||
<div x-show="!rate">
|
||||
{{ $rate := float .Params.rate }}
|
||||
{{ if ge $rate 1 }}
|
||||
<p class="text-lg text-primary dark:text-primary-light">
|
||||
<b>{{ $toName }} = {{ $fromName }} ×
|
||||
{{ printf "%.12g" $rate }}</b>
|
||||
</p>
|
||||
{{ else }}
|
||||
{{ $invRate := div 1 $rate }}
|
||||
<p class="text-lg text-primary dark:text-primary-light">
|
||||
<b>{{ $toName }} = {{ $fromName }} /
|
||||
{{ printf "%.12g" $invRate }}</b>
|
||||
</p>
|
||||
{{ end }}
|
||||
</div>
|
||||
<p x-show="ratesUpdated"
|
||||
class="text-sm text-gray-600 dark:text-gray-400 mt-2">
|
||||
Wechselkurs zuletzt aktualisiert:
|
||||
<span x-text="ratesUpdated"></span>
|
||||
</p>
|
||||
{{ end }}
|
||||
|
||||
40
hugo/layouts/partials/conversion/currencies-data.html
Normal file
40
hugo/layouts/partials/conversion/currencies-data.html
Normal file
@@ -0,0 +1,40 @@
|
||||
<div x-data="{
|
||||
inputValue: '1',
|
||||
rate: 0,
|
||||
formula: '',
|
||||
ratesError: '',
|
||||
ratesUpdated: '',
|
||||
convert(v) { return v.times(this.rate); },
|
||||
async init() {
|
||||
const params = new URLSearchParams(window.location.search);
|
||||
const valueParam = params.get('v');
|
||||
if (valueParam) this.inputValue = valueParam.replace(/,/g, '.');
|
||||
|
||||
const pbUrl = document.querySelector('meta[name=\'pocketbase-url\']')?.content || 'https://www.alphabreed.com';
|
||||
try {
|
||||
const response = await fetch(pbUrl + '/api/collections/currencies/records');
|
||||
if (!response.ok) {
|
||||
this.ratesError = 'Wechselkurse konnten nicht geladen werden.';
|
||||
return;
|
||||
}
|
||||
const data = await response.json();
|
||||
const rates = {};
|
||||
let updated = '';
|
||||
for (const item of data.items || []) {
|
||||
rates[item.id] = item.rate;
|
||||
updated = item.updated;
|
||||
}
|
||||
const fromRate = '{{ .Params.from }}' === 'eur' ? 1 : rates['{{ .Params.from }}'];
|
||||
const toRate = '{{ .Params.to }}' === 'eur' ? 1 : rates['{{ .Params.to }}'];
|
||||
if (fromRate && toRate) {
|
||||
this.rate = parseFloat(toRate) / parseFloat(fromRate);
|
||||
this.ratesUpdated = new Date(updated).toLocaleString('de-DE', { day: '2-digit', month: 'long', year: 'numeric', hour: '2-digit', minute: '2-digit' });
|
||||
this.formula = '1 {{ .Params.from | upper }} = ' + prettyNumber(this.rate) + ' {{ .Params.to | upper }}';
|
||||
} else {
|
||||
this.ratesError = 'Wechselkurse nicht gefunden.';
|
||||
}
|
||||
} catch (e) {
|
||||
this.ratesError = 'Wechselkurse konnten nicht geladen werden.';
|
||||
}
|
||||
}
|
||||
}">
|
||||
9
hugo/layouts/partials/conversion/linear-data.html
Normal file
9
hugo/layouts/partials/conversion/linear-data.html
Normal file
@@ -0,0 +1,9 @@
|
||||
<div x-data="{
|
||||
inputValue: '1',
|
||||
convert: v => new Decimal(v).times({{ .Params.from_factor }}).dividedBy({{ .Params.to_factor }}),
|
||||
async init() {
|
||||
const params = new URLSearchParams(window.location.search);
|
||||
const valueParam = params.get('v');
|
||||
if (valueParam) this.inputValue = valueParam.replace(/,/g, '.');
|
||||
}
|
||||
}" x-init="init()">
|
||||
9
hugo/layouts/partials/conversion/temperatures-data.html
Normal file
9
hugo/layouts/partials/conversion/temperatures-data.html
Normal file
@@ -0,0 +1,9 @@
|
||||
<div x-data="{
|
||||
inputValue: '1',
|
||||
convert: {{ .Params.convertFormula | safeJS }},
|
||||
async init() {
|
||||
const params = new URLSearchParams(window.location.search);
|
||||
const valueParam = params.get('v');
|
||||
if (valueParam) this.inputValue = valueParam.replace(/,/g, '.');
|
||||
}
|
||||
}" x-init="init()">
|
||||
@@ -9,12 +9,14 @@
|
||||
<div><b>{{ $data.name }}</b></div>
|
||||
<ul class="pl-1 text-xs">
|
||||
{{ $count := 0 }}
|
||||
{{ range $unitSlug, $unitData := $units }}
|
||||
{{ if lt $count 12 }}
|
||||
{{ range $data.unitOrder }}
|
||||
{{ $unitSlug := . }}
|
||||
{{ $unitData := index $units $unitSlug }}
|
||||
{{ if and $unitData (lt $count 12) }}
|
||||
{{ $toSlug := "" }}
|
||||
{{ range $u, $ud := $units }}
|
||||
{{ if and (ne $u $unitSlug) (eq $toSlug "") }}
|
||||
{{ $toSlug = $u }}
|
||||
{{ range $data.unitOrder }}
|
||||
{{ if and (ne . $unitSlug) (eq $toSlug "") }}
|
||||
{{ $toSlug = . }}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
{{ $url := printf "/%s-in-%s/" $unitSlug $toSlug }}
|
||||
|
||||
@@ -1,180 +1,5 @@
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Alpine.js navigation helpers for conversion page.
|
||||
* Handles navigation via hidden AJAX link.
|
||||
*/
|
||||
function navActions() {
|
||||
return {
|
||||
navigate(url) {
|
||||
this.$refs.ajaxLink.href = url;
|
||||
this.$nextTick(() => this.$refs.ajaxLink.click());
|
||||
},
|
||||
navigateWithValue(url) {
|
||||
const el = document.getElementById('value');
|
||||
const val = el ? el.value.replace(/,/g, '.') : '1';
|
||||
this.$refs.ajaxLink.href = url + '?v=' + val;
|
||||
this.$nextTick(() => this.$refs.ajaxLink.click());
|
||||
},
|
||||
navigateWithResult(url) {
|
||||
const el = document.getElementById('result');
|
||||
const val = el ? el.value.replace(/,/g, '.') : '';
|
||||
if (val) {
|
||||
this.$refs.ajaxLink.href = url + '?v=' + val;
|
||||
} else {
|
||||
this.$refs.ajaxLink.href = url;
|
||||
}
|
||||
this.$nextTick(() => this.$refs.ajaxLink.click());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Factory function for Alpine.js converter components.
|
||||
* @param {string} engine - 'linear', 'intermediate' or 'runtime'
|
||||
* @param {object} config - Engine-specific configuration
|
||||
* @returns {object} Alpine component data
|
||||
*/
|
||||
function createConverter(engine, config) {
|
||||
if (engine === 'runtime') {
|
||||
return {
|
||||
inputValue: '1',
|
||||
result: '',
|
||||
rates: {},
|
||||
ratesError: '',
|
||||
async init() {
|
||||
await this.loadRates();
|
||||
const params = new URLSearchParams(
|
||||
window.location.search);
|
||||
const valueParam = params.get('v');
|
||||
if (valueParam) {
|
||||
this.inputValue = valueParam.replace(/,/g, '.');
|
||||
}
|
||||
this.$watch('inputValue', val => {
|
||||
if (val && val.indexOf(',') !== -1) {
|
||||
this.inputValue = val.replace(/,/g, '.');
|
||||
}
|
||||
});
|
||||
this.calculate();
|
||||
},
|
||||
async loadRates() {
|
||||
const pbUrl = document.querySelector(
|
||||
'meta[name="pocketbase-url"]')?.content
|
||||
|| 'https://www.alphabreed.com';
|
||||
try {
|
||||
const response = await fetch(
|
||||
`${pbUrl}/api/collections/currencies/records`);
|
||||
if (!response.ok) {
|
||||
this.ratesError =
|
||||
'Wechselkurse konnten nicht geladen werden.';
|
||||
return;
|
||||
}
|
||||
const data = await response.json();
|
||||
for (const item of data.items || []) {
|
||||
this.rates[item.id] = item.rate;
|
||||
}
|
||||
} catch (e) {
|
||||
this.ratesError =
|
||||
'Wechselkurse konnten nicht geladen werden.';
|
||||
}
|
||||
},
|
||||
calculate() {
|
||||
try {
|
||||
this.result = '';
|
||||
if (Object.keys(this.rates).length === 0) {
|
||||
return;
|
||||
}
|
||||
const normalized = parseNumber(
|
||||
this.inputValue);
|
||||
if (!normalized || isNaN(normalized)) {
|
||||
return;
|
||||
}
|
||||
const fromCode = config.fromCurrency || '';
|
||||
const toCode = config.toCurrency || '';
|
||||
const fromRate = fromCode === 'eur'
|
||||
? 1 : this.rates[fromCode];
|
||||
const toRate = toCode === 'eur'
|
||||
? 1 : this.rates[toCode];
|
||||
if (!fromRate || !toRate) {
|
||||
return;
|
||||
}
|
||||
const value = new Decimal(normalized);
|
||||
const rate = new Decimal(toRate)
|
||||
.dividedBy(new Decimal(fromRate));
|
||||
const rawResult = value.times(rate);
|
||||
this.result = prettyNumber(rawResult);
|
||||
const normalizedInputValue = this.inputValue
|
||||
.replace(/,/g, '.');
|
||||
if (normalizedInputValue
|
||||
&& normalizedInputValue !== '0') {
|
||||
history.replaceState(
|
||||
null, '', '?v=' + normalizedInputValue);
|
||||
}
|
||||
} catch (e) {
|
||||
this.result = '';
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
inputValue: '1',
|
||||
result: '',
|
||||
ratesError: '',
|
||||
init() {
|
||||
const params = new URLSearchParams(
|
||||
window.location.search);
|
||||
const valueParam = params.get('v');
|
||||
if (valueParam) {
|
||||
this.inputValue = valueParam.replace(/,/g, '.');
|
||||
}
|
||||
this.$watch('inputValue', val => {
|
||||
if (val && val.indexOf(',') !== -1) {
|
||||
this.inputValue = val.replace(/,/g, '.');
|
||||
}
|
||||
});
|
||||
this.calculate();
|
||||
},
|
||||
calculate() {
|
||||
try {
|
||||
const normalized = parseNumber(this.inputValue);
|
||||
if (!normalized || isNaN(normalized)) {
|
||||
this.result = '';
|
||||
return;
|
||||
}
|
||||
const value = new Decimal(normalized);
|
||||
let rawResult;
|
||||
if (engine === 'linear') {
|
||||
const fromFactor = new Decimal(
|
||||
config.fromFactor);
|
||||
const toFactor = new Decimal(
|
||||
config.toFactor);
|
||||
rawResult = value.times(fromFactor)
|
||||
.dividedBy(toFactor);
|
||||
} else if (engine === 'intermediate') {
|
||||
let v = value.toNumber();
|
||||
v = config.toIntermediate(v);
|
||||
v = config.fromIntermediate(v);
|
||||
rawResult = new Decimal(v);
|
||||
} else {
|
||||
this.result = '';
|
||||
return;
|
||||
}
|
||||
this.result = prettyNumber(rawResult);
|
||||
const normalizedInputValue = this.inputValue
|
||||
.replace(/,/g, '.');
|
||||
if (normalizedInputValue
|
||||
&& normalizedInputValue !== '0') {
|
||||
history.replaceState(
|
||||
null, '', '?v=' + normalizedInputValue);
|
||||
}
|
||||
} catch (e) {
|
||||
this.result = '';
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats a number as plain digits with dot as decimal separator.
|
||||
* @param {Decimal|string|number} num
|
||||
@@ -185,12 +10,21 @@ function createConverter(engine, config) {
|
||||
function prettyNumber(num, minPrecision, maxPrecision) {
|
||||
minPrecision = minPrecision || 4;
|
||||
maxPrecision = maxPrecision || 10;
|
||||
const d = new Decimal(num);
|
||||
const val = num instanceof Decimal ? num.toNumber() : Number(num);
|
||||
if (!Number.isFinite(val)) {
|
||||
return '';
|
||||
}
|
||||
let d;
|
||||
try {
|
||||
d = new Decimal(num);
|
||||
} catch (e) {
|
||||
return '';
|
||||
}
|
||||
const absVal = d.abs();
|
||||
// Larger numbers need fewer decimal places for readable output;
|
||||
// smaller numbers get more to stay meaningful.
|
||||
let precision = maxPrecision;
|
||||
if (absVal.gte(1000000)) {
|
||||
if (absVal.gte(10000)) {
|
||||
precision = 2;
|
||||
} else if (absVal.gte(1000)) {
|
||||
precision = 4;
|
||||
@@ -210,17 +44,56 @@ function prettyNumber(num, minPrecision, maxPrecision) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a German number string.
|
||||
* Accepts both comma and dot as decimal separator.
|
||||
* @param {string} input
|
||||
* @returns {string} Normalized string with dot as decimal
|
||||
* Parses a number string for conversion.
|
||||
* Accepts both German (1.234,56) and US (1,234.56) notation.
|
||||
* The last dot or comma is always the decimal separator;
|
||||
* all preceding ones are treated as thousand separators and removed.
|
||||
* Invalid or empty input returns Decimal(0).
|
||||
* @param {string} input - User input from field
|
||||
* @returns {Decimal} Parsed Decimal value
|
||||
*/
|
||||
function parseNumber(input) {
|
||||
if (!input) return '0';
|
||||
const hasComma = input.indexOf(',') !== -1;
|
||||
const hasDot = input.indexOf('.') !== -1;
|
||||
if (hasComma && hasDot) {
|
||||
return input.replace(/\./g, '').replace(/,/g, '.') || '0';
|
||||
if (!input || input.trim() === '') {
|
||||
return new Decimal(0);
|
||||
}
|
||||
const trimmed = input.trim();
|
||||
const lastDot = trimmed.lastIndexOf('.');
|
||||
const lastComma = trimmed.lastIndexOf(',');
|
||||
const lastSep = Math.max(lastDot, lastComma);
|
||||
let normalized;
|
||||
if (lastSep === -1) {
|
||||
normalized = trimmed;
|
||||
} else {
|
||||
const beforeSep = trimmed.slice(0, lastSep).replace(/[.,]/g, '');
|
||||
const afterSep = trimmed.slice(lastSep + 1);
|
||||
normalized = beforeSep + '.' + afterSep;
|
||||
}
|
||||
try {
|
||||
return new Decimal(normalized);
|
||||
} catch (e) {
|
||||
return new Decimal(0);
|
||||
}
|
||||
return input.replace(/,/g, '.') || '0';
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the URL with the current input value.
|
||||
* @param {string} value - The input value
|
||||
*/
|
||||
function updateUrl(value) {
|
||||
const normalized = value ? value.replace(/,/g, '.') : '';
|
||||
if (normalized && normalized !== '0') {
|
||||
history.replaceState(null, '', '?v=' + normalized);
|
||||
} else {
|
||||
history.replaceState(null, '', '?v=1');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Navigates to a new URL with the current input value as parameter.
|
||||
* @param {string} url - Target URL
|
||||
* @param {string} value - Current input value
|
||||
*/
|
||||
function navigate(url, value) {
|
||||
const normalized = value ? value.replace(/,/g, '.') : '1';
|
||||
window.location.href = url + '?v=' + normalized;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user