mirror of
https://github.com/Wei-Shaw/sub2api.git
synced 2026-10-31 00:24:38 +00:00
Merge pull request #4648 from creamtea47/codex/fix-mobile-account-actions-menu
fix: 修复账号管理移动端更多操作菜单溢出
This commit is contained in:
@@ -0,0 +1,43 @@
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import { getFloatingPanelPosition } from '@/utils/floatingPanel'
|
||||
|
||||
describe('getFloatingPanelPosition', () => {
|
||||
it('移动端使用视口安全边距,不再从靠左按钮向屏幕外展开', () => {
|
||||
const position = getFloatingPanelPosition(
|
||||
{ top: 160, right: 148, bottom: 200 },
|
||||
393,
|
||||
844
|
||||
)
|
||||
|
||||
expect(position).toMatchObject({
|
||||
top: 208,
|
||||
bottom: null,
|
||||
left: 16,
|
||||
width: 320
|
||||
})
|
||||
expect(position.left + position.width).toBeLessThanOrEqual(393 - 16)
|
||||
})
|
||||
|
||||
it('桌面端与按钮右侧对齐', () => {
|
||||
const position = getFloatingPanelPosition(
|
||||
{ top: 100, right: 1000, bottom: 140 },
|
||||
1280,
|
||||
900
|
||||
)
|
||||
|
||||
expect(position.left).toBe(680)
|
||||
expect(position.width).toBe(320)
|
||||
})
|
||||
|
||||
it('按钮下方空间不足时改为向上展开', () => {
|
||||
const position = getFloatingPanelPosition(
|
||||
{ top: 700, right: 1000, bottom: 740 },
|
||||
1280,
|
||||
800
|
||||
)
|
||||
|
||||
expect(position.top).toBeNull()
|
||||
expect(position.bottom).toBe(108)
|
||||
expect(position.maxHeight).toBe(560)
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,56 @@
|
||||
export interface FloatingPanelPosition {
|
||||
top: number | null
|
||||
bottom: number | null
|
||||
left: number
|
||||
width: number
|
||||
maxHeight: number
|
||||
}
|
||||
|
||||
export interface FloatingPanelOptions {
|
||||
viewportPadding?: number
|
||||
gap?: number
|
||||
maxWidth?: number
|
||||
maxHeightRatio?: number
|
||||
mobileBreakpoint?: number
|
||||
minComfortableHeight?: number
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算挂载到 body 的浮层位置,避免触发按钮靠近视口边缘时浮层被挤到屏幕外。
|
||||
*/
|
||||
export const getFloatingPanelPosition = (
|
||||
triggerRect: Pick<DOMRect, 'top' | 'right' | 'bottom'>,
|
||||
viewportWidth: number,
|
||||
viewportHeight: number,
|
||||
options: FloatingPanelOptions = {}
|
||||
): FloatingPanelPosition => {
|
||||
const viewportPadding = options.viewportPadding ?? 16
|
||||
const gap = options.gap ?? 8
|
||||
const maxWidth = options.maxWidth ?? 320
|
||||
const maxHeightRatio = options.maxHeightRatio ?? 0.7
|
||||
const mobileBreakpoint = options.mobileBreakpoint ?? 768
|
||||
const minComfortableHeight = options.minComfortableHeight ?? 240
|
||||
|
||||
const availableWidth = Math.max(0, viewportWidth - viewportPadding * 2)
|
||||
const width = Math.min(maxWidth, availableWidth)
|
||||
const left = viewportWidth < mobileBreakpoint
|
||||
? viewportPadding
|
||||
: Math.max(
|
||||
viewportPadding,
|
||||
Math.min(triggerRect.right - width, viewportWidth - width - viewportPadding)
|
||||
)
|
||||
|
||||
const preferredMaxHeight = Math.max(0, Math.floor(viewportHeight * maxHeightRatio))
|
||||
const spaceBelow = Math.max(0, viewportHeight - triggerRect.bottom - gap - viewportPadding)
|
||||
const spaceAbove = Math.max(0, triggerRect.top - gap - viewportPadding)
|
||||
const openAbove = spaceBelow < Math.min(minComfortableHeight, preferredMaxHeight) && spaceAbove > spaceBelow
|
||||
const maxHeight = Math.min(preferredMaxHeight, openAbove ? spaceAbove : spaceBelow)
|
||||
|
||||
return {
|
||||
top: openAbove ? null : triggerRect.bottom + gap,
|
||||
bottom: openAbove ? viewportHeight - triggerRect.top + gap : null,
|
||||
left,
|
||||
width,
|
||||
maxHeight
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user