17 changed files with 457 additions and 22 deletions
After Width: | Height: | Size: 4.9 KiB |
@ -0,0 +1,137 @@
@@ -0,0 +1,137 @@
|
||||
<template> |
||||
<teleport to="#app"> |
||||
<div class="drawer" @click="show = false" v-show="show" |
||||
@contextmenu.prevent="console.log('禁用浏览器默认右键功能')"> |
||||
<div class="content" :style="style" @click.native.stop> |
||||
<div class="title" v-if="showHeader"> |
||||
<span>{{ title }}</span> |
||||
<i class="close" @click="show = false; emit('close')"></i> |
||||
</div> |
||||
<slot /> |
||||
</div> |
||||
</div> |
||||
</teleport> |
||||
</template> |
||||
|
||||
<script lang="ts" setup> |
||||
import { useStore } from "vuex"; |
||||
import { watch, onMounted, ref, onBeforeUnmount } from "vue"; |
||||
import { useI18n } from "vue3-i18n"; |
||||
|
||||
const { t } = useI18n(); |
||||
const { state, commit, dispatch } = useStore(); |
||||
const show = ref(false); |
||||
const style = ref({}) |
||||
|
||||
const emit = defineEmits(['update:modelValue', 'close']) |
||||
const prop = defineProps({ |
||||
modelValue: { |
||||
type: Boolean, |
||||
default: false |
||||
}, |
||||
showHeader: { |
||||
type: Boolean, |
||||
default: true |
||||
}, |
||||
title: { |
||||
type: String, |
||||
defalut: "" |
||||
}, |
||||
width: { |
||||
type: String, |
||||
default: '' |
||||
}, |
||||
height: { |
||||
type: String, |
||||
default: '' |
||||
}, |
||||
direction: { |
||||
type: String, |
||||
default: 'left' |
||||
}, |
||||
padding: { |
||||
type: String, |
||||
default: '10px' |
||||
}, |
||||
}) |
||||
watch(show, (n, o) => { |
||||
emit('update:modelValue', n); |
||||
}) |
||||
watch(() => prop.modelValue, (n, o) => { |
||||
show.value = n; |
||||
}) |
||||
|
||||
const setDirection = () => { |
||||
switch (prop.direction) { |
||||
case 'left': |
||||
style.value = { left: '0', width: prop.width, height: '100%' }; |
||||
break; |
||||
case 'right': |
||||
style.value = { right: '0', width: prop.width, height: '100%' }; |
||||
break; |
||||
case 'top': |
||||
style.value = { top: '0', width: '100%', height: prop.height }; |
||||
break; |
||||
case 'bottom': |
||||
style.value = { bottom: '0', width: '100%', height: prop.height }; |
||||
break; |
||||
} |
||||
} |
||||
|
||||
watch(() => prop.direction, setDirection); |
||||
|
||||
const keydown = (e) => { |
||||
if (e.keyCode == 27) { |
||||
show.value = false; |
||||
} |
||||
} |
||||
|
||||
onMounted(() => { |
||||
setDirection(); |
||||
document.addEventListener('keydown', keydown) |
||||
}); |
||||
onBeforeUnmount(() => { |
||||
document.removeEventListener('keydown', keydown) |
||||
}); |
||||
</script> |
||||
<style lang="scss" scoped> |
||||
.drawer { |
||||
width: 100%; |
||||
height: 100%; |
||||
position: absolute; |
||||
z-index: 9; |
||||
background: rgba(0, 0, 0, 0.5); |
||||
|
||||
.content { |
||||
position: absolute; |
||||
background: rgba(0, 0, 0, 0.7); |
||||
padding: v-bind('prop.padding'); |
||||
width: v-bind('prop.width'); |
||||
} |
||||
} |
||||
|
||||
.title { |
||||
display: flex; |
||||
position: relative; |
||||
align-items: center; |
||||
justify-content: center; |
||||
font-size: 1.8rem; |
||||
height: 3.5rem; |
||||
line-height: 3.5rem; |
||||
width: 100%; |
||||
color: white; |
||||
margin-bottom: 0.5rem; |
||||
|
||||
.close { |
||||
cursor: pointer; |
||||
position: absolute; |
||||
top: 0.5rem; |
||||
right: 0.5rem; |
||||
display: block; |
||||
width: 2rem; |
||||
height: 2rem; |
||||
background-image: url(@/assets/icons/close.png); |
||||
background-size: cover; |
||||
} |
||||
} |
||||
</style> |
@ -0,0 +1,4 @@
@@ -0,0 +1,4 @@
|
||||
import Tab from './tab.vue'; |
||||
import Tabs from './tabs.vue'; |
||||
|
||||
export { Tabs, Tab }; |
@ -0,0 +1,36 @@
@@ -0,0 +1,36 @@
|
||||
<template> |
||||
<div v-show="isSelected" class="tab__pane"> |
||||
<slot /> |
||||
</div> |
||||
</template> |
||||
|
||||
<script lang="ts" setup> |
||||
import { useStore } from "vuex"; |
||||
import { getCurrentInstance, onMounted, ref, computed, watch } from "vue"; |
||||
import { useI18n } from "vue3-i18n"; |
||||
|
||||
const { t } = useI18n(); |
||||
const { state, commit, dispatch } = useStore(); |
||||
const parent: any = getCurrentInstance()?.parent; |
||||
const name = ref(""); |
||||
|
||||
const props = defineProps({ |
||||
label: { |
||||
type: String, |
||||
default: '' |
||||
}, |
||||
name: { |
||||
type: String, |
||||
default: '' |
||||
} |
||||
}) |
||||
|
||||
const isSelected = computed(() => { |
||||
return parent.exposed.curActive.value == props.name; |
||||
}) |
||||
|
||||
onMounted(() => { |
||||
name.value = props.name; |
||||
}); |
||||
</script> |
||||
<style lang="scss" scoped></style> |
@ -0,0 +1,102 @@
@@ -0,0 +1,102 @@
|
||||
<template> |
||||
<div class="tabs"> |
||||
<div class="tabs__nav"> |
||||
<div v-for="item in tabs" :key="item.name" ref="tabs" @click="curActive = item.name" class="tab" |
||||
:class="{ 'tab--active': item.name === curActive }"> |
||||
<span>{{ item.label || item.name }}</span> |
||||
</div> |
||||
</div> |
||||
<slot /> |
||||
</div> |
||||
</template> |
||||
|
||||
<script lang="ts" setup> |
||||
import { useStore } from "vuex"; |
||||
import { watch, onMounted, ref } from "vue"; |
||||
import { useI18n } from "vue3-i18n"; |
||||
|
||||
const { t } = useI18n(); |
||||
const { state, commit, dispatch } = useStore(); |
||||
const curActive = ref(''); |
||||
const emit = defineEmits(['update:modelValue']) |
||||
|
||||
const props = defineProps({ |
||||
modelValue: { |
||||
type: String, |
||||
default: '' |
||||
}, |
||||
active: { |
||||
type: String, |
||||
default: '' |
||||
}, |
||||
tabs: { |
||||
type: Array as () => any[], |
||||
default: [] |
||||
} |
||||
}) |
||||
|
||||
watch(curActive, (n, o) => { |
||||
emit('update:modelValue', n); |
||||
}) |
||||
watch(() => props.modelValue, (n, o) => { |
||||
curActive.value = n; |
||||
}) |
||||
|
||||
defineExpose({ curActive }) |
||||
|
||||
onMounted(() => { |
||||
curActive.value = props.active || props.tabs[0]?.name; |
||||
}); |
||||
</script> |
||||
<style lang="scss" scoped> |
||||
*{ |
||||
color: white; |
||||
} |
||||
.tab { |
||||
// flex: 1; |
||||
cursor: pointer; |
||||
min-width: 0; |
||||
padding: 0.3rem 0.3rem; |
||||
font-size: 14px; |
||||
position: relative; |
||||
color: #000; |
||||
line-height: 50px; |
||||
text-align: center; |
||||
box-sizing: border-box; |
||||
margin-right: 2rem; |
||||
|
||||
span { |
||||
display: block; |
||||
} |
||||
|
||||
&--active { |
||||
font-weight: 500 !important; |
||||
} |
||||
} |
||||
|
||||
.tab--active { |
||||
border-bottom: 2px solid #ccc; |
||||
} |
||||
|
||||
.tabs { |
||||
position: relative; |
||||
|
||||
&__nav { |
||||
display: flex; |
||||
user-select: none; |
||||
position: relative; |
||||
height: 100%; |
||||
box-sizing: content-box; |
||||
} |
||||
|
||||
&__line { |
||||
z-index: 1; |
||||
left: 0; |
||||
bottom: 0px; |
||||
height: 3px; |
||||
position: absolute; |
||||
border-radius: 3px; |
||||
background-color: red; |
||||
} |
||||
} |
||||
</style> |
@ -0,0 +1,76 @@
@@ -0,0 +1,76 @@
|
||||
<template> |
||||
<div class="title">{{ t('quality.' + quality) }}{{ t(type + '.type') }} |
||||
</div> |
||||
<div class="equips"> |
||||
<div class="equip" v-for="item in categorys" :key="item.name"> |
||||
<EquipIcon :equip="getShowEquip(item)" /> |
||||
<div class="name">{{ t(type + '.' + item.name + '.0') }}</div> |
||||
<div class="entry" v-for="e in item.entry">{{ t(e.type + '.0') }}</div> |
||||
</div> |
||||
</div> |
||||
</template> |
||||
|
||||
<script lang="ts" setup> |
||||
import { useStore } from "vuex"; |
||||
import { reactive, onMounted, ref } from "vue"; |
||||
import { useI18n } from "vue3-i18n"; |
||||
import { EquipIcon } from "@/components"; |
||||
import { quality_collor } from "@/config"; |
||||
|
||||
const { t } = useI18n(); |
||||
const { state, commit, dispatch } = useStore(); |
||||
const color = ref('#FFF'); |
||||
|
||||
const props = defineProps({ |
||||
type: { |
||||
type: String, |
||||
default: '' |
||||
}, |
||||
quality: { |
||||
type: String, |
||||
default: '' |
||||
}, |
||||
categorys: { |
||||
type: Array as () => any[], |
||||
default: [], |
||||
}, |
||||
}); |
||||
|
||||
const getShowEquip = (category) => { |
||||
const quality = props.quality; |
||||
const equip: any = new Object(); |
||||
equip.quality = { quality: quality, color: quality_collor[quality] }; |
||||
equip.base = { icon: category.icon }; |
||||
return equip; |
||||
} |
||||
|
||||
onMounted(() => { |
||||
color.value = quality_collor[props.quality]; |
||||
}); |
||||
</script> |
||||
<style lang="scss" scoped> |
||||
.title { |
||||
height: 2.5rem; |
||||
font-size: 1.5rem; |
||||
color: v-bind('color'); |
||||
} |
||||
|
||||
.equips { |
||||
display: flex; |
||||
flex-wrap: wrap; |
||||
width: 50rem; |
||||
|
||||
.equip { |
||||
align-items: center; |
||||
text-align: center; |
||||
justify-items: center; |
||||
width: 10rem; |
||||
margin-bottom: 1rem; |
||||
|
||||
.name { |
||||
padding-bottom: 0.5rem; |
||||
color: v-bind('color'); |
||||
} |
||||
} |
||||
} |
||||
</style> |
@ -0,0 +1,69 @@
@@ -0,0 +1,69 @@
|
||||
<template> |
||||
<Tooltip :infos="[t('illustrated.0')]" width="8rem"> |
||||
<img class="menu-img" :src="menu_icons.illustrated" @click="showMenu"> |
||||
</Tooltip> |
||||
|
||||
<Drawer :title="t('illustrated.0')" v-model="showIllustrated"> |
||||
<Tabs :tabs="tabs"> |
||||
<tab v-for="item in tabs" :name="item.name"> |
||||
<Equips :type="item.name" quality="unique" :categorys="uniques[item.name]" /> |
||||
<Equips :type="item.name" quality="epic" :categorys="epics[item.name]" /> |
||||
</tab> |
||||
</Tabs> |
||||
</Drawer> |
||||
|
||||
</template> |
||||
|
||||
<script lang="ts" setup> |
||||
import { useStore } from "vuex"; |
||||
import { computed, onMounted, ref, onBeforeUnmount } from "vue"; |
||||
import { useI18n } from "vue3-i18n"; |
||||
import { Tooltip, Drawer, Tabs, Tab } from "@/components"; |
||||
import { menu_icons, weaponCategorys, weaponUniqueCategorys, armorUniqueCategorys, armorCategorys } from "@/config"; |
||||
import { neckUniqueCategorys, neckCategorys, ringUniqueCategorys, ringCategorys } from "@/config"; |
||||
import Equips from "./equips.vue"; |
||||
|
||||
const { t } = useI18n(); |
||||
const { state, commit, dispatch } = useStore(); |
||||
const showIllustrated = computed(() => { |
||||
return state.curMenu == 'illustrated'; |
||||
}); |
||||
const uniques = { |
||||
weapon: weaponUniqueCategorys, |
||||
armor: armorUniqueCategorys, |
||||
neck: neckUniqueCategorys, |
||||
ring: ringUniqueCategorys |
||||
} |
||||
const epics = { |
||||
weapon: weaponCategorys, |
||||
armor: armorCategorys, |
||||
neck: neckCategorys, |
||||
ring: ringCategorys |
||||
} |
||||
|
||||
const tabs = [ |
||||
{ label: t('weapon.type'), name: 'weapon' }, |
||||
{ label: t('armor.type'), name: 'armor' }, |
||||
{ label: t('neck.type'), name: 'neck' }, |
||||
{ label: t('ring.type'), name: 'ring' } |
||||
] |
||||
|
||||
const showMenu = () => { |
||||
state.curMenu = showIllustrated.value ? null : 'illustrated'; |
||||
} |
||||
|
||||
const keydown = (e) => { |
||||
if (e.keyCode == 73 && !e.ctrlKey) { |
||||
showMenu(); |
||||
} |
||||
} |
||||
|
||||
onMounted(() => { |
||||
document.addEventListener('keydown', keydown); |
||||
}); |
||||
onBeforeUnmount(() => { |
||||
document.removeEventListener('keydown', keydown); |
||||
}) |
||||
|
||||
</script> |
||||
<style lang="scss" scoped></style> |
@ -0,0 +1,3 @@
@@ -0,0 +1,3 @@
|
||||
import Illustrated from './illustrated.vue'; |
||||
|
||||
export default Illustrated; |
Loading…
Reference in new issue