mirror of
https://github.com/BTMuli/TeyvatGuide.git
synced 2025-12-11 09:08:14 +08:00
✨ 支持 post&anno share
This commit is contained in:
@@ -30,7 +30,8 @@
|
|||||||
"https://hk4e-api.mihoyo.com/*",
|
"https://hk4e-api.mihoyo.com/*",
|
||||||
"https://passport-api.mihoyo.com/*",
|
"https://passport-api.mihoyo.com/*",
|
||||||
"https://passport-api-v4.mihoyo.com/*",
|
"https://passport-api-v4.mihoyo.com/*",
|
||||||
"https://act-webstatic.mihoyo.com/*"
|
"https://act-webstatic.mihoyo.com/*",
|
||||||
|
"https://sdk-webstatic.mihoyo.com/*"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"shell": {
|
"shell": {
|
||||||
|
|||||||
@@ -1,12 +1,14 @@
|
|||||||
/*
|
/*
|
||||||
|
* @file assets css post-parser.css
|
||||||
* @description 游戏公告解析 css
|
* @description 游戏公告解析 css
|
||||||
* @since Alpha v0.1.1
|
* @author BTMuli <bt-muli@outlook.com
|
||||||
|
* @since Alpha v0.2.0
|
||||||
*/
|
*/
|
||||||
|
|
||||||
.anno-body {
|
.anno-body {
|
||||||
margin: 20px auto;
|
margin: 0 auto;
|
||||||
width: 800px;
|
width: 800px;
|
||||||
font-family: "Genshin-Light", serif;
|
font-family: var(--font-text);
|
||||||
}
|
}
|
||||||
|
|
||||||
.anno-title {
|
.anno-title {
|
||||||
|
|||||||
@@ -1,12 +1,14 @@
|
|||||||
/*
|
/*
|
||||||
|
* @file assets css post-parser.css
|
||||||
* @description 米游社解析 css
|
* @description 米游社解析 css
|
||||||
* @since Alpha v0.1.3
|
* @author BTMuli <bt-muli@outlook.com>
|
||||||
|
* @since Alpha v0.2.0
|
||||||
*/
|
*/
|
||||||
|
|
||||||
.mys-post-body {
|
.mys-post-body {
|
||||||
margin: 20px auto;
|
margin: 0 auto;
|
||||||
width: 800px;
|
width: 800px;
|
||||||
font-family: "Genshin-Light", serif;
|
font-family: var(--font-text);
|
||||||
color: var(--post-default-text);
|
color: var(--post-default-text);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
48
src/components/main/t-shareBtn.vue
Normal file
48
src/components/main/t-shareBtn.vue
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
<template>
|
||||||
|
<div class="share-box">
|
||||||
|
<div class="share-btn" @click="shareContent()">
|
||||||
|
<v-icon style="color:var(--theme-switch-icon)">
|
||||||
|
mdi-share-variant
|
||||||
|
</v-icon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script lang="ts" setup>
|
||||||
|
// utils
|
||||||
|
import { generateShareImg } from "../../utils/TGShare";
|
||||||
|
|
||||||
|
interface TShareBtnProps {
|
||||||
|
modelValue: HTMLElement;
|
||||||
|
title: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const props = defineProps<TShareBtnProps>();
|
||||||
|
|
||||||
|
async function shareContent () {
|
||||||
|
await generateShareImg(props.title, props.modelValue);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style lang="css" scoped>
|
||||||
|
.share-box {
|
||||||
|
position: absolute;
|
||||||
|
top: 20px;
|
||||||
|
right: 20px;
|
||||||
|
cursor: pointer;
|
||||||
|
border-radius: 50%;
|
||||||
|
border: var(--theme-switch-icon) 2px solid;
|
||||||
|
}
|
||||||
|
|
||||||
|
.share-box:hover {
|
||||||
|
opacity: 0.8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.share-btn {
|
||||||
|
width: 24px;
|
||||||
|
height: 24px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
margin: 5px;
|
||||||
|
padding-right: 2px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
<!-- eslint-disable vue/no-v-html -->
|
<!-- eslint-disable vue/no-v-html -->
|
||||||
<template>
|
<template>
|
||||||
<TSwitchTheme />
|
<TSwitchTheme />
|
||||||
|
<TShareBtn v-show="!loadingEmpty" v-model="annoRef" :title="annoTitle" />
|
||||||
<TOLoading v-model="loading" :title="loadingTitle" :empty="loadingEmpty" />
|
<TOLoading v-model="loading" :title="loadingTitle" :empty="loadingEmpty" />
|
||||||
<div class="anno-body">
|
<div class="anno-body">
|
||||||
<div class="anno-title">
|
<div class="anno-title">
|
||||||
@@ -9,7 +10,7 @@
|
|||||||
<div class="anno-subtitle">
|
<div class="anno-subtitle">
|
||||||
{{ annoData.subtitle }}
|
{{ annoData.subtitle }}
|
||||||
</div>
|
</div>
|
||||||
<img v-if="annoData.banner !== ''" :src="annoData.banner" alt="cover" class="anno-img">
|
<img v-if="annoData.banner !== ''" :src="annoBanner" alt="cover" class="anno-img">
|
||||||
<div class="anno-content" v-html="annoHtml" />
|
<div class="anno-content" v-html="annoHtml" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@@ -19,21 +20,28 @@ import { ref, onMounted } from "vue";
|
|||||||
import { useRoute } from "vue-router";
|
import { useRoute } from "vue-router";
|
||||||
import TOLoading from "../components/overlay/to-loading.vue";
|
import TOLoading from "../components/overlay/to-loading.vue";
|
||||||
import TSwitchTheme from "../components/main/t-switchTheme.vue";
|
import TSwitchTheme from "../components/main/t-switchTheme.vue";
|
||||||
|
import TShareBtn from "../components/main/t-shareBtn.vue";
|
||||||
// tauri
|
// tauri
|
||||||
import { appWindow } from "@tauri-apps/api/window";
|
import { appWindow } from "@tauri-apps/api/window";
|
||||||
// plugins
|
// plugins
|
||||||
import TGRequest from "../web/request/TGRequest";
|
import TGRequest from "../web/request/TGRequest";
|
||||||
import TGUtils from "../web/utils/TGUtils";
|
import TGUtils from "../web/utils/TGUtils";
|
||||||
|
import { saveImgLocal } from "../utils/TGShare";
|
||||||
|
|
||||||
// loading
|
// loading
|
||||||
const loading = ref(true as boolean);
|
const loading = ref(true as boolean);
|
||||||
const loadingTitle = ref("正在加载");
|
const loadingTitle = ref("正在加载");
|
||||||
const loadingEmpty = ref(false as boolean);
|
const loadingEmpty = ref(false as boolean);
|
||||||
|
|
||||||
|
// share
|
||||||
|
const annoRef = ref({} as HTMLElement);
|
||||||
|
const annoTitle = ref("");
|
||||||
|
|
||||||
// 数据
|
// 数据
|
||||||
const annoId = Number(useRoute().params.anno_id);
|
const annoId = Number(useRoute().params.anno_id);
|
||||||
const annoData = ref({} as TGApp.BBS.Announcement.ContentItem);
|
const annoData = ref({} as TGApp.BBS.Announcement.ContentItem);
|
||||||
const annoHtml = ref("");
|
const annoHtml = ref("");
|
||||||
|
const annoBanner = ref("");
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
await appWindow.show();
|
await appWindow.show();
|
||||||
@@ -49,8 +57,13 @@ onMounted(async () => {
|
|||||||
try {
|
try {
|
||||||
annoData.value = await TGRequest.Anno.getContent(annoId);
|
annoData.value = await TGRequest.Anno.getContent(annoId);
|
||||||
loadingTitle.value = "正在渲染数据...";
|
loadingTitle.value = "正在渲染数据...";
|
||||||
annoHtml.value = TGUtils.Anno.parseContent(annoData.value.content);
|
annoHtml.value = await TGUtils.Anno.parseContent(annoData.value.content);
|
||||||
|
annoBanner.value = await saveImgLocal(annoData.value.banner);
|
||||||
|
console.log(annoBanner.value);
|
||||||
|
annoTitle.value = annoData.value.title;
|
||||||
|
annoRef.value = document.querySelector(".anno-body") as HTMLElement;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
loadingEmpty.value = true;
|
loadingEmpty.value = true;
|
||||||
loadingTitle.value = "公告不存在或解析失败";
|
loadingTitle.value = "公告不存在或解析失败";
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -222,7 +222,7 @@ import MysOper from "../plugins/Mys";
|
|||||||
// utils
|
// utils
|
||||||
import { createTGWindow } from "../utils/TGWindow";
|
import { createTGWindow } from "../utils/TGWindow";
|
||||||
// interface
|
// interface
|
||||||
import { NewsCard, NewsData } from "../plugins/Mys/interface/news";
|
import { NewsCard } from "../plugins/Mys/interface/news";
|
||||||
|
|
||||||
// 路由
|
// 路由
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
<!-- eslint-disable vue/no-v-html -->
|
<!-- eslint-disable vue/no-v-html -->
|
||||||
<template>
|
<template>
|
||||||
<TSwitchTheme />
|
<TSwitchTheme />
|
||||||
|
<TShareBtn v-show="!loadingEmpty" v-model="postRef" :title="postTitle" />
|
||||||
<TOLoading v-model="loading" :empty="loadingEmpty" :title="loadingTitle" />
|
<TOLoading v-model="loading" :empty="loadingEmpty" :title="loadingTitle" />
|
||||||
<div class="mys-post-body" v-html="postHtml" />
|
<div class="mys-post-body" v-html="postHtml" />
|
||||||
</template>
|
</template>
|
||||||
@@ -9,21 +10,27 @@
|
|||||||
import { ref, onMounted } from "vue";
|
import { ref, onMounted } from "vue";
|
||||||
import { useRoute } from "vue-router";
|
import { useRoute } from "vue-router";
|
||||||
import TOLoading from "../components/overlay/to-loading.vue";
|
import TOLoading from "../components/overlay/to-loading.vue";
|
||||||
|
import TSwitchTheme from "../components/main/t-switchTheme.vue";
|
||||||
|
import TShareBtn from "../components/main/t-shareBtn.vue";
|
||||||
// tauri
|
// tauri
|
||||||
import { appWindow } from "@tauri-apps/api/window";
|
import { appWindow } from "@tauri-apps/api/window";
|
||||||
// plugins
|
// plugins
|
||||||
import MysOper from "../plugins/Mys";
|
import MysOper from "../plugins/Mys";
|
||||||
import TSwitchTheme from "../components/main/t-switchTheme.vue";
|
|
||||||
|
|
||||||
// loading
|
// loading
|
||||||
const loading = ref(true as boolean);
|
const loading = ref(true as boolean);
|
||||||
const loadingTitle = ref("正在加载");
|
const loadingTitle = ref("正在加载");
|
||||||
const loadingEmpty = ref(false as boolean);
|
const loadingEmpty = ref(false as boolean);
|
||||||
|
|
||||||
|
// share
|
||||||
|
const postRef = ref({} as HTMLElement);
|
||||||
|
const postTitle = ref("");
|
||||||
|
|
||||||
// 数据
|
// 数据
|
||||||
const postId = Number(useRoute().params.post_id);
|
const postId = Number(useRoute().params.post_id);
|
||||||
const postHtml = ref("");
|
const postHtml = ref("");
|
||||||
|
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
await appWindow.show();
|
await appWindow.show();
|
||||||
// 检查数据
|
// 检查数据
|
||||||
@@ -39,6 +46,8 @@ onMounted(async () => {
|
|||||||
const postData = await MysOper.Post.get(postId);
|
const postData = await MysOper.Post.get(postId);
|
||||||
loadingTitle.value = "正在渲染数据...";
|
loadingTitle.value = "正在渲染数据...";
|
||||||
postHtml.value = MysOper.Post.parser(postData);
|
postHtml.value = MysOper.Post.parser(postData);
|
||||||
|
postTitle.value = postData.post.subject;
|
||||||
|
postRef.value = document.querySelector(".mys-post-body") as HTMLElement;
|
||||||
await appWindow.setTitle(postData.post.subject);
|
await appWindow.setTitle(postData.post.subject);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error);
|
console.error(error);
|
||||||
|
|||||||
@@ -1,19 +1,20 @@
|
|||||||
/**
|
/**
|
||||||
* @file web utils parseAnno.ts
|
* @file web utils parseAnno.ts
|
||||||
* @description 解析游戏内公告数据
|
* @description 解析游戏内公告数据
|
||||||
* @author BTMuli<bt-muli@outlook.com>
|
* @author BTMuli <bt-muli@outlook.com>
|
||||||
* @since Alpha v0.1.5
|
* @since Alpha v0.2.0
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { decodeRegExp } from "./tools";
|
import { decodeRegExp } from "./tools";
|
||||||
|
import { saveImgLocal } from "../../utils/TGShare";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @description 解析游戏内公告数据
|
* @description 解析游戏内公告数据
|
||||||
* @since Alpha v0.1.5
|
* @since Alpha v0.2.0
|
||||||
* @param {string} data 游戏内公告数据
|
* @param {string} data 游戏内公告数据
|
||||||
* @returns {string} 解析后的数据
|
* @returns {Promise<string>} 解析后的数据
|
||||||
*/
|
*/
|
||||||
export function parseAnnoContent (data: string): string {
|
export async function parseAnnoContent(data: string): Promise<string> {
|
||||||
const htmlBase = new DOMParser().parseFromString(data, "text/html");
|
const htmlBase = new DOMParser().parseFromString(data, "text/html");
|
||||||
htmlBase.querySelectorAll("span").forEach((span) => {
|
htmlBase.querySelectorAll("span").forEach((span) => {
|
||||||
if (span.style.fontSize) {
|
if (span.style.fontSize) {
|
||||||
@@ -40,11 +41,16 @@ export function parseAnnoContent (data: string): string {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
htmlBase.querySelectorAll("img").forEach((img) => {
|
const imgList = Array.from(htmlBase.querySelectorAll("img"));
|
||||||
|
for (const img of imgList) {
|
||||||
img.style.maxWidth = "100%";
|
img.style.maxWidth = "100%";
|
||||||
img.style.borderRadius = "10px";
|
img.style.borderRadius = "10px";
|
||||||
img.style.margin = "10px 0";
|
img.style.margin = "10px 0";
|
||||||
});
|
const src = img.getAttribute("src");
|
||||||
|
if (src) {
|
||||||
|
img.setAttribute("src", await saveImgLocal(src));
|
||||||
|
}
|
||||||
|
}
|
||||||
htmlBase.querySelectorAll("a").forEach((a) => {
|
htmlBase.querySelectorAll("a").forEach((a) => {
|
||||||
const span = htmlBase.createElement("i");
|
const span = htmlBase.createElement("i");
|
||||||
span.classList.add("mdi", "mdi-link-variant", "anno-link-icon");
|
span.classList.add("mdi", "mdi-link-variant", "anno-link-icon");
|
||||||
|
|||||||
Reference in New Issue
Block a user