From e5729f996a0a2e3ceb7e0f420e1a1acdeab3194e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ramirez=20Vargas=2C=20Jos=C3=A9=20Pablo?= Date: Thu, 16 Jul 2026 16:39:45 -0600 Subject: [PATCH 1/5] chore: Add the www.collagejs.dev route explicitly --- wrangler.jsonc | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/wrangler.jsonc b/wrangler.jsonc index 32f8453..aa725ae 100644 --- a/wrangler.jsonc +++ b/wrangler.jsonc @@ -6,7 +6,10 @@ "nodejs_als" ], "compatibility_date": "2026-07-14", - "route": "*.collagejs.dev/*", + "routes": [ + "collagejs.dev/*", + "www.collagejs.dev/*" + ], "assets": { "binding": "ASSETS", "directory": ".svelte-kit/cloudflare" From ad15f892fdbd24dff220389c7c7916a7befe116e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ramirez=20Vargas=2C=20Jos=C3=A9=20Pablo?= Date: Thu, 16 Jul 2026 16:42:15 -0600 Subject: [PATCH 2/5] chore: Update packages --- package-lock.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/package-lock.json b/package-lock.json index 80196a5..2a575d4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2973,9 +2973,9 @@ "optional": true }, "node_modules/obug": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/obug/-/obug-2.1.3.tgz", - "integrity": "sha512-9miFgM2OFba7hB+pRgvtV84pYTBaoTHohvmIgiRt6dRIzbwEOIaNaP+dIlGs2fNFoB0SeISs0Jz5WFVRid6Xyg==", + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/obug/-/obug-2.1.4.tgz", + "integrity": "sha512-4a+OsYv9UktOJKE+l1A4OufDgdRF9PifWj+tJnHURo/P+WOxpG4GzUFL9qCalmWauao6ogiG+QvnCovwPoyAWA==", "dev": true, "funding": [ "https://github.com/sponsors/sxzz", @@ -3335,9 +3335,9 @@ } }, "node_modules/svelte": { - "version": "5.56.5", - "resolved": "https://registry.npmjs.org/svelte/-/svelte-5.56.5.tgz", - "integrity": "sha512-P03YJmUy2JoOxYHb4Ka3oFat1hq2ko2it1MOItSjsJ4B6WgZPLc3+RyyU+57OGWhs3Ieq74EJpZtSnNXdAGgDw==", + "version": "5.56.6", + "resolved": "https://registry.npmjs.org/svelte/-/svelte-5.56.6.tgz", + "integrity": "sha512-p4HDLDogGHKRKCrgckQHNs5PEfXkju6JI5jTywueaKJI5hAdjPohEhRtQ0M1SWC/+TA73SPln+r7srr+7e4nZA==", "license": "MIT", "dependencies": { "@jridgewell/remapping": "^2.3.4", From 19a99c52a291baf168aa4a25f8ec824228354967 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ramirez=20Vargas=2C=20Jos=C3=A9=20Pablo?= Date: Sat, 18 Jul 2026 13:11:12 -0600 Subject: [PATCH 3/5] feat: WIP - Basic setup - Navigation sidebar - Next/Preview navigation at the bottom - Footer - Under Construction for things not yet done --- package-lock.json | 220 ++++++++++++--- package.json | 2 + src/app.d.ts | 8 + src/lib/contexts.svelte.ts | 7 + src/lib/md-layouts/Blockquote.svelte | 21 ++ src/lib/md-layouts/Hr.svelte | 10 + src/lib/md-layouts/Li.svelte | 23 ++ src/lib/md-layouts/MdLayout.svelte | 51 ++++ src/lib/md-layouts/Ol.svelte | 15 + src/lib/md-layouts/headers/H1.svelte | 10 + src/lib/md-layouts/headers/H2.svelte | 10 + src/lib/md-layouts/headers/H3.svelte | 10 + src/lib/md-layouts/headers/H4.svelte | 10 + src/lib/md-layouts/headers/H5.svelte | 10 + src/lib/md-layouts/headers/H6.svelte | 10 + src/lib/md-layouts/headers/Header.svelte | 25 ++ src/lib/md-layouts/list-context.svelte.ts | 10 + src/routes/(docs-like)/+layout.svelte | 68 +++++ src/routes/(docs-like)/Footer.svelte | 16 ++ .../NavArticleButtons.svelte | 42 +++ .../PrimarySidebar/ArticleLink.svelte | 17 ++ .../PrimarySidebar/ArticlesContainer.svelte | 21 ++ .../PrimarySidebar/PrimarySidebar.svelte | 25 ++ .../(docs-like)/PrimarySidebar/Section.svelte | 36 +++ .../PrimarySidebar/context.svelte.ts | 8 + src/routes/(docs-like)/TopNav.svelte | 98 +++++++ src/routes/(docs-like)/api/+layout.svelte | 10 + .../(docs-like)/{docs => api}/+page.svelte | 0 .../(docs-like)/api/primary-sidebar.json | 1 + src/routes/(docs-like)/docs/+layout.svelte | 3 + src/routes/(docs-like)/docs/+page.md | 21 ++ .../(docs-like)/docs/[...slug]/+page.svelte | 8 + .../(docs-like)/docs/introduction/+page.md | 190 +++++++++++++ .../(docs-like)/docs/primary-sidebar.json | 108 ++++++++ .../(docs-like)/docs/project-types/+page.md | 262 ++++++++++++++++++ src/routes/(docs-like)/guides/+layout.svelte | 10 + .../+page.svelte | 0 .../(docs-like)/guides/primary-sidebar.json | 1 + src/routes/(docs-like)/utils.ts | 5 + src/routes/+layout.svelte | 25 +- src/routes/+page.svelte | 11 +- src/routes/Features/Features.svelte | 3 +- src/scss/_bs.scss | 18 ++ src/scss/app.scss | 29 ++ src/scss/code.css | 111 ++++++++ src/scss/md-content.css | 25 ++ src/types.ts | 11 + vite.config.ts | 22 +- 48 files changed, 1596 insertions(+), 61 deletions(-) create mode 100644 src/lib/contexts.svelte.ts create mode 100644 src/lib/md-layouts/Blockquote.svelte create mode 100644 src/lib/md-layouts/Hr.svelte create mode 100644 src/lib/md-layouts/Li.svelte create mode 100644 src/lib/md-layouts/MdLayout.svelte create mode 100644 src/lib/md-layouts/Ol.svelte create mode 100644 src/lib/md-layouts/headers/H1.svelte create mode 100644 src/lib/md-layouts/headers/H2.svelte create mode 100644 src/lib/md-layouts/headers/H3.svelte create mode 100644 src/lib/md-layouts/headers/H4.svelte create mode 100644 src/lib/md-layouts/headers/H5.svelte create mode 100644 src/lib/md-layouts/headers/H6.svelte create mode 100644 src/lib/md-layouts/headers/Header.svelte create mode 100644 src/lib/md-layouts/list-context.svelte.ts create mode 100644 src/routes/(docs-like)/+layout.svelte create mode 100644 src/routes/(docs-like)/Footer.svelte create mode 100644 src/routes/(docs-like)/NavArticleButtons/NavArticleButtons.svelte create mode 100644 src/routes/(docs-like)/PrimarySidebar/ArticleLink.svelte create mode 100644 src/routes/(docs-like)/PrimarySidebar/ArticlesContainer.svelte create mode 100644 src/routes/(docs-like)/PrimarySidebar/PrimarySidebar.svelte create mode 100644 src/routes/(docs-like)/PrimarySidebar/Section.svelte create mode 100644 src/routes/(docs-like)/PrimarySidebar/context.svelte.ts create mode 100644 src/routes/(docs-like)/TopNav.svelte create mode 100644 src/routes/(docs-like)/api/+layout.svelte rename src/routes/(docs-like)/{docs => api}/+page.svelte (100%) create mode 100644 src/routes/(docs-like)/api/primary-sidebar.json create mode 100644 src/routes/(docs-like)/docs/+page.md create mode 100644 src/routes/(docs-like)/docs/[...slug]/+page.svelte create mode 100644 src/routes/(docs-like)/docs/introduction/+page.md create mode 100644 src/routes/(docs-like)/docs/primary-sidebar.json create mode 100644 src/routes/(docs-like)/docs/project-types/+page.md create mode 100644 src/routes/(docs-like)/guides/+layout.svelte rename src/routes/(docs-like)/guides/{migration-from-single-spa => [...slug]}/+page.svelte (100%) create mode 100644 src/routes/(docs-like)/guides/primary-sidebar.json create mode 100644 src/routes/(docs-like)/utils.ts create mode 100644 src/scss/code.css create mode 100644 src/scss/md-content.css create mode 100644 src/types.ts diff --git a/package-lock.json b/package-lock.json index 2a575d4..c955cd9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -17,7 +17,9 @@ "@sveltejs/adapter-cloudflare": "^7.2.9", "@sveltejs/kit": "^2.63.0", "@sveltejs/vite-plugin-svelte": "^7.1.2", + "@types/node": "^26.1.1", "@vitest/browser-playwright": "^4.1.8", + "mdsvex": "^0.12.7", "playwright": "^1.60.0", "prettier": "^3.8.3", "prettier-plugin-svelte": "^4.1.0", @@ -64,9 +66,9 @@ } }, "node_modules/@cloudflare/workerd-darwin-64": { - "version": "1.20260710.1", - "resolved": "https://registry.npmjs.org/@cloudflare/workerd-darwin-64/-/workerd-darwin-64-1.20260710.1.tgz", - "integrity": "sha512-OqJl2eWF5+y9jarMm3YqqCTUe7Hd4ihogX5jyRU8iaAgOVyDr/Bk6aXpPCVUi1/MHzO93a18R/TmSTtzmB0sQw==", + "version": "1.20260714.1", + "resolved": "https://registry.npmjs.org/@cloudflare/workerd-darwin-64/-/workerd-darwin-64-1.20260714.1.tgz", + "integrity": "sha512-ZWXqAN8G7Cx9hMRQuk+59ziJhR3j1F4iO+Qs8aHdfKZ3Dq5Yi/57xvkJTgCGBnW1YU/L78r8f6HEy51bwbTpNw==", "cpu": [ "x64" ], @@ -81,9 +83,9 @@ } }, "node_modules/@cloudflare/workerd-darwin-arm64": { - "version": "1.20260710.1", - "resolved": "https://registry.npmjs.org/@cloudflare/workerd-darwin-arm64/-/workerd-darwin-arm64-1.20260710.1.tgz", - "integrity": "sha512-MYBqWgUblO+VlGvO73zYsH3hB9tdRj+yLyt5IHDFWryipb2l1efmNiWtAOkIhSRfypqLYGFrfpaDm2Hg00XVKw==", + "version": "1.20260714.1", + "resolved": "https://registry.npmjs.org/@cloudflare/workerd-darwin-arm64/-/workerd-darwin-arm64-1.20260714.1.tgz", + "integrity": "sha512-tueWxWC3wyCbMG6zRAxsMXX0YLgrRWbiAPYFQ2uJ7dUH8G+5E7UTWaQS9B1HdJ0bpKFW1NWxhs1o2noKVFSUYg==", "cpu": [ "arm64" ], @@ -98,9 +100,9 @@ } }, "node_modules/@cloudflare/workerd-linux-64": { - "version": "1.20260710.1", - "resolved": "https://registry.npmjs.org/@cloudflare/workerd-linux-64/-/workerd-linux-64-1.20260710.1.tgz", - "integrity": "sha512-lVWUgqI8qrkqvaCBGElu1kdaUFdAvaS2RD8K4qkCFP9hI3f5TCXumEs5qWSeZkvKum0+X/uJZ5hBFWsYI5SmoQ==", + "version": "1.20260714.1", + "resolved": "https://registry.npmjs.org/@cloudflare/workerd-linux-64/-/workerd-linux-64-1.20260714.1.tgz", + "integrity": "sha512-1VChTZRb0l0F7R4e1G5RtLKV4oFi6x+rQgxh2+yu887j3l/3TLgatuv1L8/5zhc9gKEhATTxOh0e52Rtd9dDWQ==", "cpu": [ "x64" ], @@ -115,9 +117,9 @@ } }, "node_modules/@cloudflare/workerd-linux-arm64": { - "version": "1.20260710.1", - "resolved": "https://registry.npmjs.org/@cloudflare/workerd-linux-arm64/-/workerd-linux-arm64-1.20260710.1.tgz", - "integrity": "sha512-kDwDPItBjAI4JL0df9Fma2N+Qggbm77IB/DnroAkEGQ79fpR80sYMyuB/ZQKyjEk9f48Ocq7HCCLq59qVSyNqA==", + "version": "1.20260714.1", + "resolved": "https://registry.npmjs.org/@cloudflare/workerd-linux-arm64/-/workerd-linux-arm64-1.20260714.1.tgz", + "integrity": "sha512-rMm3G+NirG2UdgHIRDdF1asNC6FqgIzZzkRG+VDhhDGcVxAQwvrMT1E38BivEvHr3G04MB4AfhcOczX0+GtRkQ==", "cpu": [ "arm64" ], @@ -132,9 +134,9 @@ } }, "node_modules/@cloudflare/workerd-windows-64": { - "version": "1.20260710.1", - "resolved": "https://registry.npmjs.org/@cloudflare/workerd-windows-64/-/workerd-windows-64-1.20260710.1.tgz", - "integrity": "sha512-GcLHy1oN1dfK6g1Z7UDV9f5xMGyTfPwcjWQ0sfWKH31IsoEVCRapnj3IC0PoIrDbnoo6irGPP0CwVs3WzdTajw==", + "version": "1.20260714.1", + "resolved": "https://registry.npmjs.org/@cloudflare/workerd-windows-64/-/workerd-windows-64-1.20260714.1.tgz", + "integrity": "sha512-cGqnU3Hg2YZS/k3SAqrMp1DjpdsyFde72tWltdl6ZT9+SFz/Zrk/8gyTU1TcxC4YApXeNVH5TyU5cOGPgUJ0pg==", "cpu": [ "x64" ], @@ -1238,9 +1240,9 @@ } }, "node_modules/@lucide/svelte": { - "version": "1.24.0", - "resolved": "https://registry.npmjs.org/@lucide/svelte/-/svelte-1.24.0.tgz", - "integrity": "sha512-yXwewA7ANQ5hfaSDrvsecosWjZn5RglzeXUZRSnxeANBskpNwblOkEJTqD0ujDdNKIKL8E9eVc2U/P3ziJr7OA==", + "version": "1.25.0", + "resolved": "https://registry.npmjs.org/@lucide/svelte/-/svelte-1.25.0.tgz", + "integrity": "sha512-v9m+dD68jxVnqkU3K59mG/RSRFlPGzmKCGSyMfnXcaGv9jODDQMyQkcp1CGvk3Y/cUj9v7f8rw1n//K0B53xGQ==", "license": "ISC", "peerDependencies": { "svelte": "^5" @@ -1977,9 +1979,9 @@ "license": "MIT OR Apache-2.0" }, "node_modules/@sveltejs/kit": { - "version": "2.69.3", - "resolved": "https://registry.npmjs.org/@sveltejs/kit/-/kit-2.69.3.tgz", - "integrity": "sha512-cphwqMRcE19/9VkrIPr5qZhQ0SptSSDfDzRUpYHu9OJDFGuYBFyJzK+KQA27wB4YG32O/yF2QjBkDmTyo0vtCw==", + "version": "2.70.0", + "resolved": "https://registry.npmjs.org/@sveltejs/kit/-/kit-2.70.0.tgz", + "integrity": "sha512-5pBnJwdNzxbrxp1TLK1NPMFF0Cx57iZUDKInznKcfifYR9m9poWfZI2Tfhw6BZIjYor5dXvcibt4EQgar3k6ww==", "dev": true, "license": "MIT", "dependencies": { @@ -2103,12 +2105,39 @@ "integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==", "license": "MIT" }, + "node_modules/@types/mdast": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.4.tgz", + "integrity": "sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "*" + } + }, + "node_modules/@types/node": { + "version": "26.1.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-26.1.1.tgz", + "integrity": "sha512-nxAkRSVkN1Y0JC1W8ky/fTfkGsMmcrRsbx+3XoZE+rMOX71kLYTV7fLXpqud1GpbpP5TuffXFqfX7fH2GgZREw==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~8.3.0" + } + }, "node_modules/@types/trusted-types": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz", "integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==", "license": "MIT" }, + "node_modules/@types/unist": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.11.tgz", + "integrity": "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==", + "dev": true, + "license": "MIT" + }, "node_modules/@vitest/browser": { "version": "4.1.10", "resolved": "https://registry.npmjs.org/@vitest/browser/-/browser-4.1.10.tgz", @@ -2883,17 +2912,35 @@ "@jridgewell/sourcemap-codec": "^1.5.5" } }, + "node_modules/mdsvex": { + "version": "0.12.7", + "resolved": "https://registry.npmjs.org/mdsvex/-/mdsvex-0.12.7.tgz", + "integrity": "sha512-gx4bReLCUvq+MPErHXYeyX+TEq1hsS2KfiZtEOMNTcbibSouFy8AHc5h04KbGCl+g5tLuo4/lbgRVYRnc7bJZw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.4", + "@types/unist": "^2.0.3", + "prism-svelte": "^0.4.7", + "prismjs": "^1.17.1", + "unist-util-visit": "^2.0.1", + "vfile-message": "^2.0.4" + }, + "peerDependencies": { + "svelte": "^3.56.0 || ^4.0.0 || ^5.0.0-next.120" + } + }, "node_modules/miniflare": { - "version": "4.20260710.0", - "resolved": "https://registry.npmjs.org/miniflare/-/miniflare-4.20260710.0.tgz", - "integrity": "sha512-x1LLRkU6o1p7hiKrB0TRnL0MJn6xFOT+/vrlEQINz5cRDKLP8ru4hBqWTIvXAetzr1acKAnmAaG84pQ4W/K14g==", + "version": "4.20260714.0", + "resolved": "https://registry.npmjs.org/miniflare/-/miniflare-4.20260714.0.tgz", + "integrity": "sha512-MYlTCLdWCPqvrYY2uLwOjXwmglXuiHE3TGGkbOW4BwjUPa1r07E0iuHwrNDIs/sxK21r+o90Jx58AV2KeNdJZw==", "dev": true, "license": "MIT", "dependencies": { "@cspotcode/source-map-support": "0.8.1", "sharp": "0.34.5", "undici": "7.28.0", - "workerd": "1.20260710.1", + "workerd": "1.20260714.1", "ws": "8.21.0", "youch": "4.1.0-beta.10" }, @@ -3121,6 +3168,23 @@ "svelte": "^5.0.0" } }, + "node_modules/prism-svelte": { + "version": "0.4.7", + "resolved": "https://registry.npmjs.org/prism-svelte/-/prism-svelte-0.4.7.tgz", + "integrity": "sha512-yABh19CYbM24V7aS7TuPYRNMqthxwbvx6FF/Rw920YbyBWO3tnyPIqRMgHuSVsLmuHkkBS1Akyof463FVdkeDQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/prismjs": { + "version": "1.30.0", + "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.30.0.tgz", + "integrity": "sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/readdirp": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-5.0.0.tgz", @@ -3502,6 +3566,13 @@ "node": ">=20.18.1" } }, + "node_modules/undici-types": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-8.3.0.tgz", + "integrity": "sha512-j375ScV60dom+YkPFIfTLcOiPxkN/buHz5GobjLhixFuANaNs3C9l4GmrWqejgXWJ7BbJcFYpTEUkS1Ge8bpZQ==", + "dev": true, + "license": "MIT" + }, "node_modules/unenv": { "version": "2.0.0-rc.24", "resolved": "https://registry.npmjs.org/unenv/-/unenv-2.0.0-rc.24.tgz", @@ -3512,6 +3583,77 @@ "pathe": "^2.0.3" } }, + "node_modules/unist-util-is": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-4.1.0.tgz", + "integrity": "sha512-ZOQSsnce92GrxSqlnEEseX0gi7GH9zTJZ0p9dtu87WRb/37mMPO2Ilx1s/t9vBHrFhbgweUwb+t7cIn5dxPhZg==", + "dev": true, + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-stringify-position": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-2.0.3.tgz", + "integrity": "sha512-3faScn5I+hy9VleOq/qNbAd6pAx7iH5jYBMS9I1HgQVijz/4mv5Bvw5iw1sC/90CODiKo81G/ps8AJrISn687g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "^2.0.2" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-2.0.3.tgz", + "integrity": "sha512-iJ4/RczbJMkD0712mGktuGpm/U4By4FfDonL7N/9tATGIF4imikjOuagyMY53tnZq3NP6BcmlrHhEKAfGWjh7Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "^2.0.0", + "unist-util-is": "^4.0.0", + "unist-util-visit-parents": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit-parents": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-3.1.1.tgz", + "integrity": "sha512-1KROIZWo6bcMrZEwiH2UrXDyalAa0uqzWCxCJj6lPOvTve2WkfgCytoDTPaMnodXh1WrXOq0haVYHj99ynJlsg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "^2.0.0", + "unist-util-is": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/vfile-message": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-2.0.4.tgz", + "integrity": "sha512-DjssxRGkMvifUOJre00juHoP9DPWuzjxKuMDrhNbk2TdaYYBNMStsNhEOt3idrtI12VQYM/1+iM0KOzXi4pxwQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "^2.0.0", + "unist-util-stringify-position": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/vite": { "version": "8.1.5", "resolved": "https://registry.npmjs.org/vite/-/vite-8.1.5.tgz", @@ -3750,9 +3892,9 @@ } }, "node_modules/workerd": { - "version": "1.20260710.1", - "resolved": "https://registry.npmjs.org/workerd/-/workerd-1.20260710.1.tgz", - "integrity": "sha512-U2sBPPrb9U97sBKnnMN6Kv8p65903P35nwMkPE9vSH/bRuRqkZ3a1EjUw3jV28RhiyXpkLF77Evzw8XimFxyTw==", + "version": "1.20260714.1", + "resolved": "https://registry.npmjs.org/workerd/-/workerd-1.20260714.1.tgz", + "integrity": "sha512-oIbQzfdyl9UQUnG6XLegcSq0Mgt/7WKDbFOoqGgOWCS+/fhyGB460uKEgdAQQ9RHCO/ttcNCX/KiMIQzdoeu3Q==", "dev": true, "hasInstallScript": true, "license": "Apache-2.0", @@ -3763,11 +3905,11 @@ "node": ">=16" }, "optionalDependencies": { - "@cloudflare/workerd-darwin-64": "1.20260710.1", - "@cloudflare/workerd-darwin-arm64": "1.20260710.1", - "@cloudflare/workerd-linux-64": "1.20260710.1", - "@cloudflare/workerd-linux-arm64": "1.20260710.1", - "@cloudflare/workerd-windows-64": "1.20260710.1" + "@cloudflare/workerd-darwin-64": "1.20260714.1", + "@cloudflare/workerd-darwin-arm64": "1.20260714.1", + "@cloudflare/workerd-linux-64": "1.20260714.1", + "@cloudflare/workerd-linux-arm64": "1.20260714.1", + "@cloudflare/workerd-windows-64": "1.20260714.1" } }, "node_modules/worktop": { @@ -3785,9 +3927,9 @@ } }, "node_modules/wrangler": { - "version": "4.111.0", - "resolved": "https://registry.npmjs.org/wrangler/-/wrangler-4.111.0.tgz", - "integrity": "sha512-bffpI9EyrnpKkF/1S+RaIv8oRD93GtbsA7TlfWwOsGJGB7VO3jVbdGzpC9TU7Bqom3z7jUxcte4Z9MPhaQ4HoQ==", + "version": "4.112.0", + "resolved": "https://registry.npmjs.org/wrangler/-/wrangler-4.112.0.tgz", + "integrity": "sha512-5H+XUD0TySCv1LuktFHDIEOkboH2nTfQs+35L+USt3MtntjDTMVIJprLgQcL2WBjulOyjxpd1vyTiSTJVW5MjQ==", "dev": true, "license": "MIT OR Apache-2.0", "dependencies": { @@ -3795,10 +3937,10 @@ "@cloudflare/unenv-preset": "2.16.1", "blake3-wasm": "2.1.5", "esbuild": "0.28.1", - "miniflare": "4.20260710.0", + "miniflare": "4.20260714.0", "path-to-regexp": "6.3.0", "unenv": "2.0.0-rc.24", - "workerd": "1.20260710.1" + "workerd": "1.20260714.1" }, "bin": { "cf-wrangler": "bin/cf-wrangler.js", @@ -3812,7 +3954,7 @@ "fsevents": "2.3.3" }, "peerDependencies": { - "@cloudflare/workers-types": "^5.20260710.1" + "@cloudflare/workers-types": "^5.20260714.1" }, "peerDependenciesMeta": { "@cloudflare/workers-types": { diff --git a/package.json b/package.json index beae436..7dfffe5 100644 --- a/package.json +++ b/package.json @@ -21,7 +21,9 @@ "@sveltejs/adapter-cloudflare": "^7.2.9", "@sveltejs/kit": "^2.63.0", "@sveltejs/vite-plugin-svelte": "^7.1.2", + "@types/node": "^26.1.1", "@vitest/browser-playwright": "^4.1.8", + "mdsvex": "^0.12.7", "playwright": "^1.60.0", "prettier": "^3.8.3", "prettier-plugin-svelte": "^4.1.0", diff --git a/src/app.d.ts b/src/app.d.ts index da08e6d..205bf3b 100644 --- a/src/app.d.ts +++ b/src/app.d.ts @@ -10,4 +10,12 @@ declare global { } } +declare module '*.md' { + import type { SvelteComponent } from 'svelte' + + export default class Comp extends SvelteComponent{} + + export const metadata: Record +} + export {}; diff --git a/src/lib/contexts.svelte.ts b/src/lib/contexts.svelte.ts new file mode 100644 index 0000000..c1a2c14 --- /dev/null +++ b/src/lib/contexts.svelte.ts @@ -0,0 +1,7 @@ +import { createContext } from "svelte"; + +export class PaletteContext { + value = $state(''); +} + +export const [palette, setPalette] = createContext(); diff --git a/src/lib/md-layouts/Blockquote.svelte b/src/lib/md-layouts/Blockquote.svelte new file mode 100644 index 0000000..d11bcfd --- /dev/null +++ b/src/lib/md-layouts/Blockquote.svelte @@ -0,0 +1,21 @@ + + +
+ {@render children?.()} +
+ + \ No newline at end of file diff --git a/src/lib/md-layouts/Hr.svelte b/src/lib/md-layouts/Hr.svelte new file mode 100644 index 0000000..65af53f --- /dev/null +++ b/src/lib/md-layouts/Hr.svelte @@ -0,0 +1,10 @@ + + + \ No newline at end of file diff --git a/src/lib/md-layouts/Li.svelte b/src/lib/md-layouts/Li.svelte new file mode 100644 index 0000000..46057e7 --- /dev/null +++ b/src/lib/md-layouts/Li.svelte @@ -0,0 +1,23 @@ + + +
  • + {#if !isOrdered} +   + {/if} + {@render children?.()} +
  • diff --git a/src/lib/md-layouts/MdLayout.svelte b/src/lib/md-layouts/MdLayout.svelte new file mode 100644 index 0000000..380b46e --- /dev/null +++ b/src/lib/md-layouts/MdLayout.svelte @@ -0,0 +1,51 @@ + + + + + + {seoTitle} - CollageJS + {#if description} + + {/if} + + +
    +

    {title}

    + {@render children?.()} +
    diff --git a/src/lib/md-layouts/Ol.svelte b/src/lib/md-layouts/Ol.svelte new file mode 100644 index 0000000..1c44751 --- /dev/null +++ b/src/lib/md-layouts/Ol.svelte @@ -0,0 +1,15 @@ + + +
      + {@render children?.()} +
    diff --git a/src/lib/md-layouts/headers/H1.svelte b/src/lib/md-layouts/headers/H1.svelte new file mode 100644 index 0000000..c69aef2 --- /dev/null +++ b/src/lib/md-layouts/headers/H1.svelte @@ -0,0 +1,10 @@ + + +
    diff --git a/src/lib/md-layouts/headers/H2.svelte b/src/lib/md-layouts/headers/H2.svelte new file mode 100644 index 0000000..1a4baee --- /dev/null +++ b/src/lib/md-layouts/headers/H2.svelte @@ -0,0 +1,10 @@ + + +
    diff --git a/src/lib/md-layouts/headers/H3.svelte b/src/lib/md-layouts/headers/H3.svelte new file mode 100644 index 0000000..481bb5d --- /dev/null +++ b/src/lib/md-layouts/headers/H3.svelte @@ -0,0 +1,10 @@ + + +
    diff --git a/src/lib/md-layouts/headers/H4.svelte b/src/lib/md-layouts/headers/H4.svelte new file mode 100644 index 0000000..07cc3b9 --- /dev/null +++ b/src/lib/md-layouts/headers/H4.svelte @@ -0,0 +1,10 @@ + + +
    diff --git a/src/lib/md-layouts/headers/H5.svelte b/src/lib/md-layouts/headers/H5.svelte new file mode 100644 index 0000000..0a210ab --- /dev/null +++ b/src/lib/md-layouts/headers/H5.svelte @@ -0,0 +1,10 @@ + + +
    diff --git a/src/lib/md-layouts/headers/H6.svelte b/src/lib/md-layouts/headers/H6.svelte new file mode 100644 index 0000000..ecd3501 --- /dev/null +++ b/src/lib/md-layouts/headers/H6.svelte @@ -0,0 +1,10 @@ + + +
    diff --git a/src/lib/md-layouts/headers/Header.svelte b/src/lib/md-layouts/headers/Header.svelte new file mode 100644 index 0000000..362b45f --- /dev/null +++ b/src/lib/md-layouts/headers/Header.svelte @@ -0,0 +1,25 @@ + + + + {@render children?.()} + + + \ No newline at end of file diff --git a/src/lib/md-layouts/list-context.svelte.ts b/src/lib/md-layouts/list-context.svelte.ts new file mode 100644 index 0000000..2477523 --- /dev/null +++ b/src/lib/md-layouts/list-context.svelte.ts @@ -0,0 +1,10 @@ +import { createContext } from "svelte"; + +export class ListContext { + value = $state(false); + constructor(initial: boolean = false) { + this.value = initial; + } +} + +export const [listContext, setListContext] = createContext(); diff --git a/src/routes/(docs-like)/+layout.svelte b/src/routes/(docs-like)/+layout.svelte new file mode 100644 index 0000000..2bfcda0 --- /dev/null +++ b/src/routes/(docs-like)/+layout.svelte @@ -0,0 +1,68 @@ + + +
    + +
    +
    +
    + {#if primarySidebarCtx.value?.length > 0} +
    + +
    + {/if} +
    0 && 'col-md-9']}> + {@render children()} + {#if nextArticleDefinition || previousArticleDefinition} + + {/if} +
    +
    +
    +
    +
    +
    + + diff --git a/src/routes/(docs-like)/Footer.svelte b/src/routes/(docs-like)/Footer.svelte new file mode 100644 index 0000000..f64c4d9 --- /dev/null +++ b/src/routes/(docs-like)/Footer.svelte @@ -0,0 +1,16 @@ + +
    +
    +
    +
    + Copyright © 2026 CollageJS. All rights reserved. +
    +
    +
    +
    + + \ No newline at end of file diff --git a/src/routes/(docs-like)/NavArticleButtons/NavArticleButtons.svelte b/src/routes/(docs-like)/NavArticleButtons/NavArticleButtons.svelte new file mode 100644 index 0000000..fea4b0a --- /dev/null +++ b/src/routes/(docs-like)/NavArticleButtons/NavArticleButtons.svelte @@ -0,0 +1,42 @@ + + + + + \ No newline at end of file diff --git a/src/routes/(docs-like)/PrimarySidebar/ArticleLink.svelte b/src/routes/(docs-like)/PrimarySidebar/ArticleLink.svelte new file mode 100644 index 0000000..29fdc8f --- /dev/null +++ b/src/routes/(docs-like)/PrimarySidebar/ArticleLink.svelte @@ -0,0 +1,17 @@ + + +
  • + {articleDefinition.title} +
  • diff --git a/src/routes/(docs-like)/PrimarySidebar/ArticlesContainer.svelte b/src/routes/(docs-like)/PrimarySidebar/ArticlesContainer.svelte new file mode 100644 index 0000000..597ebfd --- /dev/null +++ b/src/routes/(docs-like)/PrimarySidebar/ArticlesContainer.svelte @@ -0,0 +1,21 @@ + + +
      + {@render children?.()} +
    + + \ No newline at end of file diff --git a/src/routes/(docs-like)/PrimarySidebar/PrimarySidebar.svelte b/src/routes/(docs-like)/PrimarySidebar/PrimarySidebar.svelte new file mode 100644 index 0000000..dadcdce --- /dev/null +++ b/src/routes/(docs-like)/PrimarySidebar/PrimarySidebar.svelte @@ -0,0 +1,25 @@ + + + diff --git a/src/routes/(docs-like)/PrimarySidebar/Section.svelte b/src/routes/(docs-like)/PrimarySidebar/Section.svelte new file mode 100644 index 0000000..c71f5b2 --- /dev/null +++ b/src/routes/(docs-like)/PrimarySidebar/Section.svelte @@ -0,0 +1,36 @@ + + +
    + {group.title} + + {#each group.articles as article} + {#if isArticleGroupDefinition(article)} + + {:else} + + {/if} + {/each} + +
    + + diff --git a/src/routes/(docs-like)/PrimarySidebar/context.svelte.ts b/src/routes/(docs-like)/PrimarySidebar/context.svelte.ts new file mode 100644 index 0000000..d33ea4b --- /dev/null +++ b/src/routes/(docs-like)/PrimarySidebar/context.svelte.ts @@ -0,0 +1,8 @@ +import { createContext } from "svelte"; +import type { ArticleNode } from "../../../types.js"; + +export class PrimarySidebarContext { + value = $state([]); +} + +export const [primarySidebar, setPrimarySidebar] = createContext(); diff --git a/src/routes/(docs-like)/TopNav.svelte b/src/routes/(docs-like)/TopNav.svelte new file mode 100644 index 0000000..c4b53db --- /dev/null +++ b/src/routes/(docs-like)/TopNav.svelte @@ -0,0 +1,98 @@ + + + + + diff --git a/src/routes/(docs-like)/api/+layout.svelte b/src/routes/(docs-like)/api/+layout.svelte new file mode 100644 index 0000000..abd03c7 --- /dev/null +++ b/src/routes/(docs-like)/api/+layout.svelte @@ -0,0 +1,10 @@ + + +{@render children()} \ No newline at end of file diff --git a/src/routes/(docs-like)/docs/+page.svelte b/src/routes/(docs-like)/api/+page.svelte similarity index 100% rename from src/routes/(docs-like)/docs/+page.svelte rename to src/routes/(docs-like)/api/+page.svelte diff --git a/src/routes/(docs-like)/api/primary-sidebar.json b/src/routes/(docs-like)/api/primary-sidebar.json new file mode 100644 index 0000000..fe51488 --- /dev/null +++ b/src/routes/(docs-like)/api/primary-sidebar.json @@ -0,0 +1 @@ +[] diff --git a/src/routes/(docs-like)/docs/+layout.svelte b/src/routes/(docs-like)/docs/+layout.svelte index 518279a..abd03c7 100644 --- a/src/routes/(docs-like)/docs/+layout.svelte +++ b/src/routes/(docs-like)/docs/+layout.svelte @@ -1,7 +1,10 @@ {@render children()} \ No newline at end of file diff --git a/src/routes/(docs-like)/docs/+page.md b/src/routes/(docs-like)/docs/+page.md new file mode 100644 index 0000000..bcc31c0 --- /dev/null +++ b/src/routes/(docs-like)/docs/+page.md @@ -0,0 +1,21 @@ +--- + title: Docs + description: | + Documentation homepage for the CollageJS project. +--- + + + +
    + CollageJS +
    + +Welcome! This is where you can find the complete documentation for all that *CollageJS* has to offer, from its concept and main objective, to its support for front-end frameworks and ecosystems. + +We recommend that you move through the topics in order since the documentation has been written assuming users will read it like this. This makes the documentation easier to follow, as it can elaborate on previously-explained knowledge. + + + Start: Introduction + \ No newline at end of file diff --git a/src/routes/(docs-like)/docs/[...slug]/+page.svelte b/src/routes/(docs-like)/docs/[...slug]/+page.svelte new file mode 100644 index 0000000..40f992a --- /dev/null +++ b/src/routes/(docs-like)/docs/[...slug]/+page.svelte @@ -0,0 +1,8 @@ + + + diff --git a/src/routes/(docs-like)/docs/introduction/+page.md b/src/routes/(docs-like)/docs/introduction/+page.md new file mode 100644 index 0000000..b17fe0f --- /dev/null +++ b/src/routes/(docs-like)/docs/introduction/+page.md @@ -0,0 +1,190 @@ +--- +title: Introduction +description: | + Learn how CollageJS works at its core, which is the foundation of the entire technology. +--- + + + +*CollageJS* is a small collection of libraries that allows front-end developers the opportunity of creating user interfaces in chunks or pieces, where each piece doesn't care about the underlying technology of the other pieces. In other words: *CollageJS* can be used to create web applications piece by piece, and each piece can be created using... well, anything. It doesn't matter. + +Now you know the main objective of *CollageJS*. Let's delve next into the core concepts. + +## Core Pieces + +*Core pieces*, also known plainly as *pieces*, are the main course: A *piece* is an abstraction of a user interface element that is capable of working as a unit by itself. + +In JavaScript terms, it is an object that fulfills a contract. Which contract? The `CorePiece` interface. + +This is its TypeScript definition: + +```typescript +export interface CorePiece { + mount: MountFn | MountFn[]; + relocate?: RelocateFn | RelocateFn[]; + update?: UpdateFn | UpdateFn[]; + capabilities?: TCap & { remountable?: boolean; }; +} +``` +> ** NOTE** +> +> This is a simplification of the actual types. + +Except for the `capabilities` property, these are called *lifecycle* functions loosely, even though technically speaking, they can be an array of lifecycle functions. + +Of all the interface properties, only the `mount` lifecycle function is required. This property can be a function, an array of functions, or an array of either functions or array of functions. Let's show an example. + +### Mount + +Assuming that each letter below is a function, the following objects are valid `CorePiece` objects: + +```typescript +const myPiece = { + mount(target: AcceptableTarget, props: Record) { + // ... + }, +}; + +const myPieceComplex = { + mount: [a, b, [c, d, [e, f, g]], h, null, false, undefined], +}; +``` + +The `myPiece` object is the simplest form of `CorePiece`, and the example shows the actual function signature expected by *CollageJS*. The `target` parameter can be an HTML element or a shadow root object, while the second one is an object with the properties the `CorePiece` object supports. + +On the other hand, `myPieceComplex` is an example of how mounting functions can be arranged: We can nest arrays within arrays without issue. This is normally not what we recommend developers to do, however. The reason *CollageJS* supports this arrangement is to facilitate the composition of `CorePiece` objects. + +#### Unmounting + +Core pieces must provide an unmounting function. The mechanism is very simple: A mounting function must return the unmounting function. + +To exemplify, let's elaborate on the `myPiece` piece from above: + +```typescript +const myPiece = { + mount(target: AcceptableTarget, props: Record) { + const root = document.createElement('div'); + // Etc. Fill the root element. + target.appendChild(root); + return () => { + root.remove(); + }; + }, +}; +``` + +This kind of pattern is very popular among font-end libraries and frameworks, so hopefully this is very easy to understand. + +### Relocate + +This is mostly an optimization technique and piece objects will work just fine without this lifecycle function. + +In order to fully understand this lifecycle function, we need to understand with more depth how *CollageJS* pieces are mounted, and we haven't done this. Therefore, let's just say this: Piece objects that provide the `relocate` lifecycle function are capable of switching target elements without going through unmounting and remounting. + +Let's just stop here for now. +TODO: Add link to where the topic can be resumed. + +### Update + +This lifecycle function is in place for piece objects that are capable of reacting to component property changes. Many front-end frameworks are capable of producing components that reactively update whenever their given property values change. Just to name a few frameworks (and libraries): *React*, *Svelte*, *VueJS*, *SolidJS*, *Lit*, *Preact*, etc. + +The `update` lifecycle function is the medium that consumers of *CollageJS* pieces use to ask them to update in response to changes in their given properties. + +The implementation of this lifecycle function is heavily dependent on the framework or library used to generate the piece object. Just to show one example, here's how one would do it in *Svelte* v5: + +```typescript +// myPiece.svelte.ts + +const myProps = $state({}); + +const myPiece = { + update(newProps: MyProps) { + myProps = { + ...myProps, + ...newProps + } + }, +}; +``` + +We could go on talking about differences. For instance, *React* components re-render instead of using a signal mechanism like *Svelte* does. However, this should be sufficient for us to understand this lifecycle function. + +### Capabilities + +This is not a lifecycle function. This is a POJO where piece developers can use to pass along any values they consider appropriate for very, very specialized scenarios. Most people won't need to use this at all. + +What most people need to know, is that *CollageJS* has defined one property inside `capabilities`: `remountable?: boolean`. This is a property highly related to the `relocate` lifecycle function, and we will therefore defer the topic once more. + +## Consuming Pieces + +Now that we know how the main building block (the piece object) works, we can complete the puzzle: Let's mount a piece. + +Since we don't want to speak in terms of a framework or library, let's do some vanilla TypeScript: + +```typescript +import { mountPiece } from '@collagejs/core'; + +const pieceEl = document.querySelector('#piece'); +// Assuming we have made sure there's an element with id="piece" in our markup: +const target = pieceEl; // If we want to mount directly in the DOM +const target = pieceEl!.attachShadow({ mode: 'open' }); // If we want to mount in an open shadow root +const target = pieceEl!.attachShadow({ mode: 'closed' }); // If we want to mount in an closed shadow root + +const mountedPiece = await mountPiece(myPiece, target, { + prop1: 'Hello', + prop2: 'CollageJS!' +}); +``` + +In order, the parameters to `mountPiece` are: + +- `piece: CorePiece` -- The piece object to mount +- `target: AcceptableTarget` -- The parent object that will host the piece's user interface +- `props: TProps` -- The properties accepted by the piece object + +The returned `mountedPiece` object is of type `MountedPiece` and provides an interface almost identical to that of `CorePiece`, where: + +- `unmount` unmounts the piece +- `update` updates the piece with a new set of property values +- `relocate` relocates the piece without triggering a mounting cycle +- `capabilities` exposes the piece's `capabilities` property + +### A Better Way to Consume Pieces + +We learned that we can use `mountPiece` and its return value to handle however we think is best any core piece object. This is great as well as powerful, but it is cumbersome. Yes, the no-framework font-end developers exist and are many. If you are one of those, then you're probably all set and ready to start experimenting by yourself. + +But if you're not one of those developers, you want a friendlier way to consume pieces. We understand fully. This is where *adapters* enter the equation. + +An *adapter* is a library specialized in a particular front-end framework or library that assists in the process of achieving the 2 operations we covered here, namely: + +- Creating a `CorePiece` object +- Consuming a `CorePiece` object + +We won't discuss them in depth here, but surely we can present some sample code to illustrate the matter. + +This is an example of how we can produce a `CorePiece` object out of a Svelte component: + +```typescript +import { buildPiece } from '@collagejs/svelte'; +import Root from './Root.svelte'; + +const piece = buildPiece(Root); +``` + +This is an example of how we can consume a `CorePiece` object (no matter its nature) in a Svelte project: + +```svelte + + + +``` + +Generally speaking, adapter libraries work this way regardless of their framework. If a particular adapter cannot fulfill the standardized API for any reason, the adapter's documentation will cover the difference(s). + +TODO: Add link to specialized adapters topic. diff --git a/src/routes/(docs-like)/docs/primary-sidebar.json b/src/routes/(docs-like)/docs/primary-sidebar.json new file mode 100644 index 0000000..91c50b9 --- /dev/null +++ b/src/routes/(docs-like)/docs/primary-sidebar.json @@ -0,0 +1,108 @@ +[ + { + "title": "Get Started", + "articles": [ + { + "title": "Introduction", + "href": "/docs/introduction" + }, + { + "title": "Project Types", + "href": "/docs/project-types" + }, + { + "title": "The Root Template", + "href": "/docs/the-root-template" + }, + { + "title": "Root Projects in Detail", + "href": "/docs/root-projects-in-detail" + }, + { + "title": "Piece Projects in Detail", + "href": "/docs/piece-projects-in-detail" + } + ] + }, + { + "title": "Import Maps", + "articles": [ + { + "title": "Overview", + "href": "/docs/import-maps-overview" + }, + { + "title": "Import Maps in CollageJS", + "href": "/docs/import-maps-in-collagejs" + }, + { + "title": "Overriding Import Map Entries", + "href": "/docs/overriding-import-map-entries" + } + ] + }, + { + "title": "Framework Adapters", + "articles": [ + { + "title": "Definition & Objectives", + "href": "/docs/adapter-definition-and-objectives" + }, + { + "title": "Official Adapters", + "href": "/docs/official-adapters" + } + ] + }, + { + "title": "Advanced Topics", + "articles": [ + { + "title": "Configuring @collagejs/imo", + "href": "/docs/configuring-collagejs-imo" + }, + { + "title": "CorePiece Composition", + "href": "/docs/corepiece-composition" + }, + { + "title": "CorePiece Relocation and Capabilities", + "href": "/docs/corepiece-relocation-and-capabilities" + }, + { + "title": "Development Tips & Tricks", + "href": "/docs/development-tips-and-tricks" + } + ] + }, + { + "title": "Ecosystem", + "articles": [ + { + "title": "Supported Frameworks", + "href": "/docs/supported-frameworks" + }, + { + "title": "Vite", + "articles": [ + { + "title": "Overview", + "href": "/docs/vite-overview" + }, + { + "title": "Vite-IM Plug-In", + "href": "/docs/vite-im-plugin" + }, + { + "title": "Vite-AIM Plug-In", + "href": "/docs/vite-aim-plugin" + }, + { + "title": "Vite-CSS Plug-In", + "href": "/docs/vite-css-plugin" + } + ] + } + ] + } +] \ No newline at end of file diff --git a/src/routes/(docs-like)/docs/project-types/+page.md b/src/routes/(docs-like)/docs/project-types/+page.md new file mode 100644 index 0000000..9f453c2 --- /dev/null +++ b/src/routes/(docs-like)/docs/project-types/+page.md @@ -0,0 +1,262 @@ +--- + title: Project Types + description: | + Learn about the two project types encountered when using CollageJS to produce micro-frontend-powered applications. +--- + + + +There are 2 project types: + +- Root projects +- Piece projects + +A *root project* is the central or main web project. It is in charge of setting things up for piece (micro-frontend) consumption. Usually --but not necessarily--, this is a project that sets up the application's layout and routing mechanisms. + +Root projects can be created using any framework or library. *CollageJS* doesn't impose any restrictions. The only thing that *CollageJS* does and does it through its [Vite-IM plug-in](/docs/vite-im-plugin) is inject an import map and the tool to perform import map entry overriding. If you're unfamiliar with import maps and how they help micro-frontend applications, read the [import maps overview](/docs/import-maps-overview) and subsequent topics. + +The other type of project is the *piece project*. Piece projects are web projects that export one or more **factory functions** that create `CorePiece` objects. We say factory functions because, even though it is legal to export a pre-built `CorePiece` object, it is not desirable because it makes reuse more difficult. We prefer factories so we can create pieces when needed. Furthermore, exporting factory functions allow said factories to optionally accept configuration options, which is a great tool for more complex scenarios. + +## Creating Root Projects + +There are countless ways to create one of these. Once more: *CollageJS* doesn't restrict what can or cannot be used. Having said this, *CollageJS* has 2 recommended paths for creating root projects: + +- Using *CollageJS*' root template +- Creating a Vite project with `npm create vite` + +To know more about the root template alternative, read the [root template](/docs/the-root-template) topic. From this point forward, we'll see about using `npm create vite`. + +The first step is to create a new Vite project with Vite's creation package, `vite-create`. Use the template you like the best: + +```bash +npm create vite@latest -- --template svelte-ts +``` +> This is not a Vite tutorial, so we'll assume the reader will be able to get to the point where the project is created, configured and running. + +As your root project currently stands, you *can* start mounting pieces using the `mountPiece` function from `@collagejs/core`, assuming you proceed to install this package. If you take this route, you'll be able to manage the mounted pieces as shown in the [introduction](docs/introduction). + +However and also mentioned in the introduction, there are better ways to do things. If your chosen template when creating your root project corresponds to a technology covered by an adapter (be it official or not), you can instead proceed to install said adapter. + +In the example code, we chose TypeScript Svelte, and Svelte does have an official adapter named `@collagejs/svelte`. Install it: + +```bash +npm install @collagejs/svelte +``` + +Now we're ready to mount pieces using the Svelte adapter, and we don't have to deal directly with the `mountPiece` function. Instead, we'll be using the `` component provided by the adapter. + +To actually show an example on how to do this, let's pause on the root project topic and let's create a piece project. We will also cover the installation of the [Vite-IM plug-in](/docs/vite-im-plugin) after we have a working piece project. + +## Creating Piece Projects + +Deja vu: The same things we said about root projects are applicable to piece projects: + +- There are no restrictions on how it is created +- There are no restrictions to the technologies used to create it +- *CollageJS* recommends a Vite project + +There is no template alternative for piece projects, so let's proceed with a new Vite project: + +``` +npm create vite@latest -- --template react-ts +``` + +This time we created a TypeScript + React project. This means that the piece or pieces we'll export (via factory functions) will be powered by the React library. + +Just like root projects: We can go straight to creating factory functions if we don't mind doing the work of creating all lifecycle functions ourselves, but the introduction topic taught us this is already done in the React adapter: + +```bash +npm install @collagejs/react +``` + +Now we can use the `buildPiece` function, which greatly simplifies the process. + +### Recommended File Arrangement + +Many people like developing micro-frontends as standalone projects, at least at first. This means that they like the fact that they can run the project in serve mode (`npm run dev`) while the piece (micro-frontend) is created. + +For this reason we recommend not to delete the core files that set up the Vite project. These usually are: + +- `index.html` +- `main.ts` +- `App.[ts|tsx|svelte|vue|solid]` + +Instead, just clean them up to the point where you are comfortable. Most of the time we just blank out the `App` component, the CSS files and then change the page's title. If we proceed like this, we still have a functional Vite-powered web application, albeit a (possibly) empty one. + +In order to start coding our piece, we add a new component file. Since we created a React piece project above, let's add the `src/Root.tsx` file to create a new React component, which will be the component we will wrap into a `CorePiece` object: + +```typescript +// src/Root.tsx + +import './root.css'; // We can import some CSS to make the component pretty, if we like. + +export type RootProps = { + name?: string; +} + +export function Root(props: RootProps) { + return <> +
    + Welcome aboard, {props.name || 'stranger'}! +
    + +} +``` + +We can preview this `Root` component by adding it to `App.tsx`, so we can preview it with Vite's serve mode. Feel free to do so and make it look pretty. Perhaps a nice background, or maybe a handshake icon somewhere, etc. + +Once we're happy with the result, we recommend exporting a factory function that creates `CorePiece` objects that wrap the `Root` component. Because we're going to add the [Vite-CSS plug-in](/docs/vite-css-plugin) to the project, we'll follow this plug-in's default options and create the `src/piece.ts` file. + +We now want to install our Vite CSS plug-in and the React adapter package, if we didn't do this before: + +```bash +npm install @collagejs/vite-css @collagejs/react +``` + +Now we can add the plug-in to the list of plug-ins in `vite.config.ts`: + +```typescript +import { defineConfig } from 'vitest/config'; // or from 'vite' +import { cjsCssPlugin } from '@collagejs/vite-css'; + +export default defineConfig({ + plugins: [ + react(), + cjsCssPlugin({ + serverPort: 6101, + aim: false, + }) + ], +}); +``` +> ** AIM Plug-In Turned Off** +> +> If you would like to know what the `aim` plug-in option is for, head to the documentation for the [Vite-CSS plug-in](/docs/vite-css-plugin). + +Then we add code to our piece entry file: + +```typescript +// src/piece.ts +import Root from './Root.tsx'; +import { buildPiece } from '@collagejs/react'; +import { CssFactory } from '@collagejs/vite-css/ex'; + +const css = new CssFactory(import.meta.url); + +export function myPieceFactory() { + const lc = buildPiece(Root); + const { mount } = css.instantiate(); + + return { + ...lc, + mount: [mount, lc.mount], + } +} +``` +> ** We Simplified** +> +> The example above only composes the `mount` lifecycle function, but `css.instantiate()` also provides a `relocate` function that should be composed with the core piece's own `relocate` function. + +Believe it or not, **we're done**. + +The above code creates the core piece object, and then uses the [composition](/docs/corepiece-composition) technique to add the CSS-mounting layer provided by the `@collagejs/vite-css` plug-in, which understands how Vite bundles CSS, including Vite's split CSS chunks. Our CSS plug-in can track every chunk of CSS your piece needs and will mount it an unmount it in synchrony with your core piece. + +At this point, you may choose to run either Vite's development server of preview server. If you opt for preview server (which is required to mount the piece in shadow DOM), remember to build your piece project first. + +--- + +## Back to Root + +Great, so now we can go back to our root project and make use of the `` Svelte component (because our root is powered by Svelte) to mount our React piece. + +Somewhere inside `App.svelte`, we're going to add the React piece. To do this, we need 2 imports: + +1. The piece factory function +2. The `` Svelte component + +If you are a seasoned micro-frontends developer, you'll probably realize at this point that we will import directly from the piece project's Vite server (either development or preview). For Vite to allow us to do it, we have to use the dynamic `import()` statement... Or do we? + +The answer is: We don't! By leveraging the use of an import map and the automatic externalization that the [Vite-AIM plug-in](/docs/vite-aim-plugin) provides, we can use static import statements when importing piece factory functions. Let's set it up. + +Install the IM plug-in: + +```bash +npm install @collagejs/vite-im +``` + +This installation also carries the `@collagejs/vite-aim` plug-in, and it will be available by default. + +Let's add it to `vite.config.ts`: + +```typescript +import { defineConfig } from 'vitest/config'; // or from 'vite' +import { cjsImPlugin } from '@collagejs/vite-im'; + +export default defineConfig({ + plugins: [ + svelte(), + cjsImPlugin() + ], +}); +``` + +Now and following the plug-in's default options, we'll add the `src/importMap.json` file: + +``` +{ + "imports": { + "@tutorial/react-piece": "http://localhost:6101/piece.js" + } +} +``` +> ** This is for Preview Server** +> +> Vite provides 2 HTTP servers: Development and preview, and in the previous section we started one of these. If we chose the preview server, the above works as-is; if we chose the development server, then change `http://localhost:6101/piece.js` to `http://localhost:6101/src/piece.ts`. + +We have come up with the bare module identifier (a. k. a. bare module specifier) `@tutorial/react-piece` to refer to our React piece. The web browser will read the import map and will divert itself to the URL we have written in the import map entry. + +Because of the wonders of the *Vite-AIM* plug-in, we can directly import our `myPieceFactory` function from the React piece project using a static import statement and use it: + +```typescript +// Inside App.svelte's script tag +import { Piece, piece } from '@collagejs/svelte'; +import { myPieceFactory } from '@tutorial/react-piece'; + +const reactPiece = myPieceFactory(); +``` + +Ok, so we are not entirely done. At this point, TypeScript complains that this module is unknown. That's ok. We can teach TypeScript about the module with an [ambient module](https://www.typescriptlang.org/docs/handbook/modules/reference.html#ambient-modules): + +Add the ambient module to a `.d.ts` file in your project. Vite-powered projects usually have at least one of these ready to be used: + +```typescript +declare module '@tutorial/react-piece' { + import type { CorePiece } from '@collagejs/core'; + + export type RootProps = { + name?: string; + } + + export function myPieceFactory(): CorePiece; +} +``` + +With the ambient module in place, our static import statement should be error-free. + +Continuing in `App.svelte`, we proceed to add the `` component somewhere we like: + +```svelte + +``` +> ** CAUTION** +> +> Change `shadow` to `false` if you started the piece project's development server. + +Save your changes. If you didn't have your development server for the root project running, run it now and open the web page. The react piece should be greeting José! + +--- + +You're probably wondering about several things, like the `piece` helper function. It is perfectly normal. Keep reading to master *CollageJS*. \ No newline at end of file diff --git a/src/routes/(docs-like)/guides/+layout.svelte b/src/routes/(docs-like)/guides/+layout.svelte new file mode 100644 index 0000000..abd03c7 --- /dev/null +++ b/src/routes/(docs-like)/guides/+layout.svelte @@ -0,0 +1,10 @@ + + +{@render children()} \ No newline at end of file diff --git a/src/routes/(docs-like)/guides/migration-from-single-spa/+page.svelte b/src/routes/(docs-like)/guides/[...slug]/+page.svelte similarity index 100% rename from src/routes/(docs-like)/guides/migration-from-single-spa/+page.svelte rename to src/routes/(docs-like)/guides/[...slug]/+page.svelte diff --git a/src/routes/(docs-like)/guides/primary-sidebar.json b/src/routes/(docs-like)/guides/primary-sidebar.json new file mode 100644 index 0000000..fe51488 --- /dev/null +++ b/src/routes/(docs-like)/guides/primary-sidebar.json @@ -0,0 +1 @@ +[] diff --git a/src/routes/(docs-like)/utils.ts b/src/routes/(docs-like)/utils.ts new file mode 100644 index 0000000..93e97cc --- /dev/null +++ b/src/routes/(docs-like)/utils.ts @@ -0,0 +1,5 @@ +import type { ArticleGroupDefinition, ArticleNode } from "../../types.js"; + +export function isArticleGroupDefinition(node: ArticleNode): node is ArticleGroupDefinition { + return (node as ArticleGroupDefinition).articles !== undefined; +} diff --git a/src/routes/+layout.svelte b/src/routes/+layout.svelte index 5f5837f..af39076 100644 --- a/src/routes/+layout.svelte +++ b/src/routes/+layout.svelte @@ -1,16 +1,18 @@ @@ -18,23 +20,18 @@ CollageJS - Microfrontends Made Simple -
    - -
    -
    -
    -
    - {@render children()} -
    +
    +
    + {@render children()}
    \ No newline at end of file diff --git a/src/routes/+page.svelte b/src/routes/+page.svelte index 12b82a1..410c0f0 100644 --- a/src/routes/+page.svelte +++ b/src/routes/+page.svelte @@ -2,9 +2,16 @@ import Hero from './Hero.svelte'; import Features from './Features/Features.svelte'; import DocsLinks from './DocsLinks/DocsLinks.svelte'; + import PaletteToggler from '$lib/PaletteToggler/PaletteToggler.svelte'; + import { palette } from '$lib/contexts.svelte.js'; + + const pal = palette(); -
    +
    + +
    +
    @@ -15,6 +22,6 @@
    -
    +
    Copyright © 2026 CollageJS. All rights reserved.
    diff --git a/src/routes/Features/Features.svelte b/src/routes/Features/Features.svelte index 95cefeb..362cb55 100644 --- a/src/routes/Features/Features.svelte +++ b/src/routes/Features/Features.svelte @@ -33,7 +33,7 @@
    •  Dev/build import maps
    • -  Dev/build Automatic externalization +  Dev/build automatic externalization
    •  Dev tool for overrides
    @@ -41,6 +41,7 @@  Test-drive in minutes
    npx degit https://github.com/collagejs/root-template.git
    +

    Or Clone template on GitHub

    diff --git a/src/scss/_bs.scss b/src/scss/_bs.scss index 4db9782..c5dff1a 100644 --- a/src/scss/_bs.scss +++ b/src/scss/_bs.scss @@ -1,5 +1,23 @@ @layer Bootstrap { @import "../../node_modules/bootstrap/scss/functions"; + +$grid-breakpoints: ( + xs: 0, + sm: 576px, + md: 768px, + lg: 992px, + xl: 1200px, + xxl: 1600px +); + +$container-max-widths: ( + sm: 540px, + md: 720px, + lg: 960px, + xl: 1140px, + xxl: 1450px +); + @import "../../node_modules/bootstrap/scss/variables"; @import "../../node_modules/bootstrap/scss/variables-dark"; @import "../../node_modules/bootstrap/scss/maps"; diff --git a/src/scss/app.scss b/src/scss/app.scss index e38f707..d6aa69d 100644 --- a/src/scss/app.scss +++ b/src/scss/app.scss @@ -13,3 +13,32 @@ pre { border-radius: var(--cjs-radius); } } + +.widget { + background: var(--widget-bg); + color: var(--widget-fg); + + &.widget-rounded { + border-radius: var(--cjs-radius); + } + + &.widget-top-rounded { + border-top-left-radius: var(--cjs-radius); + border-top-right-radius: var(--cjs-radius); + } + + &.widget-bottom-rounded { + border-bottom-left-radius: var(--cjs-radius); + border-bottom-right-radius: var(--cjs-radius); + } +} + +hr { + color: var(--cjs-primary-400); +} + +.active { + font-weight: bold; + text-decoration: underline; + color: var(--cjs-primary-400); +} diff --git a/src/scss/code.css b/src/scss/code.css new file mode 100644 index 0000000..f393170 --- /dev/null +++ b/src/scss/code.css @@ -0,0 +1,111 @@ +pre[class*='language-'] { + color: rgba(var(--cjs-white-rgb), 0.9); + background: rgba(var(--cjs-black-rgb), 0.3); + text-shadow: none; + font-family: Consolas, Monaco, "Andale Mono", "Ubuntu Mono", monospace; + font-size: 1em; + line-height: 1.5; + letter-spacing: .2px; + white-space: pre; + word-spacing: normal; + word-break: normal; + word-wrap: normal; + text-align: left; + + -moz-tab-size: 4; + -o-tab-size: 4; + tab-size: 4; + + -webkit-hyphens: none; + -moz-hyphens: none; + -ms-hyphens: none; + hyphens: none; +} + +pre[class*='language-']::-moz-selection, +pre[class*='language-'] ::-moz-selection, +code[class*='language-']::-moz-selection, +code[class*='language-'] ::-moz-selection, +pre[class*='language-']::selection, +pre[class*='language-'] ::selection, +code[class*='language-']::selection, +code[class*='language-'] ::selection { + color: inherit; + background: #1d3b54; + text-shadow: none; +} + +pre[class*='language-'] { + border: 1px solid var(--cjs-primary-800); + border-radius: var(--cjs-radius-lg); + padding: 1.5em 1em; + margin: 1em 0; + overflow: auto; +} + +:not(pre) > code[class*='language-'] { + color: #f0f6f6; + background: #2a4555; + padding: 0.2em 0.3em; + border-radius: 0.2em; + box-decoration-break: clone; +} + +.token.comment, +.token.prolog, +.token.doctype, +.token.cdata { + color: var(--cjs-text-muted); +} + +.token.punctuation { + color: var(--cjs-primary-300); +} + +.token.property, +.token.tag, +.token.boolean, +.token.number, +.token.constant, +.token.symbol, +.token.deleted { + color: var(--cjs-primary-100); +} + +.token.selector, +.token.attr-name, +.token.builtin, +.token.inserted { + color: var(--cjs-accent); +} + +.token.string, +.token.char { + color: var(--cjs-primary-600); +} + +.token.operator, +.token.entity, +.token.url, +.language-css .token.string, +.style .token.string { + color: #ec8e01; + background: transparent; +} + +.token.atrule, +.token.attr-value, +.token.keyword { + color: var(--cjs-primary); +} + +.token.function, +.token.class-name { + color: var(--cjs-secondary); +} + +.token.regex, +.token.important, +.token.variable { + color: var(--cjs-primary-600); +} \ No newline at end of file diff --git a/src/scss/md-content.css b/src/scss/md-content.css new file mode 100644 index 0000000..80bc0ae --- /dev/null +++ b/src/scss/md-content.css @@ -0,0 +1,25 @@ +.md-content { + h1, h2, h3, h4, h5, h6 { + margin-top: 2rem; + margin-bottom: 1.5rem; + } + p { + margin-top: 1.3rem; + margin-bottom: 1.3rem; + line-height: 1.7; + } + + blockquote { + & > p:first-child { + margin-top: 0; + } + & > p:last-child { + margin-bottom: 0; + } + } + + ul { + list-style: none; + padding-left: 1em; + } +} \ No newline at end of file diff --git a/src/types.ts b/src/types.ts new file mode 100644 index 0000000..aaad913 --- /dev/null +++ b/src/types.ts @@ -0,0 +1,11 @@ +export type ArticleDefinition = { + title: string; + href: string; +}; + +export type ArticleGroupDefinition = { + title: string; + articles: ArticleNode[]; +}; + +export type ArticleNode = ArticleDefinition | ArticleGroupDefinition; diff --git a/vite.config.ts b/vite.config.ts index 6fde309..3503467 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -1,7 +1,9 @@ import { defineConfig } from 'vitest/config'; +import { join } from 'path'; import { playwright } from '@vitest/browser-playwright'; import adapter from '@sveltejs/adapter-cloudflare'; import { sveltekit } from '@sveltejs/kit/vite'; +import { mdsvex } from 'mdsvex'; export default defineConfig({ plugins: [ @@ -9,12 +11,22 @@ export default defineConfig({ extensions: ['.svelte', '.md'], compilerOptions: { // Force runes mode for the project, except for libraries. Can be removed in svelte 6. - runes: ({ filename }) => - filename.split(/[/\\]/).includes('node_modules') ? undefined : true + runes: ({ filename }) => { + const parts = filename.split(/[/\\]/); + const fileName = parts[parts.length - 1]; + if (fileName.endsWith('.md')) { + console.debug('runes mode for %s: %o', filename, parts); + } + return parts.includes('node_modules') || + fileName.endsWith('.md') ? undefined : true; + } }, - - // Explicit Cloudflare Workers target. - adapter: adapter() + adapter: adapter(), + preprocess: mdsvex({ + extensions: ['.md'], + smartypants: true, + layout: join(__dirname, './src/lib/md-layouts/MdLayout.svelte'), + }), }), ], test: { From 9c30534d8d80fa39935a16453f45cee669f749fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ramirez=20Vargas=2C=20Jos=C3=A9=20Pablo?= Date: Sat, 18 Jul 2026 13:22:12 -0600 Subject: [PATCH 4/5] docs: Add migration guide for single-spa link to docs root route --- src/routes/(docs-like)/docs/+page.md | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/routes/(docs-like)/docs/+page.md b/src/routes/(docs-like)/docs/+page.md index bcc31c0..f215a4d 100644 --- a/src/routes/(docs-like)/docs/+page.md +++ b/src/routes/(docs-like)/docs/+page.md @@ -14,8 +14,12 @@ Welcome! This is where you can find the complete documentation for all that *CollageJS* has to offer, from its concept and main objective, to its support for front-end frameworks and ecosystems. -We recommend that you move through the topics in order since the documentation has been written assuming users will read it like this. This makes the documentation easier to follow, as it can elaborate on previously-explained knowledge. +We recommend that you move through the topics in order since the documentation has been written assuming users will read it like this. This makes the documentation easier to follow, as it can elaborate on previously-explained knowledge. Use the navigation button at the bottom to start reading. - - Start: Introduction +## Single-SPA Developers + +If you are versed in in `single-spa`, maybe you should give the migration guide a try. *CollageJS* was born from the concept of *single-spa parcels* and you'll find much of *CollageJS* familiar. + + + Migration Guid for single-spa \ No newline at end of file From f84641f225e9556afbff929e246a3b53c8083971 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ramirez=20Vargas=2C=20Jos=C3=A9=20Pablo?= Date: Sat, 18 Jul 2026 13:27:26 -0600 Subject: [PATCH 5/5] fix: Re-add @collagejs/core --- package-lock.json | 8 ++++---- package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index c955cd9..297577d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,7 +8,7 @@ "name": "@collagejs/docs", "version": "0.0.1", "dependencies": { - "@collagejs/core": "0.x || 1.x", + "@collagejs/core": "^0.10.1", "@lucide/svelte": "^1.24.0", "bootstrap": "^5.3.8", "sass": "^1.101.0" @@ -151,9 +151,9 @@ } }, "node_modules/@collagejs/core": { - "version": "0.10.0", - "resolved": "https://registry.npmjs.org/@collagejs/core/-/core-0.10.0.tgz", - "integrity": "sha512-U2vC2hI/zIbz/OxnQ0K8SH1zmWP0VjNLiVxddppcg9ykQqf+uV06Z5ECnSrZQ0L78cVTN37fWmGd7EcLd56T3A==", + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/@collagejs/core/-/core-0.10.1.tgz", + "integrity": "sha512-NTJ28BOUz8Y8NeINBLo+xspJ2jKLqJifXIWNw/k8DVVfv9cacIzm1TiPN5IFZFcaEKQE2vD1R4mbQI0ygdnirA==", "license": "MIT" }, "node_modules/@cspotcode/source-map-support": { diff --git a/package.json b/package.json index 7dfffe5..3041d57 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "wrangler": "^4.27.0" }, "dependencies": { - "@collagejs/core": "0.x || 1.x", + "@collagejs/core": "^0.10.1", "@lucide/svelte": "^1.24.0", "bootstrap": "^5.3.8", "sass": "^1.101.0"