Skip to content

Commit 432f0d0

Browse files
taylorarndtCopilot
andcommitted
Add EPUB build pipeline
- scripts/build-epub.js — builds a single EPUB from all 44 docs/ files - epub/metadata.yaml — title, author, language, TOC depth, CC BY 4.0 rights - epub/epub.css — clean typesetting (serif body, sans headings, code blocks, tables) - .github/workflows/build-epub.yml — auto-builds on docs/ changes, uploads as artifact - npm run build:epub script added to package.json EPUB is generated locally but not committed (in .gitignore). The workflow artifact is retained for 90 days. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent ab2f926 commit 432f0d0

6 files changed

Lines changed: 277 additions & 0 deletions

File tree

.github/workflows/build-epub.yml

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
name: Build EPUB
2+
3+
on:
4+
push:
5+
branches: [ main ]
6+
paths:
7+
- 'docs/**'
8+
- 'epub/metadata.yaml'
9+
- 'epub/epub.css'
10+
- 'scripts/build-epub.js'
11+
workflow_dispatch:
12+
13+
permissions:
14+
contents: write
15+
16+
jobs:
17+
build:
18+
runs-on: ubuntu-latest
19+
steps:
20+
- name: Checkout repository
21+
uses: actions/checkout@v4
22+
23+
- name: Install Pandoc
24+
run: |
25+
sudo apt-get update -qq
26+
sudo apt-get install -y pandoc
27+
28+
- name: Set up Node.js
29+
uses: actions/setup-node@v4
30+
with:
31+
node-version: 20
32+
33+
- name: Build EPUB
34+
run: node scripts/build-epub.js
35+
36+
- name: Upload EPUB artifact
37+
uses: actions/upload-artifact@v4
38+
with:
39+
name: git-going-with-github-epub
40+
path: epub/git-going-with-github.epub
41+
retention-days: 90
42+
43+
- name: Commit EPUB to repository
44+
run: |
45+
git config user.name "github-actions[bot]"
46+
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
47+
git add epub/git-going-with-github.epub
48+
if [ -n "$(git status --porcelain)" ]; then
49+
git commit -m "chore: rebuild EPUB from latest docs"
50+
git push
51+
else
52+
echo "No EPUB changes to commit"
53+
fi

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,3 +165,4 @@ podcasts/tts/samples/
165165
*.onnx
166166
*.onnx.json
167167
*.wav
168+
epub/git-going-with-github.epub

epub/epub.css

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
/* GIT Going with GitHub — EPUB Stylesheet */
2+
3+
/* ---- Body & typography ---- */
4+
body {
5+
font-family: Georgia, "Times New Roman", serif;
6+
font-size: 1em;
7+
line-height: 1.7;
8+
color: #1a1a1a;
9+
margin: 0;
10+
padding: 0;
11+
}
12+
13+
/* ---- Headings ---- */
14+
h1, h2, h3, h4, h5, h6 {
15+
font-family: -apple-system, "Segoe UI", Helvetica, Arial, sans-serif;
16+
font-weight: 700;
17+
line-height: 1.3;
18+
margin-top: 1.5em;
19+
margin-bottom: 0.5em;
20+
page-break-after: avoid;
21+
}
22+
23+
h1 {
24+
font-size: 1.9em;
25+
border-bottom: 2px solid #1a1a1a;
26+
padding-bottom: 0.3em;
27+
page-break-before: always;
28+
}
29+
30+
/* Don't page-break before the very first chapter */
31+
h1:first-child {
32+
page-break-before: avoid;
33+
}
34+
35+
h2 { font-size: 1.4em; }
36+
h3 { font-size: 1.15em; }
37+
h4 { font-size: 1em; font-style: italic; }
38+
39+
/* ---- Paragraphs ---- */
40+
p {
41+
margin-top: 0;
42+
margin-bottom: 0.9em;
43+
orphans: 3;
44+
widows: 3;
45+
}
46+
47+
/* ---- Links ---- */
48+
a {
49+
color: #0550ae;
50+
text-decoration: underline;
51+
}
52+
53+
/* ---- Code ---- */
54+
code, kbd, samp {
55+
font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, monospace;
56+
font-size: 0.88em;
57+
background: #f3f4f6;
58+
padding: 0.1em 0.35em;
59+
border-radius: 3px;
60+
}
61+
62+
pre {
63+
font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, monospace;
64+
font-size: 0.82em;
65+
background: #f3f4f6;
66+
border: 1px solid #d1d5db;
67+
border-radius: 4px;
68+
padding: 1em;
69+
overflow-x: auto;
70+
white-space: pre-wrap;
71+
word-break: break-word;
72+
page-break-inside: avoid;
73+
}
74+
75+
pre code {
76+
background: none;
77+
padding: 0;
78+
border-radius: 0;
79+
font-size: 1em;
80+
}
81+
82+
/* ---- Blockquotes ---- */
83+
blockquote {
84+
margin: 1em 0 1em 1.5em;
85+
padding-left: 1em;
86+
border-left: 3px solid #9ca3af;
87+
color: #4b5563;
88+
font-style: italic;
89+
}
90+
91+
/* ---- Lists ---- */
92+
ul, ol {
93+
margin: 0.5em 0 0.9em 1.5em;
94+
padding: 0;
95+
}
96+
97+
li {
98+
margin-bottom: 0.3em;
99+
}
100+
101+
/* ---- Tables ---- */
102+
table {
103+
width: 100%;
104+
border-collapse: collapse;
105+
margin: 1em 0;
106+
font-size: 0.9em;
107+
page-break-inside: avoid;
108+
}
109+
110+
th, td {
111+
border: 1px solid #d1d5db;
112+
padding: 0.5em 0.75em;
113+
text-align: left;
114+
vertical-align: top;
115+
}
116+
117+
th {
118+
background: #f3f4f6;
119+
font-weight: 700;
120+
}
121+
122+
tr:nth-child(even) td {
123+
background: #fafafa;
124+
}
125+
126+
/* ---- Horizontal rules ---- */
127+
hr {
128+
border: none;
129+
border-top: 1px solid #d1d5db;
130+
margin: 2em 0;
131+
}
132+
133+
/* ---- Images ---- */
134+
img {
135+
max-width: 100%;
136+
height: auto;
137+
}
138+
139+
/* ---- Callout-style blockquotes (podcast tip blocks) ---- */
140+
blockquote p strong:first-child {
141+
display: block;
142+
font-style: normal;
143+
color: #1a1a1a;
144+
}

epub/metadata.yaml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
---
2+
title: "GIT Going with GitHub"
3+
subtitle: "A Two-Day Accessible Open Source Workshop"
4+
author: "Community Access"
5+
date: "2026"
6+
lang: en
7+
description: "A comprehensive two-day workshop teaching GitHub fundamentals with a focus on accessibility, screen readers, and inclusive open source participation."
8+
rights: "CC BY 4.0 — Community Access"
9+
toc: true
10+
toc-depth: 2
11+
epub-chapter-level: 1

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
"version": "1.0.0",
44
"description": "GIT Going with GitHub - Accessible open source workshop by Community Access",
55
"scripts": {
6+
"build:epub": "node scripts/build-epub.js",
67
"build:html": "node scripts/build-html.js",
78
"build:podcasts": "node podcasts/build-bundles.js && node podcasts/generate-site.js",
89
"build:podcast-bundles": "node podcasts/build-bundles.js",

scripts/build-epub.js

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
#!/usr/bin/env node
2+
/**
3+
* Build EPUB from docs/ markdown files using Pandoc.
4+
* Outputs: epub/git-going-with-github.epub
5+
*/
6+
7+
const { execSync } = require('child_process');
8+
const fs = require('fs');
9+
const path = require('path');
10+
11+
const ROOT = path.resolve(__dirname, '..');
12+
const DOCS = path.join(ROOT, 'docs');
13+
const OUT = path.join(ROOT, 'epub', 'git-going-with-github.epub');
14+
const METADATA = path.join(ROOT, 'epub', 'metadata.yaml');
15+
const CSS = path.join(ROOT, 'epub', 'epub.css');
16+
17+
// Ordered file list: course-guide first, then 00-16, then appendices a-z
18+
function getDocFiles() {
19+
const all = fs.readdirSync(DOCS)
20+
.filter(f => f.endsWith('.md'))
21+
.sort();
22+
23+
const courseGuide = all.filter(f => f === 'course-guide.md');
24+
const chapters = all.filter(f => /^\d{2}-/.test(f));
25+
const appendices = all.filter(f => f.startsWith('appendix-'));
26+
const rest = all.filter(f =>
27+
!courseGuide.includes(f) &&
28+
!chapters.includes(f) &&
29+
!appendices.includes(f)
30+
);
31+
32+
return [...courseGuide, ...chapters, ...appendices, ...rest]
33+
.map(f => path.join(DOCS, f));
34+
}
35+
36+
const files = getDocFiles();
37+
38+
console.log(`Building EPUB from ${files.length} files...\n`);
39+
files.forEach(f => console.log(' ', path.relative(ROOT, f)));
40+
41+
const fileArgs = files.map(f => `"${f}"`).join(' ');
42+
43+
const cmd = [
44+
'pandoc',
45+
'--from markdown+smart',
46+
'--to epub3',
47+
`--output "${OUT}"`,
48+
`--metadata-file "${METADATA}"`,
49+
`--css "${CSS}"`,
50+
'--toc',
51+
'--toc-depth=2',
52+
'--split-level=1',
53+
'--syntax-highlighting=tango',
54+
'--wrap=none',
55+
fileArgs
56+
].join(' \\\n ');
57+
58+
console.log('\nRunning pandoc...\n');
59+
60+
try {
61+
execSync(cmd, { stdio: 'inherit', cwd: ROOT });
62+
const size = (fs.statSync(OUT).size / 1024).toFixed(1);
63+
console.log(`\nDone. EPUB written to: epub/git-going-with-github.epub (${size} KB)`);
64+
} catch (err) {
65+
console.error('\nPandoc failed. Is pandoc installed? Run: brew install pandoc');
66+
process.exit(1);
67+
}

0 commit comments

Comments
 (0)