Skip to content

Commit fdc7535

Browse files
committed
Add schedule PDF export
1 parent a1f49d7 commit fdc7535

3 files changed

Lines changed: 182 additions & 6 deletions

File tree

assets/site.js

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -312,6 +312,8 @@ const copy = {
312312
scheduleOpenDay: "回到今日清单",
313313
matrixKicker: "Schedule Table",
314314
matrixTitle: "间隔学习总表",
315+
exportMatrixPdf: "导出 PDF",
316+
exportMatrixPdfTitle: "Vibe Coding Guide · 36 天学习计划",
315317
resetMatrix: "清空表格勾选",
316318
resetMatrixConfirm: "确定要清空总表里的所有勾选吗?",
317319
matrixDay: "天",
@@ -421,6 +423,8 @@ const copy = {
421423
scheduleOpenDay: "Today's checklist",
422424
matrixKicker: "Schedule Table",
423425
matrixTitle: "Spaced Learning Table",
426+
exportMatrixPdf: "Export PDF",
427+
exportMatrixPdfTitle: "Vibe Coding Guide · 36-Day Learning Plan",
424428
resetMatrix: "Clear table checks",
425429
resetMatrixConfirm: "Clear all table checks?",
426430
matrixDay: "Day",
@@ -647,6 +651,8 @@ const els = {
647651
matrixKicker: document.querySelector("#matrix-kicker"),
648652
matrixTitle: document.querySelector("#matrix-title"),
649653
matrixTable: document.querySelector("#schedule-table"),
654+
exportMatrixPdf: document.querySelector("#export-matrix-pdf-button"),
655+
exportMatrixPdfLabel: document.querySelector("#export-matrix-pdf-label"),
650656
resetMatrix: document.querySelector("#reset-matrix-button"),
651657
resetMatrixLabel: document.querySelector("#reset-matrix-label"),
652658
noteKicker: document.querySelector("#note-kicker"),
@@ -1714,6 +1720,9 @@ function renderSchedulePlan() {
17141720
els.scheduleOpenDayLabel.textContent = text.scheduleOpenDay;
17151721
els.matrixKicker.textContent = text.matrixKicker;
17161722
els.matrixTitle.textContent = text.matrixTitle;
1723+
els.exportMatrixPdfLabel.textContent = text.exportMatrixPdf;
1724+
els.exportMatrixPdf.title = text.exportMatrixPdf;
1725+
els.exportMatrixPdf.setAttribute("aria-label", text.exportMatrixPdf);
17171726
els.resetMatrixLabel.textContent = text.resetMatrix;
17181727

17191728
renderScheduleTable();
@@ -2062,6 +2071,23 @@ function resetMatrixProgress() {
20622071
renderSchedulePlan();
20632072
}
20642073

2074+
function exportSchedulePdf() {
2075+
const previousTitle = document.title;
2076+
document.body.dataset.printMode = "schedule";
2077+
document.title = copy[state.lang].exportMatrixPdfTitle;
2078+
2079+
window.addEventListener(
2080+
"afterprint",
2081+
() => {
2082+
delete document.body.dataset.printMode;
2083+
document.title = previousTitle;
2084+
},
2085+
{ once: true },
2086+
);
2087+
2088+
window.requestAnimationFrame(() => window.print());
2089+
}
2090+
20652091
async function loadGuide(lang, shouldUpdateUrl = true) {
20662092
state.lang = lang;
20672093
state.headings = [];
@@ -2376,6 +2402,7 @@ els.nextDay.addEventListener("click", () => setDay(state.day + 1));
23762402
els.openReader.addEventListener("click", () => openChapter(firstChapterForDay(state.day)));
23772403
els.resetDay.addEventListener("click", () => resetDay(state.day));
23782404
els.resetAllButton.addEventListener("click", resetAllProgress);
2405+
els.exportMatrixPdf.addEventListener("click", exportSchedulePdf);
23792406
els.resetMatrix.addEventListener("click", resetMatrixProgress);
23802407
els.search.addEventListener("input", renderToc);
23812408
els.top.addEventListener("click", () => window.scrollTo({ top: 0, behavior: "smooth" }));

assets/styles.css

Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -674,6 +674,13 @@ button:disabled {
674674
align-items: end;
675675
}
676676

677+
.matrix-actions {
678+
display: flex;
679+
flex-wrap: wrap;
680+
gap: 0.55rem;
681+
justify-content: flex-end;
682+
}
683+
677684
.section-heading h2 {
678685
margin: 0;
679686
font-size: clamp(1.4rem, 2.4vw, 2rem);
@@ -1723,3 +1730,139 @@ button:disabled {
17231730
min-height: 8.5rem;
17241731
}
17251732
}
1733+
1734+
@page {
1735+
size: A4 landscape;
1736+
margin: 10mm;
1737+
}
1738+
1739+
@media print {
1740+
body[data-print-mode="schedule"] {
1741+
width: auto;
1742+
min-width: 0;
1743+
padding: 0 !important;
1744+
overflow: visible !important;
1745+
background: #fff !important;
1746+
color: #000;
1747+
}
1748+
1749+
body[data-print-mode="schedule"] .site-progress,
1750+
body[data-print-mode="schedule"] .topbar,
1751+
body[data-print-mode="schedule"] .sidebar,
1752+
body[data-print-mode="schedule"] .planner-view,
1753+
body[data-print-mode="schedule"] .reader-view,
1754+
body[data-print-mode="schedule"] .schedule-hero,
1755+
body[data-print-mode="schedule"] .matrix-actions,
1756+
body[data-print-mode="schedule"] .noscript {
1757+
display: none !important;
1758+
}
1759+
1760+
body[data-print-mode="schedule"] .app-shell,
1761+
body[data-print-mode="schedule"] .workspace,
1762+
body[data-print-mode="schedule"] .schedule-view {
1763+
display: block !important;
1764+
width: 100% !important;
1765+
max-width: none !important;
1766+
min-height: 0 !important;
1767+
margin: 0 !important;
1768+
padding: 0 !important;
1769+
}
1770+
1771+
body[data-print-mode="schedule"] .schedule-view[hidden] {
1772+
display: block !important;
1773+
}
1774+
1775+
body[data-print-mode="schedule"] .matrix-section,
1776+
body[data-print-mode="schedule"] .schedule-view .matrix-section {
1777+
display: block !important;
1778+
padding: 0 !important;
1779+
border: 0 !important;
1780+
}
1781+
1782+
body[data-print-mode="schedule"] .section-heading {
1783+
margin: 0 0 6mm;
1784+
}
1785+
1786+
body[data-print-mode="schedule"] .section-heading h2 {
1787+
color: #000;
1788+
font-size: 16pt;
1789+
}
1790+
1791+
body[data-print-mode="schedule"] .section-heading .eyebrow {
1792+
color: #000;
1793+
font-size: 8pt;
1794+
}
1795+
1796+
body[data-print-mode="schedule"] .schedule-table-wrap {
1797+
overflow: visible !important;
1798+
border: 0;
1799+
border-radius: 0;
1800+
background: #fff;
1801+
}
1802+
1803+
body[data-print-mode="schedule"] .schedule-table {
1804+
width: 100%;
1805+
min-width: 0;
1806+
table-layout: fixed;
1807+
border-collapse: collapse;
1808+
}
1809+
1810+
body[data-print-mode="schedule"] .schedule-table thead th:first-child,
1811+
body[data-print-mode="schedule"] .schedule-table tbody th {
1812+
position: static;
1813+
}
1814+
1815+
body[data-print-mode="schedule"] .schedule-table th,
1816+
body[data-print-mode="schedule"] .schedule-table td {
1817+
min-width: 0;
1818+
height: auto;
1819+
padding: 3.2pt;
1820+
border: 0.8pt solid #000;
1821+
background: #fff !important;
1822+
color: #000;
1823+
font-size: 7.2pt;
1824+
line-height: 1.25;
1825+
}
1826+
1827+
body[data-print-mode="schedule"] .schedule-table thead th {
1828+
font-size: 7.5pt;
1829+
}
1830+
1831+
body[data-print-mode="schedule"] .schedule-table tbody th {
1832+
width: auto;
1833+
}
1834+
1835+
body[data-print-mode="schedule"] .schedule-cell {
1836+
display: inline-flex;
1837+
gap: 2pt;
1838+
}
1839+
1840+
body[data-print-mode="schedule"] .schedule-day-link,
1841+
body[data-print-mode="schedule"] .schedule-cell-link {
1842+
color: #000;
1843+
text-decoration: none;
1844+
}
1845+
1846+
body[data-print-mode="schedule"] .schedule-check {
1847+
width: 8pt;
1848+
height: 8pt;
1849+
}
1850+
1851+
body[data-print-mode="schedule"] .schedule-check-mark {
1852+
width: 8pt;
1853+
height: 8pt;
1854+
border: 0.8pt solid #000;
1855+
border-radius: 1pt;
1856+
}
1857+
1858+
body[data-print-mode="schedule"] .schedule-check input:checked + .schedule-check-mark {
1859+
border-color: #000;
1860+
background: #fff;
1861+
box-shadow: none;
1862+
}
1863+
1864+
body[data-print-mode="schedule"] .schedule-check input:checked + .schedule-check-mark::after {
1865+
color: #000;
1866+
font-size: 7pt;
1867+
}
1868+
}

index.html

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,12 @@
1919
<meta name="twitter:card" content="summary" />
2020
<link rel="canonical" href="https://lling0000.github.io/Vibe_coding_guide/" />
2121
<title>Vibe Coding Guide | AI Coding 工程工作流手册</title>
22-
<link rel="stylesheet" href="./assets/styles.css?v=20260617-chapter-reader" />
22+
<link rel="stylesheet" href="./assets/styles.css?v=20260617-schedule-pdf" />
2323
<script defer src="https://cdn.jsdelivr.net/npm/dompurify@3.2.6/dist/purify.min.js"></script>
2424
<script defer src="https://cdn.jsdelivr.net/npm/marked@15.0.12/marked.min.js"></script>
2525
<script defer src="https://cdn.jsdelivr.net/npm/mermaid@11.4.1/dist/mermaid.min.js"></script>
2626
<script defer src="https://cdn.jsdelivr.net/npm/lucide@0.475.0/dist/umd/lucide.min.js"></script>
27-
<script defer src="./assets/site.js?v=20260617-chapter-reader"></script>
27+
<script defer src="./assets/site.js?v=20260617-schedule-pdf"></script>
2828
</head>
2929
<body data-mode="planner">
3030
<div class="site-progress" aria-hidden="true">
@@ -211,10 +211,16 @@ <h1 id="schedule-title">36 天学习计划</h1>
211211
<p class="eyebrow" id="matrix-kicker">Schedule Table</p>
212212
<h2 id="matrix-title">间隔学习总表</h2>
213213
</div>
214-
<button type="button" class="text-button" id="reset-matrix-button">
215-
<i data-lucide="eraser" aria-hidden="true"></i>
216-
<span id="reset-matrix-label">清空表格勾选</span>
217-
</button>
214+
<div class="matrix-actions">
215+
<button type="button" class="text-button primary" id="export-matrix-pdf-button">
216+
<i data-lucide="file-down" aria-hidden="true"></i>
217+
<span id="export-matrix-pdf-label">导出 PDF</span>
218+
</button>
219+
<button type="button" class="text-button" id="reset-matrix-button">
220+
<i data-lucide="eraser" aria-hidden="true"></i>
221+
<span id="reset-matrix-label">清空表格勾选</span>
222+
</button>
223+
</div>
218224
</div>
219225
<div class="schedule-table-wrap">
220226
<table class="schedule-table" id="schedule-table"></table>

0 commit comments

Comments
 (0)