refactor: rename feed column to timeline column and update related components

- Rename `feed-column` directory to `timeline-column`
- Update import paths and references across the application
- Refactor sidebar and column-related atoms and hooks
- Improve naming consistency for timeline-related components and functions

Signed-off-by: Innei <tukon479@gmail.com>
This commit is contained in:
Innei 2025-02-10 22:24:56 +08:00
parent 8fede2f0c4
commit 3ad053bab3
No known key found for this signature in database
GPG Key ID: 0F62D33977F021F7
31 changed files with 151 additions and 58 deletions

View File

@ -4,20 +4,32 @@ import { createAtomHooks } from "~/lib/jotai"
import { getIsZenMode, useIsZenMode } from "./settings/ui"
const [, , internal_useFeedColumnShow, , internal_getFeedColumnShow, setFeedColumnShow] =
createAtomHooks(atom(true))
const [
,
,
internal_useTimelineColumnShow,
,
internal_getTimelineColumnShow,
setTimelineColumnShow,
] = createAtomHooks(atom(true))
export const useFeedColumnShow = () => {
export const useTimelineColumnShow = () => {
const isZenMode = useIsZenMode()
return internal_useFeedColumnShow() && !isZenMode
return internal_useTimelineColumnShow() && !isZenMode
}
export const getFeedColumnShow = () => {
const isZenMode = getIsZenMode()
return internal_getFeedColumnShow() && !isZenMode
return internal_getTimelineColumnShow() && !isZenMode
}
export { setFeedColumnShow }
export { setTimelineColumnShow }
export const [, , useFeedColumnTempShow, , getFeedColumnTempShow, setFeedColumnTempShow] =
createAtomHooks(atom(false))
export const [
,
,
useTimelineColumnTempShow,
,
getTimelineColumnTempShow,
setTimelineColumnTempShow,
] = createAtomHooks(atom(false))

View File

@ -8,7 +8,7 @@ import { useHotkeys } from "react-hotkeys-hook"
import { useParams } from "react-router"
import { useRealInWideMode } from "~/atoms/settings/ui"
import { useFeedColumnShow, useFeedColumnTempShow } from "~/atoms/sidebar"
import { useTimelineColumnShow, useTimelineColumnTempShow } from "~/atoms/sidebar"
import { m } from "~/components/common/Motion"
import { FixedModalCloseButton } from "~/components/ui/modal/components/close"
import { HotKeyScopeMap, ROUTE_ENTRY_PENDING, ROUTE_FEED_PENDING } from "~/constants"
@ -28,8 +28,8 @@ export const RightContentDesktop = () => {
const realEntryId = entryId === ROUTE_ENTRY_PENDING ? "" : entryId
const showEntryContent = !(views[view]!.wideMode || (settingWideMode && !realEntryId))
const wideMode = !!(settingWideMode && realEntryId)
const feedColumnTempShow = useFeedColumnTempShow()
const feedColumnShow = useFeedColumnShow()
const feedColumnTempShow = useTimelineColumnTempShow()
const feedColumnShow = useTimelineColumnShow()
const shouldHeaderPaddingLeft = feedColumnTempShow && !feedColumnShow && settingWideMode
useHotkeys(

View File

@ -20,11 +20,11 @@ import { Outlet } from "react-router"
import { setMainContainerElement, setRootContainerElement } from "~/atoms/dom"
import { getIsZenMode, getUISettings, setUISetting, useUISettingKey } from "~/atoms/settings/ui"
import {
getFeedColumnTempShow,
setFeedColumnShow,
setFeedColumnTempShow,
useFeedColumnShow,
useFeedColumnTempShow,
getTimelineColumnTempShow,
setTimelineColumnShow,
setTimelineColumnTempShow,
useTimelineColumnShow,
useTimelineColumnTempShow,
} from "~/atoms/sidebar"
import { useLoginModalShow, useWhoami } from "~/atoms/user"
import { AppErrorBoundary } from "~/components/common/AppErrorBoundary"
@ -40,13 +40,13 @@ import { EnvironmentIndicator } from "~/modules/app/EnvironmentIndicator"
import { NetworkStatusIndicator } from "~/modules/app/NetworkStatusIndicator"
import { LoginModalContent } from "~/modules/auth/LoginModalContent"
import { DebugRegistry } from "~/modules/debug/registry"
import { FeedColumn } from "~/modules/feed-column"
import { getSelectedFeedIds, resetSelectedFeedIds } from "~/modules/feed-column/atom"
import { useShortcutsModal } from "~/modules/modal/shortcuts"
import { CmdF } from "~/modules/panel/cmdf"
import { SearchCmdK } from "~/modules/panel/cmdk"
import { CmdNTrigger } from "~/modules/panel/cmdn"
import { CornerPlayer } from "~/modules/player/corner-player"
import { FeedColumn } from "~/modules/timeline-column"
import { getSelectedFeedIds, resetSelectedFeedIds } from "~/modules/timeline-column/atom"
import { UpdateNotice } from "~/modules/update-notice/UpdateNotice"
import { AppNotificationContainer } from "~/modules/upgrade/lazy/index"
import { AppLayoutGridContainerProvider } from "~/providers/app-grid-layout-container-provider"
@ -200,12 +200,12 @@ const FeedResponsiveResizerContainer = ({
},
})
const feedColumnShow = useFeedColumnShow()
const feedColumnTempShow = useFeedColumnTempShow()
const feedColumnShow = useTimelineColumnShow()
const feedColumnTempShow = useTimelineColumnTempShow()
useEffect(() => {
if (feedColumnShow) {
setFeedColumnTempShow(false)
setTimelineColumnTempShow(false)
return
}
const handler = debounce(
@ -214,16 +214,16 @@ const FeedResponsiveResizerContainer = ({
const mouseY = e.clientY
const uiSettings = getUISettings()
const feedColumnTempShow = getFeedColumnTempShow()
const feedColumnTempShow = getTimelineColumnTempShow()
const isInEntryContentWideMode = uiSettings.wideMode || getIsZenMode()
const feedWidth = uiSettings.feedColWidth
if (mouseY < 200 && isInEntryContentWideMode && mouseX < feedWidth) return
const threshold = feedColumnTempShow ? uiSettings.feedColWidth : 100
if (mouseX < threshold) {
setFeedColumnTempShow(true)
setTimelineColumnTempShow(true)
} else {
setFeedColumnTempShow(false)
setTimelineColumnTempShow(false)
}
},
36,
@ -241,7 +241,7 @@ const FeedResponsiveResizerContainer = ({
useHotkeys(
shortcuts.layout.toggleSidebar.key,
() => {
setFeedColumnShow(!feedColumnShow)
setTimelineColumnShow(!feedColumnShow)
},
{
scopes: HotKeyScopeMap.Home,
@ -302,7 +302,7 @@ const FeedResponsiveResizerContainer = ({
cursor={separatorCursor}
{...separatorProps}
onDoubleClick={() => {
setFeedColumnShow(false)
setTimelineColumnShow(false)
}}
tooltip={
!isDragging && (

View File

@ -11,7 +11,7 @@ import { Link } from "react-router"
import { useNavigateEntry } from "~/hooks/biz/useNavigateEntry"
import { useRouteParamsSelector } from "~/hooks/biz/useRouteParams"
import { FeedList } from "../../feed-column/list"
import { FeedList } from "../../timeline-column/FeedList"
import { MobileFloatBar } from "./float-bar.mobile"
export function FeedColumnMobile({ asWidget }: { asWidget?: boolean }) {

View File

@ -11,7 +11,7 @@ import * as React from "react"
import { useTranslation } from "react-i18next"
import { setGeneralSetting, useGeneralSettingKey } from "~/atoms/settings/general"
import { useFeedColumnShow } from "~/atoms/sidebar"
import { useTimelineColumnShow } from "~/atoms/sidebar"
import { useWhoami } from "~/atoms/user"
import { FEED_COLLECTION_LIST, ROUTE_ENTRY_PENDING } from "~/constants"
import { shortcuts } from "~/constants/shortcuts"
@ -63,7 +63,7 @@ export const EntryListHeader: FC<{
const containerRef = React.useRef<HTMLDivElement>(null)
const titleStyleBasedView = ["pl-6", "pl-7", "pl-7", "pl-7", "px-5", "pl-6"]
const feedColumnShow = useFeedColumnShow()
const feedColumnShow = useTimelineColumnShow()
return (
<div
ref={containerRef}

View File

@ -3,7 +3,7 @@ import { useCallback } from "react"
import { useNavigateEntry } from "~/hooks/biz/useNavigateEntry"
import { useRouteParams } from "~/hooks/biz/useRouteParams"
import { InboxItem, ListItem } from "~/modules/feed-column/item"
import { InboxItem, ListItem } from "~/modules/timeline-column/FeedItem"
import { useSubscriptionStore } from "~/store/subscription"
export const TimelineTabs = () => {

View File

@ -1 +0,0 @@
export { FeedList } from "./list.desktop"

View File

@ -37,10 +37,10 @@ import { useFeedUnreadStore } from "~/store/unread"
import { useModalStack } from "../../components/ui/modal/stacked/hooks"
import { ListCreationModalContent } from "../settings/tabs/lists/modals"
import { useFeedListSortSelector } from "./atom"
import { CategoryRemoveDialogContent } from "./category-remove-dialog"
import { FeedItem } from "./item"
import { CategoryRemoveDialogContent } from "./CategoryRemoveDialogContent"
import { FeedItem } from "./FeedItem"
import { feedColumnStyles } from "./styles"
import { UnreadNumber } from "./unread-number"
import { UnreadNumber } from "./UnreadNumber"
type FeedId = string
interface FeedCategoryProps {

View File

@ -33,7 +33,7 @@ import { useFeedUnreadStore } from "~/store/unread"
import { useSelectedFeedIdsState } from "./atom"
import { DraggableContext } from "./context"
import { feedColumnStyles } from "./styles"
import { UnreadNumber } from "./unread-number"
import { UnreadNumber } from "./UnreadNumber"
interface FeedItemProps {
feedId: string

View File

@ -15,8 +15,8 @@ import {
useSelectedFeedIdsState,
} from "./atom"
import { DraggableContext } from "./context"
import { EmptyFeedList, ListHeader, StarredItem, useFeedsGroupedData } from "./FeedList.shared"
import { useShouldFreeUpSpace } from "./hook"
import { EmptyFeedList, ListHeader, StarredItem, useFeedsGroupedData } from "./list.shared"
import { SortableFeedList } from "./sort-by"
const FeedListImpl = forwardRef<HTMLDivElement, { className?: string; view: number }>(

View File

@ -0,0 +1 @@
export { FeedList } from "./FeedList.mobile"

View File

@ -16,7 +16,7 @@ import {
useFeedsGroupedData,
useInboxesGroupedData,
useListsGroupedData,
} from "./list.shared"
} from "./FeedList.shared"
import { SortableFeedList, SortByAlphabeticalInbox, SortByAlphabeticalList } from "./sort-by"
import { feedColumnStyles } from "./styles"

View File

@ -28,7 +28,7 @@ import { feedUnreadActions, useFeedUnreadStore } from "~/store/unread"
import { getFeedListSort, setFeedListSortBy, setFeedListSortOrder, useFeedListSort } from "./atom"
import { feedColumnStyles } from "./styles"
import { UnreadNumber } from "./unread-number"
import { UnreadNumber } from "./UnreadNumber"
export const useFeedsGroupedData = (view: FeedViewType) => {
const { data: remoteData } = useAuthQuery(Queries.subscription.byView(view))

View File

@ -1,6 +1,6 @@
import { withResponsiveSyncComponent } from "@follow/components/utils/selector.js"
import { FeedList as FeedListDesktop } from "./list.desktop"
import { FeedList as FeedListMobile } from "./list.mobile"
import { FeedList as FeedListDesktop } from "./FeedList.desktop"
import { FeedList as FeedListMobile } from "./FeedList.mobile"
export const FeedList = withResponsiveSyncComponent(FeedListDesktop, FeedListMobile)

View File

@ -0,0 +1,81 @@
import { ScrollArea } from "@follow/components/ui/scroll-area/index.js"
import {
Tooltip,
TooltipContent,
TooltipPortal,
TooltipTrigger,
} from "@follow/components/ui/tooltip/index.js"
import { cn } from "@follow/utils/utils"
import dayjs from "dayjs"
import type { FC } from "react"
import { useTranslation } from "react-i18next"
import { useNavigateEntry } from "~/hooks/biz/useNavigateEntry"
import { useFeedById } from "~/store/feed"
import { useListById } from "~/store/list"
import { FeedIcon } from "../feed/feed-icon"
import { FeedTitle } from "../feed/feed-title"
import { feedColumnStyles } from "./styles"
export const ListFeedList: FC<{ listId: string }> = ({ listId }) => {
const list = useListById(listId)
if (!list) return null
return (
<ScrollArea.ScrollArea flex viewportClassName="!px-3" rootClassName="h-full">
{list?.feedIds.map((feedId) => <FeedItem key={feedId} feedId={feedId} />)}
</ScrollArea.ScrollArea>
)
}
interface FeedItemProps {
feedId: string
}
const FeedItem = ({ feedId }: FeedItemProps) => {
const feed = useFeedById(feedId)
const { t } = useTranslation()
const navigate = useNavigateEntry()
if (!feed) return null
const handleClick = () => {
navigate({ feedId })
}
return (
<div className={cn("my-px px-2.5 py-0.5", feedColumnStyles.item)} onClick={handleClick}>
<div
className={cn(
"flex min-w-0 items-center",
feed.errorAt && "text-red-900 dark:text-red-500",
)}
>
<FeedIcon fallback feed={feed} size={16} />
<FeedTitle feed={feed} />
{feed?.errorAt && (
<Tooltip delayDuration={300}>
<TooltipTrigger asChild>
<i className="i-mgc-wifi-off-cute-re ml-1 shrink-0 text-base" />
</TooltipTrigger>
<TooltipPortal>
<TooltipContent>
<div className="flex items-center gap-1">
<i className="i-mgc-time-cute-re" />
{t("feed_item.error_since")}{" "}
{dayjs
.duration(dayjs(feed.errorAt).diff(dayjs(), "minute"), "minute")
.humanize(true)}
</div>
{!!feed.errorMessage && (
<div className="flex items-center gap-1">
<i className="i-mgc-bug-cute-re" />
{feed.errorMessage}
</div>
)}
</TooltipContent>
</TooltipPortal>
</Tooltip>
)}
</div>
</div>
)
}

View File

@ -15,7 +15,7 @@ import { toast } from "sonner"
import { setAppSearchOpen } from "~/atoms/app"
import { useGeneralSettingKey } from "~/atoms/settings/general"
import { useIsZenMode, useSetZenMode } from "~/atoms/settings/ui"
import { setFeedColumnShow, useFeedColumnShow } from "~/atoms/sidebar"
import { setTimelineColumnShow, useTimelineColumnShow } from "~/atoms/sidebar"
import { useNavigateEntry } from "~/hooks/biz/useNavigateEntry"
import { useRouteParamsSelector } from "~/hooks/biz/useRouteParams"
import { useI18n } from "~/hooks/common"
@ -37,7 +37,7 @@ const useBackHome = (timelineId?: string) => {
)
}
export const FeedColumnHeader = memo(() => {
export const TimelineColumnHeader = memo(() => {
const timelineId = useRouteParamsSelector((s) => s.timelineId)
const navigateBackHome = useBackHome(timelineId)
const normalStyle = !window.electron || window.electron.process.platform !== "darwin"
@ -80,7 +80,7 @@ export const FeedColumnHeader = memo(() => {
})
const LayoutActionButton = () => {
const feedColumnShow = useFeedColumnShow()
const feedColumnShow = useTimelineColumnShow()
const [animation, setAnimation] = useState({
width: !feedColumnShow ? "auto" : 0,
@ -119,7 +119,7 @@ const LayoutActionButton = () => {
if (isZenMode) {
setIsZenMode(false)
} else {
setFeedColumnShow(!feedColumnShow)
setTimelineColumnShow(!feedColumnShow)
}
}}
/>

View File

@ -6,17 +6,17 @@ import {
ROUTE_TIMELINE_OF_VIEW,
} from "~/constants"
import { FeedList } from "./list"
import { FeedList } from "./FeedList"
import { ListFeedList } from "./ListFeedList"
export default function TimelineList({ timelineId }: { timelineId: string }) {
if (timelineId.startsWith(ROUTE_TIMELINE_OF_VIEW)) {
const id = Number.parseInt(timelineId.slice(ROUTE_TIMELINE_OF_VIEW.length), 10) as FeedViewType
return <FeedList className="flex size-full flex-col text-sm" view={id} />
} else if (timelineId.startsWith(ROUTE_TIMELINE_OF_LIST)) {
// const id = timelineId.slice(ROUTE_TIMELINE_OF_LIST.length)
return null
const listId = timelineId.slice(ROUTE_TIMELINE_OF_LIST.length)
return <ListFeedList listId={listId} />
} else if (timelineId.startsWith(ROUTE_TIMELINE_OF_INBOX)) {
// const id = timelineId.slice(ROUTE_TIMELINE_OF_INBOX.length)
return null
}
}

View File

@ -15,7 +15,7 @@ import { isHotkeyPressed, useHotkeys } from "react-hotkeys-hook"
import { useRootContainerElement } from "~/atoms/dom"
import { useUISettingKey } from "~/atoms/settings/ui"
import { setFeedColumnShow, useFeedColumnShow } from "~/atoms/sidebar"
import { setTimelineColumnShow, useTimelineColumnShow } from "~/atoms/sidebar"
import { HotKeyScopeMap, isElectronBuild } from "~/constants"
import { shortcuts } from "~/constants/shortcuts"
import { useNavigateEntry } from "~/hooks/biz/useNavigateEntry"
@ -25,11 +25,11 @@ import { useTimelineList } from "~/hooks/biz/useTimelineList"
import { WindowUnderBlur } from "../../components/ui/background"
import { getSelectedFeedIds, resetSelectedFeedIds, setSelectedFeedIds } from "./atom"
import { FeedColumnHeader } from "./header"
import { useShouldFreeUpSpace } from "./hook"
import styles from "./index.module.css"
import TimelineList from "./timeline-list"
import { TimelineSwitchButton } from "./timeline-switch-button"
import { TimelineColumnHeader } from "./TimelineColumnHeader"
import TimelineList from "./TimelineList"
import { TimelineSwitchButton } from "./TimelineSwitchButton"
const lethargy = new Lethargy()
@ -123,7 +123,7 @@ export function FeedColumn({ children, className }: PropsWithChildren<{ classNam
})
const shouldFreeUpSpace = useShouldFreeUpSpace()
const feedColumnShow = useFeedColumnShow()
const feedColumnShow = useTimelineColumnShow()
const rootContainerElement = useRootContainerElement()
return (
@ -137,13 +137,13 @@ export function FeedColumn({ children, className }: PropsWithChildren<{ classNam
)}
onClick={useCallback(() => navigateBackHome(), [navigateBackHome])}
>
<FeedColumnHeader />
<TimelineColumnHeader />
{!feedColumnShow && (
<RootPortal to={rootContainerElement}>
<ActionButton
tooltip={"Toggle Feed Column"}
className="center absolute top-2.5 z-0 hidden -translate-x-2 text-zinc-500 left-macos-traffic-light macos:flex"
onClick={() => setFeedColumnShow(true)}
onClick={() => setTimelineColumnShow(true)}
>
<i className="i-mgc-layout-leftbar-open-cute-re" />
</ActionButton>

View File

@ -6,8 +6,8 @@ import { getPreferredTitle, useFeedStore } from "~/store/feed"
import { useSubscriptionStore } from "~/store/subscription"
import { useFeedListSortSelector } from "../atom"
import { FeedCategory } from "../category"
import { InboxItem, ListItem } from "../item"
import { FeedCategory } from "../FeedCategory"
import { InboxItem, ListItem } from "../FeedItem"
import type { FeedListProps, ListListProps } from "./types"
export const SortByAlphabeticalFeedList = ({

View File

@ -3,7 +3,7 @@ import { Fragment, useCallback } from "react"
import { useFeedUnreadStore } from "~/store/unread"
import { useFeedListSortSelector } from "../atom"
import { FeedCategory } from "../category"
import { FeedCategory } from "../FeedCategory"
import type { FeedListProps } from "./types"
export const SortByUnreadFeedList = ({ view, data, categoryOpenStateData }: FeedListProps) => {