265 lines
8.5 KiB
TypeScript
265 lines
8.5 KiB
TypeScript
import { defineComponent, ref, Transition, TransitionGroup, watch } from 'vue'
|
|
import ModeSwitch from './ModeSwitch'
|
|
import icons, { initIcons } from './icons'
|
|
import { OhVueIcon, addIcons } from 'oh-vue-icons'
|
|
import { PxHeadset, PxAddBox, PxCheck } from 'oh-vue-icons/icons'
|
|
import useRouterStore from '@/useRouterStore'
|
|
import useLayoutStore from '../useLayoutStore'
|
|
import useUserStore from '@/user/useUserStore'
|
|
import AvatarCircle from '@/user/AvatarCircle'
|
|
import clsx from 'clsx'
|
|
import useSettingsStore from '@/settings/useSettingsStore'
|
|
import { useMenuStore } from '../GlobalMenu'
|
|
import { v4 as uuid } from 'uuid'
|
|
initIcons()
|
|
addIcons(PxHeadset, PxAddBox, PxCheck)
|
|
const Item = defineComponent({
|
|
props: {
|
|
name: {
|
|
type: String,
|
|
default: ''
|
|
},
|
|
label: {
|
|
type: String,
|
|
default: ''
|
|
},
|
|
idx: {
|
|
type: Number,
|
|
default: 0
|
|
},
|
|
active: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
id: {
|
|
type: String,
|
|
default: ''
|
|
}
|
|
},
|
|
emits: ['click'],
|
|
setup(props, ctx) {
|
|
const hover = ref(false)
|
|
return () => (
|
|
<div
|
|
onContextmenu={(e) => {
|
|
useMenuStore().open('page')
|
|
useMenuStore().selectPage = {
|
|
id: props.id,
|
|
label: props.label,
|
|
name: props.name,
|
|
}
|
|
e.stopPropagation()
|
|
e.preventDefault()
|
|
}}
|
|
class={
|
|
'relative z-10 w-full h-[56px] flex flex-col justify-center items-center text-[13px] cursor-pointer transition-all font-bold ' +
|
|
(props.active ? 'text-white' : hover.value ? 'text-white' : 'text-white/80')
|
|
}
|
|
onMouseenter={() => {
|
|
hover.value = true
|
|
}}
|
|
onMouseleave={() => {
|
|
hover.value = false
|
|
}}
|
|
onClick={() => {
|
|
ctx.emit('click')
|
|
}}
|
|
>
|
|
<OhVueIcon name={props.name} fill="white" scale={1.2} />
|
|
{props.label}
|
|
</div>
|
|
)
|
|
}
|
|
})
|
|
export default defineComponent(() => {
|
|
const menu = useMenuStore()
|
|
const selected = ref(icons[0])
|
|
const router = useRouterStore()
|
|
const layout = useLayoutStore()
|
|
const settings = useSettingsStore()
|
|
const user = useUserStore()
|
|
const show = ref(false)
|
|
const label = ref('')
|
|
watch(
|
|
selected,
|
|
(val) => {
|
|
label.value = val.label
|
|
},
|
|
{ immediate: true }
|
|
)
|
|
watch(
|
|
() => menu.selectPage,
|
|
(val) => {
|
|
if (val) {
|
|
selected.value = {
|
|
name: val.name,
|
|
label: val.label
|
|
}
|
|
label.value = val.label
|
|
} else {
|
|
selected.value = icons[0]
|
|
label.value = ''
|
|
}
|
|
}
|
|
)
|
|
return () => (
|
|
<Transition>
|
|
{layout.ready && (
|
|
<div
|
|
class={clsx(
|
|
'w-[130px] min-h-[620px] hover:bg-red-10 z-20 fixed top-1/2 -translate-y-1/2 bottom-0 ',
|
|
settings.state.siderDirection === 'left' ? 'left-0' : 'right-0'
|
|
)}
|
|
onDragover={() => {
|
|
show.value = true
|
|
}}
|
|
onMouseleave={() => {
|
|
show.value = false
|
|
}}
|
|
onMouseenter={() => {
|
|
show.value = true
|
|
}}
|
|
>
|
|
<div
|
|
class={clsx(
|
|
'fixed top-1/2 -translate-y-1/2 h-[600px] z-30 duration-150',
|
|
settings.state.siderDirection === 'left'
|
|
? settings.state.showSider === 'auto' && !show.value
|
|
? '-left-14'
|
|
: 'left-6'
|
|
: settings.state.showSider === 'auto' && !show.value
|
|
? '-right-14'
|
|
: 'right-6'
|
|
)}
|
|
>
|
|
<div class="w-[56px] h-full rounded-[28px] bg-black/70 backdrop-blur flex flex-col justify-between items-center">
|
|
<ModeSwitch />
|
|
<div class="w-full h-[64px]" />
|
|
<div class="w-full h-0 flex-grow overflow-auto relative no-scrollbar">
|
|
<TransitionGroup>
|
|
{layout.currentMode.pages.map((el, idx) => (
|
|
<Item
|
|
key={idx}
|
|
name={el.name}
|
|
label={el.label}
|
|
id={el.id}
|
|
idx={idx}
|
|
active={layout.state.currentPage === idx}
|
|
onClick={() => {
|
|
layout.state.currentPage = idx
|
|
}}
|
|
/>
|
|
))}
|
|
</TransitionGroup>
|
|
<Transition>
|
|
{layout.currentMode.pages.length > 0 && (
|
|
<div
|
|
class="absolute w-full h-[56px] rounded-lg bg-white/40 left-0 transition-all"
|
|
style={{
|
|
transitionDuration: '.3s',
|
|
top: `${layout.state.currentPage * 56}px`
|
|
}}
|
|
/>
|
|
)}
|
|
</Transition>
|
|
</div>
|
|
<div class="w-full h-4" />
|
|
<Item
|
|
name="px-add-box"
|
|
label="添加"
|
|
onClick={() => {
|
|
menu.showEditPage = true
|
|
}}
|
|
/>
|
|
<Item
|
|
name="px-headset"
|
|
label="反馈"
|
|
onClick={() => {
|
|
router.go('settings-fallback')
|
|
}}
|
|
/>
|
|
<div
|
|
class="w-[56px] h-[56px] rounded-full border-white border-[2px] border-solid overflow-hidden cursor-pointer"
|
|
onClick={() => {
|
|
if (user.isLogin) {
|
|
router.go('settings-user')
|
|
} else {
|
|
router.go('global-login')
|
|
}
|
|
}}
|
|
>
|
|
<AvatarCircle />
|
|
</div>
|
|
</div>
|
|
{/* 添加页面 */}
|
|
{menu.showEditPage && (
|
|
<div
|
|
class={clsx(
|
|
'absolute bottom-0 w-56 rounded-lg p-4 bg-white/40 backdrop-blur shadow-lg',
|
|
settings.state.siderDirection === 'left' ? 'left-[70px]' : 'right-[70px]'
|
|
)}
|
|
v-outside-click={() => {
|
|
menu.showEditPage = false
|
|
}}
|
|
>
|
|
<input
|
|
class="rounded bg-black/10 text-center text-sm w-full py-1"
|
|
v-model={label.value}
|
|
maxlength={2}
|
|
/>
|
|
<div class="flex flex-wrap gap-1 mt-2">
|
|
{icons.map((el) => (
|
|
<div
|
|
class={
|
|
'p-1 rounded cursor-pointer transition-all ' +
|
|
(selected.value.name === el.name
|
|
? 'text-black/80 bg-white shadow'
|
|
: 'text-black/60 hover:shadow hover:text-black/80 hover:bg-white')
|
|
}
|
|
onClick={() => {
|
|
selected.value = { ...el }
|
|
}}
|
|
>
|
|
<OhVueIcon name={el.name} fill="black" scale={1.3} />
|
|
</div>
|
|
))}
|
|
</div>
|
|
<div
|
|
class="w-full mt-2 py-1 rounded-lg bg-white text-center text-sm shadow hover:shadow-lg transition-all cursor-pointer"
|
|
onClick={() => {
|
|
if (menu.selectPage) {
|
|
menu.selectPage.name = selected.value.name
|
|
menu.selectPage.label = label.value
|
|
if (!menu.selectPage?.id) return
|
|
const idx = layout.state.content[layout.state.current].pages.findIndex(val => val.id === menu.selectPage?.id)
|
|
if (idx !== -1) {
|
|
layout.state.content[layout.state.current].pages[idx].label = label.value
|
|
layout.state.content[layout.state.current].pages[idx].name = selected.value.name
|
|
|
|
}
|
|
menu.selectPage = undefined
|
|
} else {
|
|
layout.currentMode.pages.push({
|
|
list: [],
|
|
label: label.value,
|
|
name: selected.value.name,
|
|
id: uuid()
|
|
})
|
|
}
|
|
|
|
menu.showEditPage = false
|
|
|
|
}}
|
|
>
|
|
<OhVueIcon name="px-check" />
|
|
{menu.selectPage ? "修改页面" : "添加页面"}
|
|
</div>
|
|
</div>
|
|
)}
|
|
</div>
|
|
</div>
|
|
)}
|
|
</Transition>
|
|
)
|
|
})
|