Skip to content

Commit 0d2d889

Browse files
committed
fix: breakout landing, use node 24
1 parent 308da19 commit 0d2d889

3 files changed

Lines changed: 365 additions & 249 deletions

File tree

packages/server/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
"types": "./dist/index.d.ts",
88
"scripts": {
99
"develop": "tsx --watch src/index.ts",
10-
"build": "tsc --build && cp src/schema/schema.graphql dist/schema/",
10+
"build": "tsc --build && cp src/schema/schema.graphql dist/schema/ && cp src/landing.html dist/",
1111
"type-check": "tsc --noEmit",
1212
"lint": "oxlint src",
1313
"format": "prettier --write src/",

packages/server/src/landing.html

Lines changed: 352 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,352 @@
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.0" />
6+
<title>freeCodeCamp Curriculum GraphQL API</title>
7+
<style>
8+
* {
9+
margin: 0;
10+
padding: 0;
11+
box-sizing: border-box;
12+
}
13+
14+
body {
15+
font-family:
16+
-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto,
17+
'Helvetica Neue', Arial, sans-serif;
18+
background: linear-gradient(135deg, #0a0a23 0%, #1b1b32 100%);
19+
color: #fff;
20+
min-height: 100vh;
21+
display: flex;
22+
align-items: center;
23+
justify-content: center;
24+
padding: 2rem;
25+
}
26+
27+
.container {
28+
max-width: 800px;
29+
background: rgba(255, 255, 255, 0.05);
30+
border-radius: 12px;
31+
padding: 3rem;
32+
backdrop-filter: blur(10px);
33+
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3);
34+
}
35+
36+
h1 {
37+
font-size: 2rem;
38+
margin-bottom: 1rem;
39+
background: linear-gradient(90deg, #fff, #aaa);
40+
-webkit-background-clip: text;
41+
-webkit-text-fill-color: transparent;
42+
background-clip: text;
43+
}
44+
45+
.badge {
46+
display: inline-block;
47+
background: linear-gradient(135deg, #ff6b6b, #ee5a6f);
48+
color: #fff;
49+
padding: 0.4rem 0.8rem;
50+
border-radius: 20px;
51+
font-size: 0.75rem;
52+
font-weight: 700;
53+
letter-spacing: 0.5px;
54+
text-transform: uppercase;
55+
margin-bottom: 1rem;
56+
box-shadow: 0 2px 8px rgba(255, 107, 107, 0.3);
57+
}
58+
59+
.subtitle {
60+
font-size: 1.2rem;
61+
color: #aaa;
62+
margin-bottom: 2rem;
63+
}
64+
65+
.section {
66+
margin: 2rem 0;
67+
}
68+
69+
.section h2 {
70+
font-size: 1.5rem;
71+
margin-bottom: 1rem;
72+
color: #fff;
73+
}
74+
75+
.link-card {
76+
background: rgba(255, 255, 255, 0.08);
77+
border: 1px solid rgba(255, 255, 255, 0.1);
78+
border-radius: 8px;
79+
padding: 1.5rem;
80+
margin-bottom: 1rem;
81+
transition: all 0.3s ease;
82+
}
83+
84+
.link-card:hover {
85+
background: rgba(255, 255, 255, 0.12);
86+
border-color: rgba(255, 255, 255, 0.2);
87+
transform: translateY(-2px);
88+
}
89+
90+
.link-card h3 {
91+
color: #fff;
92+
margin-bottom: 0.5rem;
93+
font-size: 1.2rem;
94+
}
95+
96+
.link-card p {
97+
color: #aaa;
98+
margin-bottom: 0.75rem;
99+
line-height: 1.6;
100+
}
101+
102+
.link-card a {
103+
display: inline-block;
104+
color: #3eeca8;
105+
text-decoration: none;
106+
font-weight: 600;
107+
transition: color 0.2s;
108+
}
109+
110+
.link-card a:hover {
111+
color: #2bc88d;
112+
}
113+
114+
.code {
115+
background: rgba(0, 0, 0, 0.3);
116+
padding: 0.25rem 0.5rem;
117+
border-radius: 4px;
118+
font-family: 'Courier New', monospace;
119+
font-size: 0.9rem;
120+
}
121+
122+
.footer {
123+
margin-top: 2rem;
124+
padding-top: 2rem;
125+
border-top: 1px solid rgba(255, 255, 255, 0.1);
126+
text-align: center;
127+
color: #888;
128+
font-size: 0.9rem;
129+
}
130+
131+
.footer a {
132+
color: #3eeca8;
133+
text-decoration: none;
134+
}
135+
136+
.stats-list {
137+
list-style: none;
138+
padding: 0;
139+
}
140+
141+
.stats-item {
142+
padding: 0.5rem 0;
143+
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
144+
}
145+
146+
.stats-item:last-child {
147+
border-bottom: none;
148+
}
149+
150+
.stats-number {
151+
color: #3eeca8;
152+
}
153+
154+
.stats-label {
155+
color: #aaa;
156+
}
157+
158+
.text-muted {
159+
color: #ddd;
160+
}
161+
162+
.mt-0-5 {
163+
margin-top: 0.5rem;
164+
}
165+
166+
.mt-1 {
167+
margin-top: 1rem;
168+
}
169+
170+
.mb-1 {
171+
margin-bottom: 1rem;
172+
}
173+
174+
.code-block {
175+
background: rgba(0, 0, 0, 0.3);
176+
padding: 1rem;
177+
border-radius: 4px;
178+
overflow-x: auto;
179+
font-size: 0.85rem;
180+
line-height: 1.5;
181+
margin-top: 0.5rem;
182+
}
183+
</style>
184+
</head>
185+
186+
<body>
187+
<div class="container">
188+
<div class="badge">Early Alpha</div>
189+
<h1>freeCodeCamp Curriculum GraphQL API</h1>
190+
<p class="subtitle">
191+
Access curriculum metadata for superblocks, blocks, and challenges
192+
</p>
193+
194+
<div class="section">
195+
<h2>Getting Started</h2>
196+
<div class="link-card">
197+
<h3>GraphQL Playground</h3>
198+
<p>Interactive GraphiQL interface to explore and test queries</p>
199+
<a href="/graphql">Open GraphiQL →</a>
200+
</div>
201+
<div class="link-card">
202+
<h3>GraphQL Endpoint</h3>
203+
<p>Send POST requests to <span class="code">/graphql</span></p>
204+
<a href="/graphql" target="_blank">View Endpoint →</a>
205+
</div>
206+
<div class="link-card">
207+
<h3>GitHub Repository</h3>
208+
<p>View source code, contribute, and report issues</p>
209+
<a
210+
href="https://github.com/freeCodeCamp/curriculum-db"
211+
target="_blank"
212+
>View on GitHub →</a
213+
>
214+
</div>
215+
</div>
216+
217+
<div class="section">
218+
<h2>Statistics</h2>
219+
<div class="link-card">
220+
<p class="mb-1">
221+
The API provides access to the complete freeCodeCamp curriculum
222+
structure:
223+
</p>
224+
<ul class="stats-list">
225+
<li class="stats-item">
226+
<strong class="stats-number">37</strong>
227+
<span class="stats-label">Superblocks</span>
228+
</li>
229+
<li class="stats-item">
230+
<strong class="stats-number">38</strong>
231+
<span class="stats-label"
232+
>Chapters (v9 curriculum primitive)</span
233+
>
234+
</li>
235+
<li class="stats-item">
236+
<strong class="stats-number">217</strong>
237+
<span class="stats-label">Modules (v9 curriculum primitive)</span>
238+
</li>
239+
<li class="stats-item">
240+
<strong class="stats-number">779</strong>
241+
<span class="stats-label">Unique Blocks (deduplicated)</span>
242+
</li>
243+
<li class="stats-item">
244+
<strong class="stats-number">14,038</strong>
245+
<span class="stats-label">Challenges</span>
246+
</li>
247+
</ul>
248+
</div>
249+
</div>
250+
251+
<div class="section">
252+
<h2>Sample Queries</h2>
253+
254+
<div class="link-card">
255+
<h3>Hierarchical Structure</h3>
256+
<p>The new v9 curriculum introduces a three-level hierarchy:</p>
257+
<p class="mt-0-5">
258+
<span class="code">Superblock → Chapter → Module → Block</span>
259+
</p>
260+
<p class="mt-1 text-muted">Query chapters and modules directly:</p>
261+
<pre class="code-block">
262+
query {
263+
chapters(superblockDashedName: "full-stack-developer") {
264+
dashedName
265+
modules {
266+
dashedName
267+
blocks
268+
}
269+
}
270+
}</pre
271+
>
272+
</div>
273+
274+
<div class="link-card">
275+
<h3>Block Sharing</h3>
276+
<p>
277+
In v9 curriculum, blocks can be shared across multiple superblocks.
278+
The API automatically deduplicates blocks and tracks all parent
279+
superblocks:
280+
</p>
281+
<pre class="code-block">
282+
query {
283+
block(dashedName: "learn-html-by-building-a-cat-photo-app") {
284+
title
285+
superblocks {
286+
dashedName
287+
title
288+
}
289+
}
290+
}</pre
291+
>
292+
</div>
293+
294+
<div class="link-card">
295+
<h3>Get Curriculum Overview</h3>
296+
<pre class="code-block">
297+
query {
298+
curriculum {
299+
superblocks
300+
certifications
301+
}
302+
}</pre
303+
>
304+
</div>
305+
306+
<div class="link-card">
307+
<h3>Query Modules by Chapter</h3>
308+
<pre class="code-block">
309+
query {
310+
modules(chapterDashedName: "html") {
311+
dashedName
312+
moduleType
313+
blockObjects {
314+
title
315+
challenges {
316+
id
317+
title
318+
}
319+
}
320+
}
321+
}</pre
322+
>
323+
</div>
324+
325+
<div class="link-card">
326+
<h3>Explore a Superblock (Legacy)</h3>
327+
<pre class="code-block">
328+
query {
329+
superblock(dashedName: "responsive-web-design") {
330+
title
331+
blocks
332+
challenges {
333+
id
334+
title
335+
}
336+
}
337+
}</pre
338+
>
339+
</div>
340+
</div>
341+
342+
<div class="footer">
343+
<p>
344+
Built with ❤️ by
345+
<a href="https://www.freecodecamp.org" target="_blank"
346+
>freeCodeCamp</a
347+
>
348+
</p>
349+
</div>
350+
</div>
351+
</body>
352+
</html>

0 commit comments

Comments
 (0)