✦
Next Assignment
Up next
Learn it.
Build it.
Use it.
Coursework
Choose where you want to work.
Build the knowledge, systems, and habits to become stronger in modern office, operations, and business-support roles.
Your eight-week business operations learning journey
This track now uses Nextra itself as the project. You will learn the web stack, then the modular folder structure, data-driven interfaces, browser state, PWA caching, Supabase, SQL security, and Cloudflare Pages deployment.
HTMLStructure and meaningCSSLayout and visual systemJavaScriptBehavior and stateSQL + SupabaseCloud data and access rulesStart with the anatomy of a web page.
These controls update CSS custom properties live. This is the same design-token concept used by Nextra's theme engine in css/app.css and js/core.js.
Browse Nextra the same way you would browse a real codebase: by folder and module. Expand a folder, open a file, then click any source line to see which Build Lab lesson explains that region.
Each visible region has an HTML structure, CSS rules, and often JavaScript behavior attached to it.
<body>Browser pageContains the app and scripts.<main>App shellShared wrapper around Nextra.<header> + <nav>NavigationBrand, Home/System links, autosave status..tab-pageApp screensHome, Coursework, Build Lab, Code Lab, Sync.#courseAssignmentsRendered from JavaScript data.#buildLessonsLessonsAlso rendered from data.localStorageBrowser memoryProgress and preferences.SupabaseCloud layerAuthentication and synced state.Each dropdown defines the important syntax and links to official documentation.
The browser begins with the document shell. The head contains metadata, fonts, the PWA manifest, and CSS. The body contains the visible app and JavaScript behavior.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Nextra — Career Learning</title>
</head>
<body>
<main>...</main>
<script>...</script>
</body>
</html>lang="en"Declares the document language.charset="utf-8"Selects UTF-8 text encoding.viewportControls mobile viewport scaling.<body>Contains the rendered page content.The app shell contains the shared header plus separate Coursework, Build Lab, Code Lab, and Sync sections. JavaScript toggles the active class so only one app page is visible at a time.
<main class="app-shell">
<header>...</header>
<section id="pageCoursework" class="tab-page active">...</section>
<section id="pageBuild" class="tab-page">...</section>
<section id="pageCode" class="tab-page">...</section>
<section id="pageSync" class="tab-page">...</section>
</main>idA unique element identifier.classA reusable styling/behavior hook.activeA state class used to show the selected page.<section>A semantic thematic region.Nextra uses setTab() as a small client-side router. It shows the requested screen, updates the browser URL with the History API, and restores the correct screen when Back or Forward is used.
function setTab(tab) {
page.classList.toggle("active", tab === "coursework");
buildPage.classList.toggle("active", tab === "build");
codePage.classList.toggle("active", tab === "code");
}functionDeclares reusable JavaScript logic.classList.toggle()Adds or removes a class based on a condition.onclickRuns JavaScript when a control is activated.DOMThe browser's object representation of the HTML document.Coursework uses CSS Grid for the main content and sidebar. Media queries collapse the grid on smaller screens, allowing the same HTML to work on desktop and mobile.
.coursework-layout {
display: grid;
grid-template-columns: minmax(0, 1fr) 286px;
gap: 14px;
}
@media (max-width: 1080px) {
.coursework-layout { grid-template-columns: 1fr; }
}display:gridCreates a Grid layout context.grid-template-columnsDefines the grid column tracks.minmax()Sets minimum and maximum track sizing.@mediaConditionally applies responsive CSS.The assignment cards are generated from JavaScript data rather than copied into HTML 32 times. render() reads assignment objects plus saved state, creates DOM nodes, and inserts them into the course container.
assignments.forEach(a => {
const card = document.createElement("article");
card.innerHTML = `<strong>${a.title}</strong>`;
course.appendChild(card);
});arrayAn ordered JavaScript collection.objectA set of named key/value properties.createElement()Creates a DOM element.template literalA backtick string supporting ${expression}.The theme system stores independent design tokens for the page background, foreground panels, and accent. JavaScript writes those values into CSS custom properties and derives readable supporting colors.
:root {
--user-background: #121014;
--user-panel: #cbc7cc;
--theme-accent: #d4479a;
}
.card { background: var(--user-panel); }--custom-propertyA reusable CSS variable.var()Reads a custom property.setProperty()Updates a CSS property from JavaScript.color-mix()Creates a color by mixing two inputs.Course progress, notes, due dates, and preferences are serialized to localStorage. That keeps state available after refreshes before cloud synchronization happens.
localStorage.setItem(
STORE,
JSON.stringify(state)
);
const restored = JSON.parse(
localStorage.getItem(STORE) || "{}"
);localStorageBrowser key/value storage for the current origin.JSON.stringify()Converts a JavaScript value to JSON text.JSON.parse()Converts JSON text back to JavaScript.originThe scheme/host/port boundary used by browser storage.Changes write to localStorage immediately. When signed in, a short debounce schedules cloud sync. syncNow() merges local and remote state, then upserts the result to Supabase.
function saveLocal() {
localStorage.setItem(STORE, JSON.stringify(state));
clearTimeout(saveDebounce);
saveDebounce = setTimeout(() => {
syncNow(false);
}, 650);
}debounceDelays repeated work until activity settles.setTimeout()Schedules a callback later.async / awaitSyntax for promise-based asynchronous work.upsertInsert a missing row or update an existing one.The manifest describes the installable app. The service worker caches the app shell and can answer requests from CacheStorage, helping the installed PWA load reliably.
self.addEventListener("install", event => {
event.waitUntil(
caches.open(CACHE).then(cache => cache.addAll(ASSETS))
);
});service workerA background browser worker.CacheStorageBrowser API for cached responses.manifest.jsonMetadata for an installable web app.fetch eventA network request intercepted by a service worker.Supabase stores course state in Postgres. The table contains a user_id, JSON state/preferences, and timestamps. RLS policies compare auth.uid() to user_id so each signed-in user can only access their own row.
create table public.course_state (
user_id uuid primary key
references auth.users(id),
state jsonb not null default '{}',
preferences jsonb not null default '{}'
);
alter table public.course_state
enable row level security;uuidA universally unique identifier.jsonbPostgreSQL JSON storage type.primary keyUniquely identifies a row.RLSRow Level Security.auth.uid()Current authenticated Supabase user UUID.The upload box receives File objects from the browser. Nextra stores the binary Blob in IndexedDB, keeps lightweight metadata in course state, and can optionally mirror the Blob into a private Supabase Storage bucket for cross-device downloads.
<input type="file" multiple>
const file = input.files[0];
await putWorkBlob({ blob: file });
const url =
URL.createObjectURL(file);
type="file"Creates a browser file picker.multipleAllows more than one selected file.File / BlobBrowser objects representing binary file data.IndexedDBBrowser database that can persist Blobs and structured objects.createObjectURL()Creates a temporary URL that can download or display a Blob.The learning drawer separates category-level navigation from page-level navigation. Career currently contains Business Operations. Coding contains Build Lab and Code Lab. Because the drawer is generated from LEARNING_AREAS, future tracks such as Python can be added to the Coding category without rebuilding the menu from scratch.
const LEARNING_AREAS = [
{
id: "coding",
pages: [
{ tab: "build" },
{ tab: "code" }
]
}
];
nested arrayPages are grouped inside a learning-area object.data-drawer-tabStores which app page a rendered menu button opens.aria-expandedCommunicates whether the drawer is open.Escape keyProvides keyboard dismissal for the side panel.The source-line selector highlights matching lessons here.
Open any term while reading the source.
<header>⌄Introductory or navigation content.
Official reference ↗<nav>⌄Navigation region.
Official reference ↗<main>⌄Dominant document content.
Official reference ↗<section>⌄Thematic section.
Official reference ↗<article>⌄Self-contained composition.
Official reference ↗<aside>⌄Related secondary content.
Official reference ↗<details>⌄Native expandable disclosure.
Official reference ↗<summary>⌄Clickable label for <details>.
Official reference ↗id⌄Unique element identifier.
Official reference ↗class⌄Reusable styling and behavior classes.
Official reference ↗aria-label⌄Accessible name for a control or region.
Official reference ↗data-*⌄Custom data stored on an HTML element.
Official reference ↗href⌄Navigation/resource target.
Official reference ↗type⌄Defines control/input behavior.
Official reference ↗value⌄Current/default form-control value.
Official reference ↗placeholder⌄Hint displayed in an empty form control.
Official reference ↗:root⌄Root pseudo-class, commonly used for global variables.
Official reference ↗--custom-property⌄Author-defined CSS variable.
Official reference ↗var()⌄Reads a CSS custom property.
Official reference ↗display:grid⌄Two-dimensional Grid layout.
Official reference ↗display:flex⌄One-dimensional Flexbox layout.
Official reference ↗@media⌄Conditional responsive CSS.
Official reference ↗::before / ::after⌄Generated pseudo-elements.
Official reference ↗!important⌄Raises declaration priority in the cascade.
Official reference ↗const / let⌄Block-scoped variable declarations.
Official reference ↗function⌄Reusable executable logic.
Official reference ↗getElementById()⌄Finds an element by id.
Official reference ↗querySelector()⌄Finds the first element matching a CSS selector.
Official reference ↗classList⌄Adds/removes/toggles classes.
Official reference ↗addEventListener()⌄Registers an event callback.
Official reference ↗async / await⌄Promise-based asynchronous control flow.
Official reference ↗localStorage⌄Persistent origin-scoped browser storage.
Official reference ↗fetch()⌄Promise-based network request API.
Official reference ↗CREATE TABLE⌄Creates a database table.
Official reference ↗uuid⌄UUID data type.
Official reference ↗jsonb⌄Binary JSON storage type.
Official reference ↗PRIMARY KEY⌄Uniquely identifies a row.
Official reference ↗RLS policy⌄Row-level database access rule.
Official reference ↗auth.uid()⌄Current authenticated user's UUID.
Official reference ↗Each dropdown represents a project layer. Expand a folder, choose a file, then inspect and search the real source Cloudflare is serving.
Your recovered high-school websites live directly in /websites/. Nextra catalogs them here while Cloudflare serves each recovered HTML file as its own real website.
nextra-learning.pages.dev/websites/project-name.html
.html file into /websites/.Example: /websites/web-design-final.html.websites/catalog.json.Enter a title, exact HTML filename, year, and optional description.If each project really contains all of its CSS and JavaScript inside one HTML file, it should load as-is. Only projects that reference external files need those extra files copied too.
Connect your Supabase account once per device, then your completed assignments, notes, and reminder preferences can sync through the cloud.
Your display name belongs to the Supabase account that is signed in. It follows that account to your other devices and is used for the welcome message on Home.
Once signed in, coursework, adjustable due dates, notes, Build Lab progress, reminders, and your personal color theme save locally immediately and sync to Supabase automatically. Each authenticated user keeps a separate course row, so multiple people can use the same published Cloudflare Pages app without sharing progress or theme settings. Manual sync is only a fallback.
Use this on both phone and desktop. The account fingerprint should match on both devices. Background checks are now read-only unless there is actually something new to save.
Do not clear its browser or PWA storage. Open that device first after deploying this version, make sure the account fingerprint matches your other device, then press Verify + merge now.
Your browser still keeps a local copy. Export a JSON backup periodically; restore merges the newest version of each assignment back into the app.