♻️ 角色 wiki 与武器 wiki 样式重构

This commit is contained in:
BTMuli
2024-01-06 18:14:35 +08:00
parent 722efe7d0c
commit ea012c428c
5 changed files with 618 additions and 96 deletions

View File

@@ -0,0 +1,237 @@
<template>
<div class="twc-box" v-if="data !== undefined">
<div class="twc-brief">
<TItembox :model-value="box" />
<div class="twc-brief-info">
<div class="twc-bi-top">
<span>{{ data.name }} {{ data.title }}</span>
<span>{{ data.description }}</span>
</div>
<div class="twc-bi-grid1">
<div class="twc-big-item">
<span>所属</span>
<span>{{ data.brief.camp }}</span>
</div>
<div class="twc-big-item">
<span>命之座</span>
<span>{{ data.brief.constellation }}</span>
</div>
<div class="twc-big-item">
<span>生日</span>
<span>{{ data.brief.birth }}</span>
</div>
</div>
<div class="twc-bi-grid2">
<div class="twc-big-item">
<span>汉语CV</span>
<span>{{ data.brief.cv.cn }}</span>
</div>
<div class="twc-big-item">
<span>日语CV</span>
<span>{{ data.brief.cv.jp }}</span>
</div>
<div class="twc-big-item">
<span>英语CV</span>
<span>{{ data.brief.cv.en }}</span>
</div>
<div class="twc-big-item">
<span>韩语CV</span>
<span>{{ data.brief.cv.kr }}</span>
</div>
</div>
</div>
</div>
<TwcMaterials :data="data.materials" />
<TwcSkills :data="data.skills" />
<TwcConstellations :data="data.constellation" />
<v-expansion-panels class="twc-text-item">
<v-expansion-panel>
<template #title><span class="twc-text-title">资料</span></template>
<template #text>
<v-expansion-panels variant="popout">
<v-expansion-panel
expand-icon="mdi-menu-down"
v-for="(item, index) in data?.talks"
:key="index"
>
<template #title
><span class="twc-text-item-title">{{ item.Title }}</span></template
>
<template #text
><span class="twc-text-item-content">{{ item.Context }}</span></template
>
</v-expansion-panel>
</v-expansion-panels>
</template>
</v-expansion-panel>
<v-expansion-panel>
<template #title><span class="twc-text-title">故事</span></template>
<template #text>
<v-expansion-panels variant="popout">
<v-expansion-panel
expand-icon="mdi-menu-down"
v-for="(item, index) in data.stories"
:key="index"
>
<template #title
><span class="twc-text-item-title">{{ item.Title }}</span></template
>
<template #text
><span class="twc-text-item-content">{{ item.Context }}</span></template
>
</v-expansion-panel>
</v-expansion-panels>
</template>
</v-expansion-panel>
</v-expansion-panels>
</div>
</template>
<script setup lang="ts">
import { computed, onMounted, ref, watch } from "vue";
import TwcConstellations from "./twc-constellations.vue";
import TwcMaterials from "./twc-materials.vue";
import TwcSkills from "./twc-skills.vue";
import { getWikiData } from "../../data";
import showSnackbar from "../func/snackbar";
import TItembox, { TItemBoxData } from "../main/t-itembox.vue";
interface TwcCharacterProps {
item: TGApp.App.Character.WikiBriefInfo;
}
interface TwcCharacterEmits {
error: (err: Error) => void;
}
const props = defineProps<TwcCharacterProps>();
const emits = defineEmits<TwcCharacterEmits>();
const data = ref<TGApp.App.Character.WikiItem>();
const box = computed(() => {
return <TItemBoxData>{
bg: `/icon/bg/${data.value?.star}-Star.webp`,
icon: `/WIKI/character/${data.value?.id}.webp`,
size: "128px",
height: "128px",
display: "inner",
lt: `/icon/element/${data.value?.element}元素.webp`,
ltSize: "40px",
innerHeight: 30,
innerIcon: `/icon/weapon/${data.value?.weapon}.webp`,
innerText: data.value?.name,
clickable: false,
};
});
async function loadData(): Promise<void> {
try {
const res = await getWikiData("Character", props.item.id);
if (res === undefined) return;
data.value = res.default;
showSnackbar({
text: `成功获取角色 ${props.item.name} 的 Wiki 数据`,
color: "success",
});
} catch (error) {
showSnackbar({
text: `未获取到角色 ${props.item.name} 的 Wiki 数据`,
color: "error",
});
console.error(error);
emits("error", error);
}
}
watch(
() => props.item,
async () => {
await loadData();
},
);
onMounted(async () => {
await loadData();
});
</script>
<style lang="css" scoped>
.twc-box {
display: flex;
flex-direction: column;
margin: 0 auto;
row-gap: 10px;
}
.twc-brief {
display: flex;
align-items: flex-start;
column-gap: 10px;
}
.twc-brief-info {
display: flex;
flex-direction: column;
justify-content: space-between;
}
.twc-bi-top {
display: flex;
flex-direction: column;
}
.twc-bi-top :nth-child(1) {
color: var(--common-text-title);
font-family: var(--font-title);
font-size: 20px;
}
.twc-bi-top :nth-child(2) {
display: flex;
align-items: flex-end;
font-size: 14px;
opacity: 0.8;
}
.twc-bi-grid1 {
display: grid;
column-gap: 10px;
grid-template-columns: repeat(3, 1fr);
}
.twc-bi-grid2 {
display: grid;
column-gap: 10px;
grid-template-columns: repeat(2, 1fr);
}
.twc-big-item {
display: flex;
column-gap: 5px;
}
.twc-big-item :nth-child(1) {
font-weight: bold;
}
.twc-text-title {
color: var(--common-text-title);
font-family: var(--font-title);
font-size: 18px;
}
.twc-text-item {
display: flex;
flex-direction: column;
row-gap: 5px;
}
.twc-text-item-title {
font-weight: bold;
}
.twc-text-item-content {
font-size: 14px;
white-space: pre-wrap;
word-break: break-all;
}
</style>

View File

@@ -0,0 +1,90 @@
<template>
<div class="twc-li-box">
<div class="twc-li-left">
<img class="twc-li-bg" :src="getBg()" alt="bg" />
<img class="twc-li-icon" :src="getIcon()" alt="icon" />
</div>
<div class="twc-li-right" :title="props.data.name">{{ props.data.name }}</div>
</div>
</template>
<script lang="ts" setup>
import { computed } from "vue";
type TwcListItemProps =
| {
mode: "character";
data: TGApp.App.Character.WikiBriefInfo;
curItem: TGApp.App.Character.WikiBriefInfo;
}
| {
mode: "weapon";
data: TGApp.App.Weapon.WikiBriefInfo;
curItem: TGApp.App.Weapon.WikiBriefInfo;
};
const props = defineProps<TwcListItemProps>();
const isSelected = computed(() => {
return props.data.id === props.curItem.id;
});
const bgColor = computed(() => {
return isSelected.value ? "var(--box-bg-2)" : "var(--box-bg-1)";
});
function getBg(): string {
return `/icon/bg/${props.data.star}-Star.webp`;
}
function getIcon(): string {
if (props.mode === "character") {
return `/WIKI/character/${props.data.id}.webp`;
} else {
return `/WIKI/weapon/${props.data.id}.webp`;
}
}
</script>
<style lang="css" scoped>
.twc-li-box {
position: relative;
display: flex;
height: 45px;
align-items: center;
border: 1px solid var(--common-shadow-1);
border-radius: 5px;
background: v-bind(bgColor);
gap: 10px;
}
.twc-li-left {
width: 45px;
height: 45px;
border-bottom-left-radius: 5px;
border-top-left-radius: 5px;
}
.twc-li-bg,
.twc-li-icon {
position: absolute;
top: 0;
width: 45px;
height: 45px;
border-bottom-left-radius: 5px;
border-top-left-radius: 5px;
}
.twc-li-bg img,
.twc-li-icon img {
width: 100%;
height: 100%;
border-bottom-left-radius: 5px;
border-top-left-radius: 5px;
object-fit: cover;
}
.twc-li-right {
overflow: hidden;
color: var(--app-page-content);
font-size: 14px;
text-overflow: ellipsis;
white-space: nowrap;
}
</style>

View File

@@ -0,0 +1,163 @@
<template>
<div class="tww-box" v-if="data !== undefined">
<div class="tww-brief">
<TItembox :model-value="box" />
<div class="tww-brief-info">
<div class="tww-brief-title">{{ data.name }}</div>
<v-rating
class="tww-brief-rating"
v-model="select"
:length="selectItems.length"
:size="24"
dense
/>
<div class="tww-brief-desc">{{ data.description }}</div>
</div>
</div>
<TwcMaterials :data="data.materials" />
<v-expansion-panels class="tww-affix">
<v-expansion-panel expand-icon="mdi-menu-down">
<template #title>
<span class="tww-text-title">{{ data.affix.Name }}-精炼 {{ select }}</span>
</template>
<template #text>
<span
class="tww-text-content"
v-html="parseHtmlText(data.affix.Descriptions[select - 1].Description)"
/>
</template>
</v-expansion-panel>
</v-expansion-panels>
<v-expansion-panels class="tww-story">
<v-expansion-panel
expand-icon="mdi-menu-down"
v-for="(story, index) in data.story"
:key="index"
>
<template #title>
<span class="tww-text-title">
{{ data.story.length > 1 ? `故事 ${index + 1}` : "故事" }}
</span>
</template>
<template #text>
<span class="tww-text-content">{{ parseHtmlText(story) }}</span>
</template>
</v-expansion-panel>
</v-expansion-panels>
</div>
</template>
<script lang="ts" setup>
import { computed, onMounted, ref, watch } from "vue";
import TwcMaterials from "./twc-materials.vue";
import { getWikiData } from "../../data";
import { parseHtmlText } from "../../utils/toolFunc";
import showSnackbar from "../func/snackbar";
import TItembox, { TItemBoxData } from "../main/t-itembox.vue";
interface TwcWeaponProps {
item: TGApp.App.Weapon.WikiBriefInfo;
}
interface TwcWeaponEmits {
error: (err: Error) => void;
}
const props = defineProps<TwcWeaponProps>();
const emits = defineEmits<TwcWeaponEmits>();
const data = ref<TGApp.App.Weapon.WikiItem>();
const box = computed(() => {
return <TItemBoxData>{
bg: `/icon/bg/${data.value?.star}-Star.webp`,
icon: `/WIKI/weapon/${data.value?.id}.webp`,
size: "128px",
height: "128px",
display: "inner",
lt: `/icon/weapon/${data.value?.weapon}.webp`,
ltSize: "40px",
innerHeight: 0,
clickable: false,
};
});
const select = ref<number>(1);
const selectItems = ref<number[]>([]);
async function loadData(): Promise<void> {
try {
const res = await getWikiData("Weapon", props.item.id);
if (res === undefined) return;
data.value = res.default;
selectItems.value = data.value?.affix.Descriptions.map((item) => item.Level) ?? [];
} catch (error) {
showSnackbar({
text: `未获取到武器 ${props.item.name} 的 Wiki 数据`,
color: "error",
});
emits("error", error);
}
}
watch(
() => props.item,
async () => {
await loadData();
},
);
onMounted(async () => {
await loadData();
});
</script>
<style lang="css" scoped>
.tww-box {
display: flex;
flex-direction: column;
margin: 0 auto;
row-gap: 10px;
}
.tww-brief {
display: flex;
align-items: flex-start;
column-gap: 10px;
}
.tww-brief-info {
display: flex;
flex-direction: column;
justify-content: space-between;
}
.tww-brief-title {
color: var(--common-text-title);
font-family: var(--font-title);
font-size: 20px;
}
.tww-brief-rating {
color: var(--common-text-title);
}
.tww-brief-desc {
display: flex;
align-items: flex-end;
opacity: 0.8;
}
.tww-story {
display: flex;
flex-direction: column;
row-gap: 5px;
}
.tww-text-title {
font-weight: bold;
}
.tww-text-content {
font-size: 14px;
white-space: pre-wrap;
word-break: break-all;
}
</style>