mirror of
https://gitee.com/mateos/mateclaw.git
synced 2026-09-13 03:13:41 +08:00
fix(webchat): align demo and widget theme tokens
This commit is contained in:
parent
1b198e3d08
commit
924d056b79
119
mateclaw-webchat/index.html
Normal file
119
mateclaw-webchat/index.html
Normal file
@ -0,0 +1,119 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<title>MateClaw WebChat Demo</title>
|
||||||
|
<style>
|
||||||
|
:root {
|
||||||
|
--mc-font-body: 'Inter', 'Avenir Next', 'SF Pro Display', 'Segoe UI', 'PingFang SC', 'Microsoft YaHei', sans-serif;
|
||||||
|
--mc-text-sm: 13px;
|
||||||
|
--mc-text-base: 15px;
|
||||||
|
--mc-radius-md: 12px;
|
||||||
|
--mc-radius-full: 9999px;
|
||||||
|
--mc-primary: #d96d46;
|
||||||
|
--mc-primary-hover: #bb4f27;
|
||||||
|
--mc-bg: #f6f1ea;
|
||||||
|
--mc-bg-elevated: #ffffff;
|
||||||
|
--mc-bg-muted: #f1e8df;
|
||||||
|
--mc-border-light: #ebe3db;
|
||||||
|
--mc-text-primary: #1d1612;
|
||||||
|
--mc-text-secondary: #665245;
|
||||||
|
--mc-text-inverse: #ffffff;
|
||||||
|
--mc-shadow-medium: 0 18px 48px rgba(58, 32, 19, 0.12);
|
||||||
|
--mc-shadow-strong: 0 24px 70px rgba(58, 32, 19, 0.16);
|
||||||
|
--mc-chat-bg: #fafaf8;
|
||||||
|
--mc-chat-header-bg: #ffffff;
|
||||||
|
--mc-assistant-bubble-bg: #ffffff;
|
||||||
|
--mc-assistant-bubble-border: #ddd5cc;
|
||||||
|
--mc-assistant-bubble-color: #1c1410;
|
||||||
|
--mc-user-bubble-bg: #d97757;
|
||||||
|
--mc-user-bubble-color: #ffffff;
|
||||||
|
--mc-input-bg: #fafaf8;
|
||||||
|
--mc-input-border: #ddd5cc;
|
||||||
|
--mc-input-text: #1c1410;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
min-height: 100vh;
|
||||||
|
background: var(--mc-bg);
|
||||||
|
color: var(--mc-text-primary);
|
||||||
|
font-family: var(--mc-font-body);
|
||||||
|
}
|
||||||
|
|
||||||
|
main {
|
||||||
|
max-width: 760px;
|
||||||
|
padding: 48px 32px;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
margin: 0 0 12px;
|
||||||
|
font-size: 28px;
|
||||||
|
line-height: 36px;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
margin: 0;
|
||||||
|
color: var(--mc-text-secondary);
|
||||||
|
font-size: 15px;
|
||||||
|
line-height: 24px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<main>
|
||||||
|
<h1>MateClaw WebChat Demo</h1>
|
||||||
|
<p>点击右下角按钮打开 WebChat。本页面会模拟流式接口,方便本地预览组件交互。</p>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<script type="module">
|
||||||
|
import { init } from './src/index.ts'
|
||||||
|
|
||||||
|
const originalFetch = window.fetch.bind(window)
|
||||||
|
|
||||||
|
window.fetch = async (input, initOptions) => {
|
||||||
|
const url = typeof input === 'string' ? input : input.url
|
||||||
|
if (url.includes('/api/v1/channels/webchat/stream')) {
|
||||||
|
const body = JSON.parse(String(initOptions?.body || '{}'))
|
||||||
|
const encoder = new TextEncoder()
|
||||||
|
|
||||||
|
return new Response(
|
||||||
|
new ReadableStream({
|
||||||
|
start(controller) {
|
||||||
|
const chunks = [
|
||||||
|
`data: ${JSON.stringify({ text: `收到:${body.message || ''}` })}\n\n`,
|
||||||
|
`data: ${JSON.stringify({ text: '\\n这是本地 demo 的模拟流式回复。' })}\n\n`,
|
||||||
|
'event: done\n\n',
|
||||||
|
]
|
||||||
|
|
||||||
|
chunks.forEach((chunk, index) => {
|
||||||
|
setTimeout(() => {
|
||||||
|
controller.enqueue(encoder.encode(chunk))
|
||||||
|
if (index === chunks.length - 1) controller.close()
|
||||||
|
}, index * 220)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
{
|
||||||
|
status: 200,
|
||||||
|
headers: { 'Content-Type': 'text/event-stream' },
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return originalFetch(input, initOptions)
|
||||||
|
}
|
||||||
|
|
||||||
|
init({
|
||||||
|
apiKey: 'dev-key',
|
||||||
|
server: location.origin,
|
||||||
|
title: 'MateClaw WebChat',
|
||||||
|
primaryColor: 'var(--mc-primary, #D97757)',
|
||||||
|
subtitle: '本地预览',
|
||||||
|
welcomeMessage: '我是 MateClaw WebChat,本页面用于本地开发预览。',
|
||||||
|
quickPrompts: ['分析这个问题', '给我执行建议', '你能做哪些事情?'],
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@ -15,7 +15,7 @@ export interface WebChatConfig {
|
|||||||
server: string
|
server: string
|
||||||
/** Widget position */
|
/** Widget position */
|
||||||
position?: 'bottom-right' | 'bottom-left'
|
position?: 'bottom-right' | 'bottom-left'
|
||||||
/** Primary color (hex) */
|
/** Primary color (CSS color). Defaults to MateClaw UI token. */
|
||||||
primaryColor?: string
|
primaryColor?: string
|
||||||
/** Widget title */
|
/** Widget title */
|
||||||
title?: string
|
title?: string
|
||||||
@ -30,7 +30,7 @@ interface Message {
|
|||||||
|
|
||||||
const DEFAULT_CONFIG: Partial<WebChatConfig> = {
|
const DEFAULT_CONFIG: Partial<WebChatConfig> = {
|
||||||
position: 'bottom-right',
|
position: 'bottom-right',
|
||||||
primaryColor: '#409eff',
|
primaryColor: 'var(--mc-primary, #D97757)',
|
||||||
title: 'MateClaw',
|
title: 'MateClaw',
|
||||||
placeholder: 'Type a message...',
|
placeholder: 'Type a message...',
|
||||||
}
|
}
|
||||||
@ -58,6 +58,13 @@ function generateId(): string {
|
|||||||
function injectStyles() {
|
function injectStyles() {
|
||||||
const style = document.createElement('style')
|
const style = document.createElement('style')
|
||||||
style.textContent = `
|
style.textContent = `
|
||||||
|
.mc-webchat-bubble,
|
||||||
|
.mc-webchat-panel,
|
||||||
|
.mc-webchat-panel * {
|
||||||
|
box-sizing: border-box;
|
||||||
|
font-family: var(--mc-font-body, 'Inter', 'Avenir Next', 'SF Pro Display', 'Segoe UI', 'PingFang SC', 'Microsoft YaHei', sans-serif);
|
||||||
|
letter-spacing: 0;
|
||||||
|
}
|
||||||
.mc-webchat-bubble {
|
.mc-webchat-bubble {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
${config.position === 'bottom-left' ? 'left: 20px' : 'right: 20px'};
|
${config.position === 'bottom-left' ? 'left: 20px' : 'right: 20px'};
|
||||||
@ -66,10 +73,10 @@ function injectStyles() {
|
|||||||
height: 56px;
|
height: 56px;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
background: ${config.primaryColor};
|
background: ${config.primaryColor};
|
||||||
color: white;
|
color: var(--mc-text-inverse, #ffffff);
|
||||||
border: none;
|
border: none;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
box-shadow: 0 4px 12px rgba(0,0,0,0.15);
|
box-shadow: var(--mc-shadow-medium, 0 18px 48px rgba(58, 32, 19, 0.12));
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
@ -83,29 +90,31 @@ function injectStyles() {
|
|||||||
bottom: 88px;
|
bottom: 88px;
|
||||||
width: 380px;
|
width: 380px;
|
||||||
height: 520px;
|
height: 520px;
|
||||||
background: white;
|
background: var(--mc-bg-elevated, #ffffff);
|
||||||
border-radius: 12px;
|
color: var(--mc-text-primary, #1d1612);
|
||||||
box-shadow: 0 8px 32px rgba(0,0,0,0.12);
|
border: 1px solid var(--mc-border-light, #ebe3db);
|
||||||
|
border-radius: var(--mc-radius-md, 12px);
|
||||||
|
box-shadow: var(--mc-shadow-strong, 0 24px 70px rgba(58, 32, 19, 0.16));
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
z-index: 99999;
|
z-index: 99999;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
||||||
}
|
}
|
||||||
.mc-webchat-header {
|
.mc-webchat-header {
|
||||||
padding: 14px 16px;
|
padding: 14px 16px;
|
||||||
background: ${config.primaryColor};
|
background: var(--mc-chat-header-bg, #ffffff);
|
||||||
color: white;
|
color: var(--mc-text-primary, #1d1612);
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
font-size: 15px;
|
font-size: 15px;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
|
border-bottom: 1px solid var(--mc-border-light, #ebe3db);
|
||||||
}
|
}
|
||||||
.mc-webchat-close {
|
.mc-webchat-close {
|
||||||
background: none;
|
background: none;
|
||||||
border: none;
|
border: none;
|
||||||
color: white;
|
color: var(--mc-text-secondary, #665245);
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
font-size: 18px;
|
font-size: 18px;
|
||||||
padding: 0 4px;
|
padding: 0 4px;
|
||||||
@ -119,40 +128,45 @@ function injectStyles() {
|
|||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
|
background: var(--mc-chat-bg, #FAFAF8);
|
||||||
}
|
}
|
||||||
.mc-webchat-msg {
|
.mc-webchat-msg {
|
||||||
max-width: 85%;
|
max-width: 85%;
|
||||||
padding: 8px 12px;
|
padding: 8px 12px;
|
||||||
border-radius: 12px;
|
border-radius: var(--mc-radius-md, 12px);
|
||||||
font-size: 14px;
|
font-size: var(--mc-text-sm, 13px);
|
||||||
line-height: 1.5;
|
line-height: 1.5;
|
||||||
word-break: break-word;
|
word-break: break-word;
|
||||||
white-space: pre-wrap;
|
white-space: pre-wrap;
|
||||||
}
|
}
|
||||||
.mc-webchat-msg--user {
|
.mc-webchat-msg--user {
|
||||||
align-self: flex-end;
|
align-self: flex-end;
|
||||||
background: ${config.primaryColor};
|
background: var(--mc-user-bubble-bg, ${config.primaryColor});
|
||||||
color: white;
|
color: var(--mc-user-bubble-color, #ffffff);
|
||||||
border-bottom-right-radius: 4px;
|
border-bottom-right-radius: 4px;
|
||||||
}
|
}
|
||||||
.mc-webchat-msg--assistant {
|
.mc-webchat-msg--assistant {
|
||||||
align-self: flex-start;
|
align-self: flex-start;
|
||||||
background: #f0f2f5;
|
background: var(--mc-assistant-bubble-bg, #ffffff);
|
||||||
color: #333;
|
color: var(--mc-assistant-bubble-color, #1C1410);
|
||||||
|
border: 1px solid var(--mc-assistant-bubble-border, #DDD5CC);
|
||||||
border-bottom-left-radius: 4px;
|
border-bottom-left-radius: 4px;
|
||||||
}
|
}
|
||||||
.mc-webchat-input-area {
|
.mc-webchat-input-area {
|
||||||
padding: 10px 12px;
|
padding: 10px 12px;
|
||||||
border-top: 1px solid #eee;
|
border-top: 1px solid var(--mc-border-light, #ebe3db);
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
|
background: var(--mc-bg-elevated, #ffffff);
|
||||||
}
|
}
|
||||||
.mc-webchat-input {
|
.mc-webchat-input {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
padding: 8px 12px;
|
padding: 8px 12px;
|
||||||
border: 1px solid #ddd;
|
border: 1px solid var(--mc-input-border, #DDD5CC);
|
||||||
border-radius: 20px;
|
border-radius: var(--mc-radius-full, 9999px);
|
||||||
font-size: 14px;
|
background: var(--mc-input-bg, #FAFAF8);
|
||||||
|
color: var(--mc-input-text, #1C1410);
|
||||||
|
font-size: var(--mc-text-sm, 13px);
|
||||||
outline: none;
|
outline: none;
|
||||||
}
|
}
|
||||||
.mc-webchat-input:focus { border-color: ${config.primaryColor}; }
|
.mc-webchat-input:focus { border-color: ${config.primaryColor}; }
|
||||||
@ -161,7 +175,7 @@ function injectStyles() {
|
|||||||
height: 36px;
|
height: 36px;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
background: ${config.primaryColor};
|
background: ${config.primaryColor};
|
||||||
color: white;
|
color: var(--mc-text-inverse, #ffffff);
|
||||||
border: none;
|
border: none;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user