Files
podstalk/template/dashboard.html
T
jbrechtel 0861f7510b
Build and Deploy / build-and-deploy (push) Failing after 13s
Per-user podcasts, file uploads, RSS images, Docker support
- Each user owns a podcast: podcast title/author/image on users table
- Episodes scoped by user_id with context-based auth
- Audio file upload replaces URL linking, served from /uploads/
- Podcast and per-episode images with itunes:image in RSS
- RSS per-user via ?user=N, dashboard shows user-specific feed URL
- Settings form for title + author + image per user
- Docker multi-stage build (golang:1.25-alpine / alpine:3.21)
- Removed PODSTALK_TITLE/AUTHOR env vars
2026-07-08 09:20:19 -04:00

139 lines
6.2 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Podstalk — Dashboard</title>
<link rel="stylesheet" href="https://unpkg.com/neobrutalismcss@latest" />
<style>
body { max-width: 960px; margin: 0 auto; padding: 2rem 1rem; }
.container { margin-top: 2rem; }
.flash { padding: 0.75rem 1rem; margin-bottom: 1rem; border: 2px solid #000; }
.flash-error { background: #ffcdd2; }
.flash-success { background: #c8e6c9; }
.episode-actions { display: flex; gap: 0.5rem; }
.settings-section { margin-bottom: 2rem; padding-bottom: 1.5rem; border-bottom: 2px solid #ddd; }
.settings-form { display: flex; gap: 1rem; align-items: flex-end; flex-wrap: wrap; }
.settings-form .form-group { margin-bottom: 0; }
.inline-form { display: flex; gap: 0.5rem; align-items: center; }
</style>
</head>
<body>
<nav class="nb-navbar" role="navigation" aria-label="Main navigation">
<a href="/" class="nb-navbar-brand" aria-label="Go to homepage">{{.PodcastTitle}}</a>
<ul class="nb-navbar-nav" role="menubar">
<li class="nb-navbar-item" role="none">
<a href="/" class="nb-navbar-link active" role="menuitem" aria-current="page">Dashboard</a>
</li>
<li class="nb-navbar-item" role="none">
<a href="/signout" class="nb-navbar-link" role="menuitem">Sign Out</a>
</li>
</ul>
</nav>
<div class="container">
<div class="settings-section">
<h2>Podcast Settings</h2>
<form method="post" action="/settings" enctype="multipart/form-data">
<div class="settings-form">
<div class="form-group" style="flex: 1; min-width: 200px;">
<label for="podcast_title">Podcast Title</label>
<input type="text" id="podcast_title" name="podcast_title" class="nb-input blue"
value="{{.PodcastTitle}}" />
</div>
<div class="form-group" style="flex: 1; min-width: 200px;">
<label for="podcast_author">Author</label>
<input type="text" id="podcast_author" name="podcast_author" class="nb-input blue"
value="{{.PodcastAuthor}}" placeholder="Podcast Host" />
</div>
<div class="form-group">
<label for="podcast_image">Podcast Image</label>
<input type="file" id="podcast_image" name="podcast_image" accept="image/*" />
</div>
<div class="form-group">
<button type="submit" class="nb-button green">Save</button>
</div>
</div>
</form>
{{if .PodcastImage}}
<div style="margin-top: 1rem;">
<img src="/uploads/{{.PodcastImage}}" alt="Podcast image" style="max-width: 150px; max-height: 150px; border: 2px solid #000;" />
</div>
{{end}}
</div>
<div class="nb-card" style="margin-bottom: 1.5rem;">
<div class="nb-card-content">
<h4 class="nb-card-title">RSS Feed</h4>
<p class="nb-card-text">
<code id="rss-url"></code>
<button class="nb-button default" onclick="copyRSS()" style="margin-left: 0.5rem;">Copy</button>
</p>
</div>
</div>
<script>
const rssURL = '{{.BaseURL}}/rss?user={{.UserID}}';
document.getElementById('rss-url').textContent = rssURL;
function copyRSS() {
navigator.clipboard.writeText(rssURL).then(() => {
const btn = event.target;
btn.textContent = 'Copied!';
setTimeout(() => btn.textContent = 'Copy', 1500);
});
}
</script>
<h2>Episodes</h2>
<div style="margin-bottom: 1.5rem;">
<a href="/episodes/new" class="nb-button blue">+ New Episode</a>
</div>
{{if .Episodes}}
<div class="nb-table-container">
<div class="nb-table-header">All Episodes ({{len .Episodes}})</div>
<table class="nb-table">
<thead>
<tr>
<th>Title</th>
<th>Image</th>
<th>Published</th>
<th>Audio</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
{{range .Episodes}}
<tr>
<td>{{.Title}}</td>
<td>
{{$img := .ImagePath}}
{{if not $img}}{{$img = $.PodcastImage}}{{end}}
{{if $img}}<img src="/uploads/{{$img}}" style="max-width: 48px; max-height: 48px; border: 1px solid #000;" />{{else}}—{{end}}
</td>
<td>{{.PublishedAt.Format "Jan 2, 2006"}}</td>
<td>{{if .AudioPath}}✓{{else}}—{{end}}</td>
<td>
<div class="episode-actions">
<a href="/episodes/edit?id={{.ID}}" class="nb-button default">Edit</a>
<form method="post" action="/episodes/delete?id={{.ID}}" style="display:inline" onsubmit="return confirm('Delete this episode?')">
<button type="submit" class="nb-button orange">Delete</button>
</form>
</div>
</td>
</tr>
{{end}}
</tbody>
</table>
</div>
{{else}}
<div class="nb-card">
<div class="nb-card-content">
<h4 class="nb-card-title">No episodes yet</h4>
<p class="nb-card-text">Create your first episode to get started.</p>
</div>
</div>
{{end}}
</div>
</body>
</html>