npx skills add https://github.com/shipshitdev/library --skill quick-view在浏览器中生成最简化的 HTML 以查看结构化数据。样式极简,可读性最大化。
务必:
<table>、<ul>、<details>、<pre>、<h1-3>_private/views/ 目录open _private/views/{filename} 命令打开广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
视图文件有一个生命周期:临时 → 保留 → 归档。
| 阶段 | 文件名 | 时机 |
|---|---|---|
| 临时 | name-temp.html | 新视图的默认状态 |
| 保留 | name.html | 用户说"保留这个"、"这个不错"时 |
| 归档 | name.2025-01-01.html | 在提升新版本时,之前的保留文件 |
规则:
-temp 后缀创建 — 每个新视图都以 name-temp.html 开始name.htmlname.html 已存在,在提升新版本前将其重命名为 name.DATE.html-temp 文件工作流程:
# 第一次迭代
drafts-temp.html ← 已创建
# 用户:"保留这个"
drafts.html ← 已提升(临时文件删除)
# 后续迭代
drafts-temp.html ← 新的临时文件创建
drafts.html ← 保留文件保持不变
# 用户:"这个更好,保留它"
drafts.2025-01-01.html ← 旧的保留文件归档
drafts.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;
}
/* 长内容截断 */
.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-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 { color: var(--muted); font-size: 0.75rem; }
.source a { color: var(--muted); }
.source a:hover { color: var(--accent); }
</style>
</head>
<body>
<p class="meta">生成时间: {timestamp} · {count} 个项目</p>
{content}
<script>
// 截断切换
document.querySelectorAll('.truncate').forEach(el => {
if (el.scrollHeight > 220) {
const btn = document.createElement('button');
btn.className = 'expand-btn';
btn.textContent = '显示更多';
btn.onclick = () => {
el.classList.toggle('expanded');
btn.textContent = el.classList.contains('expanded') ? '显示更少' : '显示更多';
};
el.after(btn);
} else {
el.classList.add('expanded'); // 无需截断
}
});
</script>
</body>
</html>
<h1>标题</h1>
<ul>
<li><strong>@username</strong> — 待办事项</li>
</ul>
<table>
<tr><th>联系人</th><th>操作</th><th>草稿</th></tr>
<tr><td>@name</td><td>跟进</td><td>你好...</td></tr>
</table>
<details>
<summary><strong>@username</strong> — 操作</summary>
<div class="truncate">
<pre>可能需要截断的长内容...</pre>
</div>
</details>
<div class="type-user">用户消息或输入</div>
<div class="type-draft">草稿内容</div>
<div class="type-done">已完成项目</div>
<p>
<a href="tg://resolve?domain=username">打开 Telegram</a> ·
<button onclick="navigator.clipboard.writeText('draft text')">复制</button>
</p>
当显示从外部来源收集的数据时,始终包含用于深入查看的归属链接。
添加到基础模板 CSS:
.source { color: var(--muted); font-size: 0.75rem; }
.source a { color: var(--muted); }
.source a:hover { color: var(--accent); }
内联归属(列表首选):
<div class="tip">
<strong>提示标题</strong> — 提示描述。
<span class="source">— <a href="https://x.com/user/status/123">@username</a></span>
</div>
带来源列的表格:
<table>
<tr><th>提示</th><th>来源</th></tr>
<tr>
<td>此处描述</td>
<td class="source"><a href="https://x.com/user/status/123">@user</a></td>
</tr>
</table>
摘要中带来源的可展开内容:
<details>
<summary><strong>提示标题</strong> <span class="source">— <a href="URL">@source</a></span></summary>
<p>完整内容...</p>
</details>
带主要来源的元数据头部:
<p class="meta">
生成时间: {timestamp} · {count} 个项目 ·
来源: <a href="https://x.com/user/status/123">原始主题</a>
</p>
原则:
@username,文章使用域名适用于用户在发送前可能编辑的草稿。跟踪原始版本与编辑版本以供后续分析。
<details>
<summary><strong>@username</strong> — 操作 <span class="status"></span></summary>
<pre contenteditable="true"
data-username="username"
data-original="原始草稿文本在此"
onblur="saveDraft(this)">原始草稿文本在此</pre>
<div class="actions">
<a href="tg://resolve?domain=username">打开 Telegram</a>
<button onclick="copyDraft(this)">复制</button>
</div>
</details>
在 <body> 结束前(在 </body> 标签之前)包含此脚本块:
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 = '(已编辑)';
}
}
function copyDraft(btn) {
const pre = btn.closest('details').querySelector('pre');
navigator.clipboard.writeText(pre.textContent.trim());
btn.textContent = '已复制!';
setTimeout(() => btn.textContent = '复制', 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 = '(已编辑)';
}
});
}
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('没有可导出的编辑'); 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();
使用可编辑草稿时,在头部添加导出按钮:
<p class="meta">生成时间: {timestamp} · {count} 个草稿 · <button onclick="exportEdits()">导出编辑</button></p>
_private/views/{name}-temp.htmlopen _private/views/{name}-temp.html{name}.html用户:"给我看看草稿"
Claude:
_private/drafts/outreach_drafts.md<details> 的 HTML_private/views/drafts-temp.htmlopen _private/views/drafts-temp.html结果:浏览器打开,用户看到可展开的草稿列表,自动深色/浅色模式,长内容被截断并带有"显示更多"按钮,可以复制每个草稿。
用户:"看起来不错,保留它"
Claude:
drafts-temp.html → drafts.html此技能生成功能性的 HTML,样式极简。如需完整的视觉样式,请在生成后调用 html-style 技能。
快速查看使用的类(与 html-style 兼容):
| 类 | 用途 |
|---|---|
.type-user | 用户输入/消息 |
.type-draft | 草稿内容 |
.type-done | 已完成项目 |
.source | 归属链接 |
.meta | 元数据头部 |
.truncate | 长内容容器 |
.actions | 操作按钮容器 |
用于 JS 钩子的数据属性:
data-username — 草稿的标识符data-original — 用于差异跟踪的原始文本截断模式和 CSS 变量方法灵感来源于 simon willison's claude-code-transcripts。
每周安装数
75
仓库
GitHub 星标数
19
首次出现
2026年1月20日
安全审计
安装于
codex58
opencode57
gemini-cli56
cursor52
github-copilot49
claude-code49
Generate minimal HTML to review structured data in a browser. Minimal styling, maximum readability.
DO:
<table>, <ul>, <details>, <pre>, <h1-3>_private/views/open _private/views/{filename}DO NOT:
Views have a lifecycle: temporary → keeper → archived.
| Stage | Filename | When |
|---|---|---|
| Temporary | name-temp.html | Default for new views |
| Keeper | name.html | User says "keep this", "this is good" |
| Archived | name.2025-01-01.html | Previous keeper when promoting new one |
Rules:
-temp suffix — Every new view starts as name-temp.htmlname.htmlname.html exists, rename to name.DATE.html before promoting-temp filesWorkflow:
# First iteration
drafts-temp.html ← created
# User: "keep this"
drafts.html ← promoted (temp deleted)
# Later iteration
drafts-temp.html ← new temp created
drafts.html ← keeper untouched
# User: "this is better, keep it"
drafts.2025-01-01.html ← old keeper archived
drafts.html ← new keeper promoted
Trigger phrases for promotion:
Every quick-view HTML file:
<!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>
<h1>Title</h1>
<ul>
<li><strong>@username</strong> — action item</li>
</ul>
<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>
<details>
<summary><strong>@username</strong> — action</summary>
<div class="truncate">
<pre>Long content here that may need truncation...</pre>
</div>
</details>
<div class="type-user">User message or input</div>
<div class="type-draft">Draft content</div>
<div class="type-done">Completed item</div>
<p>
<a href="tg://resolve?domain=username">Open Telegram</a> ·
<button onclick="navigator.clipboard.writeText('draft text')">Copy</button>
</p>
When displaying data gathered from external sources, always include attribution links for drill-down.
Add to base template 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):
<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:
<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:
<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:
<p class="meta">
Generated: {timestamp} · {count} items ·
Source: <a href="https://x.com/user/status/123">Original thread</a>
</p>
Principles:
@username for social media, domain for articlesFor drafts that user may edit before sending. Tracks original vs edited for later analysis.
<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 <body> (before closing </body> tag):
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:
<p class="meta">Generated: {timestamp} · {count} drafts · <button onclick="exportEdits()">Export Edits</button></p>
_private/views/{name}-temp.htmlopen _private/views/{name}-temp.html{name}.htmlUser: "show me the drafts"
Claude:
_private/drafts/outreach_drafts.md<details> for each draft_private/views/drafts-temp.htmlopen _private/views/drafts-temp.htmlResult: 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:
drafts-temp.html → drafts.htmlThis skill produces functional HTML with minimal styling. For full visual styling, invoke the html-style skill after generating.
Classes used by quick-view (compatible with html-style):
| Class | Purpose |
|---|---|
.type-user | User input/message |
.type-draft | Draft content |
.type-done | Completed item |
.source | Attribution links |
.meta | Metadata header |
.truncate | Long content container |
Data attributes for JS hooks:
data-username — Identifier for draftsdata-original — Original text for diff trackingTruncation pattern and CSS variables approach inspired by simon willison's claude-code-transcripts.
Weekly Installs
75
Repository
GitHub Stars
19
First Seen
Jan 20, 2026
Security Audits
Gen Agent Trust HubPassSocketPassSnykFail
Installed on
codex58
opencode57
gemini-cli56
cursor52
github-copilot49
claude-code49
React 组合模式指南:Vercel 组件架构最佳实践,提升代码可维护性
120,000 周安装
微信文章转Markdown工具 - 高效抓取公众号文章并转换为Markdown格式,支持存档与AI处理
215 周安装
Mantine Combobox 组件:React 下拉选择与自动完成的底层原语 | 构建自定义 UI
241 周安装
新西兰商务英语指南:专业写作、毛利语使用与语气规范 | 商务沟通技巧
228 周安装
Browserbase Search API:快速搜索网络并返回结构化结果,无需浏览器会话
247 周安装
图标系统设计规范与最佳实践 - 图标网格、命名规则、可访问性指南
75 周安装
物联网开发技能 | Arduino/ESP32编程、MQTT通信、智能家居与工业物联网解决方案
228 周安装
.actions| Action button container |