feat: Add custom model download functionality and enhance model management

- Implemented `model-download-custom` command to download HuggingFace models.
- Added support for discovering manually placed models in the cache.
- Enhanced the model list view to display recommended and discovered models separately.
- Introduced JSON editor for direct configuration mode in API settings.
- Added validation and formatting features for JSON input.
- Updated translations for new API settings and common actions.
- Improved user interface for model management, including action buttons and tooltips.
This commit is contained in:
catlog22
2026-01-11 15:13:11 +08:00
parent 16083130f8
commit 1e91fa9f9e
7 changed files with 1268 additions and 7 deletions

View File

@@ -2457,4 +2457,315 @@ select.cli-input {
width: 100%;
justify-content: flex-end;
}
}
/* ===========================
CLI Settings Form
=========================== */
/* Tool Detail Header */
.tool-detail-header {
display: flex;
align-items: center;
justify-content: space-between;
padding: 1rem 1.5rem;
border-bottom: 1px solid hsl(var(--border));
background: hsl(var(--muted) / 0.2);
flex-shrink: 0;
}
.tool-detail-header h3 {
display: flex;
align-items: center;
gap: 0.5rem;
margin: 0;
font-size: 1.125rem;
font-weight: 600;
color: hsl(var(--foreground));
}
.tool-detail-header h3 svg,
.tool-detail-header h3 i {
width: 1.25rem;
height: 1.25rem;
color: hsl(var(--primary));
}
/* Claude Config Form Container */
.claude-config-form {
flex: 1;
overflow-y: auto;
padding: 1.5rem;
display: flex;
flex-direction: column;
gap: 1rem;
}
/* Config Mode Toggle */
.config-mode-toggle {
display: flex;
gap: 0.5rem;
margin-bottom: 0.5rem;
padding: 0.25rem;
background: hsl(var(--muted) / 0.3);
border-radius: 0.5rem;
}
.config-mode-btn {
flex: 1;
display: flex;
align-items: center;
justify-content: center;
gap: 0.5rem;
padding: 0.625rem 1rem;
font-size: 0.875rem;
font-weight: 500;
color: hsl(var(--muted-foreground));
background: transparent;
border: 1px solid transparent;
border-radius: 0.375rem;
cursor: pointer;
transition: all 0.2s;
}
.config-mode-btn:hover {
color: hsl(var(--foreground));
background: hsl(var(--muted) / 0.5);
}
.config-mode-btn.active {
color: hsl(var(--primary));
background: hsl(var(--card));
border-color: hsl(var(--border));
box-shadow: 0 1px 3px hsl(var(--foreground) / 0.05);
}
.config-mode-btn svg,
.config-mode-btn i {
width: 1rem;
height: 1rem;
}
/* Model Config Section */
.model-config-section {
margin-top: 1rem;
padding: 1rem;
background: hsl(var(--muted) / 0.2);
border: 1px solid hsl(var(--border));
border-radius: 0.5rem;
}
.model-config-section h4 {
display: flex;
align-items: center;
gap: 0.5rem;
margin: 0 0 1rem 0;
font-size: 0.875rem;
font-weight: 600;
color: hsl(var(--foreground));
}
.model-config-section h4 svg,
.model-config-section h4 i {
width: 1rem;
height: 1rem;
color: hsl(var(--primary));
}
.model-config-grid {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 0.75rem;
}
.model-config-grid .form-group {
margin-bottom: 0;
}
.model-config-grid .form-group label {
font-size: 0.75rem;
font-family: 'SF Mono', 'Consolas', 'Liberation Mono', monospace;
color: hsl(var(--muted-foreground));
}
/* Form Actions - Sticky at bottom */
.claude-config-form .form-actions {
position: sticky;
bottom: 0;
margin-top: auto;
padding: 1rem 0 0;
background: hsl(var(--card));
border-top: 1px solid hsl(var(--border));
}
/* Responsive adjustments */
@media (max-width: 640px) {
.model-config-grid {
grid-template-columns: 1fr;
}
.config-mode-toggle {
flex-direction: column;
}
}
/* ===========================
JSON Editor Section
=========================== */
.json-editor-section {
margin-top: 1rem;
border: 1px solid hsl(var(--border));
border-radius: 0.5rem;
overflow: hidden;
background: hsl(var(--card));
}
.json-editor-header {
display: flex;
align-items: center;
justify-content: space-between;
padding: 0.75rem 1rem;
background: hsl(var(--muted) / 0.3);
border-bottom: 1px solid hsl(var(--border));
}
.json-editor-header h4 {
display: flex;
align-items: center;
gap: 0.5rem;
margin: 0;
font-size: 0.875rem;
font-weight: 600;
color: hsl(var(--foreground));
}
.json-editor-header h4 svg,
.json-editor-header h4 i {
width: 1rem;
height: 1rem;
color: hsl(var(--primary));
}
.json-editor-actions {
display: flex;
gap: 0.25rem;
}
.json-editor-actions .btn-ghost {
padding: 0.375rem 0.625rem;
font-size: 0.75rem;
background: transparent;
border: none;
color: hsl(var(--muted-foreground));
cursor: pointer;
border-radius: 0.25rem;
display: inline-flex;
align-items: center;
gap: 0.25rem;
transition: all 0.15s;
}
.json-editor-actions .btn-ghost:hover {
background: hsl(var(--muted) / 0.5);
color: hsl(var(--foreground));
}
.json-editor-actions .btn-ghost svg,
.json-editor-actions .btn-ghost i {
width: 0.875rem;
height: 0.875rem;
}
.json-editor-body {
display: flex;
position: relative;
min-height: 200px;
max-height: 350px;
}
.json-line-numbers {
width: 2.5rem;
padding: 0.75rem 0.5rem;
background: hsl(var(--muted) / 0.2);
border-right: 1px solid hsl(var(--border));
font-family: 'SF Mono', 'Consolas', 'Liberation Mono', monospace;
font-size: 0.75rem;
line-height: 1.5;
color: hsl(var(--muted-foreground));
text-align: right;
user-select: none;
overflow: hidden;
flex-shrink: 0;
}
.json-line-numbers span {
display: block;
}
.json-textarea {
flex: 1;
padding: 0.75rem;
border: none;
resize: none;
font-family: 'SF Mono', 'Consolas', 'Liberation Mono', monospace;
font-size: 0.8125rem;
line-height: 1.5;
color: hsl(var(--foreground));
background: hsl(var(--background));
outline: none;
overflow-y: auto;
tab-size: 2;
}
.json-textarea::placeholder {
color: hsl(var(--muted-foreground) / 0.5);
}
.json-textarea.invalid {
background: hsl(var(--destructive) / 0.05);
border-left: 2px solid hsl(var(--destructive));
}
.json-editor-footer {
display: flex;
align-items: center;
justify-content: space-between;
padding: 0.5rem 1rem;
background: hsl(var(--muted) / 0.2);
border-top: 1px solid hsl(var(--border));
}
.json-status {
display: inline-flex;
align-items: center;
gap: 0.25rem;
font-size: 0.75rem;
font-weight: 500;
}
.json-status svg,
.json-status i {
width: 0.875rem;
height: 0.875rem;
}
.json-status.valid {
color: hsl(142 76% 36%);
}
.json-status.invalid {
color: hsl(var(--destructive));
}
.json-hint {
font-size: 0.6875rem;
color: hsl(var(--muted-foreground));
}
/* Button styles for JSON editor */
.btn-sm {
padding: 0.375rem 0.75rem;
font-size: 0.75rem;
border-radius: 0.375rem;
}