mirror of
https://github.com/BTMuli/TeyvatGuide.git
synced 2026-04-01 06:39:45 +08:00
162 lines
4.3 KiB
Vue
162 lines
4.3 KiB
Vue
<template>
|
|
<span
|
|
v-if="mode == 'link'"
|
|
class="tp-text-link"
|
|
@click="toLink()"
|
|
:title="props.data.attributes?.link"
|
|
:style="getTextStyle()"
|
|
>
|
|
{{ props.data.insert }}
|
|
</span>
|
|
<span v-else-if="mode == 'emoji'" class="tp-text-emoji">
|
|
<img :src="getEmojiUrl()" :alt="getEmojiName()" :title="getEmojiName()" />
|
|
</span>
|
|
<TpText
|
|
v-else-if="mode == 'emojis'"
|
|
v-for="(emoji, indexE) in emojis"
|
|
:data="emoji"
|
|
:key="indexE"
|
|
/>
|
|
<span v-else :style="getTextStyle()">{{ props.data.insert }}</span>
|
|
</template>
|
|
<script lang="ts" setup>
|
|
import { onMounted, ref, StyleValue, toRaw } from "vue";
|
|
|
|
import { getEmojis } from "../../plugins/Mys/request/getEmojis.js";
|
|
import { parseLink, parsePost } from "../../utils/linkParser.js";
|
|
import { isColorSimilar } from "../../utils/toolFunc.js";
|
|
import showSnackbar from "../func/snackbar.js";
|
|
|
|
export interface TpText {
|
|
insert: string;
|
|
attributes?: {
|
|
header?: number;
|
|
link?: string;
|
|
bold?: boolean;
|
|
color?: string;
|
|
align?: string;
|
|
italic?: boolean;
|
|
};
|
|
}
|
|
|
|
interface TpTextProps {
|
|
data: TpText;
|
|
}
|
|
|
|
const props = defineProps<TpTextProps>();
|
|
const mode = ref<string>("text");
|
|
const localEmojis = ref<string | null>(localStorage.getItem("emojis"));
|
|
const emojis = ref<TpText[]>([]);
|
|
|
|
console.log("tpText", JSON.stringify(props.data.insert), toRaw(props.data)?.attributes);
|
|
|
|
onMounted(async () => {
|
|
if (props.data.attributes && "link" in props.data.attributes) {
|
|
mode.value = "link";
|
|
return;
|
|
}
|
|
// thanks, @Lightczx & webstorm
|
|
const reg = /(?<=\n|.+?|^)(_\(.+?\)(?=\n|.+?|$))/g;
|
|
const res = props.data.insert.split(reg);
|
|
if (res.length > 2) {
|
|
if (res.length === 3 && res[0] === "" && res[2] === "") {
|
|
mode.value = "emoji";
|
|
return;
|
|
}
|
|
mode.value = "emojis";
|
|
emojis.value = res.map((i) => ({ insert: i, attributes: props.data.attributes }));
|
|
return;
|
|
}
|
|
mode.value = "text";
|
|
});
|
|
|
|
// 解析文本样式
|
|
function getTextStyle(): StyleValue {
|
|
const style = <Array<StyleValue>>[];
|
|
const data: TpText = props.data;
|
|
style.push("white-space: pre-wrap");
|
|
style.push("line-break: anywhere");
|
|
style.push("word-break: break-all");
|
|
if (data.attributes) {
|
|
const ruleBold: StyleValue = "fontFamily: var(--font-title)";
|
|
const ruleItalic: StyleValue = "fontStyle: italic";
|
|
if (data.attributes.bold) style.push(ruleBold);
|
|
if (data.attributes.italic) style.push(ruleItalic);
|
|
if (data.attributes.color) {
|
|
let colorGet = data.attributes.color;
|
|
if (isColorSimilar("#000000", data.attributes.color)) {
|
|
colorGet = "var(--app-page-content)";
|
|
}
|
|
const ruleColor: StyleValue = `color: ${colorGet}`;
|
|
style.push(ruleColor);
|
|
}
|
|
}
|
|
return style;
|
|
}
|
|
|
|
// 解析链接目标
|
|
async function toLink() {
|
|
if (!props.data.attributes) return;
|
|
if (!props.data.attributes.link) return;
|
|
const link = props.data.attributes.link;
|
|
const isPost = await parsePost(link);
|
|
if (isPost !== false) {
|
|
location.href = `/post_detail/${isPost}`;
|
|
return;
|
|
}
|
|
const res = await parseLink(link);
|
|
if (res === true) return;
|
|
if (res === false) {
|
|
showSnackbar.error(`未知链接:${link}`, 3000);
|
|
return;
|
|
}
|
|
window.open(res);
|
|
}
|
|
|
|
// 解析表情链接
|
|
function getEmojiUrl(): string {
|
|
if (localEmojis.value === null || !JSON.parse(localEmojis.value)[getEmojiName()]) {
|
|
console.warn("tpEmoji unknown", getEmojiName());
|
|
getEmojis().then((res) => {
|
|
if ("retcode" in res) {
|
|
console.error(res);
|
|
showSnackbar.error("获取表情包失败!");
|
|
mode.value = "text";
|
|
return "";
|
|
}
|
|
localEmojis.value = JSON.stringify(res);
|
|
localStorage.setItem("emojis", localEmojis.value);
|
|
});
|
|
}
|
|
const emojiName = getEmojiName();
|
|
const emojiMap: Record<string, string> = JSON.parse(<string>localEmojis.value);
|
|
if (!Object.keys(emojiMap).includes(emojiName)) mode.value = "text";
|
|
return JSON.parse(<string>localEmojis.value)[emojiName];
|
|
}
|
|
|
|
function getEmojiName() {
|
|
return props.data.insert.slice(2, -1);
|
|
}
|
|
</script>
|
|
<style lang="css" scoped>
|
|
.tp-text-link {
|
|
color: #00c3ff;
|
|
cursor: pointer;
|
|
text-decoration: underline solid #00c3ff;
|
|
text-underline-position: under;
|
|
}
|
|
|
|
.tp-text-emoji {
|
|
display: inline-flex;
|
|
align-items: flex-end;
|
|
justify-content: center;
|
|
transform: translateY(5px);
|
|
}
|
|
|
|
.tp-text-emoji img {
|
|
width: 45px;
|
|
height: 45px;
|
|
margin: 0 5px;
|
|
}
|
|
</style>
|