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 (
<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
type="button"
onClick={() => handleSwitch("claude")}

View File

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

View File

@@ -29,7 +29,7 @@ const UsageFooter: React.FC<UsageFooterProps> = ({
// 错误状态
if (!usage.success) {
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 gap-2 text-red-500 dark:text-red-400">
<AlertCircle size={14} />
@@ -56,7 +56,7 @@ const UsageFooter: React.FC<UsageFooterProps> = ({
if (usageDataList.length === 0) return null;
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">
<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),
})
}
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>
</div>

View File

@@ -626,7 +626,7 @@ const McpFormModal: React.FC<McpFormModalProps> = ({
<input
id={syncCheckboxId}
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}
onChange={(event) => setSyncOtherSide(event.target.checked)}
/>

View File

@@ -52,7 +52,7 @@ const McpListItem: React.FC<McpListItemProps> = ({
};
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">
{/* 左侧Toggle 开关 */}
<div className="flex-shrink-0">

View File

@@ -230,7 +230,7 @@ const McpWizardModal: React.FC<McpWizardModalProps> = ({
{/* Content */}
<div className="flex-1 overflow-y-auto px-6 py-4 space-y-4">
{/* 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">
{t("mcp.wizard.hint")}
</p>
@@ -252,7 +252,7 @@ const McpWizardModal: React.FC<McpWizardModalProps> = ({
onChange={(e) =>
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">
{t("mcp.wizard.typeStdio")}
@@ -266,7 +266,7 @@ const McpWizardModal: React.FC<McpWizardModalProps> = ({
onChange={(e) =>
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">
{t("mcp.wizard.typeHttp")}
@@ -286,7 +286,7 @@ const McpWizardModal: React.FC<McpWizardModalProps> = ({
onChange={(e) => setWizardTitle(e.target.value)}
onKeyDown={handleKeyDown}
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>
@@ -305,7 +305,7 @@ const McpWizardModal: React.FC<McpWizardModalProps> = ({
onChange={(e) => setWizardCommand(e.target.value)}
onKeyDown={handleKeyDown}
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>
@@ -319,7 +319,7 @@ const McpWizardModal: React.FC<McpWizardModalProps> = ({
onChange={(e) => setWizardArgs(e.target.value)}
placeholder={t("mcp.wizard.argsPlaceholder")}
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>
@@ -333,7 +333,7 @@ const McpWizardModal: React.FC<McpWizardModalProps> = ({
onChange={(e) => setWizardEnv(e.target.value)}
placeholder={t("mcp.wizard.envPlaceholder")}
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>
</>
@@ -354,7 +354,7 @@ const McpWizardModal: React.FC<McpWizardModalProps> = ({
onChange={(e) => setWizardUrl(e.target.value)}
onKeyDown={handleKeyDown}
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>
@@ -368,7 +368,7 @@ const McpWizardModal: React.FC<McpWizardModalProps> = ({
onChange={(e) => setWizardHeaders(e.target.value)}
placeholder={t("mcp.wizard.headersPlaceholder")}
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>
</>
@@ -381,7 +381,7 @@ const McpWizardModal: React.FC<McpWizardModalProps> = ({
wizardEnv ||
wizardUrl ||
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">
{t("mcp.wizard.preview")}
</h3>

View File

@@ -92,10 +92,10 @@ export function ProviderCard({
className={cn(
"rounded-lg bg-card p-4 shadow-sm transition-all duration-200",
isCurrent
? "border-2 border-[hsl(var(--primary))] bg-primary/5"
: "border border-[hsl(var(--border))] hover:border-primary/40",
? "border-active border-border-active bg-primary/5"
: "border border-border-default hover:border-border-hover",
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">
@@ -105,9 +105,9 @@ export function ProviderCard({
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",
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",
dragHandleProps?.isDragging && "border-primary text-primary",
dragHandleProps?.isDragging && "border-border-active text-primary",
)}
aria-label={t("provider.dragHandle")}
{...(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 ${
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"
: "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"
? "bg-gray-100 dark:bg-gray-800 border-border-default text-gray-400 dark:text-gray-500 cursor-not-allowed"
: "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 (

View File

@@ -84,7 +84,7 @@ const ClaudeConfigEditor: React.FC<ClaudeConfigEditorProps> = ({
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"
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")}
</label>

View File

@@ -53,7 +53,7 @@ export const CodexCommonConfigModal: React.FC<CodexCommonConfigModalProps> = ({
# Add your common TOML configuration here`}
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"
autoCorrect="off"
autoCapitalize="none"

View File

@@ -36,7 +36,7 @@ export const CodexAuthSection: React.FC<CodexAuthSectionProps> = ({
placeholder={t("codexConfig.authJsonPlaceholder")}
rows={6}
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"
autoCorrect="off"
autoCapitalize="none"
@@ -98,7 +98,7 @@ export const CodexConfigSection: React.FC<CodexConfigSectionProps> = ({
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"
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")}
</label>
@@ -126,7 +126,7 @@ export const CodexConfigSection: React.FC<CodexConfigSectionProps> = ({
onChange={(e) => onChange(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]"
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"
autoCorrect="off"
autoCapitalize="none"

View File

@@ -239,7 +239,7 @@ export const CodexQuickWizardModal: React.FC<CodexQuickWizardModalProps> = ({
{/* Preview */}
{(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">
{t("codexConfig.configPreview")}
</h3>

View File

@@ -60,7 +60,7 @@ export function CommonConfigEditor({
id="useCommonConfig"
checked={useCommonConfig}
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>
{t("claudeConfig.writeCommonConfig", {

View File

@@ -457,7 +457,7 @@ const EndpointSpeedTest: React.FC<EndpointSpeedTestProps> = ({
type="checkbox"
checked={autoSelect}
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")}
</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 ${
isSelected
? "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">
@@ -595,7 +595,7 @@ const EndpointSpeedTest: React.FC<EndpointSpeedTestProps> = ({
})}
</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")}
</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 ${
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"
: "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"
? "bg-gray-100 dark:bg-gray-800 border-border-default text-gray-400 dark:text-gray-500 cursor-not-allowed"
: "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<{

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",
// 轮廓按钮
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:
"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
ref={ref}
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],
className,
)}

View File

@@ -40,7 +40,7 @@ const DropdownMenuSubContent = React.forwardRef<
<DropdownMenuPrimitive.SubContent
ref={ref}
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,
)}
{...props}
@@ -58,7 +58,7 @@ const DropdownMenuContent = React.forwardRef<
ref={ref}
sideOffset={sideOffset}
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,
)}
{...props}

View File

@@ -9,7 +9,7 @@ const Input = React.forwardRef<HTMLInputElement, InputProps>(
<input
type={type}
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,
)}
ref={ref}

View File

@@ -16,7 +16,7 @@ const SelectTrigger = React.forwardRef<
<SelectPrimitive.Trigger
ref={ref}
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,
)}
{...props}
@@ -37,7 +37,7 @@ const SelectContent = React.forwardRef<
<SelectPrimitive.Content
ref={ref}
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,
)}
position={position}

View File

@@ -8,7 +8,7 @@ const Textarea = React.forwardRef<HTMLTextAreaElement, TextareaProps>(
return (
<textarea
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,
)}
ref={ref}

View File

@@ -122,3 +122,33 @@ html.dark ::-webkit-scrollbar-thumb:hover {
*:focus-visible {
@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);
}
}