🎨 一些代码调整

This commit is contained in:
目棃
2024-12-06 14:36:30 +08:00
parent f4678be198
commit dd65bb565d
32 changed files with 401 additions and 589 deletions

View File

@@ -6,10 +6,10 @@
</transition>
</template>
<script lang="ts" setup>
import { ref, onMounted, onUnmounted } from "vue";
import { onMounted, onUnmounted, ref } from "vue";
const scrollTop = ref(0); // 滚动条距离顶部的距离
const canTop = ref(false); // 默认不显示
const scrollTop = ref<number>(0); // 滚动条距离顶部的距离
const canTop = ref<boolean>(false); // 默认不显示
// 监听滚动事件
function handleScroll(): void {
@@ -40,15 +40,8 @@ function handleScrollTop(): void {
});
}
// 监听滚动事件
onMounted(() => {
window.addEventListener("scroll", handleScroll);
});
// 销毁监听
onUnmounted(() => {
window.removeEventListener("scroll", handleScroll);
});
onMounted(() => window.addEventListener("scroll", handleScroll));
onUnmounted(() => window.removeEventListener("scroll", handleScroll));
</script>
<style scoped>

View File

@@ -12,7 +12,7 @@
</template>
<script lang="ts" setup>
import { emit } from "@tauri-apps/api/event";
import { computed, onMounted, ref, watch } from "vue";
import { computed, onMounted, ref, shallowRef, watch } from "vue";
import Mys from "../../plugins/Mys/index.js";
import { useAppStore } from "../../store/modules/app.js";
@@ -25,17 +25,12 @@ import showSnackbar from "../func/snackbar.js";
import ToLivecode from "./to-livecode.vue";
interface TGameNavProps {
modelValue: number;
}
const props = withDefaults(defineProps<TGameNavProps>(), {
modelValue: 2,
});
type TGameNavProps = { modelValue: number };
const props = withDefaults(defineProps<TGameNavProps>(), { modelValue: 2 });
const appStore = useAppStore();
const nav = ref<TGApp.BBS.Navigator.Navigator[]>([]);
const codeData = ref<TGApp.BBS.Navigator.CodeData[]>([]);
const nav = shallowRef<TGApp.BBS.Navigator.Navigator[]>([]);
const codeData = shallowRef<TGApp.BBS.Navigator.CodeData[]>([]);
const showOverlay = ref<boolean>(false);
const actId = ref<string>();

View File

@@ -8,23 +8,13 @@
</transition>
</template>
<script lang="ts" setup>
// vue
import { ref, watch } from "vue";
interface TolProps {
modelValue: boolean;
toClick?: () => void;
blurVal: string;
hide?: true;
}
type TolProps = { modelValue: boolean; toClick?: () => void; blurVal: string; hide?: true };
const props = withDefaults(defineProps<TolProps>(), {
modelValue: false,
blurVal: "20px",
});
const showTolo = ref(!props.hide);
const showToli = ref(!props.hide);
const props = withDefaults(defineProps<TolProps>(), { modelValue: false, blurVal: "20px" });
const showTolo = ref<boolean>(!props.hide);
const showToli = ref<boolean>(!props.hide);
watch(
() => props.modelValue,
@@ -32,14 +22,10 @@ watch(
if (props.modelValue) {
showTolo.value = true;
showToli.value = true;
} else {
setTimeout(() => {
showToli.value = false;
}, 100);
setTimeout(() => {
showTolo.value = false;
}, 300);
return;
}
setTimeout(() => (showToli.value = false), 100);
setTimeout(() => (showTolo.value = false), 300);
},
);
</script>

View File

@@ -15,10 +15,10 @@
</div>
<div class="tpc-title" :title="card.title" @click="shareCard">{{ card.title }}</div>
</div>
<div class="tpc-mid" v-if="card.user">
<div class="tpc-mid" v-if="card.user !== null">
<TpAvatar :data="card.user" position="left" />
</div>
<div class="tpc-bottom" v-if="card.data">
<div class="tpc-bottom" v-if="card.data !== null">
<div class="tpc-tags">
<div v-for="topic in card.topics" :key="topic.id" class="tpc-tag" @click="toTopic(topic)">
<v-icon size="10">mdi-tag</v-icon>
@@ -50,7 +50,7 @@
</div>
<div
class="tpc-forum"
v-if="card.forum && card.forum.name !== ''"
v-if="card.forum !== null && card.forum.name !== ''"
:title="`频道: ${card.forum.name}`"
@click="toForum(card.forum)"
>
@@ -68,27 +68,20 @@
</template>
<script lang="ts" setup>
import { emit } from "@tauri-apps/api/event";
import { computed, onMounted, onUnmounted, ref, watch } from "vue";
import { computed, onMounted, onUnmounted, ref, shallowRef, watch } from "vue";
import { generateShareImg, saveImgLocal } from "../../utils/TGShare.js";
import { createPost } from "../../utils/TGWindow.js";
import showSnackbar from "../func/snackbar.js";
import TpAvatar from "../viewPost/tp-avatar.vue";
interface TPostCardProps {
modelValue: TGApp.Plugins.Mys.Post.FullData;
selectMode?: boolean;
}
type TPostCardProps = { modelValue: TGApp.Plugins.Mys.Post.FullData; selectMode?: boolean };
type TPostCardEmits = (e: "onSelected", v: string) => void;
interface TPostCardEmits {
(e: "onSelected", value: string): void;
}
const props = withDefaults(defineProps<TPostCardProps>(), {
selectMode: false,
});
const props = withDefaults(defineProps<TPostCardProps>(), { selectMode: false });
const emits = defineEmits<TPostCardEmits>();
const isAct = ref<boolean>(false);
const card = ref<TGApp.Plugins.Mys.News.RenderCard>();
const card = shallowRef<TGApp.Plugins.Mys.News.RenderCard>();
const localCover = ref<string>();
const cardBg = computed<string>(() => {
@@ -106,9 +99,8 @@ async function reload(data: TGApp.Plugins.Mys.Post.FullData): Promise<void> {
localCover.value = undefined;
}
card.value = getPostCard(data);
if (card.value && card.value.cover !== "") {
if (card.value && card.value.cover !== "")
localCover.value = await saveImgLocal(card.value.cover);
}
}
onUnmounted(() => {
@@ -186,32 +178,30 @@ function getPostCover(item: TGApp.Plugins.Mys.Post.FullData): string {
* @returns {TGApp.Plugins.Mys.News.RenderCard} 渲染用咨讯列表项
*/
function getCommonCard(item: TGApp.Plugins.Mys.Post.FullData): TGApp.Plugins.Mys.News.RenderCard {
let forum: TGApp.Plugins.Mys.News.RenderForum | null = null;
let data: TGApp.Plugins.Mys.News.RenderData | null = null;
if (item.forum !== null) {
forum = {
name: item.forum.name,
icon: item.forum.icon,
id: item.forum.id,
};
}
if (item.stat !== null) {
data = {
mark: item.stat.bookmark_num,
forward: item.stat.forward_num,
like: item.stat.like_num,
reply: item.stat.reply_num,
view: item.stat.view_num,
};
}
return {
title: item.post.subject,
cover: getPostCover(item),
postId: Number(item.post.post_id),
subtitle: item.post.post_id,
user: item.user,
forum: forum,
data: data,
forum:
item.forum !== null
? {
name: item.forum.name,
icon: item.forum.icon,
id: item.forum.id,
}
: null,
data:
item.stat !== null
? {
mark: item.stat.bookmark_num,
forward: item.stat.forward_num,
like: item.stat.like_num,
reply: item.stat.reply_num,
view: item.stat.view_num,
}
: null,
topics: item.topics,
};
}
@@ -235,9 +225,13 @@ function getPostCard(item: TGApp.Plugins.Mys.Post.FullData): TGApp.Plugins.Mys.N
async function shareCard(): Promise<void> {
if (!card.value) return;
const dom = <HTMLDivElement>document.querySelector(`#post-card-${card.value.postId}`);
const shareDom = document.querySelector<HTMLDivElement>(`#post-card-${card.value.postId}`);
if (shareDom === null) {
showSnackbar.error("分享内容不存在", 3000);
return;
}
const fileName = `PostCard_${card.value.postId}`;
await generateShareImg(fileName, dom, 2.5);
await generateShareImg(fileName, shareDom, 2.5);
}
async function toTopic(topic: TGApp.Plugins.Mys.Topic.Info): Promise<void> {

View File

@@ -9,31 +9,28 @@
import TGLogger from "../../utils/TGLogger.js";
import { generateShareImg } from "../../utils/TGShare.js";
import showLoading from "../func/loading.js";
import showSnackbar from "../func/snackbar.js";
interface TShareBtnProps {
modelValue: HTMLElement;
title: string;
}
type TShareBtnProps = { selector: string; title: string };
const props = defineProps<TShareBtnProps>();
async function shareContent(): Promise<void> {
showLoading.start("正在生成分享图片", props.title);
await TGLogger.Info("[TShareBtn][shareContent] 开始生成分享图片");
props.modelValue.querySelectorAll("details").forEach((item) => {
if (item.open) {
item.setAttribute("details-open", "");
} else {
item.open = true;
}
const shareDom = document.querySelector<HTMLElement>(props.selector);
if (shareDom === null) {
showSnackbar.error("分享内容不存在", 3000);
showLoading.end();
return;
}
shareDom.querySelectorAll("details").forEach((item) => {
if (item.open) item.setAttribute("details-open", "");
else item.open = true;
});
await generateShareImg(props.title, props.modelValue);
props.modelValue.querySelectorAll("details").forEach((item) => {
if (item.hasAttribute("details-open")) {
item.removeAttribute("details-open");
} else {
item.open = false;
}
await generateShareImg(props.title, shareDom);
shareDom.querySelectorAll("details").forEach((item) => {
if (item.hasAttribute("details-open")) item.removeAttribute("details-open");
else item.open = false;
});
showLoading.end();
await TGLogger.Info("[TShareBtn][shareContent] 生成分享图片完成");

View File

@@ -2,7 +2,7 @@
<v-navigation-drawer :permanent="true" :rail="rail" class="tsb-box">
<v-list class="side-list" density="compact" :nav="true">
<!-- 负责收缩侧边栏 -->
<v-list-item @click="collapse()">
<v-list-item @click="rail = !rail">
<template v-if="rail" #prepend>
<v-list-item-action>
<v-icon>mdi-chevron-right</v-icon>
@@ -202,7 +202,7 @@
class="side-item-menu"
title="登录"
@click="login"
v-show="userStore.cookie.value?.stoken === ''"
v-show="cookie?.stoken === ''"
>
<template #prepend>
<img src="/source/UI/lumine.webp" class="side-icon-menu" alt="login" />
@@ -231,71 +231,46 @@
<script lang="ts" setup>
import { event, webviewWindow } from "@tauri-apps/api";
import { UnlistenFn, Event } from "@tauri-apps/api/event";
import { Event, UnlistenFn } from "@tauri-apps/api/event";
import { storeToRefs } from "pinia";
import { computed, onMounted, onUnmounted, ref, watch } from "vue";
import { computed, onMounted, onUnmounted, shallowRef } from "vue";
import { useAppStore } from "../../store/modules/app.js";
import { useUserStore } from "../../store/modules/user.js";
import mhyClient from "../../utils/TGClient.js";
import TGLogger from "../../utils/TGLogger.js";
import showSnackbar from "../func/snackbar.js";
const appStore = useAppStore();
const userStore = storeToRefs(useUserStore());
const { cookie, briefInfo } = storeToRefs(useUserStore());
const isDevEnv = ref<boolean>(import.meta.env.MODE === "development");
const userInfo = ref({
nickname: "未登录",
uid: "-1",
desc: "请扫码登录",
avatar: "/source/UI/lumine.webp",
// @ts-expect-error The import.meta meta-property is not allowed in files which will build into CommonJS output.
const isDevEnv = import.meta.env.MODE === "development";
const themeListener = shallowRef<UnlistenFn | null>(null);
const rail = computed<boolean>({
get: () => appStore.sidebar.collapse,
set: (v: boolean) => (appStore.sidebar.collapse = v),
});
watch(userStore.briefInfo, (val) => {
if (val && val.nickname) {
userInfo.value = val;
}
const userInfo = computed<TGApp.App.Account.BriefInfo>(() => {
if (briefInfo.value && briefInfo.value.nickname) return briefInfo.value;
return {
nickname: "未登录",
uid: "-1",
desc: "请扫码登录",
avatar: "/source/UI/lumine.webp",
};
});
const rail = ref(appStore.sidebar.collapse);
// theme
const themeGet = computed({
get() {
return appStore.theme;
},
set(value: string) {
appStore.theme = value;
},
const themeGet = computed<string>({
get: () => appStore.theme,
set: (v: string) => (appStore.theme = v),
});
const themeTitle = computed(() => {
return themeGet.value === "default" ? "夜间模式" : "日间模式";
});
watch(themeTitle, async (val) => {
const themeNow = val === "夜间模式" ? "浅色模式" : "深色模式";
await TGLogger.Info(`[App][theme] 已切换到${themeNow}`);
});
function collapse(): void {
rail.value = !rail.value;
appStore.sidebar.collapse = rail.value;
}
let themeListener: UnlistenFn;
const themeTitle = computed<string>(() => (themeGet.value === "default" ? "夜间模式" : "日间模式"));
onMounted(async () => {
themeListener = await event.listen("readTheme", (e: Event<string>) => {
themeListener.value = await event.listen("readTheme", (e: Event<string>) => {
const theme = e.payload;
themeGet.value = theme === "default" ? "default" : "dark";
});
if (webviewWindow.getCurrentWebviewWindow().label === "TeyvatGuide") {
await mhyClient.run();
}
if (userStore.briefInfo.value && userStore.briefInfo.value.nickname) {
userInfo.value = userStore.briefInfo.value;
}
if (webviewWindow.getCurrentWebviewWindow().label === "TeyvatGuide") await mhyClient.run();
});
async function switchTheme(): Promise<void> {
@@ -303,21 +278,16 @@ async function switchTheme(): Promise<void> {
}
async function openClient(func: string): Promise<void> {
if (appStore.isLogin) {
await mhyClient.open(func);
} else {
login();
if (appStore.isLogin) await mhyClient.open(func);
else showSnackbar.warn("请前往设置页面登录!");
}
onUnmounted(() => {
if (themeListener.value !== null) {
themeListener.value();
themeListener.value = null;
}
}
function login(): void {
showSnackbar({
text: "请前往设置页面登录!",
color: "warn",
});
}
onUnmounted(() => themeListener());
});
</script>
<style lang="css" scoped>

View File

@@ -1,13 +1,11 @@
<template>
<div class="tsl-box">
<img src="../../assets/icons/arrow-right.svg" alt="right" />
<slot>{{ props.title }}</slot>
<slot>{{ title }}</slot>
</div>
</template>
<script lang="ts" setup>
const props = defineProps<{
title?: string;
}>();
defineProps<{ title?: string }>();
</script>
<style lang="css" scoped>
.tsl-box {

View File

@@ -9,25 +9,19 @@
</template>
<script lang="ts" setup>
import { event } from "@tauri-apps/api";
import { UnlistenFn, Event } from "@tauri-apps/api/event";
import { computed, onMounted, onUnmounted } from "vue";
import { Event, UnlistenFn } from "@tauri-apps/api/event";
import { computed, onMounted, onUnmounted, shallowRef } from "vue";
import { useAppStore } from "../../store/modules/app.js";
const appStore = useAppStore();
const themeGet = computed({
get() {
return appStore.theme;
},
set(value: string) {
appStore.theme = value;
},
const themeGet = computed<string>({
get: () => appStore.theme,
set: (v: string) => (appStore.theme = v),
});
let themeListener: UnlistenFn | null = null;
const themeListener = shallowRef<UnlistenFn | null>(null);
onMounted(async () => {
themeListener = await listenOnTheme();
});
onMounted(async () => (themeListener.value = await listenOnTheme()));
async function switchTheme(): Promise<void> {
appStore.changeTheme();
@@ -42,9 +36,9 @@ async function listenOnTheme(): Promise<UnlistenFn> {
}
onUnmounted(() => {
if (themeListener !== null) {
themeListener();
themeListener = null;
if (themeListener.value !== null) {
themeListener.value();
themeListener.value = null;
}
});
</script>

View File

@@ -64,16 +64,14 @@ interface ToLiveCodeProps {
modelValue: boolean;
}
type ToLiveCodeEmits = (e: "update:modelValue", value: boolean) => void;
type ToLiveCodeEmits = (e: "update:modelValue", v: boolean) => void;
const props = withDefaults(defineProps<ToLiveCodeProps>(), { modelValue: false });
const emits = defineEmits<ToLiveCodeEmits>();
const visible = computed<boolean>({
get: () => props.modelValue,
set: (value) => {
emits("update:modelValue", value);
},
set: (v: boolean) => emits("update:modelValue", v),
});
function onCancel(): void {
@@ -86,7 +84,11 @@ function copy(code: string): void {
}
async function shareImg(): Promise<void> {
const element = <HTMLElement>document.querySelector(".tolc-box");
const element = document.querySelector<HTMLElement>(".tolc-box");
if (element === null) {
showSnackbar.error("未获取到分享内容");
return;
}
const fileName = `LiveCode_${props.actId}_${new Date().getTime()}`;
await generateShareImg(fileName, element, 2);
}

View File

@@ -1,5 +1,5 @@
<template>
<v-list class="top-nc-box" @click="toNameCard(props.data)">
<v-list class="top-nc-box" @click="emit('selected', props.data)">
<v-list-item :title="props.data.name">
<template #subtitle>
<span :title="props.data.desc">{{ props.data.desc }}</span>
@@ -13,13 +13,8 @@
<script lang="ts" setup>
import { computed } from "vue";
interface TopNameCardProps {
data: TGApp.App.NameCard.Item;
}
interface TopNameCardEmits {
(e: "selected", data: TGApp.App.NameCard.Item): void;
}
type TopNameCardProps = { data: TGApp.App.NameCard.Item };
type TopNameCardEmits = (e: "selected", v: TGApp.App.NameCard.Item) => void;
const props = defineProps<TopNameCardProps>();
const emit = defineEmits<TopNameCardEmits>();
@@ -28,10 +23,6 @@ const bgImage = computed<string>(() => {
if (props.data.name === "原神·印象") return "none;";
return `url("${props.data.bg}")`;
});
function toNameCard(item: TGApp.App.NameCard.Item) {
emit("selected", item);
}
</script>
<style lang="css" scoped>
.top-nc-box {

View File

@@ -23,7 +23,7 @@
</transition>
</template>
<script lang="ts" setup>
import { reactive, ref, watch, onMounted, toRaw } from "vue";
import { ref, watch, onMounted, toRaw } from "vue";
import { LoadingParams } from "./loading.js";
@@ -32,7 +32,7 @@ const showOuter = ref<boolean>(false);
const showInner = ref<boolean>(false);
const props = defineProps<LoadingParams>();
const data = reactive<LoadingParams>(toRaw(props));
const data = ref<LoadingParams>(toRaw(props));
watch(
() => showBox.value,
@@ -53,15 +53,15 @@ function displayBox(params: LoadingParams): void {
if (!params.show) {
showBox.value = false;
setTimeout(() => {
data.title = "";
data.subtitle = "";
data.empty = false;
data.value.title = "";
data.value.subtitle = "";
data.value.empty = false;
}, 500);
return;
}
data.title = params.title;
data.subtitle = params.subtitle;
data.empty = params.empty;
data.value.title = params.title;
data.value.subtitle = params.subtitle;
data.value.empty = params.empty;
showBox.value = true;
}
@@ -180,7 +180,6 @@ defineExpose({ displayBox });
.loading-circle > div {
position: relative;
box-sizing: border-box;
box-sizing: border-box;
}
.loading-circle {

View File

@@ -59,6 +59,7 @@ import { AbyssDataItem } from "../../pages/WIKI/Abyss.vue";
import { generateShareImg } from "../../utils/TGShare.js";
import { timestampToDate } from "../../utils/toolFunc.js";
import TOverlay from "../app/t-overlay.vue";
import showSnackbar from "../func/snackbar.js";
import HtaOverviewLine from "./hta-overview-line.vue";
@@ -93,7 +94,12 @@ function onCancel(): void {
async function share(): Promise<void> {
loadShare.value = true;
const shareEl = <HTMLElement>document.querySelector(".hta-oo-box");
const shareEl = document.querySelector<HTMLElement>(".hta-oo-box");
if (shareEl === null) {
showSnackbar.warn("分享失败");
loadShare.value = false;
return;
}
const fileName = `深渊数据统计_${timestampToDate(dataCur.value.Timestamp)}.png`;
await generateShareImg(fileName, shareEl, 2);
loadShare.value = false;

View File

@@ -12,10 +12,7 @@
</div>
</template>
<script lang="ts" setup>
interface THomeCardProps {
append?: boolean;
}
type THomeCardProps = { append?: boolean };
const props = defineProps<THomeCardProps>();
</script>
<style lang="css" scoped>