mcp-scraper 0.40.1 → 0.40.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/bin/api-server.cjs +60220 -0
- package/dist/bin/api-server.cjs.map +1 -0
- package/dist/bin/api-server.d.cts +1 -0
- package/dist/bin/api-server.d.ts +1 -0
- package/dist/bin/api-server.js +38 -0
- package/dist/bin/api-server.js.map +1 -0
- package/dist/bin/mcp-scraper-cli.cjs +2671 -0
- package/dist/bin/mcp-scraper-cli.cjs.map +1 -0
- package/dist/bin/mcp-scraper-cli.d.cts +1 -0
- package/dist/bin/mcp-scraper-cli.d.ts +1 -0
- package/dist/bin/mcp-scraper-cli.js +742 -0
- package/dist/bin/mcp-scraper-cli.js.map +1 -0
- package/dist/bin/mcp-scraper-install.cjs +129 -0
- package/dist/bin/mcp-scraper-install.cjs.map +1 -0
- package/dist/bin/mcp-scraper-install.d.cts +1 -0
- package/dist/bin/mcp-scraper-install.d.ts +1 -0
- package/dist/bin/mcp-scraper-install.js +27 -0
- package/dist/bin/mcp-scraper-install.js.map +1 -0
- package/dist/bin/mcp-stdio-server.cjs +12532 -0
- package/dist/bin/mcp-stdio-server.cjs.map +1 -0
- package/dist/bin/mcp-stdio-server.d.cts +1 -0
- package/dist/bin/mcp-stdio-server.d.ts +1 -0
- package/dist/bin/mcp-stdio-server.js +135 -0
- package/dist/bin/mcp-stdio-server.js.map +1 -0
- package/dist/bin/paa-harvest.cjs +3808 -0
- package/dist/bin/paa-harvest.cjs.map +1 -0
- package/dist/bin/paa-harvest.d.cts +1 -0
- package/dist/bin/paa-harvest.d.ts +1 -0
- package/dist/bin/paa-harvest.js +44 -0
- package/dist/bin/paa-harvest.js.map +1 -0
- package/dist/chunk-345BQXZH.js +712 -0
- package/dist/chunk-345BQXZH.js.map +1 -0
- package/dist/chunk-3PIWJS6Y.js +276 -0
- package/dist/chunk-3PIWJS6Y.js.map +1 -0
- package/dist/chunk-44HZLHDV.js +52 -0
- package/dist/chunk-44HZLHDV.js.map +1 -0
- package/dist/chunk-7XBBFBYY.js +3410 -0
- package/dist/chunk-7XBBFBYY.js.map +1 -0
- package/dist/chunk-CB5C3BPB.js +135 -0
- package/dist/chunk-CB5C3BPB.js.map +1 -0
- package/dist/chunk-FQI5PFE7.js +1866 -0
- package/dist/chunk-FQI5PFE7.js.map +1 -0
- package/dist/chunk-G3P3ZDB4.js +69 -0
- package/dist/chunk-G3P3ZDB4.js.map +1 -0
- package/dist/chunk-GUVKHCKE.js +3050 -0
- package/dist/chunk-GUVKHCKE.js.map +1 -0
- package/dist/chunk-K443GQY5.js +24 -0
- package/dist/chunk-K443GQY5.js.map +1 -0
- package/dist/chunk-LP6E462I.js +11555 -0
- package/dist/chunk-LP6E462I.js.map +1 -0
- package/dist/chunk-NVXNEOUQ.js +158 -0
- package/dist/chunk-NVXNEOUQ.js.map +1 -0
- package/dist/chunk-QZXKQB7Y.js +414 -0
- package/dist/chunk-QZXKQB7Y.js.map +1 -0
- package/dist/chunk-SBLGBZZB.js +647 -0
- package/dist/chunk-SBLGBZZB.js.map +1 -0
- package/dist/chunk-X2LKCX6H.js +499 -0
- package/dist/chunk-X2LKCX6H.js.map +1 -0
- package/dist/chunk-XELSA2MS.js +108 -0
- package/dist/chunk-XELSA2MS.js.map +1 -0
- package/dist/chunk-XORPNO3Z.js +684 -0
- package/dist/chunk-XORPNO3Z.js.map +1 -0
- package/dist/chunk-ZUJLSICT.js +7 -0
- package/dist/chunk-ZUJLSICT.js.map +1 -0
- package/dist/db-W3CP562I.js +239 -0
- package/dist/db-W3CP562I.js.map +1 -0
- package/dist/editorial-reading-room/assets/app.js +335 -0
- package/dist/editorial-reading-room/assets/index.html +131 -0
- package/dist/editorial-reading-room/assets/styles.css +1052 -0
- package/dist/extract-bundle-K4PG3RZJ.js +568 -0
- package/dist/extract-bundle-K4PG3RZJ.js.map +1 -0
- package/dist/index.cjs +4160 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +413 -0
- package/dist/index.d.ts +413 -0
- package/dist/index.js +338 -0
- package/dist/index.js.map +1 -0
- package/dist/location-data-repository-RLQX6SNM.js +35 -0
- package/dist/location-data-repository-RLQX6SNM.js.map +1 -0
- package/dist/server-KM3CFWCF.js +34674 -0
- package/dist/server-KM3CFWCF.js.map +1 -0
- package/dist/site-extract-repository-2SMMFKKL.js +62 -0
- package/dist/site-extract-repository-2SMMFKKL.js.map +1 -0
- package/dist/worker-FXAGFYOE.js +142 -0
- package/dist/worker-FXAGFYOE.js.map +1 -0
- package/package.json +4 -2
|
@@ -0,0 +1,335 @@
|
|
|
1
|
+
const elements = {
|
|
2
|
+
home: document.querySelector("#home-view"),
|
|
3
|
+
article: document.querySelector("#article-view"),
|
|
4
|
+
loading: document.querySelector("#loading-screen"),
|
|
5
|
+
menuButton: document.querySelector("#menu-button"),
|
|
6
|
+
menuClose: document.querySelector("#menu-close"),
|
|
7
|
+
backdrop: document.querySelector("#drawer-backdrop"),
|
|
8
|
+
drawer: document.querySelector("#navigation-drawer"),
|
|
9
|
+
drawerNav: document.querySelector("#drawer-navigation"),
|
|
10
|
+
search: document.querySelector("#menu-search"),
|
|
11
|
+
progress: document.querySelector("#reading-progress-bar"),
|
|
12
|
+
desktopJumps: document.querySelector("#desktop-jump-links")
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
const state = {
|
|
16
|
+
data: null,
|
|
17
|
+
current: null,
|
|
18
|
+
storageKey: "editorial-reading-room",
|
|
19
|
+
typeIndex: Number(localStorage.getItem("editorial-reading-room:type") || 0),
|
|
20
|
+
completed: new Set(
|
|
21
|
+
JSON.parse(localStorage.getItem("editorial-reading-room:completed") || "[]")
|
|
22
|
+
)
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
const typeModes = ["default", "large", "larger"];
|
|
26
|
+
|
|
27
|
+
function escapeHtml(value = "") {
|
|
28
|
+
return value
|
|
29
|
+
.replace(/&/g, "&")
|
|
30
|
+
.replace(/</g, "<")
|
|
31
|
+
.replace(/>/g, ">")
|
|
32
|
+
.replace(/"/g, """);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function setTypeMode() {
|
|
36
|
+
const mode = typeModes[state.typeIndex % typeModes.length];
|
|
37
|
+
if (mode === "default") document.documentElement.removeAttribute("data-type");
|
|
38
|
+
else document.documentElement.dataset.type = mode;
|
|
39
|
+
localStorage.setItem(`${state.storageKey}:type`, String(state.typeIndex % typeModes.length));
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function setTheme(theme) {
|
|
43
|
+
if (theme === "evening") document.documentElement.dataset.theme = "evening";
|
|
44
|
+
else document.documentElement.removeAttribute("data-theme");
|
|
45
|
+
localStorage.setItem(`${state.storageKey}:theme`, theme);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function routeSlug() {
|
|
49
|
+
return new URL(window.location.href).searchParams.get("article");
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function articleUrl(slug, section = "") {
|
|
53
|
+
const url = new URL(window.location.href);
|
|
54
|
+
if (slug) url.searchParams.set("article", slug);
|
|
55
|
+
else url.searchParams.delete("article");
|
|
56
|
+
url.hash = section ? `#${section}` : "";
|
|
57
|
+
return `${url.pathname}${url.search}${url.hash}`;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function navigate(slug, section = "", replace = false) {
|
|
61
|
+
const method = replace ? "replaceState" : "pushState";
|
|
62
|
+
history[method]({}, "", articleUrl(slug, section));
|
|
63
|
+
renderRoute();
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function openDrawer() {
|
|
67
|
+
document.body.classList.add("drawer-open");
|
|
68
|
+
elements.drawer.setAttribute("aria-hidden", "false");
|
|
69
|
+
elements.menuButton.setAttribute("aria-expanded", "true");
|
|
70
|
+
renderDrawer();
|
|
71
|
+
requestAnimationFrame(() => elements.search.focus());
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function closeDrawer() {
|
|
75
|
+
document.body.classList.remove("drawer-open");
|
|
76
|
+
elements.drawer.setAttribute("aria-hidden", "true");
|
|
77
|
+
elements.menuButton.setAttribute("aria-expanded", "false");
|
|
78
|
+
elements.search.value = "";
|
|
79
|
+
elements.menuButton.focus();
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function groupArticles(articles) {
|
|
83
|
+
const groups = new Map();
|
|
84
|
+
articles.forEach((article) => {
|
|
85
|
+
if (!groups.has(article.category)) groups.set(article.category, []);
|
|
86
|
+
groups.get(article.category).push(article);
|
|
87
|
+
});
|
|
88
|
+
return groups;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function renderDrawer() {
|
|
92
|
+
const query = elements.search.value.trim().toLowerCase();
|
|
93
|
+
const current = state.current;
|
|
94
|
+
const articles = state.data.articles.filter((article) => {
|
|
95
|
+
if (!query) return true;
|
|
96
|
+
return `${article.title} ${article.summary} ${article.category}`
|
|
97
|
+
.toLowerCase()
|
|
98
|
+
.includes(query);
|
|
99
|
+
});
|
|
100
|
+
const groups = groupArticles(articles);
|
|
101
|
+
let html = "";
|
|
102
|
+
for (const [category, items] of groups) {
|
|
103
|
+
html += `<section class="drawer-group"><p class="drawer-group-title">${escapeHtml(
|
|
104
|
+
category
|
|
105
|
+
)}</p>`;
|
|
106
|
+
items.forEach((article) => {
|
|
107
|
+
const index = String(article.order).padStart(2, "0");
|
|
108
|
+
const completed = state.completed.has(article.slug) ? "✓" : index;
|
|
109
|
+
html += `<button class="drawer-link" data-article="${article.slug}" ${
|
|
110
|
+
current?.slug === article.slug ? 'aria-current="page"' : ""
|
|
111
|
+
}><span class="drawer-index">${completed}</span><span class="drawer-title">${escapeHtml(
|
|
112
|
+
article.title
|
|
113
|
+
)}</span></button>`;
|
|
114
|
+
});
|
|
115
|
+
html += "</section>";
|
|
116
|
+
}
|
|
117
|
+
if (current && (!query || current.title.toLowerCase().includes(query))) {
|
|
118
|
+
html += `<section class="jump-group"><p class="drawer-group-title">Jump within this article</p>`;
|
|
119
|
+
current.toc.forEach((item) => {
|
|
120
|
+
html += `<button class="jump-link level-${item.level}" data-section="${item.id}">${escapeHtml(
|
|
121
|
+
item.title
|
|
122
|
+
)}</button>`;
|
|
123
|
+
});
|
|
124
|
+
html += "</section>";
|
|
125
|
+
}
|
|
126
|
+
elements.drawerNav.innerHTML = html || "<p>No matching articles.</p>";
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function renderHome() {
|
|
130
|
+
state.current = null;
|
|
131
|
+
elements.home.hidden = false;
|
|
132
|
+
elements.article.hidden = true;
|
|
133
|
+
elements.progress.style.width = "0";
|
|
134
|
+
document.title = state.data.site.title;
|
|
135
|
+
document.querySelector("#masthead-product").textContent = state.data.site.product;
|
|
136
|
+
document.querySelector("#masthead-title").textContent = state.data.site.edition;
|
|
137
|
+
document.querySelector("#edition-label").textContent = state.data.site.editionLabel;
|
|
138
|
+
document.querySelector("#issue-label").textContent = state.data.site.issueLabel;
|
|
139
|
+
document.querySelector("#home-eyebrow").textContent = state.data.site.eyebrow;
|
|
140
|
+
document.querySelector("#home-title").textContent = state.data.site.heroTitle;
|
|
141
|
+
document.querySelector("#start-label").textContent = state.data.site.startLabel;
|
|
142
|
+
document.querySelector("#footer-title").textContent = state.data.site.title;
|
|
143
|
+
document.querySelector("#home-deck").textContent = state.data.deck;
|
|
144
|
+
document.querySelector("#article-count").textContent = `${state.data.articles.length} readings`;
|
|
145
|
+
document.querySelector("#generated-at").textContent = `Updated ${new Date(
|
|
146
|
+
state.data.generatedAt
|
|
147
|
+
).toLocaleDateString("en-US", { month: "short", day: "numeric", year: "numeric" })}`;
|
|
148
|
+
|
|
149
|
+
const featured = state.data.articles.slice(0, 3);
|
|
150
|
+
document.querySelector("#featured-grid").innerHTML = featured
|
|
151
|
+
.map(
|
|
152
|
+
(article) => `<article class="feature-card">
|
|
153
|
+
<button data-article="${article.slug}">
|
|
154
|
+
<p class="card-kicker">${escapeHtml(article.kicker)}</p>
|
|
155
|
+
<h2>${escapeHtml(article.title)}</h2>
|
|
156
|
+
<p>${escapeHtml(article.summary)}</p>
|
|
157
|
+
</button>
|
|
158
|
+
</article>`
|
|
159
|
+
)
|
|
160
|
+
.join("");
|
|
161
|
+
|
|
162
|
+
document.querySelector("#contents-list").innerHTML = state.data.articles
|
|
163
|
+
.map(
|
|
164
|
+
(article) => `<article class="content-row">
|
|
165
|
+
<span class="content-number">${String(article.order).padStart(2, "0")}</span>
|
|
166
|
+
<button data-article="${article.slug}"><h3>${escapeHtml(article.title)}</h3></button>
|
|
167
|
+
<p>${escapeHtml(article.summary)}</p>
|
|
168
|
+
<span class="content-meta">${article.readingMinutes} min${
|
|
169
|
+
state.completed.has(article.slug) ? " · Read" : ""
|
|
170
|
+
}</span>
|
|
171
|
+
</article>`
|
|
172
|
+
)
|
|
173
|
+
.join("");
|
|
174
|
+
window.scrollTo({ top: 0, behavior: "instant" });
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
function renderDesktopJumps(article) {
|
|
178
|
+
elements.desktopJumps.innerHTML = article.toc
|
|
179
|
+
.map(
|
|
180
|
+
(item) =>
|
|
181
|
+
`<a class="level-${item.level}" href="#${item.id}" data-section-link="${item.id}">${escapeHtml(
|
|
182
|
+
item.title
|
|
183
|
+
)}</a>`
|
|
184
|
+
)
|
|
185
|
+
.join("");
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
function renderArticle(article) {
|
|
189
|
+
state.current = article;
|
|
190
|
+
elements.home.hidden = true;
|
|
191
|
+
elements.article.hidden = false;
|
|
192
|
+
document.title = `${article.title} — ${state.data.site.title}`;
|
|
193
|
+
document.querySelector("#article-category").textContent = article.category;
|
|
194
|
+
document.querySelector("#article-kicker").textContent = article.kicker;
|
|
195
|
+
document.querySelector("#article-title").textContent = article.title;
|
|
196
|
+
document.querySelector("#article-summary").textContent = article.summary;
|
|
197
|
+
document.querySelector("#article-reading-time").textContent = `${article.readingMinutes} min read`;
|
|
198
|
+
document.querySelector("#article-word-count").textContent = `${article.wordCount.toLocaleString()} words`;
|
|
199
|
+
document.querySelector("#article-revision").textContent = article.revision
|
|
200
|
+
? `Revision ${article.revision}`
|
|
201
|
+
: article.sourceType || "Source material";
|
|
202
|
+
document.querySelector("#article-body").innerHTML = article.html;
|
|
203
|
+
document.querySelector("#article-source").textContent = article.sourceLabel;
|
|
204
|
+
renderDesktopJumps(article);
|
|
205
|
+
renderAdjacent(article);
|
|
206
|
+
requestAnimationFrame(() => {
|
|
207
|
+
if (window.location.hash) {
|
|
208
|
+
document.querySelector(window.location.hash)?.scrollIntoView();
|
|
209
|
+
} else {
|
|
210
|
+
window.scrollTo({ top: 0, behavior: "instant" });
|
|
211
|
+
}
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
function renderAdjacent(article) {
|
|
216
|
+
const index = state.data.articles.findIndex((item) => item.slug === article.slug);
|
|
217
|
+
const previous = state.data.articles[index - 1];
|
|
218
|
+
const next = state.data.articles[index + 1];
|
|
219
|
+
const previousButton = document.querySelector("#previous-article");
|
|
220
|
+
const nextButton = document.querySelector("#next-article");
|
|
221
|
+
|
|
222
|
+
previousButton.disabled = !previous;
|
|
223
|
+
previousButton.dataset.article = previous?.slug || "";
|
|
224
|
+
previousButton.innerHTML = previous
|
|
225
|
+
? `<span class="eyebrow">Previous</span><br>${escapeHtml(previous.title)}`
|
|
226
|
+
: "Beginning of the edition";
|
|
227
|
+
|
|
228
|
+
nextButton.disabled = !next;
|
|
229
|
+
nextButton.dataset.article = next?.slug || "";
|
|
230
|
+
nextButton.innerHTML = next
|
|
231
|
+
? `<span class="eyebrow">Next</span><br>${escapeHtml(next.title)}`
|
|
232
|
+
: "End of the edition";
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
function renderRoute() {
|
|
236
|
+
const slug = routeSlug();
|
|
237
|
+
if (!slug) renderHome();
|
|
238
|
+
else {
|
|
239
|
+
const article = state.data.articles.find((item) => item.slug === slug);
|
|
240
|
+
if (article) renderArticle(article);
|
|
241
|
+
else navigate(null, "", true);
|
|
242
|
+
}
|
|
243
|
+
renderDrawer();
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
function updateReadingProgress() {
|
|
247
|
+
if (!state.current) return;
|
|
248
|
+
const article = document.querySelector("#article-body");
|
|
249
|
+
const rect = article.getBoundingClientRect();
|
|
250
|
+
const start = window.scrollY + rect.top - window.innerHeight * 0.18;
|
|
251
|
+
const end = start + article.offsetHeight - window.innerHeight * 0.55;
|
|
252
|
+
const percent = Math.max(0, Math.min(1, (window.scrollY - start) / Math.max(1, end - start)));
|
|
253
|
+
elements.progress.style.width = `${percent * 100}%`;
|
|
254
|
+
localStorage.setItem(`${state.storageKey}:progress:${state.current.slug}`, String(percent));
|
|
255
|
+
if (percent > 0.94 && !state.completed.has(state.current.slug)) {
|
|
256
|
+
state.completed.add(state.current.slug);
|
|
257
|
+
localStorage.setItem(`${state.storageKey}:completed`, JSON.stringify([...state.completed]));
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
let active = null;
|
|
261
|
+
for (const heading of document.querySelectorAll(".article-body h2, .article-body h3")) {
|
|
262
|
+
if (heading.getBoundingClientRect().top <= 150) active = heading.id;
|
|
263
|
+
}
|
|
264
|
+
document.querySelectorAll("[data-section-link]").forEach((link) => {
|
|
265
|
+
link.classList.toggle("active", link.dataset.sectionLink === active);
|
|
266
|
+
});
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
document.addEventListener("click", (event) => {
|
|
270
|
+
const articleButton = event.target.closest("[data-article]");
|
|
271
|
+
if (articleButton?.dataset.article) {
|
|
272
|
+
navigate(articleButton.dataset.article);
|
|
273
|
+
closeDrawer();
|
|
274
|
+
return;
|
|
275
|
+
}
|
|
276
|
+
const jump = event.target.closest("[data-section]");
|
|
277
|
+
if (jump && state.current) {
|
|
278
|
+
closeDrawer();
|
|
279
|
+
history.replaceState({}, "", articleUrl(state.current.slug, jump.dataset.section));
|
|
280
|
+
document.querySelector(`#${CSS.escape(jump.dataset.section)}`)?.scrollIntoView();
|
|
281
|
+
}
|
|
282
|
+
});
|
|
283
|
+
|
|
284
|
+
elements.menuButton.addEventListener("click", openDrawer);
|
|
285
|
+
elements.menuClose.addEventListener("click", closeDrawer);
|
|
286
|
+
elements.backdrop.addEventListener("click", closeDrawer);
|
|
287
|
+
elements.search.addEventListener("input", renderDrawer);
|
|
288
|
+
document.querySelector("#home-button").addEventListener("click", () => navigate(null));
|
|
289
|
+
document.querySelector("#footer-contents").addEventListener("click", () => navigate(null));
|
|
290
|
+
document.querySelector("#article-category").addEventListener("click", () => navigate(null));
|
|
291
|
+
document.querySelector("#start-reading").addEventListener("click", () =>
|
|
292
|
+
navigate(state.data.articles[0].slug)
|
|
293
|
+
);
|
|
294
|
+
document.querySelector("#type-button").addEventListener("click", () => {
|
|
295
|
+
state.typeIndex = (state.typeIndex + 1) % typeModes.length;
|
|
296
|
+
setTypeMode();
|
|
297
|
+
});
|
|
298
|
+
document.querySelector("#theme-button").addEventListener("click", () => {
|
|
299
|
+
setTheme(document.documentElement.dataset.theme === "evening" ? "day" : "evening");
|
|
300
|
+
});
|
|
301
|
+
|
|
302
|
+
window.addEventListener("popstate", renderRoute);
|
|
303
|
+
window.addEventListener("scroll", updateReadingProgress, { passive: true });
|
|
304
|
+
window.addEventListener("keydown", (event) => {
|
|
305
|
+
if (event.key === "Escape" && document.body.classList.contains("drawer-open")) closeDrawer();
|
|
306
|
+
if (event.key.toLowerCase() === "m" && !/input|textarea/i.test(event.target.tagName)) openDrawer();
|
|
307
|
+
if (!state.current || /input|textarea/i.test(event.target.tagName)) return;
|
|
308
|
+
const index = state.data.articles.findIndex((item) => item.slug === state.current.slug);
|
|
309
|
+
if (event.key === "[" && index > 0) navigate(state.data.articles[index - 1].slug);
|
|
310
|
+
if (event.key === "]" && index < state.data.articles.length - 1)
|
|
311
|
+
navigate(state.data.articles[index + 1].slug);
|
|
312
|
+
});
|
|
313
|
+
|
|
314
|
+
async function boot() {
|
|
315
|
+
const dataElement = document.querySelector("#reading-room-data");
|
|
316
|
+
if (!dataElement?.textContent) throw new Error("Could not load the reading-room content.");
|
|
317
|
+
state.data = JSON.parse(dataElement.textContent);
|
|
318
|
+
state.storageKey = `editorial-reading-room:${state.data.site.slug}`;
|
|
319
|
+
state.typeIndex = Number(localStorage.getItem(`${state.storageKey}:type`) || 0);
|
|
320
|
+
state.completed = new Set(
|
|
321
|
+
JSON.parse(localStorage.getItem(`${state.storageKey}:completed`) || "[]")
|
|
322
|
+
);
|
|
323
|
+
const savedTheme = localStorage.getItem(`${state.storageKey}:theme`);
|
|
324
|
+
if (savedTheme === "evening") setTheme("evening");
|
|
325
|
+
setTypeMode();
|
|
326
|
+
renderRoute();
|
|
327
|
+
elements.loading.classList.add("loaded");
|
|
328
|
+
document.querySelector("#main-content").focus({ preventScroll: true });
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
boot().catch((error) => {
|
|
332
|
+
elements.loading.innerHTML = `<span class="loading-mark">!</span><p>${escapeHtml(
|
|
333
|
+
error.message
|
|
334
|
+
)}</p>`;
|
|
335
|
+
});
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
6
|
+
<meta
|
|
7
|
+
name="description"
|
|
8
|
+
content="A mobile-first editorial reading room."
|
|
9
|
+
/>
|
|
10
|
+
<meta name="theme-color" content="#f5f1e8" />
|
|
11
|
+
<title>Editorial Reading Room</title>
|
|
12
|
+
<style>/*__READING_ROOM_STYLES__*/</style>
|
|
13
|
+
</head>
|
|
14
|
+
<body>
|
|
15
|
+
<a class="skip-link" href="#main-content">Skip to the article</a>
|
|
16
|
+
<div class="reading-progress" aria-hidden="true">
|
|
17
|
+
<span id="reading-progress-bar"></span>
|
|
18
|
+
</div>
|
|
19
|
+
|
|
20
|
+
<header class="site-header">
|
|
21
|
+
<button
|
|
22
|
+
class="menu-button"
|
|
23
|
+
id="menu-button"
|
|
24
|
+
type="button"
|
|
25
|
+
aria-label="Open contents and jump links"
|
|
26
|
+
aria-controls="navigation-drawer"
|
|
27
|
+
aria-expanded="false"
|
|
28
|
+
>
|
|
29
|
+
<span></span><span></span><span></span>
|
|
30
|
+
</button>
|
|
31
|
+
<button class="masthead" id="home-button" type="button" aria-label="Return to contents">
|
|
32
|
+
<span class="masthead-product" id="masthead-product">Reading Room</span>
|
|
33
|
+
<span class="masthead-title" id="masthead-title">Field Notes</span>
|
|
34
|
+
</button>
|
|
35
|
+
<div class="header-tools">
|
|
36
|
+
<button class="text-button" id="type-button" type="button" aria-label="Change text size">
|
|
37
|
+
<span aria-hidden="true">A<span class="type-large">A</span></span>
|
|
38
|
+
<span class="tool-label">Type</span>
|
|
39
|
+
</button>
|
|
40
|
+
<button class="text-button" id="theme-button" type="button" aria-label="Toggle evening mode">
|
|
41
|
+
<span aria-hidden="true">◐</span>
|
|
42
|
+
<span class="tool-label">Evening</span>
|
|
43
|
+
</button>
|
|
44
|
+
</div>
|
|
45
|
+
</header>
|
|
46
|
+
|
|
47
|
+
<aside class="navigation-drawer" id="navigation-drawer" aria-hidden="true">
|
|
48
|
+
<div class="drawer-header">
|
|
49
|
+
<p class="eyebrow">Reading desk</p>
|
|
50
|
+
<button id="menu-close" type="button" aria-label="Close navigation">Close</button>
|
|
51
|
+
</div>
|
|
52
|
+
<label class="search-field">
|
|
53
|
+
<span class="sr-only">Search the reading room</span>
|
|
54
|
+
<input id="menu-search" type="search" placeholder="Find an article or section" />
|
|
55
|
+
</label>
|
|
56
|
+
<nav id="drawer-navigation" aria-label="Reading room contents"></nav>
|
|
57
|
+
</aside>
|
|
58
|
+
<button class="drawer-backdrop" id="drawer-backdrop" type="button" aria-label="Close navigation"></button>
|
|
59
|
+
|
|
60
|
+
<main id="main-content" tabindex="-1">
|
|
61
|
+
<section id="home-view" class="home-view" hidden>
|
|
62
|
+
<div class="issue-line">
|
|
63
|
+
<span id="edition-label">Reader’s edition</span>
|
|
64
|
+
<span id="issue-label">Current edition</span>
|
|
65
|
+
<span id="article-count"></span>
|
|
66
|
+
</div>
|
|
67
|
+
<section class="home-hero">
|
|
68
|
+
<p class="eyebrow" id="home-eyebrow">A guided collection</p>
|
|
69
|
+
<h1 id="home-title">Make complex material easy to explore.</h1>
|
|
70
|
+
<p class="home-deck" id="home-deck"></p>
|
|
71
|
+
<button class="primary-link" id="start-reading" type="button">
|
|
72
|
+
<span id="start-label">Start reading</span> <span aria-hidden="true">→</span>
|
|
73
|
+
</button>
|
|
74
|
+
</section>
|
|
75
|
+
<section class="featured-grid" id="featured-grid" aria-label="Featured reading"></section>
|
|
76
|
+
<section class="contents-section">
|
|
77
|
+
<div class="section-heading">
|
|
78
|
+
<p class="eyebrow">The complete edition</p>
|
|
79
|
+
<h2>Contents</h2>
|
|
80
|
+
</div>
|
|
81
|
+
<div id="contents-list" class="contents-list"></div>
|
|
82
|
+
</section>
|
|
83
|
+
</section>
|
|
84
|
+
|
|
85
|
+
<section id="article-view" class="article-view" hidden>
|
|
86
|
+
<div class="article-shell">
|
|
87
|
+
<aside class="article-rail" aria-label="In this article">
|
|
88
|
+
<p class="rail-label">In this article</p>
|
|
89
|
+
<nav id="desktop-jump-links"></nav>
|
|
90
|
+
</aside>
|
|
91
|
+
<article>
|
|
92
|
+
<header class="article-header">
|
|
93
|
+
<button class="breadcrumb" id="article-category" type="button">Field Notes</button>
|
|
94
|
+
<p class="article-kicker" id="article-kicker"></p>
|
|
95
|
+
<h1 id="article-title"></h1>
|
|
96
|
+
<p class="article-deck" id="article-summary"></p>
|
|
97
|
+
<div class="article-meta">
|
|
98
|
+
<span id="article-reading-time"></span>
|
|
99
|
+
<span id="article-word-count"></span>
|
|
100
|
+
<span id="article-revision"></span>
|
|
101
|
+
</div>
|
|
102
|
+
</header>
|
|
103
|
+
<div class="article-body" id="article-body"></div>
|
|
104
|
+
<footer class="article-source">
|
|
105
|
+
<p class="eyebrow">Source record</p>
|
|
106
|
+
<p id="article-source"></p>
|
|
107
|
+
</footer>
|
|
108
|
+
</article>
|
|
109
|
+
</div>
|
|
110
|
+
<nav class="next-previous" aria-label="Previous and next articles">
|
|
111
|
+
<button id="previous-article" type="button"></button>
|
|
112
|
+
<button id="next-article" type="button"></button>
|
|
113
|
+
</nav>
|
|
114
|
+
</section>
|
|
115
|
+
</main>
|
|
116
|
+
|
|
117
|
+
<footer class="site-footer">
|
|
118
|
+
<span id="footer-title">Editorial Reading Room</span>
|
|
119
|
+
<button id="footer-contents" type="button">Contents</button>
|
|
120
|
+
<span id="generated-at"></span>
|
|
121
|
+
</footer>
|
|
122
|
+
|
|
123
|
+
<div class="loading-screen" id="loading-screen" role="status">
|
|
124
|
+
<span class="loading-mark">M</span>
|
|
125
|
+
<p>Preparing the reading room…</p>
|
|
126
|
+
</div>
|
|
127
|
+
|
|
128
|
+
<script id="reading-room-data" type="application/json">/*__READING_ROOM_DATA__*/</script>
|
|
129
|
+
<script>/*__READING_ROOM_SCRIPT__*/</script>
|
|
130
|
+
</body>
|
|
131
|
+
</html>
|