fix bug
This commit is contained in:
@@ -1,24 +1,54 @@
|
||||
import { computed, onMounted, onUnmounted, ref } from 'vue'
|
||||
|
||||
const DRAG_THRESHOLD = 6
|
||||
const POSITION_VERSION = 1
|
||||
|
||||
type FabPosition = { x: number; y: number }
|
||||
|
||||
type SavedFabOffset = {
|
||||
version: number
|
||||
dx: number
|
||||
dy: number
|
||||
}
|
||||
|
||||
type DraggableFloatingOptions = {
|
||||
width?: number
|
||||
height?: number
|
||||
defaultBottomOffset?: number
|
||||
/** فاصله از پایینِ نوار منو + montzar (px) — مثل تصویر */
|
||||
defaultBottomGap?: number
|
||||
defaultRightOffset?: number
|
||||
}
|
||||
|
||||
function readBottomChromeHeight(): number {
|
||||
const styles = getComputedStyle(document.documentElement)
|
||||
const direct = parseFloat(styles.getPropertyValue('--app-bottom-chrome-height'))
|
||||
if (!Number.isNaN(direct) && direct > 0) {
|
||||
return direct
|
||||
}
|
||||
|
||||
const nav = parseFloat(styles.getPropertyValue('--app-nav-height')) || 80
|
||||
const creditOffset = parseFloat(styles.getPropertyValue('--app-credit-footer-offset'))
|
||||
if (!Number.isNaN(creditOffset) && creditOffset > 0) {
|
||||
return nav + creditOffset
|
||||
}
|
||||
|
||||
const probe = document.createElement('div')
|
||||
probe.style.cssText = 'position:fixed;visibility:hidden;pointer-events:none;height:var(--app-bottom-chrome-height)'
|
||||
document.body.appendChild(probe)
|
||||
const measured = probe.getBoundingClientRect().height
|
||||
document.body.removeChild(probe)
|
||||
|
||||
return measured > 0 ? measured : nav + 28
|
||||
}
|
||||
|
||||
export function useDraggableFloatingButton(
|
||||
storageKey: string,
|
||||
options: DraggableFloatingOptions = {}
|
||||
) {
|
||||
const width = options.width ?? 96
|
||||
const height = options.height ?? 44
|
||||
const defaultBottomOffset = options.defaultBottomOffset ?? 120
|
||||
const defaultRightOffset = options.defaultRightOffset ?? 20
|
||||
const defaultBottomGap = options.defaultBottomGap ?? 12
|
||||
const defaultRightOffset = options.defaultRightOffset ?? 16
|
||||
|
||||
const pos = ref<FabPosition>({ x: 0, y: 0 })
|
||||
const dragging = ref(false)
|
||||
@@ -44,26 +74,40 @@ export function useDraggableFloatingButton(
|
||||
function getHorizontalOffset() {
|
||||
const vw = window.innerWidth
|
||||
const contentWidth = getViewportWidth()
|
||||
|
||||
return Math.max(0, (vw - contentWidth) / 2)
|
||||
}
|
||||
|
||||
function resetToDefault() {
|
||||
function getDefaultPosition(): FabPosition {
|
||||
const vh = window.innerHeight
|
||||
const offsetX = getHorizontalOffset()
|
||||
const contentWidth = getViewportWidth()
|
||||
const bottomChrome = readBottomChromeHeight()
|
||||
|
||||
pos.value = {
|
||||
return {
|
||||
x: offsetX + contentWidth - width - defaultRightOffset,
|
||||
y: vh - defaultBottomOffset - height
|
||||
y: vh - bottomChrome - defaultBottomGap - height
|
||||
}
|
||||
}
|
||||
|
||||
function applySavedOffset(dx: number, dy: number) {
|
||||
const base = getDefaultPosition()
|
||||
pos.value = {
|
||||
x: base.x + dx,
|
||||
y: base.y + dy
|
||||
}
|
||||
clampToViewport()
|
||||
}
|
||||
|
||||
function clampToViewport() {
|
||||
const vw = window.innerWidth
|
||||
const vh = window.innerHeight
|
||||
const offsetX = getHorizontalOffset()
|
||||
const contentWidth = getViewportWidth()
|
||||
const minX = offsetX
|
||||
const maxX = offsetX + contentWidth - width
|
||||
|
||||
pos.value = {
|
||||
x: Math.max(0, Math.min(vw - width, pos.value.x)),
|
||||
x: Math.max(minX, Math.min(maxX, pos.value.x)),
|
||||
y: Math.max(0, Math.min(vh - height, pos.value.y))
|
||||
}
|
||||
}
|
||||
@@ -72,25 +116,56 @@ export function useDraggableFloatingButton(
|
||||
try {
|
||||
const raw = localStorage.getItem(storageKey)
|
||||
if (!raw) return false
|
||||
const parsed = JSON.parse(raw) as FabPosition
|
||||
if (typeof parsed?.x === 'number' && typeof parsed?.y === 'number') {
|
||||
pos.value = parsed
|
||||
clampToViewport()
|
||||
|
||||
const parsed = JSON.parse(raw) as SavedFabOffset
|
||||
if (
|
||||
parsed?.version === POSITION_VERSION
|
||||
&& typeof parsed.dx === 'number'
|
||||
&& typeof parsed.dy === 'number'
|
||||
) {
|
||||
applySavedOffset(parsed.dx, parsed.dy)
|
||||
return true
|
||||
}
|
||||
} catch {
|
||||
// ignore
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
function savePosition() {
|
||||
localStorage.setItem(storageKey, JSON.stringify(pos.value))
|
||||
const base = getDefaultPosition()
|
||||
const payload: SavedFabOffset = {
|
||||
version: POSITION_VERSION,
|
||||
dx: pos.value.x - base.x,
|
||||
dy: pos.value.y - base.y
|
||||
}
|
||||
localStorage.setItem(storageKey, JSON.stringify(payload))
|
||||
}
|
||||
|
||||
function resetToDefault() {
|
||||
pos.value = getDefaultPosition()
|
||||
}
|
||||
|
||||
function handleResize() {
|
||||
clampToViewport()
|
||||
savePosition()
|
||||
try {
|
||||
const raw = localStorage.getItem(storageKey)
|
||||
if (raw) {
|
||||
const parsed = JSON.parse(raw) as SavedFabOffset
|
||||
if (
|
||||
parsed?.version === POSITION_VERSION
|
||||
&& typeof parsed.dx === 'number'
|
||||
&& typeof parsed.dy === 'number'
|
||||
) {
|
||||
applySavedOffset(parsed.dx, parsed.dy)
|
||||
return
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
// ignore
|
||||
}
|
||||
|
||||
resetToDefault()
|
||||
}
|
||||
|
||||
function handlePointerDown(event: PointerEvent) {
|
||||
|
||||
Reference in New Issue
Block a user