mirror of
https://github.com/svemagie/blog-eleventy-indiekit.git
synced 2026-04-02 16:44:56 +02:00
fix: show inline reply form under webmention cards
Reply buttons on webmention interactions (Bluesky, Mastodon, IndieWeb) now show an inline reply form directly under the card instead of delegating to the hidden Comments section. The form posts via Micropub with optional syndication targeting. Confab-Link: http://localhost:8080/sessions/184584f4-67e1-485a-aba8-02ac34a600fe
This commit is contained in:
@@ -617,6 +617,62 @@
|
||||
|
||||
// Wire reply buttons: unhide and attach click handlers for unwired buttons
|
||||
// Called from owner:detected handler AND after dynamic replies are appended
|
||||
// Close any open inline reply form
|
||||
function closeActiveReplyForm() {
|
||||
var existing = document.querySelector('.wm-inline-reply-form');
|
||||
if (existing) existing.remove();
|
||||
}
|
||||
|
||||
// Submit a Micropub reply
|
||||
function submitMicropubReply(replyUrl, platform, syndicateTo, textarea, statusEl, submitBtn) {
|
||||
var content = textarea.value.trim();
|
||||
if (!content) return;
|
||||
|
||||
submitBtn.disabled = true;
|
||||
submitBtn.textContent = 'Sending...';
|
||||
statusEl.textContent = '';
|
||||
|
||||
var body = {
|
||||
type: ['h-entry'],
|
||||
properties: {
|
||||
content: [content],
|
||||
'in-reply-to': [replyUrl]
|
||||
}
|
||||
};
|
||||
|
||||
if (syndicateTo) {
|
||||
body.properties['mp-syndicate-to'] = [syndicateTo];
|
||||
} else {
|
||||
body.properties['mp-syndicate-to'] = [];
|
||||
}
|
||||
|
||||
fetch('/micropub', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json', Accept: 'application/json' },
|
||||
credentials: 'include',
|
||||
body: JSON.stringify(body)
|
||||
}).then(function(res) {
|
||||
if (res.ok || res.status === 201 || res.status === 202) {
|
||||
statusEl.className = 'text-xs text-green-600 dark:text-green-400 mt-1';
|
||||
statusEl.textContent = 'Reply posted' + (syndicateTo ? ' and syndicated!' : '!');
|
||||
textarea.value = '';
|
||||
setTimeout(closeActiveReplyForm, 2000);
|
||||
} else {
|
||||
return res.json().catch(function() { return {}; }).then(function(data) {
|
||||
statusEl.className = 'text-xs text-red-600 dark:text-red-400 mt-1';
|
||||
statusEl.textContent = data.error_description || data.error || 'Failed to post reply';
|
||||
submitBtn.disabled = false;
|
||||
submitBtn.textContent = 'Send Reply';
|
||||
});
|
||||
}
|
||||
}).catch(function(err) {
|
||||
statusEl.className = 'text-xs text-red-600 dark:text-red-400 mt-1';
|
||||
statusEl.textContent = 'Error: ' + err.message;
|
||||
submitBtn.disabled = false;
|
||||
submitBtn.textContent = 'Send Reply';
|
||||
});
|
||||
}
|
||||
|
||||
function wireReplyButtons() {
|
||||
var ownerStore = Alpine.store && Alpine.store('owner');
|
||||
if (!ownerStore || !ownerStore.isOwner) return;
|
||||
@@ -632,15 +688,59 @@
|
||||
if (platform === 'bluesky') syndicateTo = ownerStore.syndicationTargets.bluesky || null;
|
||||
if (platform === 'mastodon') syndicateTo = ownerStore.syndicationTargets.mastodon || null;
|
||||
|
||||
// Find the commentsSection Alpine component and call startReply
|
||||
var commentsEl = document.querySelector('[x-data*="commentsSection"]');
|
||||
if (commentsEl && window.Alpine) {
|
||||
var data = Alpine.$data(commentsEl);
|
||||
if (data && data.startReply) {
|
||||
data.startReply(replyUrl, platform, replyUrl, syndicateTo);
|
||||
commentsEl.scrollIntoView({ behavior: 'smooth', block: 'start' });
|
||||
}
|
||||
// Close any existing reply form
|
||||
closeActiveReplyForm();
|
||||
|
||||
// Find the owner-reply-slot next to this webmention card
|
||||
var li = btn.closest('li') || btn.closest('.webmention-reply');
|
||||
var slot = li ? li.querySelector('.wm-owner-reply-slot') : null;
|
||||
if (!slot) {
|
||||
// Fallback: insert after the button's parent
|
||||
slot = document.createElement('div');
|
||||
btn.parentElement.after(slot);
|
||||
}
|
||||
|
||||
// Build inline reply form
|
||||
var form = document.createElement('div');
|
||||
form.className = 'wm-inline-reply-form mt-2 p-3 bg-surface-100 dark:bg-surface-900 rounded-lg border-l-2 border-primary-400';
|
||||
|
||||
var label = document.createElement('div');
|
||||
label.className = 'text-xs text-surface-500 dark:text-surface-400 mb-1';
|
||||
label.textContent = 'Replying via ' + platform + (syndicateTo ? ' (will syndicate)' : '');
|
||||
|
||||
var textarea = document.createElement('textarea');
|
||||
textarea.rows = 3;
|
||||
textarea.placeholder = 'Write your reply...';
|
||||
textarea.className = 'w-full px-3 py-2 border rounded-lg text-sm dark:bg-surface-800 dark:border-surface-700 dark:text-surface-100';
|
||||
|
||||
var actions = document.createElement('div');
|
||||
actions.className = 'flex items-center gap-2 mt-2';
|
||||
|
||||
var submitBtn = document.createElement('button');
|
||||
submitBtn.className = 'button text-sm';
|
||||
submitBtn.textContent = 'Send Reply';
|
||||
|
||||
var cancelBtn = document.createElement('button');
|
||||
cancelBtn.className = 'text-xs text-surface-500 hover:underline';
|
||||
cancelBtn.textContent = 'Cancel';
|
||||
|
||||
var statusEl = document.createElement('div');
|
||||
statusEl.className = 'text-xs mt-1';
|
||||
|
||||
submitBtn.addEventListener('click', function() {
|
||||
submitMicropubReply(replyUrl, platform, syndicateTo, textarea, statusEl, submitBtn);
|
||||
});
|
||||
cancelBtn.addEventListener('click', closeActiveReplyForm);
|
||||
|
||||
actions.appendChild(submitBtn);
|
||||
actions.appendChild(cancelBtn);
|
||||
form.appendChild(label);
|
||||
form.appendChild(textarea);
|
||||
form.appendChild(actions);
|
||||
form.appendChild(statusEl);
|
||||
slot.appendChild(form);
|
||||
|
||||
textarea.focus();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user