diff --git a/web/i18n/de.json b/web/i18n/de.json index 7bbe21a..bcaba5c 100644 --- a/web/i18n/de.json +++ b/web/i18n/de.json @@ -26,6 +26,7 @@ "timeout": "Zeit\u00fcberschreitung bei Standortabfrage." }, "add": "Profil hinzuf\u00fcgen", + "save": "Profil speichern", "edit": "Bearbeiten", "delete": "L\u00f6schen", "noItems": "Noch keine Profile. Erstellen Sie eines, um zu beginnen." @@ -62,6 +63,7 @@ "tooltip": "Aktuelle oder gew\u00fcnschte Raumtemperatur. Standard 25\u00b0C." }, "add": "Raum hinzuf\u00fcgen", + "save": "Raum speichern", "noItems": "Noch keine R\u00e4ume. F\u00fcgen Sie R\u00e4ume zu Ihrem Profil hinzu." }, "devices": { @@ -75,6 +77,7 @@ "wattsPeak": { "label": "Watt (Spitze)", "tooltip": "Leistungsaufnahme bei Maximallast (z.B. Gaming)" }, "dutyCycle": { "label": "Einschaltdauer", "tooltip": "Anteil der aktiven Zeit (0\u20131). K\u00fchlschrank \u2248 0,3, PC \u2248 1,0." }, "add": "Ger\u00e4t hinzuf\u00fcgen", + "save": "Ger\u00e4t speichern", "noItems": "Noch keine Ger\u00e4te." }, "occupants": { @@ -89,6 +92,7 @@ }, "vulnerable": { "label": "Schutzbed\u00fcrftig", "tooltip": "Ankreuzen bei \u00e4lteren Menschen, Kleinkindern oder gesundheitlich eingeschr\u00e4nkten Personen. F\u00fcgt Pflegeerinnerungen hinzu." }, "add": "Bewohner hinzuf\u00fcgen", + "save": "Bewohner speichern", "noItems": "Noch keine Bewohner." }, "ac": { @@ -105,6 +109,7 @@ "dehumidify": { "label": "Entfeuchtung", "tooltip": "Ob das Ger\u00e4t einen Entfeuchtungsmodus hat" }, "rooms": { "label": "Zugewiesene R\u00e4ume", "tooltip": "Welche R\u00e4ume dieses Klimager\u00e4t versorgt" }, "add": "Klimager\u00e4t hinzuf\u00fcgen", + "save": "Klimager\u00e4t speichern", "noItems": "Noch keine Klimager\u00e4te." }, "toggles": { @@ -173,7 +178,23 @@ "riskLow": "Niedrig", "riskModerate": "Mittel", "riskHigh": "Hoch", - "riskExtreme": "Extrem" + "riskExtreme": "Extrem", + "noActions": "Keine Maßnahmen", + "effort": "Aufwand", + "impact": "Wirkung", + "aiDisclaimer": "KI-generierte Zusammenfassung. Kein Ersatz für professionelle Beratung.", + "coolVentilate": "Fenster öffnen", + "coolAC": "Klimaanlage", + "coolOverloaded": "Klima überlastet", + "aiActions": "KI-empfohlene Maßnahmen", + "category": { + "shading": "Verschattung", + "ventilation": "Lüftung", + "internal_gains": "Wärmequellen", + "ac_strategy": "Klimastrategie", + "hydration": "Flüssigkeit", + "care": "Pflege" + } }, "guide": { "title": "Erste Schritte", diff --git a/web/i18n/en.json b/web/i18n/en.json index a957a01..b46aea8 100644 --- a/web/i18n/en.json +++ b/web/i18n/en.json @@ -26,6 +26,7 @@ "timeout": "Location request timed out." }, "add": "Add Profile", + "save": "Save Profile", "edit": "Edit", "delete": "Delete", "noItems": "No profiles yet. Create one to get started." @@ -62,6 +63,7 @@ "tooltip": "Current or target indoor temperature. Default 25\u00b0C." }, "add": "Add Room", + "save": "Save Room", "noItems": "No rooms yet. Add rooms to your profile." }, "devices": { @@ -75,6 +77,7 @@ "wattsPeak": { "label": "Watts (Peak)", "tooltip": "Power draw at maximum load (e.g. gaming)" }, "dutyCycle": { "label": "Duty Cycle", "tooltip": "Fraction of time active (0\u20131). Fridge \u2248 0.3, PC \u2248 1.0." }, "add": "Add Device", + "save": "Save Device", "noItems": "No devices yet." }, "occupants": { @@ -89,6 +92,7 @@ }, "vulnerable": { "label": "Vulnerable", "tooltip": "Check if elderly, young children, or health-compromised. Adds care reminders." }, "add": "Add Occupants", + "save": "Save Occupants", "noItems": "No occupants yet." }, "ac": { @@ -105,6 +109,7 @@ "dehumidify": { "label": "Dehumidify", "tooltip": "Whether the unit has a dehumidify mode" }, "rooms": { "label": "Assigned Rooms", "tooltip": "Which rooms this AC unit serves" }, "add": "Add AC Unit", + "save": "Save AC Unit", "noItems": "No AC units yet." }, "toggles": { @@ -173,7 +178,23 @@ "riskLow": "Low", "riskModerate": "Moderate", "riskHigh": "High", - "riskExtreme": "Extreme" + "riskExtreme": "Extreme", + "noActions": "No actions", + "effort": "Effort", + "impact": "Impact", + "aiDisclaimer": "AI-generated summary. Not a substitute for professional advice.", + "coolVentilate": "Open windows", + "coolAC": "AC cooling", + "coolOverloaded": "AC overloaded", + "aiActions": "AI-recommended actions", + "category": { + "shading": "Shading", + "ventilation": "Ventilation", + "internal_gains": "Heat Sources", + "ac_strategy": "AC Strategy", + "hydration": "Hydration", + "care": "Care" + } }, "guide": { "title": "Getting Started", diff --git a/web/js/setup.js b/web/js/setup.js index adf585e..9e3095c 100644 --- a/web/js/setup.js +++ b/web/js/setup.js @@ -2,6 +2,10 @@ (function() { "use strict"; + // SVG icon templates + const iconEdit = ''; + const iconDelete = ''; + // Tab switching const tabBtns = document.querySelectorAll(".tab-btn"); const tabPanels = document.querySelectorAll(".tab-panel"); @@ -67,6 +71,7 @@ form.reset(); const hidden = form.querySelector('input[name="id"]'); if (hidden) hidden.value = ""; + exitEditMode(form); } function numOrDefault(val, def) { @@ -74,6 +79,47 @@ return isNaN(n) ? def : n; } + // Edit mode helpers + function enterEditMode(form) { + form.classList.add("ring-2", "ring-orange-400"); + const submitBtn = form.querySelector(".submit-btn"); + const cancelBtn = form.querySelector(".cancel-btn"); + if (submitBtn) submitBtn.textContent = submitBtn.dataset.saveText; + if (cancelBtn) cancelBtn.classList.remove("hidden"); + } + + function exitEditMode(form) { + form.classList.remove("ring-2", "ring-orange-400"); + const submitBtn = form.querySelector(".submit-btn"); + const cancelBtn = form.querySelector(".cancel-btn"); + if (submitBtn) submitBtn.textContent = submitBtn.dataset.addText; + if (cancelBtn) cancelBtn.classList.add("hidden"); + } + + // Wire up all cancel buttons + document.querySelectorAll(".cancel-btn").forEach(btn => { + btn.addEventListener("click", () => { + const form = btn.closest("form"); + if (form) resetForm(form); + }); + }); + + // List item card classes + const cardClasses = "bg-white dark:bg-gray-800 rounded-lg p-3 shadow-sm flex items-center justify-between hover:shadow-md transition-all duration-200"; + + // Action button builders + function editBtn(onclick) { + return ``; + } + + function deleteBtn(onclick) { + return ``; + } + + function actionGroup(editOnclick, deleteOnclick) { + return `