|
|
|
@ -32,6 +32,29 @@ const authorName = ref('') |
|
|
|
const authorEmail = ref('') |
|
|
|
const content = ref('') |
|
|
|
const quotedComment = ref<CommentResponse | null>(null) |
|
|
|
const overflowIds = ref<Set<number>>(new Set()) |
|
|
|
const expandedIds = ref<Set<number>>(new Set()) |
|
|
|
|
|
|
|
function measureComment(id: number, el: Element | null) { |
|
|
|
if (!el) return |
|
|
|
const node = el as HTMLElement |
|
|
|
const lh = parseFloat(getComputedStyle(node).lineHeight) || 22 |
|
|
|
if (node.scrollHeight > lh * 4 + 2) { |
|
|
|
if (!overflowIds.value.has(id)) { |
|
|
|
overflowIds.value = new Set([...overflowIds.value, id]) |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
function toggleExpand(id: number) { |
|
|
|
const next = new Set(expandedIds.value) |
|
|
|
if (next.has(id)) { |
|
|
|
next.delete(id) |
|
|
|
} else { |
|
|
|
next.add(id) |
|
|
|
} |
|
|
|
expandedIds.value = next |
|
|
|
} |
|
|
|
|
|
|
|
function escapeBrackets(text: string): string { |
|
|
|
return text.replace(/[<>]/g, (ch) => '\\' + ch) |
|
|
|
@ -205,7 +228,20 @@ onMounted(() => { |
|
|
|
<span class="comment-author">{{ comment.authorName }}</span> |
|
|
|
<span class="comment-time">{{ formatDate(comment.createdAt) }}</span> |
|
|
|
</div> |
|
|
|
<p class="comment-content" v-html="renderCommentContent(comment.content ?? '')"></p> |
|
|
|
<p |
|
|
|
class="comment-content" |
|
|
|
:class="{ 'content-clamped': overflowIds.has(comment.id!) && !expandedIds.has(comment.id!) }" |
|
|
|
:ref="(el: unknown) => measureComment(comment.id!, el as Element | null)" |
|
|
|
v-html="renderCommentContent(comment.content ?? '')" |
|
|
|
></p> |
|
|
|
<button |
|
|
|
v-if="overflowIds.has(comment.id!)" |
|
|
|
class="comment-toggle" |
|
|
|
type="button" |
|
|
|
@click="toggleExpand(comment.id!)" |
|
|
|
> |
|
|
|
{{ expandedIds.has(comment.id!) ? '收起' : '展开全文' }} |
|
|
|
</button> |
|
|
|
<button class="comment-quote" type="button" title="引用评论" @click="quoteComment(comment)"> |
|
|
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"> |
|
|
|
<path d="M21.44 11.05l-9.19 9.19a6 6 0 0 1-8.49-8.49l9.19-9.19a4 4 0 0 1 5.66 5.66l-9.2 9.19a2 2 0 0 1-2.83-2.83l8.49-8.48" /> |
|
|
|
@ -345,6 +381,29 @@ onMounted(() => { |
|
|
|
white-space: pre-line; |
|
|
|
} |
|
|
|
|
|
|
|
.comment-content.content-clamped { |
|
|
|
display: -webkit-box; |
|
|
|
-webkit-box-orient: vertical; |
|
|
|
-webkit-line-clamp: 4; |
|
|
|
overflow: hidden; |
|
|
|
} |
|
|
|
|
|
|
|
.comment-toggle { |
|
|
|
display: block; |
|
|
|
margin-top: 4px; |
|
|
|
border: none; |
|
|
|
background: none; |
|
|
|
color: var(--ac-primary-ink); |
|
|
|
cursor: pointer; |
|
|
|
font-size: 12px; |
|
|
|
padding: 2px 0; |
|
|
|
transition: color var(--song-dur-1) var(--song-ease); |
|
|
|
} |
|
|
|
|
|
|
|
.comment-toggle:hover { |
|
|
|
color: var(--ac-primary); |
|
|
|
} |
|
|
|
|
|
|
|
.comment-star { |
|
|
|
display: inline-flex; |
|
|
|
align-items: center; |
|
|
|
|