fix: lock system tab ordering

This commit is contained in:
ourongxing
2026-06-26 11:26:24 +00:00
parent caad61e5bd
commit f4e3e9208d
8 changed files with 35 additions and 17 deletions
+8 -5
View File
@@ -96,7 +96,7 @@ function getUpdatedSourceIds() {
try {
const baseRef = getVersionBaseRef()
const ids = new Map<string, number>()
if (!baseRef) return []
if (!baseRef) return
const changedFiles = git(["diff", "--name-only", baseRef, "--", "server/sources"])
.split("\n")
@@ -115,7 +115,6 @@ function getUpdatedSourceIds() {
.map(([id]) => id)
} catch {
consola.warn("Skip updated sources: failed to read git info.")
return []
}
}
@@ -140,9 +139,13 @@ try {
}
try {
const updatedSourceIds = JSON.stringify(getUpdatedSourceIds(), undefined, 2)
writeFileSync(join(projectDir, "./shared/updated-sources.ts"), `export const updatedSourceIds = ${updatedSourceIds} as const\n`)
consola.info("Generated updated-sources.ts")
const updatedSourceIds = getUpdatedSourceIds()
if (updatedSourceIds) {
writeFileSync(join(projectDir, "./shared/updated-sources.ts"), `export const updatedSourceIds = ${JSON.stringify(updatedSourceIds, undefined, 2)} as const\n`)
consola.info("Generated updated-sources.ts")
} else {
consola.info("Skipped updated-sources.ts")
}
} catch {
consola.error("Failed to generate updated-sources.ts")
}
+9 -2
View File
@@ -38,6 +38,13 @@ const updatedSourceIds = [..._updatedSourceIds] as SourceID[]
export const fixedColumnIds = ["focus", "hottest", "realtime", "updated"] as const satisfies Partial<ColumnID>[]
export const hiddenColumns = Object.keys(columns).filter(id => !fixedColumnIds.includes(id as any)) as HiddenColumnID[]
function getSortedSourceIds(type: "hottest" | "realtime") {
return typeSafeObjectEntries(sources)
.filter(([, v]) => v.type === type && !v.redirect)
.map(([k]) => k)
.sort((m, n) => m.localeCompare(n))
}
export const metadata: Metadata = typeSafeObjectFromEntries(typeSafeObjectEntries(columns).map(([k, v]) => {
switch (k) {
case "focus":
@@ -48,12 +55,12 @@ export const metadata: Metadata = typeSafeObjectFromEntries(typeSafeObjectEntrie
case "hottest":
return [k, {
name: v.zh,
sources: typeSafeObjectEntries(sources).filter(([, v]) => v.type === "hottest" && !v.redirect).map(([k]) => k),
sources: getSortedSourceIds("hottest"),
}]
case "realtime":
return [k, {
name: v.zh,
sources: typeSafeObjectEntries(sources).filter(([, v]) => v.type === "realtime" && !v.redirect).map(([k]) => k),
sources: getSortedSourceIds("realtime"),
}]
case "updated":
return [k, {
+1
View File
@@ -97,6 +97,7 @@ export const originSources = {
color: "blue",
home: "https://36kr.com",
column: "tech",
disable: "cf",
sub: {
quick: {
title: "快讯",
+3
View File
@@ -108,6 +108,7 @@
"redirect": "36kr-quick",
"name": "36氪",
"type": "realtime",
"disable": "cf",
"column": "tech",
"home": "https://36kr.com",
"color": "blue",
@@ -117,6 +118,7 @@
"36kr-quick": {
"name": "36氪",
"type": "realtime",
"disable": "cf",
"column": "tech",
"home": "https://36kr.com",
"color": "blue",
@@ -126,6 +128,7 @@
"36kr-renqi": {
"name": "36氪",
"type": "hottest",
"disable": "cf",
"column": "tech",
"home": "https://36kr.com",
"color": "blue",
+1 -1
View File
@@ -20,5 +20,5 @@ export const updatedSourceIds = [
"bilibili-hot-video",
"bilibili-ranking",
"kuaishou",
"toutiao",
"toutiao"
] as const
+1
View File
@@ -21,6 +21,7 @@ export const currentSourcesAtom = atom((get) => {
const id = get(currentColumnIDAtom)
return get(primitiveMetadataAtom).data[id]
}, (get, set, update: Update<SourceID[]>) => {
if (get(currentColumnIDAtom) !== "focus") return
const _ = update instanceof Function ? update(get(currentSourcesAtom)) : update
set(primitiveMetadataAtom, {
updatedTime: Date.now(),
+1 -3
View File
@@ -44,9 +44,7 @@ export function preprocessMetadata(target: PrimitiveMetadata) {
.filter(([id]) => initialMetadata[id])
.map(([id, s]) => {
if (id === "focus") return [id, s.filter(k => sources[k]).map(k => sources[k].redirect ?? k)]
const oldS = s.filter(k => initialMetadata[id].includes(k)).map(k => sources[k].redirect ?? k)
const newS = initialMetadata[id].filter(k => !oldS.includes(k))
return [id, [...oldS, ...newS]]
return [id, initialMetadata[id]]
}),
),
},
+11 -6
View File
@@ -14,12 +14,14 @@ import { useSortable } from "../common/dnd/useSortable"
import { OverlayScrollbar } from "../common/overlay-scrollbar"
import type { ItemsProps } from "./card"
import { CardWrapper } from "./card"
import { currentSourcesAtom } from "~/atoms"
import { currentColumnIDAtom, currentSourcesAtom } from "~/atoms"
const AnimationDuration = 200
const WIDTH = 350
export function Dnd() {
const [items, setItems] = useAtom(currentSourcesAtom)
const currentColumnID = useAtomValue(currentColumnIDAtom)
const sortable = currentColumnID === "focus"
const [parent] = useAutoAnimate({ duration: AnimationDuration })
useEntireQuery(items)
const { width } = useWindowSize()
@@ -31,7 +33,7 @@ export function Dnd() {
if (!items.length) return null
return (
<DndWrapper items={items} setItems={setItems} isSingleColumn={isMobile}>
<DndWrapper items={items} setItems={setItems} isSingleColumn={isMobile} sortable={sortable}>
<OverlayScrollbar defer className="overflow-x-auto">
<motion.ol
className={isMobile
@@ -80,7 +82,7 @@ export function Dnd() {
},
}}
>
<SortableCardWrapper id={id} />
<SortableCardWrapper id={id} sortable={sortable} />
</motion.li>
))}
</motion.ol>
@@ -94,10 +96,11 @@ export function Dnd() {
)
}
function DndWrapper({ items, setItems, isSingleColumn, children }: PropsWithChildren<{
function DndWrapper({ items, setItems, isSingleColumn, sortable, children }: PropsWithChildren<{
items: SourceID[]
setItems: (items: SourceID[]) => void
isSingleColumn: boolean
sortable: boolean
}>) {
const onDropTargetChange = useCallback(({ location, source }: BaseEventPayload<ElementDragType>) => {
const traget = location.current.dropTargets[0]
@@ -122,6 +125,8 @@ function DndWrapper({ items, setItems, isSingleColumn, children }: PropsWithChil
wait: AnimationDuration,
})
const { el } = useAtomValue(goToTopAtom)
if (!sortable) return children
return (
<DndContext onDropTargetChange={run} autoscroll={el ? { element: el } : undefined}>
{children}
@@ -166,7 +171,7 @@ function CardOverlay({ id }: { id: SourceID }) {
)
}
function SortableCardWrapper({ id }: ItemsProps) {
function SortableCardWrapper({ id, sortable }: ItemsProps & { sortable: boolean }) {
const {
isDragging,
setNodeRef,
@@ -186,7 +191,7 @@ function SortableCardWrapper({ id }: ItemsProps) {
ref={setNodeRef}
id={id}
isDragging={isDragging}
setHandleRef={setHandleRef}
setHandleRef={sortable ? setHandleRef : undefined}
/>
{OverlayContainer && createPortal(<CardOverlay id={id} />, OverlayContainer)}
</>