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 = () => {
{/* 背景模糊晕染球 */}
<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="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)
? renderEmailLoginForm()
: renderOAuthOptions()}
......
......@@ -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-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="w-full max-w-md">
<div className="flex items-center justify-center mb-6 gap-2">
......
......@@ -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-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="w-full max-w-md">
<div className="flex items-center justify-center mb-6 gap-2">
......
......@@ -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-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)
? renderEmailRegisterForm()
: renderOAuthOptions()}
......
......@@ -23,7 +23,7 @@ const PageLayout = () => {
const { i18n } = useTranslation();
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') &&
!location.pathname.startsWith('/console/chat') &&
......
......@@ -379,7 +379,7 @@ const PersonalSetting = () => {
};
return (
<div className="bg-gray-50 mt-[64px]">
<div className="bg-gray-50 mt-[60px]">
<div className="flex justify-center">
<div className="w-full">
{/* 主卡片容器 */}
......
......@@ -1902,7 +1902,7 @@ const ChannelsTable = () => {
/>
<Card
className="!rounded-2xl"
className="table-scroll-card !rounded-2xl"
title={renderHeader()}
shadows='always'
bordered={false}
......
......@@ -1202,7 +1202,7 @@ const LogsTable = () => {
<>
{renderColumnSelector()}
<Card
className='!rounded-2xl mb-4'
className='table-scroll-card !rounded-2xl mb-4'
title={
<div className='flex flex-col w-full'>
<Spin spinning={loadingStat}>
......
......@@ -799,7 +799,7 @@ const LogsTable = () => {
{renderColumnSelector()}
<Layout>
<Card
className="!rounded-2xl mb-4"
className="table-scroll-card !rounded-2xl mb-4"
title={
<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">
......
......@@ -574,7 +574,7 @@ const RedemptionsTable = () => {
></EditRedemption>
<Card
className="!rounded-2xl"
className="table-scroll-card !rounded-2xl"
title={renderHeader()}
shadows='always'
bordered={false}
......
......@@ -649,7 +649,7 @@ const LogsTable = () => {
{renderColumnSelector()}
<Layout>
<Card
className="!rounded-2xl mb-4"
className="table-scroll-card !rounded-2xl mb-4"
title={
<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">
......
......@@ -872,7 +872,7 @@ const TokensTable = () => {
></EditToken>
<Card
className="!rounded-2xl"
className="table-scroll-card !rounded-2xl"
title={renderHeader()}
shadows='always'
bordered={false}
......
......@@ -639,7 +639,7 @@ const UsersTable = () => {
></EditUser>
<Card
className="!rounded-2xl"
className="table-scroll-card !rounded-2xl"
title={renderHeader()}
shadows='always'
bordered={false}
......
......@@ -14,22 +14,16 @@
}
/* ==================== 全局基础样式 ==================== */
/* 侧边栏宽度相关的 CSS 变量,配合 .sidebar-collapsed 类和媒体查询实现响应式布局 */
:root {
--sidebar-width: 180px;
/* 展开时宽度 */
--sidebar-width-collapsed: 60px; /* 折叠后宽度,显示图标栏 */
/* 折叠后宽度 */
--sidebar-width-collapsed: 60px;
--sidebar-current-width: var(--sidebar-width);
}
/* 当 body 上存在 .sidebar-collapsed 类时,使用折叠宽度 */
body.sidebar-collapsed {
--sidebar-current-width: var(--sidebar-width-collapsed);
}
/* 移除了在移动端强制设为 0 的限制,改由 React 控制是否渲染侧边栏以实现显示/隐藏 */
body {
font-family: Lato, 'Helvetica Neue', Arial, Helvetica, 'Microsoft YaHei', sans-serif;
color: var(--semi-color-text-0);
......@@ -615,4 +609,31 @@ html:not(.dark) .blur-ball-indigo {
html:not(.dark) .blur-ball-teal {
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 = () => {
);
return (
<div className="mt-[64px] px-2">
<div className="mt-[60px] px-2">
{aboutLoaded && about === '' ? (
<div className="flex justify-center items-center h-screen p-8">
<Empty
......
......@@ -3,7 +3,7 @@ import ChannelsTable from '../../components/table/ChannelsTable';
const File = () => {
return (
<div className="mt-[64px] px-2">
<div className="mt-[60px] px-2">
<ChannelsTable />
</div>
);
......
......@@ -42,7 +42,7 @@ const ChatPage = () => {
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">
<Spin
size="large"
......
......@@ -17,7 +17,7 @@ const chat2page = () => {
}
return (
<div className="mt-[64px] px-2">
<div className="mt-[60px] px-2">
<h3>正在加载,请稍候...</h3>
</div>
);
......
......@@ -1120,7 +1120,7 @@ const Detail = (props) => {
}, []);
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">
<h2
className="text-2xl font-semibold text-gray-800 transition-opacity duration-1000 ease-in-out"
......
......@@ -274,7 +274,7 @@ const Home = () => {
className="w-full h-screen border-none"
/>
) : (
<div className="mt-[64px]" dangerouslySetInnerHTML={{ __html: homePageContent }} />
<div className="mt-[60px]" dangerouslySetInnerHTML={{ __html: homePageContent }} />
)}
</div>
)}
......
......@@ -2,7 +2,7 @@ import React from 'react';
import LogsTable from '../../components/table/LogsTable';
const Token = () => (
<div className="mt-[64px] px-2">
<div className="mt-[60px] px-2">
<LogsTable />
</div>
);
......
......@@ -2,7 +2,7 @@ import React from 'react';
import MjLogsTable from '../../components/table/MjLogsTable';
const Midjourney = () => (
<div className="mt-[64px] px-2">
<div className="mt-[60px] px-2">
<MjLogsTable />
</div>
);
......
......@@ -6,7 +6,7 @@ import { useTranslation } from 'react-i18next';
const NotFound = () => {
const { t } = useTranslation();
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
image={<IllustrationNotFound style={{ width: 250, height: 250 }} />}
darkModeImage={<IllustrationNotFoundDark style={{ width: 250, height: 250 }} />}
......
......@@ -352,7 +352,7 @@ const Playground = () => {
}, [setMessage, saveMessagesImmediately]);
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">
{(showSettings || !isMobile) && (
<Layout.Sider
......
......@@ -2,7 +2,7 @@ import React from 'react';
import ModelPricing from '../../components/table/ModelPricing.js';
const Pricing = () => (
<div className="mt-[64px] px-2">
<div className="mt-[60px] px-2">
<ModelPricing />
</div>
);
......
......@@ -3,7 +3,7 @@ import RedemptionsTable from '../../components/table/RedemptionsTable';
const Redemption = () => {
return (
<div className="mt-[64px] px-2">
<div className="mt-[60px] px-2">
<RedemptionsTable />
</div>
);
......
......@@ -150,7 +150,7 @@ const Setting = () => {
}
}, [location.search]);
return (
<div className="mt-[64px] px-2">
<div className="mt-[60px] px-2">
<Layout>
<Layout.Content>
<Tabs
......
......@@ -133,7 +133,7 @@ const Setup = () => {
};
return (
<div className="bg-gray-50 mt-[64px]">
<div className="bg-gray-50 mt-[60px]">
<Layout>
<Layout.Content>
<div className="flex justify-center px-4 py-8">
......
......@@ -2,7 +2,7 @@ import React from 'react';
import TaskLogsTable from '../../components/table/TaskLogsTable.js';
const Task = () => (
<div className="mt-[64px] px-2">
<div className="mt-[60px] px-2">
<TaskLogsTable />
</div>
);
......
......@@ -3,7 +3,7 @@ import TokensTable from '../../components/table/TokensTable';
const Token = () => {
return (
<div className="mt-[64px] px-2">
<div className="mt-[60px] px-2">
<TokensTable />
</div>
);
......
......@@ -382,7 +382,7 @@ const TopUp = () => {
};
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
title={
......
......@@ -3,7 +3,7 @@ import UsersTable from '../../components/table/UsersTable';
const User = () => {
return (
<div className="mt-[64px] px-2">
<div className="mt-[60px] px-2">
<UsersTable />
</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