Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
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
116 changes: 115 additions & 1 deletion .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,15 @@ jobs:
- name: Cache cargo registry and target
uses: Swatinem/rust-cache@v2

- name: Install Node.js
uses: actions/setup-node@v4
with:
node-version: "20"
cache: "npm"

- name: Install npm dependencies (UnoCSS)
run: npm ci

- name: Install Trunk
run: |
wget -qO- https://github.com/trunk-rs/trunk/releases/download/v0.21.14/trunk-x86_64-unknown-linux-gnu.tar.gz \
Expand Down Expand Up @@ -195,10 +204,115 @@ jobs:
fi
}
check 'odp-*_bg.wasm' 'wasm' 230
check 'tailwind-*.css' 'tailwind CSS' 10
check 'base-*.css' 'base CSS' 5
check 'uno.generated-*.css' 'UnoCSS bundle' 10
check 'repo_graph.css' 'repo_graph CSS' 2
check 'odp-*.js' 'wasm-bindgen JS' 20
if [ "$fail" -ne 0 ]; then
echo "::error::One or more assets exceeded their size budget."
exit 1
fi

- name: Critical icon classes present
# UnoCSS preset-icons silently emits nothing when an icon class
# cannot be resolved (missing iconify pack, typo, etc.), which
# would ship a working build with invisible buttons. Assert that
# the icons we actually rely on made it into the generated CSS.
run: |
set -euo pipefail
css=$(ls dist/uno.generated-*.css | head -n1)
required="i-lucide-moon i-lucide-sun i-lucide-menu i-lucide-x i-lucide-arrow-right i-lucide-github i-lucide-play"
missing=""
for cls in $required; do
grep -qF ".$cls" "$css" || missing="$missing $cls"
done
if [ -n "$missing" ]; then
echo "::error::UnoCSS did not emit rules for:$missing"
echo "::error::Likely cause: missing iconify pack in node_modules (run 'npm ci'), or class typo in src/."
exit 1
fi
echo "OK: all required icon utilities present in $css"

lighthouse:
name: Lighthouse (mobile, soft)
runs-on: ubuntu-latest
timeout-minutes: 15
# Soft mode: this job MUST NOT block PR merges. It exists to
# surface regressions in performance / accessibility / SEO / best
# practices, not to gate them. Once scores stabilize we'll flip
# to strict assertions in a follow-up.
continue-on-error: true
steps:
- uses: actions/checkout@v4

- name: Install nightly Rust
uses: dtolnay/rust-toolchain@nightly
with:
targets: wasm32-unknown-unknown

- name: Cache cargo registry and target
uses: Swatinem/rust-cache@v2
with:
key: lighthouse-build

- name: Install Node.js
uses: actions/setup-node@v4
with:
node-version: "20"
cache: "npm"

- name: Install npm dependencies (UnoCSS)
run: npm ci

- name: Install Trunk
run: |
wget -qO- https://github.com/trunk-rs/trunk/releases/download/v0.21.14/trunk-x86_64-unknown-linux-gnu.tar.gz \
| tar -xzf- -C /usr/local/bin

- name: Build with Trunk
run: trunk build --release

- name: Install Lighthouse CI
# ubuntu-latest ships Google Chrome; @lhci/cli discovers it
# automatically. Pin to the 0.14.x line for stability.
run: npm install --no-save @lhci/cli@0.14.x

- name: Run Lighthouse CI (soft)
# `|| true` belts `continue-on-error`'s suspenders: a transient
# lhci failure (Chrome crash, port collision) still leaves the
# job green so we always reach the summary + artifact steps.
run: npx lhci autorun --config=lighthouserc.json || true

- name: Summarize scores
# Extract median category scores from each Lighthouse report
# and post a compact table to the workflow run summary so
# reviewers don't have to download the artifact for the
# at-a-glance number.
run: |
set -euo pipefail
shopt -s nullglob
files=(lhci-reports/lhr-*.json)
if [ ${#files[@]} -eq 0 ]; then
echo "::warning::No Lighthouse reports were produced."
exit 0
fi
{
echo "| URL | Perf | A11y | Best | SEO |"
echo "|---|---|---|---|---|"
for f in "${files[@]}"; do
node -e "
const r = require('./$f');
const c = r.categories;
const pct = k => Math.round(c[k].score * 100);
console.log(\`| \${r.finalUrl} | \${pct('performance')} | \${pct('accessibility')} | \${pct('best-practices')} | \${pct('seo')} |\`);
"
done
} | tee -a "$GITHUB_STEP_SUMMARY"

- name: Upload Lighthouse reports
if: always()
uses: actions/upload-artifact@v4
with:
name: lighthouse-reports
path: lhci-reports/
retention-days: 14
9 changes: 9 additions & 0 deletions .github/workflows/cloudflare-pages-deploy.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,15 @@ jobs:
# - name: Download and install tailwindcss binary
# run: npm install -D tailwindcss && npx tailwindcss -i <INPUT/PATH.css> -o <OUTPUT/PATH.css> # run tailwind

- name: Install Node.js
uses: actions/setup-node@v4
with:
node-version: "20"
cache: "npm"

- name: Install npm dependencies (UnoCSS)
run: npm ci

- name: Download and install Trunk binary
run: wget -qO- https://github.com/trunk-rs/trunk/releases/download/v0.21.14/trunk-x86_64-unknown-linux-gnu.tar.gz | tar -xzf-

Expand Down
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,8 @@
/target
/dist/

# UnoCSS pipeline -- generated stylesheet and Node tooling are not
# committed; consumers run `npm install` once and `trunk build` after.
/node_modules/
/style/uno.generated.css

45 changes: 45 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,14 @@ console_error_panic_hook = "0.1.7"
leptos = { version = "0.8.2", features = ["csr"] }
leptos_meta = "0.8.2"
leptos_router = "0.8.2"
unocss-classes = "2"
wasm-bindgen = "0.2.100"
# All the web-sys features we use directly (Window, Document, Console)
# are already enabled transitively by leptos's `csr` feature, so we
# don't need to opt into them again here. We still depend on web-sys
# directly for the `web_sys::js_sys` re-export and `web_sys::window()`
# in `repo_view.rs`.
web-sys = "0.3.77"
web-sys = { version = "0.3.77", features = ["Storage", "MediaQueryList"] }

[dev-dependencies]
js-sys = "0.3"
Expand Down
130 changes: 130 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
# OpenDevicePartnership.github.io

Website for the Open Device Partnership, built with Rust, Leptos, and Trunk.

## Prerequisites

Install these once on your machine:

1. **Rust** (nightly toolchain) — [https://rustup.rs/](https://rustup.rs/)

```cmd
rustup toolchain install nightly
rustup default nightly
Comment on lines +9 to +13
```

2. **WebAssembly target**

```cmd
rustup target add wasm32-unknown-unknown
```

3. **Trunk** — bundles the Rust → WASM app and serves it.

```cmd
cargo binstall trunk
:: or
cargo install trunk
```

4. **Node.js 20+** — needed by the UnoCSS pipeline that Trunk invokes as a
pre-build hook (see `Trunk.toml [[hooks]]`). Install from
[https://nodejs.org/](https://nodejs.org/) or via your package manager.

## First-time setup

After cloning, install the JavaScript dependencies that UnoCSS needs:

```cmd
npm ci
```

> **Important:** use `npm ci` (not `npm install`) so the lockfile is honored
> exactly. The `@iconify-json/lucide` package is required for every icon on
> the site (theme toggle, mobile menu, card arrows, etc.). If it is missing,
> UnoCSS silently emits no CSS for icon utilities and buttons appear empty
> with **no build error**. CI guards against this with an explicit
> "Critical icon classes present" check, but locally you must keep
> `node_modules/` in sync with `package-lock.json`.

If you ever see invisible icons or hit `i-lucide-*` classes that don't
render, the fix is almost always:

```cmd
npm ci
trunk build
```

## Development

Run the dev server:

```cmd
trunk serve
```

This will:

- Run the UnoCSS pre-build hook (`npm run build:css`) to regenerate
`style/uno.generated.css` from `src/**/*.rs` and `index.html`
- Build the project in debug mode
- Start a development server at <http://127.0.0.1:3000>
- Watch for file changes and auto-reload the browser

If you are editing CSS classes heavily and want a tighter loop, run the
UnoCSS watcher alongside `trunk serve` in a second terminal:

```cmd
npm run watch:css
```

## Production build

```cmd
trunk build --release
```

The optimized output is written to `dist/`. This is exactly what the
Cloudflare Pages deploy workflow runs.

## Tests and lint

```cmd
cargo test --all-targets
cargo fmt --all -- --check
cargo clippy --target wasm32-unknown-unknown --all-targets -- -D warnings
leptosfmt --check src
```

Browser-side tests (requires `wasm-pack` and Firefox):

```cmd
wasm-pack test --headless --firefox --test wasm
```

## Project structure

- `src/` — Rust source code
- `components/` — reusable UI components
- `pages/` — page components
- `data/` — content modules (projects, announcements, etc.)
- `style/` — CSS files
- `base.css` — design tokens and reset (single source of truth for colors,
type, spacing). Uses `color-scheme: light dark` + `light-dark()` so
each token is defined once and the active theme is chosen automatically.
- `repo_graph.css` — styles for the lazy-loaded D3 dependency graph.
- `uno.generated.css` — generated by UnoCSS; do not edit by hand.
- `public/` — static assets (images, fonts).
- `index.html` — main HTML template (loaded by Trunk).
- `Trunk.toml` — Trunk configuration; declares the `npm run build:css`
pre-build hook.
- `unocss.config.ts` — UnoCSS configuration; declares the icon presets,
design-token aliases, and scan globs.
- `package.json` / `package-lock.json` — UnoCSS + iconify dependencies.
- `Cargo.toml` — Rust dependencies.

## Technology stack

- **Leptos** — reactive web framework for Rust (CSR build)
- **Trunk** — WASM web application bundler
- **UnoCSS** — atomic CSS engine (Wind3 preset + iconify lucide icons)
Loading
Loading