refactor: implement unified border design system

- Define custom border utilities in @layer utilities for consistent theming
- Add border-default (1px gray), border-active (2px primary), border-hover (40% primary), and border-dragging (60% primary) classes
- Update all UI components (Input, Select, TextArea, Button, Dialog, Dropdown) to use unified border classes
- Replace hardcoded border colors (gray-200/300/600/700) with theme-responsive border-border-default
- Update provider cards, MCP components, settings, and forms with new border system
- Remove dark mode border overrides to simplify CSS and improve maintainability
- Ensure all borders automatically adapt to light/dark themes via CSS variables
This commit is contained in:
Jason
2025-10-20 23:44:06 +08:00
parent 13acc5323c
commit 3626880663
23 changed files with 74 additions and 44 deletions

View File

@@ -13,7 +13,7 @@ export function AppSwitcher({ activeApp, onSwitch }: AppSwitcherProps) {
}; };
return ( return (
<div className="inline-flex bg-gray-100 dark:bg-gray-800 rounded-lg p-1 gap-1 border border-transparent dark:border-gray-700"> <div className="inline-flex bg-gray-100 dark:bg-gray-800 rounded-lg p-1 gap-1 border border-transparent ">
<button <button
type="button" type="button"
onClick={() => handleSwitch("claude")} onClick={() => handleSwitch("claude")}

View File

@@ -21,7 +21,7 @@ export function UpdateBadge({ className = "", onClick }: UpdateBadgeProps) {
className={` className={`
flex items-center gap-1.5 px-2.5 py-1 flex items-center gap-1.5 px-2.5 py-1
bg-white dark:bg-gray-800 bg-white dark:bg-gray-800
border border-gray-200 dark:border-gray-700 border border-border-default
rounded-lg text-xs rounded-lg text-xs
shadow-sm shadow-sm
transition-all duration-200 transition-all duration-200

View File

@@ -29,7 +29,7 @@ const UsageFooter: React.FC<UsageFooterProps> = ({
// 错误状态 // 错误状态
if (!usage.success) { if (!usage.success) {
return ( return (
<div className="mt-3 pt-3 border-t border-gray-200 dark:border-gray-700"> <div className="mt-3 pt-3 border-t border-border-default ">
<div className="flex items-center justify-between gap-2 text-xs"> <div className="flex items-center justify-between gap-2 text-xs">
<div className="flex items-center gap-2 text-red-500 dark:text-red-400"> <div className="flex items-center gap-2 text-red-500 dark:text-red-400">
<AlertCircle size={14} /> <AlertCircle size={14} />
@@ -56,7 +56,7 @@ const UsageFooter: React.FC<UsageFooterProps> = ({
if (usageDataList.length === 0) return null; if (usageDataList.length === 0) return null;
return ( return (
<div className="mt-3 pt-3 border-t border-gray-200 dark:border-gray-700"> <div className="mt-3 pt-3 border-t border-border-default ">
{/* 标题行:包含刷新按钮 */} {/* 标题行:包含刷新按钮 */}
<div className="flex items-center justify-between mb-2"> <div className="flex items-center justify-between mb-2">
<span className="text-xs text-gray-500 dark:text-gray-400 font-medium"> <span className="text-xs text-gray-500 dark:text-gray-400 font-medium">

View File

@@ -253,7 +253,7 @@ const UsageScriptModal: React.FC<UsageScriptModalProps> = ({
timeout: parseInt(e.target.value), timeout: parseInt(e.target.value),
}) })
} }
className="mt-1 w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded bg-white dark:bg-gray-800 text-gray-900 dark:text-gray-100" className="mt-1 w-full px-3 py-2 border border-border-default dark:border-border-default rounded bg-white dark:bg-gray-800 text-gray-900 dark:text-gray-100"
/> />
</label> </label>
</div> </div>

View File

@@ -626,7 +626,7 @@ const McpFormModal: React.FC<McpFormModalProps> = ({
<input <input
id={syncCheckboxId} id={syncCheckboxId}
type="checkbox" type="checkbox"
className="h-4 w-4 rounded border-gray-300 text-emerald-600 focus:ring-emerald-500 dark:border-gray-600 dark:bg-gray-800" className="h-4 w-4 rounded border-border-default text-emerald-600 focus:ring-emerald-500 dark:bg-gray-800"
checked={syncOtherSide} checked={syncOtherSide}
onChange={(event) => setSyncOtherSide(event.target.checked)} onChange={(event) => setSyncOtherSide(event.target.checked)}
/> />

View File

@@ -52,7 +52,7 @@ const McpListItem: React.FC<McpListItemProps> = ({
}; };
return ( return (
<div className="h-16 rounded-lg border border-border bg-card p-4 transition-[border-color,box-shadow] duration-200 hover:border-primary/40 hover:shadow-sm"> <div className="h-16 rounded-lg border border-border-default bg-card p-4 transition-[border-color,box-shadow] duration-200 hover:border-border-hover hover:shadow-sm">
<div className="flex items-center gap-4 h-full"> <div className="flex items-center gap-4 h-full">
{/* 左侧Toggle 开关 */} {/* 左侧Toggle 开关 */}
<div className="flex-shrink-0"> <div className="flex-shrink-0">

View File

@@ -230,7 +230,7 @@ const McpWizardModal: React.FC<McpWizardModalProps> = ({
{/* Content */} {/* Content */}
<div className="flex-1 overflow-y-auto px-6 py-4 space-y-4"> <div className="flex-1 overflow-y-auto px-6 py-4 space-y-4">
{/* Hint */} {/* Hint */}
<div className="rounded-lg border border-blue-200 bg-blue-50 p-3 dark:border-blue-800 dark:bg-blue-900/20"> <div className="rounded-lg border border-border-active bg-blue-50 p-3 dark:bg-blue-900/20">
<p className="text-sm text-blue-800 dark:text-blue-200"> <p className="text-sm text-blue-800 dark:text-blue-200">
{t("mcp.wizard.hint")} {t("mcp.wizard.hint")}
</p> </p>
@@ -252,7 +252,7 @@ const McpWizardModal: React.FC<McpWizardModalProps> = ({
onChange={(e) => onChange={(e) =>
setWizardType(e.target.value as "stdio" | "http") setWizardType(e.target.value as "stdio" | "http")
} }
className="w-4 h-4 text-emerald-500 bg-white dark:bg-gray-800 border-gray-200 dark:border-gray-700 focus:ring-emerald-500 dark:focus:ring-emerald-400 focus:ring-2" className="w-4 h-4 text-emerald-500 bg-white dark:bg-gray-800 border-border-default focus:ring-emerald-500 dark:focus:ring-emerald-400 focus:ring-2"
/> />
<span className="text-sm text-gray-900 dark:text-gray-100"> <span className="text-sm text-gray-900 dark:text-gray-100">
{t("mcp.wizard.typeStdio")} {t("mcp.wizard.typeStdio")}
@@ -266,7 +266,7 @@ const McpWizardModal: React.FC<McpWizardModalProps> = ({
onChange={(e) => onChange={(e) =>
setWizardType(e.target.value as "stdio" | "http") setWizardType(e.target.value as "stdio" | "http")
} }
className="w-4 h-4 text-emerald-500 bg-white dark:bg-gray-800 border-gray-200 dark:border-gray-700 focus:ring-emerald-500 dark:focus:ring-emerald-400 focus:ring-2" className="w-4 h-4 text-emerald-500 bg-white dark:bg-gray-800 border-border-default focus:ring-emerald-500 dark:focus:ring-emerald-400 focus:ring-2"
/> />
<span className="text-sm text-gray-900 dark:text-gray-100"> <span className="text-sm text-gray-900 dark:text-gray-100">
{t("mcp.wizard.typeHttp")} {t("mcp.wizard.typeHttp")}
@@ -286,7 +286,7 @@ const McpWizardModal: React.FC<McpWizardModalProps> = ({
onChange={(e) => setWizardTitle(e.target.value)} onChange={(e) => setWizardTitle(e.target.value)}
onKeyDown={handleKeyDown} onKeyDown={handleKeyDown}
placeholder={t("mcp.form.titlePlaceholder")} placeholder={t("mcp.form.titlePlaceholder")}
className="w-full rounded-lg border border-gray-200 px-3 py-2 text-sm font-mono focus:outline-none focus:ring-2 focus:ring-emerald-500/20 dark:border-gray-700 dark:bg-gray-800 dark:text-gray-100" className="w-full rounded-lg border border-border-default px-3 py-2 text-sm font-mono focus:outline-none focus:ring-2 focus:ring-emerald-500/20 dark:bg-gray-800 dark:text-gray-100"
/> />
</div> </div>
@@ -305,7 +305,7 @@ const McpWizardModal: React.FC<McpWizardModalProps> = ({
onChange={(e) => setWizardCommand(e.target.value)} onChange={(e) => setWizardCommand(e.target.value)}
onKeyDown={handleKeyDown} onKeyDown={handleKeyDown}
placeholder={t("mcp.wizard.commandPlaceholder")} placeholder={t("mcp.wizard.commandPlaceholder")}
className="w-full rounded-lg border border-gray-200 px-3 py-2 text-sm font-mono focus:outline-none focus:ring-2 focus:ring-emerald-500/20 dark:border-gray-700 dark:bg-gray-800 dark:text-gray-100" className="w-full rounded-lg border border-border-default px-3 py-2 text-sm font-mono focus:outline-none focus:ring-2 focus:ring-emerald-500/20 dark:bg-gray-800 dark:text-gray-100"
/> />
</div> </div>
@@ -319,7 +319,7 @@ const McpWizardModal: React.FC<McpWizardModalProps> = ({
onChange={(e) => setWizardArgs(e.target.value)} onChange={(e) => setWizardArgs(e.target.value)}
placeholder={t("mcp.wizard.argsPlaceholder")} placeholder={t("mcp.wizard.argsPlaceholder")}
rows={3} rows={3}
className="w-full rounded-lg border border-gray-200 px-3 py-2 text-sm font-mono focus:outline-none focus:ring-2 focus:ring-emerald-500/20 dark:border-gray-700 dark:bg-gray-800 dark:text-gray-100 resize-y" className="w-full rounded-lg border border-border-default px-3 py-2 text-sm font-mono focus:outline-none focus:ring-2 focus:ring-emerald-500/20 dark:bg-gray-800 dark:text-gray-100 resize-y"
/> />
</div> </div>
@@ -333,7 +333,7 @@ const McpWizardModal: React.FC<McpWizardModalProps> = ({
onChange={(e) => setWizardEnv(e.target.value)} onChange={(e) => setWizardEnv(e.target.value)}
placeholder={t("mcp.wizard.envPlaceholder")} placeholder={t("mcp.wizard.envPlaceholder")}
rows={3} rows={3}
className="w-full rounded-lg border border-gray-200 px-3 py-2 text-sm font-mono focus:outline-none focus:ring-2 focus:ring-emerald-500/20 dark:border-gray-700 dark:bg-gray-800 dark:text-gray-100 resize-y" className="w-full rounded-lg border border-border-default px-3 py-2 text-sm font-mono focus:outline-none focus:ring-2 focus:ring-emerald-500/20 dark:bg-gray-800 dark:text-gray-100 resize-y"
/> />
</div> </div>
</> </>
@@ -354,7 +354,7 @@ const McpWizardModal: React.FC<McpWizardModalProps> = ({
onChange={(e) => setWizardUrl(e.target.value)} onChange={(e) => setWizardUrl(e.target.value)}
onKeyDown={handleKeyDown} onKeyDown={handleKeyDown}
placeholder={t("mcp.wizard.urlPlaceholder")} placeholder={t("mcp.wizard.urlPlaceholder")}
className="w-full rounded-lg border border-gray-200 px-3 py-2 text-sm font-mono focus:outline-none focus:ring-2 focus:ring-emerald-500/20 dark:border-gray-700 dark:bg-gray-800 dark:text-gray-100" className="w-full rounded-lg border border-border-default px-3 py-2 text-sm font-mono focus:outline-none focus:ring-2 focus:ring-emerald-500/20 dark:bg-gray-800 dark:text-gray-100"
/> />
</div> </div>
@@ -368,7 +368,7 @@ const McpWizardModal: React.FC<McpWizardModalProps> = ({
onChange={(e) => setWizardHeaders(e.target.value)} onChange={(e) => setWizardHeaders(e.target.value)}
placeholder={t("mcp.wizard.headersPlaceholder")} placeholder={t("mcp.wizard.headersPlaceholder")}
rows={3} rows={3}
className="w-full rounded-lg border border-gray-200 px-3 py-2 text-sm font-mono focus:outline-none focus:ring-2 focus:ring-emerald-500/20 dark:border-gray-700 dark:bg-gray-800 dark:text-gray-100 resize-y" className="w-full rounded-lg border border-border-default px-3 py-2 text-sm font-mono focus:outline-none focus:ring-2 focus:ring-emerald-500/20 dark:bg-gray-800 dark:text-gray-100 resize-y"
/> />
</div> </div>
</> </>
@@ -381,7 +381,7 @@ const McpWizardModal: React.FC<McpWizardModalProps> = ({
wizardEnv || wizardEnv ||
wizardUrl || wizardUrl ||
wizardHeaders) && ( wizardHeaders) && (
<div className="space-y-2 border-t border-gray-200 pt-4 dark:border-gray-700"> <div className="space-y-2 border-t border-border-default pt-4 ">
<h3 className="text-sm font-medium text-gray-900 dark:text-gray-100"> <h3 className="text-sm font-medium text-gray-900 dark:text-gray-100">
{t("mcp.wizard.preview")} {t("mcp.wizard.preview")}
</h3> </h3>

View File

@@ -92,10 +92,10 @@ export function ProviderCard({
className={cn( className={cn(
"rounded-lg bg-card p-4 shadow-sm transition-all duration-200", "rounded-lg bg-card p-4 shadow-sm transition-all duration-200",
isCurrent isCurrent
? "border-2 border-[hsl(var(--primary))] bg-primary/5" ? "border-active border-border-active bg-primary/5"
: "border border-[hsl(var(--border))] hover:border-primary/40", : "border border-border-default hover:border-border-hover",
dragHandleProps?.isDragging && dragHandleProps?.isDragging &&
"cursor-grabbing border-2 border-[hsl(var(--primary)/.6)] shadow-lg", "cursor-grabbing border-active border-border-dragging shadow-lg",
)} )}
> >
<div className="flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between"> <div className="flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between">
@@ -105,9 +105,9 @@ export function ProviderCard({
className={cn( className={cn(
"mt-1 flex h-8 flex-shrink-0 items-center justify-center overflow-hidden rounded-md border text-muted-foreground transition-all duration-200", "mt-1 flex h-8 flex-shrink-0 items-center justify-center overflow-hidden rounded-md border text-muted-foreground transition-all duration-200",
isEditMode isEditMode
? "w-8 mr-3 border-muted hover:border-primary hover:text-foreground opacity-100" ? "w-8 mr-3 border-muted hover:border-border-hover hover:text-foreground opacity-100"
: "w-0 mr-0 border-transparent opacity-0 pointer-events-none", : "w-0 mr-0 border-transparent opacity-0 pointer-events-none",
dragHandleProps?.isDragging && "border-primary text-primary", dragHandleProps?.isDragging && "border-border-active text-primary",
)} )}
aria-label={t("provider.dragHandle")} aria-label={t("provider.dragHandle")}
{...(dragHandleProps?.attributes ?? {})} {...(dragHandleProps?.attributes ?? {})}

View File

@@ -30,8 +30,8 @@ const ApiKeyInput: React.FC<ApiKeyInputProps> = ({
const inputClass = `w-full px-3 py-2 pr-10 border rounded-lg text-sm transition-colors ${ const inputClass = `w-full px-3 py-2 pr-10 border rounded-lg text-sm transition-colors ${
disabled disabled
? "bg-gray-100 dark:bg-gray-800 border-gray-200 dark:border-gray-700 text-gray-400 dark:text-gray-500 cursor-not-allowed" ? "bg-gray-100 dark:bg-gray-800 border-border-default text-gray-400 dark:text-gray-500 cursor-not-allowed"
: "border-gray-200 dark:border-gray-700 dark:bg-gray-800 dark:text-gray-100 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" : "border-border-default dark:bg-gray-800 dark:text-gray-100 focus:outline-none focus:ring-2 focus:ring-blue-500/20 dark:focus:ring-blue-400/20 focus:border-border-active "
}`; }`;
return ( return (

View File

@@ -84,7 +84,7 @@ const ClaudeConfigEditor: React.FC<ClaudeConfigEditorProps> = ({
type="checkbox" type="checkbox"
checked={useCommonConfig} checked={useCommonConfig}
onChange={(e) => onCommonConfigToggle(e.target.checked)} 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" className="w-4 h-4 text-blue-500 bg-white dark:bg-gray-800 border-border-default rounded focus:ring-blue-500 dark:focus:ring-blue-400 focus:ring-2"
/> />
{t("claudeConfig.writeCommonConfig")} {t("claudeConfig.writeCommonConfig")}
</label> </label>

View File

@@ -53,7 +53,7 @@ export const CodexCommonConfigModal: React.FC<CodexCommonConfigModalProps> = ({
# Add your common TOML configuration here`} # Add your common TOML configuration here`}
rows={12} rows={12}
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" className="w-full px-3 py-2 border border-border-default 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-border-active transition-colors resize-y"
autoComplete="off" autoComplete="off"
autoCorrect="off" autoCorrect="off"
autoCapitalize="none" autoCapitalize="none"

View File

@@ -36,7 +36,7 @@ export const CodexAuthSection: React.FC<CodexAuthSectionProps> = ({
placeholder={t("codexConfig.authJsonPlaceholder")} placeholder={t("codexConfig.authJsonPlaceholder")}
rows={6} rows={6}
required required
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-[8rem]" className="w-full px-3 py-2 border border-border-default 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-border-active transition-colors resize-y min-h-[8rem]"
autoComplete="off" autoComplete="off"
autoCorrect="off" autoCorrect="off"
autoCapitalize="none" autoCapitalize="none"
@@ -98,7 +98,7 @@ export const CodexConfigSection: React.FC<CodexConfigSectionProps> = ({
type="checkbox" type="checkbox"
checked={useCommonConfig} checked={useCommonConfig}
onChange={(e) => onCommonConfigToggle(e.target.checked)} 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" className="w-4 h-4 text-blue-500 bg-white dark:bg-gray-800 border-border-default rounded focus:ring-blue-500 dark:focus:ring-blue-400 focus:ring-2"
/> />
{t("codexConfig.writeCommonConfig")} {t("codexConfig.writeCommonConfig")}
</label> </label>
@@ -126,7 +126,7 @@ export const CodexConfigSection: React.FC<CodexConfigSectionProps> = ({
onChange={(e) => onChange(e.target.value)} onChange={(e) => onChange(e.target.value)}
placeholder="" placeholder=""
rows={8} 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]" className="w-full px-3 py-2 border border-border-default 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-border-active transition-colors resize-y min-h-[10rem]"
autoComplete="off" autoComplete="off"
autoCorrect="off" autoCorrect="off"
autoCapitalize="none" autoCapitalize="none"

View File

@@ -239,7 +239,7 @@ export const CodexQuickWizardModal: React.FC<CodexQuickWizardModalProps> = ({
{/* Preview */} {/* Preview */}
{(templateApiKey || templateProviderName || templateBaseUrl) && ( {(templateApiKey || templateProviderName || templateBaseUrl) && (
<div className="space-y-2 border-t border-gray-200 pt-4 dark:border-gray-700"> <div className="space-y-2 border-t border-border-default pt-4 ">
<h3 className="text-sm font-medium text-gray-900 dark:text-gray-100"> <h3 className="text-sm font-medium text-gray-900 dark:text-gray-100">
{t("codexConfig.configPreview")} {t("codexConfig.configPreview")}
</h3> </h3>

View File

@@ -60,7 +60,7 @@ export function CommonConfigEditor({
id="useCommonConfig" id="useCommonConfig"
checked={useCommonConfig} checked={useCommonConfig}
onChange={(e) => onCommonConfigToggle(e.target.checked)} onChange={(e) => onCommonConfigToggle(e.target.checked)}
className="w-4 h-4 text-blue-500 bg-white dark:bg-gray-800 border-gray-300 dark:border-gray-600 rounded focus:ring-blue-500 dark:focus:ring-blue-400 focus:ring-2" className="w-4 h-4 text-blue-500 bg-white dark:bg-gray-800 border-border-default rounded focus:ring-blue-500 dark:focus:ring-blue-400 focus:ring-2"
/> />
<span> <span>
{t("claudeConfig.writeCommonConfig", { {t("claudeConfig.writeCommonConfig", {

View File

@@ -457,7 +457,7 @@ const EndpointSpeedTest: React.FC<EndpointSpeedTestProps> = ({
type="checkbox" type="checkbox"
checked={autoSelect} checked={autoSelect}
onChange={(event) => setAutoSelect(event.target.checked)} onChange={(event) => setAutoSelect(event.target.checked)}
className="h-3.5 w-3.5 rounded border-gray-300 dark:border-gray-600" className="h-3.5 w-3.5 rounded border-border-default "
/> />
{t("endpointTest.autoSelect")} {t("endpointTest.autoSelect")}
</label> </label>
@@ -530,7 +530,7 @@ const EndpointSpeedTest: React.FC<EndpointSpeedTestProps> = ({
className={`group flex cursor-pointer items-center justify-between px-3 py-2.5 rounded-lg border transition ${ className={`group flex cursor-pointer items-center justify-between px-3 py-2.5 rounded-lg border transition ${
isSelected isSelected
? "border-blue-500 bg-blue-50 dark:border-blue-500 dark:bg-blue-900/20" ? "border-blue-500 bg-blue-50 dark:border-blue-500 dark:bg-blue-900/20"
: "border-gray-200 bg-white hover:border-gray-300 hover:bg-gray-50 dark:border-gray-700 dark:bg-gray-900 dark:hover:border-gray-600 dark:hover:bg-gray-800" : "border-border-default bg-white hover:border-border-default hover:bg-gray-50 dark:bg-gray-900 dark:hover:border-gray-600 dark:hover:bg-gray-800"
}`} }`}
> >
<div className="flex min-w-0 flex-1 items-center gap-3"> <div className="flex min-w-0 flex-1 items-center gap-3">
@@ -595,7 +595,7 @@ const EndpointSpeedTest: React.FC<EndpointSpeedTestProps> = ({
})} })}
</div> </div>
) : ( ) : (
<div className="rounded-md border border-dashed border-gray-200 bg-gray-50 py-8 text-center text-xs text-gray-500 dark:border-gray-700 dark:bg-gray-900 dark:text-gray-400"> <div className="rounded-md border border-dashed border-border-default bg-gray-50 py-8 text-center text-xs text-gray-500 dark:bg-gray-900 dark:text-gray-400">
{t("endpointTest.noEndpoints")} {t("endpointTest.noEndpoints")}
</div> </div>
)} )}

View File

@@ -98,8 +98,8 @@ const KimiModelSelector: React.FC<KimiModelSelectorProps> = ({
const selectClass = `w-full px-3 py-2 border rounded-lg text-sm transition-colors appearance-none bg-white dark:bg-gray-800 ${ const selectClass = `w-full px-3 py-2 border rounded-lg text-sm transition-colors appearance-none bg-white dark:bg-gray-800 ${
disabled disabled
? "bg-gray-100 dark:bg-gray-800 border-gray-200 dark:border-gray-700 text-gray-400 dark:text-gray-500 cursor-not-allowed" ? "bg-gray-100 dark:bg-gray-800 border-border-default text-gray-400 dark:text-gray-500 cursor-not-allowed"
: "border-gray-200 dark:border-gray-700 dark:text-gray-100 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" : "border-border-default dark:text-gray-100 focus:outline-none focus:ring-2 focus:ring-blue-500/20 dark:focus:ring-blue-400/20 focus:border-border-active "
}`; }`;
const ModelSelect: React.FC<{ const ModelSelect: React.FC<{

View File

@@ -16,7 +16,7 @@ const buttonVariants = cva(
"bg-red-500 text-white hover:bg-red-600 dark:bg-red-600 dark:hover:bg-red-700", "bg-red-500 text-white hover:bg-red-600 dark:bg-red-600 dark:hover:bg-red-700",
// 轮廓按钮 // 轮廓按钮
outline: outline:
"border border-gray-200 bg-background hover:bg-gray-100 dark:border-gray-700 dark:hover:bg-gray-800", "border border-border-default bg-background hover:bg-gray-100 hover:border-border-hover dark:hover:bg-gray-800",
// 次按钮:灰色(对应旧版 secondary // 次按钮:灰色(对应旧版 secondary
secondary: secondary:
"text-gray-500 hover:bg-gray-100 dark:text-gray-400 dark:hover:bg-gray-800 dark:hover:text-gray-200", "text-gray-500 hover:bg-gray-100 dark:text-gray-400 dark:hover:bg-gray-800 dark:hover:text-gray-200",

View File

@@ -55,7 +55,7 @@ const DialogContent = React.forwardRef<
<DialogPrimitive.Content <DialogPrimitive.Content
ref={ref} ref={ref}
className={cn( className={cn(
"fixed left-1/2 top-1/2 flex flex-col w-full max-w-lg max-h-[90vh] translate-x-[-50%] translate-y-[-50%] border bg-white dark:bg-gray-900 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg", "fixed left-1/2 top-1/2 flex flex-col w-full max-w-lg max-h-[90vh] translate-x-[-50%] translate-y-[-50%] border border-border-default bg-white dark:bg-gray-900 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg",
zIndexMap[zIndex], zIndexMap[zIndex],
className, className,
)} )}

View File

@@ -40,7 +40,7 @@ const DropdownMenuSubContent = React.forwardRef<
<DropdownMenuPrimitive.SubContent <DropdownMenuPrimitive.SubContent
ref={ref} ref={ref}
className={cn( className={cn(
"z-50 min-w-[8rem] rounded-md border bg-popover p-1 text-popover-foreground shadow-md", "z-50 min-w-[8rem] rounded-md border border-border-default bg-popover p-1 text-popover-foreground shadow-md",
className, className,
)} )}
{...props} {...props}
@@ -58,7 +58,7 @@ const DropdownMenuContent = React.forwardRef<
ref={ref} ref={ref}
sideOffset={sideOffset} sideOffset={sideOffset}
className={cn( className={cn(
"z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2", "z-50 min-w-[8rem] overflow-hidden rounded-md border border-border-default bg-popover p-1 text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
className, className,
)} )}
{...props} {...props}

View File

@@ -9,7 +9,7 @@ const Input = React.forwardRef<HTMLInputElement, InputProps>(
<input <input
type={type} type={type}
className={cn( className={cn(
"flex h-9 w-full rounded-md border border-input bg-background px-3 py-1 text-sm shadow-sm transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50", "flex h-9 w-full rounded-md border border-border-default bg-background px-3 py-1 text-sm shadow-sm transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:outline-none focus-visible:border-border-active disabled:cursor-not-allowed disabled:opacity-50",
className, className,
)} )}
ref={ref} ref={ref}

View File

@@ -16,7 +16,7 @@ const SelectTrigger = React.forwardRef<
<SelectPrimitive.Trigger <SelectPrimitive.Trigger
ref={ref} ref={ref}
className={cn( className={cn(
"flex h-9 w-full items-center justify-between whitespace-nowrap rounded-md border border-input bg-background px-3 py-2 text-sm shadow-sm ring-offset-background placeholder:text-muted-foreground focus:outline-none focus:ring-1 focus:ring-ring disabled:cursor-not-allowed disabled:opacity-50", "flex h-9 w-full items-center justify-between whitespace-nowrap rounded-md border border-border-default bg-background px-3 py-2 text-sm shadow-sm ring-offset-background placeholder:text-muted-foreground focus:outline-none focus:border-border-active disabled:cursor-not-allowed disabled:opacity-50",
className, className,
)} )}
{...props} {...props}
@@ -37,7 +37,7 @@ const SelectContent = React.forwardRef<
<SelectPrimitive.Content <SelectPrimitive.Content
ref={ref} ref={ref}
className={cn( className={cn(
"relative z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2", "relative z-50 min-w-[8rem] overflow-hidden rounded-md border border-border-default bg-popover text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
className, className,
)} )}
position={position} position={position}

View File

@@ -8,7 +8,7 @@ const Textarea = React.forwardRef<HTMLTextAreaElement, TextareaProps>(
return ( return (
<textarea <textarea
className={cn( className={cn(
"flex min-h-[80px] w-full rounded-md border border-input bg-background px-3 py-2 text-sm shadow-sm placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50", "flex min-h-[80px] w-full rounded-md border border-border-default bg-background px-3 py-2 text-sm shadow-sm placeholder:text-muted-foreground focus-visible:outline-none focus-visible:border-border-active disabled:cursor-not-allowed disabled:opacity-50",
className, className,
)} )}
ref={ref} ref={ref}

View File

@@ -122,3 +122,33 @@ html.dark ::-webkit-scrollbar-thumb:hover {
*:focus-visible { *:focus-visible {
@apply outline-2 outline-blue-500 outline-offset-2; @apply outline-2 outline-blue-500 outline-offset-2;
} }
/* 统一边框设计系统 - 使用工具类定义 */
@layer utilities {
/* 默认边框1px使用主题边框颜色 */
.border-default {
border-width: 1px;
border-color: hsl(var(--border));
}
/* 激活边框2px使用主色 */
.border-active {
border-width: 2px;
}
.border-border-default {
border-color: hsl(var(--border));
}
.border-border-active {
border-color: hsl(var(--primary));
}
.border-border-hover {
border-color: hsl(var(--primary) / 0.4);
}
.border-border-dragging {
border-color: hsl(var(--primary) / 0.6);
}
}