refactor: improve UI layout for VS Code and common config options

- Implement horizontal two-column layout for better space utilization
- Convert VS Code config from button to checkbox pattern for consistency
- Add automatic VS Code settings write on checkbox toggle
- Fix layout stability issues with fixed height containers
- Remove unnecessary wrapper functions for cleaner code
- Adjust spacing and alignment for more compact design
This commit is contained in:
Jason
2025-09-18 12:07:36 +08:00
parent 9bf216b102
commit 2a9f093210

View File

@@ -30,7 +30,7 @@ const CodexConfigEditor: React.FC<CodexConfigEditorProps> = ({
authError,
}) => {
const [isCommonConfigModalOpen, setIsCommonConfigModalOpen] = useState(false);
const [isWritingVscode, setIsWritingVscode] = useState(false);
const [writeVscodeConfig, setWriteVscodeConfig] = useState(false);
const [vscodeError, setVscodeError] = useState("");
const [vscodeSuccess, setVscodeSuccess] = useState("");
@@ -48,6 +48,51 @@ const CodexConfigEditor: React.FC<CodexConfigEditorProps> = ({
return () => window.clearTimeout(timer);
}, [vscodeSuccess]);
// 监听 writeVscodeConfig 变化并执行写入
useEffect(() => {
if (!writeVscodeConfig) return;
const performWrite = async () => {
setVscodeError("");
setVscodeSuccess("");
if (typeof window === "undefined" || !window.api?.writeVscodeSettings) {
setVscodeError("当前环境暂不支持写入 VS Code 配置");
setWriteVscodeConfig(false);
return;
}
const trimmed = configValue.trim();
if (!trimmed) {
setVscodeError("请先填写 config.toml再写入 VS Code 配置");
setWriteVscodeConfig(false);
return;
}
const baseUrl = extractBaseUrlFromToml(trimmed);
if (!baseUrl) {
setVscodeError("未在 config.toml 中找到 base_url 字段");
setWriteVscodeConfig(false);
return;
}
try {
const success = await window.api.writeVscodeSettings(baseUrl);
if (success) {
setVscodeSuccess("已写入 VS Code 配置");
} else {
setVscodeError("写入 VS Code 配置失败,请稍后重试");
setWriteVscodeConfig(false);
}
} catch (error) {
setVscodeError(`写入 VS Code 配置失败: ${String(error)}`);
setWriteVscodeConfig(false);
}
};
performWrite();
}, [writeVscodeConfig, configValue]);
// 支持按下 ESC 关闭弹窗
useEffect(() => {
if (!isCommonConfigModalOpen) return;
@@ -66,54 +111,6 @@ const CodexConfigEditor: React.FC<CodexConfigEditorProps> = ({
setIsCommonConfigModalOpen(false);
};
const handleAuthChange = (value: string) => {
onAuthChange(value);
};
const handleConfigChange = (value: string) => {
onConfigChange(value);
};
const handleCommonConfigSnippetChange = (value: string) => {
onCommonConfigSnippetChange(value);
};
const handleWriteVscodeConfig = async () => {
setVscodeError("");
setVscodeSuccess("");
if (typeof window === "undefined" || !window.api?.writeVscodeSettings) {
setVscodeError("当前环境暂不支持写入 VS Code 配置");
return;
}
const trimmed = configValue.trim();
if (!trimmed) {
setVscodeError("请先填写 config.toml再写入 VS Code 配置");
return;
}
const baseUrl = extractBaseUrlFromToml(trimmed);
if (!baseUrl) {
setVscodeError("未在 config.toml 中找到 base_url 字段");
return;
}
setIsWritingVscode(true);
try {
const success = await window.api.writeVscodeSettings(baseUrl);
if (success) {
setVscodeSuccess("已写入 VS Code 配置");
} else {
setVscodeError("写入 VS Code 配置失败,请稍后重试");
}
} catch (error) {
setVscodeError(`写入 VS Code 配置失败: ${String(error)}`);
} finally {
setIsWritingVscode(false);
}
};
return (
<div className="space-y-6">
<div className="space-y-2">
@@ -126,7 +123,7 @@ const CodexConfigEditor: React.FC<CodexConfigEditorProps> = ({
<textarea
id="codexAuth"
value={authValue}
onChange={(e) => handleAuthChange(e.target.value)}
onChange={(e) => onAuthChange(e.target.value)}
onBlur={onAuthBlur}
placeholder={`{
"OPENAI_API_KEY": "sk-your-api-key-here"
@@ -155,59 +152,72 @@ const CodexConfigEditor: React.FC<CodexConfigEditorProps> = ({
</div>
<div className="space-y-2">
<div className="flex items-center justify-between">
<div className="flex items-start justify-between">
<label
htmlFor="codexConfig"
className="block text-sm font-medium text-gray-900 dark:text-gray-100"
>
config.toml (TOML)
</label>
<label className="inline-flex items-center gap-2 text-sm text-gray-500 dark:text-gray-400 cursor-pointer">
<input
type="checkbox"
checked={useCommonConfig}
onChange={(e) => onCommonConfigToggle(e.target.checked)}
className="w-4 h-4 text-blue-500 bg-white dark:bg-gray-800 border-gray-200 dark:border-gray-700 rounded focus:ring-blue-500 dark:focus:ring-blue-400 focus:ring-2"
/>
</label>
{/* 右侧对齐的双列布局 - 使用flex而非grid以更好控制宽度 */}
<div className="flex gap-3">
{/* 左列VS Code 配置 */}
<div className="flex flex-col items-end space-y-1">
<label className="inline-flex items-center gap-2 text-sm text-gray-500 dark:text-gray-400 cursor-pointer">
<input
type="checkbox"
checked={writeVscodeConfig}
onChange={(e) => setWriteVscodeConfig(e.target.checked)}
className="w-4 h-4 text-blue-500 bg-white dark:bg-gray-800 border-gray-200 dark:border-gray-700 rounded focus:ring-blue-500 dark:focus:ring-blue-400 focus:ring-2"
/>
VS Code
</label>
<div className="h-4 w-48 flex justify-end">
{vscodeSuccess && !vscodeError && (
<p className="text-xs text-emerald-600 dark:text-emerald-400 text-right truncate">
{vscodeSuccess}
</p>
)}
{vscodeError && (
<p className="text-xs text-red-500 dark:text-red-400 text-right truncate" title={vscodeError}>
{vscodeError}
</p>
)}
</div>
</div>
{/* 右列:通用配置 - 不设置宽度,让内容自然收缩 */}
<div className="flex flex-col items-end space-y-1">
<label className="inline-flex items-center gap-2 text-sm text-gray-500 dark:text-gray-400 cursor-pointer">
<input
type="checkbox"
checked={useCommonConfig}
onChange={(e) => onCommonConfigToggle(e.target.checked)}
className="w-4 h-4 text-blue-500 bg-white dark:bg-gray-800 border-gray-200 dark:border-gray-700 rounded focus:ring-blue-500 dark:focus:ring-blue-400 focus:ring-2"
/>
</label>
<button
type="button"
onClick={() => setIsCommonConfigModalOpen(true)}
className="text-xs text-blue-500 dark:text-blue-400 hover:underline whitespace-nowrap"
>
</button>
{commonConfigError && !isCommonConfigModalOpen && (
<p className="text-xs text-red-500 dark:text-red-400 mt-1 max-w-[120px] truncate" title={commonConfigError}>
{commonConfigError}
</p>
)}
</div>
</div>
</div>
<div className="flex items-center justify-end gap-3">
<button
type="button"
onClick={handleWriteVscodeConfig}
disabled={isWritingVscode}
className="text-xs text-blue-500 dark:text-blue-400 hover:underline disabled:opacity-60 disabled:cursor-not-allowed"
>
{isWritingVscode ? "写入中..." : "写入 VS Code 配置"}
</button>
<button
type="button"
onClick={() => setIsCommonConfigModalOpen(true)}
className="text-xs text-blue-500 dark:text-blue-400 hover:underline"
>
</button>
</div>
{commonConfigError && !isCommonConfigModalOpen && (
<p className="text-xs text-red-500 dark:text-red-400 text-right">
{commonConfigError}
</p>
)}
{vscodeError && (
<p className="text-xs text-red-500 dark:text-red-400 text-right">
{vscodeError}
</p>
)}
{vscodeSuccess && !vscodeError && (
<p className="text-xs text-emerald-600 dark:text-emerald-400 text-right">
{vscodeSuccess}
</p>
)}
<textarea
id="codexConfig"
value={configValue}
onChange={(e) => handleConfigChange(e.target.value)}
onChange={(e) => onConfigChange(e.target.value)}
placeholder=""
rows={8}
className="w-full px-3 py-2 border border-gray-200 dark:border-gray-700 dark:bg-gray-800 dark:text-gray-100 rounded-lg text-sm font-mono focus:outline-none focus:ring-2 focus:ring-blue-500/20 dark:focus:ring-blue-400/20 focus:border-blue-500 dark:focus:border-blue-400 transition-colors resize-y min-h-[10rem]"
@@ -260,7 +270,7 @@ const CodexConfigEditor: React.FC<CodexConfigEditorProps> = ({
</p>
<textarea
value={commonConfigSnippet}
onChange={(e) => handleCommonConfigSnippetChange(e.target.value)}
onChange={(e) => onCommonConfigSnippetChange(e.target.value)}
placeholder={`# Common Codex config
# Add your common TOML configuration here`}
rows={12}