Files
abot/plugins/message_summary/templates/gemini_summary_card.html
liuwei a55121aa05 切换群总结模板为线上字体优先策略
- gemini_summary_card 模板新增 Google Fonts 引入(Inter / JetBrains Mono)\n- main.py 调整本地字体注入逻辑,停止注入 Inter/JetBrains 本地 @font-face\n- 保留 simhei/simsun 中文兜底字体,避免外网不可达时中文显示异常\n- 统一字体变量栈,优先线上字体,回退本地中文与系统字体
2026-04-23 11:06:42 +08:00

544 lines
16 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{ title }}</title>
<style>
/* 说明:线上字体优先,用于还原 gemini-code 的字形与排版气质。 */
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700;800;900&family=JetBrains+Mono:wght@400;500;700&display=swap');
{{ local_font_css }}
:root {
--bg: #F8FAFC;
--surface: #FFFFFF;
--text: #334155;
--heading: #0F172A;
--line: #F1F5F9;
--blue: #2563EB;
--green: #22C55E;
--rose: #F43F5E;
--shadow-sm: 0 1px 3px rgba(15, 23, 42, 0.05);
}
* { box-sizing: border-box; }
body {
margin: 0;
padding: 10px 0;
background: var(--bg);
color: var(--text);
font-family: var(--abot-font-sans, 'Inter', 'PingFang SC', system-ui, sans-serif);
-webkit-font-smoothing: antialiased;
}
.report-container {
width: 420px;
margin: 0 auto;
background: var(--surface);
border: 1px solid var(--line);
box-shadow: var(--shadow-sm);
}
.label-tiny {
display: block;
font-size: 9px;
line-height: 1.2;
font-weight: 800;
text-transform: uppercase;
letter-spacing: 0.08em;
color: #94a3b8;
margin-bottom: 3px;
}
.mono { font-family: var(--abot-font-code, 'JetBrains Mono', 'SF Mono', monospace); }
.header {
padding: 12px;
border-bottom: 1px solid var(--line);
}
.header-top {
display: flex;
justify-content: space-between;
align-items: flex-start;
gap: 8px;
margin-bottom: 8px;
}
.header-title {
margin: 0;
font-size: 13px;
line-height: 1.25;
font-weight: 900;
color: var(--heading);
letter-spacing: -0.02em;
}
.header-title .accent { color: var(--blue); font-weight: 600; }
.header-id {
margin: 3px 0 0;
font-size: 9px;
color: #94a3b8;
letter-spacing: 0.03em;
}
.header-tag {
padding: 2px 6px;
border-radius: 4px;
background: #f1f5f9;
border: 1px solid #e2e8f0;
font-size: 9px;
color: #64748b;
font-weight: 700;
white-space: nowrap;
text-transform: uppercase;
}
.kpi-grid {
display: grid;
grid-template-columns: repeat(4, minmax(0, 1fr));
gap: 6px;
}
.kpi {
background: #f8fafc;
border: 1px solid var(--line);
border-radius: 4px;
padding: 5px 4px;
text-align: center;
}
.kpi .value {
font-size: 11px;
font-weight: 800;
color: #475569;
}
.kpi .value.is-blue { color: var(--blue); }
.kpi .value.is-indigo { color: #4f46e5; }
.kpi .value.is-emerald { color: #059669; }
.radar {
padding: 10px 12px;
border-bottom: 1px solid var(--line);
}
.radar-tags {
display: flex;
flex-wrap: wrap;
gap: 6px;
margin-top: 2px;
}
.radar-tag {
font-size: 9px;
line-height: 1.2;
padding: 2px 7px;
border-radius: 999px;
border: 1px solid #e2e8f0;
background: #f1f5f9;
color: #64748b;
font-weight: 700;
}
.radar-tag.hit-blue { background: #eff6ff; border-color: #dbeafe; color: #2563eb; }
.radar-tag.hit-indigo { background: #eef2ff; border-color: #e0e7ff; color: #4f46e5; }
.radar-tag.hit-emerald { background: #ecfdf5; border-color: #d1fae5; color: #059669; }
.content {
padding: 12px;
}
.lead {
margin: 0 0 10px;
background: #f0fdf4;
border-left: 2px solid var(--green);
border-radius: 0 4px 4px 0;
padding: 7px 8px;
font-size: 11px;
line-height: 1.55;
color: #166534;
font-weight: 700;
}
.topic-list {
display: flex;
flex-direction: column;
gap: 8px;
}
.topic-card {
border: 1px solid #e2e8f0;
border-radius: 6px;
padding: 8px;
background: #fff;
}
.topic-title-row {
display: flex;
align-items: center;
gap: 7px;
margin-bottom: 6px;
}
.topic-title {
margin: 0;
font-size: 13px;
font-weight: 800;
color: var(--heading);
line-height: 1.3;
}
.topic-divider {
flex: 1;
height: 1px;
background: var(--line);
}
.topic-meta {
margin: 0 0 6px;
font-size: 10px;
color: #64748b;
line-height: 1.45;
padding: 5px 6px;
border: 1px dashed #e2e8f0;
border-radius: 4px;
background: #f8fafc;
}
.topic-block { margin-bottom: 6px; }
.topic-block:last-child { margin-bottom: 0; }
.topic-text {
margin: 0;
font-size: 11px;
color: #475569;
line-height: 1.55;
}
.topic-bullets {
margin: 0;
padding-left: 10px;
font-size: 11px;
color: #475569;
line-height: 1.5;
}
.topic-bullets li { margin: 1px 0; }
.conclusion-area {
background: #f0fdf4;
border-left: 2px solid var(--green);
border-radius: 0 4px 4px 0;
padding: 6px 7px;
}
.conclusion-text {
margin: 0;
font-size: 11px;
line-height: 1.5;
font-weight: 700;
color: #166534;
font-style: italic;
}
.resource-wrap {
margin-top: 10px;
padding: 10px 0;
border-top: 1px solid var(--line);
border-bottom: 1px solid var(--line);
background: rgba(248, 250, 252, 0.5);
}
.resource-list {
display: flex;
flex-direction: column;
gap: 4px;
padding: 0 8px;
}
.resource-item {
border: 1px solid var(--line);
border-radius: 4px;
padding: 5px 6px;
background: #fff;
display: flex;
align-items: center;
justify-content: space-between;
gap: 6px;
min-height: 24px;
}
.resource-left {
display: flex;
align-items: center;
gap: 5px;
min-width: 0;
}
.resource-icon {
width: 14px;
text-align: center;
font-size: 10px;
color: #94a3b8;
flex-shrink: 0;
}
.resource-title {
font-size: 10px;
color: #475569;
line-height: 1.2;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.resource-arrow {
font-size: 9px;
color: #cbd5e1;
flex-shrink: 0;
}
.widget-grid {
margin-top: 10px;
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 8px;
}
.widget {
border: 1px solid var(--line);
border-radius: 4px;
padding: 6px;
background: #fff;
min-height: 62px;
}
.widget-item {
margin: 0 0 4px;
font-size: 10px;
line-height: 1.45;
color: #475569;
}
.widget-item:last-child { margin-bottom: 0; }
.widget-item.trade { color: var(--rose); font-weight: 700; }
.core-wrap { margin-top: 10px; }
.core-card {
border-radius: 4px;
background: #0F172A;
border: 1px solid #1e293b;
padding: 8px;
}
.core-item {
margin: 0 0 5px;
font-size: 10px;
line-height: 1.5;
color: #cbd5e1;
}
.core-item:last-child { margin-bottom: 0; }
.contributors {
margin-top: 10px;
padding: 8px;
background: #f8fafc;
border-top: 1px solid var(--line);
border-bottom: 1px solid var(--line);
display: flex;
justify-content: space-between;
align-items: center;
gap: 8px;
}
.avatar-list {
display: flex;
margin-left: auto;
}
.avatar {
width: 22px;
height: 22px;
border-radius: 50%;
border: 2px solid #fff;
display: inline-flex;
align-items: center;
justify-content: center;
margin-left: -5px;
font-size: 9px;
font-weight: 800;
}
.avatar:nth-child(1) { background: #dbeafe; color: #2563eb; }
.avatar:nth-child(2) { background: #e0e7ff; color: #4f46e5; }
.avatar:nth-child(3) { background: #e2e8f0; color: #64748b; }
.footer-note {
padding: 8px 0 10px;
text-align: center;
font-size: 9px;
color: #94a3b8;
letter-spacing: 0.03em;
text-transform: uppercase;
}
</style>
</head>
<body>
<div class="report-container">
<header class="header">
<div class="header-top">
<div>
<h1 class="header-title">CHAT INSIGHTS <span class="accent">REPORT</span></h1>
<p class="header-id mono">ID: {{ generated_at }}</p>
</div>
<div class="header-tag">{{ summary_metrics.activity_badge or "Daily Archive" }}</div>
</div>
<div class="kpi-grid">
{% for card in summary_metrics.kpi_cards|default([]) %}
<div class="kpi">
<span class="label-tiny">{{ card.label }}</span>
<span class="value {% if card.tone == 'blue' %}is-blue{% elif card.tone == 'violet' %}is-indigo{% elif card.tone == 'emerald' %}is-emerald{% endif %}">{{ card.value }}</span>
</div>
{% endfor %}
</div>
</header>
<section class="radar">
<span class="label-tiny"># Personal Interest Radar</span>
<div class="radar-tags">
{% for tag in summary_metrics.topic_tags|default([]) %}
<span class="radar-tag {% if loop.index0 % 4 == 0 %}hit-blue{% elif loop.index0 % 4 == 1 %}hit-indigo{% elif loop.index0 % 4 == 2 %}hit-emerald{% else %}{% endif %}">{{ tag }}</span>
{% endfor %}
{% if not (summary_metrics.topic_tags|default([])) %}
<span class="radar-tag">暂无热点标签</span>
{% endif %}
</div>
</section>
<section class="content">
<span class="label-tiny"># {{ summary_doc_title or title }}</span>
<p class="lead">{{ summary_lead or "暂无总结内容。" }}</p>
<span class="label-tiny"># Key Discussions</span>
<div class="topic-list">
{% for topic in summary_topics|default([]) %}
<article class="topic-card">
<div class="topic-title-row">
<h3 class="topic-title">{{ "%02d"|format(loop.index) }}. {{ topic["title"] }}</h3>
<div class="topic-divider"></div>
</div>
{% if topic["time_range"] or topic["participants"] %}
<div class="topic-meta">
{% if topic["time_range"] %}<div>时段:{{ topic["time_range"] }}</div>{% endif %}
{% if topic["participants"] %}<div>参与人数:{{ topic["participants"] }}</div>{% endif %}
</div>
{% endif %}
{% if topic["analysis_points"]|default([]) %}
<div class="topic-block">
<span class="label-tiny">Background</span>
<p class="topic-text">{{ topic["analysis_points"][0] }}</p>
</div>
{% endif %}
{% if topic["overview_points"]|default([]) %}
<div class="topic-block">
<span class="label-tiny">Key Points</span>
<ul class="topic-bullets">
{% for line in topic["overview_points"] %}
<li>{{ line }}</li>
{% endfor %}
</ul>
</div>
{% endif %}
{% if topic["quote_text"] %}
<div class="conclusion-area">
<span class="label-tiny" style="color:#16a34a;">Conclusion</span>
<p class="conclusion-text">{{ topic["quote_text"] }}</p>
</div>
{% endif %}
</article>
{% endfor %}
</div>
{% if not (summary_topics|default([])) %}
<p class="widget-item">{{ summary_fallback_text }}</p>
{% endif %}
{% if summary_resource_hub|default([]) %}
<section class="resource-wrap">
<span class="label-tiny" style="padding: 0 8px 4px;"># Shared Resources</span>
<div class="resource-list">
{% for item in summary_resource_hub %}
<div class="resource-item">
<div class="resource-left">
<span class="resource-icon">{{ item.icon }}</span>
<span class="resource-title">{{ item.title }}</span>
</div>
<span class="resource-arrow"></span>
</div>
{% endfor %}
</div>
</section>
{% endif %}
<section class="widget-grid">
<article class="widget">
<span class="label-tiny"># Marketplace</span>
{% for line in summary_marketplace|default([]) %}
<p class="widget-item trade">{{ line }}</p>
{% endfor %}
{% if not (summary_marketplace|default([])) %}
<p class="widget-item">暂无交易信息</p>
{% endif %}
</article>
<article class="widget">
<span class="label-tiny"># Unresolved Pool</span>
{% for line in summary_unresolved_pool|default([]) %}
<p class="widget-item">{{ line }}</p>
{% endfor %}
{% if not (summary_unresolved_pool|default([])) %}
<p class="widget-item">暂无待解问题</p>
{% endif %}
</article>
</section>
<section class="core-wrap">
<div class="core-card">
<span class="label-tiny" style="color:#64748b;"># Core Knowledge Points</span>
{% for line in summary_core_points|default([]) %}
<p class="core-item">{{ line }}</p>
{% endfor %}
{% if not (summary_core_points|default([])) %}
<p class="core-item">暂无核心知识点</p>
{% endif %}
</div>
</section>
<div class="contributors">
<span class="label-tiny" style="margin:0;">Top Contributors</span>
<div class="avatar-list">
{% for name in summary_top_contributors|default([]) %}
<span class="avatar">{{ name[:1] }}</span>
{% endfor %}
{% if not (summary_top_contributors|default([])) %}
<span class="avatar">A</span><span class="avatar">B</span><span class="avatar">C</span>
{% endif %}
</div>
</div>
<div class="footer-note">Engine: Playwright · Tokens: {{ summary_metrics.token_total }} · Latency: {{ summary_metrics.latency_text }}</div>
</section>
</div>
</body>
</html>