UI polish: centering, search width, dropdown contrast, cover thumbnails, branding, sticky headers
- Constrain main content to max-w-5xl centered - Widen search input (w-72 md:w-80 lg:w-96) - Search dropdown: card with shadow, border, and primary-tinted hover - Branding: SVG music note icon + gradient text + tagline - Covers: 64px with front-250 thumbnail URL for faster loading - Badge colors per type (primary/secondary/accent/ghost) - Sticky table headers via table-pin-rows - SVG icons for Add/Remove/RSS/OPML buttons - Consistent hover transitions across tables
This commit is contained in:
@@ -1,9 +1,9 @@
|
||||
{#include layouts/base}
|
||||
{#page-content}
|
||||
<div class="w-full max-w-4xl mx-auto">
|
||||
<h2 class="text-2xl font-bold mb-4">🎤 Artists</h2>
|
||||
<div class="w-full">
|
||||
<h2 class="text-2xl font-bold mb-5">🎤 Tracked Artists</h2>
|
||||
<div id="artist-list" hx-get="/api/artists/list" hx-trigger="load">
|
||||
<span class="loading loading-spinner loading-lg block mx-auto"></span>
|
||||
<span class="loading loading-spinner loading-lg block mx-auto my-12"></span>
|
||||
</div>
|
||||
</div>
|
||||
{/page-content}
|
||||
|
||||
@@ -1,80 +1,84 @@
|
||||
<div id="artist-list" hx-swap-oob="true">
|
||||
{#if artists.isEmpty()}
|
||||
<div class="card bg-base-100 shadow-xl p-8 text-center">
|
||||
<p class="text-lg text-base-content/60">No artists tracked yet</p>
|
||||
<p class="text-sm text-base-content/40 mt-2">Search for artists using the search bar above and click "+ Add"</p>
|
||||
<div class="card bg-base-100 shadow-xl p-10 text-center border border-base-300">
|
||||
<svg class="w-12 h-12 mx-auto text-base-content/20 mb-3" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/>
|
||||
</svg>
|
||||
<p class="text-lg font-medium text-base-content/60">No artists tracked yet</p>
|
||||
<p class="text-sm text-base-content/40 mt-1">Search for artists using the search bar above and click <span class="font-semibold text-primary">+ Add</span></p>
|
||||
</div>
|
||||
{#else}
|
||||
<div class="overflow-x-auto">
|
||||
<table class="table table-zebra">
|
||||
<div class="overflow-x-auto rounded-box border border-base-300">
|
||||
<table class="table table-pin-rows">
|
||||
<thead>
|
||||
<tr>
|
||||
<tr class="bg-base-200/80">
|
||||
<th>Artist</th>
|
||||
<th>Since</th>
|
||||
<th>Release Types</th>
|
||||
<th>Actions</th>
|
||||
<th class="w-24">Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{#for artist in artists}
|
||||
<tr>
|
||||
<tr class="hover:bg-base-200/50 transition-colors">
|
||||
<td>
|
||||
<div class="font-medium">{artist.name}</div>
|
||||
{#if artist.disambiguation}
|
||||
<div class="text-xs text-base-content/60">{artist.disambiguation}</div>
|
||||
<div class="text-xs text-base-content/50">{artist.disambiguation}</div>
|
||||
{/if}
|
||||
</td>
|
||||
<td class="text-sm text-base-content/60">{artist.createdAt}</td>
|
||||
<td class="text-sm text-base-content/50">{artist.createdAt}</td>
|
||||
<td>
|
||||
<div class="flex flex-wrap gap-1">
|
||||
<label class="label cursor-pointer gap-1">
|
||||
<div class="flex flex-wrap gap-1.5">
|
||||
<label class="label cursor-pointer gap-1.5 p-1">
|
||||
<input type="checkbox" class="checkbox checkbox-xs checkbox-primary"
|
||||
{#if artist.albumMonitored}checked{/if}
|
||||
hx-patch="/api/artists/{artist.mbid}/monitor?type=album"
|
||||
hx-target="#artist-list"
|
||||
hx-swap="innerHTML">
|
||||
<span class="label-text text-xs">Album</span>
|
||||
<span class="label-text text-xs font-medium text-primary">Album</span>
|
||||
</label>
|
||||
<label class="label cursor-pointer gap-1">
|
||||
<input type="checkbox" class="checkbox checkbox-xs"
|
||||
<label class="label cursor-pointer gap-1.5 p-1">
|
||||
<input type="checkbox" class="checkbox checkbox-xs checkbox-secondary"
|
||||
{#if artist.singleMonitored}checked{/if}
|
||||
hx-patch="/api/artists/{artist.mbid}/monitor?type=single"
|
||||
hx-target="#artist-list"
|
||||
hx-swap="innerHTML">
|
||||
<span class="label-text text-xs">Single</span>
|
||||
<span class="label-text text-xs font-medium text-secondary">Single</span>
|
||||
</label>
|
||||
<label class="label cursor-pointer gap-1">
|
||||
<input type="checkbox" class="checkbox checkbox-xs"
|
||||
<label class="label cursor-pointer gap-1.5 p-1">
|
||||
<input type="checkbox" class="checkbox checkbox-xs checkbox-accent"
|
||||
{#if artist.epMonitored}checked{/if}
|
||||
hx-patch="/api/artists/{artist.mbid}/monitor?type=ep"
|
||||
hx-target="#artist-list"
|
||||
hx-swap="innerHTML">
|
||||
<span class="label-text text-xs">EP</span>
|
||||
<span class="label-text text-xs font-medium text-accent">EP</span>
|
||||
</label>
|
||||
<label class="label cursor-pointer gap-1">
|
||||
<label class="label cursor-pointer gap-1.5 p-1">
|
||||
<input type="checkbox" class="checkbox checkbox-xs"
|
||||
{#if artist.broadcastMonitored}checked{/if}
|
||||
hx-patch="/api/artists/{artist.mbid}/monitor?type=broadcast"
|
||||
hx-target="#artist-list"
|
||||
hx-swap="innerHTML">
|
||||
<span class="label-text text-xs">Broadcast</span>
|
||||
<span class="label-text text-xs text-base-content/60">Broadcast</span>
|
||||
</label>
|
||||
<label class="label cursor-pointer gap-1">
|
||||
<label class="label cursor-pointer gap-1.5 p-1">
|
||||
<input type="checkbox" class="checkbox checkbox-xs"
|
||||
{#if artist.otherMonitored}checked{/if}
|
||||
hx-patch="/api/artists/{artist.mbid}/monitor?type=other"
|
||||
hx-target="#artist-list"
|
||||
hx-swap="innerHTML">
|
||||
<span class="label-text text-xs">Other</span>
|
||||
<span class="label-text text-xs text-base-content/60">Other</span>
|
||||
</label>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<button class="btn btn-error btn-xs"
|
||||
<button class="btn btn-ghost btn-xs text-error hover:bg-error/10"
|
||||
hx-delete="/api/artists/{artist.mbid}"
|
||||
hx-target="#artist-list"
|
||||
hx-swap="innerHTML"
|
||||
onclick="return confirm('Remove {artist.name}?')">
|
||||
<svg class="w-4 h-4" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="3 6 5 6 21 6"/><path d="M19 6v14a2 2 0 01-2 2H7a2 2 0 01-2-2V6m3 0V4a2 2 0 012-2h4a2 2 0 012 2v2"/></svg>
|
||||
Remove
|
||||
</button>
|
||||
</td>
|
||||
|
||||
@@ -1,46 +1,60 @@
|
||||
{#if entries.isEmpty()}
|
||||
<div class="card bg-base-100 shadow-xl p-8 text-center">
|
||||
<p class="text-lg text-base-content/60">No releases found</p>
|
||||
<p class="text-sm text-base-content/40 mt-2">Add artists to your collection to see their releases here</p>
|
||||
<div class="card bg-base-100 shadow-xl p-10 text-center">
|
||||
<svg class="w-12 h-12 mx-auto text-base-content/20 mb-3" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
|
||||
<circle cx="6" cy="18" r="3"/><circle cx="18" cy="16" r="3"/>
|
||||
<path d="M9 18V5l12-2v13"/><path d="M9 9l12-2"/>
|
||||
</svg>
|
||||
<p class="text-lg font-medium text-base-content/60">No releases found</p>
|
||||
<p class="text-sm text-base-content/40 mt-1">Add artists to your collection to see their releases here</p>
|
||||
</div>
|
||||
{#else}
|
||||
<div class="overflow-x-auto">
|
||||
<table class="table table-zebra">
|
||||
<div class="overflow-x-auto rounded-box border border-base-300">
|
||||
<table class="table table-pin-rows">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Cover</th>
|
||||
<tr class="bg-base-200/80">
|
||||
<th class="w-20">Cover</th>
|
||||
<th>Artist</th>
|
||||
<th>Release</th>
|
||||
<th>Type</th>
|
||||
<th>Date</th>
|
||||
<th class="w-28">Date</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{#for entry in entries}
|
||||
<tr>
|
||||
<tr class="hover:bg-base-200/50 transition-colors">
|
||||
<td>
|
||||
<a href="https://musicbrainz.org/release-group/{entry.mbid}"
|
||||
target="_blank" rel="noopener noreferrer">
|
||||
<img src="https://coverartarchive.org/release-group/{entry.mbid}/front"
|
||||
<img src="https://coverartarchive.org/release-group/{entry.mbid}/front-250"
|
||||
alt="Cover"
|
||||
width="48" height="48"
|
||||
style="width:48px;height:48px;object-fit:cover;border-radius:6px"
|
||||
width="64" height="64"
|
||||
style="width:64px;height:64px;object-fit:cover;border-radius:8px"
|
||||
loading="lazy"
|
||||
onerror="this.src='data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 48 48%22><rect width=%2248%22 height=%2248%22 fill=%22%23333%22/><text x=%2224%22 y=%2230%22 text-anchor=%22middle%22 fill=%22%23999%22 font-size=%2210%22>No Art</text></svg>'">
|
||||
onerror="this.style.display='none'">
|
||||
</a>
|
||||
</td>
|
||||
<td class="font-medium">{entry.artistName}</td>
|
||||
<td>
|
||||
<span class="font-medium">{entry.artistName}</span>
|
||||
</td>
|
||||
<td>
|
||||
<a href="https://musicbrainz.org/release-group/{entry.mbid}"
|
||||
target="_blank" rel="noopener noreferrer"
|
||||
class="link link-hover">
|
||||
class="link link-hover font-medium">
|
||||
{entry.title}
|
||||
</a>
|
||||
</td>
|
||||
<td>
|
||||
<span class="badge badge-outline badge-sm">{entry.primaryType}</span>
|
||||
{#if entry.primaryType == 'Album'}
|
||||
<span class="badge badge-primary badge-sm">Album</span>
|
||||
{#else if entry.primaryType == 'Single'}
|
||||
<span class="badge badge-secondary badge-sm">Single</span>
|
||||
{#else if entry.primaryType == 'EP'}
|
||||
<span class="badge badge-accent badge-sm">EP</span>
|
||||
{#else}
|
||||
<span class="badge badge-ghost badge-sm">{entry.primaryType}</span>
|
||||
{/if}
|
||||
</td>
|
||||
<td class="text-sm text-base-content/60">{entry.firstReleaseDate}</td>
|
||||
<td class="text-sm text-base-content/50">{entry.firstReleaseDate}</td>
|
||||
</tr>
|
||||
{/for}
|
||||
</tbody>
|
||||
|
||||
@@ -1,27 +1,37 @@
|
||||
<div class="bg-base-100 shadow-xl border border-base-300 rounded-box mt-1 max-h-64 overflow-y-auto">
|
||||
<div class="card bg-base-100 shadow-xl border border-base-300 mt-1 max-h-72 overflow-y-auto">
|
||||
{#if artists.isEmpty()}
|
||||
<div class="p-3 text-sm text-base-content/60">No artists found</div>
|
||||
<div class="p-4 text-sm text-base-content/50 text-center">No artists found</div>
|
||||
{#else}
|
||||
{#for artist in artists}
|
||||
<div class="flex items-center justify-between p-3 hover:bg-base-200 border-b border-base-200 last:border-b-0">
|
||||
<div class="flex-1 min-w-0">
|
||||
<span class="font-medium">{artist.name}</span>
|
||||
{#if artist.disambiguation}
|
||||
<span class="text-sm text-base-content/60">— {artist.disambiguation}</span>
|
||||
<div class="flex items-center justify-between p-3 hover:bg-primary/10 transition-colors border-b border-base-200 last:border-b-0">
|
||||
<div class="flex-1 min-w-0 mr-2">
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="font-semibold text-sm">{artist.name}</span>
|
||||
{#if artist.type}
|
||||
<span class="badge badge-ghost badge-xs">{artist.type}</span>
|
||||
{/if}
|
||||
<br>
|
||||
<span class="text-xs text-base-content/40">{artist.area}</span>
|
||||
</div>
|
||||
<div class="ml-2 flex-shrink-0">
|
||||
{#if artist.disambiguation}
|
||||
<div class="text-xs text-base-content/50 truncate">{artist.disambiguation}</div>
|
||||
{/if}
|
||||
{#if artist.area}
|
||||
<div class="text-xs text-base-content/40">{artist.area}</div>
|
||||
{/if}
|
||||
</div>
|
||||
<div class="flex-shrink-0">
|
||||
{#if artist.alreadyTracked}
|
||||
<span class="badge badge-success badge-sm">✓ Added</span>
|
||||
<span class="badge badge-success badge-sm gap-1">
|
||||
<svg class="w-3 h-3" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3"><polyline points="20 6 9 17 4 12"/></svg>
|
||||
Added
|
||||
</span>
|
||||
{#else}
|
||||
<button class="btn btn-primary btn-xs"
|
||||
hx-post="/api/artists/{artist.mbid}/track"
|
||||
hx-target="#search-results"
|
||||
hx-swap="innerHTML"
|
||||
onclick="document.getElementById('search-input').value=''">
|
||||
+ Add
|
||||
<svg class="w-3 h-3" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><line x1="12" y1="5" x2="12" y2="19"/><line x1="5" y1="12" x2="19" y2="12"/></svg>
|
||||
Add
|
||||
</button>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
@@ -18,6 +18,9 @@
|
||||
z-index: 50;
|
||||
width: 100%;
|
||||
}
|
||||
body {
|
||||
margin: 0;
|
||||
}
|
||||
</style>
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
@@ -32,19 +35,30 @@
|
||||
</script>
|
||||
</head>
|
||||
<body class="min-h-screen bg-base-200">
|
||||
<div class="navbar bg-base-100 shadow-lg px-4">
|
||||
<div class="navbar bg-base-100 shadow-lg px-6">
|
||||
<div class="navbar-start">
|
||||
<div class="flex items-center gap-2">
|
||||
<a href="/" class="text-xl font-bold">🎵 DiscDrop</a>
|
||||
<div class="tabs tabs-box ml-2 hidden sm:flex">
|
||||
<a href="/" class="tab {#if activeTab == 'releases'}tab-active{/if}">Releases</a>
|
||||
<a href="/artists" class="tab {#if activeTab == 'artists'}tab-active{/if}">Artists</a>
|
||||
<div class="flex items-center gap-3">
|
||||
<a href="/" class="flex items-center gap-2 no-underline">
|
||||
<svg class="w-7 h-7 text-primary" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<circle cx="6" cy="18" r="3"/>
|
||||
<circle cx="18" cy="16" r="3"/>
|
||||
<path d="M9 18V5l12-2v13"/>
|
||||
<path d="M9 9l12-2"/>
|
||||
</svg>
|
||||
<div>
|
||||
<span class="text-xl font-extrabold bg-gradient-to-r from-primary to-accent bg-clip-text text-transparent">DiscDrop</span>
|
||||
<span class="text-xs text-base-content/50 hidden sm:block leading-none -mt-0.5">Release Groups Feed</span>
|
||||
</div>
|
||||
</a>
|
||||
<div class="tabs tabs-box ml-4 hidden sm:flex">
|
||||
<a href="/" class="tab tab-sm {#if activeTab == 'releases'}tab-active{/if}">Releases</a>
|
||||
<a href="/artists" class="tab tab-sm {#if activeTab == 'artists'}tab-active{/if}">Artists</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="navbar-center">
|
||||
<div id="search-wrapper" class="w-48 md:w-64">
|
||||
<div id="search-wrapper" class="w-72 md:w-80 lg:w-96">
|
||||
<form hx-get="/api/artists/search"
|
||||
hx-target="#search-results"
|
||||
hx-swap="innerHTML"
|
||||
@@ -63,7 +77,7 @@
|
||||
<div class="navbar-end gap-2">
|
||||
<select class="select select-bordered select-sm w-full max-w-[8rem]"
|
||||
onchange="setTheme(this)">
|
||||
<option value="dark" selected>Dark</option>
|
||||
<option value="dark">Dark</option>
|
||||
<option value="light">Light</option>
|
||||
<option value="synthwave">Synthwave</option>
|
||||
<option value="retro">Retro</option>
|
||||
@@ -78,7 +92,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<main class="container mx-auto p-4">
|
||||
<main class="max-w-5xl mx-auto px-4 sm:px-6 py-6">
|
||||
{#insert page-content}{/insert}
|
||||
</main>
|
||||
|
||||
|
||||
@@ -1,13 +1,26 @@
|
||||
{#include layouts/base}
|
||||
{#page-content}
|
||||
<div class="w-full max-w-4xl mx-auto">
|
||||
<h2 class="text-2xl font-bold mb-4 text-center">📡 Releases</h2>
|
||||
<div id="feed-entries" hx-get="/api/artists/feed-table" hx-trigger="load">
|
||||
<span class="loading loading-spinner loading-lg block mx-auto"></span>
|
||||
<div class="w-full">
|
||||
<div class="flex items-center justify-between mb-5">
|
||||
<h2 class="text-2xl font-bold">📡 Releases</h2>
|
||||
<div class="flex gap-2">
|
||||
<a href="/feed/rss.xml" class="btn btn-primary btn-sm gap-2">
|
||||
<svg class="w-4 h-4" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M4 11a9 9 0 019 9"/><path d="M4 4a16 16 0 0116 16"/>
|
||||
<circle cx="5" cy="19" r="1"/>
|
||||
</svg>
|
||||
RSS Feed
|
||||
</a>
|
||||
<a href="/feed/opml" class="btn btn-ghost btn-sm gap-2">
|
||||
<svg class="w-4 h-4" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M21 15v4a2 2 0 01-2 2H5a2 2 0 01-2-2v-4"/><polyline points="7 10 12 15 17 10"/><line x1="12" y1="15" x2="12" y2="3"/></svg>
|
||||
OPML
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div id="feed-entries" hx-get="/api/artists/feed-table" hx-trigger="load">
|
||||
<div class="flex justify-center my-16">
|
||||
<span class="loading loading-spinner loading-lg"></span>
|
||||
</div>
|
||||
<div class="mt-6 flex justify-center gap-4">
|
||||
<a href="/feed/rss.xml" class="btn btn-primary">📥 RSS Feed</a>
|
||||
<a href="/feed/opml" class="btn btn-ghost">📋 OPML</a>
|
||||
</div>
|
||||
</div>
|
||||
{/page-content}
|
||||
|
||||
Reference in New Issue
Block a user