From e2d324500d48080f178dbeeb8b3f49daeda9302b Mon Sep 17 00:00:00 2001 From: syui Date: Thu, 15 Jan 2026 17:41:53 +0900 Subject: [PATCH] add post fix --- src/components/posts.ts | 75 ++++++++++++++++++++++++++++--- src/lib/auth.ts | 24 ++++++++++ src/main.ts | 3 +- src/styles/main.css | 97 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 191 insertions(+), 8 deletions(-) diff --git a/src/components/posts.ts b/src/components/posts.ts index 817d146..b1f4c11 100644 --- a/src/components/posts.ts +++ b/src/components/posts.ts @@ -1,4 +1,5 @@ import type { BlogPost } from '../types.js' +import { putRecord } from '../lib/auth.js' function formatDate(dateStr: string): string { const date = new Date(dateStr) @@ -38,17 +39,77 @@ export function mountPostList(container: HTMLElement, posts: BlogPost[]): void { container.innerHTML = `` } -export function mountPostDetail(container: HTMLElement, post: BlogPost, handle: string): void { +export function mountPostDetail(container: HTMLElement, post: BlogPost, handle: string, collection: string, canEdit: boolean = false): void { + const rkey = post.uri.split('/').pop() || '' + const jsonUrl = `?mode=browser&handle=${handle}&collection=${encodeURIComponent(collection)}&rkey=${rkey}` + + const editBtn = canEdit ? `` : '' + container.innerHTML = `
-

${escapeHtml(post.title)}

- +

${escapeHtml(post.title)}

+
-
${escapeHtml(post.content)}
- +
${escapeHtml(post.content)}
+ + ` + + if (canEdit) { + const editBtnEl = document.getElementById('edit-btn') + const editFormContainer = document.getElementById('edit-form-container') + const editForm = document.getElementById('edit-form') as HTMLFormElement + const editCancel = document.getElementById('edit-cancel') + const postArticle = container.querySelector('.post-detail') as HTMLElement + + editBtnEl?.addEventListener('click', () => { + postArticle.style.display = 'none' + editFormContainer!.style.display = 'block' + }) + + editCancel?.addEventListener('click', () => { + postArticle.style.display = 'block' + editFormContainer!.style.display = 'none' + }) + + editForm?.addEventListener('submit', async (e) => { + e.preventDefault() + const title = (document.getElementById('edit-title') as HTMLInputElement).value + const content = (document.getElementById('edit-content') as HTMLTextAreaElement).value + const submitBtn = document.getElementById('edit-submit') as HTMLButtonElement + + try { + submitBtn.disabled = true + submitBtn.textContent = 'Saving...' + + await putRecord(collection, rkey, { + title, + content, + createdAt: post.createdAt, + }) + + window.location.reload() + } catch (err) { + alert('Save failed: ' + err) + submitBtn.disabled = false + submitBtn.textContent = 'Save' + } + }) + } } diff --git a/src/lib/auth.ts b/src/lib/auth.ts index e80d91c..300fcb0 100644 --- a/src/lib/auth.ts +++ b/src/lib/auth.ts @@ -161,3 +161,27 @@ export async function deleteRecord(collection: string, rkey: string): Promise +): Promise<{ uri: string; cid: string } | null> { + if (!agent) return null + + try { + const result = await agent.com.atproto.repo.putRecord({ + repo: agent.assertDid, + collection, + rkey, + record: { + $type: collection, + ...record, + }, + }) + return { uri: result.data.uri, cid: result.data.cid } + } catch (err) { + console.error('Put record error:', err) + throw err + } +} diff --git a/src/main.ts b/src/main.ts index 5b4d1ed..743f23a 100644 --- a/src/main.ts +++ b/src/main.ts @@ -142,7 +142,8 @@ async function init(): Promise { if (rkey) { const post = await getRecord(profile.did, config.collection, rkey) if (post) { - mountPostDetail(contentEl, post, handle) + const canEdit = isLoggedIn && authSession?.did === profile.did + mountPostDetail(contentEl, post, handle, config.collection, canEdit) } else { contentEl.innerHTML = '

Post not found

' } diff --git a/src/styles/main.css b/src/styles/main.css index 9027347..311e1d1 100644 --- a/src/styles/main.css +++ b/src/styles/main.css @@ -288,6 +288,97 @@ body { color: #333; } +.edit-btn { + display: inline-flex; + align-items: center; + justify-content: center; + padding: 4px 8px; + background: #28a745; + color: #fff; + border: none; + border-radius: 4px; + text-decoration: none; + font-family: monospace; + font-size: 12px; + cursor: pointer; +} + +.edit-btn:hover { + background: #218838; +} + +/* Edit Form */ +.edit-form-container { + padding: 20px 0; +} + +.edit-form-container h3 { + font-size: 18px; + margin-bottom: 16px; +} + +.edit-form { + display: flex; + flex-direction: column; + gap: 12px; +} + +.edit-form-title { + padding: 10px 12px; + border: 1px solid #ddd; + border-radius: 6px; + font-size: 16px; +} + +.edit-form-body { + padding: 10px 12px; + border: 1px solid #ddd; + border-radius: 6px; + font-size: 14px; + resize: vertical; + min-height: 200px; + font-family: inherit; +} + +.edit-form-footer { + display: flex; + justify-content: flex-end; + gap: 8px; +} + +.edit-cancel-btn { + padding: 10px 24px; + background: #6c757d; + color: #fff; + border: none; + border-radius: 6px; + font-size: 14px; + cursor: pointer; +} + +.edit-cancel-btn:hover { + background: #5a6268; +} + +.edit-submit-btn { + padding: 10px 24px; + background: #28a745; + color: #fff; + border: none; + border-radius: 6px; + font-size: 14px; + cursor: pointer; +} + +.edit-submit-btn:hover { + background: #218838; +} + +.edit-submit-btn:disabled { + background: #ccc; + cursor: not-allowed; +} + .post-content { font-size: 16px; line-height: 1.8; @@ -549,6 +640,12 @@ body { background: #333; color: #e0e0e0; } + .edit-form-title, + .edit-form-body { + background: #1a1a1a; + border-color: #333; + color: #e0e0e0; + } .tab:hover { background: #333; }