refactor: unify speed test panel UI with project design system

UI improvements:
- Update modal border radius from rounded-lg to rounded-xl
- Unify header padding from px-6 py-4 to p-6
- Change speed test button color to blue theme (bg-blue-500) for consistency
- Update footer background from bg-gray-50 to bg-gray-100
- Style "Done" button as primary action button with blue theme
- Adjust footer button spacing and hover states

Simplify endpoint display:
- Remove endpoint labels (e.g., "Current Address", "Custom 1")
- Display only URL for cleaner interface
- Clean up all label-related logic:
  * Remove label field from EndpointCandidate interface
  * Remove label generation in buildInitialEntries function
  * Remove label handling in useEffect merge logic
  * Remove label generation in handleAddEndpoint
  * Remove label parameters from claudeSpeedTestEndpoints
  * Remove label parameters from codexSpeedTestEndpoints
This commit is contained in:
Jason
2025-10-06 21:14:54 +08:00
parent 1c9a9af11c
commit b4b176580e
2 changed files with 23 additions and 70 deletions

View File

@@ -1123,21 +1123,21 @@ const ProviderForm: React.FC<ProviderFormProps> = ({
const claudeSpeedTestEndpoints = useMemo<EndpointCandidate[]>(() => { const claudeSpeedTestEndpoints = useMemo<EndpointCandidate[]>(() => {
if (isCodex) return []; if (isCodex) return [];
const map = new Map<string, EndpointCandidate>(); const map = new Map<string, EndpointCandidate>();
const add = (url?: string, label?: string) => { const add = (url?: string) => {
if (!url) return; if (!url) return;
const sanitized = url.trim().replace(/\/+$/, ""); const sanitized = url.trim().replace(/\/+$/, "");
if (!sanitized || map.has(sanitized)) return; if (!sanitized || map.has(sanitized)) return;
map.set(sanitized, { url: sanitized, label }); map.set(sanitized, { url: sanitized });
}; };
if (baseUrl) { if (baseUrl) {
add(baseUrl, "当前地址"); add(baseUrl);
} }
if (initialData && typeof initialData.settingsConfig === "object") { if (initialData && typeof initialData.settingsConfig === "object") {
const envUrl = (initialData.settingsConfig as any)?.env?.ANTHROPIC_BASE_URL; const envUrl = (initialData.settingsConfig as any)?.env?.ANTHROPIC_BASE_URL;
if (typeof envUrl === "string") { if (typeof envUrl === "string") {
add(envUrl, envUrl === baseUrl ? "当前地址" : "历史地址"); add(envUrl);
} }
} }
@@ -1149,7 +1149,7 @@ const ProviderForm: React.FC<ProviderFormProps> = ({
const preset = providerPresets[selectedPreset]; const preset = providerPresets[selectedPreset];
const presetEnv = (preset.settingsConfig as any)?.env?.ANTHROPIC_BASE_URL; const presetEnv = (preset.settingsConfig as any)?.env?.ANTHROPIC_BASE_URL;
if (typeof presetEnv === "string") { if (typeof presetEnv === "string") {
add(presetEnv, presetEnv === baseUrl ? "当前地址" : "预设地址"); add(presetEnv);
} }
} }
@@ -1159,15 +1159,15 @@ const ProviderForm: React.FC<ProviderFormProps> = ({
const codexSpeedTestEndpoints = useMemo<EndpointCandidate[]>(() => { const codexSpeedTestEndpoints = useMemo<EndpointCandidate[]>(() => {
if (!isCodex) return []; if (!isCodex) return [];
const map = new Map<string, EndpointCandidate>(); const map = new Map<string, EndpointCandidate>();
const add = (url?: string, label?: string) => { const add = (url?: string) => {
if (!url) return; if (!url) return;
const sanitized = url.trim().replace(/\/+$/, ""); const sanitized = url.trim().replace(/\/+$/, "");
if (!sanitized || map.has(sanitized)) return; if (!sanitized || map.has(sanitized)) return;
map.set(sanitized, { url: sanitized, label }); map.set(sanitized, { url: sanitized });
}; };
if (codexBaseUrl) { if (codexBaseUrl) {
add(codexBaseUrl, "当前地址"); add(codexBaseUrl);
} }
const initialCodexConfig = const initialCodexConfig =
@@ -1176,7 +1176,7 @@ const ProviderForm: React.FC<ProviderFormProps> = ({
: ""; : "";
const existing = extractCodexBaseUrl(initialCodexConfig); const existing = extractCodexBaseUrl(initialCodexConfig);
if (existing) { if (existing) {
add(existing, existing === codexBaseUrl ? "当前地址" : "历史地址"); add(existing);
} }
if ( if (
@@ -1187,7 +1187,7 @@ const ProviderForm: React.FC<ProviderFormProps> = ({
const presetConfig = codexProviderPresets[selectedCodexPreset]?.config; const presetConfig = codexProviderPresets[selectedCodexPreset]?.config;
const presetBase = extractCodexBaseUrl(presetConfig); const presetBase = extractCodexBaseUrl(presetConfig);
if (presetBase) { if (presetBase) {
add(presetBase, presetBase === codexBaseUrl ? "当前地址" : "预设地址"); add(presetBase);
} }
} }

View File

@@ -7,7 +7,6 @@ import type { AppType } from "../../lib/tauri-api";
export interface EndpointCandidate { export interface EndpointCandidate {
id?: string; id?: string;
url: string; url: string;
label?: string;
isCustom?: boolean; isCustom?: boolean;
} }
@@ -40,25 +39,11 @@ const buildInitialEntries = (
const addCandidate = (candidate: EndpointCandidate) => { const addCandidate = (candidate: EndpointCandidate) => {
const sanitized = candidate.url ? normalizeEndpointUrl(candidate.url) : ""; const sanitized = candidate.url ? normalizeEndpointUrl(candidate.url) : "";
if (!sanitized) return; if (!sanitized) return;
if (map.has(sanitized)) { if (map.has(sanitized)) return;
const existing = map.get(sanitized)!;
if (candidate.label && candidate.label !== existing.label) {
map.set(sanitized, { ...existing, label: candidate.label });
}
return;
}
const index = map.size;
const label =
candidate.label ??
(candidate.isCustom
? `自定义 ${index + 1}`
: index === 0
? "默认地址"
: `候选 ${index + 1}`);
map.set(sanitized, { map.set(sanitized, {
id: candidate.id ?? randomId(), id: candidate.id ?? randomId(),
url: sanitized, url: sanitized,
label,
isCustom: candidate.isCustom ?? false, isCustom: candidate.isCustom ?? false,
latency: null, latency: null,
status: undefined, status: undefined,
@@ -70,7 +55,7 @@ const buildInitialEntries = (
const selectedUrl = normalizeEndpointUrl(selected); const selectedUrl = normalizeEndpointUrl(selected);
if (selectedUrl && !map.has(selectedUrl)) { if (selectedUrl && !map.has(selectedUrl)) {
addCandidate({ url: selectedUrl, label: "当前地址", isCustom: true }); addCandidate({ url: selectedUrl, isCustom: true });
} }
return Array.from(map.values()); return Array.from(map.values());
@@ -112,25 +97,11 @@ const EndpointSpeedTest: React.FC<EndpointSpeedTestProps> = ({
: ""; : "";
if (!sanitized) return; if (!sanitized) return;
const existing = map.get(sanitized); const existing = map.get(sanitized);
if (existing) { if (existing) return;
if (candidate.label && candidate.label !== existing.label) {
map.set(sanitized, { ...existing, label: candidate.label });
changed = true;
}
return;
}
const index = map.size;
const label =
candidate.label ??
(candidate.isCustom
? `自定义 ${index + 1}`
: index === 0
? "默认地址"
: `候选 ${index + 1}`);
map.set(sanitized, { map.set(sanitized, {
id: candidate.id ?? randomId(), id: candidate.id ?? randomId(),
url: sanitized, url: sanitized,
label,
isCustom: candidate.isCustom ?? false, isCustom: candidate.isCustom ?? false,
latency: null, latency: null,
status: undefined, status: undefined,
@@ -141,19 +112,8 @@ const EndpointSpeedTest: React.FC<EndpointSpeedTestProps> = ({
initialEndpoints.forEach(mergeCandidate); initialEndpoints.forEach(mergeCandidate);
if (normalizedSelected) { if (normalizedSelected && !map.has(normalizedSelected)) {
const existing = map.get(normalizedSelected); mergeCandidate({ url: normalizedSelected, isCustom: true });
if (existing) {
if (existing.label !== "当前地址") {
map.set(normalizedSelected, {
...existing,
label: existing.isCustom ? existing.label : "当前地址",
});
changed = true;
}
} else {
mergeCandidate({ url: normalizedSelected, label: "当前地址", isCustom: true });
}
} }
if (!changed) { if (!changed) {
@@ -204,13 +164,11 @@ const EndpointSpeedTest: React.FC<EndpointSpeedTestProps> = ({
setAddError("该地址已存在"); setAddError("该地址已存在");
return prev; return prev;
} }
const customCount = prev.filter((entry) => entry.isCustom).length;
return [ return [
...prev, ...prev,
{ {
id: randomId(), id: randomId(),
url: sanitized, url: sanitized,
label: `自定义 ${customCount + 1}`,
isCustom: true, isCustom: true,
latency: null, latency: null,
status: undefined, status: undefined,
@@ -341,9 +299,9 @@ const EndpointSpeedTest: React.FC<EndpointSpeedTestProps> = ({
/> />
{/* Modal */} {/* Modal */}
<div className="relative bg-white dark:bg-gray-900 rounded-lg shadow-lg w-full max-w-2xl mx-4 max-h-[80vh] overflow-hidden flex flex-col"> <div className="relative bg-white dark:bg-gray-900 rounded-xl shadow-lg w-full max-w-2xl mx-4 max-h-[80vh] overflow-hidden flex flex-col">
{/* Header */} {/* Header */}
<div className="flex items-center justify-between px-6 py-4 border-b border-gray-200 dark:border-gray-800"> <div className="flex items-center justify-between p-6 border-b border-gray-200 dark:border-gray-800">
<h3 className="text-base font-medium text-gray-900 dark:text-gray-100"> <h3 className="text-base font-medium text-gray-900 dark:text-gray-100">
</h3> </h3>
@@ -378,7 +336,7 @@ const EndpointSpeedTest: React.FC<EndpointSpeedTestProps> = ({
type="button" type="button"
onClick={runSpeedTest} onClick={runSpeedTest}
disabled={isTesting || !hasEndpoints} disabled={isTesting || !hasEndpoints}
className="flex h-7 items-center gap-1.5 rounded-md bg-gray-900 px-2.5 text-xs font-medium text-white transition hover:bg-gray-800 disabled:cursor-not-allowed disabled:opacity-40 dark:bg-gray-100 dark:text-gray-900 dark:hover:bg-gray-200" className="flex h-7 items-center gap-1.5 rounded-md bg-blue-500 px-2.5 text-xs font-medium text-white transition hover:bg-blue-600 disabled:cursor-not-allowed disabled:opacity-40 dark:bg-blue-600 dark:hover:bg-blue-700"
> >
{isTesting ? ( {isTesting ? (
<> <>
@@ -456,12 +414,7 @@ const EndpointSpeedTest: React.FC<EndpointSpeedTestProps> = ({
{/* 内容 */} {/* 内容 */}
<div className="min-w-0 flex-1"> <div className="min-w-0 flex-1">
<div className="flex items-center gap-2"> <div className="truncate text-sm text-gray-900 dark:text-gray-100">
<span className="text-sm font-medium text-gray-900 dark:text-gray-100">
{entry.label}
</span>
</div>
<div className="mt-0.5 truncate text-xs text-gray-500 dark:text-gray-400">
{entry.url} {entry.url}
</div> </div>
</div> </div>
@@ -516,11 +469,11 @@ const EndpointSpeedTest: React.FC<EndpointSpeedTestProps> = ({
</div> </div>
{/* Footer */} {/* Footer */}
<div className="flex items-center justify-end px-6 py-4 border-t border-gray-200 dark:border-gray-800 bg-gray-50 dark:bg-gray-800"> <div className="flex items-center justify-end gap-3 p-6 border-t border-gray-200 dark:border-gray-800 bg-gray-100 dark:bg-gray-800">
<button <button
type="button" type="button"
onClick={onClose} onClick={onClose}
className="px-4 py-2 text-sm font-medium text-gray-900 dark:text-gray-100 hover:bg-gray-100 dark:hover:bg-gray-700 rounded-md transition-colors" className="px-4 py-2 bg-blue-500 dark:bg-blue-600 text-white rounded-lg hover:bg-blue-600 dark:hover:bg-blue-700 transition-colors text-sm font-medium"
> >
</button> </button>