",
+ placement: "after",
+ type: "html",
+ path: "src/partials/navigation.html",
+ optional: true,
+ },
+ {
+ key: "",
+ placement: "before",
+ type: "string",
+ value: "",
+ optional: true,
+ },
+ {
+ key: "",
+ placement: "replace",
+ type: "html",
+ path: "src/partials/blink.html",
+ occurrence: "all",
+ optional: true,
+ },
+ {
+ key: "",
+ placement: "before",
+ type: "string",
+ value: "",
+ optional: true,
+ },
+];
diff --git a/block-01/week-01-the_web_under_the_hood/demo/src/style.css b/block-01/week-01-the_web_under_the_hood/demo/src/style.css
index 2d20f2a..2fcb849 100644
--- a/block-01/week-01-the_web_under_the_hood/demo/src/style.css
+++ b/block-01/week-01-the_web_under_the_hood/demo/src/style.css
@@ -23,10 +23,10 @@
@keyframes scanline {
from {
- transform: translateY(-100%);
+ background-position: 0 0;
}
to {
- transform: translateY(100vh);
+ background-position: 0 -10px;
}
}
@@ -62,6 +62,7 @@ body::before {
rgba(0, 0, 0, 0.18) 2px,
rgba(0, 0, 0, 0.18) 4px
);
+ animation: scanline 1s linear infinite;
}
/* vignette */
diff --git a/block-01/week-01-the_web_under_the_hood/demo/src/utils/inject.js b/block-01/week-01-the_web_under_the_hood/demo/src/utils/inject.js
new file mode 100644
index 0000000..da1fc1d
--- /dev/null
+++ b/block-01/week-01-the_web_under_the_hood/demo/src/utils/inject.js
@@ -0,0 +1,86 @@
+import fs from "fs/promises";
+import path from "path";
+// ─── Helpers ──────────────────────────────────────────────────────────────────
+function nthIndexOf(haystack, needle, n) {
+ let index = -1;
+ let remaining = n;
+ let searchFrom = 0;
+ while (remaining > 0) {
+ index = haystack.indexOf(needle, searchFrom);
+ if (index === -1)
+ return -1;
+ searchFrom = index + 1;
+ remaining--;
+ }
+ return index;
+}
+function applyInjection(html, content, markerIndex, markerLength, placement) {
+ switch (placement) {
+ case "before":
+ return html.slice(0, markerIndex) + content + html.slice(markerIndex);
+ case "after": {
+ const after = markerIndex + markerLength;
+ return html.slice(0, after) + content + html.slice(after);
+ }
+ case "replace":
+ return (html.slice(0, markerIndex) +
+ content +
+ html.slice(markerIndex + markerLength));
+ }
+}
+// ─── Core ─────────────────────────────────────────────────────────────────────
+export async function resolveContent(injection) {
+ if (injection.type === "html") {
+ try {
+ return await fs.readFile(path.resolve(injection.path), "utf-8");
+ }
+ catch (err) {
+ const message = err instanceof Error ? err.message : String(err);
+ throw new Error(`[inject] Failed to read "${injection.path}": ${message}`);
+ }
+ }
+ return injection.value;
+}
+export async function injectIntoHtml(html, injections, options = {}) {
+ const contents = await Promise.all(injections.map(resolveContent));
+ for (let i = 0; i < injections.length; i++) {
+ const injection = injections[i];
+ const content = contents[i];
+ const occurrence = injection.occurrence ?? 1;
+ const handleMissing = () => {
+ if (injection.optional)
+ return;
+ if (options.onMissing) {
+ options.onMissing(injection.key, occurrence);
+ }
+ else {
+ throw new Error(`[inject] Marker "${injection.key}" (occurrence: ${occurrence}) not found.`);
+ }
+ };
+ if (occurrence === "all") {
+ const indices = [];
+ let searchFrom = 0;
+ let idx;
+ while ((idx = html.indexOf(injection.key, searchFrom)) !== -1) {
+ indices.push(idx);
+ searchFrom = idx + 1;
+ }
+ if (indices.length === 0) {
+ handleMissing();
+ continue;
+ }
+ for (let j = indices.length - 1; j >= 0; j--) {
+ html = applyInjection(html, content, indices[j], injection.key.length, injection.placement);
+ }
+ }
+ else {
+ const markerIndex = nthIndexOf(html, injection.key, occurrence);
+ if (markerIndex === -1) {
+ handleMissing();
+ continue;
+ }
+ html = applyInjection(html, content, markerIndex, injection.key.length, injection.placement);
+ }
+ }
+ return html;
+}
diff --git a/block-01/week-02-html_and_the_dom/README.md b/block-01/week-02-html_and_the_dom/README.md
new file mode 100644
index 0000000..92dbf32
--- /dev/null
+++ b/block-01/week-02-html_and_the_dom/README.md
@@ -0,0 +1,18 @@
+# Week 2 — HTML & the DOM
+
+## What is HTML?
+
+HTML (HyperText Markup Language) is the language of the web. It's a way to structure content on a page using tags. For example:
+
+```html
+
My First Heading
+
This is a paragraph.
+```
+
+This tells the browser to display a heading and a paragraph. HTML is not a programming language — it doesn't have logic or variables. It's a markup language that describes the structure of content.
+
+## The DOM — Document Object Model
+
+When the browser loads an HTML page, it parses the HTML and creates a tree-like structure called the **DOM** (Document Object Model). The DOM represents the page as a hierarchy of nodes, where each node corresponds to an element in the HTML. For example, the HTML above would create a DOM with a root node containing an `
` node and a `
` node.
+
+The DOM allows JavaScript to interact with the page. You can use JavaScript to read and modify the DOM, which is how you create dynamic web pages. For example, you could use JavaScript to change the text of the heading or add new paragraphs.
diff --git a/block-01/week-02-html_and_the_dom/demo/README.md b/block-01/week-02-html_and_the_dom/demo/README.md
new file mode 100644
index 0000000..e0aa2c7
--- /dev/null
+++ b/block-01/week-02-html_and_the_dom/demo/README.md
@@ -0,0 +1,8 @@
+# Demo — Login Form
+
+This demo is a simple static HTML page with a login form. It doesn't actually authenticate — it just shows how HTML looks and how to inspect it in the browser. Use this as a starting point to explore HTML structure and the DOM.
+
+## Setup
+
+1. Create a new file `index.html` with the following content:
+2. Open `index.html` in your browser
\ No newline at end of file
diff --git a/block-01/week-02-html_and_the_dom/demo/avatar.svg b/block-01/week-02-html_and_the_dom/demo/avatar.svg
new file mode 100644
index 0000000..5ab5153
--- /dev/null
+++ b/block-01/week-02-html_and_the_dom/demo/avatar.svg
@@ -0,0 +1,7 @@
+
+
+
diff --git a/block-01/week-02-html_and_the_dom/demo/bylaw-182.html b/block-01/week-02-html_and_the_dom/demo/bylaw-182.html
new file mode 100644
index 0000000..937f464
--- /dev/null
+++ b/block-01/week-02-html_and_the_dom/demo/bylaw-182.html
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+ ICC By-law 182.32
+
+
+
ICC By-law 182.32
+
+ All personnel must be cleared for deep-space operations before being
+ assigned to any vessel or station beyond the Sol system.
+
+ Manifest sealed under MU-TH-UR authority — unauthorised
+ amendments constitute breach of
+ ICC
+ statute 12.7-ALPHA.
+
+
+
+
+
+
+
+
+
+
+
Mission Debrief — Completion
+
+
Section A — Incident report
+
+
+
+
Section B — Specimen data
+
+
+
+
Section C — Crew psychological assessment
+
+
+
+
+
+
+ Complete all sections before
+ or your service contract
+ will be suspended.
+
+
+
+
+
+
+
+
+ ICC
+ Regulation Reference
+
+
+ Regulation ISCC By-law 182.32 requires all commercial vessels to
+ investigate signals of potential intelligent origin. Full text
+ rendered below via secure relay:
+
+
+
+
+
+
+
+
+
Emergency Protocols
+
+ Initiate shipwide alert or open the emergency channel below. All
+ actions are logged to MU-TH-UR.
+