From 179358c919a8e25d26d9aa62361238412a57dd9d Mon Sep 17 00:00:00 2001
From: Ou
Date: Sat, 19 Oct 2024 13:15:29 +0800
Subject: [PATCH] feat: ui
---
src/components/column/dnd.tsx | 6 +-
src/components/column/index.tsx | 24 ++++--
src/components/column/navbar.tsx | 33 -------
src/components/common/toast.tsx | 35 ++++++++
.../{header.tsx => header/index.tsx} | 82 ++++--------------
src/components/header/menu.tsx | 85 +++++++++++++++++++
src/components/navbar.tsx | 30 +++++++
src/hooks/useDark.ts | 4 +-
src/hooks/useOnReload.ts | 8 +-
src/routes/index.tsx | 8 +-
src/styles/globals.css | 4 +
11 files changed, 196 insertions(+), 123 deletions(-)
delete mode 100644 src/components/column/navbar.tsx
create mode 100644 src/components/common/toast.tsx
rename src/components/{header.tsx => header/index.tsx} (53%)
create mode 100644 src/components/header/menu.tsx
create mode 100644 src/components/navbar.tsx
diff --git a/src/components/column/dnd.tsx b/src/components/column/dnd.tsx
index 6478785..f026b18 100644
--- a/src/components/column/dnd.tsx
+++ b/src/components/column/dnd.tsx
@@ -36,9 +36,13 @@ export function Dnd() {
initial="hidden"
animate="visible"
variants={{
+ hidden: {
+ opacity: 0,
+ },
visible: {
+ opacity: 1,
transition: {
- delayChildren: 0.2,
+ delayChildren: 0.1,
staggerChildren: 0.1,
},
},
diff --git a/src/components/column/index.tsx b/src/components/column/index.tsx
index 9bc96fe..e0c69d8 100644
--- a/src/components/column/index.tsx
+++ b/src/components/column/index.tsx
@@ -1,8 +1,10 @@
import type { ColumnID } from "@shared/types"
import { useAtom } from "jotai"
import { useEffect } from "react"
+import { useTitle } from "react-use"
+import { metadata } from "@shared/metadata"
+import { NavBar } from "../navbar"
import { Dnd } from "./dnd"
-import { NavBar } from "./navbar"
import { currentColumnIDAtom } from "~/atoms"
export function Column({ id }: { id: ColumnID }) {
@@ -10,10 +12,18 @@ export function Column({ id }: { id: ColumnID }) {
useEffect(() => {
setCurrentColumnID(id)
}, [id, setCurrentColumnID])
- return (
- <>
-
- { currentColumnID === id && }
- >
- )
+
+ useTitle(`NewsNow | ${metadata[id].name}`)
+ if (id === currentColumnID) {
+ return (
+ <>
+
+
+
+
+
+
+ >
+ )
+ }
}
diff --git a/src/components/column/navbar.tsx b/src/components/column/navbar.tsx
deleted file mode 100644
index f14536b..0000000
--- a/src/components/column/navbar.tsx
+++ /dev/null
@@ -1,33 +0,0 @@
-import { columnIds, metadata } from "@shared/metadata"
-import type { ColumnID } from "@shared/types"
-import { Link } from "@tanstack/react-router"
-import clsx from "clsx"
-import { useTitle } from "react-use"
-
-export function NavBar({ id }: { id: ColumnID }) {
- useTitle(`NewsNow | ${metadata[id].name}`)
- return (
-
-
- {columnIds.map(columnId => (
-
- {metadata[columnId].name}
-
- ))}
-
-
- )
-}
diff --git a/src/components/common/toast.tsx b/src/components/common/toast.tsx
new file mode 100644
index 0000000..bb7f905
--- /dev/null
+++ b/src/components/common/toast.tsx
@@ -0,0 +1,35 @@
+import clsx from "clsx"
+import { Toaster } from "sonner"
+
+export function Toast() {
+ return (
+
+ )
+}
diff --git a/src/components/header.tsx b/src/components/header/index.tsx
similarity index 53%
rename from src/components/header.tsx
rename to src/components/header/index.tsx
index c48e427..906d084 100644
--- a/src/components/header.tsx
+++ b/src/components/header/index.tsx
@@ -5,76 +5,23 @@ import { useIsFetching } from "@tanstack/react-query"
import clsx from "clsx"
import type { SourceID } from "@shared/types"
import { Homepage, Version } from "@shared/consts"
-import { useLocalStorage } from "react-use"
-import { useDark } from "~/hooks/useDark"
+import { NavBar } from "../navbar"
+import { Menu } from "./menu"
import { currentSourcesAtom, goToTopAtom, refetchSourcesAtom } from "~/atoms"
-function ThemeToggle() {
- const { toggleDark } = useDark()
- return (
-
- )
-}
-
-function LoginIn() {
- // useLocalStorage 默认会自动序列化
- const [info] = useLocalStorage<{ name: string, avatar: string }>("user_info")
- const [jwt, _setJwt] = useLocalStorage("user_jwt", undefined, {
- raw: true,
- })
- if (jwt) {
- return (
-
- )
- }
- return (
-
- )
-}
-
function GoTop() {
const { ok, fn: goToTop } = useAtomValue(goToTopAtom)
return (
- ok && (
-
- )
+
)
}
-export function GithubIcon() {
- return
-}
-function RefreshButton() {
+function Refresh() {
const currentSources = useAtomValue(currentSourcesAtom)
const setRefetchSource = useSetAtom(refetchSourcesAtom)
const refreshAll = useCallback(() => {
@@ -115,16 +62,17 @@ export function Header() {
-
+
{`v${Version}`}
+
+
+
-
-
-
- { __ENABLE_LOGIN__ && }
+
+
>
)
diff --git a/src/components/header/menu.tsx b/src/components/header/menu.tsx
new file mode 100644
index 0000000..869715b
--- /dev/null
+++ b/src/components/header/menu.tsx
@@ -0,0 +1,85 @@
+import { Homepage } from "@shared/consts"
+import clsx from "clsx"
+import { motion } from "framer-motion"
+import { useRef, useState } from "react"
+import { useClickAway } from "react-use"
+import { useDark } from "~/hooks/useDark"
+import { useLogin } from "~/hooks/useLogin"
+
+function ThemeToggle() {
+ const { isDark, toggleDark } = useDark()
+ return (
+
+
+
+ {isDark ? "黑暗模式" : "白天模式"}
+
+
+ )
+}
+
+export function Menu() {
+ const { loggedIn, login, logout, enabledLogin, userInfo } = useLogin()
+ const [shown, show] = useState(false)
+ const ref = useRef(null)
+ useClickAway(ref, () => {
+ show(false)
+ })
+ return (
+
+ show(!shown)}>
+ {
+ enabledLogin && loggedIn && userInfo.avatar
+ ? (
+
+ )
+ :
+ }
+
+ {shown && (
+
+ )}
+
+ )
+}
diff --git a/src/components/navbar.tsx b/src/components/navbar.tsx
new file mode 100644
index 0000000..e2b885e
--- /dev/null
+++ b/src/components/navbar.tsx
@@ -0,0 +1,30 @@
+import { columnIds, metadata } from "@shared/metadata"
+import { Link } from "@tanstack/react-router"
+import clsx from "clsx"
+import { useAtomValue } from "jotai"
+import { currentColumnIDAtom } from "~/atoms"
+
+export function NavBar() {
+ const currentId = useAtomValue(currentColumnIDAtom)
+ return (
+
+ {columnIds.map(columnId => (
+
+ {metadata[columnId].name}
+
+ ))}
+
+ )
+}
diff --git a/src/hooks/useDark.ts b/src/hooks/useDark.ts
index df45ab3..4e515a3 100644
--- a/src/hooks/useDark.ts
+++ b/src/hooks/useDark.ts
@@ -4,9 +4,7 @@ import { useLocalStorage, useMedia } from "react-use"
export declare type ColorScheme = "dark" | "light" | "auto"
export function useDark(key = "color-scheme", defaultColorScheme: ColorScheme = "auto") {
- const [colorScheme, setColorScheme] = useLocalStorage(key, defaultColorScheme, {
- raw: true,
- })
+ const [colorScheme, setColorScheme] = useLocalStorage(key, defaultColorScheme)
const prefersDarkMode = useMedia("(prefers-color-scheme: dark)")
const isDark = useMemo(() => colorScheme === "auto" ? prefersDarkMode : colorScheme === "dark", [colorScheme, prefersDarkMode])
diff --git a/src/hooks/useOnReload.ts b/src/hooks/useOnReload.ts
index 58aefb9..a9f8687 100644
--- a/src/hooks/useOnReload.ts
+++ b/src/hooks/useOnReload.ts
@@ -1,5 +1,4 @@
-import { useEffect } from "react"
-import { useBeforeUnload } from "react-use"
+import { useBeforeUnload, useMount } from "react-use"
export function useOnReload(fn?: () => Promise | void, fallback?: () => Promise | void) {
useBeforeUnload(() => {
@@ -7,7 +6,7 @@ export function useOnReload(fn?: () => Promise | void, fallback?: () => Pr
return false
})
- useEffect(() => {
+ useMount(() => {
const _ = localStorage.getItem("quitTime")
const quitTime = _ ? Number(_) : 0
if (!Number.isNaN(quitTime) && Date.now() - quitTime < 1000) {
@@ -15,6 +14,5 @@ export function useOnReload(fn?: () => Promise | void, fallback?: () => Pr
} else {
fallback?.()
}
- // eslint-disable-next-line react-hooks/exhaustive-deps
- }, [])
+ })
}
diff --git a/src/routes/index.tsx b/src/routes/index.tsx
index 999a648..86f6eb4 100644
--- a/src/routes/index.tsx
+++ b/src/routes/index.tsx
@@ -1,9 +1,7 @@
import { createFileRoute } from "@tanstack/react-router"
import { useAtomValue } from "jotai"
-import { useMemo } from "react"
import { focusSourcesAtom } from "~/atoms"
import { Column } from "~/components/column"
-import { } from "cookie-es"
export const Route = createFileRoute("/")({
component: IndexComponent,
@@ -11,9 +9,5 @@ export const Route = createFileRoute("/")({
function IndexComponent() {
const focusSources = useAtomValue(focusSourcesAtom)
- const id = useMemo(() => {
- return focusSources.length ? "focus" : "realtime"
- // eslint-disable-next-line react-hooks/exhaustive-deps
- }, [])
- return
+ return
}
diff --git a/src/styles/globals.css b/src/styles/globals.css
index 5c834b0..6fe3b2d 100644
--- a/src/styles/globals.css
+++ b/src/styles/globals.css
@@ -46,4 +46,8 @@ button:disabled {
*, a, button {
cursor: default;
user-select: none;
+}
+
+#dropdown-menu li {
+ --at-apply: hover:bg-neutral-400/10 rounded-md flex items-center p-1 gap-1;
}
\ No newline at end of file