feat(deeplink): add Claude model fields support and enhance import dialog

- Add Claude-specific model field support in deeplink import:
  * Support model (ANTHROPIC_MODEL) - general default model
  * Support haikuModel (ANTHROPIC_DEFAULT_HAIKU_MODEL)
  * Support sonnetModel (ANTHROPIC_DEFAULT_SONNET_MODEL)
  * Support opusModel (ANTHROPIC_DEFAULT_OPUS_MODEL)
  * Backend: Update DeepLinkImportRequest struct to include optional model fields
  * Frontend: Add TypeScript type definitions for new model parameters

- Enhance deeplink demo page (deplink.html):
  * Add 5 new Claude configuration examples showcasing different model setups
  * Add parameter documentation with required/optional tags
  * Include basic config (no models), single model, complete 4-model, partial models, and third-party provider examples
  * Improve visual design with param-list component and color-coded badges
  * Add detailed descriptions for each configuration scenario

- Redesign DeepLinkImportDialog layout:
  * Switch from 3-column to compact 2-column grid layout
  * Reduce dialog width from 500px to 650px for better content display
  * Add dedicated section for Claude model configurations with blue highlight box
  * Use uppercase labels and smaller text for more information density
  * Add truncation and tooltips for long URLs
  * Improve visual hierarchy with spacing and grouping
  * Increase z-index to 9999 to ensure dialog appears on top

- Minor UI refinements:
  * Update App.tsx layout adjustments
  * Optimize McpFormModal styling
  * Refine ProviderCard and BasicFormFields components

This enables users to import Claude providers with precise model configurations via deeplink.
This commit is contained in:
YoVinchen
2025-11-22 03:26:28 +08:00
parent 127fa5bf9d
commit 1a89267986
8 changed files with 402 additions and 76 deletions

View File

@@ -96,8 +96,8 @@ export function DeepLinkImportDialog() {
: "****";
return (
<Dialog open={isOpen} onOpenChange={setIsOpen}>
<DialogContent className="sm:max-w-[500px]">
<Dialog open={isOpen} onOpenChange={setIsOpen} modal={true}>
<DialogContent className="sm:max-w-[650px] z-[9999]">
{/* 标题显式左对齐,避免默认居中样式影响 */}
<DialogHeader className="text-left sm:text-left">
<DialogTitle>{t("deeplink.confirmImport")}</DialogTitle>
@@ -106,82 +106,120 @@ export function DeepLinkImportDialog() {
</DialogDescription>
</DialogHeader>
{/* 主体内容整体右移,略大于标题内边距,让内容看起来不贴边 */}
<div className="space-y-4 px-8 py-4">
{/* App Type */}
<div className="grid grid-cols-3 items-center gap-4">
<div className="font-medium text-sm text-muted-foreground">
{t("deeplink.app")}
{/* 使用两列布局压缩内容 */}
<div className="space-y-4 px-4 py-3">
{/* 第一行:应用类型 + 供应商名称 */}
<div className="grid grid-cols-2 gap-4">
<div className="space-y-1">
<div className="font-medium text-xs text-muted-foreground uppercase">
{t("deeplink.app")}
</div>
<div className="text-sm font-medium capitalize">
{request.app}
</div>
</div>
<div className="col-span-2 text-sm font-medium capitalize">
{request.app}
<div className="space-y-1">
<div className="font-medium text-xs text-muted-foreground uppercase">
{t("deeplink.providerName")}
</div>
<div className="text-sm font-medium truncate" title={request.name}>
{request.name}
</div>
</div>
</div>
{/* Provider Name */}
<div className="grid grid-cols-3 items-center gap-4">
<div className="font-medium text-sm text-muted-foreground">
{t("deeplink.providerName")}
{/* 第二行:官网 + 端点 */}
<div className="grid grid-cols-2 gap-4">
<div className="space-y-1">
<div className="font-medium text-xs text-muted-foreground uppercase">
{t("deeplink.homepage")}
</div>
<div className="text-xs break-all text-blue-600 dark:text-blue-400 line-clamp-2" title={request.homepage}>
{request.homepage}
</div>
</div>
<div className="col-span-2 text-sm font-medium">{request.name}</div>
</div>
{/* Homepage */}
<div className="grid grid-cols-3 items-center gap-4">
<div className="font-medium text-sm text-muted-foreground">
{t("deeplink.homepage")}
</div>
<div className="col-span-2 text-sm break-all text-blue-600 dark:text-blue-400">
{request.homepage}
<div className="space-y-1">
<div className="font-medium text-xs text-muted-foreground uppercase">
{t("deeplink.endpoint")}
</div>
<div className="text-xs break-all line-clamp-2" title={request.endpoint}>
{request.endpoint}
</div>
</div>
</div>
{/* API Endpoint */}
<div className="grid grid-cols-3 items-center gap-4">
<div className="font-medium text-sm text-muted-foreground">
{t("deeplink.endpoint")}
</div>
<div className="col-span-2 text-sm break-all">
{request.endpoint}
</div>
</div>
{/* API Key (masked) */}
<div className="grid grid-cols-3 items-center gap-4">
<div className="font-medium text-sm text-muted-foreground">
{/* 第三行API Key */}
<div className="space-y-1">
<div className="font-medium text-xs text-muted-foreground uppercase">
{t("deeplink.apiKey")}
</div>
<div className="col-span-2 text-sm font-mono text-muted-foreground">
<div className="text-sm font-mono text-muted-foreground">
{maskedApiKey}
</div>
</div>
{/* Model (if present) */}
{/* 第四行:默认模型(如果有) */}
{request.model && (
<div className="grid grid-cols-3 items-center gap-4">
<div className="font-medium text-sm text-muted-foreground">
<div className="space-y-1">
<div className="font-medium text-xs text-muted-foreground uppercase">
{t("deeplink.model")}
</div>
<div className="col-span-2 text-sm font-mono">
{request.model}
<div className="text-sm font-mono">{request.model}</div>
</div>
)}
{/* Claude 专用模型字段(紧凑布局) */}
{request.app === "claude" && (request.haikuModel || request.sonnetModel || request.opusModel) && (
<div className="rounded-lg bg-blue-50 dark:bg-blue-900/20 p-3 space-y-2">
<div className="font-medium text-xs text-blue-900 dark:text-blue-100 uppercase">
{t("deeplink.claudeModels", "Claude 模型配置")}
</div>
<div className="grid grid-cols-3 gap-2 text-xs">
{request.haikuModel && (
<div>
<span className="text-muted-foreground">Haiku:</span>
<div className="font-mono truncate" title={request.haikuModel}>
{request.haikuModel}
</div>
</div>
)}
{request.sonnetModel && (
<div>
<span className="text-muted-foreground">Sonnet:</span>
<div className="font-mono truncate" title={request.sonnetModel}>
{request.sonnetModel}
</div>
</div>
)}
{request.opusModel && (
<div>
<span className="text-muted-foreground">Opus:</span>
<div className="font-mono truncate" title={request.opusModel}>
{request.opusModel}
</div>
</div>
)}
</div>
</div>
)}
{/* Notes (if present) */}
{/* 备注(如果有) */}
{request.notes && (
<div className="grid grid-cols-3 items-start gap-4">
<div className="font-medium text-sm text-muted-foreground">
<div className="space-y-1">
<div className="font-medium text-xs text-muted-foreground uppercase">
{t("deeplink.notes")}
</div>
<div className="col-span-2 text-sm text-muted-foreground">
<div className="text-sm text-muted-foreground line-clamp-2" title={request.notes}>
{request.notes}
</div>
</div>
)}
{/* Warning */}
<div className="rounded-lg bg-yellow-50 dark:bg-yellow-900/20 p-3 text-sm text-yellow-800 dark:text-yellow-200">
{/* 警告提示(紧凑版) */}
<div className="rounded-lg bg-yellow-50 dark:bg-yellow-900/20 p-2 text-xs text-yellow-800 dark:text-yellow-200">
{t("deeplink.warning")}
</div>
</div>