Add bettervent.me provider with lazy-cached device list (~6,700 Eurovent-certified heat pumps), search API endpoint, device search UI with auto-populate, BTU/kW unit switcher for European users, and extended AC fields (SEER, SCOP, COP, TOL, Tbiv, refrigerant). Closes #2.
527 lines
42 KiB
HTML
527 lines
42 KiB
HTML
{{define "content"}}
|
|
<div id="setup">
|
|
<h1 class="text-2xl font-bold mb-6">{{t "setup.title"}}</h1>
|
|
|
|
<!-- Tabs -->
|
|
<div class="flex gap-1 mb-6 overflow-x-auto border-b border-gray-200 dark:border-gray-700">
|
|
<button class="tab-btn px-3 py-2 text-sm font-medium whitespace-nowrap border-b-2 border-orange-600 text-orange-600 dark:text-orange-400 dark:border-orange-400" data-tab="profiles">{{t "setup.profiles.title"}}</button>
|
|
<button class="tab-btn px-3 py-2 text-sm font-medium whitespace-nowrap border-b-2 border-transparent text-gray-500 hover:text-gray-700 dark:text-gray-400" data-tab="rooms">{{t "setup.rooms.title"}}</button>
|
|
<button class="tab-btn px-3 py-2 text-sm font-medium whitespace-nowrap border-b-2 border-transparent text-gray-500 hover:text-gray-700 dark:text-gray-400" data-tab="devices">{{t "setup.devices.title"}}</button>
|
|
<button class="tab-btn px-3 py-2 text-sm font-medium whitespace-nowrap border-b-2 border-transparent text-gray-500 hover:text-gray-700 dark:text-gray-400" data-tab="occupants">{{t "setup.occupants.title"}}</button>
|
|
<button class="tab-btn px-3 py-2 text-sm font-medium whitespace-nowrap border-b-2 border-transparent text-gray-500 hover:text-gray-700 dark:text-gray-400" data-tab="ac">{{t "setup.ac.title"}}</button>
|
|
<button class="tab-btn px-3 py-2 text-sm font-medium whitespace-nowrap border-b-2 border-transparent text-gray-500 hover:text-gray-700 dark:text-gray-400" data-tab="toggles">{{t "setup.toggles.title"}}</button>
|
|
<button class="tab-btn px-3 py-2 text-sm font-medium whitespace-nowrap border-b-2 border-transparent text-gray-500 hover:text-gray-700 dark:text-gray-400" data-tab="forecast">{{t "setup.forecast.title"}}</button>
|
|
<button class="tab-btn px-3 py-2 text-sm font-medium whitespace-nowrap border-b-2 border-transparent text-gray-500 hover:text-gray-700 dark:text-gray-400" data-tab="llm">{{t "setup.llm.title"}}</button>
|
|
</div>
|
|
|
|
<!-- Toast -->
|
|
<div id="toast" class="hidden fixed bottom-4 right-4 px-4 py-2 rounded-lg shadow-lg text-sm z-50 transition-opacity"></div>
|
|
|
|
<!-- Profiles tab -->
|
|
<section id="tab-profiles" class="tab-panel">
|
|
<p class="text-sm text-gray-500 dark:text-gray-400 mb-4">{{t "setup.profiles.help"}}</p>
|
|
<form id="profile-form" class="bg-white dark:bg-gray-800 rounded-xl p-4 shadow-sm space-y-3 mb-4">
|
|
<div class="grid grid-cols-1 sm:grid-cols-2 gap-3">
|
|
<div>
|
|
<label class="block text-sm font-medium mb-1">{{t "setup.profiles.name.label"}} <span class="tooltip-trigger" data-tooltip="{{t "setup.profiles.name.tooltip"}}">?</span></label>
|
|
<input type="text" name="name" required 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>
|
|
<label class="block text-sm font-medium mb-1">{{t "setup.profiles.timezone.label"}} <span class="tooltip-trigger" data-tooltip="{{t "setup.profiles.timezone.tooltip"}}">?</span></label>
|
|
<input type="text" name="timezone" value="Europe/Berlin" 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>
|
|
<label class="block text-sm font-medium mb-1">{{t "setup.profiles.latitude.label"}} <span class="tooltip-trigger" data-tooltip="{{t "setup.profiles.latitude.tooltip"}}">?</span></label>
|
|
<input type="number" name="latitude" step="0.0001" required 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>
|
|
<label class="block text-sm font-medium mb-1">{{t "setup.profiles.longitude.label"}} <span class="tooltip-trigger" data-tooltip="{{t "setup.profiles.longitude.tooltip"}}">?</span></label>
|
|
<input type="number" name="longitude" step="0.0001" required 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>
|
|
<div class="flex gap-2">
|
|
<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="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>
|
|
<div id="profiles-list" class="space-y-2">
|
|
<p class="text-sm text-gray-400 dark:text-gray-500">{{t "setup.profiles.noItems"}}</p>
|
|
</div>
|
|
</section>
|
|
|
|
<!-- Rooms tab -->
|
|
<section id="tab-rooms" class="tab-panel hidden">
|
|
<p class="text-sm text-gray-500 dark:text-gray-400 mb-4">{{t "setup.rooms.help"}}</p>
|
|
<form id="room-form" class="bg-white dark:bg-gray-800 rounded-xl p-4 shadow-sm space-y-3 mb-4">
|
|
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-3">
|
|
<div>
|
|
<label class="block text-sm font-medium mb-1">{{t "setup.rooms.name.label"}} <span class="tooltip-trigger" data-tooltip="{{t "setup.rooms.name.tooltip"}}">?</span></label>
|
|
<input type="text" name="name" required 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>
|
|
<label class="block text-sm font-medium mb-1">{{t "setup.rooms.area.label"}} <span class="tooltip-trigger" data-tooltip="{{t "setup.rooms.area.tooltip"}}">?</span></label>
|
|
<input type="number" name="areaSqm" step="0.1" required 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>
|
|
<label class="block text-sm font-medium mb-1">{{t "setup.rooms.ceilingHeight.label"}} <span class="tooltip-trigger" data-tooltip="{{t "setup.rooms.ceilingHeight.tooltip"}}">?</span></label>
|
|
<input type="number" name="ceilingHeightM" step="0.1" value="2.5" 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>
|
|
<label class="block text-sm font-medium mb-1">{{t "setup.rooms.floor.label"}} <span class="tooltip-trigger" data-tooltip="{{t "setup.rooms.floor.tooltip"}}">?</span></label>
|
|
<input type="number" name="floor" value="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>
|
|
<label class="block text-sm font-medium mb-1">{{t "setup.rooms.orientation.label"}} <span class="tooltip-trigger" data-tooltip="{{t "setup.rooms.orientation.tooltip"}}">?</span></label>
|
|
<select name="orientation" 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">
|
|
<option value="N">{{t "setup.rooms.orientation.options.N"}}</option><option value="NE">{{t "setup.rooms.orientation.options.NE"}}</option><option value="E">{{t "setup.rooms.orientation.options.E"}}</option>
|
|
<option value="SE">{{t "setup.rooms.orientation.options.SE"}}</option><option value="S" selected>{{t "setup.rooms.orientation.options.S"}}</option><option value="SW">{{t "setup.rooms.orientation.options.SW"}}</option>
|
|
<option value="W">{{t "setup.rooms.orientation.options.W"}}</option><option value="NW">{{t "setup.rooms.orientation.options.NW"}}</option>
|
|
</select>
|
|
</div>
|
|
<div>
|
|
<label class="block text-sm font-medium mb-1">{{t "setup.rooms.shadingType.label"}} <span class="tooltip-trigger" data-tooltip="{{t "setup.rooms.shadingType.tooltip"}}">?</span></label>
|
|
<select name="shadingType" 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">
|
|
<option value="none">{{t "setup.rooms.shadingType.options.none"}}</option><option value="blinds">{{t "setup.rooms.shadingType.options.blinds"}}</option>
|
|
<option value="shutters">{{t "setup.rooms.shadingType.options.shutters"}}</option><option value="awning">{{t "setup.rooms.shadingType.options.awning"}}</option>
|
|
</select>
|
|
</div>
|
|
<div>
|
|
<label class="block text-sm font-medium mb-1">{{t "setup.rooms.shadingFactor.label"}} <span class="tooltip-trigger" data-tooltip="{{t "setup.rooms.shadingFactor.tooltip"}}">?</span></label>
|
|
<input type="number" name="shadingFactor" 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>
|
|
<label class="block text-sm font-medium mb-1">{{t "setup.rooms.ventilationAch.label"}} <span class="tooltip-trigger" data-tooltip="{{t "setup.rooms.ventilationAch.tooltip"}}">?</span></label>
|
|
<input type="number" name="ventilationAch" step="0.1" value="0.5" 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>
|
|
<label class="block text-sm font-medium mb-1">{{t "setup.rooms.windowFraction.label"}} <span class="tooltip-trigger" data-tooltip="{{t "setup.rooms.windowFraction.tooltip"}}">?</span></label>
|
|
<input type="number" name="windowFraction" step="0.01" min="0" max="1" value="0.15" 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>
|
|
<label class="block text-sm font-medium mb-1">{{t "setup.rooms.shgc.label"}} <span class="tooltip-trigger" data-tooltip="{{t "setup.rooms.shgc.tooltip"}}">?</span></label>
|
|
<input type="number" name="shgc" step="0.1" min="0" max="1" value="0.6" 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>
|
|
<label class="block text-sm font-medium mb-1">{{t "setup.rooms.insulation.label"}} <span class="tooltip-trigger" data-tooltip="{{t "setup.rooms.insulation.tooltip"}}">?</span></label>
|
|
<select name="insulation" 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">
|
|
<option value="poor">{{t "setup.rooms.insulation.options.poor"}}</option><option value="average" selected>{{t "setup.rooms.insulation.options.average"}}</option>
|
|
<option value="good">{{t "setup.rooms.insulation.options.good"}}</option><option value="excellent">{{t "setup.rooms.insulation.options.excellent"}}</option>
|
|
</select>
|
|
</div>
|
|
<div>
|
|
<label class="block text-sm font-medium mb-1">{{t "setup.rooms.indoorTemp.label"}} <span class="tooltip-trigger" data-tooltip="{{t "setup.rooms.indoorTemp.tooltip"}}">?</span></label>
|
|
<input type="number" name="indoorTempC" step="0.5" min="15" max="35" value="25" 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>
|
|
<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.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="">
|
|
</form>
|
|
<div id="rooms-list" class="space-y-2">
|
|
<p class="text-sm text-gray-400 dark:text-gray-500">{{t "setup.rooms.noItems"}}</p>
|
|
</div>
|
|
|
|
<!-- Windows sub-section (shown after a room is saved/selected for editing) -->
|
|
<div id="windows-section" class="mt-6 hidden">
|
|
<h3 class="text-md font-semibold mb-2">{{t "setup.windows.title"}}</h3>
|
|
<p class="text-sm text-gray-500 dark:text-gray-400 mb-3">{{t "setup.windows.help"}}</p>
|
|
<div id="windows-save-first" class="hidden text-sm text-gray-400 italic mb-3">{{t "setup.windows.saveRoomFirst"}}</div>
|
|
<form id="window-form" class="bg-white dark:bg-gray-800 rounded-xl p-4 shadow-sm space-y-3 mb-4">
|
|
<div class="grid grid-cols-2 sm:grid-cols-3 lg:grid-cols-5 gap-3">
|
|
<div>
|
|
<label class="block text-xs font-medium mb-1">{{t "setup.windows.orientation.label"}}</label>
|
|
<select name="orientation" class="w-full px-2 py-1 rounded-lg border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700 text-sm">
|
|
<option value="N">{{t "setup.rooms.orientation.options.N"}}</option><option value="NE">{{t "setup.rooms.orientation.options.NE"}}</option><option value="E">{{t "setup.rooms.orientation.options.E"}}</option>
|
|
<option value="SE">{{t "setup.rooms.orientation.options.SE"}}</option><option value="S" selected>{{t "setup.rooms.orientation.options.S"}}</option><option value="SW">{{t "setup.rooms.orientation.options.SW"}}</option>
|
|
<option value="W">{{t "setup.rooms.orientation.options.W"}}</option><option value="NW">{{t "setup.rooms.orientation.options.NW"}}</option>
|
|
</select>
|
|
</div>
|
|
<div>
|
|
<label class="block text-xs font-medium mb-1">{{t "setup.windows.area.label"}}</label>
|
|
<input type="number" name="areaSqm" step="0.1" min="0.1" required class="w-full px-2 py-1 rounded-lg border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700 text-sm">
|
|
</div>
|
|
<div>
|
|
<label class="block text-xs font-medium mb-1">{{t "setup.windows.shgc.label"}}</label>
|
|
<input type="number" name="shgc" step="0.1" min="0" max="1" value="0.6" class="w-full px-2 py-1 rounded-lg border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700 text-sm">
|
|
</div>
|
|
<div>
|
|
<label class="block text-xs font-medium mb-1">{{t "setup.windows.shadingType.label"}}</label>
|
|
<select name="shadingType" class="w-full px-2 py-1 rounded-lg border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700 text-sm">
|
|
<option value="none">{{t "setup.rooms.shadingType.options.none"}}</option><option value="blinds">{{t "setup.rooms.shadingType.options.blinds"}}</option>
|
|
<option value="shutters">{{t "setup.rooms.shadingType.options.shutters"}}</option><option value="awning">{{t "setup.rooms.shadingType.options.awning"}}</option>
|
|
</select>
|
|
</div>
|
|
<div>
|
|
<label class="block text-xs font-medium mb-1">{{t "setup.windows.shadingFactor.label"}}</label>
|
|
<input type="number" name="shadingFactor" step="0.1" min="0" max="1" value="1.0" class="w-full px-2 py-1 rounded-lg border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700 text-sm">
|
|
</div>
|
|
</div>
|
|
<div class="flex gap-2">
|
|
<button type="submit" class="submit-btn px-3 py-1 text-sm bg-orange-600 text-white rounded-lg hover:bg-orange-700 transition" data-add-text="{{t "setup.windows.add"}}" data-save-text="{{t "setup.windows.save"}}">{{t "setup.windows.add"}}</button>
|
|
<button type="button" class="cancel-btn hidden px-3 py-1 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="roomId" value="">
|
|
</form>
|
|
<div id="windows-list" class="space-y-2">
|
|
<p class="text-sm text-gray-400 dark:text-gray-500">{{t "setup.windows.noItems"}}</p>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<!-- Devices tab -->
|
|
<section id="tab-devices" class="tab-panel hidden">
|
|
<p class="text-sm text-gray-500 dark:text-gray-400 mb-4">{{t "setup.devices.help"}}</p>
|
|
<div id="device-no-rooms" class="hidden text-sm text-amber-600 dark:text-amber-400 mb-3">{{t "setup.devices.noRooms"}}</div>
|
|
<form id="device-form" class="bg-white dark:bg-gray-800 rounded-xl p-4 shadow-sm space-y-3 mb-4">
|
|
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-3">
|
|
<div>
|
|
<label class="block text-sm font-medium mb-1">{{t "setup.devices.room.label"}} <span class="tooltip-trigger" data-tooltip="{{t "setup.devices.room.tooltip"}}">?</span></label>
|
|
<select name="roomId" required 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" id="device-room-select"></select>
|
|
</div>
|
|
<div>
|
|
<label class="block text-sm font-medium mb-1">{{t "setup.devices.name.label"}} <span class="tooltip-trigger" data-tooltip="{{t "setup.devices.name.tooltip"}}">?</span></label>
|
|
<input type="text" name="name" required 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>
|
|
<label class="block text-sm font-medium mb-1">{{t "setup.devices.type.label"}} <span class="tooltip-trigger" data-tooltip="{{t "setup.devices.type.tooltip"}}">?</span></label>
|
|
<input type="text" name="deviceType" value="electronics" 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>
|
|
<label class="block text-sm font-medium mb-1">{{t "setup.devices.wattsIdle.label"}} <span class="tooltip-trigger" data-tooltip="{{t "setup.devices.wattsIdle.tooltip"}}">?</span></label>
|
|
<input type="number" name="wattsIdle" step="1" value="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>
|
|
<label class="block text-sm font-medium mb-1">{{t "setup.devices.wattsTypical.label"}} <span class="tooltip-trigger" data-tooltip="{{t "setup.devices.wattsTypical.tooltip"}}">?</span></label>
|
|
<input type="number" name="wattsTypical" step="1" required 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>
|
|
<label class="block text-sm font-medium mb-1">{{t "setup.devices.wattsPeak.label"}} <span class="tooltip-trigger" data-tooltip="{{t "setup.devices.wattsPeak.tooltip"}}">?</span></label>
|
|
<input type="number" name="wattsPeak" step="1" value="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>
|
|
<label class="block text-sm font-medium mb-1">{{t "setup.devices.dutyCycle.label"}} <span class="tooltip-trigger" data-tooltip="{{t "setup.devices.dutyCycle.tooltip"}}">?</span></label>
|
|
<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>
|
|
<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">
|
|
<p class="text-sm text-gray-400 dark:text-gray-500">{{t "setup.devices.noItems"}}</p>
|
|
</div>
|
|
</section>
|
|
|
|
<!-- Occupants tab -->
|
|
<section id="tab-occupants" class="tab-panel hidden">
|
|
<p class="text-sm text-gray-500 dark:text-gray-400 mb-4">{{t "setup.occupants.help"}}</p>
|
|
<div id="occupant-no-rooms" class="hidden text-sm text-amber-600 dark:text-amber-400 mb-3">{{t "setup.occupants.noRooms"}}</div>
|
|
<form id="occupant-form" class="bg-white dark:bg-gray-800 rounded-xl p-4 shadow-sm space-y-3 mb-4">
|
|
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-3">
|
|
<div>
|
|
<label class="block text-sm font-medium mb-1">{{t "setup.occupants.room.label"}} <span class="tooltip-trigger" data-tooltip="{{t "setup.occupants.room.tooltip"}}">?</span></label>
|
|
<select name="roomId" required 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" id="occupant-room-select"></select>
|
|
</div>
|
|
<div>
|
|
<label class="block text-sm font-medium mb-1">{{t "setup.occupants.count.label"}} <span class="tooltip-trigger" data-tooltip="{{t "setup.occupants.count.tooltip"}}">?</span></label>
|
|
<input type="number" name="count" min="1" value="1" required 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>
|
|
<label class="block text-sm font-medium mb-1">{{t "setup.occupants.activity.label"}} <span class="tooltip-trigger" data-tooltip="{{t "setup.occupants.activity.tooltip"}}">?</span></label>
|
|
<select name="activityLevel" 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">
|
|
<option value="sleeping">{{t "setup.occupants.activity.options.sleeping"}}</option><option value="sedentary" selected>{{t "setup.occupants.activity.options.sedentary"}}</option>
|
|
<option value="light">{{t "setup.occupants.activity.options.light"}}</option><option value="moderate">{{t "setup.occupants.activity.options.moderate"}}</option><option value="heavy">{{t "setup.occupants.activity.options.heavy"}}</option>
|
|
</select>
|
|
</div>
|
|
<div class="flex items-end pb-1">
|
|
<label class="flex items-center gap-2 text-sm">
|
|
<input type="checkbox" name="vulnerable" class="rounded">
|
|
{{t "setup.occupants.vulnerable.label"}} <span class="tooltip-trigger" data-tooltip="{{t "setup.occupants.vulnerable.tooltip"}}">?</span>
|
|
</label>
|
|
</div>
|
|
</div>
|
|
<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">
|
|
<p class="text-sm text-gray-400 dark:text-gray-500">{{t "setup.occupants.noItems"}}</p>
|
|
</div>
|
|
</section>
|
|
|
|
<!-- AC Units tab -->
|
|
<section id="tab-ac" class="tab-panel hidden">
|
|
<p class="text-sm text-gray-500 dark:text-gray-400 mb-4">{{t "setup.ac.help"}}</p>
|
|
<div id="ac-no-rooms" class="hidden text-sm text-amber-600 dark:text-amber-400 mb-3">{{t "setup.ac.noRooms"}}</div>
|
|
|
|
<!-- Device search -->
|
|
<div class="mb-3">
|
|
<label class="block text-sm font-medium mb-1">{{t "setup.ac.search.label"}}</label>
|
|
<div class="relative">
|
|
<input type="text" id="ac-device-search" placeholder="{{t "setup.ac.search.placeholder"}}" 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 id="ac-search-results" class="hidden absolute z-40 w-full mt-1 bg-white dark:bg-gray-800 border border-gray-300 dark:border-gray-600 rounded-lg shadow-lg max-h-64 overflow-y-auto"></div>
|
|
</div>
|
|
<p class="text-xs text-gray-400 dark:text-gray-500 mt-1">{{t "setup.ac.search.hint"}} — <a href="https://bettervent.me" class="text-orange-600 dark:text-orange-400 hover:underline" target="_blank" rel="noopener">bettervent.me</a></p>
|
|
</div>
|
|
|
|
<!-- Unit toggle -->
|
|
<div class="flex items-center gap-2 mb-3">
|
|
<span class="text-sm text-gray-500 dark:text-gray-400">{{t "setup.ac.unit.switch"}}:</span>
|
|
<button type="button" id="ac-unit-toggle" class="px-3 py-1 text-xs rounded-full border border-gray-300 dark:border-gray-600 hover:bg-gray-100 dark:hover:bg-gray-700 transition font-medium" data-unit="btuh">BTU/h</button>
|
|
</div>
|
|
|
|
<form id="ac-form" class="bg-white dark:bg-gray-800 rounded-xl p-4 shadow-sm space-y-3 mb-4">
|
|
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-3">
|
|
<div>
|
|
<label class="block text-sm font-medium mb-1">{{t "setup.ac.name.label"}} <span class="tooltip-trigger" data-tooltip="{{t "setup.ac.name.tooltip"}}">?</span></label>
|
|
<input type="text" name="name" required 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>
|
|
<label class="block text-sm font-medium mb-1">{{t "setup.ac.type.label"}} <span class="tooltip-trigger" data-tooltip="{{t "setup.ac.type.tooltip"}}">?</span></label>
|
|
<select name="acType" 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">
|
|
<option value="portable">{{t "setup.ac.type.options.portable"}}</option><option value="window">{{t "setup.ac.type.options.window"}}</option>
|
|
<option value="split">{{t "setup.ac.type.options.split"}}</option><option value="central">{{t "setup.ac.type.options.central"}}</option>
|
|
</select>
|
|
</div>
|
|
<div>
|
|
<label class="block text-sm font-medium mb-1" id="ac-capacity-label">{{t "setup.ac.capacity.label"}} <span class="tooltip-trigger" data-tooltip="{{t "setup.ac.capacity.tooltip"}}">?</span></label>
|
|
<input type="number" name="capacityBtu" step="100" required 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>
|
|
<label class="block text-sm font-medium mb-1">{{t "setup.ac.eer.label"}} <span class="tooltip-trigger" data-tooltip="{{t "setup.ac.eer.tooltip"}}">?</span></label>
|
|
<input type="number" name="efficiencyEer" step="0.1" value="10" 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 class="flex items-end pb-1">
|
|
<label class="flex items-center gap-2 text-sm">
|
|
<input type="checkbox" name="hasDehumidify" class="rounded">
|
|
{{t "setup.ac.dehumidify.label"}} <span class="tooltip-trigger" data-tooltip="{{t "setup.ac.dehumidify.tooltip"}}">?</span>
|
|
</label>
|
|
</div>
|
|
<div class="flex items-end pb-1">
|
|
<label class="flex items-center gap-2 text-sm">
|
|
<input type="checkbox" name="canHeat" class="rounded" id="ac-can-heat">
|
|
{{t "setup.ac.canHeat.label"}} <span class="tooltip-trigger" data-tooltip="{{t "setup.ac.canHeat.tooltip"}}">?</span>
|
|
</label>
|
|
</div>
|
|
<div>
|
|
<label class="block text-sm font-medium mb-1" id="ac-heating-capacity-label">{{t "setup.ac.heatingCapacity.label"}} <span class="tooltip-trigger" data-tooltip="{{t "setup.ac.heatingCapacity.tooltip"}}">?</span></label>
|
|
<input type="number" name="heatingCapacityBtu" step="100" value="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>
|
|
<div>
|
|
<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>
|
|
<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>
|
|
|
|
<!-- Extended device info (shown after search selection or when editing device with extended data) -->
|
|
<div id="ac-extended-info" class="hidden bg-gray-50 dark:bg-gray-900 rounded-lg p-3 text-sm space-y-1 mb-4">
|
|
<div class="font-medium text-gray-600 dark:text-gray-300 mb-1" id="ac-extended-title"></div>
|
|
<div class="grid grid-cols-2 sm:grid-cols-3 gap-x-4 gap-y-0.5 text-xs text-gray-500 dark:text-gray-400">
|
|
<div>{{t "setup.ac.seer"}}: <span id="ac-ext-seer" class="font-medium text-gray-700 dark:text-gray-200"></span></div>
|
|
<div>{{t "setup.ac.scop"}}: <span id="ac-ext-scop" class="font-medium text-gray-700 dark:text-gray-200"></span></div>
|
|
<div>{{t "setup.ac.cop"}}: <span id="ac-ext-cop" class="font-medium text-gray-700 dark:text-gray-200"></span></div>
|
|
<div>{{t "setup.ac.tol"}}: <span id="ac-ext-tol" class="font-medium text-gray-700 dark:text-gray-200"></span></div>
|
|
<div>{{t "setup.ac.tbiv"}}: <span id="ac-ext-tbiv" class="font-medium text-gray-700 dark:text-gray-200"></span></div>
|
|
<div>{{t "setup.ac.refrigerant"}}: <span id="ac-ext-refrigerant" class="font-medium text-gray-700 dark:text-gray-200"></span></div>
|
|
</div>
|
|
</div>
|
|
|
|
<div id="ac-list" class="space-y-2">
|
|
<p class="text-sm text-gray-400 dark:text-gray-500">{{t "setup.ac.noItems"}}</p>
|
|
</div>
|
|
</section>
|
|
|
|
<!-- Toggles tab -->
|
|
<section id="tab-toggles" class="tab-panel hidden">
|
|
<p class="text-sm text-gray-500 dark:text-gray-400 mb-4">{{t "setup.toggles.help"}}</p>
|
|
<div class="bg-white dark:bg-gray-800 rounded-xl p-4 shadow-sm space-y-3">
|
|
<label class="flex items-center gap-3 cursor-pointer">
|
|
<input type="checkbox" id="toggle-gaming" class="toggle-switch rounded" data-toggle="gaming">
|
|
<span class="text-sm">{{t "setup.toggles.gaming"}}</span>
|
|
</label>
|
|
<label class="flex items-center gap-3 cursor-pointer">
|
|
<input type="checkbox" id="toggle-cooking" class="toggle-switch rounded" data-toggle="cooking">
|
|
<span class="text-sm">{{t "setup.toggles.cooking"}}</span>
|
|
</label>
|
|
<label class="flex items-center gap-3 cursor-pointer">
|
|
<input type="checkbox" id="toggle-laundry" class="toggle-switch rounded" data-toggle="laundry">
|
|
<span class="text-sm">{{t "setup.toggles.laundry"}}</span>
|
|
</label>
|
|
<label class="flex items-center gap-3 cursor-pointer">
|
|
<input type="checkbox" id="toggle-guests" class="toggle-switch rounded" data-toggle="guests">
|
|
<span class="text-sm">{{t "setup.toggles.guests"}}</span>
|
|
</label>
|
|
</div>
|
|
</section>
|
|
|
|
<!-- Forecast tab -->
|
|
<section id="tab-forecast" class="tab-panel hidden">
|
|
<p class="text-sm text-gray-500 dark:text-gray-400 mb-4">{{t "setup.forecast.help"}}</p>
|
|
<div class="bg-white dark:bg-gray-800 rounded-xl p-4 shadow-sm space-y-3">
|
|
<div class="flex items-center gap-4">
|
|
<button id="fetch-forecast-btn" class="px-4 py-2 bg-orange-600 text-white rounded-lg hover:bg-orange-700 transition text-sm">
|
|
{{t "setup.forecast.fetch"}}
|
|
</button>
|
|
<span id="forecast-status" class="text-sm text-gray-500 dark:text-gray-400">
|
|
{{t "setup.forecast.lastFetched"}}: <span id="last-fetched">{{t "setup.forecast.never"}}</span>
|
|
</span>
|
|
</div>
|
|
<div id="forecast-spinner" class="hidden text-sm text-gray-500 dark:text-gray-400">
|
|
<span class="inline-block animate-spin mr-2">↻</span> {{t "setup.forecast.fetching"}}
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<!-- LLM tab -->
|
|
<section id="tab-llm" class="tab-panel hidden">
|
|
<p class="text-sm text-gray-500 dark:text-gray-400 mb-4">{{t "setup.llm.help"}}</p>
|
|
<div class="bg-white dark:bg-gray-800 rounded-xl p-4 shadow-sm space-y-4">
|
|
<div id="llm-server-info" class="text-sm text-gray-400 hidden"></div>
|
|
<form id="llm-form" class="space-y-3">
|
|
<div class="grid grid-cols-1 sm:grid-cols-2 gap-3">
|
|
<div>
|
|
<label class="block text-sm font-medium mb-1">{{t "setup.llm.provider"}}</label>
|
|
<select name="llmProvider" id="llm-provider-select" 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">
|
|
<option value="">-- {{t "setup.llm.provider"}} --</option>
|
|
<option value="anthropic">{{t "setup.llm.providerOptions.anthropic"}}</option>
|
|
<option value="openai">{{t "setup.llm.providerOptions.openai"}}</option>
|
|
<option value="gemini">{{t "setup.llm.providerOptions.gemini"}}</option>
|
|
</select>
|
|
</div>
|
|
<div>
|
|
<label class="block text-sm font-medium mb-1">{{t "setup.llm.apiKey"}}</label>
|
|
<input type="password" name="llmApiKey" id="llm-api-key" placeholder="{{t "setup.llm.apiKeyPlaceholder"}}" 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>
|
|
<label class="block text-sm font-medium mb-1">{{t "setup.llm.model"}}</label>
|
|
<input type="text" name="llmModel" id="llm-model" placeholder="{{t "setup.llm.modelPlaceholder"}}" 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.llm.save"}}</button>
|
|
</form>
|
|
</div>
|
|
</section>
|
|
|
|
<!-- Card templates (cloned by setup.js) -->
|
|
<template id="tpl-profile-card">
|
|
<div class="bg-white dark:bg-gray-800 rounded-lg p-3 shadow-sm flex items-center justify-between hover:shadow-md transition-all duration-200">
|
|
<div>
|
|
<span class="font-medium" data-slot="name"></span>
|
|
<span class="text-xs text-gray-400 ml-2" data-slot="details"></span>
|
|
</div>
|
|
<div class="flex items-center gap-2">
|
|
<button data-action="activate" class="text-xs px-2 py-1 rounded"></button>
|
|
<div class="flex items-center gap-1">
|
|
<button data-action="edit" 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"><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></button>
|
|
<button data-action="delete" 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"><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></button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<template id="tpl-room-card">
|
|
<div class="bg-white dark:bg-gray-800 rounded-lg p-3 shadow-sm flex items-center justify-between hover:shadow-md transition-all duration-200">
|
|
<div>
|
|
<span class="font-medium" data-slot="name"></span>
|
|
<span class="text-xs text-gray-400 ml-2" data-slot="details"></span>
|
|
</div>
|
|
<div class="flex items-center gap-1">
|
|
<button data-action="edit" 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"><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></button>
|
|
<button data-action="delete" 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"><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></button>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<template id="tpl-window-card">
|
|
<div class="bg-white dark:bg-gray-800 rounded-lg p-3 shadow-sm flex items-center justify-between hover:shadow-md transition-all duration-200">
|
|
<div>
|
|
<span class="font-medium" data-slot="orientation"></span>
|
|
<span class="text-xs text-gray-400 ml-2" data-slot="details"></span>
|
|
</div>
|
|
<div class="flex items-center gap-1">
|
|
<button data-action="edit" 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"><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></button>
|
|
<button data-action="delete" 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"><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></button>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<template id="tpl-device-card">
|
|
<div class="bg-white dark:bg-gray-800 rounded-lg p-3 shadow-sm flex items-center justify-between hover:shadow-md transition-all duration-200">
|
|
<div>
|
|
<span class="font-medium" data-slot="name"></span>
|
|
<span class="text-xs text-gray-400 ml-2" data-slot="details"></span>
|
|
</div>
|
|
<div class="flex items-center gap-1">
|
|
<button data-action="edit" 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"><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></button>
|
|
<button data-action="delete" 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"><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></button>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<template id="tpl-occupant-card">
|
|
<div class="bg-white dark:bg-gray-800 rounded-lg p-3 shadow-sm flex items-center justify-between hover:shadow-md transition-all duration-200">
|
|
<div>
|
|
<span class="font-medium" data-slot="count-activity"></span>
|
|
<span class="text-xs text-gray-400 ml-2" data-slot="details"></span>
|
|
</div>
|
|
<div class="flex items-center gap-1">
|
|
<button data-action="edit" 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"><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></button>
|
|
<button data-action="delete" 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"><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></button>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<template id="tpl-ac-card">
|
|
<div class="bg-white dark:bg-gray-800 rounded-lg p-3 shadow-sm flex items-center justify-between hover:shadow-md transition-all duration-200">
|
|
<div>
|
|
<span class="font-medium" data-slot="name"></span>
|
|
<span class="text-xs text-gray-400 ml-2" data-slot="details"></span>
|
|
</div>
|
|
<div class="flex items-center gap-1">
|
|
<button data-action="edit" 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"><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></button>
|
|
<button data-action="delete" 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"><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></button>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<template id="tpl-room-option">
|
|
<option></option>
|
|
</template>
|
|
|
|
<template id="tpl-ac-room-checkbox">
|
|
<label class="flex items-center gap-1 text-sm">
|
|
<input type="checkbox" class="rounded">
|
|
<span data-slot="name"></span>
|
|
</label>
|
|
</template>
|
|
|
|
<template id="tpl-toast">
|
|
<span data-slot="message"></span>
|
|
<button class="ml-2 text-white/80 hover:text-white text-lg leading-none" data-action="close">×</button>
|
|
</template>
|
|
</div>
|
|
{{end}}
|
|
|
|
{{define "scripts"}}
|
|
<script src="/assets/js/db.js"></script>
|
|
<script src="/assets/js/setup.js"></script>
|
|
{{end}}
|