diff --git a/_includes/layouts/base.njk b/_includes/layouts/base.njk
index 5d47014..ee216e8 100644
--- a/_includes/layouts/base.njk
+++ b/_includes/layouts/base.njk
@@ -453,6 +453,8 @@
{# Admin auth detection - shows dashboard link + FAB when logged in #}
+ {# Save for Later buttons — active when logged in #}
+
{# Floating Action Button - visible only when logged in #}
Visit Blog
+
diff --git a/css/tailwind.css b/css/tailwind.css
index 43062db..91c8fd4 100644
--- a/css/tailwind.css
+++ b/css/tailwind.css
@@ -741,3 +741,33 @@
display: none;
}
}
+
+/* Save for Later buttons — hidden until auth confirmed */
+.save-later-btn {
+ display: none;
+}
+
+body[data-indiekit-auth="true"] .save-later-btn {
+ display: inline-flex;
+ align-items: center;
+ gap: 4px;
+ cursor: pointer;
+ background: none;
+ border: 1px solid transparent;
+ border-radius: 6px;
+ padding: 2px 8px;
+ font-size: 0.75rem;
+ color: #6b7280;
+ transition: all 0.2s ease;
+}
+
+body[data-indiekit-auth="true"] .save-later-btn:hover {
+ border-color: #d1d5db;
+ color: #4a9eff;
+}
+
+.save-later--saved {
+ color: #4a9eff !important;
+ opacity: 0.6;
+ pointer-events: none;
+}
diff --git a/js/save-later.js b/js/save-later.js
new file mode 100644
index 0000000..eff4f33
--- /dev/null
+++ b/js/save-later.js
@@ -0,0 +1,51 @@
+/**
+ * Save for Later — shared frontend module
+ * Handles save button clicks on blogroll, podroll, listening, and news pages.
+ * Only active when user is logged in (body[data-indiekit-auth="true"]).
+ */
+(function () {
+ function isLoggedIn() {
+ return document.body.getAttribute('data-indiekit-auth') === 'true';
+ }
+
+ async function saveForLater(button) {
+ var url = button.dataset.saveUrl;
+ var title = button.dataset.saveTitle || url;
+ var source = button.dataset.saveSource || 'manual';
+ if (!url) return;
+
+ button.disabled = true;
+
+ try {
+ var response = await fetch('/readlater/save', {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify({ url: url, title: title, source: source }),
+ credentials: 'same-origin'
+ });
+
+ if (response.ok) {
+ button.classList.add('save-later--saved');
+ button.title = 'Saved';
+ button.setAttribute('aria-label', 'Saved');
+ var label = button.querySelector('.save-later-label');
+ if (label) label.textContent = 'Saved';
+ var icon = button.querySelector('.save-later-icon');
+ if (icon) icon.textContent = '🔖';
+ } else {
+ button.disabled = false;
+ }
+ } catch (e) {
+ button.disabled = false;
+ }
+ }
+
+ document.addEventListener('click', function (e) {
+ if (!isLoggedIn()) return;
+ var button = e.target.closest('.save-later-btn');
+ if (button) {
+ e.preventDefault();
+ saveForLater(button);
+ }
+ });
+})();
diff --git a/listening.njk b/listening.njk
index 2f9cfc4..3823fe4 100644
--- a/listening.njk
+++ b/listening.njk
@@ -295,6 +295,16 @@ withSidebar: true