feat: improve setup page UX with SVG icons, edit state, and global max-width
Replace Unicode edit/delete characters with SVG pencil/trash icon buttons, add edit mode visual feedback (orange ring + Save/Cancel buttons), group action buttons consistently across all entity types, add hover effects to list items, and constrain all pages to 1800px max-width via layout template.
This commit is contained in:
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -2,6 +2,10 @@
|
||||
(function() {
|
||||
"use strict";
|
||||
|
||||
// SVG icon templates
|
||||
const iconEdit = '<svg class="w-4 h-4" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M17 3a2.83 2.83 0 114 4L7.5 20.5 2 22l1.5-5.5L17 3z"/></svg>';
|
||||
const iconDelete = '<svg class="w-4 h-4" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="3 6 5 6 21 6"/><path d="M19 6l-1 14a2 2 0 01-2 2H8a2 2 0 01-2-2L5 6"/><path d="M10 11v6"/><path d="M14 11v6"/><path d="M9 6V4a1 1 0 011-1h4a1 1 0 011 1v2"/></svg>';
|
||||
|
||||
// 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 `<button onclick="${onclick}" class="p-1.5 rounded-lg text-gray-400 hover:text-blue-600 hover:bg-blue-50 dark:hover:bg-blue-900/30 transition" title="Edit">${iconEdit}</button>`;
|
||||
}
|
||||
|
||||
function deleteBtn(onclick) {
|
||||
return `<button onclick="${onclick}" class="p-1.5 rounded-lg text-gray-400 hover:text-red-600 hover:bg-red-50 dark:hover:bg-red-900/30 transition" title="Delete">${iconDelete}</button>`;
|
||||
}
|
||||
|
||||
function actionGroup(editOnclick, deleteOnclick) {
|
||||
return `<div class="flex items-center gap-1">${editBtn(editOnclick)}${deleteBtn(deleteOnclick)}</div>`;
|
||||
}
|
||||
|
||||
// ========== Profiles ==========
|
||||
async function loadProfiles() {
|
||||
const profiles = await dbGetAll("profiles");
|
||||
@@ -86,17 +132,16 @@
|
||||
list.innerHTML = profiles.map(p => {
|
||||
const isActive = activeId === p.id;
|
||||
return `
|
||||
<div class="bg-white dark:bg-gray-800 rounded-lg p-3 shadow-sm flex items-center justify-between">
|
||||
<div class="${cardClasses}">
|
||||
<div>
|
||||
<span class="font-medium">${esc(p.name)}</span>
|
||||
<span class="text-xs text-gray-400 ml-2">${p.latitude.toFixed(4)}, ${p.longitude.toFixed(4)} · ${esc(p.timezone || "")}</span>
|
||||
</div>
|
||||
<div class="flex gap-2">
|
||||
<div class="flex items-center gap-2">
|
||||
<button onclick="activateProfile(${p.id})" class="text-xs px-2 py-1 rounded ${isActive ? 'bg-orange-600 text-white' : 'bg-gray-100 dark:bg-gray-700'}">
|
||||
${isActive ? '● Active' : 'Set Active'}
|
||||
</button>
|
||||
<button onclick="editProfileUI(${p.id})" class="text-xs text-blue-500 hover:text-blue-700">✎</button>
|
||||
<button onclick="deleteProfileUI(${p.id})" class="text-xs text-red-500 hover:text-red-700">✕</button>
|
||||
${actionGroup(`editProfileUI(${p.id})`, `deleteProfileUI(${p.id})`)}
|
||||
</div>
|
||||
</div>`;
|
||||
}).join("");
|
||||
@@ -118,6 +163,7 @@
|
||||
form.querySelector('input[name="latitude"]').value = p.latitude;
|
||||
form.querySelector('input[name="longitude"]').value = p.longitude;
|
||||
form.querySelector('input[name="timezone"]').value = p.timezone || "Europe/Berlin";
|
||||
enterEditMode(form);
|
||||
form.querySelector('input[name="name"]').focus();
|
||||
};
|
||||
|
||||
@@ -188,13 +234,12 @@
|
||||
return;
|
||||
}
|
||||
list.innerHTML = rooms.map(r => `
|
||||
<div class="bg-white dark:bg-gray-800 rounded-lg p-3 shadow-sm flex items-center justify-between">
|
||||
<div class="${cardClasses}">
|
||||
<div>
|
||||
<span class="font-medium">${esc(r.name)}</span>
|
||||
<span class="text-xs text-gray-400 ml-2">${r.areaSqm}m² · ${r.orientation} · SHGC ${r.shgc} · ${r.indoorTempC || 25}°C</span>
|
||||
</div>
|
||||
<button onclick="editRoomUI(${r.id})" class="text-xs text-blue-500 hover:text-blue-700">✎</button>
|
||||
<button onclick="deleteRoomUI(${r.id})" class="text-xs text-red-500 hover:text-red-700">✕</button>
|
||||
${actionGroup(`editRoomUI(${r.id})`, `deleteRoomUI(${r.id})`)}
|
||||
</div>
|
||||
`).join("");
|
||||
}
|
||||
@@ -216,6 +261,7 @@
|
||||
form.querySelector('input[name="shgc"]').value = r.shgc || 0.6;
|
||||
form.querySelector('select[name="insulation"]').value = r.insulation || "average";
|
||||
form.querySelector('input[name="indoorTempC"]').value = r.indoorTempC || 25;
|
||||
enterEditMode(form);
|
||||
form.querySelector('input[name="name"]').focus();
|
||||
};
|
||||
|
||||
@@ -276,13 +322,12 @@
|
||||
return;
|
||||
}
|
||||
list.innerHTML = allDevices.map(d => `
|
||||
<div class="bg-white dark:bg-gray-800 rounded-lg p-3 shadow-sm flex items-center justify-between">
|
||||
<div class="${cardClasses}">
|
||||
<div>
|
||||
<span class="font-medium">${esc(d.name)}</span>
|
||||
<span class="text-xs text-gray-400 ml-2">${esc(d._roomName)} · ${d.wattsTypical}W typical</span>
|
||||
</div>
|
||||
<button onclick="editDeviceUI(${d.id})" class="text-xs text-blue-500 hover:text-blue-700">✎</button>
|
||||
<button onclick="deleteDeviceUI(${d.id})" class="text-xs text-red-500 hover:text-red-700">✕</button>
|
||||
${actionGroup(`editDeviceUI(${d.id})`, `deleteDeviceUI(${d.id})`)}
|
||||
</div>
|
||||
`).join("");
|
||||
}
|
||||
@@ -299,6 +344,7 @@
|
||||
form.querySelector('input[name="wattsTypical"]').value = d.wattsTypical || 0;
|
||||
form.querySelector('input[name="wattsPeak"]').value = d.wattsPeak || 0;
|
||||
form.querySelector('input[name="dutyCycle"]').value = d.dutyCycle ?? 1.0;
|
||||
enterEditMode(form);
|
||||
form.querySelector('input[name="name"]').focus();
|
||||
};
|
||||
|
||||
@@ -347,13 +393,12 @@
|
||||
return;
|
||||
}
|
||||
list.innerHTML = allOccupants.map(o => `
|
||||
<div class="bg-white dark:bg-gray-800 rounded-lg p-3 shadow-sm flex items-center justify-between">
|
||||
<div class="${cardClasses}">
|
||||
<div>
|
||||
<span class="font-medium">${o.count}x ${esc(o.activityLevel)}</span>
|
||||
<span class="text-xs text-gray-400 ml-2">${esc(o._roomName)}${o.vulnerable ? ' · ⚠ vulnerable' : ''}</span>
|
||||
</div>
|
||||
<button onclick="editOccupantUI(${o.id})" class="text-xs text-blue-500 hover:text-blue-700">✎</button>
|
||||
<button onclick="deleteOccupantUI(${o.id})" class="text-xs text-red-500 hover:text-red-700">✕</button>
|
||||
${actionGroup(`editOccupantUI(${o.id})`, `deleteOccupantUI(${o.id})`)}
|
||||
</div>
|
||||
`).join("");
|
||||
}
|
||||
@@ -367,6 +412,7 @@
|
||||
form.querySelector('input[name="count"]').value = o.count || 1;
|
||||
form.querySelector('select[name="activityLevel"]').value = o.activityLevel || "sedentary";
|
||||
form.querySelector('input[name="vulnerable"]').checked = !!o.vulnerable;
|
||||
enterEditMode(form);
|
||||
form.querySelector('input[name="count"]').focus();
|
||||
};
|
||||
|
||||
@@ -414,13 +460,12 @@
|
||||
const roomIds = assignments.filter(a => a.acId === u.id).map(a => a.roomId);
|
||||
const roomNames = roomIds.map(id => roomMap[id] || `Room ${id}`).join(", ");
|
||||
return `
|
||||
<div class="bg-white dark:bg-gray-800 rounded-lg p-3 shadow-sm flex items-center justify-between">
|
||||
<div class="${cardClasses}">
|
||||
<div>
|
||||
<span class="font-medium">${esc(u.name)}</span>
|
||||
<span class="text-xs text-gray-400 ml-2">${u.capacityBtu} BTU · ${esc(u.acType)}${roomNames ? ' · ' + esc(roomNames) : ''}</span>
|
||||
</div>
|
||||
<button onclick="editACUI(${u.id})" class="text-xs text-blue-500 hover:text-blue-700">✎</button>
|
||||
<button onclick="deleteACUI(${u.id})" class="text-xs text-red-500 hover:text-red-700">✕</button>
|
||||
${actionGroup(`editACUI(${u.id})`, `deleteACUI(${u.id})`)}
|
||||
</div>
|
||||
`;
|
||||
}).join("");
|
||||
@@ -442,6 +487,7 @@
|
||||
document.querySelectorAll('#ac-room-checkboxes input').forEach(cb => {
|
||||
cb.checked = assignedRoomIds.has(parseInt(cb.value));
|
||||
});
|
||||
enterEditMode(form);
|
||||
form.querySelector('input[name="name"]').focus();
|
||||
};
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<main class="mx-auto px-4 sm:px-6 lg:px-8 py-6">
|
||||
<main class="max-w-[1800px] mx-auto px-4 sm:px-6 lg:px-8 py-6">
|
||||
{{block "content" .}}{{end}}
|
||||
</main>
|
||||
|
||||
|
||||
@@ -43,7 +43,8 @@
|
||||
<button type="button" id="geolocate-btn" class="px-3 py-1.5 text-sm bg-gray-100 dark:bg-gray-700 rounded-lg hover:bg-gray-200 dark:hover:bg-gray-600 transition">
|
||||
📍 {{t "setup.profiles.geolocate.button"}}
|
||||
</button>
|
||||
<button type="submit" class="px-4 py-1.5 text-sm bg-orange-600 text-white rounded-lg hover:bg-orange-700 transition">{{t "setup.profiles.add"}}</button>
|
||||
<button type="submit" class="submit-btn px-4 py-1.5 text-sm bg-orange-600 text-white rounded-lg hover:bg-orange-700 transition" data-add-text="{{t "setup.profiles.add"}}" data-save-text="{{t "setup.profiles.save"}}">{{t "setup.profiles.add"}}</button>
|
||||
<button type="button" class="cancel-btn hidden px-3 py-1.5 text-sm rounded-lg border border-gray-300 dark:border-gray-600 hover:bg-gray-100 dark:hover:bg-gray-700 transition">{{t "common.cancel"}}</button>
|
||||
</div>
|
||||
<input type="hidden" name="id" value="">
|
||||
</form>
|
||||
@@ -117,7 +118,8 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex gap-2">
|
||||
<button type="submit" class="px-4 py-1.5 text-sm bg-orange-600 text-white rounded-lg hover:bg-orange-700 transition">{{t "setup.rooms.add"}}</button>
|
||||
<button type="submit" class="submit-btn px-4 py-1.5 text-sm bg-orange-600 text-white rounded-lg hover:bg-orange-700 transition" data-add-text="{{t "setup.rooms.add"}}" data-save-text="{{t "setup.rooms.save"}}">{{t "setup.rooms.add"}}</button>
|
||||
<button type="button" class="cancel-btn hidden px-3 py-1.5 text-sm rounded-lg border border-gray-300 dark:border-gray-600 hover:bg-gray-100 dark:hover:bg-gray-700 transition">{{t "common.cancel"}}</button>
|
||||
</div>
|
||||
<input type="hidden" name="id" value="">
|
||||
<input type="hidden" name="profileId" value="">
|
||||
@@ -161,7 +163,10 @@
|
||||
<input type="number" name="dutyCycle" step="0.1" min="0" max="1" value="1.0" class="w-full px-3 py-1.5 rounded-lg border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700 text-sm">
|
||||
</div>
|
||||
</div>
|
||||
<button type="submit" class="px-4 py-1.5 text-sm bg-orange-600 text-white rounded-lg hover:bg-orange-700 transition">{{t "setup.devices.add"}}</button>
|
||||
<div class="flex gap-2">
|
||||
<button type="submit" class="submit-btn px-4 py-1.5 text-sm bg-orange-600 text-white rounded-lg hover:bg-orange-700 transition" data-add-text="{{t "setup.devices.add"}}" data-save-text="{{t "setup.devices.save"}}">{{t "setup.devices.add"}}</button>
|
||||
<button type="button" class="cancel-btn hidden px-3 py-1.5 text-sm rounded-lg border border-gray-300 dark:border-gray-600 hover:bg-gray-100 dark:hover:bg-gray-700 transition">{{t "common.cancel"}}</button>
|
||||
</div>
|
||||
<input type="hidden" name="id" value="">
|
||||
</form>
|
||||
<div id="devices-list" class="space-y-2">
|
||||
@@ -196,7 +201,10 @@
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<button type="submit" class="px-4 py-1.5 text-sm bg-orange-600 text-white rounded-lg hover:bg-orange-700 transition">{{t "setup.occupants.add"}}</button>
|
||||
<div class="flex gap-2">
|
||||
<button type="submit" class="submit-btn px-4 py-1.5 text-sm bg-orange-600 text-white rounded-lg hover:bg-orange-700 transition" data-add-text="{{t "setup.occupants.add"}}" data-save-text="{{t "setup.occupants.save"}}">{{t "setup.occupants.add"}}</button>
|
||||
<button type="button" class="cancel-btn hidden px-3 py-1.5 text-sm rounded-lg border border-gray-300 dark:border-gray-600 hover:bg-gray-100 dark:hover:bg-gray-700 transition">{{t "common.cancel"}}</button>
|
||||
</div>
|
||||
<input type="hidden" name="id" value="">
|
||||
</form>
|
||||
<div id="occupants-list" class="space-y-2">
|
||||
@@ -239,7 +247,10 @@
|
||||
<label class="block text-sm font-medium mb-1">{{t "setup.ac.rooms.label"}} <span class="tooltip-trigger" data-tooltip="{{t "setup.ac.rooms.tooltip"}}">?</span></label>
|
||||
<div id="ac-room-checkboxes" class="flex flex-wrap gap-2"></div>
|
||||
</div>
|
||||
<button type="submit" class="px-4 py-1.5 text-sm bg-orange-600 text-white rounded-lg hover:bg-orange-700 transition">{{t "setup.ac.add"}}</button>
|
||||
<div class="flex gap-2">
|
||||
<button type="submit" class="submit-btn px-4 py-1.5 text-sm bg-orange-600 text-white rounded-lg hover:bg-orange-700 transition" data-add-text="{{t "setup.ac.add"}}" data-save-text="{{t "setup.ac.save"}}">{{t "setup.ac.add"}}</button>
|
||||
<button type="button" class="cancel-btn hidden px-3 py-1.5 text-sm rounded-lg border border-gray-300 dark:border-gray-600 hover:bg-gray-100 dark:hover:bg-gray-700 transition">{{t "common.cancel"}}</button>
|
||||
</div>
|
||||
<input type="hidden" name="id" value="">
|
||||
</form>
|
||||
<div id="ac-list" class="space-y-2">
|
||||
|
||||
Reference in New Issue
Block a user