Refactor: Eliminate duplicate types - Use handler types directly

- Deleted templates.CollectionDetailData - using templates.CollectionData everywhere
- Deleted templates.BookData - using handlers.BookInfo everywhere
- Deleted templates.DeviceData - using handlers.DeviceInfo everywhere
- Deleted templates.ProgressItemData - using handlers.ProgressWithMedia everywhere
- Deleted templates.convertDevices() helper - Use handlers types directly in templates
- Enhanced handlers.ProgressWithMedia with device metadata fields
- Added handlers.getDeviceIcon() helper
- Updated all templates to import handlers package
- Cleaned up unused imports

This aligns codebase with templ's design philosophy (use Go types directly, no parallel type system)
This commit is contained in:
2026-02-12 19:48:07 -05:00
parent b5745e1554
commit 2a64ca423f
15 changed files with 639 additions and 168 deletions
+41 -17
View File
@@ -42,6 +42,7 @@
- `internal/router/device.go` - Add regenerate token route
- `internal/handlers/devices.go` - Add regenerate token handler
- `templates/devices.templ` - Add copy/regenerate UI
- `web/src/device-management.ts` - Add device management TypeScript
- `bruno/sync-kobo/api.bru` - Add URL path token requests
- `bruno/devices/regenerate-*.bru` - New token regeneration test files
- `bruno/opds/*-*.bru` - New OPDS authentication test files
@@ -86,14 +87,6 @@ SET
updated_at = NOW()
WHERE id = $1
RETURNING *;
-- name: RevokeDevice :exec
UPDATE devices
SET
auth_token = NULL,
sync_enabled = false,
updated_at = NOW()
WHERE id = $1;
```
**Verification**: Run `go build ./...` after adding this query to ensure sqlc generates the new function correctly.
@@ -504,11 +497,7 @@ func (h *DeviceHandler) RegenerateDeviceToken(c echo.Context) error {
3. Add "Regenerate Token" button for each device
4. Add JavaScript functions for copy and regenerate
#### 1.6.1 Update DeviceData Struct
**Location**: Find `DeviceData` struct (near top of file)
**Current struct** (lines vary, find structure):
**ADD FIELD** to struct:
```go
type DeviceData struct {
@@ -522,6 +511,31 @@ type DeviceData struct {
SyncFrequency int
CreatedAt string
DeviceMetadata json.RawMessage
AuthToken string // NEW: Device API key for authentication
}
```
#### 1.6.3 Update Collection Detail Template
**File**: `templates/collection.templ`
**Location**: Line 213 (function signature)
**Current**:
```templ
templ CollectionDetail(user User, collection CollectionDetailData, books []BookData) {
```
**CHANGE** (use handlers.BookInfo):
```templ
templ CollectionDetail(user User, collection CollectionData, books []handlers.BookInfo) {
```
**ADD FIELD** to struct:
```go
AuthToken string // NEW: Device API key for authentication
}
```
@@ -872,7 +886,7 @@ put {
docs {
## Regenerate Device Token
Regenerates the auth token for a device, invalidating the old token immediately.
Regenerates auth token for a device, invalidating old token immediately.
**Method:** PUT
@@ -899,7 +913,7 @@ docs {
**Important Notes:**
- Old token stops working immediately
- Device must be updated with new token to resume syncing
- No data loss - device ID remains the same
- No data loss - device ID remains same
**Example Response:**
```json
@@ -911,14 +925,24 @@ docs {
"device_name": "My Kobo Clara",
"device_type": "kobo",
"sync_enabled": true,
"auto_sync": true
"auto_sync": true,
"sync_frequency_minutes": 5,
"created_at": "2026-02-12T10:00:00Z",
"device_metadata": "{...}"
},
"sync_urls": {
"sync_url": "http://localhost:8765/api/sync/kobo/dev_new_token",
"markup": "http://localhost:8765/api/sync/kobo/dev_new_token/markup"
"markup": "http://localhost:8765/api/sync/kobo/dev_new_token/markup",
"bookmark": "http://localhost:8765/api/sync/kobo/dev_new_token/bookmark",
"init": "http://localhost:8765/api/sync/kobo/dev_new_token/v1/initialization"
}
}
```
**Important Notes:**
- Old token stops working immediately
- Device must be updated with new token to resume syncing
- No data loss - device ID remains same
}
```
+474
View File
@@ -0,0 +1,474 @@
# Type Duplication Refactoring Plan
**Document Purpose**: Consolidate duplicate type definitions across templates/ and handlers/ packages to align with templ's design philosophy and reduce maintenance burden.
**Status**: Planning Phase
**Last Updated**: 2026-02-12
**Separation from**: IMPLEMENTATION_EXACT.md (this is independent refactoring)
**Core Principle**: **API wins** - When there's ambiguity between template types and API/handler types, the API/handler types take precedence.
---
## Executive Summary
**Problem**: Codebase maintains parallel type systems:
- `templates/types.go` - Template-specific types
- `handlers/*.go` - API response types
**Core Principle**: **API wins - when in doubt, API/handler types take precedence**
### Why "API wins"?
1. **API is public contract**: Handler types define your public API surface - these are more stable
2. **Templates are presentation**: HTML templates can format any Go type - they're flexible
3. **Single source of truth**: One authoritative type definition vs two parallel definitions
4. **Json serialization**: Handler types already have `json:"..."` tags for API responses
5. **Future API clients**: If you add mobile apps or CLI tools, they need handler types anyway
### Trade-offs
**Pro**: Simpler codebase, one type to maintain, automatic API/HTML consistency
**Con**: Templates may have unused fields visible in scope (acceptable - templ handles this well)
**Impact**:
- ~40 lines of duplicate type definitions
- Unnecessary conversion functions
- Maintenance burden (update 2 places for 1 change)
- Violates templ's design philosophy
**Solution**: Use handler types directly in templates, eliminate template-specific duplicates.
---
## Current State Analysis
### Duplicates Found
| Template Type | Handler Type | Overlap | Action |
|---------------|---------------|----------|--------|
| `DeviceData` | `DeviceInfo` | 90% | **DELETE** DeviceData |
| `BookData` | `collections.BookInfo` | 100% | **DELETE** BookData |
| `CollectionDetailData` | `CollectionData` | 100% | **DELETE** CollectionDetailData |
| `ProgressItemData` | `ProgressWithMedia` | 70% | **MERGE** (different fields) |
| `QueueItemData` | `QueueItemResponse` | 60% | **KEEP** (template uses subset) |
### Already Using Handler Types (Good Patterns)
`Conflicts` template uses `handlers.ConflictDetailResponse`
`Queue` template uses `handlers.QueueItemResponse`
**This is the pattern we want everywhere.**
---
## Refactoring Plan
### Phase 1: Eliminate Complete Duplicates
#### 1.1 Delete CollectionDetailData
**Files to Modify**:
- `templates/types.go` (lines 26-32) - DELETE struct
- `templates/collection_rules.templ` (line 3) - Change signature
- `templates/collections.templ` (line 213) - Change signature
**Changes**:
**Delete** from `templates/types.go`:
```go
type CollectionDetailData struct {
ID string
Name string
Description string
Color string
Icon string
}
```
**Update** `templates/collection_rules.templ:3`:
```templ
// BEFORE:
templ CollectionRules(user User, collection CollectionDetailData) {
// AFTER:
templ CollectionRules(user User, collection templates.CollectionData) {
```
**Update** `templates/collections.templ:213`:
```templ
// BEFORE:
templ CollectionDetail(user User, collection CollectionDetailData, books []BookData) {
// AFTER:
templ CollectionDetail(user User, collection templates.CollectionData, books []collections.BookInfo) {
```
**Test**: `go test ./templates/...` after template regeneration
---
#### 1.2 Delete BookData
**Files to Modify**:
- `templates/types.go` (lines 34-39) - DELETE struct
- `templates/collections.templ` (line 213) - Change books param
**Changes**:
**Delete** from `templates/types.go`:
```go
type BookData struct {
MediaItemID string
Title string
Author string
CoverImagePath string
}
```
**Update** `templates/collections.templ:213`:
```templ
// BEFORE:
templ CollectionDetail(user User, collection templates.CollectionData, books []BookData) {
// AFTER:
templ CollectionDetail(user User, collection templates.CollectionData, books []collections.BookInfo) {
```
**Test**: View collection detail page, verify books display correctly
---
#### 1.3 Delete DeviceData and ConvertDevices
**Files to Modify**:
- `templates/types.go` (lines 48-57) - DELETE struct
- `templates/devices.templ` (line 3) - Change signature
- `internal/router/helpers.go` (lines 46-67) - DELETE function
- `internal/router/frontend.go` (lines 161-169) - Remove conversion
**Changes**:
**Delete** from `templates/types.go`:
```go
type DeviceData struct {
ID string
DeviceName string
DeviceType string
SyncEnabled bool
AutoSync bool
SyncFrequency int32
LastSync string
LastSeen string
}
```
**Delete** from `internal/router/helpers.go`:
```go
func convertDevices(deviceInfos []handlers.DeviceInfo) []templates.DeviceData {
// ... entire function (lines 46-67)
}
```
**Update** `templates/devices.templ:3`:
```templ
// BEFORE:
templ Devices(user User, devices []DeviceData, pendingRegistrations []PendingRegistrationData) {
// AFTER:
templ Devices(user User, devices []handlers.DeviceInfo, pendingRegistrations []PendingRegistrationData) {
```
**Update** `templates/devices.templ` template logic:
Find these patterns and update:
```templ
// BEFORE:
if device.LastSync != "" {
<span>{ device.LastSync }</span>
}
// AFTER:
if device.LastSync != nil {
<span>{ device.LastSync.Format("2006-01-02 15:04") }</span>
}
```
**Update** `internal/router/frontend.go:161-169`:
```go
// BEFORE:
deviceData, err := cfg.DeviceHandler.GetDevicesData(c)
if err != nil {
return c.HTML(http.StatusInternalServerError, "Error loading devices")
}
pendingData, err := cfg.DeviceHandler.GetPendingRegistrationsData(c)
if err != nil {
return c.HTML(http.StatusInternalServerError, "Error loading pending")
}
deviesList := convertDevices(deviceData)
pendingList := convertPending(pendingData)
// AFTER:
deviceData, err := cfg.DeviceHandler.GetDevicesData(c)
if err != nil {
return c.HTML(http.StatusInternalServerError, "Error loading devices")
}
pendingData, err := cfg.DeviceHandler.GetPendingRegistrationsData(c)
if err != nil {
return c.HTML(http.StatusInternalServerError, "Error loading pending")
}
// No conversion - use handler data directly
```
**Test**: Devices page renders correctly with proper date formatting
---
### Phase 2: Eliminate Remaining Template Types
#### 2.1 ProgressItemData → Use ProgressWithMedia
**Current Issue**:
- `handlers.ProgressWithMedia` exists as API response type
- `templates.ProgressItemData` duplicates it with minor variations
**Decision**: **API wins** - Use `handlers.ProgressWithMedia` everywhere
**Files to Modify**:
- `internal/handlers/progress.go` - Update `ProgressWithMedia` struct
- `templates/types.go` - DELETE `ProgressItemData`
- `templates/progress.templ` - Use `handlers.ProgressWithMedia`
**Changes**:
**Add fields to** `internal/handlers/progress.go:ProgressWithMedia`:
```go
// ADD fields to existing struct:
type ProgressWithMedia struct {
MediaItemID uuid.UUID `json:"media_item_id"`
Title string `json:"title"`
Author string `json:"author"`
CoverImagePath string `json:"cover_image_path"`
Percentage float64 `json:"percentage"`
CurrentPage int32 `json:"current_page"`
TotalPages int32 `json:"total_pages"`
LastReadAt time.Time `json:"last_read_at"`
Epubcfi string `json:"epubcfi"`
LastSyncDevice string `json:"last_sync_device"`
DeviceName string `json:"device_name,omitempty"` // ADD
DeviceType string `json:"device_type,omitempty"` // ADD
DeviceIcon string `json:"device_icon,omitempty"` // ADD
}
```
**Update** `internal/handlers/progress.go:GetAllProgress()` to populate new device fields.
**Delete** from `templates/types.go` (lines 99-112):
```go
type ProgressItemData struct {
// ... delete entire struct
}
```
**Update** `templates/progress.templ:3`:
```templ
// BEFORE:
templ Progress(user User, progressData []ProgressItemData) {
// AFTER:
templ Progress(user User, progressData []handlers.ProgressWithMedia) {
```
**Test**: Progress page displays device names and icons
**Delete** from `templates/types.go` (lines 99-112):
```go
type ProgressItemData struct {
// ... delete entire struct
}
```
**Update** `templates/progress.templ:3`:
```templ
// BEFORE:
templ Progress(user User, progressData []ProgressItemData) {
// AFTER:
templ Progress(user User, progressData []handlers.ProgressWithMedia) {
```
**Test**: Progress page displays device names and icons
---
### Phase 3: Update Get*Data Functions
**Issue**: Several handler functions return handler types but aren't used directly by templates due to conversion layer.
**Files to Modify**:
- `internal/router/frontend.go` - Remove conversions
**Changes**:
**Devices** (already done in Phase 1.3):
- `GetDevicesData()` returns `[]handlers.DeviceInfo`
- Template uses directly
**Progress**:
```go
// frontend.go - update progress route
protected.GET("/progress-page", func(c echo.Context) error {
// ...
progressData, err := cfg.Handler.GetAllProgressData(c)
// Returns []handlers.ProgressWithMedia directly - no conversion
// ...
})
```
**Collections**:
```go
// collections.go - update to return handler types
func (h *CollectionHandler) GetCollectionBooksData(c echo.Context) ([]collections.BookInfo, error) {
// Already returns BookInfo - just update template
}
```
---
## Summary Table
| Phase | Files Changed | Lines Removed | Lines Added | Net Change |
|-------|--------------|---------------|--------------|-------------|
| 1.1 CollectionDetailData | 3 | 7 | 2 | -5 |
| 1.2 BookData | 3 | 6 | 0 | -6 |
| 1.3 DeviceData | 4 | 24 | 5 | -19 |
| 2.1 ProgressItemData | 4 | 14 | 3 | -11 |
| **Total** | **14** | **51** | **10** | **-41** |
**Note**: QueueItemData already uses handler type (good pattern). Conflicts already uses handler type (good pattern).
---
## Testing Checklist
After each phase:
### Phase 1.1 (CollectionDetailData)
- [ ] View collection rules page
- [ ] Edit collection rules
- [ ] View collection detail page
- [ ] Add books to collection
### Phase 1.2 (BookData)
- [ ] View collection detail page
- [ ] Browse books in collection
- [ ] Book covers display correctly
### Phase 1.3 (DeviceData)
- [ ] Devices page loads
- [ ] Device cards display
- [ ] Last sync/last seen dates formatted
- [ ] Device type icons show correctly
### Phase 2.1 (ProgressItemData)
- [ ] Progress page loads
- [ ] Progress entries show device names/icons
- [ ] Percentage display works
- [ ] Cover images display
---
## Rollback Plan
If refactoring breaks functionality:
1. **Git stash** changes before starting
2. **Commit after each successful phase**
3. **Revert individual commits** if needed
4. **Keep conversion functions** commented out temporarily
```bash
# Before starting
git stash push -m "pre-refactor-state"
# After Phase 1.1
git commit -m "refactor: delete CollectionDetailData, use CollectionData"
# If Phase 1.2 breaks
git revert HEAD
# Continue with 1.3
```
---
## Benefits
### Code Quality
- ✅ Aligns with templ's design philosophy
- ✅ Single source of truth for types
- ✅ Reduced code duplication
-**API-first**: Handler types are authoritative
### Maintenance
- ✅ Update types in 1 place, not 2
- ✅ Less conversion logic to maintain
- ✅ Clearer data flow
-**Template changes automatically get API updates**
### Consistency
- ✅ All templates use handlers types (like Queue/Conflicts already do)
- ✅ API and HTML use same type definitions
- ✅ 41 fewer lines of code
-**"API wins"** principle eliminates ambiguity
---
## Future Considerations
### For IMPLEMENTATION_EXACT.md
After this refactoring, adding `AuthToken` to devices is simpler:
- Add `AuthToken string` to `handlers.DeviceInfo` struct
- Add to `GetDevicesData()` function return values
- Template automatically gets it (no conversion layer)
This **solves the critical issue** found in IMPLEMENTATION_EXACT.md analysis automatically.
### For New Features
- Define handler types with json tags first
- Templates use same types directly
- Only create template-specific types for:
- Computed/derived fields not in API
- Combining data from multiple sources
- Simplifying complex nested structures
---
## Execution Order
1. **Run tests** to ensure baseline: `go test ./...`
2. **Create feature branch**: `git checkout -b refactor/types-consolidation`
3. **Execute Phase 1.1** (CollectionDetailData) - DELETE template type, use API type
4. **Commit and test**
5. **Execute Phase 1.2** (BookData) - DELETE template type, use API type
6. **Commit and test**
7. **Execute Phase 1.3** (DeviceData) - DELETE template type, use API type
8. **Commit and test**
9. **Execute Phase 2.1** (ProgressItemData) - DELETE template type, enhance API type
10. **Final commit and test**
11. **Update IMPLEMENTATION_EXACT.md** to reference handler types only
**Total Estimated Time**: 2-3 hours with testing
**Key Mindset**: Every change removes a template type, never the reverse. API types are authoritative.
---
## Questions for User
1. **Progress template updates**: Since we're using `handlers.ProgressWithMedia` (API type) in templates, any template formatting changes (like date formatting) should be done in the template itself. Is this acceptable?
2. **Testing**: Do you have automated template tests, or is this manual testing only?
3. **Implementation plan**: Should I update IMPLEMENTATION_EXACT.md after this refactoring to reference `handlers.DeviceInfo` instead of `DeviceData`?
4. **Json tags on handler types**: Templates don't need `json:"..."` tags - should we document that these are for API responses only?
+7 -7
View File
@@ -63,6 +63,13 @@ type UpdateDeviceMappingRequest struct {
SyncDirection string `json:"sync_direction" validate:"required,oneof=bidirectional book_to_device device_to_book none"`
}
type BookInfo struct {
MediaItemID string `json:"media_item_id"`
Title string `json:"title"`
Author string `json:"author"`
CoverImagePath string `json:"cover_image_path"`
}
func (h *CollectionHandler) CreateCollection(c echo.Context) error {
user := c.Get("user").(database.Users)
userUUID := uuid.UUID(user.ID.Bytes)
@@ -171,13 +178,6 @@ func (h *CollectionHandler) GetCollection(c echo.Context) error {
return c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()})
}
type BookInfo struct {
MediaItemID string `json:"media_item_id"`
Title string `json:"title"`
Author string `json:"author"`
CoverImagePath string `json:"cover_image_path"`
}
bookList := make([]BookInfo, 0, len(books))
for _, book := range books {
bookList = append(bookList, BookInfo{
+39 -11
View File
@@ -14,6 +14,20 @@ import (
"github.com/labstack/echo/v4"
)
// getDeviceIcon returns an emoji icon for device type
func getDeviceIcon(deviceType string) string {
switch deviceType {
case "kobo":
return "📚"
case "koreader":
return "📖"
case "kindle":
return "📱"
default:
return "📚"
}
}
// GetUniversalProgress retrieves progress with all location references
func (h *Handler) GetUniversalProgress(c echo.Context) error {
user := MustGetAuthenticatedUser(c)
@@ -229,16 +243,22 @@ func (h *Handler) GetProgressHistory(c echo.Context) error {
}
type ProgressWithMedia struct {
MediaItemID uuid.UUID
Title string
Author string
CoverImagePath string
Percentage float64
CurrentPage int32
TotalPages int32
LastReadAt time.Time
Epubcfi string
LastSyncDevice string
MediaItemID uuid.UUID `json:"media_item_id"`
Title string `json:"title"`
Author string `json:"author"`
CoverImagePath string `json:"cover_image_path"`
Percentage float64 `json:"percentage"`
CurrentPage int32 `json:"current_page"`
TotalPages int32 `json:"total_pages"`
LastReadAt time.Time `json:"last_read_at"`
Epubcfi string `json:"epubcfi"`
LastSyncDevice string `json:"last_sync_device"`
DeviceName string `json:"device_name,omitempty"`
DeviceType string `json:"device_type,omitempty"`
DeviceIcon string `json:"device_icon,omitempty"`
ProgressPercentage float64 `json:"-"`
EpubCFI string `json:"-"`
LastUpdated string `json:"-"`
}
// GetAllProgress retrieves all progress for a user with sync source info
@@ -283,6 +303,11 @@ func (h *Handler) GetAllProgress(c echo.Context) error {
deviceName = progress.LastSyncDevice.String
}
lastUpdated := ""
if progress.LastReadAt.Valid {
lastUpdated = progress.LastReadAt.Time.Format("2006-01-02 15:04")
}
progressList = append(progressList, ProgressWithMedia{
MediaItemID: progress.MediaItemID.Bytes,
Title: mediaItem.Title,
@@ -294,6 +319,10 @@ func (h *Handler) GetAllProgress(c echo.Context) error {
LastReadAt: progress.LastReadAt.Time,
Epubcfi: epubcfi,
LastSyncDevice: deviceName,
ProgressPercentage: progress.Percentage.Float64,
EpubCFI: epubcfi,
LastUpdated: lastUpdated,
DeviceIcon: getDeviceIcon(deviceName),
})
}
@@ -361,4 +390,3 @@ func (h *Handler) GetAllProgressData(c echo.Context) ([]ProgressWithMedia, error
return progressList, nil
}
+4 -5
View File
@@ -158,18 +158,17 @@ func registerFrontendRoutes(cfg *Config) {
if err != nil {
return c.HTML(http.StatusInternalServerError, "Error loading user")
}
deviceData, err := cfg.DeviceHandler.GetDevicesData(c)
devices, err := cfg.DeviceHandler.GetDevicesData(c)
if err != nil {
return c.HTML(http.StatusInternalServerError, "Error loading devices")
}
pendingData, err := cfg.DeviceHandler.GetPendingRegistrationsData(c)
pendingMaps, err := cfg.DeviceHandler.GetPendingRegistrationsData(c)
if err != nil {
return c.HTML(http.StatusInternalServerError, "Error loading pending")
}
devicesList := convertDevices(deviceData)
pendingList := convertPending(pendingData)
pendingList := convertPending(pendingMaps)
var buf bytes.Buffer
err = templates.Devices(user, devicesList, pendingList).Render(c.Request().Context(), &buf)
err = templates.Devices(user, devices, pendingList).Render(c.Request().Context(), &buf)
if err != nil {
return err
}
-25
View File
@@ -2,9 +2,7 @@ package router
import (
"context"
"time"
"bookhoard/internal/handlers"
"bookhoard/templates"
"github.com/google/uuid"
@@ -43,29 +41,6 @@ func getTemplateUserWithTheme(c echo.Context, cfg *Config) (templates.User, erro
}, nil
}
func convertDevices(deviceInfos []handlers.DeviceInfo) []templates.DeviceData {
result := make([]templates.DeviceData, len(deviceInfos))
for i, d := range deviceInfos {
lastSync := ""
if d.LastSync != nil {
lastSync = d.LastSync.Format(time.RFC3339)
}
lastSeen := ""
if d.LastSeen != nil {
lastSeen = d.LastSeen.Format(time.RFC3339)
}
result[i] = templates.DeviceData{
ID: d.ID.String(),
DeviceName: d.DeviceName,
DeviceType: d.DeviceType,
SyncEnabled: d.SyncEnabled,
LastSync: lastSync,
LastSeen: lastSeen,
}
}
return result
}
func convertPending(pending []map[string]interface{}) []templates.PendingRegistrationData {
result := make([]templates.PendingRegistrationData, len(pending))
for i, p := range pending {
+1 -1
View File
@@ -1,6 +1,6 @@
package templates
templ CollectionRules(user User, collection CollectionDetailData) {
templ CollectionRules(user User, collection CollectionData) {
<!DOCTYPE html>
<html lang="en">
<head>
+1 -1
View File
@@ -8,7 +8,7 @@ package templates
import "github.com/a-h/templ"
import templruntime "github.com/a-h/templ/runtime"
func CollectionRules(user User, collection CollectionDetailData) templ.Component {
func CollectionRules(user User, collection CollectionData) templ.Component {
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
+3 -1
View File
@@ -1,5 +1,7 @@
package templates
import "bookhoard/internal/handlers"
templ Collection(user User, collections []CollectionData) {
<!DOCTYPE html>
<html lang="en">
@@ -210,7 +212,7 @@ templ Collection(user User, collections []CollectionData) {
</html>
}
templ CollectionDetail(user User, collection CollectionDetailData, books []BookData) {
templ CollectionDetail(user User, collection CollectionData, books []handlers.BookInfo) {
<!DOCTYPE html>
<html lang="en">
<head>
+12 -10
View File
@@ -8,6 +8,8 @@ package templates
import "github.com/a-h/templ"
import templruntime "github.com/a-h/templ/runtime"
import "bookhoard/internal/handlers"
func Collection(user User, collections []CollectionData) templ.Component {
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
@@ -55,7 +57,7 @@ func Collection(user User, collections []CollectionData) templ.Component {
var templ_7745c5c3_Var2 string
templ_7745c5c3_Var2, templ_7745c5c3_Err = templ.JoinStringErrs(col.Icon)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/collections.templ`, Line: 46, Col: 60}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/collections.templ`, Line: 48, Col: 60}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var2))
if templ_7745c5c3_Err != nil {
@@ -68,7 +70,7 @@ func Collection(user User, collections []CollectionData) templ.Component {
var templ_7745c5c3_Var3 string
templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(col.Name)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/collections.templ`, Line: 58, Col: 109}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/collections.templ`, Line: 60, Col: 109}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3))
if templ_7745c5c3_Err != nil {
@@ -81,7 +83,7 @@ func Collection(user User, collections []CollectionData) templ.Component {
var templ_7745c5c3_Var4 string
templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(col.Description)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/collections.templ`, Line: 59, Col: 103}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/collections.templ`, Line: 61, Col: 103}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4))
if templ_7745c5c3_Err != nil {
@@ -100,7 +102,7 @@ func Collection(user User, collections []CollectionData) templ.Component {
})
}
func CollectionDetail(user User, collection CollectionDetailData, books []BookData) templ.Component {
func CollectionDetail(user User, collection CollectionData, books []handlers.BookInfo) templ.Component {
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
@@ -128,7 +130,7 @@ func CollectionDetail(user User, collection CollectionDetailData, books []BookDa
var templ_7745c5c3_Var6 string
templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs(collection.Name)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/collections.templ`, Line: 219, Col: 32}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/collections.templ`, Line: 221, Col: 32}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var6))
if templ_7745c5c3_Err != nil {
@@ -149,7 +151,7 @@ func CollectionDetail(user User, collection CollectionDetailData, books []BookDa
var templ_7745c5c3_Var7 string
templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinStringErrs(collection.Icon)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/collections.templ`, Line: 234, Col: 95}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/collections.templ`, Line: 236, Col: 95}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var7))
if templ_7745c5c3_Err != nil {
@@ -162,7 +164,7 @@ func CollectionDetail(user User, collection CollectionDetailData, books []BookDa
var templ_7745c5c3_Var8 string
templ_7745c5c3_Var8, templ_7745c5c3_Err = templ.JoinStringErrs(collection.Name)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/collections.templ`, Line: 236, Col: 107}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/collections.templ`, Line: 238, Col: 107}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var8))
if templ_7745c5c3_Err != nil {
@@ -175,7 +177,7 @@ func CollectionDetail(user User, collection CollectionDetailData, books []BookDa
var templ_7745c5c3_Var9 string
templ_7745c5c3_Var9, templ_7745c5c3_Err = templ.JoinStringErrs(collection.Description)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/collections.templ`, Line: 237, Col: 88}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/collections.templ`, Line: 239, Col: 88}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var9))
if templ_7745c5c3_Err != nil {
@@ -199,7 +201,7 @@ func CollectionDetail(user User, collection CollectionDetailData, books []BookDa
var templ_7745c5c3_Var10 string
templ_7745c5c3_Var10, templ_7745c5c3_Err = templ.JoinStringErrs(book.Title)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/collections.templ`, Line: 284, Col: 131}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/collections.templ`, Line: 286, Col: 131}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var10))
if templ_7745c5c3_Err != nil {
@@ -217,7 +219,7 @@ func CollectionDetail(user User, collection CollectionDetailData, books []BookDa
var templ_7745c5c3_Var11 string
templ_7745c5c3_Var11, templ_7745c5c3_Err = templ.JoinStringErrs(book.Author)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/collections.templ`, Line: 286, Col: 108}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/collections.templ`, Line: 288, Col: 108}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var11))
if templ_7745c5c3_Err != nil {
+7 -5
View File
@@ -1,6 +1,8 @@
package templates
templ Devices(user User, devices []DeviceData, pendingRegistrations []PendingRegistrationData) {
import "bookhoard/internal/handlers"
templ Devices(user User, devices []handlers.DeviceInfo, pendingRegistrations []PendingRegistrationData) {
<!DOCTYPE html>
<html lang="en">
<head>
@@ -79,16 +81,16 @@ templ Devices(user User, devices []DeviceData, pendingRegistrations []PendingReg
</div>
<div class="flex justify-between">
<span style="color: var(--text-secondary)">Last Sync</span>
if device.LastSync != "" {
<span style="color: var(--text-primary)">{ device.LastSync }</span>
if device.LastSync != nil {
<span style="color: var(--text-primary)">{ device.LastSync.Format("2006-01-02 15:04") }</span>
} else {
<span style="color: var(--text-primary)">Never</span>
}
</div>
<div class="flex justify-between">
<span style="color: var(--text-secondary)">Last Seen</span>
if device.LastSeen != "" {
<span style="color: var(--text-primary)">{ device.LastSeen }</span>
if device.LastSeen != nil {
<span style="color: var(--text-primary)">{ device.LastSeen.Format("2006-01-02 15:04") }</span>
} else {
<span style="color: var(--text-primary)">Never</span>
}
+14 -12
View File
@@ -8,7 +8,9 @@ package templates
import "github.com/a-h/templ"
import templruntime "github.com/a-h/templ/runtime"
func Devices(user User, devices []DeviceData, pendingRegistrations []PendingRegistrationData) templ.Component {
import "bookhoard/internal/handlers"
func Devices(user User, devices []handlers.DeviceInfo, pendingRegistrations []PendingRegistrationData) templ.Component {
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
@@ -89,7 +91,7 @@ func Devices(user User, devices []DeviceData, pendingRegistrations []PendingRegi
var templ_7745c5c3_Var2 string
templ_7745c5c3_Var2, templ_7745c5c3_Err = templ.JoinStringErrs(device.DeviceName)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/devices.templ`, Line: 69, Col: 102}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/devices.templ`, Line: 71, Col: 102}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var2))
if templ_7745c5c3_Err != nil {
@@ -102,7 +104,7 @@ func Devices(user User, devices []DeviceData, pendingRegistrations []PendingRegi
var templ_7745c5c3_Var3 string
templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(device.DeviceType)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/devices.templ`, Line: 70, Col: 89}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/devices.templ`, Line: 72, Col: 89}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3))
if templ_7745c5c3_Err != nil {
@@ -127,15 +129,15 @@ func Devices(user User, devices []DeviceData, pendingRegistrations []PendingRegi
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
if device.LastSync != "" {
if device.LastSync != nil {
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 17, "<span style=\"color: var(--text-primary)\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var4 string
templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(device.LastSync)
templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(device.LastSync.Format("2006-01-02 15:04"))
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/devices.templ`, Line: 83, Col: 70}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/devices.templ`, Line: 85, Col: 97}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4))
if templ_7745c5c3_Err != nil {
@@ -155,15 +157,15 @@ func Devices(user User, devices []DeviceData, pendingRegistrations []PendingRegi
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
if device.LastSeen != "" {
if device.LastSeen != nil {
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 21, "<span style=\"color: var(--text-primary)\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var5 string
templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs(device.LastSeen)
templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs(device.LastSeen.Format("2006-01-02 15:04"))
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/devices.templ`, Line: 91, Col: 70}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/devices.templ`, Line: 93, Col: 97}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var5))
if templ_7745c5c3_Err != nil {
@@ -206,7 +208,7 @@ func Devices(user User, devices []DeviceData, pendingRegistrations []PendingRegi
var templ_7745c5c3_Var6 string
templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs(reg.DeviceName)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/devices.templ`, Line: 110, Col: 87}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/devices.templ`, Line: 112, Col: 87}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var6))
if templ_7745c5c3_Err != nil {
@@ -219,7 +221,7 @@ func Devices(user User, devices []DeviceData, pendingRegistrations []PendingRegi
var templ_7745c5c3_Var7 string
templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinStringErrs(reg.DeviceType)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/devices.templ`, Line: 112, Col: 27}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/devices.templ`, Line: 114, Col: 27}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var7))
if templ_7745c5c3_Err != nil {
@@ -232,7 +234,7 @@ func Devices(user User, devices []DeviceData, pendingRegistrations []PendingRegi
var templ_7745c5c3_Var8 string
templ_7745c5c3_Var8, templ_7745c5c3_Err = templ.JoinStringErrs(reg.ExpiresAt)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/devices.templ`, Line: 112, Col: 58}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/devices.templ`, Line: 114, Col: 58}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var8))
if templ_7745c5c3_Err != nil {
+3 -1
View File
@@ -1,6 +1,8 @@
package templates
templ Progress(user User, progressData []ProgressItemData) {
import "bookhoard/internal/handlers"
templ Progress(user User, progressData []handlers.ProgressWithMedia) {
<!DOCTYPE html>
<html lang="en">
<head>
+14 -12
View File
@@ -8,7 +8,9 @@ package templates
import "github.com/a-h/templ"
import templruntime "github.com/a-h/templ/runtime"
func Progress(user User, progressData []ProgressItemData) templ.Component {
import "bookhoard/internal/handlers"
func Progress(user User, progressData []handlers.ProgressWithMedia) templ.Component {
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
@@ -55,7 +57,7 @@ func Progress(user User, progressData []ProgressItemData) templ.Component {
var templ_7745c5c3_Var2 string
templ_7745c5c3_Var2, templ_7745c5c3_Err = templ.JoinStringErrs(item.Title)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/progress.templ`, Line: 44, Col: 121}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/progress.templ`, Line: 46, Col: 121}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var2))
if templ_7745c5c3_Err != nil {
@@ -73,7 +75,7 @@ func Progress(user User, progressData []ProgressItemData) templ.Component {
var templ_7745c5c3_Var3 string
templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(item.Author)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/progress.templ`, Line: 46, Col: 116}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/progress.templ`, Line: 48, Col: 116}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3))
if templ_7745c5c3_Err != nil {
@@ -91,7 +93,7 @@ func Progress(user User, progressData []ProgressItemData) templ.Component {
var templ_7745c5c3_Var4 string
templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(item.ProgressPercentage)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/progress.templ`, Line: 50, Col: 127}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/progress.templ`, Line: 52, Col: 127}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4))
if templ_7745c5c3_Err != nil {
@@ -104,7 +106,7 @@ func Progress(user User, progressData []ProgressItemData) templ.Component {
var templ_7745c5c3_Var5 string
templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs(item.CurrentPage)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/progress.templ`, Line: 64, Col: 62}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/progress.templ`, Line: 66, Col: 62}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var5))
if templ_7745c5c3_Err != nil {
@@ -117,7 +119,7 @@ func Progress(user User, progressData []ProgressItemData) templ.Component {
var templ_7745c5c3_Var6 string
templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs(item.TotalPages)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/progress.templ`, Line: 64, Col: 84}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/progress.templ`, Line: 66, Col: 84}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var6))
if templ_7745c5c3_Err != nil {
@@ -130,7 +132,7 @@ func Progress(user User, progressData []ProgressItemData) templ.Component {
var templ_7745c5c3_Var7 string
templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinStringErrs(item.LastUpdated)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/progress.templ`, Line: 69, Col: 96}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/progress.templ`, Line: 71, Col: 96}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var7))
if templ_7745c5c3_Err != nil {
@@ -143,7 +145,7 @@ func Progress(user User, progressData []ProgressItemData) templ.Component {
var templ_7745c5c3_Var8 string
templ_7745c5c3_Var8, templ_7745c5c3_Err = templ.JoinStringErrs(item.DeviceIcon)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/progress.templ`, Line: 74, Col: 83}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/progress.templ`, Line: 76, Col: 83}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var8))
if templ_7745c5c3_Err != nil {
@@ -156,7 +158,7 @@ func Progress(user User, progressData []ProgressItemData) templ.Component {
var templ_7745c5c3_Var9 string
templ_7745c5c3_Var9, templ_7745c5c3_Err = templ.JoinStringErrs(item.DeviceName)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/progress.templ`, Line: 75, Col: 102}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/progress.templ`, Line: 77, Col: 102}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var9))
if templ_7745c5c3_Err != nil {
@@ -174,7 +176,7 @@ func Progress(user User, progressData []ProgressItemData) templ.Component {
var templ_7745c5c3_Var10 string
templ_7745c5c3_Var10, templ_7745c5c3_Err = templ.JoinStringErrs(item.DeviceName)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/progress.templ`, Line: 84, Col: 90}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/progress.templ`, Line: 86, Col: 90}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var10))
if templ_7745c5c3_Err != nil {
@@ -187,7 +189,7 @@ func Progress(user User, progressData []ProgressItemData) templ.Component {
var templ_7745c5c3_Var11 string
templ_7745c5c3_Var11, templ_7745c5c3_Err = templ.JoinStringErrs(item.DeviceType)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/progress.templ`, Line: 85, Col: 68}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/progress.templ`, Line: 87, Col: 68}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var11))
if templ_7745c5c3_Err != nil {
@@ -206,7 +208,7 @@ func Progress(user User, progressData []ProgressItemData) templ.Component {
var templ_7745c5c3_Var12 string
templ_7745c5c3_Var12, templ_7745c5c3_Err = templ.JoinStringErrs(item.EpubCFI)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/progress.templ`, Line: 93, Col: 65}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/progress.templ`, Line: 95, Col: 65}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var12))
if templ_7745c5c3_Err != nil {
-41
View File
@@ -23,21 +23,6 @@ type CollectionData struct {
Icon string
}
type CollectionDetailData struct {
ID string
Name string
Description string
Color string
Icon string
}
type BookData struct {
MediaItemID string
Title string
Author string
CoverImagePath string
}
type LibraryData struct {
ID string
Name string
@@ -45,17 +30,6 @@ type LibraryData struct {
TypeName string
}
type DeviceData struct {
ID string
DeviceName string
DeviceType string
SyncEnabled bool
AutoSync bool
SyncFrequency int32
LastSync string
LastSeen string
}
type PendingRegistrationData struct {
RegistrationID string
DeviceName string
@@ -96,21 +70,6 @@ type DeviceShelfMappingData struct {
CreatedAt string
}
type ProgressItemData struct {
MediaItemID string
Title string
Author string
CoverImagePath string
CurrentPage int32
TotalPages int32
ProgressPercentage float64
LastUpdated string
DeviceName string
DeviceType string
DeviceIcon string
EpubCFI string
}
type UnlinkedBookData struct {
ProgressID string
DeviceID string