import { renderMarkdown } from '../lib/markdown' import type { Post } from '../types' import { escapeHtml, escapeAttr, formatDateJa } from '../lib/util' // Note post has extra fields for member content interface NotePost extends Post { value: Post['value'] & { member?: { text: string bonus?: string } } } // Render note list page export function renderNoteListPage(posts: NotePost[], handle: string): string { if (posts.length === 0) { return `
No note articles yet.
` } const items = posts.map(post => { const rkey = post.uri.split('/').pop() || '' const date = new Date(post.value.publishedAt).toLocaleDateString('ja-JP', { year: 'numeric', month: '2-digit', day: '2-digit' }) const tags = post.value.tags?.map(t => `${t}`).join('') || '' return `
${date} ${escapeHtml(post.value.title)} ${tags ? `
${tags}
` : ''}
` }).join('') return `
${items}
` } // Render single note detail with preview + copy export function renderNoteDetailPage( post: NotePost, _handle: string, isOwner: boolean ): string { const rkey = post.uri.split('/').pop() || '' const date = formatDateJa(post.value.publishedAt) const freeText = post.value.content?.text || '' const memberText = post.value.member?.text || '' const bonusText = post.value.member?.bonus || '' const freeHtml = renderMarkdown(freeText) const memberHtml = memberText ? renderMarkdown(memberText) : '' const bonusHtml = bonusText ? renderMarkdown(bonusText) : '' let html = '' // Action buttons at top if (isOwner) { html += `
` } html += `

${escapeHtml(post.value.title)}

${date}
${freeHtml}
` if (memberText) { html += `
── 有料ライン ──
${memberHtml}
` } if (bonusText) { html += `
${bonusHtml}
` } html += `
` // Edit form (below content) if (isOwner) { html += ` ` } return html } // Setup note detail page (copy + edit handlers) export function setupNoteDetail( post: NotePost, _onSave?: (rkey: string, record: Record) => Promise ): void { const freeText = post.value.content?.text || '' const memberText = post.value.member?.text || '' const bonusText = post.value.member?.bonus || '' // Copy buttons const copyTitle = document.getElementById('note-copy-title') const copyAll = document.getElementById('note-copy-all') const copyStatus = document.getElementById('note-copy-status') function copyToClipboard(text: string) { navigator.clipboard.writeText(text).then(() => { if (copyStatus) { copyStatus.textContent = 'Copied!' setTimeout(() => { copyStatus.textContent = '' }, 2000) } }) } copyTitle?.addEventListener('click', () => copyToClipboard(post.value.title)) copyAll?.addEventListener('click', () => { const parts = [freeText, memberText, bonusText].filter(Boolean) copyToClipboard(parts.join('\n\n')) }) // Edit toggle const editBtn = document.getElementById('note-edit-btn') const editForm = document.getElementById('note-edit-form') const display = document.getElementById('note-display') const cancelBtn = document.getElementById('note-edit-cancel') const saveBtn = document.getElementById('note-edit-save') editBtn?.addEventListener('click', () => { if (display) display.style.display = 'none' if (editForm) editForm.style.display = 'block' if (editBtn) editBtn.style.display = 'none' }) cancelBtn?.addEventListener('click', () => { if (editForm) editForm.style.display = 'none' if (display) display.style.display = '' if (editBtn) editBtn.style.display = '' }) saveBtn?.addEventListener('click', () => { const rkey = saveBtn.getAttribute('data-rkey') if (!rkey) return const title = (document.getElementById('note-edit-title') as HTMLInputElement)?.value.trim() const free = (document.getElementById('note-edit-free') as HTMLTextAreaElement)?.value.trim() const member = (document.getElementById('note-edit-member') as HTMLTextAreaElement)?.value.trim() const bonus = (document.getElementById('note-edit-bonus') as HTMLTextAreaElement)?.value.trim() if (!title || !free) { alert('Title and content are required') return } const did = post.uri.split('/')[2] const record: Record = { cid: '', uri: post.uri, value: { $type: 'ai.syui.note.post', site: post.value.site, title, content: { $type: 'ai.syui.note.post#markdown', text: free, }, publishedAt: post.value.publishedAt, langs: post.value.langs || ['ja'], tags: post.value.tags || [], } as Record, } if (member || bonus) { const memberObj: Record = {} if (member) memberObj.text = member if (bonus) memberObj.bonus = bonus ;(record.value as Record).member = memberObj } const json = JSON.stringify(record, null, 2) navigator.clipboard.writeText(json).then(() => { const statusEl = document.getElementById('note-edit-status') const filePath = `public/at/${did}/ai.syui.note.post/${rkey}.json` if (statusEl) { statusEl.innerHTML = `JSON copied! Paste to: ${filePath}` } }) }) }