Skip to content

Commit

Permalink
fix(console): flip menu when hit the boundary, fix #267
Browse files Browse the repository at this point in the history
  • Loading branch information
shigma committed Dec 18, 2023
1 parent 757fa1f commit 64c5671
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 22 deletions.
13 changes: 3 additions & 10 deletions packages/client/app/theme/menu/index.vue
Original file line number Diff line number Diff line change
@@ -1,24 +1,17 @@
<template>
<template v-for="{ id, styles } of ctx.internal.activeMenus" :key="id">
<k-menu
:id="id"
:style="styles"
:ref="el => elements[id] = (el as ComponentPublicInstance)"
></k-menu>
<template v-for="menu of ctx.internal.activeMenus" :key="id">
<k-menu v-bind="menu"></k-menu>
</template>
</template>

<script lang="ts" setup>
import { Dict, useContext } from '@koishijs/client'
import { ComponentPublicInstance, shallowReactive } from 'vue'
import { useContext } from '@koishijs/client'
import { useEventListener } from '@vueuse/core'
import KMenu from './menu.vue'
const ctx = useContext()
const elements = shallowReactive<Dict<ComponentPublicInstance>>({})
useEventListener('click', () => {
ctx.internal.activeMenus.splice(0)
})
Expand Down
40 changes: 30 additions & 10 deletions packages/client/app/theme/menu/menu.vue
Original file line number Diff line number Diff line change
@@ -1,21 +1,41 @@
<template>
<div ref="menu" class="k-menu">
<template v-for="item of ctx.internal.menus[id]">
<div class="k-menu-separator" v-if="item.id === '@separator'"></div>
<menu-item v-else v-bind="{ prefix: id, ...item }"></menu-item>
</template>
</div>
<transition name="el-zoom-in-top">
<div ref="el" v-show="el" class="k-menu" :style="getStyle()">
<template v-for="item of ctx.internal.menus[id]">
<div class="k-menu-separator" v-if="item.id === '@separator'"></div>
<menu-item v-else v-bind="{ prefix: id, ...item }"></menu-item>
</template>
</div>
</transition>
</template>

<script lang="ts" setup>
import { useContext } from '@koishijs/client'
import { ref } from 'vue'
import { useContext, ActiveMenu } from '@koishijs/client'
import MenuItem from './menu-item.vue'
defineProps<{
id: string
}>()
const props = defineProps<ActiveMenu>()
const ctx = useContext()
const el = ref<HTMLElement>()
const getStyle = () => {
if (!el.value) return {}
const { height, width } = el.value.getBoundingClientRect()
const style: any = {}
if (props.relative.right + width > window.innerWidth) {
style.right = `${window.innerWidth - props.relative.left}px`
} else {
style.left = `${props.relative.right}px`
}
if (props.relative.bottom + height > window.innerHeight) {
style.bottom = `0px`
} else {
style.top = `${props.relative.bottom}px`
}
return style
}
</script>
22 changes: 20 additions & 2 deletions packages/client/client/context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,16 @@ type Flatten<S extends {}> = Intersect<{
: { [P in K]: S[K] }
}[keyof S]>

export interface ActiveMenu {
id: string
relative: {
left: number
top: number
right: number
bottom: number
}
}

class Internal {
extensions = extensions
activities = activities
Expand All @@ -97,7 +107,7 @@ class Internal {
views = reactive<Dict<SlotOptions[]>>({})
themes = reactive<Dict<ThemeOptions>>({})
settings = reactive<Dict<SettingOptions[]>>({})
activeMenus = reactive<{ id: string; styles: Partial<CSSStyleDeclaration> }[]>([])
activeMenus = reactive<ActiveMenu[]>([])

createScope(scope = this.scope, prefix = '') {
return new Proxy({}, {
Expand All @@ -120,7 +130,15 @@ export function useMenu<K extends keyof ActionContext>(id: K) {
ctx.define(id, value)
event.preventDefault()
const { clientX, clientY } = event
ctx.internal.activeMenus.splice(0, Infinity, { id, styles: { left: clientX + 'px', top: clientY + 'px' } })
ctx.internal.activeMenus.splice(0, Infinity, {
id,
relative: {
left: clientX,
top: clientY,
right: clientX,
bottom: clientY,
},
})
}
}

Expand Down

0 comments on commit 64c5671

Please sign in to comment.