diff --git a/package.json b/package.json
index 5b234dd..186fc3e 100644
--- a/package.json
+++ b/package.json
@@ -52,7 +52,6 @@
"md5": "^2.3.0",
"ofetch": "^1.4.1",
"overlayscrollbars": "^2.10.0",
- "overlayscrollbars-react": "^0.5.6",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-use": "^17.5.1",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 8ab4bb3..cf2b0c4 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -92,18 +92,12 @@ importers:
md5:
specifier: ^2.3.0
version: 2.3.0
- motion:
- specifier: ^10.18.0
- version: 10.18.0
ofetch:
specifier: ^1.4.1
version: 1.4.1
overlayscrollbars:
specifier: ^2.10.0
version: 2.10.0
- overlayscrollbars-react:
- specifier: ^0.5.6
- version: 0.5.6(overlayscrollbars@2.10.0)(react@18.3.1)
react:
specifier: ^18.3.1
version: 18.3.1
@@ -1549,24 +1543,6 @@ packages:
resolution: {integrity: sha512-Yhlar6v9WQgUp/He7BdgzOz8lqMQ8sU+jkCq7Wx8Myc5YFJLbEe7lgui/V7G1qB1DJykHSGwreceSaD60Y0PUQ==}
hasBin: true
- '@motionone/animation@10.18.0':
- resolution: {integrity: sha512-9z2p5GFGCm0gBsZbi8rVMOAJCtw1WqBTIPw3ozk06gDvZInBPIsQcHgYogEJ4yuHJ+akuW8g1SEIOpTOvYs8hw==}
-
- '@motionone/dom@10.18.0':
- resolution: {integrity: sha512-bKLP7E0eyO4B2UaHBBN55tnppwRnaE3KFfh3Ps9HhnAkar3Cb69kUCJY9as8LrccVYKgHA+JY5dOQqJLOPhF5A==}
-
- '@motionone/easing@10.18.0':
- resolution: {integrity: sha512-VcjByo7XpdLS4o9T8t99JtgxkdMcNWD3yHU/n6CLEz3bkmKDRZyYQ/wmSf6daum8ZXqfUAgFeCZSpJZIMxaCzg==}
-
- '@motionone/generators@10.18.0':
- resolution: {integrity: sha512-+qfkC2DtkDj4tHPu+AFKVfR/C30O1vYdvsGYaR13W/1cczPrrcjdvYCj0VLFuRMN+lP1xvpNZHCRNM4fBzn1jg==}
-
- '@motionone/types@10.17.1':
- resolution: {integrity: sha512-KaC4kgiODDz8hswCrS0btrVrzyU2CSQKO7Ps90ibBVSQmjkrt2teqta6/sOG59v7+dPnKMAg13jyqtMKV2yJ7A==}
-
- '@motionone/utils@10.18.0':
- resolution: {integrity: sha512-3XVF7sgyTSI2KWvTf6uLlBJ5iAgRgmvp3bpuOiQJvInd4nZ19ET8lX5unn30SlmRH7hXbBbH+Gxd0m0klJ3Xtw==}
-
'@napi-rs/pinyin-android-arm-eabi@1.7.5':
resolution: {integrity: sha512-dnurqJdedbU8D1Ngudf10nXvc4BbVSe4ki9U2LUZoGMDGa069t4c87BHRXvcy2By3YpOozORv9/QTMxAQFVOLg==}
engines: {node: '>= 10.0'}
@@ -3998,9 +3974,6 @@ packages:
resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==}
engines: {node: '>= 0.4'}
- hey-listen@1.0.8:
- resolution: {integrity: sha512-COpmrF2NOg4TBWUJ5UVyaCU2A88wEMkUPK4hNqyCkqHbxT92BbvfjoSozkAIIm6XhicGlJHhFdullInrdhwU8Q==}
-
hookable@5.5.3:
resolution: {integrity: sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ==}
@@ -4635,9 +4608,6 @@ packages:
mockdate@3.0.5:
resolution: {integrity: sha512-iniQP4rj1FhBdBYS/+eQv7j1tadJ9lJtdzgOpvsOHng/GbcDh2Fhdeq+ZRldrPYdXvCyfFUmFeEwEGXZB5I/AQ==}
- motion@10.18.0:
- resolution: {integrity: sha512-MVAZZmwM/cp77BrNe1TxTMldxRPjwBNHheU5aPToqT4rJdZxLiADk58H+a0al5jKLxkB0OdgNq6DiVn11cjvIQ==}
-
mri@1.2.0:
resolution: {integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==}
engines: {node: '>=4'}
@@ -4804,12 +4774,6 @@ packages:
resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==}
engines: {node: '>= 0.8.0'}
- overlayscrollbars-react@0.5.6:
- resolution: {integrity: sha512-E5To04bL5brn9GVCZ36SnfGanxa2I2MDkWoa4Cjo5wol7l+diAgi4DBc983V7l2nOk/OLJ6Feg4kySspQEGDBw==}
- peerDependencies:
- overlayscrollbars: ^2.0.0
- react: '>=16.8.0'
-
overlayscrollbars@2.10.0:
resolution: {integrity: sha512-diNMeEafWTE0A4GJfwRpdBp2rE/BEvrhptBdBcDu8/UeytWcdCy9Td8tZWnztJeJ26f8/uHCWfPnPUC/dtgJdw==}
@@ -7569,41 +7533,6 @@ snapshots:
- encoding
- supports-color
- '@motionone/animation@10.18.0':
- dependencies:
- '@motionone/easing': 10.18.0
- '@motionone/types': 10.17.1
- '@motionone/utils': 10.18.0
- tslib: 2.8.0
-
- '@motionone/dom@10.18.0':
- dependencies:
- '@motionone/animation': 10.18.0
- '@motionone/generators': 10.18.0
- '@motionone/types': 10.17.1
- '@motionone/utils': 10.18.0
- hey-listen: 1.0.8
- tslib: 2.8.0
-
- '@motionone/easing@10.18.0':
- dependencies:
- '@motionone/utils': 10.18.0
- tslib: 2.8.0
-
- '@motionone/generators@10.18.0':
- dependencies:
- '@motionone/types': 10.17.1
- '@motionone/utils': 10.18.0
- tslib: 2.8.0
-
- '@motionone/types@10.17.1': {}
-
- '@motionone/utils@10.18.0':
- dependencies:
- '@motionone/types': 10.17.1
- hey-listen: 1.0.8
- tslib: 2.8.0
-
'@napi-rs/pinyin-android-arm-eabi@1.7.5':
optional: true
@@ -10427,8 +10356,6 @@ snapshots:
dependencies:
function-bind: 1.1.2
- hey-listen@1.0.8: {}
-
hookable@5.5.3: {}
hosted-git-info@2.8.9: {}
@@ -11045,13 +10972,6 @@ snapshots:
mockdate@3.0.5: {}
- motion@10.18.0:
- dependencies:
- '@motionone/animation': 10.18.0
- '@motionone/dom': 10.18.0
- '@motionone/types': 10.17.1
- '@motionone/utils': 10.18.0
-
mri@1.2.0: {}
mrmime@2.0.0: {}
@@ -11303,11 +11223,6 @@ snapshots:
type-check: 0.4.0
word-wrap: 1.2.5
- overlayscrollbars-react@0.5.6(overlayscrollbars@2.10.0)(react@18.3.1):
- dependencies:
- overlayscrollbars: 2.10.0
- react: 18.3.1
-
overlayscrollbars@2.10.0: {}
p-limit@2.3.0:
diff --git a/src/components/column/card.tsx b/src/components/column/card.tsx
index 74ecbfa..9274292 100644
--- a/src/components/column/card.tsx
+++ b/src/components/column/card.tsx
@@ -159,7 +159,7 @@ function NewsCard({ id, setHandleRef }: NewsCardProps) {
options={{
overflow: { x: "hidden" },
}}
- defer={false}
+ defer
>
{!!data?.items?.length && (sources[id].type === "hottest" ?
:
)}
diff --git a/src/components/common/overlay-scrollbar.tsx b/src/components/common/overlay-scrollbar/index.tsx
similarity index 65%
rename from src/components/common/overlay-scrollbar.tsx
rename to src/components/common/overlay-scrollbar/index.tsx
index 9515a35..789d7cc 100644
--- a/src/components/common/overlay-scrollbar.tsx
+++ b/src/components/common/overlay-scrollbar/index.tsx
@@ -1,9 +1,10 @@
-import type { UseOverlayScrollbarsParams } from "overlayscrollbars-react"
-import { useOverlayScrollbars } from "overlayscrollbars-react"
import type { HTMLProps, PropsWithChildren } from "react"
import { defu } from "defu"
import { useMount } from "react-use"
+import { useOverlayScrollbars } from "./useOverlayScrollbars"
+import type { UseOverlayScrollbarsParams } from "./useOverlayScrollbars"
import { goToTopAtom } from "~/atoms"
+import "./style.css"
type Props = HTMLProps
& UseOverlayScrollbarsParams
const defaultScrollbarParams: UseOverlayScrollbarsParams = {
@@ -15,7 +16,7 @@ const defaultScrollbarParams: UseOverlayScrollbarsParams = {
defer: true,
}
-export function OverlayScrollbar({ disabled, children, options, events, defer, ...props }: PropsWithChildren) {
+export function OverlayScrollbar({ disabled, children, options, events, defer, className, ...props }: PropsWithChildren) {
const ref = useRef(null)
const scrollbarParams = useMemo(() => defu >({
options,
@@ -23,7 +24,7 @@ export function OverlayScrollbar({ disabled, children, options, events, defer, .
defer,
}, defaultScrollbarParams), [options, events, defer])
- const [initialize] = useOverlayScrollbars(scrollbarParams)
+ const [initialize, instance] = useOverlayScrollbars(scrollbarParams)
useMount(() => {
if (!disabled) {
@@ -37,15 +38,25 @@ export function OverlayScrollbar({ disabled, children, options, events, defer, .
}
})
+ useEffect(() => {
+ if (ref.current) {
+ if (instance && instance?.state().destroyed) {
+ ref.current.classList.remove("scrollbar-hidden")
+ } else {
+ ref.current.classList.add("scrollbar-hidden")
+ }
+ }
+ }, [instance])
+
return (
-
+
{/* 只能有一个 element */}
{children}
)
}
-export function GlobalOverlayScrollbar({ children, ...props }: PropsWithChildren
>) {
+export function GlobalOverlayScrollbar({ children, className, ...props }: PropsWithChildren>) {
const ref = useRef(null)
const lastTrigger = useRef(0)
const timer = useRef()
@@ -67,7 +78,7 @@ export function GlobalOverlayScrollbar({ children, ...props }: PropsWithChildren
)
}
}, [setGoToTop])
- const [initialize] = useOverlayScrollbars({
+ const [initialize, instance] = useOverlayScrollbars({
options: {
scrollbars: {
autoHide: "scroll",
@@ -76,7 +87,7 @@ export function GlobalOverlayScrollbar({ children, ...props }: PropsWithChildren
events: {
scroll: (_, e) => onScroll(e),
},
- defer: false,
+ defer: true,
})
useMount(() => {
@@ -95,8 +106,18 @@ export function GlobalOverlayScrollbar({ children, ...props }: PropsWithChildren
}
})
+ useEffect(() => {
+ if (ref.current) {
+ if (instance && instance?.state().destroyed) {
+ ref.current.classList.remove("scrollbar-hidden")
+ } else {
+ ref.current?.classList.add("scrollbar-hidden")
+ }
+ }
+ }, [instance])
+
return (
-
+
)
diff --git a/src/components/common/overlay-scrollbar/style.css b/src/components/common/overlay-scrollbar/style.css
new file mode 100644
index 0000000..d02a465
--- /dev/null
+++ b/src/components/common/overlay-scrollbar/style.css
@@ -0,0 +1,12 @@
+::-webkit-scrollbar-thumb {
+ border-radius: 8px;
+ -webkit-border-radius: 8px;
+}
+
+.scrollbar-hidden {
+ scrollbar-width: none;
+}
+.scrollbar-hidden::-webkit-scrollbar {
+ width: 0px;
+ height: 0px;
+}
\ No newline at end of file
diff --git a/src/components/common/overlay-scrollbar/useOverlayScrollbars.ts b/src/components/common/overlay-scrollbar/useOverlayScrollbars.ts
new file mode 100644
index 0000000..b0890a8
--- /dev/null
+++ b/src/components/common/overlay-scrollbar/useOverlayScrollbars.ts
@@ -0,0 +1,152 @@
+import type { ComponentPropsWithoutRef, ElementRef, ElementType, ForwardedRef } from "react"
+import { useEffect, useMemo, useRef } from "react"
+import { OverlayScrollbars } from "overlayscrollbars"
+import type { EventListeners, InitializationTarget, PartialOptions } from "overlayscrollbars"
+
+type OverlayScrollbarsComponentBaseProps
=
+ ComponentPropsWithoutRef & {
+ /** Tag of the root element. */
+ element?: T
+ /** OverlayScrollbars options. */
+ options?: PartialOptions | false | null
+ /** OverlayScrollbars events. */
+ events?: EventListeners | false | null
+ /** Whether to defer the initialization to a point in time when the browser is idle. (or to the next frame if `window.requestIdleCallback` is not supported) */
+ defer?: boolean | IdleRequestOptions
+ }
+
+type OverlayScrollbarsComponentProps =
+ OverlayScrollbarsComponentBaseProps & {
+ ref?: ForwardedRef>
+ }
+
+interface OverlayScrollbarsComponentRef {
+ /** Returns the OverlayScrollbars instance or null if not initialized. */
+ osInstance: () => OverlayScrollbars | null
+ /** Returns the root element. */
+ getElement: () => ElementRef | null
+}
+
+type Defer = [
+ requestDefer: (callback: () => any, options?: OverlayScrollbarsComponentProps["defer"]) => void,
+ cancelDefer: () => void,
+]
+
+export interface UseOverlayScrollbarsParams {
+ /** OverlayScrollbars options. */
+ options?: OverlayScrollbarsComponentProps["options"]
+ /** OverlayScrollbars events. */
+ events?: OverlayScrollbarsComponentProps["events"]
+ /** Whether to defer the initialization to a point in time when the browser is idle. (or to the next frame if `window.requestIdleCallback` is not supported) */
+ defer?: OverlayScrollbarsComponentProps["defer"]
+}
+
+export type UseOverlayScrollbarsInitialization = (target: InitializationTarget) => void
+
+export type UseOverlayScrollbarsInstance = () => ReturnType<
+ OverlayScrollbarsComponentRef["osInstance"]
+>
+
+function createDefer(): Defer {
+ let idleId: number
+ let rafId: number
+ const wnd = window
+ const idleSupported = typeof wnd.requestIdleCallback === "function"
+ const rAF = wnd.requestAnimationFrame
+ const cAF = wnd.cancelAnimationFrame
+ const rIdle = idleSupported ? wnd.requestIdleCallback : rAF
+ const cIdle = idleSupported ? wnd.cancelIdleCallback : cAF
+ const clear = () => {
+ cIdle(idleId)
+ cAF(rafId)
+ }
+
+ return [
+ (callback, options) => {
+ clear()
+ idleId = rIdle(
+ idleSupported
+ ? () => {
+ clear()
+ // inside idle its best practice to use rAF to change DOM for best performance
+ rafId = rAF(callback)
+ }
+ : callback,
+ typeof options === "object" ? options : { timeout: 2233 },
+ )
+ },
+ clear,
+ ]
+}
+
+/**
+ * Hook for advanced usage of OverlayScrollbars. (When the OverlayScrollbarsComponent is not enough)
+ * @param params Parameters for customization.
+ * @returns A tuple with two values:
+ * The first value is the initialization function, it takes one argument which is the `InitializationTarget`.
+ * The second value is a function which returns the current OverlayScrollbars instance or `null` if not initialized.
+ */
+export function useOverlayScrollbars(params?: UseOverlayScrollbarsParams): [UseOverlayScrollbarsInitialization, OverlayScrollbars | null ] {
+ const { options, events, defer } = params || {}
+ const [requestDefer, cancelDefer] = useMemo(createDefer, [])
+ // const instanceRef = useRef>(null)
+ const [instance, setInstance] = useState>(null)
+ const deferRef = useRef(defer)
+ const optionsRef = useRef(options)
+ const eventsRef = useRef(events)
+
+ useEffect(() => {
+ deferRef.current = defer
+ }, [defer])
+
+ useEffect(() => {
+ optionsRef.current = options
+
+ if (OverlayScrollbars.valid(instance)) {
+ instance.options(options || {}, true)
+ }
+ }, [options, instance])
+
+ useEffect(() => {
+ eventsRef.current = events
+
+ if (OverlayScrollbars.valid(instance)) {
+ instance.on(events || {}, true)
+ }
+ }, [events, instance])
+
+ useEffect(
+ () => () => {
+ cancelDefer()
+ instance?.destroy()
+ },
+ [cancelDefer, instance, setInstance],
+ )
+
+ return useMemo(
+ () => [
+ (target) => {
+ // if already initialized do nothing
+ const presentInstance = instance
+ if (OverlayScrollbars.valid(presentInstance)) {
+ return
+ }
+
+ const currDefer = deferRef.current
+ const currOptions = optionsRef.current || {}
+ const currEvents = eventsRef.current || {}
+ const init = () => {
+ setInstance(OverlayScrollbars(target, currOptions, currEvents))
+ }
+
+ if (currDefer) {
+ requestDefer(init, currDefer)
+ } else {
+ init()
+ }
+ },
+ instance,
+ ],
+ [instance, requestDefer],
+ )
+}
diff --git a/src/components/common/search-bar/index.tsx b/src/components/common/search-bar/index.tsx
index 58a7a1d..daf125d 100644
--- a/src/components/common/search-bar/index.tsx
+++ b/src/components/common/search-bar/index.tsx
@@ -86,7 +86,7 @@ export function SearchBar() {
placeholder="搜索你想要的"
/>
-
+
没有找到,可以前往 Github 提 issue
{
diff --git a/vite.config.ts b/vite.config.ts
index f06e6a4..165dcbd 100644
--- a/vite.config.ts
+++ b/vite.config.ts
@@ -4,13 +4,14 @@ import react from "@vitejs/plugin-react-swc"
import { TanStackRouterVite } from "@tanstack/router-plugin/vite"
import unocss from "unocss/vite"
import unimport from "unimport/unplugin"
+import dotenv from "dotenv"
import nitro from "./nitro.config"
import { projectDir } from "./shared/dir"
import pwa from "./pwa.config"
-// dotenv.config({
-// path: join(projectDir, ".env.server"),
-// })
+dotenv.config({
+ path: join(projectDir, ".env.server"),
+})
export default defineConfig({
resolve: {