feat(web): OpenClaw 風格龍蝦 SVG + 三色狀態燈號 + 測試修正
Some checks failed
CD Pipeline / build-and-deploy (push) Failing after 1m39s
Some checks failed
CD Pipeline / build-and-deploy (push) Failing after 1m39s
前端: - OpenClawLobster 全新 SVG (參考 dashboardicons.com/icons/openclaw) 圓潤身體 + 大眼睛 + 鉗子 + 觸角 + 微笑 + 小腳 - 三色版本: red(異常/預設) / green(健康) / yellow(警告) - LobsterLoading 改用新 SVG 測試修正: - test_nemotron_failure_still_returns_proposal: func_body 截取 5000→10000 原因: 函數超過 5000 字元,導致 rfind 找不到最後的 return Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -178,7 +178,7 @@ class TestNemotronFailureFallback:
|
||||
source = f.read()
|
||||
|
||||
idx_func = source.find("async def generate_incident_proposal_with_tools")
|
||||
func_body = source[idx_func:idx_func + 5000]
|
||||
func_body = source[idx_func:idx_func + 10000]
|
||||
|
||||
# 最後的 return 在 except 之後
|
||||
idx_except = func_body.rfind("except Exception")
|
||||
|
||||
@@ -11,20 +11,80 @@
|
||||
|
||||
import { useTranslations } from 'next-intl'
|
||||
|
||||
// =============================================================================
|
||||
// OpenClaw 風格龍蝦 SVG (參考 dashboardicons.com/icons/openclaw)
|
||||
// 圓潤可愛風格 + 三色版本: red(預設/異常) / green(健康) / yellow(警告)
|
||||
// =============================================================================
|
||||
|
||||
type LobsterColor = 'red' | 'green' | 'yellow'
|
||||
|
||||
const COLOR_MAP: Record<LobsterColor, { body: string; dark: string; eye: string }> = {
|
||||
red: { body: '#ef0011', dark: '#8a000a', eye: '#0b0303' },
|
||||
green: { body: '#22C55E', dark: '#15803d', eye: '#0b0303' },
|
||||
yellow: { body: '#F59E0B', dark: '#b45309', eye: '#0b0303' },
|
||||
}
|
||||
|
||||
/** OpenClaw 風格可愛龍蝦 SVG */
|
||||
export function OpenClawLobster({ size = 36, color = 'red' }: { size?: number; color?: LobsterColor }) {
|
||||
const c = COLOR_MAP[color]
|
||||
return (
|
||||
<svg width={size} height={size} viewBox="0 0 100 100" fill="none">
|
||||
{/* 身體 (圓潤橢圓) */}
|
||||
<ellipse cx="50" cy="58" rx="28" ry="32" fill={c.body} />
|
||||
{/* 頭 (大圓) */}
|
||||
<circle cx="50" cy="35" r="22" fill={c.body} />
|
||||
{/* 肚子高光 */}
|
||||
<ellipse cx="50" cy="60" rx="18" ry="20" fill={c.body} opacity="0.6" />
|
||||
<ellipse cx="48" cy="56" rx="12" ry="14" fill="white" opacity="0.15" />
|
||||
{/* 眼睛 (大圓白底 + 黑瞳) */}
|
||||
<circle cx="40" cy="30" r="7" fill="white" />
|
||||
<circle cx="60" cy="30" r="7" fill="white" />
|
||||
<circle cx="41" cy="31" r="4" fill={c.eye} />
|
||||
<circle cx="61" cy="31" r="4" fill={c.eye} />
|
||||
{/* 眼睛高光 */}
|
||||
<circle cx="43" cy="29" r="1.5" fill="white" />
|
||||
<circle cx="63" cy="29" r="1.5" fill="white" />
|
||||
{/* 左鉗 */}
|
||||
<ellipse cx="16" cy="52" rx="10" ry="8" fill={c.body} transform="rotate(-15 16 52)" />
|
||||
<ellipse cx="13" cy="48" rx="6" ry="5" fill={c.body} transform="rotate(-20 13 48)" />
|
||||
<path d="M22 56 Q24 50 22 44" stroke={c.dark} strokeWidth="1.5" fill="none" strokeLinecap="round" />
|
||||
{/* 右鉗 */}
|
||||
<ellipse cx="84" cy="52" rx="10" ry="8" fill={c.body} transform="rotate(15 84 52)" />
|
||||
<ellipse cx="87" cy="48" rx="6" ry="5" fill={c.body} transform="rotate(20 87 48)" />
|
||||
<path d="M78 56 Q76 50 78 44" stroke={c.dark} strokeWidth="1.5" fill="none" strokeLinecap="round" />
|
||||
{/* 觸角 */}
|
||||
<path d="M38 16 Q32 4 24 8" stroke={c.dark} strokeWidth="2" fill="none" strokeLinecap="round" />
|
||||
<circle cx="24" cy="8" r="3" fill={c.body} />
|
||||
<path d="M62 16 Q68 4 76 8" stroke={c.dark} strokeWidth="2" fill="none" strokeLinecap="round" />
|
||||
<circle cx="76" cy="8" r="3" fill={c.body} />
|
||||
{/* 嘴巴 (微笑) */}
|
||||
<path d="M43 40 Q50 46 57 40" stroke={c.dark} strokeWidth="1.5" fill="none" strokeLinecap="round" />
|
||||
{/* 腳 */}
|
||||
<line x1="35" y1="82" x2="30" y2="94" stroke={c.dark} strokeWidth="2" strokeLinecap="round" />
|
||||
<line x1="45" y1="84" x2="42" y2="96" stroke={c.dark} strokeWidth="2" strokeLinecap="round" />
|
||||
<line x1="55" y1="84" x2="58" y2="96" stroke={c.dark} strokeWidth="2" strokeLinecap="round" />
|
||||
<line x1="65" y1="82" x2="70" y2="94" stroke={c.dark} strokeWidth="2" strokeLinecap="round" />
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// Loading 元件
|
||||
// =============================================================================
|
||||
|
||||
interface LobsterLoadingProps {
|
||||
/** 自訂提示文字 (預設 '載入中...') */
|
||||
text?: string
|
||||
/** 大小: 'sm' (24px) | 'md' (36px) | 'lg' (48px) */
|
||||
size?: 'sm' | 'md' | 'lg'
|
||||
color?: LobsterColor
|
||||
}
|
||||
|
||||
const SIZES = {
|
||||
sm: { svg: 24, bob: 2, fontSize: 11 },
|
||||
md: { svg: 36, bob: 3, fontSize: 12 },
|
||||
lg: { svg: 48, bob: 4, fontSize: 13 },
|
||||
sm: { svg: 28, bob: 2, fontSize: 11 },
|
||||
md: { svg: 40, bob: 3, fontSize: 12 },
|
||||
lg: { svg: 56, bob: 4, fontSize: 13 },
|
||||
}
|
||||
|
||||
export function LobsterLoading({ text, size = 'md' }: LobsterLoadingProps) {
|
||||
export function LobsterLoading({ text, size = 'md', color = 'red' }: LobsterLoadingProps) {
|
||||
const tc = useTranslations('common')
|
||||
const s = SIZES[size]
|
||||
const displayText = text ?? tc('loading')
|
||||
@@ -46,23 +106,7 @@ export function LobsterLoading({ text, size = 'md' }: LobsterLoadingProps) {
|
||||
}
|
||||
`}</style>
|
||||
<div style={{ animation: 'lobster-loading-bob 1.2s ease-in-out infinite' }}>
|
||||
<svg width={s.svg} height={Math.round(s.svg * 20 / 18)} viewBox="0 0 18 20" fill="none">
|
||||
<ellipse cx="9" cy="13" rx="5.5" ry="6.5" fill="#E85530" opacity="0.9" />
|
||||
<circle cx="9" cy="7.5" r="4.5" fill="#E85530" opacity="0.9" />
|
||||
<circle cx="7" cy="6.5" r="1" fill="#b03a1a" />
|
||||
<circle cx="11" cy="6.5" r="1" fill="#b03a1a" />
|
||||
{/* 左鉗 */}
|
||||
<path d="M3.5 10 Q1 9 1.5 12 Q2 14 4 13" stroke="#E85530" strokeWidth="1.2" fill="none" strokeLinecap="round" />
|
||||
<ellipse cx="1.5" cy="12" rx="1.2" ry="1.5" fill="#E85530" opacity="0.7" transform="rotate(-10 1.5 12)" />
|
||||
{/* 右鉗 */}
|
||||
<path d="M14.5 10 Q17 9 16.5 12 Q16 14 14 13" stroke="#E85530" strokeWidth="1.2" fill="none" strokeLinecap="round" />
|
||||
<ellipse cx="16.5" cy="12" rx="1.2" ry="1.5" fill="#E85530" opacity="0.7" transform="rotate(10 16.5 12)" />
|
||||
{/* 觸角 */}
|
||||
<path d="M7 3 Q5 1 3 2" stroke="#b03a1a" strokeWidth="0.8" fill="none" strokeLinecap="round" />
|
||||
<path d="M11 3 Q13 1 15 2" stroke="#b03a1a" strokeWidth="0.8" fill="none" strokeLinecap="round" />
|
||||
{/* 尾巴 */}
|
||||
<path d="M6 19 Q9 21 12 19" stroke="#E85530" strokeWidth="1.2" fill="none" strokeLinecap="round" />
|
||||
</svg>
|
||||
<OpenClawLobster size={s.svg} color={color} />
|
||||
</div>
|
||||
<div style={{
|
||||
fontSize: s.fontSize,
|
||||
|
||||
Reference in New Issue
Block a user