import { LitElement, html, css } from 'lit'; import { router } from '../../router.js'; import '../atoms/grain-avatar.js'; import '../atoms/grain-rich-text.js'; export class GrainComment extends LitElement { static properties = { uri: { type: String }, handle: { type: String }, displayName: { type: String }, avatarUrl: { type: String }, text: { type: String }, facets: { type: Array }, createdAt: { type: String }, isReply: { type: Boolean }, isOwner: { type: Boolean }, focusImageUrl: { type: String }, focusImageAlt: { type: String } }; static styles = css` :host { display: block; padding: var(--space-xs) 0; } :host([is-reply]) { padding-left: 40px; } .comment { display: flex; gap: var(--space-sm); cursor: pointer; } .content { flex: 1; min-width: 0; } .text-line { font-size: var(--font-size-sm); color: var(--color-text-primary); line-height: 1.4; } .handle { font-weight: var(--font-weight-semibold); cursor: pointer; } .handle:hover { text-decoration: underline; } .text { margin-left: var(--space-xs); word-break: break-word; } .meta { display: flex; gap: var(--space-sm); margin-top: var(--space-xxs); } .time { font-size: var(--font-size-xs); color: var(--color-text-secondary); } .reply-btn { font-size: var(--font-size-xs); color: var(--color-text-secondary); background: none; border: none; padding: 0; cursor: pointer; font-family: inherit; font-weight: var(--font-weight-semibold); } .reply-btn:hover, .delete-btn:hover { color: var(--color-text-primary); } .delete-btn { font-size: var(--font-size-xs); color: var(--color-text-secondary); background: none; border: none; padding: 0; cursor: pointer; font-family: inherit; font-weight: var(--font-weight-semibold); } .delete-btn:hover { color: var(--color-error, #e53935); } .focus-image { width: 40px; height: 40px; border-radius: 4px; object-fit: cover; flex-shrink: 0; } `; constructor() { super(); this.uri = ''; this.handle = ''; this.displayName = ''; this.avatarUrl = ''; this.text = ''; this.facets = []; this.createdAt = ''; this.isReply = false; this.isOwner = false; this.focusImageUrl = ''; this.focusImageAlt = ''; } #handleProfileClick(e) { e.stopPropagation(); router.push(`/profile/${this.handle}`); } #handleReplyClick(e) { e.stopPropagation(); this.dispatchEvent(new CustomEvent('reply', { detail: { uri: this.uri, handle: this.handle }, bubbles: true, composed: true })); } #handleDeleteClick(e) { e.stopPropagation(); this.dispatchEvent(new CustomEvent('delete', { detail: { uri: this.uri }, bubbles: true, composed: true })); } #formatTime(iso) { const date = new Date(iso); const now = new Date(); const diffMs = now - date; const diffMins = Math.floor(diffMs / 60000); const diffHours = Math.floor(diffMs / 3600000); const diffDays = Math.floor(diffMs / 86400000); if (diffMins < 1) return 'now'; if (diffMins < 60) return `${diffMins}m`; if (diffHours < 24) return `${diffHours}h`; if (diffDays < 7) return `${diffDays}d`; return `${Math.floor(diffDays / 7)}w`; } render() { return html`
${this.handle}
${this.#formatTime(this.createdAt)} ${this.isOwner ? html` ` : ''}
${this.focusImageUrl ? html` ${this.focusImageAlt} ` : ''}
`; } } customElements.define('grain-comment', GrainComment);