Merge branch 'nagisa77:main' into main

This commit is contained in:
浮小云
2025-08-06 19:16:00 +08:00
committed by GitHub
8 changed files with 67 additions and 83 deletions
+5
View File
@@ -66,6 +66,11 @@ body {
.vditor { .vditor {
min-height: 200px; min-height: 200px;
} }
.vditor-toolbar--pin {
top: var(--header-height) !important;
}
/* .vditor { /* .vditor {
--textarea-background-color: transparent; --textarea-background-color: transparent;
border: none !important; border: none !important;
+4 -29
View File
@@ -4,7 +4,7 @@
<div class="reactions-viewer-item-container" @click="openPanel" @mouseenter="cancelHide" <div class="reactions-viewer-item-container" @click="openPanel" @mouseenter="cancelHide"
@mouseleave="scheduleHide"> @mouseleave="scheduleHide">
<template v-if="displayedReactions.length"> <template v-if="displayedReactions.length">
<div v-for="r in displayedReactions" :key="r.type" class="reactions-viewer-item">{{ iconMap[r.type] }}</div> <div v-for="r in displayedReactions" :key="r.type" class="reactions-viewer-item">{{ reactionEmojiMap[r.type] }}</div>
<div class="reactions-count">{{ totalCount }}</div> <div class="reactions-count">{{ totalCount }}</div>
</template> </template>
<div v-else class="reactions-viewer-item placeholder"> <div v-else class="reactions-viewer-item placeholder">
@@ -24,7 +24,7 @@
<div v-if="panelVisible" class="reactions-panel" @mouseenter="cancelHide" @mouseleave="scheduleHide"> <div v-if="panelVisible" class="reactions-panel" @mouseenter="cancelHide" @mouseleave="scheduleHide">
<div v-for="t in panelTypes" :key="t" class="reaction-option" @click="toggleReaction(t)" <div v-for="t in panelTypes" :key="t" class="reaction-option" @click="toggleReaction(t)"
:class="{ selected: userReacted(t) }"> :class="{ selected: userReacted(t) }">
{{ iconMap[t] }}<span v-if="counts[t]">{{ counts[t] }}</span> {{ reactionEmojiMap[t] }}<span v-if="counts[t]">{{ counts[t] }}</span>
</div> </div>
</div> </div>
</div> </div>
@@ -34,6 +34,7 @@
import { ref, computed, watch, onMounted } from 'vue' import { ref, computed, watch, onMounted } from 'vue'
import { API_BASE_URL, toast } from '../main' import { API_BASE_URL, toast } from '../main'
import { getToken, authState } from '../utils/auth' import { getToken, authState } from '../utils/auth'
import { reactionEmojiMap } from '../utils/reactions'
let cachedTypes = null let cachedTypes = null
const fetchTypes = async () => { const fetchTypes = async () => {
@@ -54,32 +55,6 @@ const fetchTypes = async () => {
return cachedTypes return cachedTypes
} }
const iconMap = {
LIKE: '❤️',
DISLIKE: '👎',
RECOMMEND: '👏',
ANGRY: '😡',
FLUSHED: '😳',
STAR_STRUCK: '🤩',
ROFL: '🤣',
HOLDING_BACK_TEARS: '🥹',
MIND_BLOWN: '🤯',
POOP: '💩',
CLOWN: '🤡',
SKULL: '☠️',
FIRE: '🔥',
EYES: '👀',
FROWN: '☹️',
HOT: '🥵',
EAGLE: '🦅',
SPIDER: '🕷️',
BAT: '🦇',
CHINA: '🇨🇳',
USA: '🇺🇸',
JAPAN: '🇯🇵',
KOREA: '🇰🇷'
}
export default { export default {
name: 'ReactionsGroup', name: 'ReactionsGroup',
props: { props: {
@@ -202,7 +177,7 @@ export default {
} }
return { return {
iconMap, reactionEmojiMap,
counts, counts,
totalCount, totalCount,
likeCount, likeCount,
+25
View File
@@ -0,0 +1,25 @@
export const reactionEmojiMap = {
LIKE: '❤️',
DISLIKE: '👎',
RECOMMEND: '👏',
ANGRY: '😡',
FLUSHED: '😳',
STAR_STRUCK: '🤩',
ROFL: '🤣',
HOLDING_BACK_TEARS: '🥹',
MIND_BLOWN: '🤯',
POOP: '💩',
CLOWN: '🤡',
SKULL: '☠️',
FIRE: '🔥',
EYES: '👀',
FROWN: '☹️',
HOT: '🥵',
EAGLE: '🦅',
SPIDER: '🕷️',
BAT: '🦇',
CHINA: '🇨🇳',
USA: '🇺🇸',
JAPAN: '🇯🇵',
KOREA: '🇰🇷'
}
+1 -3
View File
@@ -75,13 +75,11 @@ export default {
max-width: var(--page-max-width); max-width: var(--page-max-width);
background-color: var(--background-color); background-color: var(--background-color);
margin: 0 auto; margin: 0 auto;
height: 100%;
overflow-y: auto;
} }
.about-tabs { .about-tabs {
position: sticky; position: sticky;
top: 1px; top: calc(var(--header-height) + 1px);
z-index: 200; z-index: 200;
background-color: var(--background-color-blur); background-color: var(--background-color-blur);
display: flex; display: flex;
+1 -1
View File
@@ -433,7 +433,7 @@ export default {
.topic-container { .topic-container {
position: sticky; position: sticky;
top: 1px; top: calc(var(--header-height) + 1px);
z-index: 10; z-index: 10;
background-color: var(--background-color-blur); background-color: var(--background-color-blur);
display: flex; display: flex;
+29 -43
View File
@@ -299,11 +299,12 @@ import BaseTimeline from '../components/BaseTimeline.vue'
import BasePlaceholder from '../components/BasePlaceholder.vue' import BasePlaceholder from '../components/BasePlaceholder.vue'
import NotificationContainer from '../components/NotificationContainer.vue' import NotificationContainer from '../components/NotificationContainer.vue'
import { getToken, authState } from '../utils/auth' import { getToken, authState } from '../utils/auth'
import { markNotificationsRead, fetchUnreadCount } from '../utils/notification' import { markNotificationsRead, fetchUnreadCount, notificationState } from '../utils/notification'
import { toast } from '../main' import { toast } from '../main'
import { stripMarkdownLength } from '../utils/markdown' import { stripMarkdownLength } from '../utils/markdown'
import TimeManager from '../utils/time' import TimeManager from '../utils/time'
import { hatch } from 'ldrs' import { hatch } from 'ldrs'
import { reactionEmojiMap } from '../utils/reactions'
hatch.register() hatch.register()
export default { export default {
@@ -322,28 +323,42 @@ export default {
const markRead = async id => { const markRead = async id => {
if (!id) return if (!id) return
const n = notifications.value.find(n => n.id === id)
if (!n || n.read) return
n.read = true
if (notificationState.unreadCount > 0) notificationState.unreadCount--
const ok = await markNotificationsRead([id]) const ok = await markNotificationsRead([id])
if (ok) { if (!ok) {
const n = notifications.value.find(n => n.id === id) n.read = false
if (n) n.read = true notificationState.unreadCount++
await fetchUnreadCount() } else {
fetchUnreadCount()
} }
} }
const markAllRead = async () => { const markAllRead = async () => {
// 除了 REGISTER_REQUEST 类型消息 // 除了 REGISTER_REQUEST 类型消息
const idsToMark = notifications.value.filter(n => n.type !== 'REGISTER_REQUEST').map(n => n.id) const idsToMark = notifications.value
.filter(n => n.type !== 'REGISTER_REQUEST' && !n.read)
.map(n => n.id)
if (idsToMark.length === 0) return
notifications.value.forEach(n => {
if (n.type !== 'REGISTER_REQUEST') n.read = true
})
notificationState.unreadCount = notifications.value.filter(n => !n.read).length
const ok = await markNotificationsRead(idsToMark) const ok = await markNotificationsRead(idsToMark)
if (ok) { if (!ok) {
notifications.value.forEach(n => { notifications.value.forEach(n => {
if (n.type !== 'REGISTER_REQUEST') n.read = true if (idsToMark.includes(n.id)) n.read = false
}) })
await fetchUnreadCount() await fetchUnreadCount()
if (authState.role === 'ADMIN') { return
toast.success('已读所有消息(注册请求除外)') }
} else { fetchUnreadCount()
toast.success('已读所有消息') if (authState.role === 'ADMIN') {
} toast.success('已读所有消息(注册请求除外)')
} else {
toast.success('已读所有消息')
} }
} }
@@ -364,32 +379,6 @@ export default {
MENTION: 'fas fa-at' MENTION: 'fas fa-at'
} }
const reactionEmojiMap = {
LIKE: '❤️',
DISLIKE: '👎',
RECOMMEND: '👏',
ANGRY: '😡',
FLUSHED: '😳',
STAR_STRUCK: '🤩',
ROFL: '🤣',
HOLDING_BACK_TEARS: '🥹',
MIND_BLOWN: '🤯',
POOP: '💩',
CLOWN: '🤡',
SKULL: '☠️',
FIRE: '🔥',
EYES: '👀',
FROWN: '☹️',
HOT: '🥵',
EAGLE: '🦅',
SPIDER: '🕷️',
BAT: '🦇',
CHINA: '🇨🇳',
USA: '🇺🇸',
JAPAN: '🇯🇵',
KOREA: '🇰🇷'
}
const fetchNotifications = async () => { const fetchNotifications = async () => {
try { try {
const token = getToken() const token = getToken()
@@ -628,6 +617,7 @@ export default {
.message-page { .message-page {
background-color: var(--background-color); background-color: var(--background-color);
overflow-x: hidden;
} }
.message-page-header { .message-page-header {
@@ -769,9 +759,5 @@ export default {
.has_read_button { .has_read_button {
display: none; display: none;
} }
.message-page {
overflow-x: hidden;
}
} }
</style> </style>
-2
View File
@@ -261,10 +261,8 @@ export default {
display: flex; display: flex;
justify-content: center; justify-content: center;
background-color: var(--background-color); background-color: var(--background-color);
height: 100%;
padding-right: 20px; padding-right: 20px;
padding-left: 20px; padding-left: 20px;
overflow-y: auto;
} }
.new-post-form { .new-post-form {
+1 -4
View File
@@ -497,9 +497,6 @@ export default {
.profile-page { .profile-page {
background-color: var(--background-color); background-color: var(--background-color);
height: 100%;
overflow-y: auto;
overflow-x: hidden;
} }
.profile-page-header { .profile-page-header {
@@ -639,7 +636,7 @@ export default {
.profile-tabs { .profile-tabs {
position: sticky; position: sticky;
top: 1px; top: calc(var(--header-height) + 1px);
z-index: 200; z-index: 200;
background-color: var(--background-color-blur); background-color: var(--background-color-blur);
display: flex; display: flex;