Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 0 additions & 7 deletions .babelrc

This file was deleted.

24 changes: 4 additions & 20 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,30 +17,14 @@ jobs:
steps:
- uses: actions/checkout@v4

- uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'

- run: npm ci --legacy-peer-deps
- uses: oven-sh/setup-bun@v2

- name: Restore Gatsby cache
uses: actions/cache@v4
with:
path: |
.cache
public
key: gatsby-${{ runner.os }}-${{ hashFiles('package-lock.json') }}-${{ hashFiles('src/**') }}
restore-keys: |
gatsby-${{ runner.os }}-${{ hashFiles('package-lock.json') }}-
gatsby-${{ runner.os }}-
- run: bun install --frozen-lockfile

- name: Build
run: npm run build -- --prefix-paths
env:
NODE_OPTIONS: --max-old-space-size=4096
run: bun run build

- uses: peaceiris/actions-gh-pages@v4
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./public
publish_dir: ./dist
33 changes: 10 additions & 23 deletions .github/workflows/e2e.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,45 +15,32 @@ jobs:
steps:
- uses: actions/checkout@v4

- uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- uses: oven-sh/setup-bun@v2

- run: bun install --frozen-lockfile

- run: npm ci --legacy-peer-deps
- name: Lint
run: bun run lint

- name: Cache Playwright browsers
id: playwright-cache
uses: actions/cache@v4
with:
path: ~/.cache/ms-playwright
key: playwright-${{ runner.os }}-${{ hashFiles('package-lock.json') }}
key: playwright-${{ runner.os }}-${{ hashFiles('bun.lock') }}

- name: Install Playwright system dependencies
run: npx playwright install-deps chromium
run: bunx playwright install-deps chromium

- name: Install Playwright browser
if: steps.playwright-cache.outputs.cache-hit != 'true'
run: npx playwright install chromium

- name: Restore Gatsby cache
uses: actions/cache@v4
with:
path: |
.cache
public
key: gatsby-${{ runner.os }}-${{ hashFiles('package-lock.json') }}-${{ hashFiles('src/**') }}
restore-keys: |
gatsby-${{ runner.os }}-${{ hashFiles('package-lock.json') }}-
gatsby-${{ runner.os }}-
run: bunx playwright install chromium

- name: Build
run: npm run build -- --prefix-paths
env:
NODE_OPTIONS: --max-old-space-size=4096
run: bun run build

- name: Run E2E tests
run: npx playwright test
run: bunx playwright test

- name: Upload Playwright report
uses: actions/upload-artifact@v4
Expand Down
12 changes: 3 additions & 9 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,25 +6,19 @@ npm-debug.log*
# Dependency directories
node_modules

# Directory for distribution
# Build output
/dist

# Optional npm cache directory
.npm
# Astro generated types
.astro/

# OSX
.DS_Store

/tmp
/dist
/.cache
/build
/public

report.html

# Playwright
playwright-report/
test-results/


5 changes: 0 additions & 5 deletions .prettierrc

This file was deleted.

8 changes: 5 additions & 3 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@

## Project Overview

A frontend course built with Gatsby and reveal.js, aimed at taking low-to-mid level engineers to expert level. Covers JavaScript fundamentals, programming paradigms, and key libraries/frameworks.
A frontend course built with Astro (Vite), React islands, and reveal.js 5, aimed at taking low-to-mid level engineers to expert level. Covers JavaScript fundamentals, programming paradigms, and key libraries/frameworks. Bun is the runtime/package manager; Biome handles lint + format.

Content is written in Markdown under `src/md/`. Each file is a course chapter rendered as a reveal.js slideshow. The wiki (`src/md/`) is synced via git subtree to a separate GitHub wiki repo.

**Dev server:** `npm run dev` (Gatsby)
**Build:** `npm run build`
**Dev server:** `bun run dev` (Astro, serves under `/js-training`)
**Build:** `bun run build`
**Lint/format:** `bun run lint` / `bun run format` (Biome)
**E2E tests:** `bun run test` (Playwright)

## Content Structure

Expand Down
129 changes: 59 additions & 70 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,75 +2,79 @@

## Requirements

- Node 20 LTS — run `nvm use` at the project root (`.nvmrc` is set to `20`)
- npm 8+ (comes with Node 20)
- [Bun](https://bun.sh) 1.x — runtime and package manager
- Node 20+ (used by the Astro CLI and Playwright; `.nvmrc` is set to `20`)

## Local Development

```bash
npm install --legacy-peer-deps
npm run develop # starts dev server at http://localhost:8000
bun install
bun run dev # starts dev server at http://localhost:4321/js-training
```

The `--legacy-peer-deps` flag is required because `@atlaskit/navigation-next` declares a peer dep on React 16 and was abandoned before React 18 was released.

```bash
npm run build # production build → /public
npm run serve # serve /public locally
bun run build # production build → /dist
bun run serve # serve /dist locally
bun run lint # Biome lint + format check
bun run format # apply Biome fixes
bun run test # Playwright e2e tests
```

## Project Structure

```
/
├── gatsby-config.js # Gatsby plugins (Sass, image, manifest, gtag)
├── gatsby-node.ts # Page generation + webpack config
├── gatsby-browser.js # Client-side providers (NavigationProvider, etc.)
├── gatsby-ssr.js # SSR wrappers (minimal, Atlaskit is client-only)
├── astro.config.mjs # Astro config (base path, React, markdown pipeline)
├── biome.json # Biome lint + format config
├── playwright.config.ts # E2E test config
├── public/ # Static assets (images, favicon, manifest)
├── src/
│ ├── md/ # Markdown content (git subtree from wiki)
│ ├── components/ # React components
│ │ ├── layout/ # AppLayout, GlobalNav
│ │ ├── navigation/ # Navigation views, hooks, link items
│ │ ├── page-containers/ # MarkdownDocument, MarkdownSlideshow (Gatsby page templates)
│ │ ├── markdown/ # MarkdownDoc (react-markdown renderer)
│ │ ├── revealjs/ # RevealSlideshow + RevealMarkownSlides
│ │ ├── elements/ # Reusable buttons, cards
│ │ ├── hoc/ # Higher-order components (Priority, Auth, Domain)
│ │ └── root/ # RootWrapper, PageWrapper
│ ├── lib/
│ │ ├── config/ # firebase.js, reveal.js config, chapters.js
│ │ ├── mappers/ # MarkdownParser (slide splitting), markdown.ts (DTO → Chapter)
│ │ ├── user/Services/ # Auth services (Google, GitHub, SignOut)
│ │ ├── lectures/ # Chapter/slide services and repositories
│ │ ├── graphql-fragments/ # Shared GraphQL fragments
│ │ ├── index.js # Service factory (lazy Firebase loading)
│ │ └── pages.ts # Page generation logic called from gatsby-node.ts
│ ├── content.config.ts # Astro content collection over src/md
│ ├── pages/
│ │ ├── index.tsx # Home page
│ │ └── 404.tsx # 404 page
│ ├── mocks/
│ │ └── atlaskit-navigation-next.js # SSR-safe mock (aliased by webpack during build-html)
│ │ ├── index.astro # Home page
│ │ ├── docs/[slug].astro # Document pages
│ │ ├── slides/[slug].astro # Slideshow pages
│ │ └── 404.astro # 404 page
│ ├── layouts/
│ │ └── Base.astro # HTML shell (head, favicon, manifest)
│ ├── components/
│ │ ├── Sidebar.astro # Chapter navigation sidebar
│ │ ├── HomeCard.astro # Home page cards
│ │ ├── ScreenCornerLink.astro # Doc ⇄ slideshow corner toggle
│ │ ├── RevealDeck.tsx # Reveal.js 5 island (client only)
│ │ └── ThreeBackground.tsx # three.js homepage hero island
│ ├── lib/
│ │ ├── chapters.ts # Content collection → Chapter mapping
│ │ ├── slides.ts # Build-time slide markdown → HTML (unified + Shiki)
│ │ ├── paths.ts # withBase() helper for the /js-training base path
│ │ ├── remark-base-images.mjs # Prefixes /images/... with the base path
│ │ ├── config/ # reveal.ts config, chapters.js constants
│ │ └── mappers/ # MarkdownParser (slide splitting)
│ ├── packages/three-background/ # Legacy three.js scene (homepage hero)
│ ├── styles/
│ │ ├── global.scss # Base page styles
│ │ └── reveal/ # Custom Reveal.js theme (template + overrides)
│ ├── constants.ts # URL prefixes, chapter sections list
│ └── types.ts # TypeScript type definitions
└── static/ # Static assets (images, logo)
└── e2e/ # Playwright tests + page objects
```

## How Pages Are Generated

Each `.md` file in `src/md/` produces **two pages**:

| URL pattern | Template |
| ---------------------- | ------------------------------------------------------ |
| `/docs/<kebab-name>` | `src/components/page-containers/MarkdownDocument.tsx` |
| `/slides/<kebab-name>` | `src/components/page-containers/MarkdownSlideshow.tsx` |
| URL pattern | Template |
| ---------------------- | ----------------------------- |
| `/docs/<kebab-name>` | `src/pages/docs/[slug].astro` |
| `/slides/<kebab-name>` | `src/pages/slides/[slug].astro` |

**Flow:**

1. `gatsby-source-filesystem` picks up files from `src/md/`
2. `gatsby-transformer-remark` parses them into `MarkdownRemark` GraphQL nodes
3. `gatsby-node.ts → onCreateNode` adds `fields.path` (doc/slideshow URLs) and `fields.fileBasename`
4. `gatsby-node.ts → createPages` calls `src/lib/pages.ts → getPages()`, which queries GraphQL for all chapters and calls `createPage()` for each doc/slideshow pair
1. The `chapters` content collection (`src/content.config.ts`) globs `src/md/*.md`, keeping the raw file basename as the entry id
2. `src/lib/chapters.ts → getChapters()` maps entries to chapters (title from the first `# h1`; files without one, like `_Footer.md`, are skipped)
3. Both page templates call `getChapters()` in `getStaticPaths()` — the camelCase filename becomes the kebab-case slug
4. Documents render with Astro's built-in markdown pipeline; slides are split by `src/lib/mappers/MarkdownParser.ts` and rendered to HTML at build time by `src/lib/slides.ts`, then booted client side by the `RevealDeck` island

## Adding or Editing Content

Expand Down Expand Up @@ -136,17 +140,19 @@ Visible content.
Note: This text only appears in speaker view, not projected.
```

Open the speaker view with `S` while in a slideshow.

### Images

Place images in `static/images/` and reference them as `/images/my-image.png`.
Place images in `public/images/` and reference them as `/images/my-image.png`. The base path (`/js-training`) is prefixed automatically at build time.

### Registering a new chapter

New chapters are picked up automatically by Gatsby — just add the `.md` file. To add it to the **navigation sidebar**, register it in `src/constants.ts` under the appropriate section:
New chapters are picked up automatically — just add the `.md` file. To add it to the **navigation sidebar**, register it in `src/constants.ts` under the appropriate section:

```typescript
// src/constants.ts
export const SECTIONS = [
export const sections = [
{
title: 'JavaScript Syntax',
chapters: [
Expand All @@ -164,36 +170,19 @@ export const SECTIONS = [
`src/md/` is managed as a git subtree pointing to the `js-training.wiki` GitHub repository:

```bash
npm run wiki:pull # merge latest changes from the wiki into src/md/
npm run wiki:push # push changes in src/md/ back to the wiki
bun run wiki:pull # merge latest changes from the wiki into src/md/
bun run wiki:push # push changes in src/md/ back to the wiki
```

You can also edit markdown directly in `src/md/` and commit normally — the subtree just keeps the wiki in sync.

## Navigation Structure

The sidebar uses Atlaskit `navigation-next` with a three-view hierarchy:

```
Main view → Documents view → individual chapter
→ Slideshows view → individual chapter
```

Views are defined in:

- `src/components/navigation/views/mainNavigation.tsx` — top-level menu
- `src/components/providers/useChaptersNavigationView.tsx` — generates doc/slideshow views from the chapter list in `constants.ts`

The active view switches automatically based on the current URL path (handled in `src/components/layout/AppLayout.tsx`).

## SSR / Build Quirks

**`@atlaskit/navigation-next`** calls `localStorage` at module initialisation time, which breaks Gatsby's server-side rendering. During the `build-html` and `develop-html` webpack stages it is replaced with a no-op mock via a webpack alias configured in `gatsby-node.ts`. The full Atlaskit shell only runs in the browser (hydrated via `gatsby-browser.js`).
## Base Path

**Sass deprecations** — Reveal.js v3 ships legacy SCSS that triggers dart-sass warnings. These are suppressed via `silenceDeprecations` in `gatsby-config.js`. Do not remove that config unless Reveal.js is upgraded.
The site deploys to GitHub Pages under `/js-training` (`base` in `astro.config.mjs`). Astro does **not** prefix internal links automatically — always wrap internal hrefs with `withBase()` from `src/lib/paths.ts`. The dev and preview servers also serve under `/js-training`, so a missing prefix fails locally and in e2e, not just in production.

## Architecture Notes

- **Service factory** — `src/lib/index.js` exports a `JsTraining` class that lazy-loads Firebase and dynamically imports services on first use. This keeps Firebase out of the initial bundle.
- **Event bus** — `src/lib/bus.js` is a tiny `nanobus` instance used for auth state events between services and UI.
- **`MarkdownParser`** — `src/lib/mappers/MarkdownParser.ts` splits raw markdown into a 2D array of slides using the `<!--section-->` / `<!--slide-->` separators before passing them to Reveal.js.
- **`MarkdownParser`** — `src/lib/mappers/MarkdownParser.ts` splits raw markdown into a 2D array of slides using the `<!--section-->` / `<!--slide-->` separators. E2E slide ids (`data-slide-id`) come from it — change with care.
- **Build-time slide rendering** — `src/lib/slides.ts` converts each slide's markdown to HTML during the build (unified: remark-gfm + rehype-raw + Shiki). The browser only receives static markup; the `RevealDeck` island just initialises Reveal.js 5.
- **Reveal theme** — `src/styles/reveal/` compiles the reveal.js theme template with custom variables plus local overrides. Sass `@import` deprecation warnings from the template are silenced in `astro.config.mjs`.
- **three.js hero** — `src/packages/three-background/` is legacy code pinned to three 0.70, loaded lazily as a `client:idle` island (`ThreeBackground.tsx`). Candidate for a future port to current three.js.
Loading
Loading