diff --git a/app/src/assets/admin/all.less b/app/src/assets/admin/all.less index ba6094e..c55bcca 100644 --- a/app/src/assets/admin/all.less +++ b/app/src/assets/admin/all.less @@ -16,6 +16,14 @@ height: max-content; } +.admin-card { + border: 0 !important; + + @media (max-width: 768px) { + border-radius: 0 !important; + } +} + .object-id { display: flex; flex-direction: row; diff --git a/app/src/assets/admin/channel.less b/app/src/assets/admin/channel.less index 8dbd641..2e72986 100644 --- a/app/src/assets/admin/channel.less +++ b/app/src/assets/admin/channel.less @@ -17,6 +17,10 @@ border: 1px solid hsl(var(--border)); padding-bottom: 0.5rem; + .channel-id { + color: hsl(var(--text-secondary)); + } + &:hover { border-color: hsl(var(--border-hover)); } diff --git a/app/src/assets/admin/menu.less b/app/src/assets/admin/menu.less index 8e13b60..dbbe0d8 100644 --- a/app/src/assets/admin/menu.less +++ b/app/src/assets/admin/menu.less @@ -37,7 +37,7 @@ color: hsl(var(--text-secondary)); &:hover { - background: hsl(var(--card-hover)); + color: hsl(var(--text)); } &.active { @@ -54,12 +54,16 @@ } .menu-item-icon { - width: 1.5rem; - height: 1.5rem; - scale: 0.95; + width: 1.25rem; + height: 1.25rem; margin-right: 0.5rem; margin-left: 0.5rem; transform: translateY(1px); + + svg { + width: 1.25rem; + height: 1.25rem; + } } } diff --git a/app/src/assets/globals.less b/app/src/assets/globals.less index 934eb90..18bcf59 100644 --- a/app/src/assets/globals.less +++ b/app/src/assets/globals.less @@ -43,7 +43,7 @@ --text: 0 0% 0%; --text-dark: 0 0% 100%; - --text-secondary: 0 0% 20%; + --text-secondary: 0 0% 35%; --text-secondary-dark: 0 0% 80%; --selection: 212 100% 41%; diff --git a/app/src/components/admin/assemblies/ChannelTable.tsx b/app/src/components/admin/assemblies/ChannelTable.tsx index b748c16..994895c 100644 --- a/app/src/components/admin/assemblies/ChannelTable.tsx +++ b/app/src/components/admin/assemblies/ChannelTable.tsx @@ -81,7 +81,9 @@ function ChannelTable({ display, setId, setEnabled }: ChannelTableProps) { {(data || []).map((chan, idx) => ( - {chan.id} + + #{chan.id} + {chan.name} diff --git a/app/src/components/admin/assemblies/ModelChart.tsx b/app/src/components/admin/assemblies/ModelChart.tsx index bdc79d7..3c691e9 100644 --- a/app/src/components/admin/assemblies/ModelChart.tsx +++ b/app/src/components/admin/assemblies/ModelChart.tsx @@ -3,6 +3,7 @@ import { useMemo } from "react"; import { useTranslation } from "react-i18next"; import { getModelColor } from "@/admin/colors.ts"; import { Loader2 } from "lucide-react"; +import Tips from "@/components/Tips.tsx"; type ModelChartProps = { labels: string[]; @@ -70,7 +71,10 @@ function ModelChart({ labels, datasets, dark }: ModelChartProps) { return (

-

{t("admin.model-chart")}

+

+ {t("admin.model-chart")} + +

{labels.length === 0 && ( )} diff --git a/app/src/resources/i18n/cn.json b/app/src/resources/i18n/cn.json index fe3932c..fac635b 100644 --- a/app/src/resources/i18n/cn.json +++ b/app/src/resources/i18n/cn.json @@ -349,6 +349,7 @@ "subscription-users": "订阅用户", "seat": "位", "model-chart": "模型使用统计", + "model-chart-tip": "Token 用量", "request-chart": "请求量统计", "billing-chart": "收入统计", "error-chart": "错误统计", diff --git a/app/src/resources/i18n/en.json b/app/src/resources/i18n/en.json index 68802b0..6e30739 100644 --- a/app/src/resources/i18n/en.json +++ b/app/src/resources/i18n/en.json @@ -467,7 +467,8 @@ "custom-image": "Custom Image", "custom-image-placeholder": "Please enter an image link", "update": "Update" - } + }, + "model-chart-tip": "Token usage" }, "mask": { "title": "Mask Settings", diff --git a/app/src/resources/i18n/ja.json b/app/src/resources/i18n/ja.json index 0a69e85..431addc 100644 --- a/app/src/resources/i18n/ja.json +++ b/app/src/resources/i18n/ja.json @@ -467,7 +467,8 @@ "custom-image": "カスタム画像", "custom-image-placeholder": "画像リンクを入力してください", "update": "更新" - } + }, + "model-chart-tip": "トークンの使用状況" }, "mask": { "title": "プリセット設定", diff --git a/app/src/resources/i18n/ru.json b/app/src/resources/i18n/ru.json index 92d591b..3bbfe44 100644 --- a/app/src/resources/i18n/ru.json +++ b/app/src/resources/i18n/ru.json @@ -467,7 +467,8 @@ "custom-image": "Пользовательское изображение", "custom-image-placeholder": "Введите ссылку на изображение", "update": "Обновить" - } + }, + "model-chart-tip": "Использование токенов" }, "mask": { "title": "Настройки маски", diff --git a/app/src/router.tsx b/app/src/router.tsx index 65597cf..c9f2ead 100644 --- a/app/src/router.tsx +++ b/app/src/router.tsx @@ -13,7 +13,7 @@ import Register from "@/routes/Register.tsx"; import Forgot from "@/routes/Forgot.tsx"; import { lazyFactor } from "@/utils/loader.tsx"; import { useSelector } from "react-redux"; -import { selectAdmin, selectAuthenticated } from "@/store/auth.ts"; +import { selectAdmin, selectAuthenticated, selectInit } from "@/store/auth.ts"; const Generation = lazyFactor(() => import("@/routes/Generation.tsx")); const Sharing = lazyFactor(() => import("@/routes/Sharing.tsx")); @@ -183,43 +183,46 @@ const router = createBrowserRouter( ); export function AuthRequired({ children }: { children: React.ReactNode }) { + const init = useSelector(selectInit); const authenticated = useSelector(selectAuthenticated); const navigate = useNavigate(); const location = useLocation(); useEffect(() => { - if (!authenticated) { + if (init && !authenticated) { navigate("/login", { state: { from: location.pathname } }); } - }, [authenticated]); + }, [init, authenticated]); return <>{children}; } export function AuthForbidden({ children }: { children: React.ReactNode }) { + const init = useSelector(selectInit); const authenticated = useSelector(selectAuthenticated); const navigate = useNavigate(); const location = useLocation(); useEffect(() => { - if (authenticated) { + if (init && authenticated) { navigate("/", { state: { from: location.pathname } }); } - }, [authenticated]); + }, [init, authenticated]); return <>{children}; } export function AdminRequired({ children }: { children: React.ReactNode }) { + const init = useSelector(selectInit); const admin = useSelector(selectAdmin); const navigate = useNavigate(); const location = useLocation(); useEffect(() => { - if (!admin) { + if (init && !admin) { navigate("/", { state: { from: location.pathname } }); } - }, [admin]); + }, [init, admin]); return <>{children}; } diff --git a/app/src/routes/admin/Broadcast.tsx b/app/src/routes/admin/Broadcast.tsx index fd6fc8f..7d1e4b4 100644 --- a/app/src/routes/admin/Broadcast.tsx +++ b/app/src/routes/admin/Broadcast.tsx @@ -11,7 +11,7 @@ function Broadcast() { const { t } = useTranslation(); return (
- + {t("admin.broadcast")} diff --git a/app/src/routes/admin/Channel.tsx b/app/src/routes/admin/Channel.tsx index ff52e71..5fa3254 100644 --- a/app/src/routes/admin/Channel.tsx +++ b/app/src/routes/admin/Channel.tsx @@ -12,7 +12,7 @@ function Channel() { return (
- + {t("admin.channel")} diff --git a/app/src/routes/admin/Charge.tsx b/app/src/routes/admin/Charge.tsx index 88144d5..a836d58 100644 --- a/app/src/routes/admin/Charge.tsx +++ b/app/src/routes/admin/Charge.tsx @@ -12,7 +12,7 @@ function Charge() { return (
- + {t("admin.prize")} diff --git a/app/src/routes/admin/Market.tsx b/app/src/routes/admin/Market.tsx index 7ba2f72..faa194d 100644 --- a/app/src/routes/admin/Market.tsx +++ b/app/src/routes/admin/Market.tsx @@ -384,7 +384,7 @@ function Market() { return (
- + {t("admin.market.title")}