feat(devices): reform Add Device modal with KOReader plugin instructions

- Add gear icon (proper cog) and use it for device settings button
- Replace KOReader manual identifier input with step-by-step plugin
  setup instructions (clone repo, enter server URL, approve pending reg)
- Show server URL with copy button pre-filled from baseURL
- Kobo keeps manual registration flow (device name + identifier)
- Comment out Web Browser and Mobile App options (not implemented)
- Use Alpine x-model on device-type select to toggle between
  KOReader instructions and Kobo registration form
This commit is contained in:
2026-08-06 14:48:48 -04:00
parent 6f1c13998c
commit e09c55cecc
5 changed files with 186 additions and 77 deletions
+76 -25
View File
@@ -63,9 +63,9 @@ templ Devices(user User, devices []handlers.DeviceInfo, pendingRegistrations []P
<button @click={ "showShelfMappings('" + device.ID.String() + "')" } class="icon-btn" title="Shelf mappings" aria-label="Shelf mappings">
@Icon("layers", "h-5 w-5")
</button>
<button @click={ "showDeviceSettings('" + device.ID.String() + "')" } class="icon-btn" title="Device settings" aria-label="Device settings">
@Icon("settings", "h-5 w-5")
</button>
<button @click={ "showDeviceSettings('" + device.ID.String() + "')" } class="icon-btn" title="Device settings" aria-label="Device settings">
@Icon("gear", "h-5 w-5")
</button>
</div>
</div>
<h3 class="text-lg font-semibold mb-1" style="color: var(--text-primary)">{ device.DeviceName }</h3>
@@ -190,14 +190,78 @@ templ Devices(user User, devices []handlers.DeviceInfo, pendingRegistrations []P
<div id="sync-queue" class="space-y-3"></div>
</div>
</div>
<div id="add-device-modal" class="hidden fixed inset-0 z-50 flex items-center justify-center p-4" style="background-color: var(--surface-overlay);">
<div class="card p-6 w-full max-w-md" style="box-shadow: var(--shadow-pop);">
<div class="flex justify-between items-center mb-6">
<h2 class="text-xl font-bold" style="color: var(--text-primary)">Add New Device</h2>
<button @click="hideAddDeviceModal()" class="icon-btn" aria-label="Close">
@Icon("close", "h-5 w-5")
</button>
<div id="add-device-modal" class="hidden fixed inset-0 z-50 flex items-center justify-center p-4" x-data="{ selectedType: '' }" style="background-color: var(--surface-overlay);">
<div class="card p-6 w-full max-w-md" style="box-shadow: var(--shadow-pop);">
<div class="flex justify-between items-center mb-6">
<h2 class="text-xl font-bold" style="color: var(--text-primary)">Add New Device</h2>
<button @click="hideAddDeviceModal()" class="icon-btn" aria-label="Close">
@Icon("close", "h-5 w-5")
</button>
</div>
<div class="mb-4">
<label class="block text-xs font-semibold uppercase tracking-wide mb-2" style="color: var(--text-secondary)">Device Type</label>
<select
id="device-type"
x-model="selectedType"
required
class="input"
>
<option value="">Select device type...</option>
<option value="koreader">KOReader (Kindle, Kobo, PocketBook)</option>
<option value="kobo">Kobo E-Reader</option>
<!-- <option value="web">Web Browser</option> -->
<!-- <option value="mobile">Mobile App</option> -->
</select>
</div>
<div x-show="selectedType === 'koreader'" x-cloak class="space-y-4">
<div class="rounded-lg p-4 space-y-4" style="background-color: var(--surface-secondary);">
<h3 class="text-sm font-semibold flex items-center gap-2" style="color: var(--text-primary)">
@Icon("book-open", "h-4 w-4")
KOReader Plugin Setup
</h3>
<ol class="space-y-3 text-sm" style="color: var(--text-secondary)">
<li class="flex gap-3">
<span class="flex-shrink-0 grid place-items-center h-5 w-5 rounded-full text-xs font-bold" style="background-color: var(--accent-muted); color: var(--accent);">1</span>
<span>Clone the <a href="https://git.linuxhg.com/Bookhoard/bookhoard.koplugin" class="underline" style="color: var(--accent);">Bookhoard plugin</a> to your KOReader <code class="px-1 py-0.5 rounded" style="background-color: var(--bg-primary);">plugins/</code> directory</span>
</li>
<li class="flex gap-3">
<span class="flex-shrink-0 grid place-items-center h-5 w-5 rounded-full text-xs font-bold" style="background-color: var(--accent-muted); color: var(--accent);">2</span>
<span>Open KOReader, tap the <strong>wrench icon</strong> at the top</span>
</li>
<li class="flex gap-3">
<span class="flex-shrink-0 grid place-items-center h-5 w-5 rounded-full text-xs font-bold" style="background-color: var(--accent-muted); color: var(--accent);">3</span>
<span>Find and tap <strong>Bookhoard sync</strong></span>
</li>
<li class="flex gap-3">
<span class="flex-shrink-0 grid place-items-center h-5 w-5 rounded-full text-xs font-bold" style="background-color: var(--accent-muted); color: var(--accent);">4</span>
<span>Tap <strong>Server URL</strong>, enter your server address, then tap <strong>OK</strong>:</span>
</li>
<li class="ml-8">
<div class="flex items-center gap-2">
<code class="text-xs px-2 py-1 rounded font-mono flex-1" style="background-color: var(--bg-primary); color: var(--text-primary);">{ baseURL }</code>
<button
@click={ "copyToClipboard('" + baseURL + "', 'Server URL')" }
class="btn btn-secondary text-xs px-3"
>
@Icon("copy", "h-4 w-4")
</button>
</div>
</li>
<li class="flex gap-3">
<span class="flex-shrink-0 grid place-items-center h-5 w-5 rounded-full text-xs font-bold" style="background-color: var(--accent-muted); color: var(--accent);">5</span>
<span>Return to this page and refresh you'll see a <strong>pending registration</strong>. Click <strong>Approve</strong> to connect the device.</span>
</li>
</ol>
<div class="rounded-md p-3 text-xs flex items-start gap-2" style="background-color: var(--accent-muted); color: var(--text-secondary);">
@Icon("info", "h-4 w-4 flex-shrink-0 mt-0.5")
<span>Once approved, reading progress sync and OPDS catalog access are set up automatically.</span>
</div>
</div>
<div class="flex justify-end">
<button type="button" @click="hideAddDeviceModal()" class="btn btn-primary">Got it</button>
</div>
</div>
<div x-show="selectedType === 'kobo'" x-cloak>
<form id="add-device-form" @submit="handleAddDevice($event)">
<div class="mb-4">
<label class="block text-xs font-semibold uppercase tracking-wide mb-2" style="color: var(--text-secondary)">Device Name</label>
@@ -206,23 +270,9 @@ templ Devices(user User, devices []handlers.DeviceInfo, pendingRegistrations []P
id="device-name"
required
class="input"
placeholder="My Kindle Paperwhite"
placeholder="My Kobo"
/>
</div>
<div class="mb-4">
<label class="block text-xs font-semibold uppercase tracking-wide mb-2" style="color: var(--text-secondary)">Device Type</label>
<select
id="device-type"
required
class="input"
>
<option value="">Select device type...</option>
<option value="koreader">KOReader (Kindle, Kobo, PocketBook)</option>
<option value="kobo">Kobo E-Reader</option>
<option value="web">Web Browser</option>
<option value="mobile">Mobile App</option>
</select>
</div>
<div class="mb-6">
<label class="block text-xs font-semibold uppercase tracking-wide mb-2" style="color: var(--text-secondary)">Device Identifier</label>
<input
@@ -241,6 +291,7 @@ templ Devices(user User, devices []handlers.DeviceInfo, pendingRegistrations []P
</form>
</div>
</div>
</div>
<div id="device-settings-modal" class="hidden fixed inset-0 z-50 flex items-center justify-center p-4" style="background-color: var(--surface-overlay);">
<div class="card p-6 w-full max-w-md" style="box-shadow: var(--shadow-pop);">
<div class="flex justify-between items-center mb-6">