Skip to content

Commit 98135b3

Browse files
Balaji SBalaji S
authored andcommitted
Add GitHub Pages course website
1 parent a25d57e commit 98135b3

5 files changed

Lines changed: 220 additions & 0 deletions

File tree

.github/workflows/pages.yml

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
name: Deploy course website
2+
3+
on:
4+
push:
5+
branches: [main]
6+
workflow_dispatch:
7+
8+
permissions:
9+
contents: read
10+
pages: write
11+
id-token: write
12+
13+
concurrency:
14+
group: pages
15+
cancel-in-progress: true
16+
17+
jobs:
18+
deploy:
19+
environment:
20+
name: github-pages
21+
url: ${{ steps.deployment.outputs.page_url }}
22+
runs-on: ubuntu-latest
23+
steps:
24+
- name: Checkout
25+
uses: actions/checkout@v4
26+
- name: Configure Pages
27+
uses: actions/configure-pages@v5
28+
- name: Upload website
29+
uses: actions/upload-pages-artifact@v3
30+
with:
31+
path: .
32+
- name: Deploy to GitHub Pages
33+
id: deployment
34+
uses: actions/deploy-pages@v4

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ This course is written for a first-time programmer, including school students. Y
66

77
This course is written from scratch for Python 3, with simple explanations, practical examples, and deliberate problem-solving practice.
88

9+
[Open the interactive course website](https://ibalajishanmugam.github.io/python-basic/)
10+
911
## Start here
1012

1113
1. Read [Learning Guide](LEARNING_GUIDE.md).

assets/site.css

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
:root {
2+
--ink: #172033;
3+
--muted: #637087;
4+
--line: #e4e9f1;
5+
--surface: #ffffff;
6+
--soft: #f5f7fb;
7+
--brand: #2864dc;
8+
--brand-dark: #1744a4;
9+
--warm: #fff7e8;
10+
}
11+
12+
* { box-sizing: border-box; }
13+
14+
body {
15+
margin: 0;
16+
color: var(--ink);
17+
background: var(--soft);
18+
font: 16px/1.7 system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
19+
}
20+
21+
.topbar {
22+
align-items: center;
23+
background: var(--surface);
24+
border-bottom: 1px solid var(--line);
25+
display: flex;
26+
justify-content: space-between;
27+
padding: 16px clamp(20px, 5vw, 72px);
28+
position: sticky;
29+
top: 0;
30+
z-index: 2;
31+
}
32+
33+
.brand { align-items: center; color: var(--ink); display: flex; font-size: 1.2rem; font-weight: 800; gap: 10px; text-decoration: none; }
34+
.python-logo { height: 34px; width: 34px; }
35+
.topbar nav { display: flex; gap: 22px; }
36+
.topbar nav a, .sidebar a { color: var(--muted); text-decoration: none; }
37+
.topbar nav a:hover, .sidebar a:hover { color: var(--brand); }
38+
39+
.layout { display: grid; grid-template-columns: 250px minmax(0, 850px); gap: 34px; margin: 0 auto; max-width: 1200px; padding: 34px 24px 70px; }
40+
.sidebar { align-self: start; background: var(--surface); border: 1px solid var(--line); border-radius: 14px; padding: 18px; position: sticky; top: 88px; }
41+
.sidebar-title { color: var(--ink); font-size: .82rem; font-weight: 800; letter-spacing: .08em; margin: 0 0 10px; text-transform: uppercase; }
42+
.sidebar a { display: block; font-size: .92rem; padding: 5px 0; }
43+
.content { background: var(--surface); border: 1px solid var(--line); border-radius: 16px; min-height: 70vh; padding: clamp(24px, 5vw, 56px); }
44+
.loading { color: var(--muted); }
45+
46+
h1 { font-size: clamp(2rem, 4vw, 3rem); line-height: 1.15; margin-top: 0; }
47+
h2 { border-bottom: 1px solid var(--line); line-height: 1.25; margin-top: 2.2em; padding-bottom: .3em; }
48+
h3 { margin-top: 1.8em; }
49+
a { color: var(--brand); }
50+
blockquote { background: var(--warm); border-left: 4px solid #f1b64c; margin-left: 0; padding: 10px 18px; }
51+
pre { background: #172033; border-radius: 10px; color: #f4f7fb; overflow-x: auto; padding: 16px; }
52+
code { background: #eef2f8; border-radius: 4px; padding: 2px 5px; }
53+
pre code { background: transparent; padding: 0; }
54+
table { border-collapse: collapse; display: block; margin: 18px 0; max-width: 100%; overflow-x: auto; }
55+
th, td { border: 1px solid var(--line); padding: 9px 12px; text-align: left; }
56+
th { background: var(--soft); }
57+
details { background: #f8faff; border: 1px solid #dce6fb; border-radius: 9px; margin: 14px 0; padding: 10px 14px; }
58+
summary { color: var(--brand-dark); cursor: pointer; font-weight: 700; }
59+
.footer { color: var(--muted); font-size: .9rem; padding: 0 24px 30px; text-align: center; }
60+
61+
@media (max-width: 760px) {
62+
.topbar { align-items: flex-start; flex-direction: column; gap: 8px; position: static; }
63+
.topbar nav { flex-wrap: wrap; gap: 8px 16px; }
64+
.layout { display: block; padding: 18px 12px 50px; }
65+
.sidebar { margin-bottom: 16px; position: static; }
66+
.sidebar a { display: inline-block; margin-right: 12px; }
67+
.content { padding: 24px 18px; }
68+
}

assets/site.js

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
(function () {
2+
const content = document.querySelector("#content");
3+
const params = new URLSearchParams(window.location.search);
4+
const file = params.get("file") || "README.md";
5+
6+
function isSafePath(path) {
7+
return path && !path.includes("..") && path.endsWith((".md"));
8+
}
9+
10+
function linkToSitePath(href, currentFile) {
11+
if (!href || href.startsWith("http") || href.startsWith("#") || href.startsWith("?")) return href;
12+
const clean = href.split("#")[0];
13+
if (!clean.endsWith(".md")) return href;
14+
const currentParts = currentFile.split("/");
15+
currentParts.pop();
16+
const result = [];
17+
for (const part of (currentParts.concat(clean.split("/")))) {
18+
if (!part || part === ".") continue;
19+
if (part === "..") result.pop(); else result.push(part);
20+
}
21+
const target = result.join("/");
22+
return isSafePath(target) ? `?file=${encodeURIComponent(target)}` : href;
23+
}
24+
25+
function rewriteLinks(currentFile) {
26+
content.querySelectorAll("a[href]").forEach((anchor) => {
27+
anchor.setAttribute("href", linkToSitePath(anchor.getAttribute("href"), currentFile));
28+
});
29+
}
30+
31+
async function loadPage(path) {
32+
if (!isSafePath(path) && path !== "README.md") {
33+
content.innerHTML = "<h1>Page not found</h1><p>Choose a chapter from the menu.</p>";
34+
return;
35+
}
36+
content.innerHTML = '<div class="loading">Loading...</div>';
37+
try {
38+
const response = await fetch(path);
39+
if (!response.ok) throw new Error("Page could not be loaded");
40+
const markdown = await response.text();
41+
content.innerHTML = marked.parse(markdown);
42+
rewriteLinks(path);
43+
content.focus();
44+
window.scrollTo({ top: 0, behavior: "smooth" });
45+
} catch (error) {
46+
content.innerHTML = `<h1>We could not open this lesson</h1><p>${error.message}</p><p>Use the chapter menu to try again.</p>`;
47+
}
48+
}
49+
50+
document.addEventListener("click", (event) => {
51+
const anchor = event.target.closest("a[href^='?file=']");
52+
if (!anchor) return;
53+
event.preventDefault();
54+
const next = new URL(anchor.href).searchParams.get("file");
55+
history.pushState({ file: next }, "", `?file=${encodeURIComponent(next)}`);
56+
loadPage(next);
57+
});
58+
59+
window.addEventListener("popstate", () => {
60+
loadPage(new URLSearchParams(window.location.search).get("file") || "README.md");
61+
});
62+
63+
loadPage(file);
64+
}());

index.html

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
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 name="description" content="A clear, self-paced Python course for first-time programmers and school students.">
7+
<title>Python Basic - Learn by Building</title>
8+
<link rel="stylesheet" href="assets/site.css">
9+
</head>
10+
<body>
11+
<header class="topbar">
12+
<a class="brand" href="?file=README.md">
13+
<img class="python-logo" src="https://www.python.org/static/community_logos/python-logo-only.svg" alt="Python logo">
14+
<span>Python Basic</span>
15+
</a>
16+
<nav aria-label="Main navigation">
17+
<a href="?file=COURSE_MAP.md">Course map</a>
18+
<a href="?file=projects/README.md">Projects</a>
19+
<a href="?file=interview-problems/README.md">Interview practice</a>
20+
</nav>
21+
</header>
22+
23+
<div class="layout">
24+
<aside class="sidebar" aria-label="Course chapters">
25+
<p class="sidebar-title">Learn Python</p>
26+
<a href="?file=00-setup/README.md">00. Setup</a>
27+
<a href="?file=01-python-fundamentals/lesson.md">01. Fundamentals</a>
28+
<a href="?file=02-variables-and-data-types/lesson.md">02. Data types</a>
29+
<a href="?file=03-type-conversion/lesson.md">03. Type conversion</a>
30+
<a href="?file=04-operators/lesson.md">04. Operators</a>
31+
<a href="?file=05-input-and-output/lesson.md">05. Input and output</a>
32+
<a href="?file=06-control-flow/lesson.md">06. Control flow</a>
33+
<a href="?file=07-strings/lesson.md">07. Strings</a>
34+
<a href="?file=08-lists-and-tuples/lesson.md">08. Lists and tuples</a>
35+
<a href="?file=09-sets-and-dictionaries/lesson.md">09. Sets and dictionaries</a>
36+
<a href="?file=10-functions/lesson.md">10. Functions</a>
37+
<a href="?file=11-file-handling/lesson.md">11. File handling</a>
38+
<a href="?file=12-exception-handling/lesson.md">12. Exceptions</a>
39+
<a href="?file=13-modules-and-packages/lesson.md">13. Modules and packages</a>
40+
</aside>
41+
42+
<main id="content" class="content" tabindex="-1">
43+
<div class="loading">Loading the course...</div>
44+
</main>
45+
</div>
46+
47+
<footer class="footer">Python Basic · Learn slowly, practise often, build confidently.</footer>
48+
49+
<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
50+
<script src="assets/site.js"></script>
51+
</body>
52+
</html>

0 commit comments

Comments
 (0)