Slug-based RSS URLs and success flash messages
Build and Deploy / build-and-deploy (push) Successful in 45s
Build and Deploy / build-and-deploy (push) Successful in 45s
- Add podcast_slug to users with global uniqueness check
- RSS available at /rss/{slug} (path-based) with legacy ?slug= fallback
- Slug field in dashboard settings with validation (lowercase, hyphens)
- JS flash messages for success/error after form submissions
- Remove unused imports
This commit is contained in:
+32
-2
@@ -11,11 +11,12 @@
|
||||
.flash { padding: 0.75rem 1rem; margin-bottom: 1rem; border: 2px solid #000; }
|
||||
.flash-error { background: #ffcdd2; }
|
||||
.flash-success { background: #c8e6c9; }
|
||||
.flash-info { background: #e3f2fd; }
|
||||
.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; }
|
||||
.hidden { display: none; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
@@ -31,6 +32,9 @@
|
||||
</ul>
|
||||
</nav>
|
||||
<div class="container">
|
||||
<div id="flash-error" class="flash flash-error hidden"></div>
|
||||
<div id="flash-success" class="flash flash-success hidden"></div>
|
||||
|
||||
<div class="settings-section">
|
||||
<h2>Podcast Settings</h2>
|
||||
<form method="post" action="/settings" enctype="multipart/form-data">
|
||||
@@ -40,6 +44,11 @@
|
||||
<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: 160px;">
|
||||
<label for="podcast_slug">URL Slug</label>
|
||||
<input type="text" id="podcast_slug" name="podcast_slug" class="nb-input blue"
|
||||
value="{{.PodcastSlug}}" placeholder="my-podcast" />
|
||||
</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"
|
||||
@@ -71,7 +80,28 @@
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
const rssURL = '{{.BaseURL}}/rss?user={{.UserID}}';
|
||||
// Flash messages from query params
|
||||
(function() {
|
||||
const params = new URLSearchParams(window.location.search);
|
||||
const err = params.get('error');
|
||||
const ok = params.get('success');
|
||||
if (err) {
|
||||
const el = document.getElementById('flash-error');
|
||||
el.textContent = err.replace(/\+/g, ' ').replace(/%20/g, ' ');
|
||||
el.classList.remove('hidden');
|
||||
}
|
||||
if (ok) {
|
||||
const el = document.getElementById('flash-success');
|
||||
el.textContent = ok.replace(/\+/g, ' ').replace(/%20/g, ' ');
|
||||
el.classList.remove('hidden');
|
||||
}
|
||||
// Clean URL
|
||||
if (err || ok) {
|
||||
window.history.replaceState({}, '', window.location.pathname);
|
||||
}
|
||||
})();
|
||||
|
||||
const rssURL = '{{.BaseURL}}/rss/{{.PodcastSlug}}';
|
||||
document.getElementById('rss-url').textContent = rssURL;
|
||||
function copyRSS() {
|
||||
navigator.clipboard.writeText(rssURL).then(() => {
|
||||
|
||||
Reference in New Issue
Block a user