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