feat(console): unified page-header row + UI polish + i18n sync - #11
Conversation
… header row
Introduce PageHeaderContext: a tiny provider exposing a usePageHeader hook
that pages call with `{ title, actions }` to populate the single console
page-header row PageLayout renders next to <Sidebar.Trigger />. Pages
that don't push anything (Channel, User, Token, Log, …) just get a
trigger-only row, which keeps the visual rhythm consistent across the
console without touching every page file.
Why
---
Before this change every console page either rendered its own duplicate
trigger row, or the trigger sat alone on a separate row above the page's
actual title — both ugly. The Dashboard greeting in particular ("👋 早上好,
admin") landed on a row of its own, while the sidebar collapse button
floated awkwardly above it.
After
-----
PageLayout renders one row per console route:
[trigger] [page-supplied title] [page-supplied actions]
matching heroui-pro's AppLayout where the navbar row hosts both the
sidebar trigger and page-level content.
Wire-up
-------
- PageLayout: wrap children in PageHeaderProvider, render
<ConsolePageHeader/> on console routes (reads via usePageHeaderContent)
and move padding off <main> onto an inner wrapper so overflow-y:auto
doesn't swallow the bottom gap.
- DashboardHeader: drop its own header row, push greeting + search /
refresh into the shared row via usePageHeader().
- SiderBar: remove the in-sidebar <CollapsedHeaderTrigger/> — the
trigger now lives in the page-header row exclusively, matching the
canonical heroui-pro Sidebar pattern. Add `pt-4` to Sidebar.Content
so the first group label has breathing room (we omit Sidebar.Header).
Made-with: Cursor
Now that PageLayout renders a single page-header row above <main> and applies the inner padding itself, every console page was double-padding (top gap + side gutter twice). Strip the per-page <div mt-[60px] px-2> wrappers — pages just return their content directly. Pages migrated: - Channel, Token, User, Log, Subscription, Task, Midjourney, Model, ModelDeployment, Redemption, Dashboard — table / data pages - Setting/index — drop <main className='min-w-0'> wrapper, rely on PageLayout's <main> instead - DeploymentAccessGuard — same wrapper inside the access-guard branch - PersonalSetting — drop mt-[60px] (was already centered, just needed the top offset gone) - topup/index — drop mt-[60px] px-2 After this commit no page sets `mt-[60px]` anywhere. Made-with: Cursor
A bundle of HeroUI-aligned visual polish across pages that fell behind
the rest of the v3 cleanup, picked up while rewiring the console layout:
About page
- Replace the flat <Construction/> placeholder with a HeroUI Card +
Spinner + EmptyState + Chip layout that mirrors the rest of the
console: hero title, status pills, link buttons to docs / GitHub /
settings, fallback state when home content fails to load.
Model pricing
- PricingPage / PricingContent: hand off layout to the standard console
page wrapper (no longer needs its own top offset).
- PricingVendorIntro & Skeleton: condense the giant per-vendor intro
into a tighter HeroUI Card + Chip stack; skeleton sheds 200+ lines
by reusing HeroUI Skeleton primitives.
- SearchActions: refactor the search/filter row to use HeroUI Input
+ Button compounds with proper kbd shortcuts.
- PricingCardView / PricingTable: tweak chip / pagination styling
to match the new vendor intro.
Settings
- SystemSetting / CustomOAuthSetting: tighten card spacing, reuse the
shared CheckboxRow primitive, drop a few duplicate tone overrides.
- Settings/Dashboard/{APIInfo, Announcements, DataDashboard, FAQ,
UptimeKuma}: small polish — consistent empty states, tighter form
rows.
- Setting/Operation/SettingsGeneral: align section headers / spacing
with the rest of the console.
Common
- SelectableButtonGroup: bump active state contrast — black bg / white
fg via --button-bg* CSS variable overrides so the selected option
reads clearly against the surrounding `outline` shells; inactive
rows fade to text-muted.
- useDashboardData: drop the leading 👋 emoji from the greeting; the
shared page-header row already has a clear visual anchor (sidebar
trigger on the left), so the emoji read as noise.
Made-with: Cursor
Run `bun run i18n:sync` to pick up the new `t('...')` keys introduced
across the console layout refactor and the About / pricing / settings
polish, and prune keys that were dropped along the way (e.g. the
removed Stripe / Creem placeholder copy that moved into the unified
payment gateway flow upstream).
Touches en / zh-CN / zh-TW / fr / ja / ru / vi.
Made-with: Cursor
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: c9210cdfd7
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| className='flex-1 min-w-0 relative overflow-y-auto' | ||
| style={{ WebkitOverflowScrolling: 'touch' }} | ||
| > | ||
| <div className={shouldInnerPadding ? 'p-6' : ''}> |
There was a problem hiding this comment.
Preserve full-height parent for unpadded app content
When shouldInnerPadding is false, this wrapper renders without any sizing class, so routes that rely on h-full children (notably /pricing after PricingPage switched to h-full containers) lose a concrete height ancestor. In that case percentage heights resolve to auto, and the pricing layout falls back to outer-page scrolling instead of keeping its intended bounded/independent scroll regions. Please keep a full-height context here (or skip the extra wrapper when no padding is needed).
Useful? React with 👍 / 👎.
A long-running WIP that had been sitting in the working tree, split into
4 incremental commits for review.
What changed
1.
feat(console/layout): host page-level title and actions in the shared header rowThe motivating change. Introduces
PageHeaderContextso any consolepage can call
usePageHeader({ title, actions })to populate thesingle page-header row that PageLayout renders next to the sidebar
collapse trigger. Pages that don't push anything (Channel, User,
Token, Log, …) just get a trigger-only row, which keeps the visual
rhythm consistent across the console without touching every page file.
Wire-up:
PageLayoutwraps inPageHeaderProviderand renders<ConsolePageHeader/>on console routes, padding moves off<main>onto an inner wrapper so
overflow-y:autodoesn't swallow the bottomgap;
DashboardHeaderdrops its own row and pushes greeting +search/refresh into the shared row;
SiderBarremoves the in-sidebartrigger so the page-header row owns it exclusively (canonical
heroui-pro Sidebar pattern).
2.
refactor(console/pages): drop per-page mt-[60px] px-2 wrapperNow that PageLayout owns the inner padding, every page that wrapped
its content in
<div className='mt-[60px] px-2'>was double-padding.Strip the wrapper from 12 routes (Channel, Token, User, Log,
Subscription, Task, Midjourney, Model, ModelDeployment, Redemption,
Dashboard, Setting),
DeploymentAccessGuard,PersonalSetting,topup/index. After this commit no page setsmt-[60px]anywhere.3.
refactor(web): polish About / pricing / settings UIA bundle of HeroUI-aligned visual polish picked up while rewiring the
layout — About page rewritten on top of HeroUI Card / Spinner /
EmptyState; pricing vendor intro condensed (skeleton sheds 200+
lines via reusable HeroUI Skeleton primitives); SearchActions row
rebuilt; SystemSetting / CustomOAuthSetting / 5×Settings/Dashboard /
SettingsGeneral tightened; SelectableButtonGroup gets a
high-contrast active state via
--button-bg*overrides;Dashboard greeting drops the leading 👋 emoji (the sidebar trigger
already anchors the row visually).
4.
chore(i18n): sync locale filesbun run i18n:syncoutput for the newt('...')keys introducedabove and the keys dropped during the same pass. Touches all 7
locales (en / zh-CN / zh-TW / fr / ja / ru / vi).
Test plan
bun run dev— every console route shows one and only onepage-header row (sidebar trigger ▸ optional title ▸ optional
actions); no double top padding.
as the sidebar trigger; collapsing the sidebar keeps the trigger
pinned.
page-header row stays consistently 56px tall, no flicker.
px-6 pb-6).with home page content failing to load.
before, no overflow on mobile.
bun x i18next-cli status— locale files in sync (no missingkeys, no extras).
This PR was generated automatically by Cursor.
Made with Cursor