mirror of
https://github.com/BTMuli/TeyvatGuide.git
synced 2025-12-12 09:18:14 +08:00
♻️ 帖子文本解析部分重构
This commit is contained in:
@@ -103,7 +103,6 @@ function onCancel() {
|
|||||||
visible.value = false;
|
visible.value = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// todo 存在 bug,点击成就标题时可能会没有效果
|
|
||||||
async function searchDirect(word: string): Promise<void> {
|
async function searchDirect(word: string): Promise<void> {
|
||||||
await TGLogger.Info(`[ToAchiInfo][${props.data?.id}][Search] 查询 ${word}`);
|
await TGLogger.Info(`[ToAchiInfo][${props.data?.id}][Search] 查询 ${word}`);
|
||||||
search.value = word;
|
search.value = word;
|
||||||
|
|||||||
@@ -47,7 +47,6 @@ interface TpBackupText {
|
|||||||
|
|
||||||
interface TpBackupTextProps {
|
interface TpBackupTextProps {
|
||||||
data: TpBackupText;
|
data: TpBackupText;
|
||||||
next: unknown;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const props = defineProps<TpBackupTextProps>();
|
const props = defineProps<TpBackupTextProps>();
|
||||||
|
|||||||
@@ -21,7 +21,6 @@ interface TpDivider {
|
|||||||
|
|
||||||
interface TpDividerProps {
|
interface TpDividerProps {
|
||||||
data: TpDivider;
|
data: TpDivider;
|
||||||
next: unknown;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const props = defineProps<TpDividerProps>();
|
const props = defineProps<TpDividerProps>();
|
||||||
|
|||||||
@@ -29,7 +29,6 @@ export interface TpImage {
|
|||||||
}
|
}
|
||||||
interface TpImageProps {
|
interface TpImageProps {
|
||||||
data: TpImage;
|
data: TpImage;
|
||||||
next: unknown;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const props = defineProps<TpImageProps>();
|
const props = defineProps<TpImageProps>();
|
||||||
|
|||||||
@@ -39,7 +39,6 @@ interface TpLinkCard {
|
|||||||
|
|
||||||
interface TpLinkCardProps {
|
interface TpLinkCardProps {
|
||||||
data: TpLinkCard;
|
data: TpLinkCard;
|
||||||
next: unknown;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const props = defineProps<TpLinkCardProps>();
|
const props = defineProps<TpLinkCardProps>();
|
||||||
|
|||||||
@@ -22,7 +22,6 @@ interface TpMention {
|
|||||||
|
|
||||||
interface TpMentionProps {
|
interface TpMentionProps {
|
||||||
data: TpMention;
|
data: TpMention;
|
||||||
next: unknown;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const props = defineProps<TpMentionProps>();
|
const props = defineProps<TpMentionProps>();
|
||||||
|
|||||||
@@ -1,10 +1,9 @@
|
|||||||
<template>
|
<template>
|
||||||
<component
|
<component
|
||||||
v-for="(tp, index) in props.data"
|
v-for="(tp, index) in getParsedData(props.data)"
|
||||||
:key="index"
|
:key="index"
|
||||||
:is="getTpName(tp)"
|
:is="getTpName(tp)"
|
||||||
:data="tp"
|
:data="tp"
|
||||||
:next="getTpNext(index)"
|
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
@@ -13,7 +12,8 @@ import TpDivider from "./tp-divider.vue";
|
|||||||
import TpImage from "./tp-image.vue";
|
import TpImage from "./tp-image.vue";
|
||||||
import TpLinkCard from "./tp-linkCard.vue";
|
import TpLinkCard from "./tp-linkCard.vue";
|
||||||
import TpMention from "./tp-mention.vue";
|
import TpMention from "./tp-mention.vue";
|
||||||
import TpText from "./tp-text.vue";
|
import TpText, { type TpText as TpTextType } from "./tp-text.vue";
|
||||||
|
import TpTexts from "./tp-texts.vue";
|
||||||
import TpUnknown from "./tp-unknown.vue";
|
import TpUnknown from "./tp-unknown.vue";
|
||||||
import TpVideo from "./tp-video.vue";
|
import TpVideo from "./tp-video.vue";
|
||||||
import TpVod from "./tp-vod.vue";
|
import TpVod from "./tp-vod.vue";
|
||||||
@@ -25,7 +25,65 @@ interface TpParserProps {
|
|||||||
|
|
||||||
const props = defineProps<TpParserProps>();
|
const props = defineProps<TpParserProps>();
|
||||||
|
|
||||||
|
function getParsedData(data: TGApp.Plugins.Mys.SctPost.Base[]): TGApp.Plugins.Mys.SctPost.Base[] {
|
||||||
|
const res: TGApp.Plugins.Mys.SctPost.Base[] = [];
|
||||||
|
let child: TGApp.Plugins.Mys.SctPost.Base[] = [];
|
||||||
|
let cur: TGApp.Plugins.Mys.SctPost.Base | undefined;
|
||||||
|
for (const tp of data) {
|
||||||
|
const tpName = getTpName(tp);
|
||||||
|
if (tpName !== TpText) {
|
||||||
|
cur = tp;
|
||||||
|
child = [];
|
||||||
|
res.push(cur);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (tp.insert === "\n") {
|
||||||
|
child.push(tp);
|
||||||
|
cur = {
|
||||||
|
insert: "",
|
||||||
|
attributes: tp.attributes,
|
||||||
|
children: child,
|
||||||
|
};
|
||||||
|
res.push(cur);
|
||||||
|
child = [];
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const parsedText = getParsedText(tp);
|
||||||
|
for (const text of parsedText) {
|
||||||
|
child.push(text);
|
||||||
|
if (text.insert === "\n") {
|
||||||
|
cur = {
|
||||||
|
insert: "",
|
||||||
|
attributes: text.attributes,
|
||||||
|
children: child,
|
||||||
|
};
|
||||||
|
res.push(cur);
|
||||||
|
child = [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getParsedText(data: TpTextType): TpTextType[] {
|
||||||
|
if (data.insert.includes("\n") && data.insert !== "\n") {
|
||||||
|
const splits = data.insert.split("\n");
|
||||||
|
const res = [];
|
||||||
|
for (let i = 0; i < splits.length; i++) {
|
||||||
|
if (splits[i] !== "") {
|
||||||
|
res.push({ insert: splits[i], attributes: data.attributes });
|
||||||
|
}
|
||||||
|
if (i !== splits.length - 1) {
|
||||||
|
res.push({ insert: "\n", attributes: data.attributes });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
return [data];
|
||||||
|
}
|
||||||
|
|
||||||
function getTpName(tp: TGApp.Plugins.Mys.SctPost.Base) {
|
function getTpName(tp: TGApp.Plugins.Mys.SctPost.Base) {
|
||||||
|
if (tp.children) return TpTexts;
|
||||||
if (typeof tp.insert === "string") {
|
if (typeof tp.insert === "string") {
|
||||||
return TpText;
|
return TpText;
|
||||||
} else if ("image" in tp.insert) {
|
} else if ("image" in tp.insert) {
|
||||||
@@ -47,11 +105,4 @@ function getTpName(tp: TGApp.Plugins.Mys.SctPost.Base) {
|
|||||||
}
|
}
|
||||||
return TpUnknown;
|
return TpUnknown;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getTpNext(index: number) {
|
|
||||||
if (index + 1 >= props.data.length) {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
return props.data[index + 1];
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -17,18 +17,10 @@
|
|||||||
v-for="(emoji, indexE) in emojis"
|
v-for="(emoji, indexE) in emojis"
|
||||||
:data="emoji"
|
:data="emoji"
|
||||||
:key="indexE"
|
:key="indexE"
|
||||||
:next="indexE === emojis.length - 1 ? undefined : next"
|
|
||||||
/>
|
/>
|
||||||
<TpText
|
<span v-else :style="getTextStyle()">
|
||||||
v-else-if="mode == 'texts'"
|
|
||||||
v-for="(text, indexT) in texts"
|
|
||||||
:data="text"
|
|
||||||
:key="indexT"
|
|
||||||
:next="indexT === texts.length - 1 ? next : undefined"
|
|
||||||
/>
|
|
||||||
<div v-else :style="getTextStyle()" class="tp-text-span">
|
|
||||||
{{ props.data.insert }}
|
{{ props.data.insert }}
|
||||||
</div>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { onMounted, ref, StyleValue, toRaw } from "vue";
|
import { onMounted, ref, StyleValue, toRaw } from "vue";
|
||||||
@@ -39,7 +31,7 @@ import { parseLink, parsePost } from "../../utils/linkParser";
|
|||||||
import { isColorSimilar } from "../../utils/toolFunc";
|
import { isColorSimilar } from "../../utils/toolFunc";
|
||||||
import showSnackbar from "../func/snackbar";
|
import showSnackbar from "../func/snackbar";
|
||||||
|
|
||||||
interface TpText {
|
export interface TpText {
|
||||||
insert: string;
|
insert: string;
|
||||||
attributes?: {
|
attributes?: {
|
||||||
header?: number;
|
header?: number;
|
||||||
@@ -52,14 +44,12 @@ interface TpText {
|
|||||||
|
|
||||||
interface TpTextProps {
|
interface TpTextProps {
|
||||||
data: TpText;
|
data: TpText;
|
||||||
next: TGApp.Plugins.Mys.SctPost.Base | undefined;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const props = defineProps<TpTextProps>();
|
const props = defineProps<TpTextProps>();
|
||||||
const mode = ref<string>("text");
|
const mode = ref<string>("text");
|
||||||
const localEmojis = ref(localStorage.getItem("emojis"));
|
const localEmojis = ref(localStorage.getItem("emojis"));
|
||||||
const emojis = ref<TpText[]>([]);
|
const emojis = ref<TpText[]>([]);
|
||||||
const texts = ref<TpText[]>([]);
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
console.log("tpText", JSON.stringify(props.data.insert), toRaw(props.data)?.attributes);
|
console.log("tpText", JSON.stringify(props.data.insert), toRaw(props.data)?.attributes);
|
||||||
@@ -81,45 +71,16 @@ onMounted(async () => {
|
|||||||
emojis.value = res.map((i) => ({ insert: i, attributes: props.data.attributes }));
|
emojis.value = res.map((i) => ({ insert: i, attributes: props.data.attributes }));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (props.data.insert.includes("\n") && props.data.insert !== "\n") {
|
|
||||||
mode.value = "texts";
|
|
||||||
const splits = props.data.insert.split("\n");
|
|
||||||
const temp = [];
|
|
||||||
for (let i = 0; i < splits.length; i++) {
|
|
||||||
if (splits[i] !== "") {
|
|
||||||
temp.push({ insert: splits[i], attributes: props.data.attributes });
|
|
||||||
}
|
|
||||||
if (i !== splits.length - 1) {
|
|
||||||
temp.push({ insert: "\n", attributes: props.data.attributes });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
texts.value = temp;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
mode.value = "text";
|
mode.value = "text";
|
||||||
});
|
});
|
||||||
|
|
||||||
// 解析文本样式
|
// 解析文本样式
|
||||||
function getTextStyle(): StyleValue {
|
function getTextStyle(): StyleValue {
|
||||||
const style = <Array<StyleValue>>[];
|
const style = <Array<StyleValue>>[];
|
||||||
let data: TpText;
|
const data: TpText = props.data;
|
||||||
if (props.data.insert === "\n") {
|
style.push("white-space: pre-wrap");
|
||||||
return "display: inline";
|
|
||||||
}
|
|
||||||
if (typeof props.next?.insert === "string" && props.next.insert.includes("\n")) {
|
|
||||||
data = {
|
|
||||||
insert: props.data.insert,
|
|
||||||
attributes: {
|
|
||||||
...props.data.attributes,
|
|
||||||
...props.next.attributes,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
data = props.data;
|
|
||||||
}
|
|
||||||
if (data.attributes) {
|
if (data.attributes) {
|
||||||
const ruleBold: StyleValue = "fontFamily: var(--font-title)";
|
const ruleBold: StyleValue = "fontFamily: var(--font-title)";
|
||||||
const headerFontSizes = ["2rem", "1.75rem", "1.5rem", "1.25rem", "1rem", "0.75rem"];
|
|
||||||
if (data.attributes.bold) {
|
if (data.attributes.bold) {
|
||||||
style.push(ruleBold);
|
style.push(ruleBold);
|
||||||
}
|
}
|
||||||
@@ -131,21 +92,6 @@ function getTextStyle(): StyleValue {
|
|||||||
const ruleColor: StyleValue = `color: ${colorGet}`;
|
const ruleColor: StyleValue = `color: ${colorGet}`;
|
||||||
style.push(ruleColor);
|
style.push(ruleColor);
|
||||||
}
|
}
|
||||||
if (data.attributes.align) {
|
|
||||||
const ruleAlign: StyleValue = `textAlign: ${data.attributes.align}`;
|
|
||||||
if (data.attributes.align !== "center") style.push("display: inline");
|
|
||||||
else style.push(ruleAlign);
|
|
||||||
}
|
|
||||||
if (data.attributes.header) {
|
|
||||||
const ruleHeader: StyleValue = `fontSize: ${headerFontSizes[data.attributes.header - 1]}`;
|
|
||||||
style.push(ruleHeader);
|
|
||||||
style.push(ruleBold);
|
|
||||||
}
|
|
||||||
if (!data.attributes.align && !data.attributes.header) {
|
|
||||||
style.push("display: inline");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
style.push("display: inline");
|
|
||||||
}
|
}
|
||||||
return style;
|
return style;
|
||||||
}
|
}
|
||||||
@@ -211,7 +157,7 @@ function getEmojiName() {
|
|||||||
</script>
|
</script>
|
||||||
<style lang="css" scoped>
|
<style lang="css" scoped>
|
||||||
.tp-text-link {
|
.tp-text-link {
|
||||||
display: flex;
|
display: inline-flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
color: #00c3ff;
|
color: #00c3ff;
|
||||||
@@ -231,10 +177,4 @@ function getEmojiName() {
|
|||||||
height: 45px;
|
height: 45px;
|
||||||
margin: 0 5px;
|
margin: 0 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tp-text-span {
|
|
||||||
overflow-wrap: break-word;
|
|
||||||
white-space: pre-wrap;
|
|
||||||
word-break: break-all;
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
49
src/components/post/tp-texts.vue
Normal file
49
src/components/post/tp-texts.vue
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
<template>
|
||||||
|
<div :style="getLineStyle()" class="tp-texts">
|
||||||
|
<TpText v-for="(text, indexT) in props.data.children" :data="text" :key="indexT" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { onMounted, StyleValue, toRaw } from "vue";
|
||||||
|
|
||||||
|
import TpText, { type TpText as TpTextType } from "./tp-text.vue";
|
||||||
|
|
||||||
|
interface TpTexts extends TpTextType {
|
||||||
|
children: TpTextType[];
|
||||||
|
}
|
||||||
|
|
||||||
|
interface TpTextsProps {
|
||||||
|
data: TpTexts;
|
||||||
|
}
|
||||||
|
|
||||||
|
const props = defineProps<TpTextsProps>();
|
||||||
|
|
||||||
|
if (props.data.attributes) {
|
||||||
|
console.warn("TpTexts", props.data.attributes);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getLineStyle(): StyleValue {
|
||||||
|
const style = <Array<StyleValue>>[];
|
||||||
|
if (props.data.attributes === undefined) {
|
||||||
|
return style;
|
||||||
|
}
|
||||||
|
const ruleBold: StyleValue = "fontFamily: var(--font-title)";
|
||||||
|
const headerFontSizes = ["2rem", "1.75rem", "1.5rem", "1.25rem", "1rem", "0.75rem"];
|
||||||
|
if (props.data.attributes.align) {
|
||||||
|
const ruleAlign: StyleValue = `textAlign: ${props.data.attributes.align}`;
|
||||||
|
if (props.data.attributes.align !== "center") style.push("display: inline");
|
||||||
|
else style.push(ruleAlign);
|
||||||
|
}
|
||||||
|
if (props.data.attributes.header) {
|
||||||
|
const ruleHeader: StyleValue = `fontSize: ${headerFontSizes[props.data.attributes.header - 1]}`;
|
||||||
|
style.push(ruleHeader);
|
||||||
|
style.push(ruleBold);
|
||||||
|
}
|
||||||
|
return style;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style lang="css" scoped>
|
||||||
|
.tp-texts {
|
||||||
|
white-space: pre-wrap;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -10,7 +10,6 @@ import TGLogger from "../../utils/TGLogger";
|
|||||||
|
|
||||||
interface TpUnknownProps {
|
interface TpUnknownProps {
|
||||||
data: TGApp.Plugins.Mys.SctPost.Empty;
|
data: TGApp.Plugins.Mys.SctPost.Empty;
|
||||||
next?: unknown;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const props = defineProps<TpUnknownProps>();
|
const props = defineProps<TpUnknownProps>();
|
||||||
|
|||||||
@@ -38,7 +38,6 @@ interface TpVideo {
|
|||||||
|
|
||||||
interface TpVideoProps {
|
interface TpVideoProps {
|
||||||
data: TpVideo;
|
data: TpVideo;
|
||||||
next: unknown;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const props = defineProps<TpVideoProps>();
|
const props = defineProps<TpVideoProps>();
|
||||||
|
|||||||
@@ -43,7 +43,6 @@ interface TpVod {
|
|||||||
|
|
||||||
interface TpVodProps {
|
interface TpVodProps {
|
||||||
data: TpVod;
|
data: TpVod;
|
||||||
next: unknown;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const props = defineProps<TpVodProps>();
|
const props = defineProps<TpVodProps>();
|
||||||
|
|||||||
@@ -36,7 +36,6 @@ interface TpVote {
|
|||||||
|
|
||||||
interface TpVoteProps {
|
interface TpVoteProps {
|
||||||
data: TpVote;
|
data: TpVote;
|
||||||
next: unknown;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
interface TpVoteInfo {
|
interface TpVoteInfo {
|
||||||
|
|||||||
8
src/plugins/Mys/types/SctPost.d.ts
vendored
8
src/plugins/Mys/types/SctPost.d.ts
vendored
@@ -1,27 +1,29 @@
|
|||||||
/**
|
/**
|
||||||
* @file plugins/Mys/types/SctPost.d.ts
|
* @file plugins/Mys/types/SctPost.d.ts
|
||||||
* @description Mys 插件 结构化帖子类型声明文件
|
* @description Mys 插件 结构化帖子类型声明文件
|
||||||
* @since Beta v0.3.7
|
* @since Beta v0.4.5
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @description 结构化帖子类型命名空间
|
* @description 结构化帖子类型命名空间
|
||||||
* @since Beta v0.3.7
|
* @since Beta v0.4.5
|
||||||
* @namespace TGApp.Plugins.Mys.SctPost
|
* @namespace TGApp.Plugins.Mys.SctPost
|
||||||
* @memberof TGApp.Plugins.Mys
|
* @memberof TGApp.Plugins.Mys
|
||||||
*/
|
*/
|
||||||
declare namespace TGApp.Plugins.Mys.SctPost {
|
declare namespace TGApp.Plugins.Mys.SctPost {
|
||||||
/**
|
/**
|
||||||
* @description 帖子结构化数据-基础类型
|
* @description 帖子结构化数据-基础类型
|
||||||
* @since Beta v0.3.4
|
* @since Beta v0.4.5
|
||||||
* @interface Base
|
* @interface Base
|
||||||
* @property {unknown} insert - 帖子内容
|
* @property {unknown} insert - 帖子内容
|
||||||
* @property {unknown} attributes - 帖子属性
|
* @property {unknown} attributes - 帖子属性
|
||||||
|
* @property {Base[]} children - 子帖子
|
||||||
* @return Base
|
* @return Base
|
||||||
*/
|
*/
|
||||||
interface Base {
|
interface Base {
|
||||||
insert: any;
|
insert: any;
|
||||||
attributes?: any;
|
attributes?: any;
|
||||||
|
children?: Base[];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Reference in New Issue
Block a user