refactor(console/dashboard): replace Card with HeroUI Pro Widget#3
Merged
dingyi merged 6 commits intoApr 26, 2026
Merged
Conversation
Migrate every panel on /console (StatsCards, ChartsPanel, ApiInfoPanel, AnnouncementsPanel, FaqPanel, UptimePanel) from `@heroui/react` Card to the new `Widget` primitive in `@heroui-pro/react` so each surface gets the gray outer shell + elevated white content area + subtle inner shadow defined by widget.css. Notable adjustments while wiring this up: - StatsCards: Widget.Content padding tightened from p-4 to p-3 and the KPI value font dropped from text-lg to text-base, with min-w-0 on the label cluster and shrink-0 on the trailing button/sparkline so the rendered "充值" button no longer clips against "$200.00" inside the narrower Widget content area. - ChartsPanel + AnnouncementsPanel: override Widget.Header from the default fixed h-8 to h-auto min-h-12 flex-col … lg:flex-row so the inline Tabs strip / legend has room to wrap on narrow viewports. - AnnouncementsPanel + UptimePanel: adopt Widget.Legend / Widget.LegendItem for status legends; the announcement panel maps the existing grey/blue/green/orange/red swatch keys to concrete CSS colors via a small LEGEND_COLOR_MAP because Widget.LegendItem requires a CSS color string. - All title clusters use a whitespace-nowrap flex wrapper around the lucide icon and Widget.Title so CJK title characters do not stack vertically when the grid column is narrow. widget.css is already pulled in via `@import '@heroui-pro/react/css';` in web/src/index.css, so no extra CSS plumbing is required. Verified: `bun run build` passes; `bunx prettier --check` and `bunx eslint` pass for all touched files; manual screenshot QA confirms the dashboard panels render with the new Widget surface. Made-with: Cursor
Address visual polish feedback on the Widget rebuild: - Title size: createSectionTitle in helpers/dashboard.jsx now wraps the text in a `text-sm font-semibold text-foreground` span (matching the widget__title CSS) so the four StatsCards titles (账户数据 / 使用统计 / 资源消耗 / 性能指标) match the Widget.Title used by every other panel. Also adds whitespace-nowrap + shrink-0 on the icon to prevent CJK characters from stacking. - Header height: every simple Widget.Header now uses `h-12` so the header strip matches the AnnouncementsPanel header height (which the user pointed out as the correct one). The complex headers (ChartsPanel, AnnouncementsPanel) keep their `h-auto min-h-12 … flex-col` rule for content that can wrap to a second row. - Empty state: every empty state now uses HeroUI Pro's `EmptyState` with `size='sm'` and `EmptyState.Media variant='icon'`, dropping the custom 96×96 illustration container override. FaqPanel previously used a bespoke div + HelpCircle 42px; it now uses EmptyState too, so the four panels (ApiInfoPanel / AnnouncementsPanel / FaqPanel / UptimePanel) share the same circular muted icon background and consistent typography. - Responsive grid: StatsCards collapses to 4-col only at xl (≥1280px) via `grid-cols-1 sm:grid-cols-2 xl:grid-cols-4` so each KPI card has ~360px at common 1024–1280 widths instead of ~150px (which was forcing labels like "统计次数" to wrap CJK character per line). ChartsPanel + ApiInfoPanel switch to `lg:grid-cols-3 xl:grid-cols-4` with the chart panel spanning 2/3, giving the API info column a more usable ~256px width at lg. The bottom info panels grid switches to `lg:grid-cols-2 xl:grid-cols-4` so 系统公告 takes the full row at lg with FAQ + Uptime side-by-side beneath it. - ChartsPanel tabs strip: keeps the title and the Tabs.List on separate rows through lg and only inlines them at xl. The tab list is wrapped in an overflow-x-auto container with whitespace-nowrap on each Tabs.Tab so the 4–6 chart tabs no longer collapse into vertical CJK character columns when the chart panel narrows. - Cleanup: drop the now-unused ILLUSTRATION_SIZE prop from AnnouncementsPanel / ApiInfoPanel / FaqPanel / UptimePanel and from the dashboard index that wired it through. Verified: bun run build passes, prettier --check + eslint pass on all touched files, and manual screenshot QA confirms consistent header heights, title sizes, empty state icons, and a clean 2-col KPI grid + horizontally scrollable tabs at the typical 1024px viewport. Made-with: Cursor
…tons - StatsCards: switch the 当前余额 → 充值 button from `variant='secondary'` (default surface fill + accent-soft text, which read as a muted green pill) to `variant='primary'` so it now renders with the accent fill + accent-foreground text expected of a recharge CTA. - DashboardHeader: switch the 搜索条件 + 刷新 icon-only buttons from `variant='tertiary'` (which paints the surrounding pill at rest) to `variant='ghost'` so the trigger reads as a bare icon and the background only fades in on hover/press. Drop the gap from `gap-2` to `gap-1` since the buttons no longer carry their own pill. Made-with: Cursor
The refresh trigger inside 服务可用性's compact 48px Widget.Header was still rendering at full Button `sm` icon-only dimensions (32×32 with a 16px svg, since `.button--sm` forces svg to size-4 regardless of the lucide `size` prop). Override to `!h-6 !w-6 !min-w-0` plus `[&_svg]:!size-3` so the affordance reads as a 24×24 hover pill with a 12px refresh glyph — proportionate to the small panel header without dominating the title. HeroUI Button only ships `sm`/`md`/`lg`, so a className escape hatch is the cleanest sub-`sm` path. Made-with: Cursor
The Tabs.List inside 模型数据分析's Widget.Header carries 4–6 entries (消耗分布 / 调用趋势 / 调用次数分布 / 调用次数排行 / 用户消耗排行 / 用户消耗趋势). At the default 14px tab font, only the first three fit across the chart panel at lg, forcing the rest behind the horizontal scroll. Drop each Tabs.Tab label to text-xs (12px) so 4–5 tabs are visible at rest while the secondary chrome stays subordinate to the 14px Widget.Title. Made-with: Cursor
ApiInfoPanel sits in a CSS grid row alongside the much-taller ChartsPanel, so the row stretches the API info Widget to ~24rem. Previously the empty state branch rendered straight inside ScrollableContainer, which collapses to its content height — leaving the empty state pinned to the top with all the empty space below it. Split the two render paths: - Data path keeps the ScrollableContainer for scroll-with-fade and now carries `flex-1` so the scroll region claims the stretched height. - Empty path renders into a `flex flex-1 min-h-80 items-center justify-center` wrapper, which propagates the row height down via the `flex` Widget.Content + `flex-1` child chain and centers the EmptyState both axes regardless of grid stretch height. Made-with: Cursor
4 tasks
dingyi
added a commit
that referenced
this pull request
Apr 26, 2026
* feat(console): port template-dashboard styling to /console pages Brings the visual language of the standalone @heroui-pro/template-dashboard project into all /console routes by aligning background, typography, and color tokens with the template: - Strip body radial-gradient background; body now matches template's flat var(--background) so cards/tables sit on a uniform surface. - DashboardHeader greeting drops to text-xl + text-foreground (matches template navbar title weight/size; was text-2xl text-gray-800). - StatsCards / ApiInfoPanel / AnnouncementsPanel / FaqPanel / UptimePanel swap literal text-gray-* / text-slate-* / bg-gray-50 utilities for semantic HeroUI tokens (text-foreground, text-muted, text-primary, border-border, bg-surface-secondary). - ApiInfoPanel API route label drops !font-bold for template's font-semibold; KPI numbers in StatsCards gain tabular-nums. Also rolls in pre-existing in-flight HeroUI/Semi cleanup that was sitting in the working tree, plus .gitignore entries for .playwright-mcp and loose screenshot artifacts. Made-with: Cursor * refactor(sidebar): port template-dashboard Sidebar styling to console SiderBar Brings the visual layer of the console sidebar in line with @heroui-pro/template-dashboard's Sidebar component (without changing the underlying PageLayout structure). - Drop sidebar-shell glassmorphism: remove backdrop-blur, heavy box-shadow, and gradient background. Sidebar now uses flat bg-background + border-r border-border like the template. - Add a Sidebar.Header-style block at the top: avatar + display name + role (super admin / admin / user), mirroring template's Kate Moore / Admin block. - Tone down section labels: uppercase tracking-wide bold → quiet `text-xs font-medium text-muted` labels. - Menu items: rounded-2xl → rounded-md, font-semibold → font-medium, slate-600/300 → text-muted, primary-tinted active → bg-surface-secondary + text-foreground. - Nested chat items drop to font-normal, matching template's relative weight hierarchy. - Collapse button: drop bordered + backdrop-blur look, switch to ghost variant with semantic hover tokens. Build passes (`bun run build`). Functional behavior (routing, collapse state, mobile drawer, chat sub-menu) is untouched. Made-with: Cursor * refactor(console): port template-dashboard chrome to header + sidebar Continues aligning console chrome with @heroui-pro/template-dashboard after the sidebar visual refresh. Header bar (always visible): - Drop bg-white/75 + backdrop-blur-lg glassmorphism on header element; use flat bg-background + border-b border-border like template's Navbar. - Navigation: text-slate-700/200 -> text-foreground; reduce link weight from font-semibold to font-medium to match template. - HeaderLogo: text-slate-950/white -> text-foreground. - UserArea: replace bg-slate-900/[0.04] hover:bg-slate-900/[0.07] etc. with bg-surface-secondary / hover:bg-surface-tertiary; chevron and username swap slate literal colors for text-muted/foreground; menu popover drops backdrop-blur + bg-white/95 in favor of bg-background + border-border + shadow-lg. Dashboard panels: - DashboardHeader: drop hard bg-emerald-500 / bg-blue-500 buttons in favor of HeroUI's `size='sm' variant='tertiary'` to match template's navbar action buttons. - useDashboardStats: drop pastel `bg-blue-50/green-50/yellow-50/indigo-50` card tints (which had no dark-mode adaptation) so KPI cards render on the default neutral surface like template's `<KPI>` cards. Sidebar (in-flight HeroUI Pro adoption + my user header): - SiderBar.jsx now uses the actual `<Sidebar>` / `<Sidebar.Mobile>` / `<Sidebar.Header>` / `<Sidebar.Group>` / `<Sidebar.MenuItem>` components from @heroui-pro/react, mirroring template's `dashboard-sidebar.tsx` exactly. Avatar + display name + role block sits inside Sidebar.Header. - PageLayout.jsx now wraps the app in `<Sidebar.Provider>` and bridges the existing localStorage-backed collapse state to its open/onOpenChange API. - MobileMenuButton + useHeaderBar updated to drive the new Sidebar.Provider open state. `bun run build` passes (27.42s). Visual smoke test on /login + / shows flat header with subtle border-bottom, semantic surface tokens throughout, no glassmorphism. Made-with: Cursor * refactor(sidebar): move trigger to navbar, avatar to footer, drop misaligned skeleton Three product-spec deviations from the literal template-dashboard layout: 1. Sidebar.Trigger lives in the top navbar (top-left, after the mobile menu button), NOT inside the sidebar itself. Mirrors the same place template-dashboard puts <Sidebar.Trigger /> in `dashboard-navbar.tsx`, which is conceptually "sidebar collapse is at the top" rather than bottom of the sidebar. Only renders on /console routes + non-mobile. 2. User avatar / display-name / role block moves from Sidebar.Header to Sidebar.Footer (bottom of the sidebar) per product preference (template puts it at top with Kate Moore / Admin; we want it at the bottom). 3. Drop the SkeletonWrapper that was wrapping <SidebarBody/>. The old skeleton renders bare divs sized for the previous self-implemented sidebar; nesting them inside heroui-pro's <Sidebar> component (which expects Sidebar.Content / .Footer children with its own internal layout) caused all menu items to misalign — items rendered flush-left without sidebar padding, no visible container background, and broke the visual structure entirely. Now the real Sidebar structure renders immediately; visibleSections gracefully empties while useSidebar() is still resolving, so the menu briefly shows nothing rather than misaligned placeholder bars. Build passes. Visual smoke test on /login confirms the trigger appears at top-left of the navbar and no misaligned bars remain. Made-with: Cursor * fix(sidebar): import heroui-pro stylesheet so <Sidebar> actually has CSS The misalignment everyone saw on /console was rooted in a single missing import. The codebase used <Sidebar> / <Sidebar.MenuItem> / <Sidebar.Group> from @heroui-pro/react but only loaded @heroui/styles in index.css. Without @heroui-pro/react/css the Pro components have zero styling — menu icons stack on top of labels instead of sitting beside them, group labels disappear, sidebar has no container width or border-right, and footer slot renders into nothing. Mirror the template-dashboard's globals.css layout exactly: @import '@heroui/styles'; @import '@heroui-pro/react/css'; Plus two follow-on cleanups now that the stylesheet is loaded: - Wrap the user avatar / role block as a real <Sidebar.MenuItem> inside a <Sidebar.Menu> within <Sidebar.Footer>. Sidebar.Footer ignores arbitrary children when not given a Sidebar.Menu structure. - Skip menu items / chat sub-items with no resolvable href to silence the remaining `PressResponder was rendered without a pressable child` warnings from react-aria. Verified locally with the Go backend running: - sidebar trigger □ at top-left of navbar (template parity) - menu items render as icon + label rows with primary-tinted active state - group labels (Chat / Console / Personal center / Admin) visible - user avatar + display name + role at the very bottom of the sidebar - collapse / expand via the navbar trigger works Made-with: Cursor * fix(console): scroll, trigger placement, and active icon color Three follow-on UX fixes after the heroui-pro Sidebar wiring: 1. Right-side content was no longer scrollable. Sidebar.Provider was set to `min-h-dvh` so tall console pages grew the document body and the whole page (sidebar included) scrolled. Switched to `h-dvh overflow-hidden` so the <main> element becomes the scroll container and the sidebar stays sticky like template-dashboard. 2. Sidebar.Trigger now switches sides based on expand/collapse state. - When the sidebar is collapsed: trigger renders in the navbar's top-left (NavbarTrigger). Lets the user re-expand from anywhere. - When the sidebar is expanded: trigger renders inside the page content's top-left (ConsolePageTrigger), above the page heading. Avoids visually crowding the trigger flush against the expanded sidebar's right edge. Both wrappers read `isOpen` from `useSidebar()` (heroui-pro exposes the desktop expand/collapse flag as `isOpen`, NOT `open`). 3. Active menu item icon no longer tints to primary. `getLucideIcon` was hard-setting `color: var(--app-primary)` for selected items, which clashed with the menu item's own foreground-on-active styling. Now selected icons keep `currentColor` (so they inherit the deepened foreground tone of the active row) and bump strokeWidth from 2 to 2.5 so they read as "deepened" without changing tint. Also drops the scale-105 transform. Plus index.css cleanup: remove the legacy `--sidebar-width` / `--sidebar-width-collapsed` / `--sidebar-current-width` vars and the `body.sidebar-collapsed` selector. Those drove the previous custom sidebar's width and conflict with heroui-pro's internal width vars, causing the icon-mode column to render at the wrong width. Made-with: Cursor * fix(sidebar): show user footer, fix trigger position, drop strokeWidth bump Three follow-up fixes after the live console smoke test exposed missing / out-of-spec behaviors: 1. User avatar block at the bottom was invisible. Root cause: heroui-pro's `.sidebar` is hard-coded `height: 100svh`, intended for an <AppLayout> that hoists the navbar above the Sidebar.Provider. Our PageLayout puts the navbar *inside* the provider, so the sidebar starts ~64px below the viewport top and its 100svh height pushes Sidebar.Footer (the avatar block) ~64px below the visible viewport. Override `[data-slot='sidebar'] { height: 100% }` so the sidebar fits its parent's available height. Footer now sticks at the bottom of the visible sidebar. 2. Sidebar.Trigger position must NOT change between expand/collapse. Reverted the conditional NavbarTrigger / ConsolePageTrigger split. ConsolePageTrigger now renders unconditionally above every console page (top-left of the content area, above the page heading), and the navbar no longer hosts a trigger at all. 3. Active menu item icons no longer bump strokeWidth. heroui-pro's sidebar.css already deepens active-item icons from `--muted` to `--foreground` automatically via `.sidebar__menu-item[data-current=true] .sidebar__menu-icon { color }`, so my custom `strokeWidth: 2.5` for selected items was producing icons visibly heavier than template-dashboard. Reverted to a uniform stroke of 2 for both states. Verified locally on /console with the Go backend + dingyi user logged in: trigger stays put through expand/collapse, avatar+role block reads "Root User / Super Admin" at the bottom of the sidebar in both states, active item icon matches template-dashboard's neutral (non-tinted) look. Made-with: Cursor * fix(sidebar): trigger relocates to sidebar top when collapsed When the sidebar is collapsed, render <Sidebar.Trigger /> inside a <Sidebar.Header className='pt-6 pb-3'> at the top of the sidebar so the user can re-expand from within the icon column itself. When the sidebar is expanded, keep the trigger above the page heading in the content area (unchanged). `pt-6` gives roughly 1.5rem of breathing room above the trigger so it doesn't sit flush against the navbar's bottom border. Renamed the heroui-pro `useSidebar` import to `useSidebarUI` inside SiderBar.jsx to avoid colliding with our own `hooks/common/useSidebar` (which manages module visibility). Made-with: Cursor * refactor(console/dashboard): replace Card with HeroUI Pro Widget (#3) * refactor(console/dashboard): replace Card with HeroUI Pro Widget Migrate every panel on /console (StatsCards, ChartsPanel, ApiInfoPanel, AnnouncementsPanel, FaqPanel, UptimePanel) from `@heroui/react` Card to the new `Widget` primitive in `@heroui-pro/react` so each surface gets the gray outer shell + elevated white content area + subtle inner shadow defined by widget.css. Notable adjustments while wiring this up: - StatsCards: Widget.Content padding tightened from p-4 to p-3 and the KPI value font dropped from text-lg to text-base, with min-w-0 on the label cluster and shrink-0 on the trailing button/sparkline so the rendered "充值" button no longer clips against "$200.00" inside the narrower Widget content area. - ChartsPanel + AnnouncementsPanel: override Widget.Header from the default fixed h-8 to h-auto min-h-12 flex-col … lg:flex-row so the inline Tabs strip / legend has room to wrap on narrow viewports. - AnnouncementsPanel + UptimePanel: adopt Widget.Legend / Widget.LegendItem for status legends; the announcement panel maps the existing grey/blue/green/orange/red swatch keys to concrete CSS colors via a small LEGEND_COLOR_MAP because Widget.LegendItem requires a CSS color string. - All title clusters use a whitespace-nowrap flex wrapper around the lucide icon and Widget.Title so CJK title characters do not stack vertically when the grid column is narrow. widget.css is already pulled in via `@import '@heroui-pro/react/css';` in web/src/index.css, so no extra CSS plumbing is required. Verified: `bun run build` passes; `bunx prettier --check` and `bunx eslint` pass for all touched files; manual screenshot QA confirms the dashboard panels render with the new Widget surface. Made-with: Cursor * refactor(console/dashboard): polish Widget header, empty state, and grid Address visual polish feedback on the Widget rebuild: - Title size: createSectionTitle in helpers/dashboard.jsx now wraps the text in a `text-sm font-semibold text-foreground` span (matching the widget__title CSS) so the four StatsCards titles (账户数据 / 使用统计 / 资源消耗 / 性能指标) match the Widget.Title used by every other panel. Also adds whitespace-nowrap + shrink-0 on the icon to prevent CJK characters from stacking. - Header height: every simple Widget.Header now uses `h-12` so the header strip matches the AnnouncementsPanel header height (which the user pointed out as the correct one). The complex headers (ChartsPanel, AnnouncementsPanel) keep their `h-auto min-h-12 … flex-col` rule for content that can wrap to a second row. - Empty state: every empty state now uses HeroUI Pro's `EmptyState` with `size='sm'` and `EmptyState.Media variant='icon'`, dropping the custom 96×96 illustration container override. FaqPanel previously used a bespoke div + HelpCircle 42px; it now uses EmptyState too, so the four panels (ApiInfoPanel / AnnouncementsPanel / FaqPanel / UptimePanel) share the same circular muted icon background and consistent typography. - Responsive grid: StatsCards collapses to 4-col only at xl (≥1280px) via `grid-cols-1 sm:grid-cols-2 xl:grid-cols-4` so each KPI card has ~360px at common 1024–1280 widths instead of ~150px (which was forcing labels like "统计次数" to wrap CJK character per line). ChartsPanel + ApiInfoPanel switch to `lg:grid-cols-3 xl:grid-cols-4` with the chart panel spanning 2/3, giving the API info column a more usable ~256px width at lg. The bottom info panels grid switches to `lg:grid-cols-2 xl:grid-cols-4` so 系统公告 takes the full row at lg with FAQ + Uptime side-by-side beneath it. - ChartsPanel tabs strip: keeps the title and the Tabs.List on separate rows through lg and only inlines them at xl. The tab list is wrapped in an overflow-x-auto container with whitespace-nowrap on each Tabs.Tab so the 4–6 chart tabs no longer collapse into vertical CJK character columns when the chart panel narrows. - Cleanup: drop the now-unused ILLUSTRATION_SIZE prop from AnnouncementsPanel / ApiInfoPanel / FaqPanel / UptimePanel and from the dashboard index that wired it through. Verified: bun run build passes, prettier --check + eslint pass on all touched files, and manual screenshot QA confirms consistent header heights, title sizes, empty state icons, and a clean 2-col KPI grid + horizontally scrollable tabs at the typical 1024px viewport. Made-with: Cursor * style(console/dashboard): use primary 充值 CTA and bare-icon header buttons - StatsCards: switch the 当前余额 → 充值 button from `variant='secondary'` (default surface fill + accent-soft text, which read as a muted green pill) to `variant='primary'` so it now renders with the accent fill + accent-foreground text expected of a recharge CTA. - DashboardHeader: switch the 搜索条件 + 刷新 icon-only buttons from `variant='tertiary'` (which paints the surrounding pill at rest) to `variant='ghost'` so the trigger reads as a bare icon and the background only fades in on hover/press. Drop the gap from `gap-2` to `gap-1` since the buttons no longer carry their own pill. Made-with: Cursor * style(uptime-panel): shrink the refresh action to read as inline glyph The refresh trigger inside 服务可用性's compact 48px Widget.Header was still rendering at full Button `sm` icon-only dimensions (32×32 with a 16px svg, since `.button--sm` forces svg to size-4 regardless of the lucide `size` prop). Override to `!h-6 !w-6 !min-w-0` plus `[&_svg]:!size-3` so the affordance reads as a 24×24 hover pill with a 12px refresh glyph — proportionate to the small panel header without dominating the title. HeroUI Button only ships `sm`/`md`/`lg`, so a className escape hatch is the cleanest sub-`sm` path. Made-with: Cursor * style(charts-panel): drop chart tab label font from text-sm to text-xs The Tabs.List inside 模型数据分析's Widget.Header carries 4–6 entries (消耗分布 / 调用趋势 / 调用次数分布 / 调用次数排行 / 用户消耗排行 / 用户消耗趋势). At the default 14px tab font, only the first three fit across the chart panel at lg, forcing the rest behind the horizontal scroll. Drop each Tabs.Tab label to text-xs (12px) so 4–5 tabs are visible at rest while the secondary chrome stays subordinate to the 14px Widget.Title. Made-with: Cursor * fix(api-info-panel): center empty state vertically inside the panel ApiInfoPanel sits in a CSS grid row alongside the much-taller ChartsPanel, so the row stretches the API info Widget to ~24rem. Previously the empty state branch rendered straight inside ScrollableContainer, which collapses to its content height — leaving the empty state pinned to the top with all the empty space below it. Split the two render paths: - Data path keeps the ScrollableContainer for scroll-with-fade and now carries `flex-1` so the scroll region claims the stretched height. - Empty path renders into a `flex flex-1 min-h-80 items-center justify-center` wrapper, which propagates the row height down via the `flex` Widget.Content + `flex-1` child chain and centers the EmptyState both axes regardless of grid stretch height. Made-with: Cursor --------- Co-authored-by: dingyi <dingyi@users.noreply.github.com>
dingyi
added a commit
that referenced
this pull request
Apr 27, 2026
Auto-merge — no conflicts. Brings the PR #5 (HeroUI rewrite) and PR #1/#3 console template work into the widget-dashboard-cards branch so the dashboard widget polish work (6 commits: replace Card with HeroUI Pro Widget, polish Widget header/empty state/grid, primary 充值 CTA + bare-icon header buttons, shrink uptime panel refresh action, drop charts panel tab font, vertically center api-info-panel empty state) can be merged on top of the latest UI foundation. Validation: - bun run build: passes (20.62s) - go build .: passes
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Replace every panel on
/console(the dashboard) with HeroUI Pro'sWidgetprimitive (@heroui-pro/react) so each surface gets thecharacteristic gray outer shell + elevated white content area + subtle
inner shadow defined by
widget.css.Components migrated to
WidgetStatsCards— 4 KPI tiles (账户数据 / 使用统计 / 资源消耗 / 性能指标).ChartsPanel— 模型数据分析 chart panel with the inlineTabs.Liststrip.ApiInfoPanel— API信息 list with speedtest/jump action rows.AnnouncementsPanel— 系统公告 timeline + status legend(
Widget.Legend/Widget.LegendItem).FaqPanel— 常见问答 accordion +EmptyState.UptimePanel— 服务可用性 monitor list + status legend inWidget.Footer.Polish included in this PR
createSectionTitleinhelpers/dashboard.jsxnow wraps text in a
text-sm font-semibold text-foregroundspan sothe four StatsCards titles match
Widget.Titletypography acrossevery other panel.
Widget.Headerusesh-12so thestrip matches the AnnouncementsPanel header (which already had to be
taller for the chip + legend row). Multi-row headers
(
ChartsPanel,AnnouncementsPanel) keeph-auto min-h-12 … flex-col xl:flex-rowso the trailing tabs / legend can wrap.EmptyState size='sm'with
EmptyState.Media variant='icon', replacing the bespoke96×96 illustration container override.
FaqPanel's custom div +HelpCircle 42px is also routed through
EmptyState.ApiInfoPanelwraps its empty state in
flex flex-1 min-h-80 items-center justify-centerso it stays vertically centered inside thetaller-than-its-content grid row.
grid-cols-1 sm:grid-cols-2 xl:grid-cols-4(4-col only at ≥1280px) so each KPI tile has~360px at common 1024–1280 widths. ChartsPanel + ApiInfoPanel
switch to
lg:grid-cols-3 xl:grid-cols-4with the chart panelspanning 2/3, giving the API column ~256px at lg. The bottom info
row uses
lg:grid-cols-2 xl:grid-cols-4so 系统公告 takes the fullrow at lg with FAQ + Uptime side-by-side beneath.
Tabs.Liston separate rowsthrough lg, only inlining at xl. The tab list is wrapped in an
overflow-x-autocontainer withwhitespace-nowrapperTabs.Tab, and tab labels drop totext-xs(12px) so the 6 charttabs no longer collapse into vertical CJK character columns.
variant='primary'(accent fill + accent-foreground text) ratherthan
variant='secondary'(default surface + accent-soft text)so it reads as a proper recharge CTA.
DashboardHeader's search + refreshtriggers switch to
variant='ghost'so they read as bare icons,with the surrounding pill only fading in on hover/press.
UptimePanel's refresh trigger gets!h-6 !w-6 !min-w-0+[&_svg]:!size-3to land at 24×24 with a 12px glyph,proportionate to the compact 48px panel header. HeroUI Button only
ships
sm/md/lg, so the className escape hatch is thecleanest sub-
smpath.widget.cssis already pulled in via@import '@heroui-pro/react/css';in
web/src/index.css, so no extra CSS plumbing was required.Test plan
bun run build— passes.bunx prettier --check+bunx eslint— pass on all touchedfiles.
/console: stats cards, chart panel,API info panel, announcements panel, FAQ panel, uptime panel
all render with the new Widget surface, consistent header
heights, consistent empty state icons, and a clean 2-col KPI
grid + horizontally scrollable chart tabs at the typical
1024px viewport.
This PR was generated automatically by Cursor
Made with Cursor