From 2939566a4259e6824a6135e859fd5a82727163ad Mon Sep 17 00:00:00 2001 From: czhen <56986964+shczhen@users.noreply.github.com> Date: Thu, 12 Dec 2024 16:37:57 +0800 Subject: [PATCH] fix(demo): header components (#473) * refine header * feat: support gh stars --- demo/package.json | 1 + demo/pnpm-lock.yaml | 14 ++ demo/src/app/layout.tsx | 11 +- demo/src/common/constant.ts | 5 +- demo/src/components/Icon/index.tsx | 16 +++ demo/src/components/Layout/Header.tsx | 9 +- .../components/Layout/HeaderComponents.tsx | 112 +++++++++++----- demo/src/hooks/index.ts | 32 +++++ demo/src/lib/utils.ts | 14 ++ demo/tailwind.config.js | 123 +++++++++--------- 10 files changed, 239 insertions(+), 98 deletions(-) create mode 100644 demo/src/hooks/index.ts diff --git a/demo/package.json b/demo/package.json index 32c6ff3e..f188385a 100644 --- a/demo/package.json +++ b/demo/package.json @@ -40,6 +40,7 @@ "react-redux": "^9.1.0", "redux": "^5.0.1", "sonner": "^1.5.0", + "swr": "^2.2.5", "tailwind-merge": "^2.5.4", "tailwindcss-animate": "^1.0.7", "zod": "^3.23.8" diff --git a/demo/pnpm-lock.yaml b/demo/pnpm-lock.yaml index 682d7d70..0e39c477 100644 --- a/demo/pnpm-lock.yaml +++ b/demo/pnpm-lock.yaml @@ -89,6 +89,9 @@ importers: sonner: specifier: ^1.5.0 version: 1.7.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + swr: + specifier: ^2.2.5 + version: 2.2.5(react@18.3.1) tailwind-merge: specifier: ^2.5.4 version: 2.5.4 @@ -3420,6 +3423,11 @@ packages: engines: {node: '>=14.0.0'} hasBin: true + swr@2.2.5: + resolution: {integrity: sha512-QtxqyclFeAsxEUeZIYmsaQ0UjimSq1RZ9Un7I68/0ClKK/U3LoyQunwkQfJZr2fc22DfIXLNDc2wFyTEikCUpg==} + peerDependencies: + react: ^16.11.0 || ^17.0.0 || ^18.0.0 + tailwind-merge@2.5.4: resolution: {integrity: sha512-0q8cfZHMu9nuYP/b5Shb7Y7Sh1B7Nnl5GqNr1U+n2p6+mybvRtayrQ+0042Z5byvTA8ihjlP8Odo8/VnHbZu4Q==} @@ -7280,6 +7288,12 @@ snapshots: csso: 5.0.5 picocolors: 1.1.1 + swr@2.2.5(react@18.3.1): + dependencies: + client-only: 0.0.1 + react: 18.3.1 + use-sync-external-store: 1.2.2(react@18.3.1) + tailwind-merge@2.5.4: {} tailwindcss-animate@1.0.7(tailwindcss@3.4.14): diff --git a/demo/src/app/layout.tsx b/demo/src/app/layout.tsx index cd55cb51..ef93328f 100644 --- a/demo/src/app/layout.tsx +++ b/demo/src/app/layout.tsx @@ -2,6 +2,15 @@ import { StoreProvider } from "@/store" import type { Metadata, Viewport } from "next" import "./global.css" import { Toaster } from "@/components/ui/sonner" +import { Roboto } from "next/font/google" +import { cn } from "@/lib/utils" + +const roboto = Roboto({ + subsets: ["latin"], + weight: ["400", "700"], + variable: "--font-roboto", + display: "swap", +}) export const metadata: Metadata = { title: "TEN Agent", @@ -29,7 +38,7 @@ export default function RootLayout({ }>) { return ( - + {/* ) { + return ( + + + + ) +} + export const GitHubIcon = (props: React.SVGProps) => { return (
+ {/* */}

TEN Agent

- diff --git a/demo/src/components/Layout/HeaderComponents.tsx b/demo/src/components/Layout/HeaderComponents.tsx index 31baa6f6..d643284e 100644 --- a/demo/src/components/Layout/HeaderComponents.tsx +++ b/demo/src/components/Layout/HeaderComponents.tsx @@ -13,61 +13,76 @@ import { PopoverContent, PopoverTrigger, } from "@/components/ui/popover" -import { InfoIcon, GitHubIcon, PaletteIcon } from "@/components/Icon" +import { Button } from "@/components/ui/button" +import { GitHubIcon, PaletteIcon } from "@/components/Icon" import { useAppSelector, useAppDispatch, GITHUB_URL, COLOR_LIST, + // getRandomUserId, + // getRandomChannel, + // genRandomString, + API_GH_GET_REPO_INFO, } from "@/common" -import { setThemeColor } from "@/store/reducers/global" +import { setThemeColor, setOptions } from "@/store/reducers/global" import { cn } from "@/lib/utils" import { HexColorPicker } from "react-colorful" import dynamic from "next/dynamic" +import { useCancelableSWR } from "@/hooks" +import { formatNumber } from "@/lib/utils" import styles from "./Header.module.css" export function HeaderRoomInfo() { + const dispatch = useAppDispatch() + const options = useAppSelector((state) => state.global.options) const { channel, userId } = options const roomConnected = useAppSelector((state) => state.global.roomConnected) const agentConnected = useAppSelector((state) => state.global.agentConnected) - const roomConnectedText = React.useMemo(() => { - return roomConnected ? "TRUE" : "FALSE" - }, [roomConnected]) - - const agentConnectedText = React.useMemo(() => { - return agentConnected ? "TRUE" : "FALSE" - }, [agentConnected]) + // const handleRegenerateChannelAndUserId = () => { + // const newOptions = { + // userName: genRandomString(8), + // channel: getRandomChannel(), + // userId: getRandomUserId(), + // } + // dispatch(setOptions(newOptions)) + // } return ( <> - - - - Channel Name:{" "} - - - {channel} - + + {channel} - + - + {/* - - + + */} - + - + @@ -81,12 +96,16 @@ export function HeaderRoomInfo() { - - + + - - + +
INFO
+ +
Room:ChannelName {channel}
Participant:UserID {userId}
Room connected:{roomConnectedText}Room + {roomConnected ? "Connected" : "Disconnected"} +
Agent connected:{agentConnectedText}Agent + {agentConnected ? "Connected" : "Disconnected"} +
@@ -100,12 +119,14 @@ export function HeaderRoomInfo() { export function HeaderActions() { return (
- + {/* GitHub - - - + */} + + + {/* + */}
) } @@ -203,3 +224,32 @@ const NetworkIndicator = dynamic( ssr: false, }, ) + +export const GitHubStar = () => { + const [{ data, error, isLoading }] = useCancelableSWR<{ + stargazers_count: number + }>(API_GH_GET_REPO_INFO, { + refreshInterval: 1000 * 60 * 60, // 1 hour + revalidateOnFocus: false, + revalidateOnReconnect: false, + }) + + const starsCntMemo = React.useMemo(() => { + if (!data || !data.stargazers_count) return null + return formatNumber(data?.stargazers_count || 0) + }, [data?.stargazers_count]) + + return ( + + ) +} diff --git a/demo/src/hooks/index.ts b/demo/src/hooks/index.ts new file mode 100644 index 00000000..da276f85 --- /dev/null +++ b/demo/src/hooks/index.ts @@ -0,0 +1,32 @@ +"use client" + +import { type SWRResponse, type SWRConfiguration } from "swr" +import useSWR from "swr" + +// https://github.com/vercel/swr/discussions/2330#discussioncomment-4460054 +export function useCancelableSWR( + key: string, + opts?: SWRConfiguration, +): [SWRResponse, AbortController] { + const controller = new AbortController() + return [ + useSWR( + key, + (url: string) => + fetch(url, { signal: controller.signal }).then((res) => res.json()), + { + // revalidateOnFocus: false, + errorRetryCount: 3, + refreshInterval: 1000 * 60, + // dedupingInterval: 30000, + // focusThrottleInterval: 60000, + ...opts, + }, + ), + controller, + ] + // to use it: + // const [{ data }, controller] = useCancelableSWR('/api') + // ... + // controller.abort() +} diff --git a/demo/src/lib/utils.ts b/demo/src/lib/utils.ts index ca1ebd17..ea9cc4bf 100644 --- a/demo/src/lib/utils.ts +++ b/demo/src/lib/utils.ts @@ -20,3 +20,17 @@ export function useIsMobileScreen(breakpoint?: string) { return isMobileScreen } + +export function formatNumber(num: number, decimals: number = 1): string { + if (num === 0) return "0" + + const k = 1000 + const sizes = ["", "K", "M", "B", "T"] + + const i = Math.floor(Math.log(Math.abs(num)) / Math.log(k)) + + if (i === 0) return num.toString() + + const scaled = num / Math.pow(k, i) + return `${scaled.toFixed(decimals)}${sizes[i]}` +} diff --git a/demo/tailwind.config.js b/demo/tailwind.config.js index cd5427f0..fe9112cb 100644 --- a/demo/tailwind.config.js +++ b/demo/tailwind.config.js @@ -1,64 +1,67 @@ /** @type {import('tailwindcss').Config} */ module.exports = { - darkMode: ["class"], - content: [ - "./app/**/*.{js,ts,jsx,tsx,mdx}", - "./pages/**/*.{js,ts,jsx,tsx,mdx}", - "./components/**/*.{js,ts,jsx,tsx,mdx}", + darkMode: ["class"], + content: [ + "./app/**/*.{js,ts,jsx,tsx,mdx}", + "./pages/**/*.{js,ts,jsx,tsx,mdx}", + "./components/**/*.{js,ts,jsx,tsx,mdx}", - // Or if using `src` directory: - "./src/**/*.{js,ts,jsx,tsx,mdx}", - ], - theme: { - extend: { - borderRadius: { - lg: 'var(--radius)', - md: 'calc(var(--radius) - 2px)', - sm: 'calc(var(--radius) - 4px)' - }, - colors: { - background: 'hsl(var(--background))', - foreground: 'hsl(var(--foreground))', - card: { - DEFAULT: 'hsl(var(--card))', - foreground: 'hsl(var(--card-foreground))' - }, - popover: { - DEFAULT: 'hsl(var(--popover))', - foreground: 'hsl(var(--popover-foreground))' - }, - primary: { - DEFAULT: 'hsl(var(--primary))', - foreground: 'hsl(var(--primary-foreground))' - }, - secondary: { - DEFAULT: 'hsl(var(--secondary))', - foreground: 'hsl(var(--secondary-foreground))' - }, - muted: { - DEFAULT: 'hsl(var(--muted))', - foreground: 'hsl(var(--muted-foreground))' - }, - accent: { - DEFAULT: 'hsl(var(--accent))', - foreground: 'hsl(var(--accent-foreground))' - }, - destructive: { - DEFAULT: 'hsl(var(--destructive))', - foreground: 'hsl(var(--destructive-foreground))' - }, - border: 'hsl(var(--border))', - input: 'hsl(var(--input))', - ring: 'hsl(var(--ring))', - chart: { - '1': 'hsl(var(--chart-1))', - '2': 'hsl(var(--chart-2))', - '3': 'hsl(var(--chart-3))', - '4': 'hsl(var(--chart-4))', - '5': 'hsl(var(--chart-5))' - } - } - } + // Or if using `src` directory: + "./src/**/*.{js,ts,jsx,tsx,mdx}", + ], + theme: { + extend: { + borderRadius: { + lg: "var(--radius)", + md: "calc(var(--radius) - 2px)", + sm: "calc(var(--radius) - 4px)", + }, + colors: { + background: "hsl(var(--background))", + foreground: "hsl(var(--foreground))", + card: { + DEFAULT: "hsl(var(--card))", + foreground: "hsl(var(--card-foreground))", + }, + popover: { + DEFAULT: "hsl(var(--popover))", + foreground: "hsl(var(--popover-foreground))", + }, + primary: { + DEFAULT: "hsl(var(--primary))", + foreground: "hsl(var(--primary-foreground))", + }, + secondary: { + DEFAULT: "hsl(var(--secondary))", + foreground: "hsl(var(--secondary-foreground))", + }, + muted: { + DEFAULT: "hsl(var(--muted))", + foreground: "hsl(var(--muted-foreground))", + }, + accent: { + DEFAULT: "hsl(var(--accent))", + foreground: "hsl(var(--accent-foreground))", + }, + destructive: { + DEFAULT: "hsl(var(--destructive))", + foreground: "hsl(var(--destructive-foreground))", + }, + border: "hsl(var(--border))", + input: "hsl(var(--input))", + ring: "hsl(var(--ring))", + chart: { + 1: "hsl(var(--chart-1))", + 2: "hsl(var(--chart-2))", + 3: "hsl(var(--chart-3))", + 4: "hsl(var(--chart-4))", + 5: "hsl(var(--chart-5))", + }, + }, + fontFamily: { + roboto: "var(--font-roboto)", + }, }, - plugins: [require("tailwindcss-animate")], -}; + }, + plugins: [require("tailwindcss-animate")], +}