xyyd-fatfox/src/layout/GlobalMenu.tsx

202 lines
5.5 KiB
TypeScript
Raw Normal View History

2024-09-25 18:23:54 +08:00
import { defineStore } from 'pinia'
import { computed, defineComponent, onUnmounted, reactive } from 'vue'
import type { Block } from './layout.types'
import clsx from 'clsx'
import useLayoutStore from './useLayoutStore'
const defaultDisplay = {
x: 0,
y: 0,
type: 'global' as Block | 'global' | 'dock'
}
export const useMenuStore = defineStore('menu', () => {
const display = reactive(defaultDisplay)
const mPos = {
x: 0,
y: 0
}
const handle = (e: MouseEvent) => {
mPos.x = e.pageX
mPos.y = e.pageY
}
window.addEventListener('mousemove', handle)
onUnmounted(() => {
window.removeEventListener('mousemove', handle)
})
const open = (type: (typeof defaultDisplay)['type']) => {
display.x = Math.min(window.innerWidth - 140, mPos.x)
display.y = Math.min(window.innerHeight - 240, mPos.y)
display.type = type
}
const show = computed(() => display.x > 0 && display.y > 0)
const dismiss = () => {
display.x = 0
display.y = 0
display.type = 'global'
}
return {
display,
open,
dismiss,
show
}
})
const Item = defineComponent({
props: {
alert: {
type: Boolean,
default: false
}
},
emits: {
click: () => true
},
setup(props, ctx) {
return () => (
<div
class={clsx(
'px-4 py-2 text-sm tracking-widest w-full overflow-hidden text-ellipsis whitespace-nowrap break-all transition-all rounded-lg cursor-pointer mb-2',
{
'bg-red-500/80 hover:bg-red-500 text-white': props.alert,
'bg-white/80 hover:bg-white text-black/80': !props.alert
}
)}
onClick={() => {
ctx.emit('click')
}}
>
{ctx.slots.default?.()}
</div>
)
}
})
export default defineComponent(() => {
const menu = useMenuStore()
const layout = useLayoutStore()
return () =>
menu.show && (
<div
v-outside-click={() => {
console.log(2333)
menu.dismiss()
}}
class="fixed px-2 pt-4 pb-2 bg-white/60 backdrop-blur shadow-lg rounded-lg overflow-hidden w-[120px]"
style={{
zIndex: '999',
left: menu.display.x + 'px',
top: menu.display.y + 'px'
}}
>
{(() => {
if (menu.display.type === 'global') {
// 全局菜单
return <></>
}
if (menu.display.type === 'dock') {
// dock 栏
return <></>
}
const block = menu.display.type
if (!block.link) {
// 小组件
return (
<>
<Item
alert
onClick={() => {
// 删除链接
const idx = layout.currentPage.list.findIndex((el) => el.id === block.id)
if (idx < 0) return
layout.currentPage.list.splice(idx, 1)
menu.dismiss()
}}
>
</Item>
</>
)
}
if (block.link.startsWith('id:')) {
// 文件夹
const id = block.link.slice(3)
return (
<>
<Item
onClick={() => {
block.w = 1
block.h = 1
menu.dismiss()
}}
>
</Item>
<Item
onClick={() => {
block.w = 2
block.h = 2
menu.dismiss()
}}
>
</Item>
<Item
alert
onClick={() => {
// 删除文件夹
const idx = layout.currentPage.list.findIndex((el) => el.id === block.id)
if (idx < 0) return
layout.currentPage.list.splice(idx, 1)
delete layout.state.dir[id]
menu.dismiss()
}}
>
</Item>
</>
)
}
// 链接
return (
<>
<Item></Item>
<Item
alert
onClick={() => {
// 删除链接
let idx = layout.currentPage.list.findIndex((el) => el.id === block.id)
if (idx < 0) {
// 查找文件夹
idx = layout.state.dir[layout.openDir]?.list?.findIndex(
(el) => el.id === block.id
)
if (idx === undefined || idx < 0) {
// 查找 dock
idx = layout.state.dock.findIndex((el) => el?.id === block.id)
if (idx >= 0) {
layout.state.dock[idx] = null
menu.dismiss()
}
} else {
const list = layout.state.dir[layout.openDir].list
list.splice(idx, 1)
layout.checkDir(layout.openDir)
menu.dismiss()
}
} else {
layout.currentPage.list.splice(idx, 1)
menu.dismiss()
}
}}
>
</Item>
</>
)
})()}
</div>
)
})