mirror of
https://github.com/ourongxing/newsnow.git
synced 2025-01-19 03:09:14 +08:00
refactor(ui): use dndkit instead of framer-motion
This commit is contained in:
parent
51018d4adb
commit
115f4994bd
@ -20,6 +20,7 @@ export const originSources = {
|
||||
"zhihu": {
|
||||
name: "知乎",
|
||||
type: "hottest",
|
||||
color: "blue",
|
||||
home: "https://www.zhihu.com",
|
||||
},
|
||||
"weibo": {
|
||||
@ -47,12 +48,14 @@ export const originSources = {
|
||||
name: "华尔街见闻",
|
||||
interval: Time.Fast,
|
||||
type: "realtime",
|
||||
color: "blue",
|
||||
home: "https://wallstreetcn.com/",
|
||||
title: "快讯",
|
||||
},
|
||||
"36kr": {
|
||||
name: "36氪",
|
||||
type: "realtime",
|
||||
color: "blue",
|
||||
home: "https://36kr.com",
|
||||
sub: {
|
||||
quick: {
|
||||
|
@ -59,8 +59,8 @@ export const CardWrapper = forwardRef<HTMLDivElement, ItemsProps>(({ id, isDragg
|
||||
export function CardOverlay({ id }: { id: SourceID }) {
|
||||
return (
|
||||
<div className={clsx(
|
||||
"flex flex-col h-500px rounded-2xl bg-op-50 p-4 backdrop-blur-5",
|
||||
"backdrop-blur-5 bg-op-40",
|
||||
"flex flex-col h-500px rounded-2xl p-4",
|
||||
"backdrop-blur-5 bg-op-50",
|
||||
`bg-${sources[id].color}`,
|
||||
)}
|
||||
>
|
||||
|
@ -1,19 +1,22 @@
|
||||
import type { PropsWithChildren } from "react"
|
||||
import { useCallback, useState } from "react"
|
||||
import type { DragEndEvent, DragStartEvent } from "@dnd-kit/core"
|
||||
import {
|
||||
DndContext,
|
||||
DragOverlay,
|
||||
MeasuringStrategy,
|
||||
MouseSensor,
|
||||
TouchSensor,
|
||||
closestCenter,
|
||||
useSensor,
|
||||
useSensors,
|
||||
} from "@dnd-kit/core"
|
||||
import { SortableContext, arrayMove, rectSortingStrategy, useSortable } from "@dnd-kit/sortable"
|
||||
import type { AnimateLayoutChanges } from "@dnd-kit/sortable"
|
||||
import { SortableContext, arrayMove, defaultAnimateLayoutChanges, rectSortingStrategy, useSortable } from "@dnd-kit/sortable"
|
||||
import { useAtom } from "jotai"
|
||||
import type { SourceID } from "@shared/types"
|
||||
import { CSS } from "@dnd-kit/utilities"
|
||||
import { LayoutGroup, motion } from "framer-motion"
|
||||
import { motion } from "framer-motion"
|
||||
import type { ItemsProps } from "./card"
|
||||
import { CardOverlay, CardWrapper } from "./card"
|
||||
import { currentSourcesAtom } from "~/atoms"
|
||||
@ -22,42 +25,37 @@ export function Dnd() {
|
||||
const [items, setItems] = useAtom(currentSourcesAtom)
|
||||
return (
|
||||
<DndWrapper items={items} setItems={setItems}>
|
||||
{activeid => (
|
||||
<motion.ol
|
||||
className="grid w-full gap-6"
|
||||
style={{
|
||||
gridTemplateColumns: "repeat(auto-fill, minmax(350px, 1fr))",
|
||||
}}
|
||||
initial="hidden"
|
||||
animate="visible"
|
||||
variants={{
|
||||
visible: {
|
||||
transition: {
|
||||
delayChildren: 0.3,
|
||||
staggerChildren: 0.2,
|
||||
},
|
||||
<motion.ol
|
||||
className="grid w-full gap-6"
|
||||
style={{
|
||||
gridTemplateColumns: "repeat(auto-fill, minmax(350px, 1fr))",
|
||||
}}
|
||||
initial="hidden"
|
||||
animate="visible"
|
||||
variants={{
|
||||
visible: {
|
||||
transition: {
|
||||
delayChildren: 0.3,
|
||||
staggerChildren: 0.2,
|
||||
},
|
||||
}}
|
||||
>
|
||||
<LayoutGroup>
|
||||
{items.map(id => (
|
||||
<motion.li
|
||||
layout={!activeid}
|
||||
key={id}
|
||||
variants={{
|
||||
hidden: { y: 20, opacity: 0 },
|
||||
visible: {
|
||||
y: 0,
|
||||
opacity: 1,
|
||||
},
|
||||
}}
|
||||
>
|
||||
<SortableCardWrapper id={id} />
|
||||
</motion.li>
|
||||
))}
|
||||
</LayoutGroup>
|
||||
</motion.ol>
|
||||
)}
|
||||
},
|
||||
}}
|
||||
>
|
||||
{items.map(id => (
|
||||
<motion.li
|
||||
key={id}
|
||||
variants={{
|
||||
hidden: { y: 20, opacity: 0 },
|
||||
visible: {
|
||||
y: 0,
|
||||
opacity: 1,
|
||||
},
|
||||
}}
|
||||
>
|
||||
<SortableCardWrapper id={id} />
|
||||
</motion.li>
|
||||
))}
|
||||
</motion.ol>
|
||||
</DndWrapper>
|
||||
)
|
||||
}
|
||||
@ -65,10 +63,15 @@ export function Dnd() {
|
||||
interface DndProps {
|
||||
items: SourceID[]
|
||||
setItems: (update: SourceID[]) => void
|
||||
children: (activeId: string | null) => React.ReactNode
|
||||
}
|
||||
|
||||
export function DndWrapper({ items, setItems, children }: DndProps) {
|
||||
const measuringConfig = {
|
||||
droppable: {
|
||||
strategy: MeasuringStrategy.Always,
|
||||
},
|
||||
}
|
||||
|
||||
export function DndWrapper({ items, setItems, children }: PropsWithChildren<DndProps>) {
|
||||
const [activeId, setActiveId] = useState<string | null>(null)
|
||||
const sensors = useSensors(useSensor(MouseSensor), useSensor(TouchSensor))
|
||||
|
||||
@ -94,21 +97,37 @@ export function DndWrapper({ items, setItems, children }: DndProps) {
|
||||
return (
|
||||
<DndContext
|
||||
sensors={sensors}
|
||||
measuring={measuringConfig}
|
||||
collisionDetection={closestCenter}
|
||||
onDragStart={handleDragStart}
|
||||
onDragEnd={handleDragEnd}
|
||||
onDragCancel={handleDragCancel}
|
||||
>
|
||||
<SortableContext items={items} strategy={rectSortingStrategy}>
|
||||
{children(activeId)}
|
||||
{children}
|
||||
</SortableContext>
|
||||
<DragOverlay adjustScale style={{ transformOrigin: "0 0 " }}>
|
||||
{!!activeId && <CardOverlay id={activeId as SourceID} />}
|
||||
<DragOverlay
|
||||
adjustScale
|
||||
dropAnimation={{
|
||||
duration: 300,
|
||||
easing: "cubic-bezier(0.25, 1, 0.5, 1)",
|
||||
}}
|
||||
>
|
||||
{/* {!!activeId && <CardOverlay id={activeId as SourceID} />} */}
|
||||
<CardOverlay id={activeId as SourceID} />
|
||||
</DragOverlay>
|
||||
</DndContext>
|
||||
)
|
||||
}
|
||||
|
||||
const animateLayoutChanges: AnimateLayoutChanges = (args) => {
|
||||
const { isSorting, wasDragging } = args
|
||||
if (isSorting || wasDragging) {
|
||||
return defaultAnimateLayoutChanges(args)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
function SortableCardWrapper({ id, ...props }: ItemsProps) {
|
||||
const {
|
||||
isDragging,
|
||||
@ -117,7 +136,14 @@ function SortableCardWrapper({ id, ...props }: ItemsProps) {
|
||||
setNodeRef,
|
||||
transform,
|
||||
transition,
|
||||
} = useSortable({ id })
|
||||
} = useSortable({
|
||||
id,
|
||||
animateLayoutChanges,
|
||||
transition: {
|
||||
duration: 300,
|
||||
easing: "cubic-bezier(0.25, 1, 0.5, 1)",
|
||||
},
|
||||
})
|
||||
|
||||
const style = {
|
||||
transform: CSS.Transform.toString(transform),
|
||||
|
Loading…
x
Reference in New Issue
Block a user