From bd817279dba995d987ddbf95b6bc29533732393c Mon Sep 17 00:00:00 2001 From: mamamiyear Date: Tue, 28 Oct 2025 16:46:45 +0800 Subject: [PATCH] refactor: add top bar and adjust home page layout - add top bar to show the title of web site - move ai input and input image into right side drawer --- src/apis/input.ts | 4 +- src/apis/upload.ts | 4 +- src/components/InputDrawer.css | 40 +++++++++++++++++ src/components/InputDrawer.tsx | 75 ++++++++++++++++++++++++++++++++ src/components/InputPanel.css | 3 +- src/components/InputPanel.tsx | 5 ++- src/components/LayoutWrapper.tsx | 44 ++++++++++++++++--- src/components/MainContent.tsx | 17 +++++--- src/components/SiderMenu.tsx | 34 ++++++++++----- src/components/TopBar.css | 46 ++++++++++++++++++++ src/components/TopBar.tsx | 41 +++++++++++++++++ 11 files changed, 280 insertions(+), 33 deletions(-) create mode 100644 src/components/InputDrawer.css create mode 100644 src/components/InputDrawer.tsx create mode 100644 src/components/TopBar.css create mode 100644 src/components/TopBar.tsx diff --git a/src/apis/input.ts b/src/apis/input.ts index c538d6e..fd433a0 100644 --- a/src/apis/input.ts +++ b/src/apis/input.ts @@ -12,7 +12,7 @@ import type { PostInputRequest, ApiResponse } from './types'; export async function postInput(text: string): Promise { const requestData: PostInputRequest = { text }; // 为 postInput 设置 30 秒超时时间 - return post(API_ENDPOINTS.INPUT, requestData, { timeout: 30000 }); + return post(API_ENDPOINTS.INPUT, requestData, { timeout: 120000 }); } /** @@ -22,5 +22,5 @@ export async function postInput(text: string): Promise { */ export async function postInputData(data: PostInputRequest): Promise { // 为 postInputData 设置 30 秒超时时间 - return post(API_ENDPOINTS.INPUT, data, { timeout: 30000 }); + return post(API_ENDPOINTS.INPUT, data, { timeout: 120000 }); } \ No newline at end of file diff --git a/src/apis/upload.ts b/src/apis/upload.ts index fe76e93..cfc2bfc 100644 --- a/src/apis/upload.ts +++ b/src/apis/upload.ts @@ -15,7 +15,7 @@ export async function postInputImage(file: File): Promise { throw new Error('只能上传图片文件'); } - return upload(API_ENDPOINTS.INPUT_IMAGE, file, 'image', { timeout: 30000 }); + return upload(API_ENDPOINTS.INPUT_IMAGE, file, 'image', { timeout: 120000 }); } /** @@ -75,7 +75,7 @@ export async function postInputImageWithProgress( // 发送请求 xhr.open('POST', `http://127.0.0.1:8099${API_ENDPOINTS.INPUT_IMAGE}`); - xhr.timeout = 30000; // 30秒超时 + xhr.timeout = 120000; // 30秒超时 xhr.send(formData); }); } diff --git a/src/components/InputDrawer.css b/src/components/InputDrawer.css new file mode 100644 index 0000000..0ce319d --- /dev/null +++ b/src/components/InputDrawer.css @@ -0,0 +1,40 @@ +/* 右侧输入抽屉样式(参考示例配色) */ +.input-drawer .ant-drawer-body { + background: #e9b6b6; /* 淡粉色背景,贴近参考图 */ +} + +.input-drawer-inner { + display: flex; + flex-direction: column; + gap: 16px; + align-items: center; /* 居中内部内容 */ +} +.input-drawer-title { + font-weight: 700; + color: #3b3b3b; + letter-spacing: 0.5px; + text-align: center; +} + +.input-drawer-box { + background: rgba(255,255,255,0.75); + border-radius: 12px; + padding: 16px 18px; /* 增大内边距 */ + box-shadow: 0 1px 6px rgba(0,0,0,0.08); + width: 100%; + max-width: 680px; /* 桌面居中显示更宽 */ + margin: 0 auto; /* 水平居中 */ + box-sizing: border-box; +} + +/* 抽屉底部按钮区域与页面底栏保持间距(如有) */ +.input-drawer .ant-drawer-footer { border-top: none; } + +/* 抽屉与遮罩不再额外向下偏移,依赖 getContainer 挂载到标题栏下方的容器 */ + +@media (max-width: 768px) { + .input-drawer-box { + max-width: 100%; + padding: 14px; /* 移动端更紧凑 */ + } +} \ No newline at end of file diff --git a/src/components/InputDrawer.tsx b/src/components/InputDrawer.tsx new file mode 100644 index 0000000..e01c37f --- /dev/null +++ b/src/components/InputDrawer.tsx @@ -0,0 +1,75 @@ +import React from 'react'; +import { Drawer, Grid } from 'antd'; +import InputPanel from './InputPanel.tsx'; +import HintText from './HintText.tsx'; +import './InputDrawer.css'; + +type Props = { + open: boolean; + onClose: () => void; + onResult?: (data: any) => void; + containerEl?: HTMLElement | null; // 抽屉挂载容器(用于放在标题栏下方) +}; + +const InputDrawer: React.FC = ({ open, onClose, onResult, containerEl }) => { + const screens = Grid.useBreakpoint(); + const isMobile = !screens.md; + const [topbarHeight, setTopbarHeight] = React.useState(56); + + React.useEffect(() => { + const update = () => { + const el = document.querySelector('.topbar') as HTMLElement | null; + const h = el?.clientHeight || 56; + setTopbarHeight(h); + }; + update(); + window.addEventListener('resize', update); + return () => window.removeEventListener('resize', update); + }, []); + + // 在输入处理成功(onResult 被调用)后,自动关闭抽屉 + const handleResult = React.useCallback( + (data: any) => { + onResult?.(data); + onClose(); + }, + [onResult, onClose] + ); + + return ( + containerEl : undefined} + closable={false} + zIndex={1500} + rootStyle={{ top: topbarHeight, height: `calc(100% - ${topbarHeight}px)` }} + styles={{ + header: { display: 'none' }, + body: { + padding: 16, + height: '100%', + display: 'flex', + flexDirection: 'column', + alignItems: 'center', + justifyContent: 'center', + }, + mask: { top: topbarHeight, height: `calc(100% - ${topbarHeight}px)` }, + }} + > +
+
AI FIND U
+
+ + +
+
+
+ ); +}; + +export default InputDrawer; \ No newline at end of file diff --git a/src/components/InputPanel.css b/src/components/InputPanel.css index d7f9799..1e189a8 100644 --- a/src/components/InputPanel.css +++ b/src/components/InputPanel.css @@ -2,13 +2,14 @@ .input-panel { display: flex; flex-direction: column; - gap: 8px; + gap: 12px; /* 增大间距 */ } .input-panel .ant-input-outlined, .input-panel .ant-input { background: rgba(255,255,255,0.04); color: #e5e7eb; + min-height: 180px; /* 提升基础高度,配合 autoSize 更宽裕 */ } .input-actions { diff --git a/src/components/InputPanel.tsx b/src/components/InputPanel.tsx index 31a496e..ac59968 100644 --- a/src/components/InputPanel.tsx +++ b/src/components/InputPanel.tsx @@ -88,8 +88,9 @@ const InputPanel: React.FC = ({ onResult }) => {