From 08d45617a76a03c0203747b08647fd3de71b5678 Mon Sep 17 00:00:00 2001 From: John O'Keefe Date: Sun, 8 Mar 2026 21:36:02 -0400 Subject: [PATCH] refactor: Convert template event handlers to Alpine.js Converted all inline onclick/onsubmit handlers to Alpine.js @click/@submit directives and added x-data attributes to template body tags. Templates updated: - admin.templ: Added x-data="admin", converted scan/hide buttons - analytics.templ: Added x-data, converted loadAnalytics button - api_explorer.templ: Added x-data for API explorer page - bookshelf.templ: Added x-data, converted library/pagination handlers - collection_modal.templ: Added x-data for modal components - collection_rules.templ: Added x-data, converted all rule handlers - collections.templ: Added x-data, converted navigation/book handlers - conflicts.templ: Added x-data, converted resolve/dismiss handlers - header.templ: Converted theme dropdown and user menu handlers - index.templ: Added x-data for theme/auth - login.templ: Added x-data for theme switching - profile.templ: Added x-data, converted delete account - profile_form.templ: Converted modal close handler - profile_modal.templ: Added x-data for modal - progress.templ: Removed script (uses header.logout) - queue.templ: Added x-data, converted queue handlers - register.templ: Added x-data for theme - restore_system_collection_modal.templ: Added x-data - toast.templ: Converted to x-init with Alpine - unlinked_books.templ: Added x-data for bulk operations Dynamic content in devices.templ uses event delegation via data attributes. --- templates/admin.templ | 237 +++--- templates/analytics.templ | 191 +++-- templates/api_explorer.templ | 122 +--- templates/bookshelf.templ | 318 ++------ templates/collection_modal.templ | 28 +- templates/collection_rules.templ | 610 +++++----------- templates/collections.templ | 20 +- templates/conflicts.templ | 472 ++++++------ templates/header.templ | 374 +++++----- templates/index.templ | 280 +++---- templates/login.templ | 140 ++-- templates/profile.templ | 87 +-- templates/profile_form.templ | 2 +- templates/profile_modal.templ | 20 +- templates/progress.templ | 204 +++--- templates/queue.templ | 37 +- templates/register.templ | 168 ++--- .../restore_system_collection_modal.templ | 6 +- templates/toast.templ | 29 +- templates/unlinked_books.templ | 689 +++++------------- 20 files changed, 1523 insertions(+), 2511 deletions(-) diff --git a/templates/admin.templ b/templates/admin.templ index 6687ade..6e1a46f 100644 --- a/templates/admin.templ +++ b/templates/admin.templ @@ -1,125 +1,120 @@ package templates templ Admin(user User) { - - - - - Admin Dashboard - Bookhoard - - - - - - - @Header(user, "/admin") + + + + + Admin Dashboard - Bookhoard + + + + + + @Header(user, "/admin") +
+ @AdminSidebar(user, "/admin") +
+
+
+

Dashboard

+

Overview of your Bookhoard library and settings

+
+
+
+
+
๐Ÿ“–
+
+

Library

+

Manage your ebook collection

+
+
+ View Library +
+
+
+
๐Ÿ‘๏ธ
+
+

Scan Watch Status

+

Auto-detecting new files

+
+
+
+ + Watching 0 libraries +
+
+
+
+

Quick Actions

+
+ + +
Manage Folders
+
Add or remove scan directories
+
+
+
+ + +
+
+
+ + +} -
- @AdminSidebar(user, "/admin") -
-
-
-

Dashboard

-

Overview of your Bookhoard library and settings

-
- -
-
-
-
๐Ÿ“–
-
-

Library

-

Manage your ebook collection

-
-
- View Library -
- -
-
-
๐Ÿ‘๏ธ
-
-

Scan Watch Status

-

Auto-detecting new files

-
-
-
- - Watching 0 libraries -
-
- - -
- -
-

Quick Actions

-
- - -
Manage Folders
-
Add or remove scan directories
-
-
-
- - - -
-
-
- - -} \ No newline at end of file diff --git a/templates/analytics.templ b/templates/analytics.templ index 56c40e6..a0374cb 100644 --- a/templates/analytics.templ +++ b/templates/analytics.templ @@ -1,100 +1,99 @@ package templates templ Analytics(user User) { - - - - - - Reading Analytics - Bookhoard - - - - - - - - @Header(user, "/analytics") - -
-
-

๐Ÿ“Š Reading Analytics

-

Track your reading habits and device usage

-
- - -
-
-
- - -
-
- - -
-
- -
-
-
- - -
-
-

Books Read

-

-

-
-
-

Pages Read

-

-

-
-
-

Reading Time

-

-

-
-
-

Completion Rate

-

-

-
-
- - -
- -
-

Daily Reading Minutes

-
- -
-
- - -
-

Device Usage

-
- -
-
-
- - -
-

Most Read Books

- -
-
- - - - + + + + + + Reading Analytics - Bookhoard + + + + + + @Header(user, "/analytics") +
+
+

๐Ÿ“Š Reading Analytics

+

Track your reading habits and device usage

+
+ +
+
+
+ + +
+
+ + +
+
+ +
+
+
+ +
+
+

Books Read

+

-

+
+
+

Pages Read

+

-

+
+
+

Reading Time

+

-

+
+
+

Completion Rate

+

-

+
+
+ +
+ +
+

Daily Reading Minutes

+
+ +
+
+ +
+

Device Usage

+
+ +
+
+
+ +
+

Most Read Books

+ +
+
+ + + } diff --git a/templates/api_explorer.templ b/templates/api_explorer.templ index f2b8973..8468bd2 100644 --- a/templates/api_explorer.templ +++ b/templates/api_explorer.templ @@ -25,16 +25,16 @@ templ APIExplorer(explorer APIExplorerData) {
{ explorer.Endpoint.Response }
- - + @click="copyToClipboard(JSON.stringify({ explorer.Endpoint.RequestBody }, null, 2))" class="px-4 py-2 border border-border rounded bg-background-primary text-text-primary hover:bg-background-secondary cursor-pointer text-sm">Copy Request + @click="copyToClipboard(JSON.stringify({ explorer.Endpoint.Response }, null, 2))" class="px-4 py-2 border border-border rounded bg-background-primary text-text-primary hover:bg-background-secondary cursor-pointer text-sm">Copy Response
} else { // Show interactive explorer with real execution -
+
- - + +
@@ -48,7 +48,7 @@ templ APIExplorer(explorer APIExplorerData) {

Request Body

- + } - - } // APIExplorerData holds data for the API explorer component diff --git a/templates/bookshelf.templ b/templates/bookshelf.templ index 9c280b6..daddec7 100644 --- a/templates/bookshelf.templ +++ b/templates/bookshelf.templ @@ -1,266 +1,60 @@ package templates templ BookShelf(user User, libraries []LibraryData) { - - - - - - Library - Bookhoard - - - - - - - @Header(user, "/bookshelf") -
- -
-
-
- - -
-
- -
-
-
- - -
- -
-
-

Loading your library...

-
- - - - - - -
-
- - - - - + + + + + + Library - Bookhoard + + + + + + @Header(user, "/bookshelf") +
+ +
+
+
+ + +
+
+ +
+
+
+ +
+ +
+
+

Loading your library...

+
+ + + + +
+
+ + } diff --git a/templates/collection_modal.templ b/templates/collection_modal.templ index f52a3fb..9cac027 100644 --- a/templates/collection_modal.templ +++ b/templates/collection_modal.templ @@ -1,7 +1,7 @@ package templates templ CollectionModal(collection CollectionData) { -
+
if collection.ID != "" { @@ -9,7 +9,7 @@ templ CollectionModal(collection CollectionData) { } else {

Create Collection

} - +
if collection.ID != "" {
- - - - - + + + + +
- +
@@ -132,16 +132,16 @@ templ CollectionModal(collection CollectionData) {
- - - - - + + + + +
- +
diff --git a/templates/collection_rules.templ b/templates/collection_rules.templ index d6444a7..eb99e59 100644 --- a/templates/collection_rules.templ +++ b/templates/collection_rules.templ @@ -1,420 +1,198 @@ package templates templ CollectionRules(user User, collection CollectionData) { - - - - - - Collection Rules - { collection.Name } - Bookhoard - - - - - - @Header(user, "/collections") - -
-
- -
-
{ collection.Icon }
-
-

{ collection.Name }

-

Auto-Assign Rules

-
-
-
- -
-

Existing Rules

-
-
-
๐Ÿ“‹
-

No Rules Yet

-

Create auto-assign rules to automatically add books to this collection

-
-
-
- -
-

Create New Rule

-
- - -
-
- - -
- -
- - -
-
- -
- - -
- -
- -

Uncheck to disable without deleting

-
- -
- -
- - - -
-
- -
- - - -
-
- - -
- -
-

Rule Examples

-
-
-
1
-
-

Add all Science Fiction books

- - Field: genre
- Operator: equals
- Value: Science Fiction -
-
-
-
-
2
-
-

Add books from a specific series

- - Field: series
- Operator: starts with
- Value: Harry Potter -
-
-
-
-
3
-
-

Add books published in a year range

- - Field: copyright_year
- Operator: greater than
- Value: 2020 -
-
-
-
-
-
- - - - + + + + + + Collection Rules - { collection.Name } - Bookhoard + + + + + + @Header(user, "/collections") +
+
+ +
+
{ collection.Icon }
+
+

{ collection.Name }

+

Auto-Assign Rules

+
+
+
+
+

Existing Rules

+
+
+
๐Ÿ“‹
+

No Rules Yet

+

Create auto-assign rules to automatically add books to this collection

+
+
+
+
+

Create New Rule

+
+ +
+
+ + +
+
+ + +
+
+
+ + +
+
+ +

Uncheck to disable without deleting

+
+
+ +
+ + + +
+
+
+ + + +
+
+ +
+
+

Rule Examples

+
+
+
1
+
+

Add all Science Fiction books

+ + Field: genre +
+ Operator: equals +
+ Value: Science Fiction +
+
+
+
+
2
+
+

Add books from a specific series

+ + Field: series +
+ Operator: starts with +
+ Value: Harry Potter +
+
+
+
+
3
+
+

Add books published in a year range

+ + Field: copyright_year +
+ Operator: greater than +
+ Value: 2020 +
+
+
+
+
+
+ + } diff --git a/templates/collections.templ b/templates/collections.templ index d94730f..acb8c45 100644 --- a/templates/collections.templ +++ b/templates/collections.templ @@ -13,7 +13,7 @@ templ Collection(user User, collections []CollectionData, errorMessage string) { - + @Header(user, "/collections") @@ -60,7 +60,7 @@ templ Collection(user User, collections []CollectionData, errorMessage string) {
} for _, col := range collections { -
+
- + @Header(user, "/collections")
-
@@ -147,13 +147,13 @@ templ CollectionDetail(user User, collection CollectionData, books []handlers.Bo
-
@@ -213,7 +213,7 @@ templ CollectionDetail(user User, collection CollectionData, books []handlers.Bo
+

Search and select books to add to this collection.

@@ -249,10 +249,10 @@ templ CollectionDetail(user User, collection CollectionData, books []handlers.Bo
- -
diff --git a/templates/conflicts.templ b/templates/conflicts.templ index 0088d3f..4ac1d07 100644 --- a/templates/conflicts.templ +++ b/templates/conflicts.templ @@ -3,237 +3,243 @@ package templates import "bookhoard/internal/handlers" templ Conflicts(user User, conflicts []handlers.ConflictDetailResponse, total int, unresolved int, errorMessage string) { - - - - - - Sync Conflicts - Bookhoard - - - - - - - @Header(user, "/conflicts") - -
-
-
-
-

Sync Conflicts

-

Resolve conflicts when reading progress differs across devices

-
-
- - -
-
- -
- Total: { total } - Unresolved: { unresolved } - Resolved: { total - unresolved } -
- - -
- - - - - -
- - - if len(conflicts) == 0 { -
-
โœ…
-

No Conflicts

-

Your devices are in sync! No conflicts to resolve.

-
- } - - for _, conflict := range conflicts { -
-
-
- -
-

{ conflict.MediaItemTitle }

-

Type: { conflict.ConflictType }

-
-
- -
-
- Created: { conflict.CreatedAt.Format("2006-01-02 15:04:05") } - if conflict.ResolvedBy != "" { - | Resolved by: { conflict.ResolvedBy } - } -
-
- } -
- - -
- - - - @ErrorToast(errorMessage) - - + + + + + + Sync Conflicts - Bookhoard + + + + + + @Header(user, "/conflicts") +
+
+
+
+

Sync Conflicts

+

Resolve conflicts when reading progress differs across devices

+
+
+ + +
+
+
+ Total: { total } + Unresolved: { unresolved } + Resolved: { total - unresolved } +
+ +
+ + +
+ + if len(conflicts) == 0 { +
+
โœ…
+

No Conflicts

+

Your devices are in sync! No conflicts to resolve.

+
+ } + for _, conflict := range conflicts { +
+
+
+ +
+

{ conflict.MediaItemTitle }

+

Type: { conflict.ConflictType }

+
+
+ +
+
+ Created: { conflict.CreatedAt.Format("2006-01-02 15:04:05") } + if conflict.ResolvedBy != "" { + | Resolved by: { conflict.ResolvedBy } + } +
+
+ } +
+ +
+ + @ErrorToast(errorMessage) + + } diff --git a/templates/header.templ b/templates/header.templ index 2af9167..a90d485 100644 --- a/templates/header.templ +++ b/templates/header.templ @@ -2,187 +2,199 @@ package templates templ Header(user User, currentPath string) { - - - - + if user.Role == "admin" { + + Admin Panel + + } +
+ +
+
+ } else { + + + + } +
+
+
+
+ + + + + } diff --git a/templates/index.templ b/templates/index.templ index f0ef6e1..e0c3a6c 100644 --- a/templates/index.templ +++ b/templates/index.templ @@ -1,165 +1,123 @@ package templates templ Index(loggedIn bool) { - - - - - - Bookhoard - Home - - - - - - - -
-
-
-
-
- -
+ + + + + + Bookhoard - Home + + + + + + +
+
+
+
+
+ +
+
+

+ ๐Ÿ“š Bookhoard +

+

+ Your personal ebook management system. Track reading progress, organize your library, and enjoy beautiful themes. +

+ +
+
+
+ +
+
+
+

Why Bookhoard?

+

Discover the features that make ebook management effortless

+
+
+
+
+
+ ๐Ÿ“– +
+

Reading Progress

+

Track your reading progress across all your ebooks with detailed statistics.

+
+
+
+
+
+ ๐ŸŽจ +
+

Beautiful Themes

+

Choose from 11 stunning themes including Tokyo Night, Dracula, and Catppuccin variants.

+
+
+
+
+
+ โšก +
+

Fast & Modern

+

Built with Go and HTMX for lightning-fast performance and smooth interactions.

+
+
+
+
+
+ + if !loggedIn { +
+
+
+

Join Bookhoard Today

+

Sign in to start managing your ebook library

+
+
+
+

Login

+
+
+
+ + +
+
+ + +
+ +
+
+
+
+
+
+
+ } + + +} -
-

- ๐Ÿ“š Bookhoard -

-

- Your personal ebook management system. Track reading progress, organize your library, and enjoy beautiful themes. -

- -
-
-
- - -
-
-
-

Why Bookhoard?

-

Discover the features that make ebook management effortless

-
- -
-
-
-
- ๐Ÿ“– -
-

Reading Progress

-

Track your reading progress across all your ebooks with detailed statistics.

-
-
- -
-
-
- ๐ŸŽจ -
-

Beautiful Themes

-

Choose from 11 stunning themes including Tokyo Night, Dracula, and Catppuccin variants.

-
-
- -
-
-
- โšก -
-

Fast & Modern

-

Built with Go and HTMX for lightning-fast performance and smooth interactions.

-
-
-
-
-
- - - if !loggedIn { -
-
-
-

Join Bookhoard Today

-

Sign in to start managing your ebook library

-
- -
-
-

Login

-
-
-
- - -
-
- - -
- -
-
-
-
- -
-
-
- } - - - - - -} \ No newline at end of file diff --git a/templates/login.templ b/templates/login.templ index 21ecdea..39f169e 100644 --- a/templates/login.templ +++ b/templates/login.templ @@ -1,81 +1,67 @@ package templates templ Login(sessionExpired bool, deleted bool) { - - - - - - Login - - - - - - - -
-
-

Login to Bookhoard

- -
+ + + + + + Login + + + + + +
+
+

Login to Bookhoard

+ +
+ if sessionExpired { +
+

+ Your session has expired. Please log in again to continue. +

+
+ } + if deleted { +
+

+ Your account has been deleted successfully. +

+
+ } +
+
+ + +
+
+ + +
+ +
+
+

+ Don't have an account? Sign Up +

+
+ + +} - if sessionExpired { -
-

- Your session has expired. Please log in again to continue. -

-
- } - - if deleted { -
-

- Your account has been deleted successfully. -

-
- } - -
-
- - -
-
- - -
- -
- -
- -

- Don't have an account? Sign Up -

-
- - -} \ No newline at end of file diff --git a/templates/profile.templ b/templates/profile.templ index 36353ee..081daec 100644 --- a/templates/profile.templ +++ b/templates/profile.templ @@ -3,66 +3,35 @@ package templates templ Profile(user User) { - - - Profile Settings - Bookhoard - - - - - - - @Header(user, "/profile") - -
-
-

Profile Settings

-

Manage your account information and preferences

-
- -
- -
- @ProfileForm(user, "/api/auth/profile", true, false, false) + + + Profile Settings - Bookhoard + + + + + + @Header(user, "/profile") +
+
+

Profile Settings

+

Manage your account information and preferences

- - -
-

Danger Zone

-

Once you delete your account, there is no going back. Please be certain.

- - +
+ +
+ @ProfileForm(user, "/api/auth/profile", true, false, false) +
+ +
+

Danger Zone

+

Once you delete your account, there is no going back. Please be certain.

+ +
-
-
- - - +
+ } diff --git a/templates/profile_form.templ b/templates/profile_form.templ index 2f66231..edd7c87 100644 --- a/templates/profile_form.templ +++ b/templates/profile_form.templ @@ -154,7 +154,7 @@ templ ProfileForm(user User, actionURL string, requireCurrentPassword bool, show
if showCancelButton {
- - } diff --git a/templates/progress.templ b/templates/progress.templ index 8da2131..1833d77 100644 --- a/templates/progress.templ +++ b/templates/progress.templ @@ -3,112 +3,100 @@ package templates import "bookhoard/internal/handlers" templ Progress(user User, progressData []handlers.ProgressWithMedia, errorMessage string) { - - - - - - Reading Progress - Bookhoard - - - - - - @Header(user, "/progress") - -
-
-

Reading Progress

-

Track your reading progress across all devices

-
- -
- if len(progressData) == 0 { -
-
๐Ÿ“–
-

No Progress Yet

-

Start reading a book to track your progress

-
- } - - for _, item := range progressData { -
-
-
- Cover -
-
-
-
-

{ item.Title }

- if item.Author != "" { -

by { item.Author }

- } -
-
- { item.ProgressPercentage }% -
-
- -
-
-
-
-
- -
-
-

Current Position

-

- { item.CurrentPage } / { item.TotalPages } -

-
-
-

Last Updated

-

{ item.LastUpdated }

-
-
-

Synced From

-
- { item.DeviceIcon } - { item.DeviceName } -
-
-
- - if item.DeviceIcon != "" { -
-
- ๐Ÿ”„ - Last sync from { item.DeviceName } - ({ item.DeviceType }) -
-
- } - - if item.EpubCFI != "" { -
- ๐Ÿ“ - CFI: { item.EpubCFI } -
- } -
-
-
- } -
-
- - - - @ErrorToast(errorMessage) - - + + + + + + Reading Progress - Bookhoard + + + + + + @Header(user, "/progress") +
+
+

Reading Progress

+

Track your reading progress across all devices

+
+
+ if len(progressData) == 0 { +
+
๐Ÿ“–
+

No Progress Yet

+

Start reading a book to track your progress

+
+ } + for _, item := range progressData { +
+
+
+ Cover +
+
+
+
+

{ item.Title }

+ if item.Author != "" { +

by { item.Author }

+ } +
+
+ { item.ProgressPercentage }% +
+
+
+
+
+
+
+
+
+

Current Position

+

+ { item.CurrentPage } / { item.TotalPages } +

+
+
+

Last Updated

+

{ item.LastUpdated }

+
+
+

Synced From

+
+ { item.DeviceIcon } + { item.DeviceName } +
+
+
+ if item.DeviceIcon != "" { +
+
+ ๐Ÿ”„ + Last sync from { item.DeviceName } + ({ item.DeviceType }) +
+
+ } + if item.EpubCFI != "" { +
+ ๐Ÿ“ + CFI: { item.EpubCFI } +
+ } +
+
+
+ } +
+
+ @ErrorToast(errorMessage) + + } diff --git a/templates/queue.templ b/templates/queue.templ index 6c4ae2c..ce0a98f 100644 --- a/templates/queue.templ +++ b/templates/queue.templ @@ -10,11 +10,10 @@ templ Queue(user User, queueItems []handlers.QueueItemResponse, stats handlers.Q Sync Queue - Bookhoard - + - - + @Header(user, "/queue")
@@ -24,13 +23,13 @@ templ Queue(user User, queueItems []handlers.QueueItemResponse, stats handlers.Q

Monitor and manage offline sync queue

- - -
@@ -98,7 +97,7 @@ templ Queue(user User, queueItems []handlers.QueueItemResponse, stats handlers.Q
- @@ -120,15 +119,15 @@ templ Queue(user User, queueItems []handlers.QueueItemResponse, stats handlers.Q

No items in the sync queue

} - for _, item := range queueItems { -
-
-
- { item.Status } - { item.SyncType } -
- P{ item.Priority } -
+ for _, item := range queueItems { +
+
+
+ { item.Status } + { item.SyncType } +
+ P{ item.Priority } +
Device ID: { item.DeviceID } if item.MediaTitle != nil { @@ -151,14 +150,14 @@ templ Queue(user User, queueItems []handlers.QueueItemResponse, stats handlers.Q

Queue Item Details

-
- - + +
diff --git a/templates/register.templ b/templates/register.templ index 9c6e473..5cc5394 100644 --- a/templates/register.templ +++ b/templates/register.templ @@ -1,97 +1,77 @@ package templates templ Register() { - - - - - - Register - - - - - - - -
-

Register for Bookhoard

- -
-
- - -
-
- - -
-
- - -
-
- - -
-
-

Password Requirements:

-
    -
  • - โ—‹ At least 8 characters -
  • -
  • - โ—‹ One uppercase letter -
  • -
  • - โ—‹ One lowercase letter -
  • -
  • - โ—‹ One number -
  • -
  • - โ—‹ One special character -
  • -
  • - โ—‹ Passwords match -
  • -
-
-
- - -
-
- - -
- -
- -
- -

- Already have an account? Login -

-
- - - - -} \ No newline at end of file + + + + + + Register + + + + + +
+

Register for Bookhoard

+
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+

Password Requirements:

+
    +
  • + โ—‹ At least 8 characters +
  • +
  • + โ—‹ One uppercase letter +
  • +
  • + โ—‹ One lowercase letter +
  • +
  • + โ—‹ One number +
  • +
  • + โ—‹ One special character +
  • +
  • + โ—‹ Passwords match +
  • +
+
+
+ + +
+
+ + +
+ +
+
+

+ Already have an account? Login +

+
+ + +} + diff --git a/templates/restore_system_collection_modal.templ b/templates/restore_system_collection_modal.templ index 97441b2..32810fb 100644 --- a/templates/restore_system_collection_modal.templ +++ b/templates/restore_system_collection_modal.templ @@ -1,11 +1,11 @@ package templates templ RestoreSystemCollectionModal() { -
+

Restore System Collection

- +

Select a system collection to restore:

@@ -21,7 +21,7 @@ templ RestoreSystemCollectionModal() {
- +
diff --git a/templates/toast.templ b/templates/toast.templ index 8873822..72af531 100644 --- a/templates/toast.templ +++ b/templates/toast.templ @@ -2,33 +2,6 @@ package templates templ ErrorToast(message string) { if message != "" { - +
} } diff --git a/templates/unlinked_books.templ b/templates/unlinked_books.templ index 45109c7..bc6d59f 100644 --- a/templates/unlinked_books.templ +++ b/templates/unlinked_books.templ @@ -1,501 +1,196 @@ package templates templ UnlinkedBooks(user User, unlinkedBooks []UnlinkedBookData) { - - - - - - Unlinked Books - Bookhoard - - - - - - @Header(user, "/unlinked") - -
-
-

Unlinked Books

-

Resolve books that couldn't be automatically matched between devices

-
- - if len(unlinkedBooks) > 0 { -
-
- - - 0 selected -
-
- - - -
-
- } - -
- if len(unlinkedBooks) == 0 { -
-
โœ“
-

All Books Linked!

-

There are no unlinked books that need manual resolution.

-
- } - - for _, book := range unlinkedBooks { -
-
-
- -
-
-
-
- if book.DeviceType == "koreader" { - ๐Ÿ“– - } else if book.DeviceType == "kobo" { - ๐Ÿ“š - } else { - ๐Ÿ“ฑ - } -
-
-

{ book.TitleFromDevice }

-

- Device: { book.DeviceName } ({ book.DeviceType }) -

-
-
- -
-
- File Path: - - { book.FilePath } - -
- if book.SHA256 != "" { -
- SHA-256: - - { book.SHA256 } - -
- } -
- Last Synced: - { book.LastSyncTime } -
- if book.ConfidenceScore > 0 { -
- Auto-Link Confidence: - - { book.ConfidenceScore }% confidence - -
- } -
- -
- - -
- - -
-
-
- } -
-
- - - - - - - + + + + + + Unlinked Books - Bookhoard + + + + + + @Header(user, "/unlinked") +
+
+

Unlinked Books

+

Resolve books that couldn't be automatically matched between devices

+
+ if len(unlinkedBooks) > 0 { +
+
+ + + 0 selected +
+
+ + + +
+
+ } +
+ if len(unlinkedBooks) == 0 { +
+
โœ“
+

All Books Linked!

+

There are no unlinked books that need manual resolution.

+
+ } + for _, book := range unlinkedBooks { +
+
+
+ +
+
+
+
+ if book.DeviceType == "koreader" { + ๐Ÿ“– + } else if book.DeviceType == "kobo" { + ๐Ÿ“š + } else { + ๐Ÿ“ฑ + } +
+
+

{ book.TitleFromDevice }

+

+ Device: { book.DeviceName } ({ book.DeviceType }) +

+
+
+
+
+ File Path: + + { book.FilePath } + +
+ if book.SHA256 != "" { +
+ SHA-256: + + { book.SHA256 } + +
+ } +
+ Last Synced: + { book.LastSyncTime } +
+ if book.ConfidenceScore > 0 { +
+ Auto-Link Confidence: + + { book.ConfidenceScore }% confidence + +
+ } +
+
+ + +
+ +
+
+
+ } +
+
+ + + + }