From 7010756815d7593464cd9f601419ad4cffc430f2 Mon Sep 17 00:00:00 2001 From: czhen <56986964+shczhen@users.noreply.github.com> Date: Thu, 5 Dec 2024 11:54:18 +0800 Subject: [PATCH 1/2] refine header --- demo/src/app/layout.tsx | 11 +- demo/src/components/Icon/index.tsx | 16 +++ demo/src/components/Layout/Header.tsx | 9 +- .../components/Layout/HeaderComponents.tsx | 71 ++++++---- demo/tailwind.config.js | 123 +++++++++--------- 5 files changed, 142 insertions(+), 88 deletions(-) diff --git a/demo/src/app/layout.tsx b/demo/src/app/layout.tsx index cd55cb5113..ef93328f51 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 31baa6f6f5..ce46e439c5 100644 --- a/demo/src/components/Layout/HeaderComponents.tsx +++ b/demo/src/components/Layout/HeaderComponents.tsx @@ -13,14 +13,19 @@ 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 { MessagesSquareIcon, MessageSquareOffIcon } from "lucide-react" import { useAppSelector, useAppDispatch, GITHUB_URL, COLOR_LIST, + getRandomUserId, + getRandomChannel, + genRandomString, } 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" @@ -28,46 +33,61 @@ import dynamic from "next/dynamic" 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 +101,16 @@ export function HeaderRoomInfo() { - - + + - - + +
INFO + +
Room:ChannelName {channel}
Participant:UserID {userId}
Room connected:{roomConnectedText}Room Status + {roomConnected ? "Connected" : "Disconnected"} +
Agent connected:{agentConnectedText}Agent Status + {agentConnected ? "Connected" : "Disconnected"} +
@@ -104,8 +128,9 @@ export function HeaderActions() { GitHub - - + + {/* + */}
) } diff --git a/demo/tailwind.config.js b/demo/tailwind.config.js index cd5427f02d..fe9112cb57 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")], +} From 37d8226f1c6454600bda01bf1900022abe8b2bfd Mon Sep 17 00:00:00 2001 From: czhen <56986964+shczhen@users.noreply.github.com> Date: Thu, 12 Dec 2024 16:25:45 +0800 Subject: [PATCH 2/2] feat: support gh stars --- demo/package.json | 1 + demo/pnpm-lock.yaml | 14 ++++ demo/src/common/constant.ts | 5 +- demo/src/components/Layout/Header.tsx | 4 +- .../components/Layout/HeaderComponents.tsx | 79 ++++++++++++------- demo/src/hooks/index.ts | 32 ++++++++ demo/src/lib/utils.ts | 14 ++++ 7 files changed, 118 insertions(+), 31 deletions(-) create mode 100644 demo/src/hooks/index.ts diff --git a/demo/package.json b/demo/package.json index 32c6ff3e0b..f188385a33 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 682d7d7047..0e39c47717 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/common/constant.ts b/demo/src/common/constant.ts index f91b758717..e3d5886b0d 100644 --- a/demo/src/common/constant.ts +++ b/demo/src/common/constant.ts @@ -7,6 +7,8 @@ import { ICozeSettings, } from "@/types" export const GITHUB_URL = "https://github.com/TEN-framework/TEN-Agent" +export const API_GH_GET_REPO_INFO = + "https://api.github.com/repos/TEN-framework/TEN-Agent" export const OPTIONS_KEY = "__options__" export const AGENT_SETTINGS_KEY = "__agent_settings__" export const COZE_SETTINGS_KEY = "__coze_settings__" @@ -34,8 +36,7 @@ export const DEFAULT_COZE_SETTINGS: ICozeSettings = { base_url: ECozeBaseUrl.GLOBAL, } -export const DESCRIPTION = - "A Realtime Conversational AI Agent powered by TEN" +export const DESCRIPTION = "A Realtime Conversational AI Agent powered by TEN" export const LANGUAGE_OPTIONS: LanguageOptionItem[] = [ { label: "English", diff --git a/demo/src/components/Layout/Header.tsx b/demo/src/components/Layout/Header.tsx index 14fa900093..0292f46b03 100644 --- a/demo/src/components/Layout/Header.tsx +++ b/demo/src/components/Layout/Header.tsx @@ -10,11 +10,11 @@ export default function Header(props: { className?: string }) { {/* Header */}
-
+
{/* */} diff --git a/demo/src/components/Layout/HeaderComponents.tsx b/demo/src/components/Layout/HeaderComponents.tsx index ce46e439c5..d643284e12 100644 --- a/demo/src/components/Layout/HeaderComponents.tsx +++ b/demo/src/components/Layout/HeaderComponents.tsx @@ -15,20 +15,22 @@ import { } from "@/components/ui/popover" import { Button } from "@/components/ui/button" import { GitHubIcon, PaletteIcon } from "@/components/Icon" -import { MessagesSquareIcon, MessageSquareOffIcon } from "lucide-react" import { useAppSelector, useAppDispatch, GITHUB_URL, COLOR_LIST, - getRandomUserId, - getRandomChannel, - genRandomString, + // getRandomUserId, + // getRandomChannel, + // genRandomString, + API_GH_GET_REPO_INFO, } from "@/common" 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" @@ -41,28 +43,21 @@ export function HeaderRoomInfo() { const roomConnected = useAppSelector((state) => state.global.roomConnected) const agentConnected = useAppSelector((state) => state.global.agentConnected) - const handleRegenerateChannelAndUserId = () => { - const newOptions = { - userName: genRandomString(8), - channel: getRandomChannel(), - userId: getRandomUserId(), - } - dispatch(setOptions(newOptions)) - } + // const handleRegenerateChannelAndUserId = () => { + // const newOptions = { + // userName: genRandomString(8), + // channel: getRandomChannel(), + // userId: getRandomUserId(), + // } + // dispatch(setOptions(newOptions)) + // } return ( <> - - {channel ? ( - - ) : ( - - )} - - {channel} - + + {channel} - + {/* - + */} @@ -101,13 +96,13 @@ export function HeaderRoomInfo() { - + - + @@ -124,10 +119,11 @@ export function HeaderRoomInfo() { export function HeaderActions() { return (
- + {/* GitHub - + */} + {/* */} @@ -228,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 0000000000..da276f850c --- /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 ca1ebd17cf..ea9cc4bf80 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]}` +}
INFO
ChannelName {channel}
Room StatusRoom {roomConnected ? "Connected" : "Disconnected"}
Agent StatusAgent {agentConnected ? "Connected" : "Disconnected"}