diff --git a/src/renderer/src/atoms/app.ts b/src/renderer/src/atoms/app.ts
index 6a5807919..175847da2 100644
--- a/src/renderer/src/atoms/app.ts
+++ b/src/renderer/src/atoms/app.ts
@@ -1,7 +1,5 @@
import { createAtomHooks } from "@renderer/lib/jotai"
-import { getStorageNS } from "@renderer/lib/ns"
import { atom } from "jotai"
-import { atomWithStorage } from "jotai/utils"
export const [, , useAppIsReady, , appIsReady, setAppIsReady] = createAtomHooks(
atom(false),
@@ -10,10 +8,3 @@ export const [, , useAppIsReady, , appIsReady, setAppIsReady] = createAtomHooks(
export const [, , useAppSearchOpen, , , setAppSearchOpen] = createAtomHooks(
atom(false),
)
-
-export const [, , useFeedColumnShow, , , setFeedColumnShow] = createAtomHooks(
- atomWithStorage(
- getStorageNS("feed-column-show"),
- true,
- ),
-)
diff --git a/src/renderer/src/atoms/sidebar.ts b/src/renderer/src/atoms/sidebar.ts
index d65421b36..dad16327c 100644
--- a/src/renderer/src/atoms/sidebar.ts
+++ b/src/renderer/src/atoms/sidebar.ts
@@ -47,3 +47,6 @@ viewAtom.onMount = () => {
setSidebarActiveView(view)
}
}
+export const [, , useFeedColumnShow, , , setFeedColumnShow] = createAtomHooks(
+ atom(true),
+)
diff --git a/src/renderer/src/lib/parse-html.ts b/src/renderer/src/lib/parse-html.ts
index ed6cd07f7..a250d93b2 100644
--- a/src/renderer/src/lib/parse-html.ts
+++ b/src/renderer/src/lib/parse-html.ts
@@ -56,16 +56,17 @@ export const parseHtml = (
const hastTree = pipeline.runSync(tree, file)
- let imgCount = 0
+ const images = [] as string[]
visit(tree, "element", (node) => {
- if (node.tagName === "img") {
- imgCount++
+ if (node.tagName === "img" && node.properties.src) {
+ images.push(node.properties.src as string)
}
})
return {
- imgCount,
+ hastTree,
+ images,
toContent: () =>
toJsxRuntime(hastTree, {
Fragment,
diff --git a/src/renderer/src/modules/feed-column/header.tsx b/src/renderer/src/modules/feed-column/header.tsx
new file mode 100644
index 000000000..a9627801e
--- /dev/null
+++ b/src/renderer/src/modules/feed-column/header.tsx
@@ -0,0 +1,154 @@
+import { setAppSearchOpen } from "@renderer/atoms/app"
+import { useGeneralSettingKey } from "@renderer/atoms/settings/general"
+import {
+ setFeedColumnShow,
+ useFeedColumnShow,
+ useSidebarActiveView,
+} from "@renderer/atoms/sidebar"
+import { Logo } from "@renderer/components/icons/logo"
+import { ActionButton } from "@renderer/components/ui/button"
+import {
+ Popover,
+ PopoverContent,
+ PopoverTrigger,
+} from "@renderer/components/ui/popover"
+import { ProfileButton } from "@renderer/components/user-button"
+import { useNavigateEntry } from "@renderer/hooks/biz/useNavigateEntry"
+import { stopPropagation } from "@renderer/lib/dom"
+import { cn } from "@renderer/lib/utils"
+import { m } from "framer-motion"
+import type { FC, PropsWithChildren } from "react"
+import { useCallback, useRef, useState } from "react"
+import { Link } from "react-router-dom"
+import { toast } from "sonner"
+
+const useBackHome = (active: number) => {
+ const navigate = useNavigateEntry()
+
+ return useCallback(
+ (overvideActive?: number) => {
+ navigate({
+ feedId: null,
+ entryId: null,
+ view: overvideActive ?? active,
+ })
+ },
+ [active, navigate],
+ )
+}
+
+export const FeedColumnHeader = () => {
+ const [active] = useSidebarActiveView()
+
+ const navigateBackHome = useBackHome(active)
+ const normalStyle =
+ !window.electron || window.electron.process.platform !== "darwin"
+ return (
+
+ {normalStyle && (
+
+ {
+ e.stopPropagation()
+ navigateBackHome()
+ }}
+ >
+
+
+ {APP_NAME}
+
+
+ )}
+
+
+ )
+}
+
+const LayoutActionButton = () => {
+ const feedColumnShow = useFeedColumnShow()
+
+ return (
+
+
+ }
+ onClick={() => setFeedColumnShow(!feedColumnShow)}
+ />
+
+ )
+}
+
+const LogoContextMenu: FC = ({ children }) => {
+ const [open, setOpen] = useState(false)
+ const logoRef = useRef(null)
+
+ return (
+
+ {
+ setOpen(true)
+ }}
+ >
+ {children}
+
+
+
+
+
+ )
+}
+
+const SearchActionButton = () => {
+ const canSearch = useGeneralSettingKey("dataPersist")
+ if (!canSearch) return null
+ return (
+ setAppSearchOpen(true)}
+ >
+
+
+ )
+}
diff --git a/src/renderer/src/modules/feed-column/index.tsx b/src/renderer/src/modules/feed-column/index.tsx
index 32601e2b5..220fa588c 100644
--- a/src/renderer/src/modules/feed-column/index.tsx
+++ b/src/renderer/src/modules/feed-column/index.tsx
@@ -1,16 +1,7 @@
-import { setAppSearchOpen } from "@renderer/atoms/app"
import { getReadonlyRoute } from "@renderer/atoms/route"
-import { useGeneralSettingKey } from "@renderer/atoms/settings/general"
import { useUISettingKey } from "@renderer/atoms/settings/ui"
import { useSidebarActiveView } from "@renderer/atoms/sidebar"
-import { Logo } from "@renderer/components/icons/logo"
import { ActionButton } from "@renderer/components/ui/button"
-import {
- Popover,
- PopoverContent,
- PopoverTrigger,
-} from "@renderer/components/ui/popover"
-import { ProfileButton } from "@renderer/components/user-button"
import { HotKeyScopeMap, views } from "@renderer/constants"
import { shortcuts } from "@renderer/constants/shortcuts"
import { useNavigateEntry } from "@renderer/hooks/biz/useNavigateEntry"
@@ -30,18 +21,12 @@ import type { MotionValue } from "framer-motion"
import { m, useSpring } from "framer-motion"
import { atom, useAtomValue } from "jotai"
import { Lethargy } from "lethargy"
-import type { FC, PropsWithChildren } from "react"
-import {
- useCallback,
- useLayoutEffect,
- useRef,
- useState,
-} from "react"
+import type { PropsWithChildren } from "react"
+import { useCallback, useLayoutEffect, useRef } from "react"
import { isHotkeyPressed, useHotkeys } from "react-hotkeys-hook"
-import { Link } from "react-router-dom"
-import { toast } from "sonner"
import { WindowUnderBlur } from "../../components/ui/background"
+import { FeedColumnHeader } from "./header"
import { FeedList } from "./list"
const lethargy = new Lethargy()
@@ -168,6 +153,7 @@ export function FeedColumn({ children }: PropsWithChildren) {
const handler = () => {
const width = $carousel.clientWidth
+
jotaiStore.set(carouselWidthAtom, width)
}
handler()
@@ -177,9 +163,6 @@ export function FeedColumn({ children }: PropsWithChildren) {
}
}, [])
- const normalStyle =
- !window.electron || window.electron.process.platform !== "darwin"
-
const unreadByView = useUnreadByView()
const showSidebarUnreadCount = useUISettingKey("sidebarShowUnreadCount")
@@ -193,42 +176,7 @@ export function FeedColumn({ children }: PropsWithChildren) {
className="relative flex h-full flex-col space-y-3 rounded-l-[12px] pt-2.5"
onClick={useCallback(() => navigateBackHome(), [navigateBackHome])}
>
-
- {normalStyle && (
-
- {
- e.stopPropagation()
- navigateBackHome()
- }}
- >
-
-
- {APP_NAME}
-
-
- )}
-
-
+
)
}
-
-const SearchActionButton = () => {
- const canSearch = useGeneralSettingKey("dataPersist")
- if (!canSearch) return null
- return (
-
setAppSearchOpen(true)}
- >
-
-
- )
-}
-
-const LogoContextMenu: FC
= ({ children }) => {
- const [open, setOpen] = useState(false)
- const logoRef = useRef(null)
-
- return (
-
- {
- setOpen(true)
- }}
- >
- {children}
-
-
-
-
-
- )
-}
diff --git a/src/renderer/src/pages/(main)/layout.tsx b/src/renderer/src/pages/(main)/layout.tsx
index fc75da58c..709d8669c 100644
--- a/src/renderer/src/pages/(main)/layout.tsx
+++ b/src/renderer/src/pages/(main)/layout.tsx
@@ -1,7 +1,7 @@
import { repository } from "@pkg"
-import { useFeedColumnShow } from "@renderer/atoms/app"
import { setMainContainerElement } from "@renderer/atoms/dom"
import { getUISettings, setUISetting } from "@renderer/atoms/settings/ui"
+import { setFeedColumnShow, useFeedColumnShow } from "@renderer/atoms/sidebar"
import { useLoginModalShow, useWhoami } from "@renderer/atoms/user"
import { AppErrorBoundary } from "@renderer/components/common/AppErrorBoundary"
import { ErrorComponentType } from "@renderer/components/errors"
@@ -9,6 +9,7 @@ import { PanelSplitter } from "@renderer/components/ui/divider"
import { DeclarativeModal } from "@renderer/components/ui/modal/stacked/declarative-modal"
import { NoopChildren } from "@renderer/components/ui/modal/stacked/utils"
import { RootPortal } from "@renderer/components/ui/portal"
+import { shortcuts } from "@renderer/constants/shortcuts"
import { preventDefault } from "@renderer/lib/dom"
import { cn } from "@renderer/lib/utils"
import { EnvironmentIndicator } from "@renderer/modules/app/EnvironmentIndicator"
@@ -20,8 +21,10 @@ import { CornerPlayer } from "@renderer/modules/feed-column/corner-player"
import { CmdF } from "@renderer/modules/panel/cmdf"
import { SearchCmdK } from "@renderer/modules/panel/cmdk"
import { CmdNTrigger } from "@renderer/modules/panel/cmdn"
+import { throttle } from "lodash-es"
import type { PropsWithChildren } from "react"
-import { useRef } from "react"
+import { useEffect, useRef, useState } from "react"
+import { useHotkeys } from "react-hotkeys-hook"
import { useResizable } from "react-resizable-layout"
import { Outlet } from "react-router-dom"
@@ -87,9 +90,7 @@ export function Component() {
// NOTE: tabIndex for main element can get by `document.activeElement`
tabIndex={-1}
>
-
+
@@ -138,14 +139,61 @@ const FeedResponsiveResizerContainer = ({
})
const feedColumnShow = useFeedColumnShow()
+ const [feedColumnTempShow, setFeedColumnTempShow] = useState(false)
+
+ useEffect(() => {
+ const handler = throttle((e: MouseEvent) => {
+ const mouseX = e.clientX
+ const { feedColWidth } = getUISettings()
+
+ if (mouseX < feedColWidth) {
+ setFeedColumnTempShow(true)
+ } else {
+ setFeedColumnTempShow(false)
+ }
+ }, 300)
+
+ document.addEventListener("mousemove", handler)
+ return () => {
+ document.removeEventListener("mousemove", handler)
+ }
+ }, [])
+
+ useHotkeys(shortcuts.layout.toggleSidebar.key, () => {
+ setFeedColumnShow(!feedColumnShow)
+ })
+
+ const [delayShowSplitter, setDelayShowSplitter] = useState(feedColumnShow)
+
+ useEffect(() => {
+ let timer: any
+ if (feedColumnShow) {
+ // eslint-disable-next-line @eslint-react/web-api/no-leaked-timeout
+ timer = setTimeout(() => {
+ setDelayShowSplitter(true)
+ }, 200)
+ } else {
+ // eslint-disable-next-line @eslint-react/hooks-extra/no-direct-set-state-in-use-effect
+ setDelayShowSplitter(false)
+ }
+
+ return () => {
+ timer = clearTimeout(timer)
+ }
+ }, [feedColumnShow])
return (
<>
- {feedColumnShow && }
+ {delayShowSplitter && }
>
)
}
diff --git a/src/renderer/src/styles/tailwind-extend.css b/src/renderer/src/styles/tailwind-extend.css
index 960953646..47ef7924d 100644
--- a/src/renderer/src/styles/tailwind-extend.css
+++ b/src/renderer/src/styles/tailwind-extend.css
@@ -279,6 +279,13 @@
[data-theme="dark"] .shadow-drawer-left {
box-shadow: -12px 0px 17px 2px rgba(0, 0, 0, 0.653);
}
+
+ .shadow-drawer-right {
+ box-shadow: 12px 0px 17px 2px rgba(41, 41, 41, 0.1);
+ }
+ [data-theme="dark"] .shadow-drawer-right {
+ box-shadow: 12px 0px 17px 2px rgba(0, 0, 0, 0.653);
+ }
}
@layer components {