${collection}
URI: ${record.uri}
CID: ${record.cid}
+ ${deleteBtn}${escapeHtml(JSON.stringify(record.value, null, 2))}
diff --git a/src/web/components/discussion.ts b/src/web/components/discussion.ts
new file mode 100644
index 0000000..9b553f5
--- /dev/null
+++ b/src/web/components/discussion.ts
@@ -0,0 +1,105 @@
+import { searchPostsForUrl, type SearchPost } from '../lib/api'
+
+const DISCUSSION_POST_LIMIT = 10
+
+function escapeHtml(str: string): string {
+ return str
+ .replace(/&/g, '&')
+ .replace(//g, '>')
+ .replace(/"/g, '"')
+}
+
+function formatDate(dateStr: string): string {
+ const date = new Date(dateStr)
+ return date.toLocaleDateString('ja-JP', {
+ year: 'numeric',
+ month: '2-digit',
+ day: '2-digit',
+ })
+}
+
+function getPostUrl(uri: string, appUrl: string): string {
+ // at://did:plc:xxx/app.bsky.feed.post/rkey -> {appUrl}/profile/did:plc:xxx/post/rkey
+ const parts = uri.replace('at://', '').split('/')
+ if (parts.length >= 3) {
+ return `${appUrl}/profile/${parts[0]}/post/${parts[2]}`
+ }
+ return '#'
+}
+
+export function renderDiscussion(postUrl: string, appUrl: string = 'https://bsky.app'): string {
+ // Build search URL (truncate for search limit)
+ let searchQuery = postUrl
+ try {
+ const urlObj = new URL(postUrl)
+ const pathParts = urlObj.pathname.split('/').filter(Boolean)
+ const basePath = urlObj.host + '/' + (pathParts[0] || '') + '/'
+ const rkey = pathParts[1] || ''
+ const remainingLength = 20 - basePath.length
+ const rkeyPrefix = remainingLength > 0 ? rkey.slice(0, remainingLength) : ''
+ searchQuery = basePath + rkeyPrefix
+ } catch {
+ // Keep original
+ }
+
+ const searchUrl = `${appUrl}/search?q=${encodeURIComponent(searchQuery)}`
+
+ return `
+ No posts yet.
' } + const currentLang = getCurrentLang() + const items = posts.map(post => { const rkey = post.uri.split('/').pop() || '' - const date = new Date(post.value.createdAt).toLocaleDateString('ja-JP') + const date = new Date(post.value.createdAt).toLocaleDateString('en-US') + const originalLang = post.value.lang || 'ja' + const translations = post.value.translations + + // Use translation if available + let displayTitle = post.value.title + if (translations && currentLang !== originalLang && translations[currentLang]) { + displayTitle = translations[currentLang].title || post.value.title + } return `${escapeHtml(post.value.title)}
+${escapeHtml(displayTitle)}
${escapeHtml(post.value.title)}
${escapeHtml(displayTitle)}
+${escapeHtml(displayName)}
+${handleHtml}
+ ${description ? `${escapeHtml(description)}
` : ''}${escapeHtml(description)}
-