pdf-design

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

PDF Design System

PDF设计系统

Create and edit professional PDF reports and funding proposals with live preview and iterative design.
创建和编辑带有实时预览与迭代设计功能的专业PDF报告和资助提案。

Interactive editing mode

交互式编辑模式

During a design session, use these commands:
CommandAction
preview
Screenshot current state
preview page N
Screenshot specific page
show cover
Preview cover page
show budget
Preview budget section
regenerate
Create new PDF
upload
Upload to Google Drive
done
Finish session
Workflow:
  1. You say "preview" → I show current state
  2. You describe changes → I implement them
  3. Repeat until done → Generate final PDF

在设计会话中,使用以下命令:
命令操作
preview
截图当前状态
preview page N
截图指定页面
show cover
预览封面
show budget
预览预算部分
regenerate
生成新PDF
upload
上传至Google Drive
done
结束会话
工作流程:
  1. 你说"preview" → 我展示当前状态
  2. 你描述修改需求 → 我执行修改
  3. 重复操作直至完成 → 生成最终PDF

Quick start

快速开始

bash
undefined
bash
undefined

Copy template to start new report

Copy template to start new report

cp ~/.claude/plugins/pdf-design/templates/democracy-day-proposal.html ./new-report.html
cp ~/.claude/plugins/pdf-design/templates/democracy-day-proposal.html ./new-report.html

Generate PDF (must use snap-accessible path)

Generate PDF (must use snap-accessible path)

mkdir -p ~/snap/chromium/common/pdf-work cp new-report.html ~/snap/chromium/common/pdf-work/ chromium-browser --headless --disable-gpu
--print-to-pdf="$HOME/snap/chromium/common/pdf-work/output.pdf"
--no-pdf-header-footer
"file://$HOME/snap/chromium/common/pdf-work/new-report.html"
undefined
mkdir -p ~/snap/chromium/common/pdf-work cp new-report.html ~/snap/chromium/common/pdf-work/ chromium-browser --headless --disable-gpu
--print-to-pdf="$HOME/snap/chromium/common/pdf-work/output.pdf"
--no-pdf-header-footer
"file://$HOME/snap/chromium/common/pdf-work/new-report.html"
undefined

Document types

文档类型

  • Funding proposals — Grant requests with budgets
  • Program reports — Initiative updates
  • Impact reports — Metrics and outcomes
  • Budget summaries — Financial breakdowns
  • Funding proposals — 含预算的拨款申请
  • Program reports — 项目进展报告
  • Impact reports — 指标与成果报告
  • Budget summaries — 财务明细摘要

Key principles

核心原则

  1. Sentence case — Never Title Case
  2. Left-aligned — Never justified text
  3. Print-ready — 8.5" × 11" letter size
  4. Brand consistent — CCM red or program palettes

  1. 句子大小写 — 绝不使用标题大小写
  2. 左对齐 — 绝不使用两端对齐文本
  3. 可打印格式 — 8.5" × 11" 信纸尺寸
  4. 品牌一致性 — 使用CCM红色或项目专属配色

Brand guidelines

品牌规范

CCM standard colors

CCM标准配色

css
:root {
    --ccm-red: #CA3553;
    --ccm-black: #000000;
    --ccm-gray: #666666;
    --ccm-light: #e2e8f0;
}
css
:root {
    --ccm-red: #CA3553;
    --ccm-black: #000000;
    --ccm-gray: #666666;
    --ccm-light: #e2e8f0;
}

Program-specific (Democracy Day)

项目专属配色(民主日)

css
:root {
    --civic-navy: #1a2b4a;
    --civic-blue: #2d4a7c;
    --civic-gold: #c9a227;
    --civic-red: #b31942;
}
css
:root {
    --civic-navy: #1a2b4a;
    --civic-blue: #2d4a7c;
    --civic-gold: #c9a227;
    --civic-red: #b31942;
}

Typography

排版

html
<link href="https://fonts.googleapis.com/css2?family=Montserrat:wght@400;600;700&family=Source+Sans+Pro:wght@300;400;600&display=swap" rel="stylesheet">
css
body {
    font-family: 'Source Sans Pro', sans-serif;
    font-size: 0.875rem;
    line-height: 1.6;
}

h1, h2, h3 {
    font-family: 'Montserrat', sans-serif;
}

html
<link href="https://fonts.googleapis.com/css2?family=Montserrat:wght@400;600;700&family=Source+Sans+Pro:wght@300;400;600&display=swap" rel="stylesheet">
css
body {
    font-family: 'Source Sans Pro', sans-serif;
    font-size: 0.875rem;
    line-height: 1.6;
}

h1, h2, h3 {
    font-family: 'Montserrat', sans-serif;
}

HTML structure

HTML结构

Page setup

页面设置

css
@page { size: letter; margin: 0; }

.page {
    width: 8.5in;
    height: 11in;
    padding: 0.5in 0.65in;
    position: relative;
    page-break-after: always;
}
css
@page { size: letter; margin: 0; }

.page {
    width: 8.5in;
    height: 11in;
    padding: 0.5in 0.65in;
    position: relative;
    page-break-after: always;
}

Cover page

封面

html
<div class="page cover">
    <div class="cover-header">
        <div class="cover-org">Center for Cooperative Media</div>
        <h1 class="cover-title">Report title</h1>
        <p class="cover-intro">Brief description.</p>
    </div>
    <div class="cover-footer">
        <div class="cover-stats"><!-- Stats --></div>
        <div class="cover-footer-right">
            <div class="cover-date">February 2026</div>
            <div class="cover-logo"><img src="..." alt="Logo"></div>
        </div>
    </div>
</div>
html
<div class="page cover">
    <div class="cover-header">
        <div class="cover-org">Center for Cooperative Media</div>
        <h1 class="cover-title">Report title</h1>
        <p class="cover-intro">Brief description.</p>
    </div>
    <div class="cover-footer">
        <div class="cover-stats"><!-- Stats --></div>
        <div class="cover-footer-right">
            <div class="cover-date">February 2026</div>
            <div class="cover-logo"><img src="..." alt="Logo"></div>
        </div>
    </div>
</div>

Content page

内容页

html
<div class="page content-page">
    <div class="page-header">
        <div class="page-header-title">Document Title</div>
        <div class="page-number">2</div>
    </div>
    <!-- Content -->
</div>
html
<div class="page content-page">
    <div class="page-header">
        <div class="page-header-title">Document Title</div>
        <div class="page-number">2</div>
    </div>
    <!-- Content -->
</div>

Budget table

预算表格

html
<table class="budget-table">
    <thead>
        <tr><th>Expense</th><th>Per year</th><th>Total</th></tr>
    </thead>
    <tbody>
        <tr>
            <td>Item<span class="item-desc">Details</span></td>
            <td>$10,000</td>
            <td>$20,000</td>
        </tr>
    </tbody>
    <tfoot>
        <tr><td>Total</td><td>$50,000</td><td>$100,000</td></tr>
    </tfoot>
</table>
html
<table class="budget-table">
    <thead>
        <tr><th>Expense</th><th>Per year</th><th>Total</th></tr>
    </thead>
    <tbody>
        <tr>
            <td>Item<span class="item-desc">Details</span></td>
            <td>$10,000</td>
            <td>$20,000</td>
        </tr>
    </tbody>
    <tfoot>
        <tr><td>Total</td><td>$50,000</td><td>$100,000</td></tr>
    </tfoot>
</table>

Page footer (institution note)

页面页脚(机构说明)

css
.institution-note {
    position: absolute;
    bottom: 0.5in;
    left: 0.65in;
    right: 0.65in;
    border-top: 1px solid #e2e8f0;
    font-size: 0.8rem;
}

css
.institution-note {
    position: absolute;
    bottom: 0.5in;
    left: 0.65in;
    right: 0.65in;
    border-top: 1px solid #e2e8f0;
    font-size: 0.8rem;
}

PDF generation

PDF生成

Chromium (snap-confined)

Chromium(Snap沙箱环境)

bash
undefined
bash
undefined

Must use ~/snap/chromium/common/ path

Must use ~/snap/chromium/common/ path

mkdir -p ~/snap/chromium/common/pdf-work cp template.html ~/snap/chromium/common/pdf-work/ chromium-browser --headless --disable-gpu
--print-to-pdf="$HOME/snap/chromium/common/pdf-work/output.pdf"
--no-pdf-header-footer
"file://$HOME/snap/chromium/common/pdf-work/template.html" cp ~/snap/chromium/common/pdf-work/output.pdf ./
undefined
mkdir -p ~/snap/chromium/common/pdf-work cp template.html ~/snap/chromium/common/pdf-work/ chromium-browser --headless --disable-gpu
--print-to-pdf="$HOME/snap/chromium/common/pdf-work/output.pdf"
--no-pdf-header-footer
"file://$HOME/snap/chromium/common/pdf-work/template.html" cp ~/snap/chromium/common/pdf-work/output.pdf ./
undefined

Preview pages

页面预览

bash
undefined
bash
undefined

PDF to PNG

PDF to PNG

pdftoppm -png -f 1 -l 1 output.pdf preview
pdftoppm -png -f 1 -l 1 output.pdf preview

Page count

Page count

pdfinfo output.pdf | grep Pages
undefined
pdfinfo output.pdf | grep Pages
undefined

Legion browser preview

Legion浏览器预览

bash
~/.claude/scripts/legion-browser.py screenshot "file:///path/to/template.html" -o preview.png

bash
~/.claude/scripts/legion-browser.py screenshot "file:///path/to/template.html" -o preview.png

Google Drive upload

Google Drive上传

python
cd ~/.claude/workstation/mcp-servers/gmail && source .venv/bin/activate
python3 << 'PYEOF'
from googleapiclient.discovery import build
from googleapiclient.http import MediaFileUpload
from google.oauth2.credentials import Credentials
import json

with open('/home/jamditis/.claude/google/drive-token.json') as f:
    token_data = json.load(f)

creds = Credentials(
    token=token_data['access_token'],
    refresh_token=token_data.get('refresh_token'),
    token_uri='https://oauth2.googleapis.com/token',
    client_id=token_data.get('client_id'),
    client_secret=token_data.get('client_secret')
)

service = build('drive', 'v3', credentials=creds)
python
cd ~/.claude/workstation/mcp-servers/gmail && source .venv/bin/activate
python3 << 'PYEOF'
from googleapiclient.discovery import build
from googleapiclient.http import MediaFileUpload
from google.oauth2.credentials import Credentials
import json

with open('/home/jamditis/.claude/google/drive-token.json') as f:
    token_data = json.load(f)

creds = Credentials(
    token=token_data['access_token'],
    refresh_token=token_data.get('refresh_token'),
    token_uri='https://oauth2.googleapis.com/token',
    client_id=token_data.get('client_id'),
    client_secret=token_data.get('client_secret')
)

service = build('drive', 'v3', credentials=creds)

Upload new file

Upload new file

file_metadata = { 'name': 'Report.pdf', 'parents': ['1lKTdwq4_5uErj-tBN112WCdJGD2YtetO'] # Shared with Joe } media = MediaFileUpload('/path/to/output.pdf', mimetype='application/pdf') file = service.files().create(body=file_metadata, media_body=media, fields='id,webViewLink').execute() print(f"Uploaded: {file.get('webViewLink')}") PYEOF
undefined
file_metadata = { 'name': 'Report.pdf', 'parents': ['1lKTdwq4_5uErj-tBN112WCdJGD2YtetO'] # Shared with Joe } media = MediaFileUpload('/path/to/output.pdf', mimetype='application/pdf') file = service.files().create(body=file_metadata, media_body=media, fields='id,webViewLink').execute() print(f"Uploaded: {file.get('webViewLink')}") PYEOF
undefined

Drive folders

Drive文件夹

  • Shared with Joe:
    1lKTdwq4_5uErj-tBN112WCdJGD2YtetO
  • Claude Workspace:
    1e5dtKOiuvk0PPrFq3UyNI2UAa6RFiom3

  • Shared with Joe:
    1lKTdwq4_5uErj-tBN112WCdJGD2YtetO
  • Claude Workspace:
    1e5dtKOiuvk0PPrFq3UyNI2UAa6RFiom3

Known issues

已知问题

  1. Base64 images — Don't read HTML with large base64 using Read tool (API error). Use sed/grep/Python.
  2. Snap confinement — Chromium can only write to
    ~/snap/chromium/common/
  3. Fonts — Google Fonts via CDN; for offline, embed as base64
  1. Base64 images — 不要使用Read工具读取包含大型base64编码的HTML(会触发API错误),请使用sed/grep/Python处理。
  2. Snap confinement — Chromium仅能写入
    ~/snap/chromium/common/
    目录
  3. Fonts — 通过CDN使用Google Fonts;如需离线使用,请以base64格式嵌入

Logo locations

Logo位置

  • CCM logo:
    ~/.claude/plugins/pdf-design/templates/
    (embedded in template)
  • Brand assets:
    /home/jamditis/projects/cjs2026/public/internal/brand_web_assets/
  • CCM logo:
    ~/.claude/plugins/pdf-design/templates/
    (已嵌入模板)
  • Brand assets:
    /home/jamditis/projects/cjs2026/public/internal/brand_web_assets/

Template

模板

Reference:
~/.claude/plugins/pdf-design/templates/democracy-day-proposal.html
参考模板:
~/.claude/plugins/pdf-design/templates/democracy-day-proposal.html