mirror of
https://github.com/nagisa77/OpenIsle.git
synced 2026-08-11 13:50:59 +00:00
Merge branch 'nagisa77:main' into main
This commit is contained in:
@@ -65,7 +65,12 @@ 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,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,
|
||||||
|
|||||||
@@ -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: '🇰🇷'
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
Reference in New Issue
Block a user