From 70dfa1c8f86f089ea4c92063b4296db4ced67f20 Mon Sep 17 00:00:00 2001 From: cfy666 <3087823110@qq.com> Date: Sun, 14 Jun 2026 10:18:36 +0800 Subject: [PATCH 1/2] =?UTF-8?q?feat=EF=BC=9A=E6=A0=B7=E5=BC=8F=E7=BE=8E?= =?UTF-8?q?=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/index.html | 5 +- frontend/src/App.css | 433 +++++++++++++------- frontend/src/App.tsx | 13 +- frontend/src/components/ChatPanel/index.tsx | 4 + 4 files changed, 302 insertions(+), 153 deletions(-) diff --git a/frontend/index.html b/frontend/index.html index 0fca6f0..bbbb74b 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -1,10 +1,11 @@ - + - frontend + + CamTalk — AI 视觉对话助手
diff --git a/frontend/src/App.css b/frontend/src/App.css index 330c48c..fdfb826 100644 --- a/frontend/src/App.css +++ b/frontend/src/App.css @@ -1,33 +1,41 @@ /* ============================================================ CamTalk — Web 端应用样式 双栏布局:左侧视频面板 + 右侧聊天面板 + + 设计方向:深色科技极简,Ethereal Glass 美学 + 字体:Inter 优先,系统字体栈兜底 + 颜色:冷灰体系,单一蓝色强调色 ============================================================ */ :root { - --color-primary: #2563eb; - --color-primary-hover: #1d4ed8; - --color-bg: #0b0f1a; - --color-surface: #151b2b; - --color-surface-2: #1c2438; - --color-text: #e2e8f0; - --color-text-muted: #64748b; - --color-border: #1e293b; - --color-success: #22c55e; - --color-warning: #f59e0b; - --color-error: #ef4444; - --radius: 10px; - --radius-sm: 6px; + --color-primary: #3b82f6; + --color-primary-hover: #2563eb; + --color-bg: #0a0a0f; + --color-surface: #111118; + --color-surface-2: #1a1a24; + --color-surface-3: #22222e; + --color-text: #d4d4dc; + --color-text-muted: #5a5a6e; + --color-border: #1f1f2a; + --color-success: #34d399; + --color-warning: #fbbf24; + --color-error: #f87171; + --radius: 12px; + --radius-sm: 8px; + --transition-fast: 0.2s cubic-bezier(0.25, 0.46, 0.45, 0.94); + --transition-smooth: 0.4s cubic-bezier(0.16, 1, 0.3, 1); } [data-theme="light"] { --color-primary: #2563eb; --color-primary-hover: #1d4ed8; - --color-bg: #f1f5f9; + --color-bg: #f4f4f8; --color-surface: #ffffff; - --color-surface-2: #f8fafc; - --color-text: #0f172a; - --color-text-muted: #64748b; - --color-border: #e2e8f0; + --color-surface-2: #f0f0f5; + --color-surface-3: #e8e8ee; + --color-text: #111118; + --color-text-muted: #6b6b80; + --color-border: #dddde5; --color-success: #16a34a; --color-warning: #d97706; --color-error: #dc2626; @@ -44,9 +52,12 @@ html, body, #root { } body { - font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", sans-serif; + font-family: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif; + font-variant-numeric: tabular-nums; background: var(--color-bg); color: var(--color-text); + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; } /* ---- App Shell ---- */ @@ -64,11 +75,14 @@ body { display: flex; align-items: center; justify-content: space-between; - padding: 0 20px; - height: 48px; + padding: 0 24px; + height: 56px; background: var(--color-surface); border-bottom: 1px solid var(--color-border); + box-shadow: 0 1px 8px rgba(10, 10, 15, 0.3); flex-shrink: 0; + position: relative; + z-index: 10; } .header__left { @@ -78,14 +92,17 @@ body { } .header__title { - font-size: 1.2rem; - font-weight: 700; + font-size: 1.15rem; + font-weight: 600; + letter-spacing: -0.02em; color: var(--color-text); } .header__subtitle { - font-size: 0.8rem; + font-size: 0.78rem; + font-weight: 400; color: var(--color-text-muted); + letter-spacing: 0.01em; } .header__right { @@ -95,30 +112,34 @@ body { } .header__stats { - font-size: 0.75rem; + font-size: 0.72rem; color: var(--color-text-muted); - padding: 4px 10px; + padding: 4px 12px; background: var(--color-surface-2); - border-radius: 12px; + border-radius: 20px; + font-weight: 500; + letter-spacing: 0.01em; } .badge { - font-size: 0.75rem; - padding: 3px 10px; - border-radius: 12px; + font-size: 0.72rem; + padding: 4px 12px; + border-radius: 20px; font-weight: 500; + letter-spacing: 0.01em; + transition: all var(--transition-fast); } .badge--connected { color: var(--color-success); - background: rgba(34, 197, 94, 0.1); - border: 1px solid rgba(34, 197, 94, 0.3); + background: rgba(52, 211, 153, 0.08); + border: 1px solid rgba(52, 211, 153, 0.2); } .badge--connecting { color: var(--color-warning); - background: rgba(245, 158, 11, 0.1); - border: 1px solid rgba(245, 158, 11, 0.3); + background: rgba(251, 191, 36, 0.08); + border: 1px solid rgba(251, 191, 36, 0.2); } .badge--disconnected { @@ -132,10 +153,13 @@ body { border: none; font-size: 1.1rem; cursor: pointer; - padding: 6px; + padding: 8px; border-radius: var(--radius-sm); - transition: background 0.15s; + transition: all var(--transition-fast); color: var(--color-text-muted); + display: inline-flex; + align-items: center; + justify-content: center; } .btn-icon:hover { @@ -143,6 +167,10 @@ body { color: var(--color-text); } +.btn-icon:active { + transform: scale(0.92); +} + .lang-group { display: flex; gap: 2px; @@ -158,9 +186,9 @@ body { font-size: 0.72rem; font-weight: 600; padding: 4px 10px; - border-radius: 4px; + border-radius: 6px; cursor: pointer; - transition: all 0.15s; + transition: all var(--transition-fast); } .lang-btn:hover { @@ -187,8 +215,8 @@ body { flex-shrink: 0; display: flex; flex-direction: column; - padding: 16px; - gap: 12px; + padding: 20px; + gap: 14px; } .video-container { @@ -198,6 +226,11 @@ body { border-radius: var(--radius); overflow: hidden; border: 1px solid var(--color-border); + transition: border-color var(--transition-fast); +} + +.video-container:hover { + border-color: var(--color-surface-3); } .video-container .video-preview { @@ -210,7 +243,7 @@ body { width: 100%; height: 100%; object-fit: cover; - background: #1a1a2e; + background: #12121a; } .video-placeholder { @@ -220,14 +253,15 @@ body { flex-direction: column; align-items: center; justify-content: center; - gap: 8px; + gap: 10px; color: var(--color-text-muted); font-size: 0.82rem; + font-weight: 400; } .video-placeholder__icon { - font-size: 2.4rem; - opacity: 0.2; + font-size: 2.2rem; + opacity: 0.15; margin-bottom: 4px; } @@ -235,14 +269,15 @@ body { position: absolute; bottom: 16px; left: 16px; - background: rgba(0, 0, 0, 0.75); - backdrop-filter: blur(8px); + background: rgba(10, 10, 15, 0.8); + backdrop-filter: blur(12px); + -webkit-backdrop-filter: blur(12px); color: var(--color-success); padding: 6px 14px; border-radius: var(--radius-sm); - font-size: 0.8rem; + font-size: 0.78rem; font-weight: 500; - animation: pulse 1.5s ease-in-out infinite; + animation: pulse 1.5s cubic-bezier(0.25, 0.46, 0.45, 0.94) infinite; } .live-badge { @@ -252,22 +287,23 @@ body { display: flex; align-items: center; gap: 6px; - background: rgba(0, 0, 0, 0.75); - backdrop-filter: blur(8px); + background: rgba(10, 10, 15, 0.8); + backdrop-filter: blur(12px); + -webkit-backdrop-filter: blur(12px); color: white; - padding: 4px 12px; + padding: 5px 12px; border-radius: var(--radius-sm); - font-size: 0.75rem; + font-size: 0.72rem; font-weight: 600; - letter-spacing: 0.5px; + letter-spacing: 0.04em; } .live-badge__dot { - width: 8px; - height: 8px; + width: 7px; + height: 7px; border-radius: 50%; background: var(--color-success); - animation: pulse 1.5s ease-in-out infinite; + animation: pulse 1.5s cubic-bezier(0.25, 0.46, 0.45, 0.94) infinite; } .video-indicator--loading { color: var(--color-warning); } @@ -278,45 +314,49 @@ body { position: absolute; top: 12px; right: 12px; - background: rgba(37, 99, 235, 0.85); - backdrop-filter: blur(8px); + background: rgba(59, 130, 246, 0.85); + backdrop-filter: blur(12px); + -webkit-backdrop-filter: blur(12px); color: white; padding: 3px 10px; border-radius: var(--radius-sm); - font-size: 0.7rem; + font-size: 0.68rem; font-weight: 700; - letter-spacing: 0.5px; + letter-spacing: 0.06em; } .observation-badge { position: absolute; top: 12px; left: 12px; - background: rgba(34, 197, 94, 0.85); - backdrop-filter: blur(8px); + background: rgba(52, 211, 153, 0.85); + backdrop-filter: blur(12px); + -webkit-backdrop-filter: blur(12px); color: white; padding: 3px 10px; border-radius: var(--radius-sm); - font-size: 0.7rem; + font-size: 0.68rem; font-weight: 700; - animation: pulse 2s ease-in-out infinite; + letter-spacing: 0.04em; + animation: pulse 2s cubic-bezier(0.25, 0.46, 0.45, 0.94) infinite; } .video-overlay { position: absolute; inset: 0; - background: rgba(0, 0, 0, 0.35); + background: rgba(10, 10, 15, 0.4); display: flex; align-items: center; justify-content: center; - backdrop-filter: blur(2px); + backdrop-filter: blur(3px); + -webkit-backdrop-filter: blur(3px); } .video-overlay__spinner { width: 36px; height: 36px; - border: 3px solid rgba(255, 255, 255, 0.2); - border-top-color: white; + border: 2.5px solid rgba(255, 255, 255, 0.15); + border-top-color: rgba(255, 255, 255, 0.8); border-radius: 50%; animation: spin 0.8s linear infinite; } @@ -327,53 +367,66 @@ body { flex-shrink: 0; display: flex; justify-content: center; - padding: 4px 0; + padding: 6px 0; } .video-controls__row { display: flex; - gap: 6px; + gap: 8px; flex-wrap: wrap; justify-content: center; } .btn--ctrl { - padding: 6px 12px; + padding: 7px 14px; font-size: 0.78rem; border-radius: var(--radius-sm); border: 1px solid var(--color-border); background: var(--color-surface-2); color: var(--color-text-muted); cursor: pointer; - transition: all 0.15s; + transition: all var(--transition-fast); white-space: nowrap; } .btn--ctrl:hover { - background: var(--color-border); + background: var(--color-surface-3); color: var(--color-text); + border-color: var(--color-surface-3); +} + +.btn--ctrl:active { + transform: translateY(1px); } .btn--ctrl-on { - background: rgba(34, 197, 94, 0.15); + background: rgba(52, 211, 153, 0.1); color: var(--color-success); - border-color: rgba(34, 197, 94, 0.3); + border-color: rgba(52, 211, 153, 0.25); +} + +.btn--ctrl-on:hover { + background: rgba(52, 211, 153, 0.18); } .btn--ctrl-off { - background: rgba(239, 68, 68, 0.1); + background: rgba(248, 113, 113, 0.08); color: var(--color-error); - border-color: rgba(239, 68, 68, 0.2); + border-color: rgba(248, 113, 113, 0.18); +} + +.btn--ctrl-off:hover { + background: rgba(248, 113, 113, 0.15); } .btn--speaking { - animation: micPulse 0.8s ease-in-out infinite; - box-shadow: 0 0 12px rgba(34, 197, 94, 0.5); + animation: micPulse 0.8s cubic-bezier(0.25, 0.46, 0.45, 0.94) infinite; + box-shadow: 0 0 12px rgba(52, 211, 153, 0.4); } @keyframes micPulse { - 0%, 100% { box-shadow: 0 0 8px rgba(34, 197, 94, 0.4); transform: scale(1); } - 50% { box-shadow: 0 0 16px rgba(34, 197, 94, 0.8); transform: scale(1.05); } + 0%, 100% { box-shadow: 0 0 8px rgba(52, 211, 153, 0.3); transform: scale(1); } + 50% { box-shadow: 0 0 18px rgba(52, 211, 153, 0.7); transform: scale(1.04); } } /* ---- 右侧聊天面板 ---- */ @@ -391,21 +444,23 @@ body { display: flex; align-items: center; justify-content: space-between; - padding: 12px 16px; + padding: 14px 24px; font-weight: 600; - font-size: 0.85rem; + font-size: 0.82rem; border-bottom: 1px solid var(--color-border); flex-shrink: 0; color: var(--color-text-muted); + letter-spacing: -0.01em; } .chat-panel-header__mode { - font-size: 0.7rem; + font-size: 0.68rem; font-weight: 500; color: var(--color-success); - background: rgba(34, 197, 94, 0.1); - padding: 2px 8px; - border-radius: 10px; + background: rgba(52, 211, 153, 0.08); + padding: 3px 10px; + border-radius: 12px; + letter-spacing: 0.02em; } .chat-panel-body { @@ -420,32 +475,57 @@ body { .chat-panel { flex: 1; overflow-y: auto; - padding: 12px 16px; + padding: 16px 24px; display: flex; flex-direction: column; - gap: 10px; + gap: 12px; } .chat-panel--empty { display: flex; + flex-direction: column; align-items: center; justify-content: center; flex: 1; + gap: 12px; color: var(--color-text-muted); font-size: 0.85rem; } +.chat-panel--empty-icon { + font-size: 2.4rem; + opacity: 0.12; + margin-bottom: 4px; +} + +.chat-panel--empty-hint { + font-size: 0.75rem; + opacity: 0.6; + max-width: 240px; + text-align: center; + line-height: 1.5; +} + .chat-message { - padding: 10px 14px; + padding: 12px 16px; border-radius: var(--radius-sm); background: var(--color-surface-2); - max-width: 92%; + max-width: min(92%, 65ch); + transition: background var(--transition-fast); +} + +.chat-message:hover { + background: var(--color-surface-3); } .chat-message--user { border-left: 2px solid var(--color-primary); align-self: flex-end; - background: rgba(37, 99, 235, 0.08); + background: rgba(59, 130, 246, 0.06); +} + +.chat-message--user:hover { + background: rgba(59, 130, 246, 0.1); } .chat-message--assistant { @@ -457,24 +537,27 @@ body { } .chat-message__role { - font-size: 0.65rem; + font-size: 0.62rem; font-weight: 600; text-transform: uppercase; - letter-spacing: 0.5px; + letter-spacing: 0.08em; color: var(--color-text-muted); - margin-bottom: 3px; + margin-bottom: 4px; } .chat-message__content { font-size: 0.82rem; - line-height: 1.55; + line-height: 1.65; white-space: pre-wrap; + max-width: 65ch; } .chat-message__meta { - margin-top: 6px; - font-size: 0.65rem; + margin-top: 8px; + font-size: 0.62rem; color: var(--color-text-muted); + font-weight: 400; + letter-spacing: 0.01em; } /* ---- Streaming Cursor ---- */ @@ -483,22 +566,24 @@ body { display: inline; animation: blink 0.8s step-end infinite; color: var(--color-success); + font-weight: 300; } /* ---- System Message ---- */ .system-message { text-align: center; - padding: 8px 16px; - margin: 0 20px; + padding: 10px 16px; + margin: 0 24px; border-radius: var(--radius-sm); - font-size: 0.8rem; + font-size: 0.78rem; + font-weight: 500; } .system-message--warning { - background: rgba(245, 158, 11, 0.1); + background: rgba(251, 191, 36, 0.08); color: var(--color-warning); - border: 1px solid rgba(245, 158, 11, 0.2); + border: 1px solid rgba(251, 191, 36, 0.15); } /* ---- Drawer (Config Panel) ---- */ @@ -507,9 +592,10 @@ body { position: fixed; inset: 0; z-index: 100; - background: rgba(0, 0, 0, 0.4); - backdrop-filter: blur(2px); - animation: fadeIn 0.2s ease; + background: rgba(10, 10, 15, 0.5); + backdrop-filter: blur(4px); + -webkit-backdrop-filter: blur(4px); + animation: fadeIn 0.25s var(--transition-smooth); } .drawer { @@ -522,22 +608,23 @@ body { border-left: 1px solid var(--color-border); display: flex; flex-direction: column; - animation: slideInRight 0.25s ease; - box-shadow: -8px 0 24px rgba(0, 0, 0, 0.3); + animation: slideInRight 0.35s var(--transition-smooth); + box-shadow: -8px 0 40px rgba(10, 10, 15, 0.5); } .drawer__header { display: flex; align-items: center; justify-content: space-between; - padding: 14px 16px; + padding: 16px 20px; border-bottom: 1px solid var(--color-border); flex-shrink: 0; } .drawer__title { font-weight: 600; - font-size: 0.9rem; + font-size: 0.88rem; + letter-spacing: -0.01em; } .drawer__close { @@ -546,9 +633,12 @@ body { color: var(--color-text-muted); cursor: pointer; font-size: 1rem; - padding: 4px 8px; + padding: 6px 8px; border-radius: var(--radius-sm); - transition: all 0.15s; + transition: all var(--transition-fast); + display: inline-flex; + align-items: center; + justify-content: center; } .drawer__close:hover { @@ -556,26 +646,30 @@ body { color: var(--color-text); } +.drawer__close:active { + transform: scale(0.92); +} + .drawer__body { flex: 1; overflow-y: auto; - padding: 16px; + padding: 20px; } /* ---- Config Group ---- */ .config-group { - margin-bottom: 20px; + margin-bottom: 24px; } .config-group__title { - font-size: 0.7rem; + font-size: 0.68rem; font-weight: 600; text-transform: uppercase; - letter-spacing: 0.8px; + letter-spacing: 0.1em; color: var(--color-text-muted); - margin-bottom: 12px; - padding-bottom: 8px; + margin-bottom: 14px; + padding-bottom: 10px; border-bottom: 1px solid var(--color-border); } @@ -583,16 +677,23 @@ body { display: flex; align-items: center; justify-content: space-between; - padding: 10px 0; + padding: 10px 8px; + margin: 0 -8px; font-size: 0.82rem; color: var(--color-text); cursor: pointer; + border-radius: var(--radius-sm); + transition: background var(--transition-fast); +} + +.config-row:hover { + background: var(--color-surface-2); } .config-row__info { display: flex; flex-direction: column; - gap: 2px; + gap: 3px; } .config-row__label { @@ -601,8 +702,9 @@ body { } .config-row__desc { - font-size: 0.72rem; + font-size: 0.7rem; color: var(--color-text-muted); + line-height: 1.4; } .config-row select, @@ -611,23 +713,36 @@ body { color: var(--color-text); border: 1px solid var(--color-border); border-radius: var(--radius-sm); - padding: 5px 10px; - font-size: 0.8rem; + padding: 6px 10px; + font-size: 0.78rem; cursor: pointer; + transition: all var(--transition-fast); +} + +.config-row select:hover, +.config-row input[type="checkbox"]:hover { + border-color: var(--color-surface-3); +} + +.config-row select:focus, +.config-row input[type="checkbox"]:focus { + outline: 2px solid rgba(59, 130, 246, 0.4); + outline-offset: 1px; } .config-row input[type="checkbox"] { width: 18px; height: 18px; cursor: pointer; + accent-color: var(--color-primary); } /* ---- Toast ---- */ .toast-container { position: fixed; - top: 68px; - right: 20px; + top: 72px; + right: 24px; z-index: 1000; display: flex; flex-direction: column; @@ -637,16 +752,30 @@ body { .toast { padding: 10px 16px; border-radius: var(--radius-sm); - font-size: 0.82rem; + font-size: 0.8rem; + font-weight: 500; cursor: pointer; - animation: slideIn 0.3s ease-out; + animation: slideIn 0.35s var(--transition-smooth); max-width: 320px; - backdrop-filter: blur(8px); + backdrop-filter: blur(12px); + -webkit-backdrop-filter: blur(12px); + box-shadow: 0 8px 32px rgba(10, 10, 15, 0.4); } -.toast--error { background: rgba(239, 68, 68, 0.9); color: white; } -.toast--warning { background: rgba(245, 158, 11, 0.9); color: #000; } -.toast--info { background: rgba(37, 99, 235, 0.9); color: white; } +.toast--error { + background: rgba(248, 113, 113, 0.92); + color: white; +} + +.toast--warning { + background: rgba(251, 191, 36, 0.92); + color: #111; +} + +.toast--info { + background: rgba(59, 130, 246, 0.92); + color: white; +} /* ---- Buttons ---- */ @@ -654,18 +783,23 @@ body { padding: 8px 20px; border: none; border-radius: var(--radius-sm); - font-size: 0.85rem; + font-size: 0.82rem; font-weight: 600; cursor: pointer; - transition: all 0.15s; + transition: all var(--transition-fast); display: inline-flex; align-items: center; gap: 6px; + letter-spacing: 0.01em; +} + +.btn:active { + transform: translateY(1px); } .btn--lg { padding: 12px 32px; - font-size: 0.95rem; + font-size: 0.92rem; border-radius: var(--radius); } @@ -685,43 +819,46 @@ body { } .btn--secondary:hover { - background: var(--color-border); + background: var(--color-surface-3); + border-color: var(--color-surface-3); } .btn--warning { background: var(--color-warning); - color: #000; + color: #111; } -.btn--warning:hover { opacity: 0.9; } +.btn--warning:hover { + opacity: 0.9; +} .btn--danger { - background: rgba(239, 68, 68, 0.15); + background: rgba(248, 113, 113, 0.1); color: var(--color-error); - border: 1px solid rgba(239, 68, 68, 0.3); + border: 1px solid rgba(248, 113, 113, 0.2); } .btn--danger:hover { - background: rgba(239, 68, 68, 0.25); + background: rgba(248, 113, 113, 0.18); } .btn--active { background: var(--color-primary); color: white; - box-shadow: 0 0 12px rgba(37, 99, 235, 0.4); - animation: pulseBtn 2s ease-in-out infinite; + box-shadow: 0 0 12px rgba(59, 130, 246, 0.35); + animation: pulseBtn 2s cubic-bezier(0.25, 0.46, 0.45, 0.94) infinite; } /* ---- Animations ---- */ @keyframes pulse { 0%, 100% { opacity: 1; } - 50% { opacity: 0.6; } + 50% { opacity: 0.55; } } @keyframes pulseBtn { - 0%, 100% { box-shadow: 0 0 12px rgba(37, 99, 235, 0.4); } - 50% { box-shadow: 0 0 20px rgba(37, 99, 235, 0.7); } + 0%, 100% { box-shadow: 0 0 12px rgba(59, 130, 246, 0.35); } + 50% { box-shadow: 0 0 22px rgba(59, 130, 246, 0.6); } } @keyframes blink { @@ -734,7 +871,7 @@ body { } @keyframes slideIn { - from { opacity: 0; transform: translateX(20px); } + from { opacity: 0; transform: translateX(16px); } to { opacity: 1; transform: translateX(0); } } @@ -751,7 +888,7 @@ body { /* ---- Scrollbar ---- */ ::-webkit-scrollbar { - width: 6px; + width: 4px; } ::-webkit-scrollbar-track { @@ -760,7 +897,7 @@ body { ::-webkit-scrollbar-thumb { background: var(--color-border); - border-radius: 3px; + border-radius: 2px; } ::-webkit-scrollbar-thumb:hover { diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index ffd567b..0ef33b5 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -108,8 +108,12 @@ function App() { className="btn-icon" onClick={() => setShowConfig((v) => !v)} title="设置" + aria-label="设置" > - ⚙️ + + + + @@ -161,8 +165,11 @@ function App() { )} {!isConnected && !stream && (
- 📷 - 点击右侧按钮开始对话 + + + + + 点击下方按钮开始对话
)} diff --git a/frontend/src/components/ChatPanel/index.tsx b/frontend/src/components/ChatPanel/index.tsx index bed57de..0e6ce3a 100644 --- a/frontend/src/components/ChatPanel/index.tsx +++ b/frontend/src/components/ChatPanel/index.tsx @@ -44,13 +44,17 @@ export function ChatPanel({ messages, currentReply, connectionStatus }: ChatPane if (connectionStatus !== "connected") { return (
+ 💬

点击下方按钮开始对话

+ 连接后可通过摄像头和麦克风与 AI 交互
); } return (
+ 🎙️

对着摄像头说话即可

+ AI 会自动识别你的语音并分析画面
); } -- 2.49.1 From bf0bb83f7dd6689a7f9e431e0d4f2368b4e649d5 Mon Sep 17 00:00:00 2001 From: cfy666 <3087823110@qq.com> Date: Sun, 14 Jun 2026 10:19:31 +0800 Subject: [PATCH 2/2] =?UTF-8?q?feat:=20=E5=A2=9E=E5=8A=A0=E5=89=8D?= =?UTF-8?q?=E7=AB=AF=E6=A0=B7=E5=BC=8F=E4=BC=98=E5=8C=96skill=E5=92=8Cmcp?= =?UTF-8?q?=E5=B7=A5=E5=85=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/.mcp.json | 11 + frontend/skills/redesign-skill.md | 188 +++++ frontend/skills/soft-skill.md | 98 +++ frontend/skills/taste-skill-main.md | 1206 +++++++++++++++++++++++++++ 功能创意.md | 6 + 5 files changed, 1509 insertions(+) create mode 100644 frontend/.mcp.json create mode 100644 frontend/skills/redesign-skill.md create mode 100644 frontend/skills/soft-skill.md create mode 100644 frontend/skills/taste-skill-main.md create mode 100644 功能创意.md diff --git a/frontend/.mcp.json b/frontend/.mcp.json new file mode 100644 index 0000000..bd98b4f --- /dev/null +++ b/frontend/.mcp.json @@ -0,0 +1,11 @@ +{ + "mcpServers": { + "shadcn": { + "command": "npx", + "args": [ + "shadcn@latest", + "mcp" + ] + } + } +} diff --git a/frontend/skills/redesign-skill.md b/frontend/skills/redesign-skill.md new file mode 100644 index 0000000..1f470c2 --- /dev/null +++ b/frontend/skills/redesign-skill.md @@ -0,0 +1,188 @@ +# Redesign Skill - Anti-Slop Frontend Framework + +> Source: https://github.com/Leonxlnx/taste-skill/tree/main/skills/redesign-skill +> Purpose: Audit and upgrade existing frontend code to eliminate generic AI-generated UI patterns. + +## How This Works + +When applied to an existing project, follow this sequence: + +1. **Scan** — Read the codebase. Identify the framework, styling method (Tailwind, vanilla CSS, styled-components, etc.), and current design patterns. +2. **Diagnose** — Run through the audit below. List every generic pattern, weak point, and missing state you find. +3. **Fix** — Apply targeted upgrades working with the existing stack. Do not rewrite from scratch. Improve what's there. + +--- + +## Design Audit + +### Typography + +Check for these problems and fix them: + +- **Browser default fonts or Inter everywhere.** Replace with a font that has character. Good options: `Geist`, `Outfit`, `Cabinet Grotesk`, `Satoshi`. For editorial/creative projects, pair a serif header with a sans-serif body. +- **Headlines lack presence.** Increase size for display text, tighten letter-spacing, reduce line-height. Headlines should feel heavy and intentional. +- **Body text too wide.** Limit paragraph width to roughly 65 characters. Increase line-height for readability. +- **Only Regular (400) and Bold (700) weights used.** Introduce Medium (500) and SemiBold (600) for more subtle hierarchy. +- **Numbers in proportional font.** Use a monospace font or enable tabular figures (`font-variant-numeric: tabular-nums`) for data-heavy interfaces. +- **Missing letter-spacing adjustments.** Use negative tracking for large headers, positive tracking for small caps or labels. +- **All-caps subheaders everywhere.** Try lowercase italics, sentence case, or small-caps instead. +- **Orphaned words.** Single words sitting alone on the last line. Fix with `text-wrap: balance` or `text-wrap: pretty`. + +### Color and Surfaces + +- **Pure `#000000` background.** Replace with off-black, dark charcoal, or tinted dark (`#0a0a0a`, `#121212`, or a dark navy). +- **Oversaturated accent colors.** Keep saturation below 80%. Desaturate accents so they blend with neutrals instead of screaming. +- **More than one accent color.** Pick one. Remove the rest. Consistency beats variety. +- **Mixing warm and cool grays.** Stick to one gray family. Tint all grays with a consistent hue (warm or cool, not both). +- **Purple/blue "AI gradient" aesthetic.** This is the most common AI design fingerprint. Replace with neutral bases and a single, considered accent. +- **Generic `box-shadow`.** Tint shadows to match the background hue. Use colored shadows (e.g., dark blue shadow on a blue background) instead of pure black at low opacity. +- **Flat design with zero texture.** Add subtle noise, grain, or micro-patterns to backgrounds. Pure flat vectors feel sterile. +- **Perfectly even gradients.** Break the uniformity with radial gradients, noise overlays, or mesh gradients instead of standard linear 45-degree fades. +- **Inconsistent lighting direction.** Audit all shadows to ensure they suggest a single, consistent light source. +- **Random dark sections in a light mode page (or vice versa).** A single dark-background section breaking an otherwise light page looks like a copy-paste accident. Either commit to a full dark mode or keep a consistent background tone throughout. If contrast is needed, use a slightly darker shade of the same palette — not a sudden jump to `#111` in the middle of a cream page. +- **Empty, flat sections with no visual depth.** Sections that are just text on a plain background feel unfinished. Add high-quality background imagery (blurred, overlaid, or masked), subtle patterns, or ambient gradients. Use reliable placeholder sources like `https://picsum.photos/seed/{name}/1920/1080` when real assets are not available. Experiment with background images behind hero sections, feature blocks, or CTAs — even a subtle full-width photo at low opacity adds presence. + +### Layout + +- **Everything centered and symmetrical.** Break symmetry with offset margins, mixed aspect ratios, or left-aligned headers over centered content. +- **Three equal card columns as feature row.** This is the most generic AI layout. Replace with a 2-column zig-zag, asymmetric grid, horizontal scroll, or masonry layout. +- **Using `height: 100vh` for full-screen sections.** Replace with `min-height: 100dvh` to prevent layout jumping on mobile browsers (iOS Safari viewport bug). +- **Complex flexbox percentage math.** Replace with CSS Grid for reliable multi-column structures. +- **No max-width container.** Add a container constraint (around 1200-1440px) with auto margins so content doesn't stretch edge-to-edge on wide screens. +- **Cards of equal height forced by flexbox.** Allow variable heights or use masonry when content varies in length. +- **Uniform border-radius on everything.** Vary the radius: tighter on inner elements, softer on containers. +- **No overlap or depth.** Elements sit flat next to each other. Use negative margins to create layering and visual depth. +- **Symmetrical vertical padding.** Top and bottom padding are always identical. Adjust optically — bottom padding often needs to be slightly larger. +- **Dashboard always has a left sidebar.** Try top navigation, a floating command menu, or a collapsible panel instead. +- **Missing whitespace.** Double the spacing. Let the design breathe. Dense layouts work for data dashboards, not for marketing pages. +- **Buttons not bottom-aligned in card groups.** When cards have different content lengths, CTAs end up at random heights. Pin buttons to the bottom of each card so they form a clean horizontal line regardless of content above. +- **Feature lists starting at different vertical positions.** In pricing tables or comparison cards, the list of features should start at the same Y position across all columns. Use consistent spacing above the list or fixed-height title/price blocks. +- **Inconsistent vertical rhythm in side-by-side elements.** When placing cards, columns, or panels next to each other, align shared elements (titles, descriptions, prices, buttons) across all items. Misaligned baselines make the layout look broken. +- **Mathematical alignment that looks optically wrong.** Centering by the math doesn't always look centered to the eye. Icons next to text, play buttons in circles, or text in buttons often need 1-2px optical adjustments to feel right. + +### Interactivity and States + +- **No hover states on buttons.** Add background shift, slight scale, or translate on hover. +- **No active/pressed feedback.** Add a subtle `scale(0.98)` or `translateY(1px)` on press to simulate a physical click. +- **Instant transitions with zero duration.** Add smooth transitions (200-300ms) to all interactive elements. +- **Missing focus ring.** Ensure visible focus indicators for keyboard navigation. This is an accessibility requirement, not optional. +- **No loading states.** Replace generic circular spinners with skeleton loaders that match the layout shape. +- **No empty states.** An empty dashboard showing nothing is a missed opportunity. Design a composed "getting started" view. +- **No error states.** Add clear, inline error messages for forms. Do not use `window.alert()`. +- **Dead links.** Buttons that link to `#`. Either link to real destinations or visually disable them. +- **No indication of current page in navigation.** Style the active nav link differently so users know where they are. +- **Scroll jumping.** Anchor clicks jump instantly. Add `scroll-behavior: smooth`. +- **Animations using `top`, `left`, `width`, `height`.** Switch to `transform` and `opacity` for GPU-accelerated, smooth animation. + +### Content + +- **Generic names like "John Doe" or "Jane Smith".** Use diverse, realistic-sounding names. +- **Fake round numbers like `99.99%`, `50%`, `$100.00`.** Use organic, messy data: `47.2%`, `$99.00`, `+1 (312) 847-1928`. +- **Placeholder company names like "Acme Corp", "Nexus", "SmartFlow".** Invent contextual, believable brand names. +- **AI copywriting cliches.** Never use "Elevate", "Seamless", "Unleash", "Next-Gen", "Game-changer", "Delve", "Tapestry", or "In the world of...". Write plain, specific language. +- **Exclamation marks in success messages.** Remove them. Be confident, not loud. +- **"Oops!" error messages.** Be direct: "Connection failed. Please try again." +- **Passive voice.** Use active voice: "We couldn't save your changes" instead of "Mistakes were made." +- **All blog post dates identical.** Randomize dates to appear real. +- **Same avatar image for multiple users.** Use unique assets for every distinct person. +- **Lorem Ipsum.** Never use placeholder latin text. Write real draft copy. +- **Title Case On Every Header.** Use sentence case instead. + +### Component Patterns + +- **Generic card look (border + shadow + white background).** Remove the border, or use only background color, or use only spacing. Cards should exist only when elevation communicates hierarchy. +- **Always one filled button + one ghost button.** Add text links or tertiary styles to reduce visual noise. +- **Pill-shaped "New" and "Beta" badges.** Try square badges, flags, or plain text labels. +- **Accordion FAQ sections.** Use a side-by-side list, searchable help, or inline progressive disclosure. +- **3-card carousel testimonials with dots.** Replace with a masonry wall, embedded social posts, or a single rotating quote. +- **Pricing table with 3 towers.** Highlight the recommended tier with color and emphasis, not just extra height. +- **Modals for everything.** Use inline editing, slide-over panels, or expandable sections instead of popups for simple actions. +- **Avatar circles exclusively.** Try squircles or rounded squares for a less generic look. +- **Light/dark toggle always a sun/moon switch.** Use a dropdown, system preference detection, or integrate it into settings. +- **Footer link farm with 4 columns.** Simplify. Focus on main navigational paths and legally required links. + +### Iconography + +- **Lucide or Feather icons exclusively.** These are the "default" AI icon choice. Use Phosphor, Heroicons, or a custom set for differentiation. +- **Rocketship for "Launch", shield for "Security".** Replace cliche metaphors with less obvious icons (bolt, fingerprint, spark, vault). +- **Inconsistent stroke widths across icons.** Audit all icons and standardize to one stroke weight. +- **Missing favicon.** Always include a branded favicon. +- **Stock "diverse team" photos.** Use real team photos, candid shots, or a consistent illustration style instead of uncanny stock imagery. + +### Code Quality + +- **Div soup.** Use semantic HTML: `
`, `
`, `
`, `
`, `