Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
3d74aca
build(deps): upgrade nuxt to 4.6.2
omargfh Oct 22, 2026
25e96a9
fix(nuxt-core): transform #imports in node_modules
omargfh Oct 22, 2026
4f5a9e2
fix(nuxt-core): install peers for @nuxt/ui editor drag handle
omargfh Oct 22, 2026
92b8b92
fix(docs): skip version merge when versions.json is not an array
omargfh Oct 22, 2026
ecc1acd
build(deps): drop modules that pull in @nuxt/kit 3
omargfh Oct 22, 2026
a51deef
fix(docs,learn): render content without Nuxt UI prose components
omargfh Oct 22, 2026
99f0937
fix(learn,netlogo,nuxt-core): render MDC without Nuxt UI prose compon…
omargfh Oct 23, 2026
c1093bf
fix(nuxt-core): show primitive details in a hover popover
omargfh Oct 23, 2026
8ef4633
style(nuxt-core): open the primitive popover next to its trigger
omargfh Oct 23, 2026
c11e55b
style(learn): restore the table of contents top spacing
omargfh Oct 23, 2026
fc19620
fix(learn): query a resource by the requested name
omargfh Oct 23, 2026
f58d392
fix(learn): return 404 when an article does not exist
omargfh Oct 23, 2026
162504f
fix(docs): stop duplicating keywords in the website config
omargfh Oct 23, 2026
2331e5d
build(deps): bump @nuxt/content, @nuxt/image and @nuxt/hints
omargfh Oct 23, 2026
1bc6a05
chore(nuxt-core): sync package template dependencies with package.json
omargfh Oct 23, 2026
36604b6
build(deps): refresh browserslist, caniuse-lite and baseline-browser-…
omargfh Oct 23, 2026
ad19b7b
fix(nuxt-content-assets): prepare the playground before building
omargfh Oct 23, 2026
debb68f
fix(docs): list each page keyword once
omargfh Oct 23, 2026
b7d2f6b
build(docs): include the Spanish BehaviorSpace guide in the offline b…
omargfh Oct 23, 2026
c7e1f67
test: add e2e smoke tests for docs, learn and nettango
omargfh Oct 23, 2026
e86eb71
test(docs): test the normal, offline and PDF build artifacts
omargfh Oct 23, 2026
8033366
ci: build and test each app, and add a nightly PDF and full-route run
omargfh Oct 23, 2026
ddb50bd
fix(docs): scope the PDF title page styles to the title page
omargfh Oct 23, 2026
83758be
fix(docs): list each chapter of the PDF manual once
omargfh Oct 23, 2026
3ce860f
fix(docs): read PDF table of contents headings from the chapter HTML
omargfh Oct 23, 2026
5057f20
test(docs): check that every PDF table of contents entry links to a page
omargfh Oct 23, 2026
30b86ce
ci: drop the focused-test guard
omargfh Oct 23, 2026
8df9694
build(deps): register @nuxt/fonts 1.x instead of Nuxt UI's 0.14
omargfh Oct 23, 2026
41795dc
build(deps): bump nuxt-gtag to 5.0.0
omargfh Oct 23, 2026
32e58e4
chore(nuxt-content-assets): remove lockfiles left from the standalone…
omargfh Oct 23, 2026
f8dfa1d
build(deps): remove unused pdf-creator-node, npm-run-parallel and cha…
omargfh Oct 23, 2026
43c3dda
build(deps): re-resolve transitive dependencies with open advisories
omargfh Oct 23, 2026
45887a6
build(deps): bump sharp to 0.35.5 and pin fflate 0.7.5
omargfh Oct 23, 2026
5026a60
build(deps): move image-size to 2 and puppeteer to 25
omargfh Oct 23, 2026
72645bc
ci: serve built sites with a static server that resolves pages like t…
omargfh Oct 23, 2026
306f10d
test: allow deploy-only files in the docs smoke test
omargfh Oct 23, 2026
74c5d7d
fix(docs,learn): turn off token search in content search
omargfh Oct 23, 2026
0673fbb
fix(tailwind-config): keep code blocks inside list items styled as bl…
omargfh Oct 23, 2026
a7045f7
ci: run smoke tests through serve-static in one step
omargfh Oct 23, 2026
30c699d
build(deps): declare hastscript in @repo/markdown
omargfh Oct 23, 2026
5b5ebe3
build(deps): declare typescript, tsc-alias and eslint in @repo/common…
omargfh Oct 23, 2026
eafe8e6
build(deps): declare the packages that eslint configs import
omargfh Oct 23, 2026
f082afb
build(deps): declare source imports that resolved only through hoisting
omargfh Oct 23, 2026
df9b01e
fix(scripts): print every matching lockfile-at entry and read Berry l…
omargfh Oct 23, 2026
260a394
feat(scripts): add lock-parity to compare resolved versions of two lo…
omargfh Oct 23, 2026
fd6c9ba
fix(scripts): fail check-dupes and check-deps-health on unreadable ya…
omargfh Oct 23, 2026
9421e86
test(scripts): cover lockfile parsing, lock-parity and check-dupes wi…
omargfh Oct 23, 2026
bd601de
fix(scripts): stop killing other processes from repo scripts
omargfh Oct 23, 2026
239f801
test(scripts): test yn instead of the removed _read and isolate HELIO…
omargfh Oct 23, 2026
ba7894d
build(deps): use glob 13 in learn instead of the hoisted glob 7
omargfh Oct 23, 2026
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
46 changes: 41 additions & 5 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@ concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

env:
# Repo scripts prompt for confirmation unless they run headless.
HELIO_HEADLESS: "1"
NUXT_TELEMETRY_DISABLED: "1"

jobs:
validate:
name: Run ${{ matrix.command }}
Expand Down Expand Up @@ -36,16 +41,31 @@ jobs:
run: yarn ${{ matrix.command }}

test-builds:
name: Test Builds
name: Build and test ${{ matrix.app.name }}
runs-on: ubuntu-latest

strategy:
fail-fast: false
matrix:
app:
- name: docs
command: "yarn run nuxt:generate"
path: "./apps/docs"
path: ./apps/docs
build: yarn run nuxt:generate
artifact-test: tests/artifacts/normal.test.ts
e2e: true
- name: docs (static)
path: ./apps/docs
build: DOCS_ENV_STATIC=1 yarn run nuxt:generate
artifact-test: tests/artifacts/static.test.ts
e2e: false
- name: learn
path: ./apps/learn
build: yarn run nuxt:build
e2e: true
- name: nettango
path: ./apps/nettango
build: yarn run nuxt:build
e2e: true

steps:
- name: Checkout code
Expand All @@ -61,6 +81,22 @@ jobs:
run: |
yarn run init

- name: Build ${{ matrix.app.name }}
- name: Build
working-directory: ${{ matrix.app.path }}
run: ${{ matrix.app.build }}

- name: Test build output
if: ${{ matrix.app.artifact-test }}
working-directory: ${{ matrix.app.path }}
run: yarn run test:artifacts ${{ matrix.app.artifact-test }}

- name: Install Chromium
if: ${{ matrix.app.e2e }}
run: npx playwright-core install --with-deps chromium

- name: Smoke test against the built site
if: ${{ matrix.app.e2e }}
working-directory: ${{ matrix.app.path }}
run: ${{ matrix.app.command }}
# serve-static resolves pages like the production host (nuxt preview 404s on same-named directories),
# runs the tests once it is listening, and exits with their status.
run: node ../../packages/vitest-config/src/serve-static.mjs .output/public 4100 -- yarn run test:e2e
131 changes: 131 additions & 0 deletions .github/workflows/nightly.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
name: Nightly

# Slow checks that are too heavy for every push: the PDF manual and a smoke test of every route in each sitemap.
on:
schedule:
- cron: "0 7 * * *"
workflow_dispatch:

env:
HELIO_HEADLESS: "1"
NUXT_TELEMETRY_DISABLED: "1"

permissions:
actions: read
contents: read

jobs:
changes:
name: Check for new commits since the last nightly
runs-on: ubuntu-latest
outputs:
changed: ${{ steps.compare.outputs.changed }}
steps:
- name: Compare HEAD with the last successful nightly
id: compare
env:
GH_TOKEN: ${{ github.token }}
EVENT: ${{ github.event_name }}
HEAD_SHA: ${{ github.sha }}
REPO: ${{ github.repository }}
run: |
last=$(gh run list --repo "$REPO" --workflow nightly.yml --status success --limit 1 --json headSha --jq ".[0].headSha // empty")
echo "Last successful nightly: ${last:-none}, HEAD: $HEAD_SHA"
if [ "$EVENT" = "workflow_dispatch" ] || [ "$last" != "$HEAD_SHA" ]; then
echo "changed=true" >> "$GITHUB_OUTPUT"
else
echo "changed=false" >> "$GITHUB_OUTPUT"
echo "No new commits since the last successful nightly; skipping." >> "$GITHUB_STEP_SUMMARY"
fi

pdf-manual:
name: Build and test the PDF manual
needs: changes
if: ${{ needs.changes.outputs.changed == 'true' }}
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '24.22.1'
cache: "yarn"

- name: Initialize Repository
run: |
yarn run init

- name: Build the PDF manual
working-directory: ./apps/docs
env:
PORT: "3099"
run: yarn run docs:build-and-generate-manual

- name: Test the PDF manual
working-directory: ./apps/docs
run: yarn run test:artifacts tests/artifacts/pdf.test.ts

- name: Upload the PDF manual
if: ${{ always() }}
uses: actions/upload-artifact@v4
with:
name: NetLogo_User_Manual
path: apps/docs/.build/NetLogo_User_Manual.pdf
if-no-files-found: error

- name: Summarize the artifact
if: ${{ always() }}
working-directory: ./apps/docs
run: |
echo "### PDF manual" >> "$GITHUB_STEP_SUMMARY"
ls -la .build/NetLogo_User_Manual.pdf >> "$GITHUB_STEP_SUMMARY" 2>&1 || echo "PDF missing" >> "$GITHUB_STEP_SUMMARY"

all-routes:
name: Smoke test every route of ${{ matrix.app.name }}
needs: changes
if: ${{ needs.changes.outputs.changed == 'true' }}
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
app:
- name: docs
path: ./apps/docs
build: yarn run nuxt:generate
- name: learn
path: ./apps/learn
build: yarn run nuxt:build
- name: nettango
path: ./apps/nettango
build: yarn run nuxt:build

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '24.22.1'
cache: "yarn"

- name: Initialize Repository
run: |
yarn run init

- name: Build
working-directory: ${{ matrix.app.path }}
run: ${{ matrix.app.build }}

- name: Install Chromium
run: npx playwright-core install --with-deps chromium

- name: Smoke test every sitemap route
working-directory: ${{ matrix.app.path }}
env:
SMOKE_ALL_ROUTES: "1"
# serve-static resolves pages like the production host (nuxt preview 404s on same-named directories),
# runs the tests once it is listening, and exits with their status.
run: node ../../packages/vitest-config/src/serve-static.mjs .output/public 4100 -- yarn run test:e2e
2 changes: 2 additions & 0 deletions apps/docs/app/components/Search/Search.vue
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ const { data: files } = await useLazyAsyncData(
);

const fuseOptions: IFuseOptions<unknown> = {
// @nuxt/ui 4.12 turns on token search by default, which matches a page if any single word matches.
useTokenSearch: false,
ignoreDiacritics: true,
shouldSort: true,
threshold: 0,
Expand Down
2 changes: 1 addition & 1 deletion apps/docs/app/error.vue
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,6 @@ defineProps({

<template>
<ClientNavbar />
<ErrorDisplay :error-code="error.statusCode" :error-details="error.message" />
<ErrorDisplay :error-code="error.status ?? 500" :error-details="error.message" />
<ClientFooter />
</template>
10 changes: 5 additions & 5 deletions apps/docs/app/pages/[...slug].vue
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ const layoutComponent = computed(() => {
}
});

defineOgImageComponent('DocsSeo', {
defineOgImage('DocsSeo', {
title,
description,
theme: '#f31500',
Expand All @@ -66,8 +66,8 @@ useSeoMeta({
ogType: 'article',
title: `${title}`,
description: description,
keywords: keywords,
});
useHead({ meta: [{ name: 'keywords', content: keywords }] });

function isPageContent(item: ContentCollectionItem | null | undefined): item is ContentCollectionItem {
return item !== null && item !== undefined;
Expand Down Expand Up @@ -103,7 +103,7 @@ function resolveMeta(page: ContentCollectionItem): ResolvedMeta {

const title = [meta.title, seo.title, 'NetLogo Docs'].filter(Boolean).at(0)!;
const description = [meta.description, seo.description, 'NetLogo Documentation'].filter(Boolean).at(0)!;
const keywords = [meta.keywords, seo.keywords, 'NetLogo', 'Documentation'].filter(Boolean).flat().join(', ');
const keywords = [...new Set([meta.keywords, seo.keywords, 'NetLogo', 'Documentation'].filter(Boolean).flat())].join(', ');

const layout = meta.layout ?? 'default';

Expand All @@ -115,10 +115,10 @@ function resolveMeta(page: ContentCollectionItem): ResolvedMeta {
<!-- eslint-disable-next-line vue/no-multiple-template-root -->
<template v-if="page">
<component :is="layoutComponent.component" v-if="layoutComponent" v-bind="layoutComponent.props" class="main">
<ContentRenderer :value="page" tag="article" class="prose" />
<ContentRenderer :value="page" :prose="false" tag="article" class="prose" />
</component>

<ContentRenderer v-else :value="page" tag="main" class="prose min-h-screen" />
<ContentRenderer v-else :value="page" :prose="false" tag="main" class="prose min-h-screen" />
</template>
<ErrorDisplay v-else :error-code="404" error-details="The requested page could not be found." />
</template>
4 changes: 2 additions & 2 deletions apps/docs/app/pages/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -82,10 +82,10 @@ const beginnersLinks = ref(beginnersLinksData);
useSeoMeta({
title: productName,
description: productDescription,
keywords: productKeywords.join(', '),
});
useHead({ meta: [{ name: 'keywords', content: productKeywords.join(', ') }] });

defineOgImageComponent('DocsSeo', {
defineOgImage('DocsSeo', {
title: productName,
theme: '#f31500',
siteLogo: '/turtles.png',
Expand Down
5 changes: 5 additions & 0 deletions apps/docs/nuxt.config.static.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,11 @@ const staticOverrides: Parameters<DefineNuxtConfig>[0] = {
},

nitro: {
// The static link rewrite turns hrefs into relative .html paths, which the crawler does not follow,
// so pages reachable only through such a link have to be listed.
prerender: {
routes: ['/es/behaviorspace'],
},
hooks: {
async close() {
const cwd = '.output/public'
Expand Down
53 changes: 29 additions & 24 deletions apps/docs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,14 +31,16 @@
"lint": "eslint . --max-warnings 0",
"lint:fix": "eslint . --fix",
"node-version": "node -v && npm -v",
"turbo:postinstall": "nuxt prepare"
"turbo:postinstall": "nuxt prepare",
"test:e2e": "vitest run --project e2e",
"test:artifacts": "vitest run --project artifacts"
},
"dependencies": {
"@nuxt/content": "^3.7.1",
"@nuxt/content": "^3.16.2",
"@nuxt/eslint": "1.10.0",
"@nuxt/icon": "2.0.0",
"@nuxt/ui": "4.2.1",
"@nuxtjs/sitemap": "7.4.7",
"@nuxt/icon": "2.5.1",
"@nuxt/ui": "^4.12.0",
"@nuxtjs/sitemap": "9.1.0",
"@repo/eslint-config": "0.0.0",
"@repo/netlogo-docs": "0.0.0",
"@repo/nuxt-core": "0.0.0",
Expand All @@ -47,25 +49,25 @@
"@repo/typescript-config": "0.0.0",
"@repo/utils": "0.0.0",
"@repo/vue-ui": "1.0.0",
"@tailwindcss/postcss": "^4.1.13",
"@tailwindcss/vite": "^4.1.18",
"@vueuse/core": "^14.1.0",
"better-sqlite3": "^12.4.1",
"@tailwindcss/postcss": "^4.3.3",
"@tailwindcss/vite": "^4.3.3",
"@vueuse/core": "^14.4.0",
"better-sqlite3": "^12.11.1",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"eslint": "^9.31.0",
"minimatch": "^10.0.3",
"nuxt": "^4.1.2",
"nuxt-gtag": "4.1.0",
"nuxt-link-checker": "4.3.6",
"nuxt-og-image": "^5.1.12",
"nuxt-svgo": "4.2.6",
"reka-ui": "^2.6.0",
"nuxt": "4.6.2",
"nuxt-gtag": "5.0.0",
"nuxt-link-checker": "6.0.1",
"nuxt-og-image": "^7.0.7",
"nuxt-svgo": "5.3.0",
"reka-ui": "2.11.0",
"tailwind-merge": "^3.3.1",
"tailwindcss": "^4.1.18",
"tailwindcss": "^4.3.3",
"tw-animate-css": "^1.4.0",
"vue": "^3.5.24",
"vue-router": "^4.6.3",
"vue": "3.5.44",
"vue-router": "^5.4.0",
"yaml": "^2.8.1"
},
"devDependencies": {
Expand All @@ -82,24 +84,27 @@
"@iconify-json/si": "^1.2.11",
"@iconify-json/simple-icons": "^1.2.54",
"@iconify-json/streamline": "^1.2.5",
"@nuxt/kit": "^4.2.1",
"@nuxt/kit": "4.6.2",
"@repo/markdown": "0.0.0",
"@repo/nuxt-content-assets": "1.5.0",
"@types/html-minifier-terser": "^7.0.2",
"eslint-plugin-perfectionist": "^4.15.1",
"extend": "^3.0.2",
"fs-extra": "^11.3.0",
"fuse.js": "^7.1.0",
"fuse.js": "^7.5.0",
"html-minifier-terser": "^7.2.0",
"mupdf": "^1.27.0",
"pdf-creator-node": "^2.3.5",
"puppeteer": "^24.28.0",
"puppeteer": "^25.16.0",
"rehype-autolink-headings": "^7.1.0",
"remark-toc": "^9.0.0",
"sass": "^1.93.3",
"sharp": "^0.34.4",
"sharp": "^0.35.5",
"turbo-meta-utilities": "^1.0.1",
"typescript": "^5.4.0",
"zod": "^4.1.12"
"zod": "^4.1.12",
"@nuxt/test-utils": "^4.3.4",
"@repo/vitest-config": "0.0.0",
"playwright-core": "^1.60.0",
"vitest": "^4.0.16"
}
}
2 changes: 1 addition & 1 deletion apps/docs/runtime.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ const extraWebsiteConfig = z
versionsSrc: data.VERSIONS_SRC,
}));

// Only the docs-specific fields: nuxt-core already sets the shared ones, and layer merging concatenates arrays.
const websiteConfigSchema = rootWebsiteConfigSchema
.transform((data) => ({
...data,
productIsBeta: data.productVersion.toLowerCase().includes('beta'),
}))
.and(extraWebsiteConfig);
Expand Down
Loading
Loading