quick-view
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseQuick View
快速查看
Generate minimal HTML to review structured data in a browser. Minimal styling, maximum readability.
生成极简HTML,以便在浏览器中查看结构化数据。极简样式,极致可读性。
When to Use
适用场景
- User wants to review output that's hard to read in terminal
- Lists, tables, drafts, summaries that benefit from visual layout
- User says: "show me", "view this", "make reviewable", "open as webpage"
- 用户希望查看在终端中难以阅读的输出内容
- 列表、表格、草稿、摘要等受益于可视化布局的内容
- 用户说出:“show me”“view this”“make reviewable”“open as webpage”
Output Rules
输出规则
DO:
- Semantic HTML: ,
<table>,<ul>,<details>,<pre><h1-3> - Use the base template with CSS variables
- Write to
_private/views/ - Open with
open _private/views/{filename}
DO NOT:
- Add decorative styling beyond the base template
- Use CSS frameworks
- Over-engineer or "make it nice"
执行要求:
- 使用语义化HTML:、
<table>、<ul>、<details>、<pre><h1-3> - 使用带有CSS变量的基础模板
- 写入至目录
_private/views/ - 使用命令打开
open _private/views/{filename}
禁止操作:
- 在基础模板之外添加装饰性样式
- 使用CSS框架
- 过度设计或刻意“美化”页面
File Naming
文件命名规则
Views have a lifecycle: temporary → keeper → archived.
| Stage | Filename | When |
|---|---|---|
| Temporary | | Default for new views |
| Keeper | | User says "keep this", "this is good" |
| Archived | | Previous keeper when promoting new one |
Rules:
- Always create with suffix — Every new view starts as
-tempname-temp.html - Promote on approval — When user approves, rename to
name.html - Archive before replacing — If exists, rename to
name.htmlbefore promotingname.DATE.html - Never regenerate keepers — Only regenerate files
-temp
Workflow:
undefined视图文件有三个生命周期阶段:临时文件 → 保留文件 → 归档文件。
| 阶段 | 文件名格式 | 使用时机 |
|---|---|---|
| 临时 | | 新视图文件的默认命名 |
| 保留 | | 用户说出“keep this”“this is good”时 |
| 归档 | | 升级新的保留文件时,将旧的保留文件重命名归档 |
规则细节:
- 所有新视图初始均为临时文件 — 每个新视图都以的形式创建
name-temp.html - 经批准后升级为保留文件 — 当用户确认后,重命名为
name.html - 替换前先归档旧文件 — 如果已存在,在升级新文件前需将其重命名为
name.html归档name.DATE.html - 永不重新生成保留文件 — 仅重新生成临时文件
工作流示例:
undefinedFirst iteration
第一次迭代
drafts-temp.html ← created
drafts-temp.html ← 创建完成
User: "keep this"
用户:“keep this”
drafts.html ← promoted (temp deleted)
drafts.html ← 升级为保留文件(临时文件删除)
Later iteration
后续迭代
drafts-temp.html ← new temp created
drafts.html ← keeper untouched
drafts-temp.html ← 创建新的临时文件
drafts.html ← 保留文件保持不变
User: "this is better, keep it"
用户:“this is better, keep it”
drafts.2025-01-01.html ← old keeper archived
drafts.html ← new keeper promoted
**Trigger phrases for promotion:**
- "keep this", "this is good", "save this"
- "make this the default", "lock this in"
- "I like this one"drafts.2025-01-01.html ← 旧保留文件归档
drafts.html ← 新临时文件升级为保留文件
**触发文件升级的关键词:**
- "keep this"、"this is good"、"save this"
- "make this the default"、"lock this in"
- "I like this one"Base Template
基础模板
Every quick-view HTML file:
html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>{title}</title>
<style>
:root {
--bg: #fff;
--text: #222;
--muted: #666;
--border: #ddd;
--accent: #1976d2;
}
@media (prefers-color-scheme: dark) {
:root {
--bg: #1a1a1a;
--text: #e0e0e0;
--muted: #999;
--border: #333;
--accent: #64b5f6;
}
}
body {
max-width: 800px;
margin: 40px auto;
padding: 0 20px;
font-family: system-ui;
background: var(--bg);
color: var(--text);
}
table { border-collapse: collapse; width: 100%; }
td, th { border: 1px solid var(--border); padding: 8px; text-align: left; }
.meta { color: var(--muted); font-size: 0.875rem; margin-bottom: 1rem; }
details { margin: 0.5rem 0; }
summary { cursor: pointer; }
pre {
background: var(--border);
padding: 1rem;
overflow-x: auto;
border-radius: 4px;
}
/* Long content truncation */
.truncate {
max-height: 200px;
overflow: hidden;
position: relative;
}
.truncate.expanded { max-height: none; }
.truncate:not(.expanded)::after {
content: '';
position: absolute;
bottom: 0;
left: 0;
right: 0;
height: 60px;
background: linear-gradient(transparent, var(--bg));
}
.expand-btn {
color: var(--accent);
background: none;
border: none;
cursor: pointer;
padding: 0.5rem 0;
font-size: 0.875rem;
}
/* Type borders */
.type-user { border-left: 3px solid var(--accent); padding-left: 1rem; }
.type-draft { border-left: 3px solid #ff9800; padding-left: 1rem; }
.type-done { border-left: 3px solid #4caf50; padding-left: 1rem; }
/* Source attribution */
.source { color: var(--muted); font-size: 0.75rem; }
.source a { color: var(--muted); }
.source a:hover { color: var(--accent); }
</style>
</head>
<body>
<p class="meta">Generated: {timestamp} · {count} items</p>
{content}
<script>
// Truncation toggle
document.querySelectorAll('.truncate').forEach(el => {
if (el.scrollHeight > 220) {
const btn = document.createElement('button');
btn.className = 'expand-btn';
btn.textContent = 'Show more';
btn.onclick = () => {
el.classList.toggle('expanded');
btn.textContent = el.classList.contains('expanded') ? 'Show less' : 'Show more';
};
el.after(btn);
} else {
el.classList.add('expanded'); // No truncation needed
}
});
</script>
</body>
</html>每个快速查看HTML文件均使用以下模板:
html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>{title}</title>
<style>
:root {
--bg: #fff;
--text: #222;
--muted: #666;
--border: #ddd;
--accent: #1976d2;
}
@media (prefers-color-scheme: dark) {
:root {
--bg: #1a1a1a;
--text: #e0e0e0;
--muted: #999;
--border: #333;
--accent: #64b5f6;
}
}
body {
max-width: 800px;
margin: 40px auto;
padding: 0 20px;
font-family: system-ui;
background: var(--bg);
color: var(--text);
}
table { border-collapse: collapse; width: 100%; }
td, th { border: 1px solid var(--border); padding: 8px; text-align: left; }
.meta { color: var(--muted); font-size: 0.875rem; margin-bottom: 1rem; }
details { margin: 0.5rem 0; }
summary { cursor: pointer; }
pre {
background: var(--border);
padding: 1rem;
overflow-x: auto;
border-radius: 4px;
}
/* Long content truncation */
.truncate {
max-height: 200px;
overflow: hidden;
position: relative;
}
.truncate.expanded { max-height: none; }
.truncate:not(.expanded)::after {
content: '';
position: absolute;
bottom: 0;
left: 0;
right: 0;
height: 60px;
background: linear-gradient(transparent, var(--bg));
}
.expand-btn {
color: var(--accent);
background: none;
border: none;
cursor: pointer;
padding: 0.5rem 0;
font-size: 0.875rem;
}
/* Type borders */
.type-user { border-left: 3px solid var(--accent); padding-left: 1rem; }
.type-draft { border-left: 3px solid #ff9800; padding-left: 1rem; }
.type-done { border-left: 3px solid #4caf50; padding-left: 1rem; }
/* Source attribution */
.source { color: var(--muted); font-size: 0.75rem; }
.source a { color: var(--muted); }
.source a:hover { color: var(--accent); }
</style>
</head>
<body>
<p class="meta">Generated: {timestamp} · {count} items</p>
{content}
<script>
// Truncation toggle
document.querySelectorAll('.truncate').forEach(el => {
if (el.scrollHeight > 220) {
const btn = document.createElement('button');
btn.className = 'expand-btn';
btn.textContent = 'Show more';
btn.onclick = () => {
el.classList.toggle('expanded');
btn.textContent = el.classList.contains('expanded') ? 'Show less' : 'Show more';
};
el.after(btn);
} else {
el.classList.add('expanded'); // No truncation needed
}
});
</script>
</body>
</html>Patterns
常用模式
List of items
项目列表
html
<h1>Title</h1>
<ul>
<li><strong>@username</strong> — action item</li>
</ul>html
<h1>Title</h1>
<ul>
<li><strong>@username</strong> — action item</li>
</ul>Table
表格
html
<table>
<tr><th>Contact</th><th>Action</th><th>Draft</th></tr>
<tr><td>@name</td><td>Follow up</td><td>Hey...</td></tr>
</table>html
<table>
<tr><th>Contact</th><th>Action</th><th>Draft</th></tr>
<tr><td>@name</td><td>Follow up</td><td>Hey...</td></tr>
</table>Expandable sections (for long content)
可展开区域(适用于长内容)
html
<details>
<summary><strong>@username</strong> — action</summary>
<div class="truncate">
<pre>Long content here that may need truncation...</pre>
</div>
</details>html
<details>
<summary><strong>@username</strong> — action</summary>
<div class="truncate">
<pre>Long content here that may need truncation...</pre>
</div>
</details>Type-differentiated items
类型区分的项目
html
<div class="type-user">User message or input</div>
<div class="type-draft">Draft content</div>
<div class="type-done">Completed item</div>html
<div class="type-user">User message or input</div>
<div class="type-draft">Draft content</div>
<div class="type-done">Completed item</div>With actions
带操作按钮的内容
html
<p>
<a href="tg://resolve?domain=username">Open Telegram</a> ·
<button onclick="navigator.clipboard.writeText('draft text')">Copy</button>
</p>html
<p>
<a href="tg://resolve?domain=username">Open Telegram</a> ·
<button onclick="navigator.clipboard.writeText('draft text')">Copy</button>
</p>Sourced data (citations & drill-down)
带来源标注的数据(引用与溯源)
When displaying data gathered from external sources, always include attribution links for drill-down.
Add to base template CSS:
css
.source { color: var(--muted); font-size: 0.75rem; }
.source a { color: var(--muted); }
.source a:hover { color: var(--accent); }Inline attribution (preferred for lists):
html
<div class="tip">
<strong>Tip title</strong> — Description of the tip.
<span class="source">— <a href="https://x.com/user/status/123">@username</a></span>
</div>Table with source column:
html
<table>
<tr><th>Tip</th><th>Source</th></tr>
<tr>
<td>Description here</td>
<td class="source"><a href="https://x.com/user/status/123">@user</a></td>
</tr>
</table>Expandable with source in summary:
html
<details>
<summary><strong>Tip title</strong> <span class="source">— <a href="URL">@source</a></span></summary>
<p>Full content...</p>
</details>Meta header with main source:
html
<p class="meta">
Generated: {timestamp} · {count} items ·
Source: <a href="https://x.com/user/status/123">Original thread</a>
</p>Principles:
- Always link to original when data comes from external sources
- Use for social media, domain for articles
@username - Source links should be muted/subtle, not prominent
- Include main source in meta header for collections from single source
当展示来自外部来源的数据时,始终需要添加可跳转至原文的来源链接。
在基础模板CSS中添加以下样式:
css
.source { color: var(--muted); font-size: 0.75rem; }
.source a { color: var(--muted); }
.source a:hover { color: var(--accent); }内联来源标注(列表内容首选):
html
<div class="tip">
<strong>Tip title</strong> — Description of the tip.
<span class="source">— <a href="https://x.com/user/status/123">@username</a></span>
</div>带来源列的表格:
html
<table>
<tr><th>Tip</th><th>Source</th></tr>
<tr>
<td>Description here</td>
<td class="source"><a href="https://x.com/user/status/123">@user</a></td>
</tr>
</table>来源标注在摘要中的可展开区域:
html
<details>
<summary><strong>Tip title</strong> <span class="source">— <a href="URL">@source</a></span></summary>
<p>Full content...</p>
</details>带主来源的元数据头部:
html
<p class="meta">
Generated: {timestamp} · {count} items ·
Source: <a href="https://x.com/user/status/123">Original thread</a>
</p>原则:
- 数据来自外部来源时,始终链接至原文
- 社交媒体使用标注,文章使用域名标注
@username - 来源链接应低调不突出
- 单一来源的合集内容,在元数据头部标注主来源
Editable drafts (with diff tracking)
可编辑草稿(带差异追踪)
For drafts that user may edit before sending. Tracks original vs edited for later analysis.
html
<details>
<summary><strong>@username</strong> — action <span class="status"></span></summary>
<pre contenteditable="true"
data-username="username"
data-original="Original draft text here"
onblur="saveDraft(this)">Original draft text here</pre>
<div class="actions">
<a href="tg://resolve?domain=username">Open Telegram</a>
<button onclick="copyDraft(this)">Copy</button>
</div>
</details>Include this script block at end of (before closing tag):
<body></body>javascript
function saveDraft(el) {
const key = 'draft_' + el.dataset.username;
const edited = el.textContent.trim();
const original = el.dataset.original;
if (edited !== original) {
localStorage.setItem(key, edited);
el.closest('details').querySelector('.status').textContent = '(edited)';
}
}
function copyDraft(btn) {
const pre = btn.closest('details').querySelector('pre');
navigator.clipboard.writeText(pre.textContent.trim());
btn.textContent = 'Copied!';
setTimeout(() => btn.textContent = 'Copy', 1500);
}
function restoreEdits() {
document.querySelectorAll('pre[data-username]').forEach(el => {
const saved = localStorage.getItem('draft_' + el.dataset.username);
if (saved) {
el.textContent = saved;
el.closest('details').querySelector('.status').textContent = '(edited)';
}
});
}
function exportEdits() {
const edits = [];
document.querySelectorAll('pre[data-username]').forEach(el => {
const original = el.dataset.original;
const current = el.textContent.trim();
if (original !== current) {
edits.push({ username: el.dataset.username, original, edited: current });
}
});
if (edits.length === 0) { alert('No edits to export'); return; }
const blob = new Blob([JSON.stringify({exported_at: new Date().toISOString(), edits}, null, 2)], {type: 'application/json'});
const a = document.createElement('a');
a.href = URL.createObjectURL(blob);
a.download = 'draft_edits.json';
a.click();
}
restoreEdits();Add export button in header when using editable drafts:
html
<p class="meta">Generated: {timestamp} · {count} drafts · <button onclick="exportEdits()">Export Edits</button></p>适用于用户可能在发送前编辑的草稿内容,可追踪原文与编辑后的内容以便后续分析。
html
<details>
<summary><strong>@username</strong> — action <span class="status"></span></summary>
<pre contenteditable="true"
data-username="username"
data-original="Original draft text here"
onblur="saveDraft(this)">Original draft text here</pre>
<div class="actions">
<a href="tg://resolve?domain=username">Open Telegram</a>
<button onclick="copyDraft(this)">Copy</button>
</div>
</details>在标签末尾(之前)添加以下脚本块:
<body></body>javascript
function saveDraft(el) {
const key = 'draft_' + el.dataset.username;
const edited = el.textContent.trim();
const original = el.dataset.original;
if (edited !== original) {
localStorage.setItem(key, edited);
el.closest('details').querySelector('.status').textContent = '(edited)';
}
}
function copyDraft(btn) {
const pre = btn.closest('details').querySelector('pre');
navigator.clipboard.writeText(pre.textContent.trim());
btn.textContent = 'Copied!';
setTimeout(() => btn.textContent = 'Copy', 1500);
}
function restoreEdits() {
document.querySelectorAll('pre[data-username]').forEach(el => {
const saved = localStorage.getItem('draft_' + el.dataset.username);
if (saved) {
el.textContent = saved;
el.closest('details').querySelector('.status').textContent = '(edited)';
}
});
}
function exportEdits() {
const edits = [];
document.querySelectorAll('pre[data-username]').forEach(el => {
const original = el.dataset.original;
const current = el.textContent.trim();
if (original !== current) {
edits.push({ username: el.dataset.username, original, edited: current });
}
});
if (edits.length === 0) { alert('No edits to export'); return; }
const blob = new Blob([JSON.stringify({exported_at: new Date().toISOString(), edits}, null, 2)], {type: 'application/json'});
const a = document.createElement('a');
a.href = URL.createObjectURL(blob);
a.download = 'draft_edits.json';
a.click();
}
restoreEdits();使用可编辑草稿时,在头部添加导出按钮:
html
<p class="meta">Generated: {timestamp} · {count} drafts · <button onclick="exportEdits()">Export Edits</button></p>Workflow
工作流
- Identify the data to display (file, variable, recent output)
- Choose pattern: list, table, or expandable sections
- Generate HTML using template above
- Write to
_private/views/{name}-temp.html - Run
open _private/views/{name}-temp.html - If user approves, promote to
{name}.html
- 确定需要展示的数据(文件、变量、最新输出)
- 选择合适的模式:列表、表格或可展开区域
- 使用上述模板生成HTML
- 写入至
_private/views/{name}-temp.html - 执行命令
open _private/views/{name}-temp.html - 若用户确认,将文件升级为
{name}.html
Example
示例
User: "show me the drafts"
Claude:
- Reads
_private/drafts/outreach_drafts.md - Parses each draft (heading = contact, body = draft)
- Generates HTML with for each draft
<details> - Writes to
_private/views/drafts-temp.html - Runs
open _private/views/drafts-temp.html
Result: Browser opens, user sees expandable list of drafts with auto dark/light mode, long content truncated with "Show more", can copy each one.
User: "this looks good, keep it"
Claude:
- Renames →
drafts-temp.htmldrafts.html - Confirms: "Saved as drafts.html"
用户:“show me the drafts”
Claude执行步骤:
- 读取文件
_private/drafts/outreach_drafts.md - 解析每个草稿(标题为联系人,正文为草稿内容)
- 为每个草稿生成带标签的HTML
<details> - 写入至
_private/views/drafts-temp.html - 执行命令
open _private/views/drafts-temp.html
结果:浏览器打开页面,用户可看到可展开的草稿列表,支持自动深色/浅色模式,长内容会被截断并显示“Show more”按钮,还可复制每个草稿内容。
用户:“this looks good, keep it”
Claude执行步骤:
- 将重命名为
drafts-temp.htmldrafts.html - 回复确认:“Saved as drafts.html”
Styling Handoff
样式交接
This skill produces functional HTML with minimal styling. For full visual styling, invoke the skill after generating.
html-styleClasses used by quick-view (compatible with html-style):
| Class | Purpose |
|---|---|
| User input/message |
| Draft content |
| Completed item |
| Attribution links |
| Metadata header |
| Long content container |
| Action button container |
Data attributes for JS hooks:
- — Identifier for drafts
data-username - — Original text for diff tracking
data-original
本技能生成的是具备基础功能的HTML,仅包含极简样式。如需完整的视觉样式,可在生成后调用技能。
html-style快速视图使用的类名(与html-style兼容):
| 类名 | 用途 |
|---|---|
| 用户输入/消息 |
| 草稿内容 |
| 已完成项目 |
| 来源链接 |
| 元数据头部 |
| 长内容容器 |
| 操作按钮容器 |
用于JS钩子的属性:
- — 草稿的标识
data-username - — 用于差异追踪的原文内容
data-original
Attribution
致谢
Truncation pattern and CSS variables approach inspired by simon willison's claude-code-transcripts.
截断内容的实现模式与CSS变量的使用方式灵感来自simon willison的claude-code-transcripts。