From 606ee6777896a6fea246527268417a9fe9a418cd Mon Sep 17 00:00:00 2001 From: Jason Date: Tue, 26 Aug 2025 12:34:47 +0800 Subject: [PATCH] fix(ui): Pin modal action bar; prevent bottom content overflow\n\n- Move action buttons to fixed .modal-footer at the bottom\n- Make modal a column flex container; scroll only body\n- Ensure buttons remain visible on small viewports\n- Remove sticky edge cases causing leaked content --- .gitignore | 2 +- src/components/AddProviderModal.css | 78 ++++++++++++++++++++++---- src/components/ProviderForm.tsx | 86 +++++++++++++++++++---------- 3 files changed, 125 insertions(+), 41 deletions(-) diff --git a/.gitignore b/.gitignore index 4947a84..33886b2 100644 --- a/.gitignore +++ b/.gitignore @@ -7,4 +7,4 @@ release/ .env.local *.tsbuildinfo .npmrc -CLAUDE.md \ No newline at end of file +CLAUDE.mdAGENTS.md diff --git a/src/components/AddProviderModal.css b/src/components/AddProviderModal.css index b4ec60c..7804f31 100644 --- a/src/components/AddProviderModal.css +++ b/src/components/AddProviderModal.css @@ -13,20 +13,74 @@ .modal-content { background: white; - border-radius: 8px; - padding: 2rem; + border-radius: 10px; + padding: 0; width: 90%; - max-width: 600px; + max-width: 640px; max-height: 90vh; - overflow-y: auto; - box-shadow: 0 4px 16px rgba(0, 0, 0, 0.2); + overflow: hidden; /* 由 body 滚动,标题栏固定 */ + box-shadow: 0 16px 40px rgba(0, 0, 0, 0.2); position: relative; z-index: 1001; + display: flex; /* 纵向布局,便于底栏固定 */ + flex-direction: column; } -.modal-content h2 { - margin-bottom: 1.5rem; - color: #2c3e50; +/* 模拟窗口标题栏 */ +.modal-titlebar { + display: flex; + align-items: center; + justify-content: space-between; + height: 3rem; /* 与主窗口标题栏一致 */ + padding: 0 12px; /* 接近主头部的水平留白 */ + background: #3498db; /* 与 .app-header 相同 */ + color: #fff; + border-top-left-radius: 10px; + border-top-right-radius: 10px; +} + +/* 左侧占位以保证标题居中(与右侧关闭按钮宽度相当) */ +.modal-spacer { width: 32px; flex: 0 0 32px; } + +.modal-title { + flex: 1; + text-align: center; + color: #fff; + font-weight: 600; + font-size: 1rem; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +.modal-close-btn { + background: transparent; + border: none; + color: #fff; + font-size: 20px; + line-height: 1; + padding: 2px 6px; + border-radius: 6px; + cursor: pointer; +} + +.modal-close-btn:hover { + background: rgba(255, 255, 255, 0.18); + color: #fff; +} + +.modal-form { /* 表单外层包裹 body + footer */ + display: flex; + flex-direction: column; + flex: 1 1 auto; + min-height: 0; /* 允许子元素正确计算高度 */ +} + +.modal-body { + padding: 1.25rem 1.5rem 1.5rem; + overflow: auto; /* 仅内容区滚动 */ + flex: 1 1 auto; + min-height: 0; } .error-message { @@ -109,11 +163,13 @@ border-color: #3498db; } -.form-actions { +.modal-footer { /* 固定在弹窗底部(非滚动区) */ display: flex; gap: 1rem; justify-content: flex-end; - margin-top: 2rem; + padding: 0.75rem 1.5rem; + border-top: 1px solid #ecf0f1; + background: #fff; } .cancel-btn, @@ -180,4 +236,4 @@ margin: 2px; cursor: pointer; transform: translateY(2px); -} \ No newline at end of file +} diff --git a/src/components/ProviderForm.tsx b/src/components/ProviderForm.tsx index 4e99c72..de893d5 100644 --- a/src/components/ProviderForm.tsx +++ b/src/components/ProviderForm.tsx @@ -181,34 +181,59 @@ const ProviderForm: React.FC = ({ // eslint-disable-next-line react-hooks/exhaustive-deps }, []); + // 支持按下 ESC 关闭弹窗 + useEffect(() => { + const onKeyDown = (e: KeyboardEvent) => { + if (e.key === 'Escape') { + e.preventDefault(); + onClose(); + } + }; + window.addEventListener('keydown', onKeyDown); + return () => window.removeEventListener('keydown', onKeyDown); + }, [onClose]); + return ( -
+
{ if (e.target === e.currentTarget) onClose(); }}>
-

{title}

+
+
+
{title}
+ +
- {error &&
{error}
} +
+
+ {error &&
{error}
} - {showPresets && ( -
- -
- {providerPresets.map((preset, index) => ( - - ))} + {showPresets && ( +
+ +
+ {providerPresets.map((preset, index) => ( + + ))} +
-
- )} + )} -
= ({
-
- -
+ +
+ + +
+