feat: updates

This commit is contained in:
qier222 2023-01-07 14:39:03 +08:00
parent 884f3df41a
commit c6c59b2cd9
No known key found for this signature in database
84 changed files with 3531 additions and 2616 deletions

View file

@ -1,6 +1,4 @@
import useUserAlbums, {
useMutationLikeAAlbum,
} from '@/web/api/hooks/useUserAlbums'
import useUserAlbums, { useMutationLikeAAlbum } from '@/web/api/hooks/useUserAlbums'
import contextMenus, { closeContextMenu } from '@/web/states/contextMenus'
import player from '@/web/states/player'
import { AnimatePresence } from 'framer-motion'
@ -14,16 +12,15 @@ import BasicContextMenu from './BasicContextMenu'
const AlbumContextMenu = () => {
const { t } = useTranslation()
const { cursorPosition, type, dataSourceID, target, options } =
useSnapshot(contextMenus)
const { cursorPosition, type, dataSourceID, target, options } = useSnapshot(contextMenus)
const likeAAlbum = useMutationLikeAAlbum()
const [, copyToClipboard] = useCopyToClipboard()
const { data: likedAlbums } = useUserAlbums()
const addToLibraryLabel = useMemo(() => {
return likedAlbums?.data?.find(a => a.id === Number(dataSourceID))
? 'Remove from Library'
: 'Add to Library'
? t`context-menu.remove-from-library`
: t`context-menu.add-to-library`
}, [dataSourceID, likedAlbums?.data])
return (
@ -82,19 +79,15 @@ const AlbumContextMenu = () => {
type: 'item',
label: t`context-menu.copy-netease-link`,
onClick: () => {
copyToClipboard(
`https://music.163.com/#/album?id=${dataSourceID}`
)
copyToClipboard(`https://music.163.com/#/album?id=${dataSourceID}`)
toast.success(t`toasts.copied`)
},
},
{
type: 'item',
label: 'Copy YPM Link',
label: t`context-menu.copy-r3play-link`,
onClick: () => {
copyToClipboard(
`${window.location.origin}/album/${dataSourceID}`
)
copyToClipboard(`${window.location.origin}/album/${dataSourceID}`)
toast.success(t`toasts.copied`)
},
},

View file

@ -4,6 +4,8 @@ import useLockMainScroll from '@/web/hooks/useLockMainScroll'
import useMeasure from 'react-use-measure'
import { ContextMenuItem } from './MenuItem'
import MenuPanel from './MenuPanel'
import { createPortal } from 'react-dom'
import { ContextMenuPosition } from './types'
const BasicContextMenu = ({
onClose,
@ -19,15 +21,14 @@ const BasicContextMenu = ({
cursorPosition: { x: number; y: number }
options?: {
useCursorPosition?: boolean
fixedPosition?: `${'top' | 'bottom'}-${'left' | 'right'}`
} | null
classNames?: string
}) => {
const menuRef = useRef<HTMLDivElement>(null)
const [measureRef, menu] = useMeasure()
const [position, setPosition] = useState<{ x: number; y: number } | null>(
null
)
const [position, setPosition] = useState<ContextMenuPosition | null>(null)
useClickAway(menuRef, onClose)
useLockMainScroll(!!position)
@ -43,6 +44,22 @@ const BasicContextMenu = ({
y: bottomY + menu.height < window.innerHeight ? bottomY : topY,
}
setPosition(position)
} else if (options?.fixedPosition) {
const [vertical, horizontal] = options.fixedPosition.split('-') as [
'top' | 'bottom',
'left' | 'right'
]
const button = target.getBoundingClientRect()
const leftX = button.x
const rightX = button.x - menu.width + button.width
const bottomY = button.y + button.height + 8
const topY = button.y - menu.height - 8
const position: ContextMenuPosition = {
x: horizontal === 'left' ? leftX : rightX,
y: vertical === 'bottom' ? bottomY : topY,
transformOrigin: `origin-${options.fixedPosition}`,
}
setPosition(position)
} else {
const button = target.getBoundingClientRect()
const leftX = button.x
@ -57,7 +74,7 @@ const BasicContextMenu = ({
}
}, [target, menu, options?.useCursorPosition, cursorPosition])
return (
return createPortal(
<>
<MenuPanel
position={{ x: 99999, y: 99999 }}
@ -78,7 +95,8 @@ const BasicContextMenu = ({
classNames={classNames}
/>
)}
</>
</>,
document.body
)
}

View file

@ -1,13 +1,7 @@
import { css, cx } from '@emotion/css'
import { ForwardedRef, forwardRef, useRef, useState } from 'react'
import Icon from '../Icon'
export interface ContextMenuItem {
type: 'item' | 'submenu' | 'divider'
label?: string
onClick?: (e: MouseEvent) => void
items?: ContextMenuItem[]
}
import { ContextMenuItem } from './types'
const MenuItem = ({
item,
@ -63,7 +57,7 @@ const MenuItem = ({
onSubmenuClose()
}}
className={cx(
'relative',
'relative cursor-default',
className,
css`
padding-right: 9px;

View file

@ -7,14 +7,11 @@ import {
useState,
} from 'react'
import { motion } from 'framer-motion'
import MenuItem, { ContextMenuItem } from './MenuItem'
import MenuItem from './MenuItem'
import { ContextMenuItem, ContextMenuPosition } from './types'
interface PanelProps {
position: {
x: number
y: number
transformOrigin?: `origin-${'top' | 'bottom'}-${'left' | 'right'}`
}
position: ContextMenuPosition
items: ContextMenuItem[]
onClose: (e: MouseEvent) => void
forMeasure?: boolean
@ -36,33 +33,33 @@ const MenuPanel = forwardRef(
return (
// Container (to add padding for submenus)
<motion.div
initial={{ opacity: 0, scale: forMeasure ? 1 : 0.96 }}
animate={{
opacity: 1,
scale: 1,
transition: {
duration: 0.1,
},
}}
exit={{ opacity: 0, scale: 0.96 }}
transition={{ duration: 0.2 }}
<div
ref={ref}
className={cx(
'fixed',
position.transformOrigin || 'origin-top-left',
isSubmenu ? 'submenu z-20 px-1' : 'z-10'
'fixed select-none',
isSubmenu ? 'submenu z-30 px-1' : 'z-20'
)}
style={{ left: position.x, top: position.y }}
>
{/* The real panel */}
<div
<motion.div
initial={{ opacity: 0, scale: forMeasure ? 1 : 0.96 }}
animate={{
opacity: 1,
scale: 1,
transition: {
duration: 0.1,
},
}}
exit={{ opacity: 0, scale: 0.96 }}
transition={{ duration: 0.2 }}
className={cx(
'rounded-12 border border-white/[.06] bg-gray-900/95 p-px py-2.5 shadow-xl outline outline-1 outline-black backdrop-blur-3xl',
css`
min-width: 200px;
`,
classNames
classNames,
position.transformOrigin || 'origin-top-left'
)}
>
{items.map((item, index) => (
@ -76,7 +73,7 @@ const MenuPanel = forwardRef(
className={isSubmenu ? 'submenu' : ''}
/>
))}
</div>
</motion.div>
{/* Submenu */}
<SubMenu
@ -86,7 +83,7 @@ const MenuPanel = forwardRef(
itemRect={submenuProps?.itemRect}
onClose={onClose}
/>
</motion.div>
</div>
)
}
)

View file

@ -0,0 +1,12 @@
export interface ContextMenuPosition {
x: number
y: number
transformOrigin?: `origin-${'top' | 'bottom'}-${'left' | 'right'}`
}
export interface ContextMenuItem {
type: 'item' | 'submenu' | 'divider'
label?: string
onClick?: (e: MouseEvent) => void
items?: ContextMenuItem[]
}