feat: support dnd in all sections

This commit is contained in:
Ou 2024-10-09 21:36:42 +08:00
parent c3b6ae1f01
commit 731b31c8ce
8 changed files with 49 additions and 42 deletions

View File

@ -1,13 +1,13 @@
import type { Metadata } from "./types"
export const sectionIds = ["focus", "social", "china", "world", "tech", "code"] as const
export const sectionIds = ["focus", "realtime", "china", "world", "tech", "code"] as const
export const metadata: Metadata = {
focus: {
name: "关注",
sources: [],
},
social: {
realtime: {
name: "实时",
sources: ["weibo", "douyin", "zhihu", "toutiao", "wallstreetcn", "ithome", "36kr"],
},
@ -25,6 +25,6 @@ export const metadata: Metadata = {
},
tech: {
name: "科技",
sources: ["ithome", "coolapk"],
sources: ["ithome", "coolapk", "36kr-quick"],
},
}

View File

@ -2,10 +2,32 @@ import { atom } from "jotai"
import type { SectionID, SourceID } from "@shared/types"
import { metadata } from "@shared/data"
import { sources } from "@shared/sources"
import { typeSafeObjectEntries, typeSafeObjectFromEntries } from "@shared/type.util"
import { atomWithLocalStorage } from "./hooks/atomWithLocalStorage"
export const focusSourcesAtom = atomWithLocalStorage<SourceID[]>("focusSources", [], (stored) => {
return stored.filter(item => item in sources)
const initialSources = typeSafeObjectFromEntries(typeSafeObjectEntries(metadata).map(([id, val]) => [id, val.sources]))
export const localSourcesAtom = atomWithLocalStorage<Record<SectionID, SourceID[]>>("localsources", () => {
return initialSources
}, (stored) => {
return typeSafeObjectFromEntries(typeSafeObjectEntries({
...initialSources,
...stored,
}).filter(([id]) => initialSources[id]).map(([id, val]) => {
if (id === "focus") return [id, val]
const oldS = val.filter(k => initialSources[id].includes(k))
const newS = initialSources[id].filter(k => !oldS.includes(k))
return [id, [...oldS, ...newS]]
}))
})
export const focusSourcesAtom = atom((get) => {
return get(localSourcesAtom).focus
}, (get, set, update: SourceID[] | ((prev: SourceID[]) => SourceID[])) => {
const _ = update instanceof Function ? update(get(focusSourcesAtom)) : update
set(localSourcesAtom, {
...get(localSourcesAtom),
focus: _,
})
})
function initRefetchSources() {
@ -27,15 +49,11 @@ export const currentSectionIDAtom = atom<SectionID>("focus")
export const currentSectionAtom = atom((get) => {
const id = get(currentSectionIDAtom)
if (id === "focus") {
return {
id,
...metadata[id],
sources: get(focusSourcesAtom),
}
}
return {
id,
...metadata[id],
}
return get(localSourcesAtom)[id]
}, (get, set, update: SourceID[] | ((prev: SourceID[]) => SourceID[])) => {
const _ = update instanceof Function ? update(get(currentSectionAtom)) : update
set(localSourcesAtom, {
...get(localSourcesAtom),
[get(currentSectionIDAtom)]: _,
})
})

View File

@ -24,7 +24,7 @@ function RefreshButton() {
const currentSection = useAtomValue(currentSectionAtom)
const setRefetchSource = useSetAtom(refetchSourcesAtom)
const refreshAll = useCallback(() => {
const obj = Object.fromEntries(currentSection.sources.map(id => [id, Date.now()]))
const obj = Object.fromEntries(currentSection.map(id => [id, Date.now()]))
setRefetchSource(prev => ({
...prev,
...obj,
@ -33,7 +33,7 @@ function RefreshButton() {
const isFetching = useIsFetching({
predicate: (query) => {
return currentSection.sources.includes(query.queryKey[0] as SourceID)
return currentSection.includes(query.queryKey[0] as SourceID)
},
})

View File

@ -15,10 +15,10 @@ import type { SourceID } from "@shared/types"
import { CSS } from "@dnd-kit/utilities"
import type { ItemsProps } from "./card"
import { CardWrapper } from "./card"
import { focusSourcesAtom } from "~/atoms"
import { currentSectionAtom } from "~/atoms"
export function Dnd() {
const [items, setItems] = useAtom(focusSourcesAtom)
const [items, setItems] = useAtom(currentSectionAtom)
const [activeId, setActiveId] = useState<string | null>(null)
const sensors = useSensors(useSensor(MouseSensor), useSensor(TouchSensor))

View File

@ -5,7 +5,6 @@ import clsx from "clsx"
import { useSetAtom } from "jotai"
import { useEffect } from "react"
import { Dnd } from "./dnd"
import { CardWrapper } from "./card"
import { currentSectionIDAtom } from "~/atoms"
export function Section({ id }: { id: SectionID }) {
@ -38,17 +37,7 @@ export function Section({ id }: { id: SectionID }) {
gridTemplateColumns: "repeat(auto-fill, minmax(350px, 1fr))",
}}
>
{id === "focus"
? <Dnd />
: (
<>
{
metadata[id].sources.map(source => (
<CardWrapper key={source} id={source} />
))
}
</>
)}
<Dnd />
</div>
</div>
)

View File

@ -3,7 +3,7 @@ import { atom } from "jotai"
export function atomWithLocalStorage<T>(
key: string,
initialValue: T,
initialValue: T | (() => T),
initFn?: ((stored: T) => T),
): PrimitiveAtom<T> {
const getInitialValue = () => {
@ -17,7 +17,8 @@ export function atomWithLocalStorage<T>(
} catch {
//
}
return initialValue
if (initialValue instanceof Function) return initialValue()
else return initialValue
}
const baseAtom = atom(getInitialValue())
const derivedAtom = atom(

View File

@ -16,11 +16,10 @@ export const Route = createRootRouteWithContext<{
})
function NotFoundComponent() {
// const nav = Route.useNavigate()
// nav({
// to: "/",
// })
// return <div></div>
const nav = Route.useNavigate()
nav({
to: "/",
})
}
function RootComponent() {

View File

@ -1,7 +1,7 @@
import { createFileRoute } from "@tanstack/react-router"
import { useAtomValue } from "jotai"
import { useMemo } from "react"
import { focusSourcesAtom } from "~/atoms"
import { localSourcesAtom } from "~/atoms"
import { Section } from "~/components/section"
export const Route = createFileRoute("/")({
@ -9,9 +9,9 @@ export const Route = createFileRoute("/")({
})
function IndexComponent() {
const focusSources = useAtomValue(focusSourcesAtom)
const focusSources = useAtomValue(localSourcesAtom)
const id = useMemo(() => {
return focusSources.length ? "focus" : "social"
return focusSources.focus.length ? "focus" : "realtime"
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [])
return <Section id={id} />