Fix store item variant defaults and listing sorting
Auto-select first option in variation modals and sort store items by availability, then update time. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
co-authored by
Cursor
parent
b861ab3dc1
commit
5f4b0b4f92
@@ -27,7 +27,6 @@
|
||||
.menu {
|
||||
position: fixed;
|
||||
z-index: 1200;
|
||||
transform: translateX(-100%);
|
||||
min-width: 220px;
|
||||
padding: 6px;
|
||||
border-radius: 10px;
|
||||
@@ -98,10 +97,10 @@
|
||||
@keyframes menuIn {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateX(-100%) translateY(-4px);
|
||||
transform: translateY(-4px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateX(-100%) translateY(0);
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { useEffect, useRef, useState } from 'react'
|
||||
import { useEffect, useLayoutEffect, useRef, useState } from 'react'
|
||||
import { createPortal } from 'react-dom'
|
||||
import { Eraser, MoreHorizontal, Trash2, Users } from 'lucide-react'
|
||||
import { fitFixedPopover } from '../utils/fitFixedPopover'
|
||||
import styles from './BusinessActionsOverflowMenu.module.css'
|
||||
|
||||
type PopoverPosition = {
|
||||
@@ -31,10 +32,11 @@ export function BusinessActionsOverflowMenu({
|
||||
const rect = triggerRef.current?.getBoundingClientRect()
|
||||
if (!rect) return
|
||||
|
||||
setPopoverPos({
|
||||
top: rect.bottom + 8,
|
||||
left: rect.right,
|
||||
})
|
||||
const size = popoverRef.current
|
||||
? { width: popoverRef.current.offsetWidth, height: popoverRef.current.offsetHeight }
|
||||
: { width: 220, height: 160 }
|
||||
|
||||
setPopoverPos(fitFixedPopover(rect, size, 'end'))
|
||||
}
|
||||
|
||||
function toggleOpen() {
|
||||
@@ -47,6 +49,11 @@ export function BusinessActionsOverflowMenu({
|
||||
setOpen(true)
|
||||
}
|
||||
|
||||
useLayoutEffect(() => {
|
||||
if (!open) return
|
||||
updatePopoverPosition()
|
||||
}, [open])
|
||||
|
||||
useEffect(() => {
|
||||
if (!open) return
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { useEffect, useRef, useState } from 'react'
|
||||
import { useEffect, useLayoutEffect, useRef, useState } from 'react'
|
||||
import { createPortal } from 'react-dom'
|
||||
import {
|
||||
Building2,
|
||||
@@ -8,6 +8,7 @@ import {
|
||||
Trash2,
|
||||
UserRound,
|
||||
} from 'lucide-react'
|
||||
import { fitFixedPopover } from '../utils/fitFixedPopover'
|
||||
import styles from './BusinessActionsOverflowMenu.module.css'
|
||||
|
||||
type PopoverPosition = {
|
||||
@@ -52,10 +53,11 @@ export function DomainLinksOverflowMenu({ host, onRemove }: DomainLinksOverflowM
|
||||
const rect = triggerRef.current?.getBoundingClientRect()
|
||||
if (!rect) return
|
||||
|
||||
setPopoverPos({
|
||||
top: rect.bottom + 8,
|
||||
left: rect.right,
|
||||
})
|
||||
const size = popoverRef.current
|
||||
? { width: popoverRef.current.offsetWidth, height: popoverRef.current.offsetHeight }
|
||||
: { width: 220, height: 220 }
|
||||
|
||||
setPopoverPos(fitFixedPopover(rect, size, 'end'))
|
||||
}
|
||||
|
||||
function toggleOpen() {
|
||||
@@ -68,6 +70,11 @@ export function DomainLinksOverflowMenu({ host, onRemove }: DomainLinksOverflowM
|
||||
setOpen(true)
|
||||
}
|
||||
|
||||
useLayoutEffect(() => {
|
||||
if (!open) return
|
||||
updatePopoverPosition()
|
||||
}, [open])
|
||||
|
||||
useEffect(() => {
|
||||
if (!open) return
|
||||
|
||||
|
||||
@@ -41,7 +41,6 @@
|
||||
.popover {
|
||||
position: fixed;
|
||||
z-index: 1200;
|
||||
transform: translateX(-50%);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { useEffect, useRef, useState } from 'react'
|
||||
import { useEffect, useLayoutEffect, useRef, useState } from 'react'
|
||||
import { createPortal } from 'react-dom'
|
||||
import { Moon, Sun } from 'lucide-react'
|
||||
import {
|
||||
@@ -7,6 +7,7 @@ import {
|
||||
type BusinessPrimaryColorId,
|
||||
} from '../utils/businessPrimaryColors'
|
||||
import type { DashboardThemeMode } from '../services/businessSettingsService'
|
||||
import { fitFixedPopover } from '../utils/fitFixedPopover'
|
||||
import styles from './PrimaryColorSwatchControl.module.css'
|
||||
|
||||
interface PrimaryColorSwatchControlProps {
|
||||
@@ -41,10 +42,11 @@ export function PrimaryColorSwatchControl({
|
||||
const rect = triggerRef.current?.getBoundingClientRect()
|
||||
if (!rect) return
|
||||
|
||||
setPopoverPos({
|
||||
top: rect.bottom + 8,
|
||||
left: rect.left + rect.width / 2,
|
||||
})
|
||||
const size = popoverRef.current
|
||||
? { width: popoverRef.current.offsetWidth, height: popoverRef.current.offsetHeight }
|
||||
: { width: 220, height: 160 }
|
||||
|
||||
setPopoverPos(fitFixedPopover(rect, size, 'center'))
|
||||
}
|
||||
|
||||
function toggleOpen() {
|
||||
@@ -72,6 +74,11 @@ export function PrimaryColorSwatchControl({
|
||||
}
|
||||
}
|
||||
|
||||
useLayoutEffect(() => {
|
||||
if (!open) return
|
||||
updatePopoverPosition()
|
||||
}, [open])
|
||||
|
||||
useEffect(() => {
|
||||
if (!open) return
|
||||
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
const GAP = 8
|
||||
const VIEWPORT_PAD = 8
|
||||
|
||||
export type FixedPopoverCoords = {
|
||||
top: number
|
||||
left: number
|
||||
}
|
||||
|
||||
export function fitFixedPopover(
|
||||
trigger: DOMRect,
|
||||
size: { width: number; height: number },
|
||||
align: 'end' | 'center' = 'end',
|
||||
): FixedPopoverCoords {
|
||||
const vw = window.innerWidth
|
||||
const vh = window.innerHeight
|
||||
const width = Math.max(1, size.width)
|
||||
const height = Math.max(1, size.height)
|
||||
|
||||
const spaceBelow = vh - trigger.bottom - VIEWPORT_PAD
|
||||
const spaceAbove = trigger.top - VIEWPORT_PAD
|
||||
const placeBelow = spaceBelow >= height + GAP || spaceBelow >= spaceAbove
|
||||
|
||||
let top = placeBelow ? trigger.bottom + GAP : trigger.top - GAP - height
|
||||
top = Math.min(Math.max(top, VIEWPORT_PAD), Math.max(VIEWPORT_PAD, vh - VIEWPORT_PAD - height))
|
||||
|
||||
let left =
|
||||
align === 'center'
|
||||
? trigger.left + trigger.width / 2 - width / 2
|
||||
: trigger.right - width
|
||||
|
||||
const maxLeft = Math.max(VIEWPORT_PAD, vw - VIEWPORT_PAD - width)
|
||||
left = Math.min(Math.max(left, VIEWPORT_PAD), maxLeft)
|
||||
|
||||
return { top, left }
|
||||
}
|
||||
Reference in New Issue
Block a user