diff --git a/swa/app.js b/swa/app.js index 715f979..1a83490 100644 --- a/swa/app.js +++ b/swa/app.js @@ -57,6 +57,7 @@ const followsStatus = document.getElementById('follows-status'); const followsList = document.getElementById('follows-list'); const postContent = document.getElementById('post-content'); +const postSubject = document.getElementById('post-subject'); const charCount = document.getElementById('char-count'); const postBtn = document.getElementById('post-btn'); const postResult = document.getElementById('post-result'); @@ -770,11 +771,15 @@ postBtn.addEventListener('click', async () => { setPostResult(store.postDifficulty > 0 ? 'Mining proof of work…' : 'Publishing…', ''); try { - const { content: transformedContent, tags: mentionTags } = buildMentionEvent(content); - const event = await createOwnEvent({ kind: 1, tags: mentionTags, content: transformedContent, difficulty: store.postDifficulty }); + const subject = postSubject.value.trim(); + const subjectTags = subject ? [['subject', subject]] : []; + const { content: transformedContent, tags: mentionTags } = buildMentionEvent(content, subjectTags.length); + const tags = [...subjectTags, ...mentionTags]; + const event = await createOwnEvent({ kind: 1, tags, content: transformedContent, difficulty: store.postDifficulty }); await publishToAll(event); store.addEvent(event); postContent.value = ''; + postSubject.value = ''; charCount.textContent = '0'; setPostResult('Posted.', 'ok'); } catch (err) { @@ -1472,14 +1477,15 @@ function makeRenderCallbacks() { rerenderFeed(); try { await publishFollowList(); } catch { /* ignore relay error */ } }, - onReply: async (parentEvent, content) => { + onReply: async (parentEvent, content, subject) => { if (!store.signer) throw new Error('Generate or import a keypair first.'); if (!isAnyConnected()) throw new Error('Connect to a relay first.'); + const subjectTags = subject ? [['subject', subject]] : []; const replyTags = buildReplyTags(parentEvent, store.signer.pubkeyHex); - const { content: transformedContent, tags: mentionTags } = buildMentionEvent(content, replyTags.length); + const { content: transformedContent, tags: mentionTags } = buildMentionEvent(content, subjectTags.length + replyTags.length); const event = await createOwnEvent({ kind: 1, - tags: [...replyTags, ...mentionTags], + tags: [...subjectTags, ...replyTags, ...mentionTags], content: transformedContent, difficulty: store.postDifficulty, }); diff --git a/swa/feedView.js b/swa/feedView.js index 526d9bf..e1affd8 100644 --- a/swa/feedView.js +++ b/swa/feedView.js @@ -1,4 +1,4 @@ -import { resolveReplyTag } from './threading.js'; +import { resolveReplyTag, getSubject, adornReplySubject } from './threading.js'; import { getEventDifficulty } from './proofOfWork.js'; const OTS_VERIFY_URL = 'https://opentimestamps.org'; @@ -275,6 +275,14 @@ export function renderEvent(event, slice, callbacks) { actions.appendChild(deleteBtn); } + const subject = getSubject(event); + if (subject) { + const subjectEl = document.createElement('div'); + subjectEl.className = 'event-subject'; + subjectEl.textContent = subject; + card.appendChild(subjectEl); + } + card.append(content, actions); const replyForm = createReplyForm(event, displayName, onReply); @@ -316,6 +324,13 @@ function createReplyForm(parentEvent, displayName, onReply) { label.className = 'reply-form-label'; label.textContent = `Replying to ${displayName}`; + const subjectInput = document.createElement('input'); + subjectInput.type = 'text'; + subjectInput.className = 'reply-subject-input'; + subjectInput.placeholder = 'Subject (optional)'; + subjectInput.maxLength = 80; + subjectInput.value = adornReplySubject(getSubject(parentEvent)); + const textarea = document.createElement('textarea'); textarea.rows = 3; textarea.placeholder = 'Write your reply…'; @@ -334,7 +349,7 @@ function createReplyForm(parentEvent, displayName, onReply) { resultMsg.className = 'result-msg'; formActions.append(submitBtn, cancelBtn, resultMsg); - form.append(label, textarea, formActions); + form.append(label, subjectInput, textarea, formActions); cancelBtn.addEventListener('click', () => { form.hidden = true; @@ -351,7 +366,7 @@ function createReplyForm(parentEvent, displayName, onReply) { resultMsg.className = 'result-msg'; try { - await onReply(parentEvent, content); + await onReply(parentEvent, content, subjectInput.value.trim()); textarea.value = ''; form.hidden = true; resultMsg.textContent = ''; @@ -457,7 +472,15 @@ export function renderReply(event, slice) { content.className = 'event-content'; content.appendChild(renderMentionContent(event.content, event.tags, profiles)); - card.append(meta, content); + const subject = getSubject(event); + if (subject) { + const subjectEl = document.createElement('div'); + subjectEl.className = 'event-subject'; + subjectEl.textContent = subject; + card.append(meta, subjectEl, content); + } else { + card.append(meta, content); + } return card; } diff --git a/swa/index.html b/swa/index.html index 4b47331..a9d6d56 100644 --- a/swa/index.html +++ b/swa/index.html @@ -243,6 +243,7 @@