feat: integrate header component into dashboard page
- Replace navigation bar with Header() component - Remove duplicate logout function (now in header.js) - Maintain consistent header across pages - Update generated template files This provides consistent navigation and theme switching functionality across all pages using the reusable header component.
This commit is contained in:
1 parent
703daeb32f
commit
c3dcbad177
2 files changed
+3
-40
No files matched your search
@@ -9,6 +9,7 @@ templ Dashboard(user User) {
|
||||
<title>Dashboard - Bookmann</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">
|
||||
<style>
|
||||
:root {
|
||||
@@ -72,26 +73,7 @@ templ Dashboard(user User) {
|
||||
</style>
|
||||
</head>
|
||||
<body class="theme-tokyo-night">
|
||||
<!-- Navigation Header -->
|
||||
<nav class="border-b" style="border-color: var(--border); background-color: var(--bg-secondary)">
|
||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||
<div class="flex justify-between items-center h-16">
|
||||
<div class="flex items-center">
|
||||
<h1 class="text-xl font-bold" style="color: var(--text-primary)">📚 Bookmann</h1>
|
||||
</div>
|
||||
<div class="flex items-center space-x-4">
|
||||
<a href="/" class="px-3 py-2 text-sm hover:opacity-80" style="color: var(--text-secondary)">Dashboard</a>
|
||||
if user.Role == "admin" {
|
||||
<a href="/admin" class="px-3 py-2 text-sm hover:opacity-80" style="color: var(--text-secondary)">Admin</a>
|
||||
}
|
||||
<span style="color: var(--text-secondary)">Welcome, { user.Username }!</span>
|
||||
<button onclick="logout()" class="btn-primary px-4 py-2 rounded text-sm">
|
||||
Logout
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
Header(user, "/dashboard")
|
||||
|
||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
|
||||
<!-- Header Section -->
|
||||
@@ -404,12 +386,6 @@ templ Dashboard(user User) {
|
||||
alert('Media viewer coming soon!');
|
||||
}
|
||||
|
||||
function logout() {
|
||||
localStorage.removeItem('token');
|
||||
localStorage.removeItem('user');
|
||||
window.location.href = '/';
|
||||
}
|
||||
|
||||
// Load libraries on page load
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
loadTheme();
|
||||
|
||||
@@ -29,20 +29,7 @@ func Dashboard(user User) templ.Component {
|
||||
templ_7745c5c3_Var1 = templ.NopComponent
|
||||
}
|
||||
ctx = templ.ClearChildren(ctx)
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "<!doctype html><html lang=\"en\"><head><meta charset=\"UTF-8\"><meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\"><title>Dashboard - Bookmann</title><script src=\"https://cdn.tailwindcss.com\"></script><script src=\"https://unpkg.com/htmx.org@1.9.10\"></script><style>\n :root {\n --bg-primary: #1a1b26;\n --bg-secondary: #16161e;\n --text-primary: #a9b1d6;\n --text-secondary: #565f89;\n --accent: #7aa2f7;\n --border: #414868;\n }\n .theme-tokyo-night {\n --bg-primary: #1a1b26;\n --bg-secondary: #16161e;\n --text-primary: #a9b1d6;\n --text-secondary: #565f89;\n --accent: #7aa2f7;\n --border: #414868;\n }\n body {\n background-color: var(--bg-primary);\n color: var(--text-primary);\n }\n .card {\n background-color: var(--bg-secondary);\n border-color: var(--border);\n }\n .btn-primary {\n background-color: var(--accent);\n color: var(--bg-primary);\n }\n .btn-primary:hover {\n opacity: 0.8;\n }\n </style></head><body class=\"theme-tokyo-night\"><!-- Navigation Header --><nav class=\"border-b\" style=\"border-color: var(--border); background-color: var(--bg-secondary)\"><div class=\"max-w-7xl mx-auto px-4 sm:px-6 lg:px-8\"><div class=\"flex justify-between items-center h-16\"><div class=\"flex items-center\"><h1 class=\"text-xl font-bold\" style=\"color: var(--text-primary)\">📚 Bookmann</h1></div><div class=\"flex items-center space-x-4\"><a href=\"/\" class=\"px-3 py-2 text-sm hover:opacity-80\" style=\"color: var(--text-secondary)\">Dashboard</a> <a href=\"/admin\" class=\"px-3 py-2 text-sm hover:opacity-80\" style=\"color: var(--text-secondary)\">Admin</a> <span style=\"color: var(--text-secondary)\">Welcome, ")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var2 string
|
||||
templ_7745c5c3_Var2, templ_7745c5c3_Err = templ.JoinStringErrs(user.Username)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `dashboard.templ`, Line: 57, Col: 91}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var2))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "!</span> <button onclick=\"logout()\" class=\"btn-primary px-4 py-2 rounded text-sm\">Logout</button></div></div></div></nav><div class=\"max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8\"><!-- Header Section --><div class=\"mb-8\"><div class=\"flex justify-between items-center\"><div><h2 class=\"text-3xl font-bold\" style=\"color: var(--text-primary)\">Your Ebook Library</h2><p style=\"color: var(--text-secondary)\">Manage your ebook collection and reading progress</p></div><button onclick=\"showCreateForm()\" class=\"btn-primary px-6 py-3 rounded-lg font-medium\">+ Add New Ebook</button></div></div><!-- Search and Filter --><div class=\"mb-6\"><div class=\"flex flex-col sm:flex-row gap-4\"><input type=\"text\" id=\"search-input\" placeholder=\"Search ebooks...\" class=\"flex-1 px-4 py-2 border rounded-lg\" style=\"background-color: var(--bg-secondary); color: var(--text-primary); border-color: var(--border)\" onkeyup=\"filterEbooks()\"> <select id=\"sort-select\" class=\"px-4 py-2 border rounded-lg\" style=\"background-color: var(--bg-secondary); color: var(--text-primary); border-color: var(--border)\" onchange=\"loadEbooks()\"><option value=\"created_at DESC\">Newest First</option> <option value=\"title ASC\">Title A-Z</option> <option value=\"author ASC\">Author A-Z</option> <option value=\"created_at ASC\">Oldest First</option></select></div></div><!-- Ebooks Grid --><div id=\"ebooks-container\" class=\"grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6\"><!-- Ebooks will be loaded here --></div><!-- Loading indicator --><div id=\"loading\" class=\"text-center py-8\" style=\"color: var(--text-secondary)\">Loading your ebooks...</div></div><script>\n function loadEbooks() {\n const loading = document.getElementById('loading');\n const container = document.getElementById('ebooks-container');\n\n loading.style.display = 'block';\n container.innerHTML = '';\n\n const sort = document.getElementById('sort-select').value;\n\n fetch(`/api/ebooks?limit=12&offset=0&sort=${sort}`, {\n headers: {\n 'Authorization': 'Bearer ' + localStorage.getItem('token'),\n 'Content-Type': 'application/json'\n }\n })\n .then(response => response.json())\n .then(data => {\n loading.style.display = 'none';\n renderEbooks(data);\n })\n .catch(error => {\n loading.style.display = 'none';\n console.error('Error loading ebooks:', error);\n container.innerHTML = '<div class=\"col-span-full text-center py-8\" style=\"color: var(--text-secondary)\">Error loading ebooks. Please try again.</div>';\n });\n }\n\n function renderEbooks(ebooks) {\n const container = document.getElementById('ebooks-container');\n container.innerHTML = '';\n\n ebooks.forEach(ebook => {\n const card = document.createElement('div');\n card.className = 'card p-4 rounded-lg border hover:shadow-lg transition-shadow';\n card.style.cssText = 'background-color: var(--bg-secondary); border-color: var(--border);';\n\n const coverUrl = ebook.cover_image_path ? ebook.cover_image_path : '/static/placeholder-book.svg';\n\n card.innerHTML = '<div class=\"flex flex-col h-full\"><div class=\"flex-1\"><div class=\"aspect-w-3 aspect-h-4 mb-3 overflow-hidden rounded\"><img src=\"' + coverUrl + '\" alt=\"Cover\" class=\"w-full h-48 object-cover rounded\" onerror=\"this.src=\\'/static/placeholder-book.svg\\'\"></div><h3 class=\"font-semibold text-lg mb-1 line-clamp-2\" style=\"color: var(--text-primary)\">' + ebook.title + '</h3>' + (ebook.author ? '<p class=\"text-sm mb-2\" style=\"color: var(--text-secondary)\">by ' + ebook.author + '</p>' : '') + '<div class=\"flex justify-between items-center mt-4\"><div class=\"flex space-x-2\"><button onclick=\"viewEbook(\\'' + ebook.id + '\\')\" class=\"px-3 py-1 text-sm border rounded hover:opacity-80\" style=\"border-color: var(--border); color: var(--text-secondary)\">View</button></div></div></div>';\n\n container.appendChild(card);\n });\n }\n\n function logout() {\n localStorage.removeItem('token');\n localStorage.removeItem('user');\n window.location.href = '/';\n }\n\n // Load ebooks on page load\n document.addEventListener('DOMContentLoaded', function() {\n loadTheme();\n loadEbooks();\n });\n </script></body></html>")
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "<!doctype html><html lang=\"en\"><head><meta charset=\"UTF-8\"><meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\"><title>Dashboard - Bookmann</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\"><style>\n :root {\n --bg-primary: #1a1b26;\n --bg-secondary: #16161e;\n --text-primary: #a9b1d6;\n --text-secondary: #565f89;\n --accent: #7aa2f7;\n --border: #414868;\n }\n .theme-tokyo-night {\n --bg-primary: #1a1b26;\n --bg-secondary: #16161e;\n --text-primary: #a9b1d6;\n --text-secondary: #565f89;\n --accent: #7aa2f7;\n --border: #414868;\n }\n body {\n background-color: var(--bg-primary);\n color: var(--text-primary);\n }\n .card {\n background-color: var(--bg-secondary);\n border-color: var(--border);\n }\n .btn-primary {\n background-color: var(--accent);\n color: var(--bg-primary);\n }\n .btn-primary:hover {\n opacity: 0.8;\n }\n .rating-star {\n display: inline-block;\n transition: all 0.2s ease;\n cursor: pointer;\n position: relative;\n }\n .rating-star:hover {\n transform: scale(1.1);\n }\n .half-star {\n position: relative;\n display: inline-block;\n }\n .half-star::before {\n content: '★';\n position: absolute;\n left: 0;\n top: 0;\n width: 50%;\n overflow: hidden;\n color: #facc15; /* yellow-400 */\n }\n .rating-text {\n font-size: 0.875rem;\n margin-left: 0.5rem;\n opacity: 0.8;\n }\n </style></head><body class=\"theme-tokyo-night\">Header(user, \"/dashboard\")<div class=\"max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8\"><!-- Header Section --><div class=\"mb-8\"><div><h2 class=\"text-3xl font-bold\" style=\"color: var(--text-primary)\">Your Media Library</h2><p style=\"color: var(--text-secondary)\">Browse and manage your media collections</p></div></div><!-- Libraries Section --><div id=\"libraries-container\" class=\"mb-8\"><!-- Libraries will be loaded here --></div><!-- Media Items Section --><div id=\"media-section\" class=\"hidden\"><!-- Search and Filter --><div class=\"mb-6\"><div class=\"flex flex-col sm:flex-row gap-4\"><button onclick=\"backToLibraries()\" class=\"btn-secondary px-4 py-2 rounded-lg\">← Back to Libraries</button> <input type=\"text\" id=\"search-input\" placeholder=\"Search media...\" class=\"flex-1 px-4 py-2 border rounded-lg\" style=\"background-color: var(--bg-secondary); color: var(--text-primary); border-color: var(--border)\" onkeyup=\"filterMedia()\"> <select id=\"sort-select\" class=\"px-4 py-2 border rounded-lg\" style=\"background-color: var(--bg-secondary); color: var(--text-primary); border-color: var(--border)\" onchange=\"loadMediaItems()\"><option value=\"created_at DESC\">Newest First</option> <option value=\"title ASC\">Title A-Z</option> <option value=\"author ASC\">Author A-Z</option> <option value=\"created_at ASC\">Oldest First</option></select></div></div><!-- Media Grid --><div id=\"media-container\" class=\"grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6\"><!-- Media items will be loaded here --></div></div><!-- Loading indicator --><div id=\"loading\" class=\"text-center py-8\" style=\"color: var(--text-secondary)\">Loading your media libraries...</div></div><script>\n let libraries = [];\n let currentLibrary = null;\n let mediaItems = [];\n\n function loadLibraries() {\n const loading = document.getElementById('loading');\n const librariesContainer = document.getElementById('libraries-container');\n \n loading.style.display = 'block';\n librariesContainer.innerHTML = '';\n\n fetch('/api/libraries/visible', {\n headers: {\n 'Authorization': 'Bearer ' + localStorage.getItem('token'),\n 'Content-Type': 'application/json'\n }\n })\n .then(response => response.json())\n .then(data => {\n loading.style.display = 'none';\n libraries = data;\n Line truncated
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user