Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/fix-addons-build-env.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'cherry-markdown': patch
---

- fix: 修复 addons 构建缺少环境变量替换导致运行时报错的问题
251 changes: 202 additions & 49 deletions examples/ai_chat_stream.html
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<!DOCTYPE html>
<html lang="en">
<html lang="zh-CN">

<head>
<meta charset="UTF-8">
Expand Down Expand Up @@ -137,58 +137,147 @@
cursor: pointer;
}

/* 插件选项 - 胶囊样式 */
.plugin-options {
width: 100%;
max-width: var(--ai-max-width);
margin: 0 auto 16px;
padding: 16px;
background: var(--ai-surface);
border-radius: 8px;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08);
margin: 0 auto 12px;
padding: 0;
background: transparent;
box-shadow: none;
box-sizing: border-box;
}

.plugin-options h3 {
margin: 0 0 12px;
font-size: 14px;
color: #666;
.plugin-title {
font-size: 13px;
font-weight: 600;
color: #333;
margin: 0 0 8px 0;
display: flex;
align-items: center;
gap: 6px;
}

.plugin-title-hint {
font-size: 11px;
font-weight: 400;
color: #999;
}

.plugin-list {
display: flex;
gap: 20px;
gap: 8px;
flex-wrap: wrap;
align-items: center;
}

.plugin-sep {
width: 1px;
height: 20px;
background: var(--ai-muted);
margin: 0 4px;
}

.plugin-group-label {
font-size: 12px;
color: #999;
margin-right: 2px;
}

.plugin-or {
font-size: 11px;
color: #bbb;
font-style: italic;
}

.plugin-item {
display: flex;
align-items: center;
gap: 8px;
position: relative;
cursor: pointer;
user-select: none;
}

.plugin-item input {
width: 18px;
height: 18px;
cursor: pointer;
position: absolute;
opacity: 0;
width: 0;
height: 0;
}

.plugin-item label {
cursor: pointer;
font-size: 14px;
display: inline-flex;
align-items: center;
gap: 6px;
padding: 6px 14px;
border-radius: 20px;
font-size: 13px;
font-weight: 500;
line-height: 1.4;
border: 1px solid var(--ai-muted);
background: var(--ai-surface);
color: #666;
transition: all 0.2s ease;
white-space: nowrap;
}

.plugin-item .plugin-status {
font-size: 12px;
color: #999;
margin-left: 4px;
.plugin-item input:checked+label {
background: #e6f0ff;
border-color: var(--ai-accent);
color: var(--ai-accent);
}

.plugin-item .plugin-status.loaded {
color: #52c41a;
.plugin-item input:disabled+label,
.plugin-item input[disabled]+label {
opacity: 0.5;
pointer-events: none;
}

.plugin-item .plugin-status.loading {
color: #faad14;
.plugin-item .status-dot {
width: 7px;
height: 7px;
border-radius: 50%;
background: transparent;
transition: background 0.3s ease;
flex-shrink: 0;
}

.plugin-item .status-dot.loading {
background: #faad14;
animation: pulse-dot 1s infinite;
}

.plugin-item .status-dot.loaded {
background: #52c41a;
}

@keyframes pulse-dot {
0%, 100% { opacity: 1; }
50% { opacity: 0.3; }
}

/* 消息选择器 */
.msg-picker {
width: 100%;
max-width: var(--ai-max-width);
margin: 0 auto 12px;
box-sizing: border-box;
}

.msg-picker-label {
font-size: 13px;
color: #666;
margin-bottom: 8px;
}

.msg-picker-list {
display: flex;
flex-wrap: wrap;
gap: 8px;
}

.j-msg-pick-btn:disabled,
.j-msg-pick-btn[disabled] {
opacity: 0.5;
cursor: not-allowed;
}

.custom-input {
Expand All @@ -215,6 +304,51 @@
min-height: 0;
}

/* Toast 提示 */
.toast-container {
position: fixed;
top: 16px;
right: 16px;
z-index: 9999;
display: flex;
flex-direction: column;
gap: 8px;
pointer-events: none;
}

.toast {
padding: 10px 16px;
border-radius: 8px;
font-size: 13px;
line-height: 1.5;
color: #fff;
background: #333;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
opacity: 0;
transform: translateX(20px);
transition: opacity 0.3s ease, transform 0.3s ease;
pointer-events: auto;
max-width: 360px;
word-break: break-word;
}

.toast-visible {
opacity: 1;
transform: translateX(0);
}

.toast-error {
background: #ff4d4f;
}

.toast-success {
background: #52c41a;
}

.toast-info {
background: #1890ff;
}

@media (max-width: 720px) {
.ai-chat-wrapper {
padding: 12px;
Expand All @@ -230,8 +364,12 @@
}

.plugin-list {
flex-direction: column;
gap: 12px;
gap: 6px;
}

.plugin-item label {
font-size: 12px;
padding: 5px 10px;
}
}
</style>
Expand All @@ -240,53 +378,68 @@
</head>

<body>
<!-- Toast 提示容器 -->
<div class="toast-container j-toast-container"></div>

<div class="ai-chat-wrapper">
<!-- 插件选项区 -->
<div class="plugin-options">
<h3>🔌 插件懒加载选项(勾选后懒加载对应插件)</h3>
<div class="plugin-title">
扩展插件 <span class="plugin-title-hint">勾选后点击下方消息按钮即可加载</span>
</div>
<div class="plugin-list">
<div class="plugin-item">
<input type="checkbox" id="plugin-mermaid" class="j-plugin-checkbox" data-plugin="mermaid">
<label for="plugin-mermaid">Mermaid(流程图)</label>
<span class="plugin-status j-plugin-status" data-plugin="mermaid"></span>
<label for="plugin-mermaid">Mermaid<span class="status-dot j-plugin-status j-status-dot-mermaid"></span></label>
</div>
<span class="plugin-sep"></span>
<div class="plugin-group-label">数学公式(二选一)</div>
<div class="plugin-item">
<input type="checkbox" id="plugin-katex" class="j-plugin-checkbox" data-plugin="katex" checked>
<label for="plugin-katex">KaTeX(数学公式-轻量)</label>
<span class="plugin-status j-plugin-status" data-plugin="katex"></span>
<input type="checkbox" id="plugin-katex" class="j-plugin-checkbox" data-plugin="katex">
<label for="plugin-katex">KaTeX<span class="status-dot j-plugin-status j-status-dot-katex"></span></label>
</div>
<div class="plugin-or">or</div>
<div class="plugin-item">
<input type="checkbox" id="plugin-mathjax" class="j-plugin-checkbox" data-plugin="mathjax">
<label for="plugin-mathjax">MathJax(数学公式-完整)</label>
<span class="plugin-status j-plugin-status" data-plugin="mathjax"></span>
<label for="plugin-mathjax">MathJax<span class="status-dot j-plugin-status j-status-dot-mathjax"></span></label>
</div>
<span class="plugin-sep"></span>
<div class="plugin-item">
<input type="checkbox" id="plugin-echarts" class="j-plugin-checkbox" data-plugin="echarts">
<label for="plugin-echarts">ECharts<span class="status-dot j-plugin-status j-status-dot-echarts"></span></label>
</div>
</div>
</div>

<div class="dialog j-dialog" role="log" aria-live="polite"></div>

<!-- 消息模板(隐藏) -->
<div class="one-msg j-one-msg" aria-hidden="true">
<div class="avatar">AI</div>
<div class="chat-one-msg"></div>
<!-- 消息选择区 -->
<div class="msg-picker">
<div class="msg-picker-label">选择示例消息(点击后流式打印)</div>
<div class="msg-picker-list j-msg-picker-list"></div>
</div>

<!-- 控件区 -->
<div class="controls">
<button type="button" class="button j-button">
获取消息(剩余<span class="j-button-tips"></span>条消息)
</button>
<button type="button" class="button secondary j-pause-button">
<button type="button" class="button secondary j-pause-button" disabled>
暂停流式
</button>
<label class="status">
<input class="j-status-input status-input" type="checkbox" checked> 开启流式适配
</label>
</div>

<!-- 消息模板(隐藏) -->
<div class="one-msg j-one-msg" aria-hidden="true">
<div class="avatar">AI</div>
<div class="chat-one-msg"></div>
</div>

<!-- 渲染区 -->
<div class="dialog j-dialog" role="log" aria-live="polite"></div>

<!-- 自定义输入区 -->
<div class="custom-input">
<textarea class="custom-textarea j-custom-textarea" placeholder="请输入您想要流式打印的Markdown内容..."></textarea>
<div class="button custom-button j-custom-button">流式打印自定义内容</div>
<button type="button" class="button custom-button j-custom-button">流式打印自定义内容</button>
</div>
</div>

Expand All @@ -297,4 +450,4 @@ <h3>🔌 插件懒加载选项(勾选后懒加载对应插件)</h3>
</script>
</body>

</html>
</html>
Loading
Loading