mirror of
https://github.com/ayangweb/BongoCat.git
synced 2026-03-12 17:51:48 +08:00
feat: 支持通过右键菜单快捷操作猫猫 (#136)
This commit is contained in:
103
src/composables/useSharedMenu.ts
Normal file
103
src/composables/useSharedMenu.ts
Normal file
@@ -0,0 +1,103 @@
|
||||
import type { CatMode } from '@/stores/cat'
|
||||
|
||||
import { CheckMenuItem, MenuItem, PredefinedMenuItem, Submenu } from '@tauri-apps/api/menu'
|
||||
|
||||
import { hideWindow, showWindow } from '@/plugins/window'
|
||||
import { useCatStore } from '@/stores/cat'
|
||||
import { isMac } from '@/utils/platform'
|
||||
|
||||
interface ModeOption {
|
||||
label: string
|
||||
value: CatMode
|
||||
}
|
||||
|
||||
export function useSharedMenu() {
|
||||
const catStore = useCatStore()
|
||||
const modeOptions: ModeOption[] = [
|
||||
{ label: '标准模式', value: 'standard' },
|
||||
{ label: '键盘模式', value: 'keyboard' },
|
||||
]
|
||||
|
||||
const getOpacityMenuItems = async () => {
|
||||
const options = [25, 50, 75, 100]
|
||||
|
||||
const items = options.map((item) => {
|
||||
return CheckMenuItem.new({
|
||||
text: `${item}%`,
|
||||
checked: catStore.opacity === item,
|
||||
action: () => {
|
||||
catStore.opacity = item
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
if (!options.includes(catStore.opacity)) {
|
||||
items.unshift(CheckMenuItem.new({
|
||||
text: `${catStore.opacity}%`,
|
||||
checked: true,
|
||||
enabled: false,
|
||||
}))
|
||||
}
|
||||
|
||||
return Promise.all(items)
|
||||
}
|
||||
|
||||
const getSharedMenu = async () => {
|
||||
return await Promise.all([
|
||||
MenuItem.new({
|
||||
text: '偏好设置...',
|
||||
accelerator: isMac ? 'Cmd+,' : '',
|
||||
action: () => showWindow('preference'),
|
||||
}),
|
||||
PredefinedMenuItem.new({ item: 'Separator' }),
|
||||
Submenu.new({
|
||||
text: '猫咪模式',
|
||||
items: await Promise.all(
|
||||
modeOptions.map((item) => {
|
||||
return CheckMenuItem.new({
|
||||
text: item.label,
|
||||
checked: catStore.mode === item.value,
|
||||
action: () => {
|
||||
catStore.mode = item.value
|
||||
},
|
||||
})
|
||||
}),
|
||||
),
|
||||
}),
|
||||
MenuItem.new({
|
||||
text: catStore.visible ? '隐藏猫咪' : '显示猫咪',
|
||||
action: () => {
|
||||
if (catStore.visible) {
|
||||
hideWindow('main')
|
||||
} else {
|
||||
showWindow('main')
|
||||
}
|
||||
|
||||
catStore.visible = !catStore.visible
|
||||
},
|
||||
}),
|
||||
CheckMenuItem.new({
|
||||
text: '窗口穿透',
|
||||
checked: catStore.penetrable,
|
||||
action: () => {
|
||||
catStore.penetrable = !catStore.penetrable
|
||||
},
|
||||
}),
|
||||
Submenu.new({
|
||||
text: '不透明度',
|
||||
items: await getOpacityMenuItems(),
|
||||
}),
|
||||
CheckMenuItem.new({
|
||||
text: '镜像模式',
|
||||
checked: catStore.mirrorMode,
|
||||
action: () => {
|
||||
catStore.mirrorMode = !catStore.mirrorMode
|
||||
},
|
||||
}),
|
||||
])
|
||||
}
|
||||
|
||||
return {
|
||||
getSharedMenu,
|
||||
}
|
||||
}
|
||||
@@ -2,29 +2,36 @@ import type { TrayIconOptions } from '@tauri-apps/api/tray'
|
||||
|
||||
import { getName, getVersion } from '@tauri-apps/api/app'
|
||||
import { emit } from '@tauri-apps/api/event'
|
||||
import { CheckMenuItem, Menu, MenuItem, PredefinedMenuItem, Submenu } from '@tauri-apps/api/menu'
|
||||
import { Menu, MenuItem, PredefinedMenuItem } from '@tauri-apps/api/menu'
|
||||
import { resolveResource } from '@tauri-apps/api/path'
|
||||
import { TrayIcon } from '@tauri-apps/api/tray'
|
||||
import { openUrl } from '@tauri-apps/plugin-opener'
|
||||
import { exit, relaunch } from '@tauri-apps/plugin-process'
|
||||
import { ref, watch } from 'vue'
|
||||
import { useDebounceFn } from '@vueuse/core'
|
||||
import { watch } from 'vue'
|
||||
|
||||
import { GITHUB_LINK, LISTEN_KEY } from '../constants'
|
||||
import { hideWindow, showWindow } from '../plugins/window'
|
||||
import { showWindow } from '../plugins/window'
|
||||
import { isMac } from '../utils/platform'
|
||||
|
||||
import { useSharedMenu } from './useSharedMenu'
|
||||
|
||||
import { useCatStore } from '@/stores/cat'
|
||||
|
||||
const TRAY_ID = 'BONGO_CAT_TRAY'
|
||||
|
||||
export function useTray() {
|
||||
const visible = ref(true)
|
||||
const catStore = useCatStore()
|
||||
const { getSharedMenu } = useSharedMenu()
|
||||
|
||||
watch([visible, () => catStore.mode, () => catStore.penetrable], () => {
|
||||
const debouncedUpdateTrayMenu = useDebounceFn(() => {
|
||||
updateTrayMenu()
|
||||
})
|
||||
|
||||
watch(() => catStore, () => {
|
||||
debouncedUpdateTrayMenu()
|
||||
}, { deep: true })
|
||||
|
||||
const createTray = async () => {
|
||||
const tray = await getTrayById()
|
||||
|
||||
@@ -57,49 +64,7 @@ export function useTray() {
|
||||
const appVersion = await getVersion()
|
||||
|
||||
const items = await Promise.all([
|
||||
MenuItem.new({
|
||||
text: '偏好设置...',
|
||||
accelerator: isMac ? 'Cmd+,' : '',
|
||||
action: () => showWindow(),
|
||||
}),
|
||||
MenuItem.new({
|
||||
text: visible.value ? '隐藏猫咪' : '显示猫咪',
|
||||
action: () => {
|
||||
if (visible.value) {
|
||||
hideWindow('main')
|
||||
} else {
|
||||
showWindow('main')
|
||||
}
|
||||
|
||||
visible.value = !visible.value
|
||||
},
|
||||
}),
|
||||
Submenu.new({
|
||||
text: '猫咪模式',
|
||||
items: await Promise.all([
|
||||
CheckMenuItem.new({
|
||||
text: '标准模式',
|
||||
checked: catStore.mode === 'standard',
|
||||
action: () => {
|
||||
catStore.mode = 'standard'
|
||||
},
|
||||
}),
|
||||
CheckMenuItem.new({
|
||||
text: '键盘模式',
|
||||
checked: catStore.mode === 'keyboard',
|
||||
action: () => {
|
||||
catStore.mode = 'keyboard'
|
||||
},
|
||||
}),
|
||||
]),
|
||||
}),
|
||||
CheckMenuItem.new({
|
||||
text: '窗口穿透',
|
||||
checked: catStore.penetrable,
|
||||
action: () => {
|
||||
catStore.penetrable = !catStore.penetrable
|
||||
},
|
||||
}),
|
||||
...await getSharedMenu(),
|
||||
PredefinedMenuItem.new({ item: 'Separator' }),
|
||||
MenuItem.new({
|
||||
text: '检查更新',
|
||||
|
||||
@@ -1,16 +1,19 @@
|
||||
<script setup lang="ts">
|
||||
import { Menu } from '@tauri-apps/api/menu'
|
||||
import { getCurrentWebviewWindow } from '@tauri-apps/api/webviewWindow'
|
||||
import { useDebounceFn, useEventListener } from '@vueuse/core'
|
||||
import { onMounted, onUnmounted, ref, watch } from 'vue'
|
||||
|
||||
import { useDevice } from '@/composables/useDevice'
|
||||
import { useModel } from '@/composables/useModel'
|
||||
import { useSharedMenu } from '@/composables/useSharedMenu'
|
||||
import { useCatStore } from '@/stores/cat'
|
||||
|
||||
const appWindow = getCurrentWebviewWindow()
|
||||
const { pressedMouses, mousePosition, pressedKeys } = useDevice()
|
||||
const { handleLoad, handleDestroy, handleResize, handleMouseDown, handleMouseMove, handleKeyDown } = useModel()
|
||||
const catStore = useCatStore()
|
||||
const { getSharedMenu } = useSharedMenu()
|
||||
|
||||
const resizing = ref(false)
|
||||
|
||||
@@ -38,12 +41,22 @@ watch(pressedKeys, handleKeyDown)
|
||||
|
||||
watch(() => catStore.penetrable, (value) => {
|
||||
appWindow.setIgnoreCursorEvents(value)
|
||||
}, { immediate: true })
|
||||
})
|
||||
|
||||
function handleWindowDrag() {
|
||||
appWindow.startDragging()
|
||||
}
|
||||
|
||||
async function handleContextmenu(event: MouseEvent) {
|
||||
event.preventDefault()
|
||||
|
||||
const menu = await Menu.new({
|
||||
items: await getSharedMenu(),
|
||||
})
|
||||
|
||||
menu.popup()
|
||||
}
|
||||
|
||||
function resolveImageURL(key: string) {
|
||||
return new URL(`../../assets/images/keys/${key}.png`, import.meta.url).href
|
||||
}
|
||||
@@ -54,6 +67,7 @@ function resolveImageURL(key: string) {
|
||||
class="relative children:(absolute h-screen w-screen)"
|
||||
:class="[catStore.mirrorMode ? '-scale-x-100' : 'scale-x-100']"
|
||||
:style="{ opacity: catStore.opacity / 100 }"
|
||||
@contextmenu="handleContextmenu"
|
||||
@mousedown="handleWindowDrag"
|
||||
>
|
||||
<img :src="`/images/backgrounds/${catStore.mode}.png`">
|
||||
|
||||
@@ -41,7 +41,7 @@ const modeList: SelectProps['options'] = [
|
||||
</ProListItem>
|
||||
|
||||
<ProListItem
|
||||
title="透明度"
|
||||
title="不透明度"
|
||||
vertical
|
||||
>
|
||||
<Slider
|
||||
|
||||
@@ -1,14 +1,18 @@
|
||||
import { defineStore } from 'pinia'
|
||||
import { ref } from 'vue'
|
||||
|
||||
export type CatMode = 'standard' | 'keyboard'
|
||||
|
||||
export const useCatStore = defineStore('cat', () => {
|
||||
const mode = ref<'standard' | 'keyboard'>('standard')
|
||||
const mode = ref<CatMode>('standard')
|
||||
const visible = ref(true)
|
||||
const penetrable = ref(false)
|
||||
const opacity = ref(100)
|
||||
const mirrorMode = ref(false)
|
||||
|
||||
return {
|
||||
mode,
|
||||
visible,
|
||||
penetrable,
|
||||
opacity,
|
||||
mirrorMode,
|
||||
|
||||
Reference in New Issue
Block a user