- 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)
114 lines
5.8 KiB
Templ
114 lines
5.8 KiB
Templ
package templates
|
|
|
|
import "bookhoard/internal/handlers"
|
|
|
|
templ Progress(user User, progressData []handlers.ProgressWithMedia) {
|
|
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>Reading Progress - Bookhoard</title>
|
|
<script src="/static/htmx.min.js"></script>
|
|
<script src="/static/toast.js"></script>
|
|
<script src="/static/header.js"></script>
|
|
<link href="/static/style.css" rel="stylesheet">
|
|
</head>
|
|
<body class="theme-{ user.Theme }">
|
|
@Header(user, "/progress")
|
|
|
|
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
|
|
<div class="mb-8">
|
|
<h1 class="text-3xl font-bold" style="color: var(--text-primary)">Reading Progress</h1>
|
|
<p style="color: var(--text-secondary)">Track your reading progress across all devices</p>
|
|
</div>
|
|
|
|
<div id="progress-container" class="space-y-6">
|
|
if len(progressData) == 0 {
|
|
<div class="text-center py-16" style="color: var(--text-secondary)">
|
|
<div class="text-6xl mb-4">📖</div>
|
|
<h3 class="text-xl font-semibold mb-2" style="color: var(--text-primary)">No Progress Yet</h3>
|
|
<p>Start reading a book to track your progress</p>
|
|
</div>
|
|
}
|
|
|
|
for _, item := range progressData {
|
|
<div class="card p-6 rounded-lg border" style="background-color: var(--bg-secondary); border-color: var(--border);">
|
|
<div class="flex gap-6">
|
|
<div class="flex-shrink-0">
|
|
<img src="{ item.CoverImagePath }" alt="Cover"
|
|
class="w-24 h-32 object-cover rounded"
|
|
onerror="this.src='/static/placeholder-book.svg'">
|
|
</div>
|
|
<div class="flex-1">
|
|
<div class="flex justify-between items-start mb-2">
|
|
<div>
|
|
<h3 class="font-semibold text-lg" style="color: var(--text-primary)">{ item.Title }</h3>
|
|
if item.Author != "" {
|
|
<p class="text-sm" style="color: var(--text-secondary)">by { item.Author }</p>
|
|
}
|
|
</div>
|
|
<div class="text-right">
|
|
<span class="text-2xl font-bold" style="color: var(--accent)">{ item.ProgressPercentage }%</span>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="mb-4">
|
|
<div class="w-full bg-gray-700 rounded-full h-3">
|
|
<div class="h-3 rounded-full transition-all" style="width: { item.ProgressPercentage }%; background-color: var(--accent);"></div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="grid grid-cols-1 md:grid-cols-3 gap-4 text-sm">
|
|
<div>
|
|
<p style="color: var(--text-secondary)">Current Position</p>
|
|
<p style="color: var(--text-primary)">
|
|
{ item.CurrentPage } / { item.TotalPages }
|
|
</p>
|
|
</div>
|
|
<div>
|
|
<p style="color: var(--text-secondary)">Last Updated</p>
|
|
<p style="color: var(--text-primary)">{ item.LastUpdated }</p>
|
|
</div>
|
|
<div>
|
|
<p style="color: var(--text-secondary)">Synced From</p>
|
|
<div class="flex items-center gap-2">
|
|
<span class="text-xl">{ item.DeviceIcon }</span>
|
|
<span style="color: var(--text-primary)">{ item.DeviceName }</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
if item.DeviceIcon != "" {
|
|
<div class="mt-3 pt-3 border-t" style="border-color: var(--border);">
|
|
<div class="flex items-center gap-2 text-xs" style="color: var(--text-secondary);">
|
|
<span>🔄</span>
|
|
<span>Last sync from <strong>{ item.DeviceName }</strong></span>
|
|
<span>({ item.DeviceType })</span>
|
|
</div>
|
|
</div>
|
|
}
|
|
|
|
if item.EpubCFI != "" {
|
|
<div class="mt-2 text-xs" style="color: var(--text-secondary);">
|
|
<span>📍</span>
|
|
<span>CFI: { item.EpubCFI }</span>
|
|
</div>
|
|
}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
}
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
function logout() {
|
|
localStorage.removeItem('token');
|
|
window.location.href = '/login';
|
|
}
|
|
</script>
|
|
</body>
|
|
</html>
|
|
}
|