chore(apparence): opt clawx apparence and i18n settings (#410)
This commit is contained in:
@@ -51,7 +51,7 @@ interface ChannelConfigModalProps {
|
||||
onChannelSaved?: (channelType: ChannelType) => void | Promise<void>;
|
||||
}
|
||||
|
||||
const inputClasses = 'h-[44px] rounded-xl font-mono text-[13px] bg-[#eeece3] dark:bg-[#151514] border-black/10 dark:border-white/10 focus-visible:ring-2 focus-visible:ring-blue-500/50 focus-visible:border-blue-500 shadow-sm transition-all text-foreground placeholder:text-foreground/40';
|
||||
const inputClasses = 'h-[44px] rounded-xl font-mono text-[13px] bg-[#eeece3] dark:bg-muted border-black/10 dark:border-white/10 focus-visible:ring-2 focus-visible:ring-blue-500/50 focus-visible:border-blue-500 shadow-sm transition-all text-foreground placeholder:text-foreground/40';
|
||||
const labelClasses = 'text-[14px] text-foreground/80 font-bold';
|
||||
const outlineButtonClasses = 'h-9 text-[13px] font-medium rounded-full px-4 border-black/10 dark:border-white/10 bg-transparent hover:bg-black/5 dark:hover:bg-white/5 shadow-none text-foreground/80 hover:text-foreground';
|
||||
const primaryButtonClasses = 'h-9 text-[13px] font-medium rounded-full px-4 shadow-none';
|
||||
@@ -371,7 +371,7 @@ export function ChannelConfigModal({
|
||||
return (
|
||||
<div className="fixed inset-0 z-50 bg-black/50 flex items-center justify-center p-4" onClick={onClose}>
|
||||
<Card
|
||||
className="w-full max-w-3xl max-h-[90vh] flex flex-col rounded-3xl border-0 shadow-2xl bg-[#f3f1e9] dark:bg-[#1a1a19] overflow-hidden"
|
||||
className="w-full max-w-3xl max-h-[90vh] flex flex-col rounded-3xl border-0 shadow-2xl bg-[#f3f1e9] dark:bg-card overflow-hidden"
|
||||
onClick={(event) => event.stopPropagation()}
|
||||
>
|
||||
<CardHeader className="flex flex-row items-start justify-between pb-2 shrink-0">
|
||||
@@ -409,7 +409,7 @@ export function ChannelConfigModal({
|
||||
key={type}
|
||||
onClick={() => setSelectedType(type)}
|
||||
className={cn(
|
||||
'group flex items-start gap-4 p-4 rounded-2xl transition-all text-left border relative overflow-hidden bg-[#eeece3] dark:bg-[#151514] shadow-sm',
|
||||
'group flex items-start gap-4 p-4 rounded-2xl transition-all text-left border relative overflow-hidden bg-[#eeece3] dark:bg-muted shadow-sm',
|
||||
isConfigured
|
||||
? 'border-green-500/40 bg-green-500/5 dark:bg-green-500/10'
|
||||
: 'border-black/5 dark:border-white/10 hover:bg-black/5 dark:hover:bg-white/5'
|
||||
@@ -448,7 +448,7 @@ export function ChannelConfigModal({
|
||||
</div>
|
||||
) : qrCode ? (
|
||||
<div className="text-center space-y-6">
|
||||
<div className="bg-[#eeece3] dark:bg-[#151514] p-4 rounded-3xl inline-block shadow-sm border border-black/10 dark:border-white/10">
|
||||
<div className="bg-[#eeece3] dark:bg-muted p-4 rounded-3xl inline-block shadow-sm border border-black/10 dark:border-white/10">
|
||||
{qrCode.startsWith('data:image') ? (
|
||||
<img src={qrCode} alt="Scan QR Code" className="w-64 h-64 object-contain rounded-2xl" />
|
||||
) : (
|
||||
@@ -474,7 +474,7 @@ export function ChannelConfigModal({
|
||||
</div>
|
||||
</div>
|
||||
) : loadingConfig ? (
|
||||
<div className="flex items-center justify-center py-10 rounded-2xl bg-[#eeece3] dark:bg-[#151514] border border-black/10 dark:border-white/10">
|
||||
<div className="flex items-center justify-center py-10 rounded-2xl bg-[#eeece3] dark:bg-muted border border-black/10 dark:border-white/10">
|
||||
<Loader2 className="h-6 w-6 animate-spin text-muted-foreground" />
|
||||
<span className="ml-2 text-[14px] text-muted-foreground">{t('dialog.loadingConfig')}</span>
|
||||
</div>
|
||||
@@ -487,7 +487,7 @@ export function ChannelConfigModal({
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="bg-[#eeece3] dark:bg-[#151514] p-4 rounded-2xl space-y-4 shadow-sm border border-black/10 dark:border-white/10">
|
||||
<div className="bg-[#eeece3] dark:bg-muted p-4 rounded-2xl space-y-4 shadow-sm border border-black/10 dark:border-white/10">
|
||||
<div className="flex items-center justify-between gap-3">
|
||||
<div>
|
||||
<p className={labelClasses}>{t('dialog.howToConnect')}</p>
|
||||
@@ -696,7 +696,7 @@ function ConfigField({ field, value, onChange, showSecret, onToggleSecret }: Con
|
||||
variant="outline"
|
||||
size="icon"
|
||||
onClick={onToggleSecret}
|
||||
className="h-[44px] w-[44px] rounded-xl bg-[#eeece3] dark:bg-[#151514] border-black/10 dark:border-white/10 text-muted-foreground hover:text-foreground shrink-0 shadow-sm"
|
||||
className="h-[44px] w-[44px] rounded-xl bg-[#eeece3] dark:bg-muted border-black/10 dark:border-white/10 text-muted-foreground hover:text-foreground shrink-0 shadow-sm"
|
||||
>
|
||||
{showSecret ? <EyeOff className="h-4 w-4" /> : <Eye className="h-4 w-4" />}
|
||||
</Button>
|
||||
|
||||
@@ -254,7 +254,7 @@ export function Sidebar() {
|
||||
}}
|
||||
className={cn(
|
||||
'flex w-full items-center gap-2.5 rounded-lg px-2.5 py-2 text-[14px] font-medium transition-colors mb-2',
|
||||
'bg-white dark:bg-accent shadow-sm border border-black/5 dark:border-white/10 text-foreground',
|
||||
'bg-black/5 dark:bg-accent shadow-none border border-transparent text-foreground',
|
||||
sidebarCollapsed && 'justify-center px-0',
|
||||
)}
|
||||
>
|
||||
|
||||
@@ -52,7 +52,7 @@ import { useSettingsStore } from '@/stores/settings';
|
||||
import { hostApiFetch } from '@/lib/host-api';
|
||||
import { subscribeHostEvent } from '@/lib/host-events';
|
||||
|
||||
const inputClasses = 'h-[44px] rounded-xl font-mono text-[13px] bg-[#eeece3] dark:bg-[#151514] border-black/10 dark:border-white/10 focus-visible:ring-2 focus-visible:ring-blue-500/50 focus-visible:border-blue-500 shadow-sm transition-all text-foreground placeholder:text-foreground/40';
|
||||
const inputClasses = 'h-[44px] rounded-xl font-mono text-[13px] bg-[#eeece3] dark:bg-muted border-black/10 dark:border-white/10 focus-visible:ring-2 focus-visible:ring-blue-500/50 focus-visible:border-blue-500 shadow-sm transition-all text-foreground placeholder:text-foreground/40';
|
||||
const labelClasses = 'text-[14px] text-foreground/80 font-bold';
|
||||
|
||||
function normalizeFallbackProviderIds(ids?: string[]): string[] {
|
||||
@@ -184,7 +184,7 @@ export function ProvidersSettings() {
|
||||
<h2 className="text-3xl font-serif text-foreground font-normal tracking-tight" style={{ fontFamily: 'Georgia, Cambria, "Times New Roman", Times, serif' }}>
|
||||
{t('aiProviders.title', 'AI Providers')}
|
||||
</h2>
|
||||
<Button onClick={() => setShowAddDialog(true)} className="rounded-full px-5 h-9 bg-black/5 dark:bg-white/5 hover:bg-black/10 dark:hover:bg-white/10 text-foreground border border-transparent shadow-none font-medium text-[13px]">
|
||||
<Button onClick={() => setShowAddDialog(true)} className="rounded-full px-5 h-9 shadow-none font-medium text-[13px]">
|
||||
<Plus className="h-4 w-4 mr-2" />
|
||||
{t('aiProviders.add')}
|
||||
</Button>
|
||||
@@ -407,7 +407,7 @@ function ProviderCard({
|
||||
};
|
||||
|
||||
const currentInputClasses = isDefault
|
||||
? "h-[40px] rounded-xl font-mono text-[13px] bg-white dark:bg-[#1a1a19] border-black/10 dark:border-white/10 focus-visible:ring-2 focus-visible:ring-blue-500/50 shadow-sm"
|
||||
? "h-[40px] rounded-xl font-mono text-[13px] bg-white dark:bg-card border-black/10 dark:border-white/10 focus-visible:ring-2 focus-visible:ring-blue-500/50 shadow-sm"
|
||||
: inputClasses;
|
||||
|
||||
const currentLabelClasses = isDefault ? "text-[13px] text-muted-foreground" : labelClasses;
|
||||
@@ -419,12 +419,12 @@ function ProviderCard({
|
||||
"group flex flex-col p-4 rounded-2xl transition-all relative overflow-hidden hover:bg-black/5 dark:hover:bg-white/5",
|
||||
isDefault
|
||||
? "bg-black/[0.04] dark:bg-white/[0.06] border border-transparent"
|
||||
: "bg-transparent border border-black/10 dark:border-white/10"
|
||||
: "bg-transparent border border-transparent"
|
||||
)}
|
||||
>
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex items-center gap-4">
|
||||
<div className={cn("h-[42px] w-[42px] shrink-0 flex items-center justify-center text-foreground border border-black/5 dark:border-white/10 rounded-full shadow-sm group-hover:scale-105 transition-transform", isDefault ? "bg-black/5 dark:bg-white/5" : "bg-white dark:bg-accent")}>
|
||||
<div className="h-[42px] w-[42px] shrink-0 flex items-center justify-center text-foreground border border-black/5 dark:border-white/10 rounded-full bg-black/5 dark:bg-white/5 shadow-sm group-hover:scale-105 transition-transform">
|
||||
{getProviderIconUrl(account.vendorId) ? (
|
||||
<img src={getProviderIconUrl(account.vendorId)} alt={typeInfo?.name || account.vendorId} className={cn('h-5 w-5', shouldInvertInDark(account.vendorId) && 'dark:invert')} />
|
||||
) : (
|
||||
@@ -482,7 +482,7 @@ function ProviderCard({
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
className="h-8 w-8 rounded-full text-muted-foreground hover:text-blue-600 hover:bg-white dark:hover:bg-[#1a1a19] shadow-sm"
|
||||
className="h-8 w-8 rounded-full text-muted-foreground hover:text-blue-600 hover:bg-white dark:hover:bg-card shadow-sm"
|
||||
onClick={onSetDefault}
|
||||
title={t('aiProviders.card.setDefault')}
|
||||
>
|
||||
@@ -492,7 +492,7 @@ function ProviderCard({
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
className="h-8 w-8 rounded-full text-muted-foreground hover:text-foreground hover:bg-white dark:hover:bg-[#1a1a19] shadow-sm"
|
||||
className="h-8 w-8 rounded-full text-muted-foreground hover:text-foreground hover:bg-white dark:hover:bg-card shadow-sm"
|
||||
onClick={onEdit}
|
||||
title={t('aiProviders.card.editKey')}
|
||||
>
|
||||
@@ -501,7 +501,7 @@ function ProviderCard({
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
className="h-8 w-8 rounded-full text-muted-foreground hover:text-destructive hover:bg-white dark:hover:bg-[#1a1a19] shadow-sm"
|
||||
className="h-8 w-8 rounded-full text-muted-foreground hover:text-destructive hover:bg-white dark:hover:bg-card shadow-sm"
|
||||
onClick={onDelete}
|
||||
title={t('aiProviders.card.delete')}
|
||||
>
|
||||
@@ -545,14 +545,14 @@ function ProviderCard({
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setApiProtocol('openai-completions')}
|
||||
className={cn("flex-1 py-1.5 px-3 rounded-lg border transition-colors", apiProtocol === 'openai-completions' ? "bg-white dark:bg-[#1a1a19] border-black/20 dark:border-white/20 shadow-sm font-medium" : "border-transparent bg-black/5 dark:bg-white/5 text-muted-foreground hover:bg-black/10 dark:hover:bg-white/10")}
|
||||
className={cn("flex-1 py-1.5 px-3 rounded-lg border transition-colors", apiProtocol === 'openai-completions' ? "bg-white dark:bg-card border-black/20 dark:border-white/20 shadow-sm font-medium" : "border-transparent bg-black/5 dark:bg-white/5 text-muted-foreground hover:bg-black/10 dark:hover:bg-white/10")}
|
||||
>
|
||||
{t('aiProviders.protocols.openai', 'OpenAI')}
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setApiProtocol('anthropic-messages')}
|
||||
className={cn("flex-1 py-1.5 px-3 rounded-lg border transition-colors", apiProtocol === 'anthropic-messages' ? "bg-white dark:bg-[#1a1a19] border-black/20 dark:border-white/20 shadow-sm font-medium" : "border-transparent bg-black/5 dark:bg-white/5 text-muted-foreground hover:bg-black/10 dark:hover:bg-white/10")}
|
||||
className={cn("flex-1 py-1.5 px-3 rounded-lg border transition-colors", apiProtocol === 'anthropic-messages' ? "bg-white dark:bg-card border-black/20 dark:border-white/20 shadow-sm font-medium" : "border-transparent bg-black/5 dark:bg-white/5 text-muted-foreground hover:bg-black/10 dark:hover:bg-white/10")}
|
||||
>
|
||||
{t('aiProviders.protocols.anthropic', 'Anthropic')}
|
||||
</button>
|
||||
@@ -578,8 +578,8 @@ function ProviderCard({
|
||||
onChange={(e) => setFallbackModelsText(e.target.value)}
|
||||
placeholder={t('aiProviders.dialog.fallbackModelIdsPlaceholder')}
|
||||
className={isDefault
|
||||
? "min-h-24 w-full rounded-xl border border-black/10 dark:border-white/10 bg-white dark:bg-[#1a1a19] px-3 py-2 text-[13px] font-mono outline-none focus-visible:ring-2 focus-visible:ring-blue-500/50 shadow-sm"
|
||||
: "min-h-24 w-full rounded-xl border border-black/10 dark:border-white/10 bg-[#eeece3] dark:bg-[#151514] px-3 py-2 text-[13px] font-mono outline-none focus-visible:ring-2 focus-visible:ring-blue-500/50 focus-visible:border-blue-500 shadow-sm transition-all text-foreground placeholder:text-foreground/40"}
|
||||
? "min-h-24 w-full rounded-xl border border-black/10 dark:border-white/10 bg-white dark:bg-card px-3 py-2 text-[13px] font-mono outline-none focus-visible:ring-2 focus-visible:ring-blue-500/50 shadow-sm"
|
||||
: "min-h-24 w-full rounded-xl border border-black/10 dark:border-white/10 bg-[#eeece3] dark:bg-muted px-3 py-2 text-[13px] font-mono outline-none focus-visible:ring-2 focus-visible:ring-blue-500/50 focus-visible:border-blue-500 shadow-sm transition-all text-foreground placeholder:text-foreground/40"}
|
||||
/>
|
||||
<p className="text-[12px] text-muted-foreground">
|
||||
{t('aiProviders.dialog.fallbackModelIdsHelp')}
|
||||
@@ -590,7 +590,7 @@ function ProviderCard({
|
||||
{fallbackOptions.length === 0 ? (
|
||||
<p className="text-[13px] text-muted-foreground">{t('aiProviders.dialog.noFallbackOptions')}</p>
|
||||
) : (
|
||||
<div className={cn("space-y-2 rounded-xl border border-black/10 dark:border-white/10 p-3 shadow-sm", isDefault ? "bg-white dark:bg-[#1a1a19]" : "bg-[#eeece3] dark:bg-[#151514]")}>
|
||||
<div className={cn("space-y-2 rounded-xl border border-black/10 dark:border-white/10 p-3 shadow-sm", isDefault ? "bg-white dark:bg-card" : "bg-[#eeece3] dark:bg-muted")}>
|
||||
{fallbackOptions.map((candidate) => (
|
||||
<label key={candidate.account.id} className="flex items-center gap-3 text-[13px] cursor-pointer group/label">
|
||||
<input
|
||||
@@ -666,8 +666,8 @@ function ProviderCard({
|
||||
className={cn(
|
||||
"rounded-xl px-4 border-black/10 dark:border-white/10",
|
||||
isDefault
|
||||
? "h-[40px] bg-white dark:bg-[#1a1a19] hover:bg-black/5 dark:hover:bg-white/10"
|
||||
: "h-[44px] bg-[#eeece3] dark:bg-[#151514] hover:bg-black/5 dark:hover:bg-white/10 shadow-sm"
|
||||
? "h-[40px] bg-white dark:bg-card hover:bg-black/5 dark:hover:bg-white/10"
|
||||
: "h-[44px] bg-[#eeece3] dark:bg-muted hover:bg-black/5 dark:hover:bg-white/10 shadow-sm"
|
||||
)}
|
||||
disabled={
|
||||
validating
|
||||
@@ -695,7 +695,7 @@ function ProviderCard({
|
||||
"p-0 rounded-xl",
|
||||
isDefault
|
||||
? "h-[40px] w-[40px] hover:bg-black/5 dark:hover:bg-white/10"
|
||||
: "h-[44px] w-[44px] bg-[#eeece3] dark:bg-[#151514] border border-black/10 dark:border-white/10 hover:bg-black/5 dark:hover:bg-white/10 shadow-sm text-muted-foreground hover:text-foreground"
|
||||
: "h-[44px] w-[44px] bg-[#eeece3] dark:bg-muted border border-black/10 dark:border-white/10 hover:bg-black/5 dark:hover:bg-white/10 shadow-sm text-muted-foreground hover:text-foreground"
|
||||
)}
|
||||
>
|
||||
<X className="h-4 w-4" />
|
||||
@@ -998,7 +998,7 @@ function AddProviderDialog({
|
||||
|
||||
return (
|
||||
<div className="fixed inset-0 z-50 bg-black/50 flex items-center justify-center p-4">
|
||||
<Card className="w-full max-w-2xl max-h-[90vh] flex flex-col rounded-3xl border-0 shadow-2xl bg-[#f3f1e9] dark:bg-[#1a1a19] overflow-hidden">
|
||||
<Card className="w-full max-w-2xl max-h-[90vh] flex flex-col rounded-3xl border-0 shadow-2xl bg-[#f3f1e9] dark:bg-card overflow-hidden">
|
||||
<CardHeader className="relative pb-2 shrink-0">
|
||||
<CardTitle className="text-2xl font-serif font-normal">{t('aiProviders.dialog.title')}</CardTitle>
|
||||
<CardDescription className="text-[15px] mt-1 text-foreground/70">
|
||||
@@ -1027,7 +1027,7 @@ function AddProviderDialog({
|
||||
}}
|
||||
className="p-4 rounded-2xl border border-black/5 dark:border-white/5 hover:bg-black/5 dark:hover:bg-white/5 transition-colors text-center group"
|
||||
>
|
||||
<div className="h-12 w-12 mx-auto mb-3 flex items-center justify-center bg-white dark:bg-[#1a1a19] rounded-xl shadow-sm border border-black/5 dark:border-white/5 group-hover:scale-105 transition-transform">
|
||||
<div className="h-12 w-12 mx-auto mb-3 flex items-center justify-center bg-black/5 dark:bg-white/5 rounded-xl shadow-sm border border-black/5 dark:border-white/5 group-hover:scale-105 transition-transform">
|
||||
{getProviderIconUrl(type.id) ? (
|
||||
<img src={getProviderIconUrl(type.id)} alt={type.name} className={cn('h-6 w-6', shouldInvertInDark(type.id) && 'dark:invert')} />
|
||||
) : (
|
||||
@@ -1040,7 +1040,7 @@ function AddProviderDialog({
|
||||
</div>
|
||||
) : (
|
||||
<div className="space-y-6">
|
||||
<div className="flex items-center gap-3 p-4 rounded-2xl bg-white dark:bg-[#1a1a19] border border-black/5 dark:border-white/5 shadow-sm">
|
||||
<div className="flex items-center gap-3 p-4 rounded-2xl bg-white dark:bg-card border border-black/5 dark:border-white/5 shadow-sm">
|
||||
<div className="h-10 w-10 shrink-0 flex items-center justify-center bg-black/5 dark:bg-white/5 rounded-xl">
|
||||
{getProviderIconUrl(selectedType!) ? (
|
||||
<img src={getProviderIconUrl(selectedType!)} alt={typeInfo?.name} className={cn('h-6 w-6', shouldInvertInDark(selectedType!) && 'dark:invert')} />
|
||||
@@ -1078,7 +1078,7 @@ function AddProviderDialog({
|
||||
|
||||
{/* Auth mode toggle for providers supporting both */}
|
||||
{isOAuth && supportsApiKey && (
|
||||
<div className="flex rounded-xl border border-black/10 dark:border-white/10 overflow-hidden text-[13px] font-medium shadow-sm bg-[#eeece3] dark:bg-[#151514] p-1 gap-1">
|
||||
<div className="flex rounded-xl border border-black/10 dark:border-white/10 overflow-hidden text-[13px] font-medium shadow-sm bg-[#eeece3] dark:bg-muted p-1 gap-1">
|
||||
<button
|
||||
onClick={() => setAuthMode('oauth')}
|
||||
className={cn(
|
||||
@@ -1181,14 +1181,14 @@ function AddProviderDialog({
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setApiProtocol('openai-completions')}
|
||||
className={cn("flex-1 py-1.5 px-3 rounded-lg border transition-colors", apiProtocol === 'openai-completions' ? "bg-white dark:bg-[#1a1a19] border-black/20 dark:border-white/20 shadow-sm font-medium" : "border-transparent bg-black/5 dark:bg-white/5 text-muted-foreground hover:bg-black/10 dark:hover:bg-white/10")}
|
||||
className={cn("flex-1 py-1.5 px-3 rounded-lg border transition-colors", apiProtocol === 'openai-completions' ? "bg-white dark:bg-card border-black/20 dark:border-white/20 shadow-sm font-medium" : "border-transparent bg-black/5 dark:bg-white/5 text-muted-foreground hover:bg-black/10 dark:hover:bg-white/10")}
|
||||
>
|
||||
{t('aiProviders.protocols.openai', 'OpenAI')}
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setApiProtocol('anthropic-messages')}
|
||||
className={cn("flex-1 py-1.5 px-3 rounded-lg border transition-colors", apiProtocol === 'anthropic-messages' ? "bg-white dark:bg-[#1a1a19] border-black/20 dark:border-white/20 shadow-sm font-medium" : "border-transparent bg-black/5 dark:bg-white/5 text-muted-foreground hover:bg-black/10 dark:hover:bg-white/10")}
|
||||
className={cn("flex-1 py-1.5 px-3 rounded-lg border transition-colors", apiProtocol === 'anthropic-messages' ? "bg-white dark:bg-card border-black/20 dark:border-white/20 shadow-sm font-medium" : "border-transparent bg-black/5 dark:bg-white/5 text-muted-foreground hover:bg-black/10 dark:hover:bg-white/10")}
|
||||
>
|
||||
{t('aiProviders.protocols.anthropic', 'Anthropic')}
|
||||
</button>
|
||||
@@ -1217,7 +1217,7 @@ function AddProviderDialog({
|
||||
|
||||
{/* OAuth Active State Modal / Inline View */}
|
||||
{oauthFlowing && (
|
||||
<div className="mt-4 p-5 border border-black/10 dark:border-white/10 rounded-2xl bg-white dark:bg-[#1a1a19] shadow-sm relative overflow-hidden">
|
||||
<div className="mt-4 p-5 border border-black/10 dark:border-white/10 rounded-2xl bg-white dark:bg-card shadow-sm relative overflow-hidden">
|
||||
{/* Background pulse effect */}
|
||||
<div className="absolute inset-0 bg-blue-500/5 animate-pulse" />
|
||||
|
||||
@@ -1284,7 +1284,7 @@ function AddProviderDialog({
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center justify-center gap-3 p-4 bg-[#eeece3] dark:bg-[#151514] border border-black/5 dark:border-white/5 rounded-xl shadow-inner">
|
||||
<div className="flex items-center justify-center gap-3 p-4 bg-[#eeece3] dark:bg-muted border border-black/5 dark:border-white/5 rounded-xl shadow-inner">
|
||||
<code className="text-3xl font-mono tracking-[0.2em] font-bold text-foreground">
|
||||
{oauthData.userCode}
|
||||
</code>
|
||||
|
||||
@@ -183,8 +183,7 @@
|
||||
"Read the documentation, then go to Feishu Open Platform",
|
||||
"Create a new application",
|
||||
"Get App ID and App Secret",
|
||||
"Configure event subscription",
|
||||
"Note: Not mentioned in current OpenClaw docs, but you MUST add 'contact:contact.base:readonly' **Application Permission** in Permission Management"
|
||||
"Configure event subscription"
|
||||
]
|
||||
},
|
||||
"wecom": {
|
||||
|
||||
@@ -60,4 +60,4 @@
|
||||
"contentDialogTitle": "Usage detail content",
|
||||
"close": "Close"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"title": "Agents",
|
||||
"subtitle": "新しい Agent を追加すると、ClawX はメイン Agent のワークスペース初期ファイルと実行時認証設定をコピーします。これらの設定は対話形式で編集できます。",
|
||||
"subtitle": "新しい Agent を追加すると、ClawX はメイン Agent のワークスペース初期ファイルと実行時認証設定をコピーします。これらの設定は対話形式で編集できます",
|
||||
"refresh": "更新",
|
||||
"addAgent": "Agent を追加",
|
||||
"gatewayWarning": "Gateway サービスが停止しています。Agent または Channel の変更が反映されるまで少し時間がかかる場合があります。",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"title": "メッセージングチャンネル",
|
||||
"subtitle": "メッセージングチャンネルと接続を管理。設定はメイン Agent のみ有効です。",
|
||||
"subtitle": "メッセージングチャンネルと接続を管理。設定はメイン Agent のみ有効です",
|
||||
"refresh": "更新",
|
||||
"addChannel": "チャンネルを追加",
|
||||
"stats": {
|
||||
@@ -183,8 +183,7 @@
|
||||
"ドキュメントを読み、Feishu Open Platform に移動します",
|
||||
"新しいアプリケーションを作成します",
|
||||
"App ID と App Secret を取得します",
|
||||
"イベント購読を設定します",
|
||||
"注意:現在のドキュメントには記載されていませんが、権限管理で 'contact:contact.base:readonly' **アプリケーション権限** を必ず追加してください"
|
||||
"イベント購読を設定します"
|
||||
]
|
||||
},
|
||||
"wecom": {
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
"gatewayNotRunning": "ゲートウェイが停止中",
|
||||
"models": {
|
||||
"title": "モデル",
|
||||
"subtitle": "AI プロバイダーを管理し、トークン使用量を監視します。"
|
||||
"subtitle": "AI プロバイダーを管理し、トークン使用量を監視します"
|
||||
},
|
||||
"quickActions": {
|
||||
"title": "クイックアクション",
|
||||
@@ -60,4 +60,4 @@
|
||||
"contentDialogTitle": "使用量詳細の内容",
|
||||
"close": "閉じる"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,14 +1,14 @@
|
||||
{
|
||||
"title": "Agents",
|
||||
"subtitle": "添加新的 Agent 时,ClawX 会复制主 Agent 的工作区引导文件和运行时认证配置, 配置可以通过以对话的形式进行修改。",
|
||||
"subtitle": "添加新的 Agent 时,ClawX 会复制主 Agent 的工作区引导文件和运行时认证配置, 配置可以通过以对话的形式进行修改",
|
||||
"refresh": "刷新",
|
||||
"addAgent": "添加 Agent",
|
||||
"gatewayWarning": "Gateway 服务未运行。Agent 或 Channel 变更可能需要一点时间生效。",
|
||||
"gatewayWarning": "Gateway 服务未运行。Agent 或频道变更可能需要一点时间生效。",
|
||||
"defaultBadge": "默认",
|
||||
"inherited": "继承",
|
||||
"none": "无",
|
||||
"modelLine": "Model: {{model}}{{suffix}}",
|
||||
"channelsLine": "Channels: {{channels}}",
|
||||
"channelsLine": "频道: {{channels}}",
|
||||
"deleteAgent": "删除 Agent",
|
||||
"settings": "设置",
|
||||
"creating": "创建中...",
|
||||
@@ -24,18 +24,18 @@
|
||||
},
|
||||
"settingsDialog": {
|
||||
"title": "{{name}} 设置",
|
||||
"description": "更新 Agent 名称,并管理哪些 Channel 归属于这个 Agent。",
|
||||
"description": "更新 Agent 名称,并管理哪些频道归属于这个 Agent。",
|
||||
"nameLabel": "Agent 名称",
|
||||
"agentIdLabel": "Agent ID",
|
||||
"modelLabel": "Model",
|
||||
"channelsTitle": "Channels",
|
||||
"channelsDescription": "每种 Channel 类型在 ClawX 中只保留一份配置。在这里保存已配置的 Channel 会将归属切换到当前 Agent。",
|
||||
"addChannel": "添加 Channel",
|
||||
"noChannels": "这个 Agent 还没有分配任何 Channel。"
|
||||
"channelsTitle": "频道",
|
||||
"channelsDescription": "每种频道类型在 ClawX 中只保留一份配置。在这里保存已配置的频道会将归属切换到当前 Agent。",
|
||||
"addChannel": "添加频道",
|
||||
"noChannels": "这个 Agent 还没有分配任何频道。"
|
||||
},
|
||||
"removeChannelDialog": {
|
||||
"title": "移除 Channel",
|
||||
"message": "确认移除 {{name}}?这会删除当前的 Channel 配置。"
|
||||
"title": "移除频道",
|
||||
"message": "确认移除 {{name}}?这会删除当前的频道配置。"
|
||||
},
|
||||
"toast": {
|
||||
"agentCreated": "Agent 已创建",
|
||||
@@ -44,8 +44,8 @@
|
||||
"agentUpdated": "Agent 已更新",
|
||||
"agentUpdateFailed": "更新 Agent 失败:{{error}}",
|
||||
"channelAssigned": "{{channel}} 已分配给 Agent",
|
||||
"channelAssignFailed": "分配 Channel 失败:{{error}}",
|
||||
"channelAssignFailed": "分配频道失败:{{error}}",
|
||||
"channelRemoved": "{{channel}} 已移除",
|
||||
"channelRemoveFailed": "移除 Channel 失败:{{error}}"
|
||||
"channelRemoveFailed": "移除频道失败:{{error}}"
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"title": "消息频道",
|
||||
"subtitle": "连接到消息平台,配置仅对主 Agent 生效。",
|
||||
"subtitle": "连接到消息平台,配置仅对主 Agent 生效",
|
||||
"refresh": "刷新",
|
||||
"addChannel": "添加频道",
|
||||
"stats": {
|
||||
@@ -183,8 +183,7 @@
|
||||
"阅读文档,前往飞书开放平台",
|
||||
"创建一个新应用",
|
||||
"获取 App ID 和 App Secret",
|
||||
"配置事件订阅",
|
||||
"注意:当前OpenClaw文档中未提及,但请务必在权限管理中添加 contact:contact.base:readonly **应用权限**,否则无法正常使用"
|
||||
"配置事件订阅"
|
||||
]
|
||||
},
|
||||
"wecom": {
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
"gatewayNotRunning": "网关未运行",
|
||||
"models": {
|
||||
"title": "模型",
|
||||
"subtitle": "管理您的 AI 提供商并监控 Token 用量。"
|
||||
"subtitle": "管理您的 AI 提供商并监控 Token 用量"
|
||||
},
|
||||
"quickActions": {
|
||||
"title": "快捷操作",
|
||||
@@ -60,4 +60,4 @@
|
||||
"contentDialogTitle": "用量明细内容",
|
||||
"close": "关闭"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -72,7 +72,7 @@ export function Agents() {
|
||||
>
|
||||
{t('title')}
|
||||
</h1>
|
||||
<p className="text-[17px] text-foreground/80 font-medium">{t('subtitle')}</p>
|
||||
<p className="text-[17px] text-foreground/70 font-medium">{t('subtitle')}</p>
|
||||
</div>
|
||||
<div className="flex items-center gap-3 md:mt-2">
|
||||
<Button
|
||||
@@ -244,7 +244,7 @@ function AgentCard({
|
||||
);
|
||||
}
|
||||
|
||||
const inputClasses = 'h-[44px] rounded-xl font-mono text-[13px] bg-[#eeece3] dark:bg-[#151514] border-black/10 dark:border-white/10 focus-visible:ring-2 focus-visible:ring-blue-500/50 focus-visible:border-blue-500 shadow-sm transition-all text-foreground placeholder:text-foreground/40';
|
||||
const inputClasses = 'h-[44px] rounded-xl font-mono text-[13px] bg-[#eeece3] dark:bg-muted border-black/10 dark:border-white/10 focus-visible:ring-2 focus-visible:ring-blue-500/50 focus-visible:border-blue-500 shadow-sm transition-all text-foreground placeholder:text-foreground/40';
|
||||
const labelClasses = 'text-[14px] text-foreground/80 font-bold';
|
||||
|
||||
function ChannelLogo({ type }: { type: ChannelType }) {
|
||||
@@ -294,7 +294,7 @@ function AddAgentDialog({
|
||||
|
||||
return (
|
||||
<div className="fixed inset-0 z-50 bg-black/50 flex items-center justify-center p-4">
|
||||
<Card className="w-full max-w-md rounded-3xl border-0 shadow-2xl bg-[#f3f1e9] dark:bg-[#1a1a19] overflow-hidden">
|
||||
<Card className="w-full max-w-md rounded-3xl border-0 shadow-2xl bg-[#f3f1e9] dark:bg-card overflow-hidden">
|
||||
<CardHeader className="pb-2">
|
||||
<CardTitle className="text-2xl font-serif font-normal tracking-tight">
|
||||
{t('createDialog.title')}
|
||||
@@ -405,7 +405,7 @@ function AgentSettingsModal({
|
||||
|
||||
return (
|
||||
<div className="fixed inset-0 z-50 bg-black/50 flex items-center justify-center p-4">
|
||||
<Card className="w-full max-w-2xl max-h-[90vh] flex flex-col rounded-3xl border-0 shadow-2xl bg-[#f3f1e9] dark:bg-[#1a1a19] overflow-hidden">
|
||||
<Card className="w-full max-w-2xl max-h-[90vh] flex flex-col rounded-3xl border-0 shadow-2xl bg-[#f3f1e9] dark:bg-card overflow-hidden">
|
||||
<CardHeader className="flex flex-row items-start justify-between pb-2 shrink-0">
|
||||
<div>
|
||||
<CardTitle className="text-2xl font-serif font-normal tracking-tight">
|
||||
@@ -441,7 +441,7 @@ function AgentSettingsModal({
|
||||
variant="outline"
|
||||
onClick={() => void handleSaveName()}
|
||||
disabled={savingName || !name.trim() || name.trim() === agent.name}
|
||||
className="h-[44px] text-[13px] font-medium rounded-xl px-4 border-black/10 dark:border-white/10 bg-[#eeece3] dark:bg-[#151514] hover:bg-black/5 dark:hover:bg-white/5 shadow-none text-foreground/80 hover:text-foreground"
|
||||
className="h-[44px] text-[13px] font-medium rounded-xl px-4 border-black/10 dark:border-white/10 bg-[#eeece3] dark:bg-muted hover:bg-black/5 dark:hover:bg-white/5 shadow-none text-foreground/80 hover:text-foreground"
|
||||
>
|
||||
{savingName ? (
|
||||
<RefreshCw className="h-4 w-4 animate-spin" />
|
||||
|
||||
@@ -103,7 +103,7 @@ export function Channels() {
|
||||
<h1 className="text-5xl md:text-6xl font-serif text-foreground mb-3 font-normal tracking-tight" style={{ fontFamily: 'Georgia, Cambria, "Times New Roman", Times, serif' }}>
|
||||
{t('title')}
|
||||
</h1>
|
||||
<p className="text-[17px] text-foreground/80 font-medium">
|
||||
<p className="text-[17px] text-foreground/70 font-medium">
|
||||
{t('subtitle')}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@@ -408,7 +408,7 @@ export function ChatInput({ onSend, onStop, disabled = false, sending = false, i
|
||||
)}
|
||||
|
||||
{/* Input Row */}
|
||||
<div className={`relative bg-white dark:bg-[#1a1a19] rounded-[28px] shadow-sm border p-1.5 transition-all ${dragOver ? 'border-primary ring-1 ring-primary' : 'border-black/10 dark:border-white/10'}`}>
|
||||
<div className={`relative bg-white dark:bg-card rounded-[28px] shadow-sm border p-1.5 transition-all ${dragOver ? 'border-primary ring-1 ring-primary' : 'border-black/10 dark:border-white/10'}`}>
|
||||
{selectedTarget && (
|
||||
<div className="px-2.5 pt-2 pb-1">
|
||||
<button
|
||||
@@ -452,7 +452,7 @@ export function ChatInput({ onSend, onStop, disabled = false, sending = false, i
|
||||
<AtSign className="h-4 w-4" />
|
||||
</Button>
|
||||
{pickerOpen && (
|
||||
<div className="absolute left-0 bottom-full z-20 mb-2 w-72 overflow-hidden rounded-2xl border border-black/10 bg-white p-1.5 shadow-xl dark:border-white/10 dark:bg-[#1a1a19]">
|
||||
<div className="absolute left-0 bottom-full z-20 mb-2 w-72 overflow-hidden rounded-2xl border border-black/10 bg-white p-1.5 shadow-xl dark:border-white/10 dark:bg-card">
|
||||
<div className="px-3 py-2 text-[11px] font-medium text-muted-foreground/80">
|
||||
{t('composer.agentPickerTitle', { currentAgent: currentAgentName })}
|
||||
</div>
|
||||
|
||||
@@ -234,7 +234,7 @@ function TaskDialog({ job, onClose, onSave }: TaskDialogProps) {
|
||||
|
||||
return (
|
||||
<div className="fixed inset-0 z-50 bg-black/50 flex items-center justify-center p-4" onClick={onClose}>
|
||||
<Card className="w-full max-w-lg max-h-[90vh] flex flex-col rounded-3xl border-0 shadow-2xl bg-[#f3f1e9] dark:bg-[#1a1a19] overflow-hidden" onClick={(e) => e.stopPropagation()}>
|
||||
<Card className="w-full max-w-lg max-h-[90vh] flex flex-col rounded-3xl border-0 shadow-2xl bg-[#f3f1e9] dark:bg-card overflow-hidden" onClick={(e) => e.stopPropagation()}>
|
||||
<CardHeader className="flex flex-row items-start justify-between pb-2 shrink-0">
|
||||
<div>
|
||||
<CardTitle className="text-2xl font-serif font-normal">{job ? t('dialog.editTitle') : t('dialog.createTitle')}</CardTitle>
|
||||
@@ -253,7 +253,7 @@ function TaskDialog({ job, onClose, onSave }: TaskDialogProps) {
|
||||
placeholder={t('dialog.taskNamePlaceholder')}
|
||||
value={name}
|
||||
onChange={(e) => setName(e.target.value)}
|
||||
className="h-[44px] rounded-xl font-mono text-[13px] bg-[#eeece3] dark:bg-[#151514] border-black/10 dark:border-white/10 focus-visible:ring-2 focus-visible:ring-blue-500/50 focus-visible:border-blue-500 shadow-sm transition-all text-foreground placeholder:text-foreground/40"
|
||||
className="h-[44px] rounded-xl font-mono text-[13px] bg-[#eeece3] dark:bg-muted border-black/10 dark:border-white/10 focus-visible:ring-2 focus-visible:ring-primary/50 focus-visible:border-primary shadow-sm transition-all text-foreground placeholder:text-foreground/40"
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -266,7 +266,7 @@ function TaskDialog({ job, onClose, onSave }: TaskDialogProps) {
|
||||
value={message}
|
||||
onChange={(e) => setMessage(e.target.value)}
|
||||
rows={3}
|
||||
className="rounded-xl font-mono text-[13px] bg-[#eeece3] dark:bg-[#151514] border-black/10 dark:border-white/10 focus-visible:ring-2 focus-visible:ring-blue-500/50 focus-visible:border-blue-500 shadow-sm transition-all text-foreground placeholder:text-foreground/40 resize-none"
|
||||
className="rounded-xl font-mono text-[13px] bg-[#eeece3] dark:bg-muted border-black/10 dark:border-white/10 focus-visible:ring-2 focus-visible:ring-primary/50 focus-visible:border-primary shadow-sm transition-all text-foreground placeholder:text-foreground/40 resize-none"
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -285,8 +285,8 @@ function TaskDialog({ job, onClose, onSave }: TaskDialogProps) {
|
||||
className={cn(
|
||||
"justify-start h-10 rounded-xl font-medium text-[13px] transition-all",
|
||||
schedule === preset.value
|
||||
? "bg-[#0a84ff] hover:bg-[#007aff] text-white shadow-sm border-transparent"
|
||||
: "bg-[#eeece3] dark:bg-[#151514] border-black/10 dark:border-white/10 hover:bg-black/5 dark:hover:bg-white/5 text-foreground/80 hover:text-foreground"
|
||||
? "bg-primary hover:bg-primary/90 text-primary-foreground shadow-sm border-transparent"
|
||||
: "bg-[#eeece3] dark:bg-muted border-black/10 dark:border-white/10 hover:bg-black/5 dark:hover:bg-white/5 text-foreground/80 hover:text-foreground"
|
||||
)}
|
||||
>
|
||||
<Timer className="h-4 w-4 mr-2 opacity-70" />
|
||||
@@ -299,7 +299,7 @@ function TaskDialog({ job, onClose, onSave }: TaskDialogProps) {
|
||||
placeholder={t('dialog.cronPlaceholder')}
|
||||
value={customSchedule}
|
||||
onChange={(e) => setCustomSchedule(e.target.value)}
|
||||
className="h-[44px] rounded-xl font-mono text-[13px] bg-[#eeece3] dark:bg-[#151514] border-black/10 dark:border-white/10 focus-visible:ring-2 focus-visible:ring-blue-500/50 focus-visible:border-blue-500 shadow-sm transition-all text-foreground placeholder:text-foreground/40"
|
||||
className="h-[44px] rounded-xl font-mono text-[13px] bg-[#eeece3] dark:bg-muted border-black/10 dark:border-white/10 focus-visible:ring-2 focus-visible:ring-primary/50 focus-visible:border-primary shadow-sm transition-all text-foreground placeholder:text-foreground/40"
|
||||
/>
|
||||
)}
|
||||
<div className="flex items-center justify-between mt-2">
|
||||
@@ -319,7 +319,7 @@ function TaskDialog({ job, onClose, onSave }: TaskDialogProps) {
|
||||
</div>
|
||||
|
||||
{/* Enabled */}
|
||||
<div className="flex items-center justify-between bg-[#eeece3] dark:bg-[#151514] p-4 rounded-2xl shadow-sm border border-black/5 dark:border-white/5">
|
||||
<div className="flex items-center justify-between bg-[#eeece3] dark:bg-muted p-4 rounded-2xl shadow-sm border border-black/5 dark:border-white/5">
|
||||
<div>
|
||||
<Label className="text-[14px] text-foreground/80 font-bold">{t('dialog.enableImmediately')}</Label>
|
||||
<p className="text-[13px] text-muted-foreground mt-0.5">
|
||||
@@ -334,7 +334,7 @@ function TaskDialog({ job, onClose, onSave }: TaskDialogProps) {
|
||||
<Button variant="outline" onClick={onClose} className="rounded-full px-6 h-[42px] text-[13px] font-semibold border-black/20 dark:border-white/20 bg-transparent hover:bg-black/5 dark:hover:bg-white/5 text-foreground/80 hover:text-foreground shadow-sm">
|
||||
{t('common:actions.cancel', 'Cancel')}
|
||||
</Button>
|
||||
<Button onClick={handleSubmit} disabled={saving} className="rounded-full px-6 h-[42px] text-[13px] font-semibold bg-[#0a84ff] hover:bg-[#007aff] text-white shadow-sm border border-transparent transition-all">
|
||||
<Button onClick={handleSubmit} disabled={saving} className="rounded-full px-6 h-[42px] text-[13px] font-semibold shadow-sm border border-transparent transition-all">
|
||||
{saving ? (
|
||||
<>
|
||||
<Loader2 className="h-4 w-4 mr-2 animate-spin" />
|
||||
@@ -557,7 +557,7 @@ export function Cron() {
|
||||
<h1 className="text-5xl md:text-6xl font-serif text-foreground mb-3 font-normal tracking-tight" style={{ fontFamily: 'Georgia, Cambria, "Times New Roman", Times, serif' }}>
|
||||
{t('title')}
|
||||
</h1>
|
||||
<p className="text-[17px] text-foreground/80 font-medium">
|
||||
<p className="text-[17px] text-foreground/70 font-medium">
|
||||
{t('subtitle')}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@@ -164,7 +164,7 @@ export function Models() {
|
||||
<h1 className="text-5xl md:text-6xl font-serif text-foreground mb-3 font-normal tracking-tight" style={{ fontFamily: 'Georgia, Cambria, "Times New Roman", Times, serif' }}>
|
||||
{t('dashboard:models.title')}
|
||||
</h1>
|
||||
<p className="text-[17px] text-foreground/80 font-medium">
|
||||
<p className="text-[17px] text-foreground/70 font-medium">
|
||||
{t('dashboard:models.subtitle')}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@@ -368,7 +368,7 @@ export function Settings() {
|
||||
|
||||
return (
|
||||
<div className="flex flex-col -m-6 dark:bg-background h-[calc(100vh-2.5rem)] overflow-hidden">
|
||||
<div className="w-full max-w-4xl mx-auto flex flex-col h-full p-10 pt-16">
|
||||
<div className="w-full max-w-5xl mx-auto flex flex-col h-full p-10 pt-16">
|
||||
|
||||
{/* Header */}
|
||||
<div className="flex flex-col md:flex-row md:items-start justify-between mb-12 shrink-0 gap-4">
|
||||
@@ -376,7 +376,7 @@ export function Settings() {
|
||||
<h1 className="text-5xl md:text-6xl font-serif text-foreground mb-3 font-normal tracking-tight" style={{ fontFamily: 'Georgia, Cambria, "Times New Roman", Times, serif' }}>
|
||||
{t('title')}
|
||||
</h1>
|
||||
<p className="text-[17px] text-foreground/80 font-medium">
|
||||
<p className="text-[17px] text-foreground/70 font-medium">
|
||||
{t('subtitle')}
|
||||
</p>
|
||||
</div>
|
||||
@@ -491,7 +491,7 @@ export function Settings() {
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
<pre className="text-[12px] text-muted-foreground bg-white dark:bg-[#1a1a19] p-4 rounded-xl max-h-60 overflow-auto whitespace-pre-wrap font-mono border border-black/5 dark:border-white/5 shadow-inner">
|
||||
<pre className="text-[12px] text-muted-foreground bg-white dark:bg-card p-4 rounded-xl max-h-60 overflow-auto whitespace-pre-wrap font-mono border border-black/5 dark:border-white/5 shadow-inner">
|
||||
{logContent || t('chat:noLogs')}
|
||||
</pre>
|
||||
</div>
|
||||
@@ -760,25 +760,25 @@ export function Settings() {
|
||||
{showTelemetryViewer && (
|
||||
<div className="space-y-4 rounded-2xl border border-black/10 dark:border-white/10 p-5 bg-black/5 dark:bg-white/5">
|
||||
<div className="flex flex-wrap items-center gap-2">
|
||||
<Badge variant="secondary" className="rounded-full px-3 py-1 bg-white dark:bg-[#1a1a19] border border-black/5 dark:border-white/5">{t('developer.telemetryTotal')}: {telemetryStats.total}</Badge>
|
||||
<Badge variant={telemetryStats.errorCount > 0 ? 'destructive' : 'secondary'} className={cn("rounded-full px-3 py-1", telemetryStats.errorCount === 0 && "bg-white dark:bg-[#1a1a19] border border-black/5 dark:border-white/5")}>
|
||||
<Badge variant="secondary" className="rounded-full px-3 py-1 bg-white dark:bg-card border border-black/5 dark:border-white/5">{t('developer.telemetryTotal')}: {telemetryStats.total}</Badge>
|
||||
<Badge variant={telemetryStats.errorCount > 0 ? 'destructive' : 'secondary'} className={cn("rounded-full px-3 py-1", telemetryStats.errorCount === 0 && "bg-white dark:bg-card border border-black/5 dark:border-white/5")}>
|
||||
{t('developer.telemetryErrors')}: {telemetryStats.errorCount}
|
||||
</Badge>
|
||||
<Badge variant={telemetryStats.slowCount > 0 ? 'secondary' : 'outline'} className={cn("rounded-full px-3 py-1", telemetryStats.slowCount === 0 && "bg-white dark:bg-[#1a1a19] border border-black/5 dark:border-white/5")}>
|
||||
<Badge variant={telemetryStats.slowCount > 0 ? 'secondary' : 'outline'} className={cn("rounded-full px-3 py-1", telemetryStats.slowCount === 0 && "bg-white dark:bg-card border border-black/5 dark:border-white/5")}>
|
||||
{t('developer.telemetrySlow')}: {telemetryStats.slowCount}
|
||||
</Badge>
|
||||
<div className="ml-auto flex gap-2">
|
||||
<Button type="button" variant="outline" size="sm" onClick={handleCopyTelemetry} className="rounded-full h-8 px-4 bg-white dark:bg-[#1a1a19] border-black/5 dark:border-white/5 hover:bg-black/5 dark:hover:bg-white/10">
|
||||
<Button type="button" variant="outline" size="sm" onClick={handleCopyTelemetry} className="rounded-full h-8 px-4 bg-white dark:bg-card border-black/5 dark:border-white/5 hover:bg-black/5 dark:hover:bg-white/10">
|
||||
<Copy className="h-3.5 w-3.5 mr-1.5" />
|
||||
{t('common:actions.copy')}
|
||||
</Button>
|
||||
<Button type="button" variant="outline" size="sm" onClick={handleClearTelemetry} className="rounded-full h-8 px-4 bg-white dark:bg-[#1a1a19] border-black/5 dark:border-white/5 hover:bg-black/5 dark:hover:bg-white/10">
|
||||
<Button type="button" variant="outline" size="sm" onClick={handleClearTelemetry} className="rounded-full h-8 px-4 bg-white dark:bg-card border-black/5 dark:border-white/5 hover:bg-black/5 dark:hover:bg-white/10">
|
||||
{t('common:actions.clear')}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="max-h-80 overflow-auto rounded-xl border border-black/10 dark:border-white/10 bg-white dark:bg-[#1a1a19] shadow-inner">
|
||||
<div className="max-h-80 overflow-auto rounded-xl border border-black/10 dark:border-white/10 bg-white dark:bg-card shadow-inner">
|
||||
{telemetryByEvent.length > 0 && (
|
||||
<div className="border-b border-black/5 dark:border-white/5 bg-black/5 dark:bg-white/5 p-3">
|
||||
<p className="mb-3 text-[12px] font-semibold text-muted-foreground">
|
||||
@@ -788,7 +788,7 @@ export function Settings() {
|
||||
{telemetryByEvent.map((item) => (
|
||||
<div
|
||||
key={item.event}
|
||||
className="grid grid-cols-[minmax(0,1.6fr)_0.7fr_0.9fr_0.8fr_1fr] gap-2 rounded-lg border border-black/5 dark:border-white/5 bg-white dark:bg-[#1a1a19] px-3 py-2"
|
||||
className="grid grid-cols-[minmax(0,1.6fr)_0.7fr_0.9fr_0.8fr_1fr] gap-2 rounded-lg border border-black/5 dark:border-white/5 bg-white dark:bg-card px-3 py-2"
|
||||
>
|
||||
<span className="truncate font-medium" title={item.event}>{item.event}</span>
|
||||
<span className="text-muted-foreground">n={item.count}</span>
|
||||
|
||||
@@ -158,16 +158,16 @@ function SkillDetailDialog({ skill, isOpen, onClose, onToggle, onUninstall }: Sk
|
||||
return (
|
||||
<Sheet open={isOpen} onOpenChange={(open) => !open && onClose()}>
|
||||
<SheetContent
|
||||
className="w-full sm:max-w-[450px] p-0 flex flex-col border-l border-black/10 dark:border-white/10 bg-[#f3f1e9] dark:bg-[#1a1a19] shadow-[0_0_40px_rgba(0,0,0,0.2)]"
|
||||
className="w-full sm:max-w-[450px] p-0 flex flex-col border-l border-black/10 dark:border-white/10 bg-[#f3f1e9] dark:bg-card shadow-[0_0_40px_rgba(0,0,0,0.2)]"
|
||||
side="right"
|
||||
>
|
||||
{/* Scrollable Content */}
|
||||
<div className="flex-1 overflow-y-auto px-8 py-10">
|
||||
<div className="flex flex-col items-center mb-8">
|
||||
<div className="w-16 h-16 flex items-center justify-center rounded-full bg-white dark:bg-[#2c2c2a] border border-black/5 dark:border-white/5 shrink-0 mb-4 relative shadow-sm">
|
||||
<div className="w-16 h-16 flex items-center justify-center rounded-full bg-white dark:bg-accent border border-black/5 dark:border-white/5 shrink-0 mb-4 relative shadow-sm">
|
||||
<span className="text-3xl">{skill.icon || '🔧'}</span>
|
||||
{skill.isCore && (
|
||||
<div className="absolute -bottom-1 -right-1 bg-[#f3f1e9] dark:bg-[#1a1a19] rounded-full p-1 shadow-sm border border-black/5 dark:border-white/5">
|
||||
<div className="absolute -bottom-1 -right-1 bg-[#f3f1e9] dark:bg-card rounded-full p-1 shadow-sm border border-black/5 dark:border-white/5">
|
||||
<Lock className="h-3 w-3 text-muted-foreground shrink-0" />
|
||||
</div>
|
||||
)}
|
||||
@@ -204,7 +204,7 @@ function SkillDetailDialog({ skill, isOpen, onClose, onToggle, onUninstall }: Sk
|
||||
value={apiKey}
|
||||
onChange={(e) => setApiKey(e.target.value)}
|
||||
type="password"
|
||||
className="h-[44px] font-mono text-[13px] bg-[#eeece3] dark:bg-[#151514] border-black/10 dark:border-white/10 rounded-xl focus-visible:ring-2 focus-visible:ring-blue-500/50 focus-visible:border-blue-500 shadow-sm transition-all text-foreground placeholder:text-foreground/40"
|
||||
className="h-[44px] font-mono text-[13px] bg-[#eeece3] dark:bg-muted border-black/10 dark:border-white/10 rounded-xl focus-visible:ring-2 focus-visible:ring-blue-500/50 focus-visible:border-blue-500 shadow-sm transition-all text-foreground placeholder:text-foreground/40"
|
||||
/>
|
||||
<p className="text-[12px] text-foreground/50 mt-2 font-medium">
|
||||
{t('detail.apiKeyDesc', 'The primary API key for this skill. Leave blank if not required or configured elsewhere.')}
|
||||
@@ -239,7 +239,7 @@ function SkillDetailDialog({ skill, isOpen, onClose, onToggle, onUninstall }: Sk
|
||||
|
||||
<div className="space-y-2">
|
||||
{envVars.length === 0 && (
|
||||
<div className="text-[13px] text-foreground/50 font-medium italic flex items-center bg-[#eeece3] dark:bg-[#151514] border border-black/5 dark:border-white/5 rounded-xl px-4 py-3 shadow-sm">
|
||||
<div className="text-[13px] text-foreground/50 font-medium italic flex items-center bg-[#eeece3] dark:bg-muted border border-black/5 dark:border-white/5 rounded-xl px-4 py-3 shadow-sm">
|
||||
{t('detail.noEnvVars', 'No environment variables configured.')}
|
||||
</div>
|
||||
)}
|
||||
@@ -249,13 +249,13 @@ function SkillDetailDialog({ skill, isOpen, onClose, onToggle, onUninstall }: Sk
|
||||
<Input
|
||||
value={env.key}
|
||||
onChange={(e) => handleUpdateEnv(index, 'key', e.target.value)}
|
||||
className="flex-1 h-[40px] font-mono text-[13px] bg-[#eeece3] dark:bg-[#151514] border-black/10 dark:border-white/10 rounded-xl focus-visible:ring-2 focus-visible:ring-blue-500/50 shadow-sm text-foreground"
|
||||
className="flex-1 h-[40px] font-mono text-[13px] bg-[#eeece3] dark:bg-muted border-black/10 dark:border-white/10 rounded-xl focus-visible:ring-2 focus-visible:ring-blue-500/50 shadow-sm text-foreground"
|
||||
placeholder={t('detail.keyPlaceholder', 'Key')}
|
||||
/>
|
||||
<Input
|
||||
value={env.value}
|
||||
onChange={(e) => handleUpdateEnv(index, 'value', e.target.value)}
|
||||
className="flex-1 h-[40px] font-mono text-[13px] bg-[#eeece3] dark:bg-[#151514] border-black/10 dark:border-white/10 rounded-xl focus-visible:ring-2 focus-visible:ring-blue-500/50 shadow-sm text-foreground"
|
||||
className="flex-1 h-[40px] font-mono text-[13px] bg-[#eeece3] dark:bg-muted border-black/10 dark:border-white/10 rounded-xl focus-visible:ring-2 focus-visible:ring-blue-500/50 shadow-sm text-foreground"
|
||||
placeholder={t('detail.valuePlaceholder', 'Value')}
|
||||
/>
|
||||
<Button
|
||||
@@ -556,7 +556,7 @@ export function Skills() {
|
||||
<h1 className="text-5xl md:text-6xl font-serif text-foreground mb-3 font-normal tracking-tight" style={{ fontFamily: 'Georgia, Cambria, "Times New Roman", Times, serif' }}>
|
||||
{t('title')}
|
||||
</h1>
|
||||
<p className="text-[17px] text-foreground/80 font-medium">
|
||||
<p className="text-[17px] text-foreground/70 font-medium">
|
||||
{t('subtitle')}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@@ -27,26 +27,27 @@
|
||||
--radius: 0.5rem;
|
||||
}
|
||||
|
||||
/* Neutral deep-gray dark palette */
|
||||
.dark {
|
||||
--background: 222.2 84% 4.9%;
|
||||
--foreground: 210 40% 98%;
|
||||
--card: 222.2 84% 4.9%;
|
||||
--card-foreground: 210 40% 98%;
|
||||
--popover: 222.2 84% 4.9%;
|
||||
--popover-foreground: 210 40% 98%;
|
||||
--background: 240 4% 11%;
|
||||
--foreground: 210 20% 96%;
|
||||
--card: 240 3% 14%;
|
||||
--card-foreground: 210 20% 96%;
|
||||
--popover: 240 3% 14%;
|
||||
--popover-foreground: 210 20% 96%;
|
||||
--primary: 217.2 91.2% 59.8%;
|
||||
--primary-foreground: 222.2 47.4% 11.2%;
|
||||
--secondary: 217.2 32.6% 17.5%;
|
||||
--secondary-foreground: 210 40% 98%;
|
||||
--muted: 217.2 32.6% 17.5%;
|
||||
--muted-foreground: 215 20.2% 65.1%;
|
||||
--accent: 217.2 32.6% 17.5%;
|
||||
--accent-foreground: 210 40% 98%;
|
||||
--destructive: 0 62.8% 30.6%;
|
||||
--destructive-foreground: 210 40% 98%;
|
||||
--border: 217.2 32.6% 17.5%;
|
||||
--input: 217.2 32.6% 17.5%;
|
||||
--ring: 224.3 76.3% 48%;
|
||||
--primary-foreground: 210 40% 98%;
|
||||
--secondary: 240 3% 18%;
|
||||
--secondary-foreground: 210 20% 96%;
|
||||
--muted: 240 3% 18%;
|
||||
--muted-foreground: 220 8% 72%;
|
||||
--accent: 240 3% 22%;
|
||||
--accent-foreground: 210 20% 96%;
|
||||
--destructive: 0 65% 42%;
|
||||
--destructive-foreground: 210 20% 96%;
|
||||
--border: 240 3% 24%;
|
||||
--input: 240 3% 18%;
|
||||
--ring: 217.2 91.2% 59.8%;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -375,7 +375,6 @@ export const CHANNEL_META: Record<ChannelType, ChannelMeta> = {
|
||||
'channels:meta.feishu.instructions.1',
|
||||
'channels:meta.feishu.instructions.2',
|
||||
'channels:meta.feishu.instructions.3',
|
||||
'channels:meta.feishu.instructions.4',
|
||||
],
|
||||
isPlugin: true,
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user