Commit b0e7b9ae by t0ng7u

🎨 refactor(ui): scope table scrolling to console cards & refine overall layout

Summary
Implement a dedicated, reusable scrolling mechanism for all console-table pages while keeping header and sidebar fixed, plus related layout improvements.

Key Changes
• Added `.table-scroll-card` utility class
 – Provides flex column layout and internal vertical scrolling
 – Desktop height: `calc(100vh - 110px)`; Mobile (<768 px) height: `calc(100vh - 77px)`
 – Hides scrollbars cross-browser (`-ms-overflow-style`, `scrollbar-width`, `::-webkit-scrollbar`)
• Replaced global `.semi-card` scrolling rules with `.table-scroll-card` to avoid affecting non-table cards
• Updated table components (Channels, Tokens, Users, Logs, MjLogs, TaskLogs, Redemptions) to use the new class
• PageLayout
 – Footer is now suppressed for all `/console` routes
 – Confirmed only central content area scrolls; header & sidebar remain fixed
• Restored hidden scrollbar rules for `.semi-layout-content` and removed unnecessary global overrides
• Minor CSS cleanup & comment improvements for readability

Result
Console table pages now fill the viewport with smooth, internal scrolling and no visible scrollbars, while other cards and pages remain unaffected.
parent 38bc3bad
...@@ -523,7 +523,7 @@ const LoginForm = () => { ...@@ -523,7 +523,7 @@ const LoginForm = () => {
{/* 背景模糊晕染球 */} {/* 背景模糊晕染球 */}
<div className="blur-ball blur-ball-indigo" style={{ top: '-80px', right: '-80px', transform: 'none' }} /> <div className="blur-ball blur-ball-indigo" style={{ top: '-80px', right: '-80px', transform: 'none' }} />
<div className="blur-ball blur-ball-teal" style={{ top: '50%', left: '-120px' }} /> <div className="blur-ball blur-ball-teal" style={{ top: '50%', left: '-120px' }} />
<div className="w-full max-w-sm mt-[64px]"> <div className="w-full max-w-sm mt-[60px]">
{showEmailLogin || !(status.github_oauth || status.oidc_enabled || status.wechat_login || status.linuxdo_oauth || status.telegram_oauth) {showEmailLogin || !(status.github_oauth || status.oidc_enabled || status.wechat_login || status.linuxdo_oauth || status.telegram_oauth)
? renderEmailLoginForm() ? renderEmailLoginForm()
: renderOAuthOptions()} : renderOAuthOptions()}
......
...@@ -82,7 +82,7 @@ const PasswordResetConfirm = () => { ...@@ -82,7 +82,7 @@ const PasswordResetConfirm = () => {
{/* 背景模糊晕染球 */} {/* 背景模糊晕染球 */}
<div className="blur-ball blur-ball-indigo" style={{ top: '-80px', right: '-80px', transform: 'none' }} /> <div className="blur-ball blur-ball-indigo" style={{ top: '-80px', right: '-80px', transform: 'none' }} />
<div className="blur-ball blur-ball-teal" style={{ top: '50%', left: '-120px' }} /> <div className="blur-ball blur-ball-teal" style={{ top: '50%', left: '-120px' }} />
<div className="w-full max-w-sm mt-[64px]"> <div className="w-full max-w-sm mt-[60px]">
<div className="flex flex-col items-center"> <div className="flex flex-col items-center">
<div className="w-full max-w-md"> <div className="w-full max-w-md">
<div className="flex items-center justify-center mb-6 gap-2"> <div className="flex items-center justify-center mb-6 gap-2">
......
...@@ -82,7 +82,7 @@ const PasswordResetForm = () => { ...@@ -82,7 +82,7 @@ const PasswordResetForm = () => {
{/* 背景模糊晕染球 */} {/* 背景模糊晕染球 */}
<div className="blur-ball blur-ball-indigo" style={{ top: '-80px', right: '-80px', transform: 'none' }} /> <div className="blur-ball blur-ball-indigo" style={{ top: '-80px', right: '-80px', transform: 'none' }} />
<div className="blur-ball blur-ball-teal" style={{ top: '50%', left: '-120px' }} /> <div className="blur-ball blur-ball-teal" style={{ top: '50%', left: '-120px' }} />
<div className="w-full max-w-sm mt-[64px]"> <div className="w-full max-w-sm mt-[60px]">
<div className="flex flex-col items-center"> <div className="flex flex-col items-center">
<div className="w-full max-w-md"> <div className="w-full max-w-md">
<div className="flex items-center justify-center mb-6 gap-2"> <div className="flex items-center justify-center mb-6 gap-2">
......
...@@ -540,7 +540,7 @@ const RegisterForm = () => { ...@@ -540,7 +540,7 @@ const RegisterForm = () => {
{/* 背景模糊晕染球 */} {/* 背景模糊晕染球 */}
<div className="blur-ball blur-ball-indigo" style={{ top: '-80px', right: '-80px', transform: 'none' }} /> <div className="blur-ball blur-ball-indigo" style={{ top: '-80px', right: '-80px', transform: 'none' }} />
<div className="blur-ball blur-ball-teal" style={{ top: '50%', left: '-120px' }} /> <div className="blur-ball blur-ball-teal" style={{ top: '50%', left: '-120px' }} />
<div className="w-full max-w-sm mt-[64px]"> <div className="w-full max-w-sm mt-[60px]">
{showEmailRegister || !(status.github_oauth || status.oidc_enabled || status.wechat_login || status.linuxdo_oauth || status.telegram_oauth) {showEmailRegister || !(status.github_oauth || status.oidc_enabled || status.wechat_login || status.linuxdo_oauth || status.telegram_oauth)
? renderEmailRegisterForm() ? renderEmailRegisterForm()
: renderOAuthOptions()} : renderOAuthOptions()}
......
...@@ -23,7 +23,7 @@ const PageLayout = () => { ...@@ -23,7 +23,7 @@ const PageLayout = () => {
const { i18n } = useTranslation(); const { i18n } = useTranslation();
const location = useLocation(); const location = useLocation();
const shouldHideFooter = location.pathname === '/console/playground' || location.pathname.startsWith('/console/chat'); const shouldHideFooter = location.pathname.startsWith('/console');
const shouldInnerPadding = location.pathname.includes('/console') && const shouldInnerPadding = location.pathname.includes('/console') &&
!location.pathname.startsWith('/console/chat') && !location.pathname.startsWith('/console/chat') &&
......
...@@ -379,7 +379,7 @@ const PersonalSetting = () => { ...@@ -379,7 +379,7 @@ const PersonalSetting = () => {
}; };
return ( return (
<div className="bg-gray-50 mt-[64px]"> <div className="bg-gray-50 mt-[60px]">
<div className="flex justify-center"> <div className="flex justify-center">
<div className="w-full"> <div className="w-full">
{/* 主卡片容器 */} {/* 主卡片容器 */}
......
...@@ -1902,7 +1902,7 @@ const ChannelsTable = () => { ...@@ -1902,7 +1902,7 @@ const ChannelsTable = () => {
/> />
<Card <Card
className="!rounded-2xl" className="table-scroll-card !rounded-2xl"
title={renderHeader()} title={renderHeader()}
shadows='always' shadows='always'
bordered={false} bordered={false}
......
...@@ -1202,7 +1202,7 @@ const LogsTable = () => { ...@@ -1202,7 +1202,7 @@ const LogsTable = () => {
<> <>
{renderColumnSelector()} {renderColumnSelector()}
<Card <Card
className='!rounded-2xl mb-4' className='table-scroll-card !rounded-2xl mb-4'
title={ title={
<div className='flex flex-col w-full'> <div className='flex flex-col w-full'>
<Spin spinning={loadingStat}> <Spin spinning={loadingStat}>
......
...@@ -799,7 +799,7 @@ const LogsTable = () => { ...@@ -799,7 +799,7 @@ const LogsTable = () => {
{renderColumnSelector()} {renderColumnSelector()}
<Layout> <Layout>
<Card <Card
className="!rounded-2xl mb-4" className="table-scroll-card !rounded-2xl mb-4"
title={ title={
<div className="flex flex-col w-full"> <div className="flex flex-col w-full">
<div className="flex flex-col md:flex-row justify-between items-start md:items-center gap-2 w-full"> <div className="flex flex-col md:flex-row justify-between items-start md:items-center gap-2 w-full">
......
...@@ -574,7 +574,7 @@ const RedemptionsTable = () => { ...@@ -574,7 +574,7 @@ const RedemptionsTable = () => {
></EditRedemption> ></EditRedemption>
<Card <Card
className="!rounded-2xl" className="table-scroll-card !rounded-2xl"
title={renderHeader()} title={renderHeader()}
shadows='always' shadows='always'
bordered={false} bordered={false}
......
...@@ -649,7 +649,7 @@ const LogsTable = () => { ...@@ -649,7 +649,7 @@ const LogsTable = () => {
{renderColumnSelector()} {renderColumnSelector()}
<Layout> <Layout>
<Card <Card
className="!rounded-2xl mb-4" className="table-scroll-card !rounded-2xl mb-4"
title={ title={
<div className="flex flex-col w-full"> <div className="flex flex-col w-full">
<div className="flex flex-col md:flex-row justify-between items-start md:items-center gap-2 w-full"> <div className="flex flex-col md:flex-row justify-between items-start md:items-center gap-2 w-full">
......
...@@ -872,7 +872,7 @@ const TokensTable = () => { ...@@ -872,7 +872,7 @@ const TokensTable = () => {
></EditToken> ></EditToken>
<Card <Card
className="!rounded-2xl" className="table-scroll-card !rounded-2xl"
title={renderHeader()} title={renderHeader()}
shadows='always' shadows='always'
bordered={false} bordered={false}
......
...@@ -639,7 +639,7 @@ const UsersTable = () => { ...@@ -639,7 +639,7 @@ const UsersTable = () => {
></EditUser> ></EditUser>
<Card <Card
className="!rounded-2xl" className="table-scroll-card !rounded-2xl"
title={renderHeader()} title={renderHeader()}
shadows='always' shadows='always'
bordered={false} bordered={false}
......
...@@ -14,22 +14,16 @@ ...@@ -14,22 +14,16 @@
} }
/* ==================== 全局基础样式 ==================== */ /* ==================== 全局基础样式 ==================== */
/* 侧边栏宽度相关的 CSS 变量,配合 .sidebar-collapsed 类和媒体查询实现响应式布局 */
:root { :root {
--sidebar-width: 180px; --sidebar-width: 180px;
/* 展开时宽度 */ --sidebar-width-collapsed: 60px;
--sidebar-width-collapsed: 60px; /* 折叠后宽度,显示图标栏 */
/* 折叠后宽度 */
--sidebar-current-width: var(--sidebar-width); --sidebar-current-width: var(--sidebar-width);
} }
/* 当 body 上存在 .sidebar-collapsed 类时,使用折叠宽度 */
body.sidebar-collapsed { body.sidebar-collapsed {
--sidebar-current-width: var(--sidebar-width-collapsed); --sidebar-current-width: var(--sidebar-width-collapsed);
} }
/* 移除了在移动端强制设为 0 的限制,改由 React 控制是否渲染侧边栏以实现显示/隐藏 */
body { body {
font-family: Lato, 'Helvetica Neue', Arial, Helvetica, 'Microsoft YaHei', sans-serif; font-family: Lato, 'Helvetica Neue', Arial, Helvetica, 'Microsoft YaHei', sans-serif;
color: var(--semi-color-text-0); color: var(--semi-color-text-0);
...@@ -615,4 +609,31 @@ html:not(.dark) .blur-ball-indigo { ...@@ -615,4 +609,31 @@ html:not(.dark) .blur-ball-indigo {
html:not(.dark) .blur-ball-teal { html:not(.dark) .blur-ball-teal {
opacity: 0.2; opacity: 0.2;
}
/* ==================== 表格卡片滚动设置 ==================== */
.table-scroll-card {
display: flex;
flex-direction: column;
height: calc(100vh - 110px);
max-height: calc(100vh - 110px);
}
.table-scroll-card .semi-card-body {
flex: 1 1 auto;
overflow-y: auto;
-ms-overflow-style: none;
scrollbar-width: none;
}
.table-scroll-card .semi-card-body::-webkit-scrollbar {
display: none;
}
@media (max-width: 767px) {
.table-scroll-card {
height: calc(100vh - 77px);
max-height: calc(100vh - 77px);
}
} }
\ No newline at end of file
...@@ -105,7 +105,7 @@ const About = () => { ...@@ -105,7 +105,7 @@ const About = () => {
); );
return ( return (
<div className="mt-[64px] px-2"> <div className="mt-[60px] px-2">
{aboutLoaded && about === '' ? ( {aboutLoaded && about === '' ? (
<div className="flex justify-center items-center h-screen p-8"> <div className="flex justify-center items-center h-screen p-8">
<Empty <Empty
......
...@@ -3,7 +3,7 @@ import ChannelsTable from '../../components/table/ChannelsTable'; ...@@ -3,7 +3,7 @@ import ChannelsTable from '../../components/table/ChannelsTable';
const File = () => { const File = () => {
return ( return (
<div className="mt-[64px] px-2"> <div className="mt-[60px] px-2">
<ChannelsTable /> <ChannelsTable />
</div> </div>
); );
......
...@@ -42,7 +42,7 @@ const ChatPage = () => { ...@@ -42,7 +42,7 @@ const ChatPage = () => {
allow='camera;microphone' allow='camera;microphone'
/> />
) : ( ) : (
<div className="fixed inset-0 w-screen h-screen flex items-center justify-center bg-white/80 z-[1000] mt-[64px]"> <div className="fixed inset-0 w-screen h-screen flex items-center justify-center bg-white/80 z-[1000] mt-[60px]">
<div className="flex flex-col items-center"> <div className="flex flex-col items-center">
<Spin <Spin
size="large" size="large"
......
...@@ -17,7 +17,7 @@ const chat2page = () => { ...@@ -17,7 +17,7 @@ const chat2page = () => {
} }
return ( return (
<div className="mt-[64px] px-2"> <div className="mt-[60px] px-2">
<h3>正在加载,请稍候...</h3> <h3>正在加载,请稍候...</h3>
</div> </div>
); );
......
...@@ -1120,7 +1120,7 @@ const Detail = (props) => { ...@@ -1120,7 +1120,7 @@ const Detail = (props) => {
}, []); }, []);
return ( return (
<div className="bg-gray-50 h-full mt-[64px] px-2"> <div className="bg-gray-50 h-full mt-[60px] px-2">
<div className="flex items-center justify-between mb-4"> <div className="flex items-center justify-between mb-4">
<h2 <h2
className="text-2xl font-semibold text-gray-800 transition-opacity duration-1000 ease-in-out" className="text-2xl font-semibold text-gray-800 transition-opacity duration-1000 ease-in-out"
......
...@@ -274,7 +274,7 @@ const Home = () => { ...@@ -274,7 +274,7 @@ const Home = () => {
className="w-full h-screen border-none" className="w-full h-screen border-none"
/> />
) : ( ) : (
<div className="mt-[64px]" dangerouslySetInnerHTML={{ __html: homePageContent }} /> <div className="mt-[60px]" dangerouslySetInnerHTML={{ __html: homePageContent }} />
)} )}
</div> </div>
)} )}
......
...@@ -2,7 +2,7 @@ import React from 'react'; ...@@ -2,7 +2,7 @@ import React from 'react';
import LogsTable from '../../components/table/LogsTable'; import LogsTable from '../../components/table/LogsTable';
const Token = () => ( const Token = () => (
<div className="mt-[64px] px-2"> <div className="mt-[60px] px-2">
<LogsTable /> <LogsTable />
</div> </div>
); );
......
...@@ -2,7 +2,7 @@ import React from 'react'; ...@@ -2,7 +2,7 @@ import React from 'react';
import MjLogsTable from '../../components/table/MjLogsTable'; import MjLogsTable from '../../components/table/MjLogsTable';
const Midjourney = () => ( const Midjourney = () => (
<div className="mt-[64px] px-2"> <div className="mt-[60px] px-2">
<MjLogsTable /> <MjLogsTable />
</div> </div>
); );
......
...@@ -6,7 +6,7 @@ import { useTranslation } from 'react-i18next'; ...@@ -6,7 +6,7 @@ import { useTranslation } from 'react-i18next';
const NotFound = () => { const NotFound = () => {
const { t } = useTranslation(); const { t } = useTranslation();
return ( return (
<div className="flex justify-center items-center h-screen p-8 mt-[64px]"> <div className="flex justify-center items-center h-screen p-8 mt-[60px]">
<Empty <Empty
image={<IllustrationNotFound style={{ width: 250, height: 250 }} />} image={<IllustrationNotFound style={{ width: 250, height: 250 }} />}
darkModeImage={<IllustrationNotFoundDark style={{ width: 250, height: 250 }} />} darkModeImage={<IllustrationNotFoundDark style={{ width: 250, height: 250 }} />}
......
...@@ -352,7 +352,7 @@ const Playground = () => { ...@@ -352,7 +352,7 @@ const Playground = () => {
}, [setMessage, saveMessagesImmediately]); }, [setMessage, saveMessagesImmediately]);
return ( return (
<div className="h-full bg-gray-50 mt-[64px]"> <div className="h-full bg-gray-50 mt-[60px]">
<Layout style={{ height: '100%', background: 'transparent' }} className="flex flex-col md:flex-row"> <Layout style={{ height: '100%', background: 'transparent' }} className="flex flex-col md:flex-row">
{(showSettings || !isMobile) && ( {(showSettings || !isMobile) && (
<Layout.Sider <Layout.Sider
......
...@@ -2,7 +2,7 @@ import React from 'react'; ...@@ -2,7 +2,7 @@ import React from 'react';
import ModelPricing from '../../components/table/ModelPricing.js'; import ModelPricing from '../../components/table/ModelPricing.js';
const Pricing = () => ( const Pricing = () => (
<div className="mt-[64px] px-2"> <div className="mt-[60px] px-2">
<ModelPricing /> <ModelPricing />
</div> </div>
); );
......
...@@ -3,7 +3,7 @@ import RedemptionsTable from '../../components/table/RedemptionsTable'; ...@@ -3,7 +3,7 @@ import RedemptionsTable from '../../components/table/RedemptionsTable';
const Redemption = () => { const Redemption = () => {
return ( return (
<div className="mt-[64px] px-2"> <div className="mt-[60px] px-2">
<RedemptionsTable /> <RedemptionsTable />
</div> </div>
); );
......
...@@ -150,7 +150,7 @@ const Setting = () => { ...@@ -150,7 +150,7 @@ const Setting = () => {
} }
}, [location.search]); }, [location.search]);
return ( return (
<div className="mt-[64px] px-2"> <div className="mt-[60px] px-2">
<Layout> <Layout>
<Layout.Content> <Layout.Content>
<Tabs <Tabs
......
...@@ -133,7 +133,7 @@ const Setup = () => { ...@@ -133,7 +133,7 @@ const Setup = () => {
}; };
return ( return (
<div className="bg-gray-50 mt-[64px]"> <div className="bg-gray-50 mt-[60px]">
<Layout> <Layout>
<Layout.Content> <Layout.Content>
<div className="flex justify-center px-4 py-8"> <div className="flex justify-center px-4 py-8">
......
...@@ -2,7 +2,7 @@ import React from 'react'; ...@@ -2,7 +2,7 @@ import React from 'react';
import TaskLogsTable from '../../components/table/TaskLogsTable.js'; import TaskLogsTable from '../../components/table/TaskLogsTable.js';
const Task = () => ( const Task = () => (
<div className="mt-[64px] px-2"> <div className="mt-[60px] px-2">
<TaskLogsTable /> <TaskLogsTable />
</div> </div>
); );
......
...@@ -3,7 +3,7 @@ import TokensTable from '../../components/table/TokensTable'; ...@@ -3,7 +3,7 @@ import TokensTable from '../../components/table/TokensTable';
const Token = () => { const Token = () => {
return ( return (
<div className="mt-[64px] px-2"> <div className="mt-[60px] px-2">
<TokensTable /> <TokensTable />
</div> </div>
); );
......
...@@ -382,7 +382,7 @@ const TopUp = () => { ...@@ -382,7 +382,7 @@ const TopUp = () => {
}; };
return ( return (
<div className='mx-auto relative min-h-screen lg:min-h-0 mt-[64px]'> <div className='mx-auto relative min-h-screen lg:min-h-0 mt-[60px]'>
{/* 划转模态框 */} {/* 划转模态框 */}
<Modal <Modal
title={ title={
......
...@@ -3,7 +3,7 @@ import UsersTable from '../../components/table/UsersTable'; ...@@ -3,7 +3,7 @@ import UsersTable from '../../components/table/UsersTable';
const User = () => { const User = () => {
return ( return (
<div className="mt-[64px] px-2"> <div className="mt-[60px] px-2">
<UsersTable /> <UsersTable />
</div> </div>
); );
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment