xyyd-fatfox/src/layout/GlobalMenu.tsx

408 lines
12 KiB
TypeScript

import { defineStore } from 'pinia'
import { computed, defineComponent, onUnmounted, reactive, ref } from 'vue'
import type { Block } from './layout.types'
import clsx from 'clsx'
import useLayoutStore from './useLayoutStore'
import widgetList from '@/widgets'
import useRouterStore from '@/useRouterStore'
import useAdderPageStore from './adder/useAdderPageStore'
import useSettingsStore from '@/settings/useSettingsStore'
const defaultDisplay = {
x: 0,
y: 0,
type: 'global' as Block | 'global' | 'dock' | 'page'
}
export const useMenuStore = defineStore('menu', () => {
const display = reactive(defaultDisplay)
const selectPage = ref<{
id: string
label: string
name: string
}>()
const isEditPage = ref(false)
const showEditPage = ref(false)
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 - 180, mPos.x)
display.y = Math.min(window.innerHeight - 220, 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,
isEditPage,
show,
selectPage,
showEditPage
}
})
const Item = defineComponent({
props: {
alert: {
type: Boolean,
default: false
},
noStyle: {
type: Boolean,
default: false
},
centered: {
type: Boolean,
default: false
}
},
emits: {
click: () => true
},
setup(props, ctx) {
return () => (
<div
class={clsx(
' py-1 text-sm tracking-widest w-full overflow-hidden flex text-ellipsis whitespace-nowrap break-all transition-all rounded cursor-pointer mb-[2px]',
{
' hover:bg-black/20 text-black/80': props.alert,
' hover:bg-black/20 text-black/80': !props.alert && !props.noStyle,
'bg-transparent text-black/60 hover:text-black/80 hover:bg-white/20': props.noStyle
},
props.centered ? 'justify-center' : 'pl-2 justify-start'
)}
style={
props.noStyle
? {
padding: '6px 10px'
}
: {}
}
onClick={() => {
ctx.emit('click')
}}
>
{ctx.slots.default?.()}
</div>
)
}
})
export default defineComponent(() => {
const menu = useMenuStore()
const settings = useSettingsStore()
const layout = useLayoutStore()
document.addEventListener('contextmenu', () => {
menu.open('global')
})
const router = useRouterStore()
const adderPage = useAdderPageStore()
return () =>
menu.show && (
<div
v-outside-click={() => {
menu.dismiss()
}}
class="fixed px-2 pt-2 pb-1 bg-white/60 backdrop-blur shadow-lg rounded-lg overflow-hidden"
style={{
zIndex: '999',
left: menu.display.x + 'px',
top: menu.display.y + 'px',
width: menu.display.type === 'global' ? '160px' : '120px'
}}
>
{(() => {
if (menu.display.type === 'global') {
// 全局菜单
return (
<>
<Item
noStyle
onClick={() => {
router.go('global-adder')
adderPage.type = 1
menu.dismiss()
}}
>
</Item>
<Item
noStyle
onClick={() => {
router.go('global-adder')
adderPage.type = 0
menu.dismiss()
}}
>
</Item>
<Item
noStyle
onClick={() => {
router.go('global-adder')
adderPage.type = 3
menu.dismiss()
}}
>
</Item>
<Item
noStyle
onClick={() => {
menu.isEditPage = true
menu.dismiss()
}}
>
</Item>
<Item
noStyle
onClick={() => {
router.go('global-background')
menu.dismiss()
}}
>
</Item>
<Item
noStyle
onClick={() => {
window.location.reload()
menu.dismiss()
}}
>
</Item>
</>
)
}
if (menu.display.type === 'dock') {
// dock 栏
return (
<>
<Item
noStyle
onClick={() => {
settings.state.disabledShortcut = !settings.state.disabledShortcut
menu.dismiss()
}}
>
{settings.state.disabledShortcut ? '启用' : '禁用'}
</Item>
<Item
noStyle
onClick={() => {
router.go('settings-dock')
menu.dismiss()
}}
>
</Item>
</>
)
}
if (menu.display.type === 'page') {
return (
<>
<Item
centered
onClick={() => {
menu.showEditPage = true
menu.dismiss()
}}
>
</Item>
{layout.state.content[layout.state.current].pages.length > 1 && (
<Item
alert
centered
onClick={() => {
// 删除链接
const idx = layout.state.content[layout.state.current].pages.findIndex(
(el) => el.id === menu.selectPage?.id
)
menu.dismiss()
if (idx < 0) return
layout.state.content[layout.state.current].pages.splice(idx, 1)
if (
layout.state.currentPage >=
layout.state.content[layout.state.current].pages.length
) {
layout.state.currentPage =
layout.state.content[layout.state.current].pages.length - 1
}
}}
>
</Item>
)}
</>
)
}
const block = menu.display.type
if (!block.link) {
// 小组件
const selected = widgetList.find((el) => el.name === block.name)
return (
<>
{selected?.list &&
selected.list.length > 1 &&
selected.list.map((el) => (
<Item
onClick={() => {
block.w = el.w
block.h = el.h
menu.dismiss()
}}
>
{el.label}
</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)
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
onClick={() => {
menu.dismiss()
const idx = layout.currentPage.list.findIndex((el) => el.id === block.id)
if (idx < 0) return
layout.state.dir[id].list.forEach((val) => {
layout.addBlock(val, layout.state.currentPage)
})
layout.currentPage.list.splice(idx, 1)
delete layout.state.dir[id]
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
onClick={() => {
useAdderPageStore().editBlockItem = {
id: block.id,
name: block.name,
link: block.link,
icon: block.icon,
text: block.text,
background: block.background,
color: block.color,
type: !block.icon ? 1 : 0
}
router.go('global-adder')
useAdderPageStore().type = 2
menu.dismiss()
}}
>
</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>
)
})