From 8a1c396bade6a580e08f2afd4425e222d0693ae1 Mon Sep 17 00:00:00 2001 From: bbopen Date: Sat, 21 Mar 2026 15:25:48 -0700 Subject: [PATCH 1/3] feat(docs): redesign hero with llm copy block and extracted features --- docs/.vitepress/theme/components/Hero3D.vue | 320 ++++++++++++++++---- docs/index.md | 13 - docs/public/llms-full.txt | 60 ++-- scripts/generate-llms-full.mjs | 3 +- 4 files changed, 292 insertions(+), 104 deletions(-) diff --git a/docs/.vitepress/theme/components/Hero3D.vue b/docs/.vitepress/theme/components/Hero3D.vue index 2ec79875..5db40ec6 100644 --- a/docs/.vitepress/theme/components/Hero3D.vue +++ b/docs/.vitepress/theme/components/Hero3D.vue @@ -7,12 +7,39 @@ const { site } = useData() const canvasRef = ref(null) let threeScene: ThreeSceneReturn | null = null let scrollTicking = false -let scrollRafId: number | null = null + +const features = [ + { icon: '๐Ÿ”’', title: 'Full Type Safety', details: 'TypeScript definitions generated directly from Python source analysis via AST โ€” no manual type writing.' }, + { icon: '๐ŸŒ', title: 'Multi-Runtime', details: 'One API across Node.js, Bun, Deno (subprocess), and browsers (Pyodide WebAssembly).' }, + { icon: 'โšก', title: 'Rich Data Types', details: 'First-class support for numpy, pandas, scipy, torch, and sklearn with Apache Arrow binary transport.' }, + { icon: '๐Ÿ› ', title: 'Zero-Config CLI', details: 'Run npx tywrap generate and get production-ready TypeScript wrappers with a single command.' } +] function getBase(): string { return site.value.base || '/' } +const copied = ref(false) +let copyTimeout: number + +async function copyPrompt() { + try { + const response = await fetch(getBase() + 'llms-full.txt') + if (!response.ok) throw new Error('Failed to fetch llms-full.txt') + const text = await response.text() + + await navigator.clipboard.writeText(text) + + copied.value = true + if (copyTimeout) clearTimeout(copyTimeout) + copyTimeout = window.setTimeout(() => { + copied.value = false + }, 2500) + } catch (err) { + console.error('Failed to copy prompt: ', err) + } +} + // Ensure the scroll event is throttled by requestAnimationFrame function onScroll() { if (!scrollTicking && threeScene && threeScene.onScroll) { @@ -88,12 +115,36 @@ onBeforeUnmount(() => {

- - Get Started - - - View Documentation - +
+

Copy this into your coding agent to get started in one shot:

+ + + + + View full documentation โ†’ + +
+
+ + + +
+
+
{{ feature.icon }}
+
+

{{ feature.title }}

+

+
@@ -127,16 +178,25 @@ onBeforeUnmount(() => { .hero-section { position: relative; - min-height: 100vh; display: flex; flex-direction: column; justify-content: center; - align-items: flex-start; /* Force left alignment */ + align-items: flex-start; z-index: 10; width: 100%; - padding-bottom: 5rem; - /* Align to Vitepress standard left container edge */ + padding-bottom: 2rem; + padding-top: 8rem; + box-sizing: border-box; padding-left: max(24px, calc((100vw - var(--vp-layout-max-width, 1152px)) / 2)); + padding-right: max(24px, calc((100vw - var(--vp-layout-max-width, 1152px)) / 2)); +} + +@media (min-width: 1024px) { + .hero-section { + flex-direction: row; + align-items: center; + justify-content: space-between; + } } /* ---------------------------------------------------------------- @@ -144,9 +204,10 @@ onBeforeUnmount(() => { ---------------------------------------------------------------- */ .hero-content { position: relative; - max-width: 44rem; /* Restrict width to keep left-aligned */ - padding-top: 4rem; + max-width: 44rem; + width: 100%; text-align: left; + flex: 1; } .hero-headline { @@ -205,76 +266,211 @@ onBeforeUnmount(() => { flex-direction: column; align-items: flex-start; gap: 1.5rem; + width: 100%; } -@media (min-width: 640px) { - .hero-actions { - flex-direction: row; - } +.copy-agent-block { + display: flex; + flex-direction: column; + width: 100%; + gap: 1rem; } -.btn-primary, -.btn-secondary { - display: inline-flex; +.copy-instruction { + font-size: 0.95rem; + color: #9ca3af; + font-family: var(--vp-font-family-mono); + margin: 0; + letter-spacing: -0.01em; +} + +.prompt-copy-container { + display: flex; align-items: center; - justify-content: center; + justify-content: space-between; width: 100%; - padding: 1rem 2.5rem; + max-width: 32rem; + padding: 1rem 1.25rem; + background: rgba(15, 15, 15, 0.6); + border: 1px solid rgba(255, 255, 255, 0.1); + border-radius: 0.75rem; + backdrop-filter: blur(12px); + -webkit-backdrop-filter: blur(12px); + cursor: pointer; + transition: all 0.2s ease; + color: #d1d5db; + font-family: var(--vp-font-family-mono); + font-size: 0.95rem; + box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.4), 0 2px 4px -1px rgba(0, 0, 0, 0.2); +} + +.prompt-copy-container:hover { + background: rgba(25, 25, 25, 0.8); + border-color: rgba(255, 255, 255, 0.2); + transform: translateY(-2px); + box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.5), 0 4px 6px -2px rgba(0, 0, 0, 0.3); +} + +.prompt-copy-container:active { + transform: translateY(1px); + box-shadow: 0 2px 4px -1px rgba(0, 0, 0, 0.4); +} + +.prompt-copy-container.copied { + background: rgba(16, 185, 129, 0.15); + border-color: rgba(16, 185, 129, 0.4); + color: #10b981; +} + +.prompt-text { + display: flex; + align-items: center; + gap: 0.75rem; + overflow: hidden; + text-align: left; +} + +.prompt-prefix { + color: #f4b459; /* Amber/Python focus */ font-weight: 700; - font-size: 1.125rem; - border-radius: 9999px; - text-align: center; - transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1); + user-select: none; +} + +.prompt-url { + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +.copy-icon-wrapper { + display: flex; + align-items: center; + gap: 0.5rem; + color: #9ca3af; + flex-shrink: 0; + margin-left: 1rem; + transition: color 0.2s ease; +} + +.prompt-copy-container:hover .copy-icon-wrapper { + color: #ffffff; +} + +.prompt-copy-container.copied .copy-icon-wrapper { + color: #10b981; +} + +.copied-label { + font-size: 0.85rem; + font-weight: 600; + animation: fadeIn 0.3s ease; +} + +/* Secondary Link */ +.link-secondary { + display: inline-flex; + align-items: center; + gap: 0.5rem; + font-size: 0.95rem; + color: #9ca3af; text-decoration: none; - cursor: pointer; - letter-spacing: 0.05em; + font-weight: 500; + transition: color 0.2s ease; + margin-top: 0.25rem; +} + +.link-secondary:hover { + color: #ffffff; +} + +.link-secondary .arrow { + transition: transform 0.2s ease; +} + +.link-secondary:hover .arrow { + transform: translateX(4px); } -@media (min-width: 640px) { - .btn-primary, - .btn-secondary { - width: auto; +/* ---------------------------------------------------------------- + Features (Right Column) + ---------------------------------------------------------------- */ +.hero-features { + position: relative; + display: flex; + flex-direction: column; + gap: 1rem; + margin-top: 3rem; + width: 100%; + max-width: 28rem; + flex-shrink: 0; +} + +@media (min-width: 1024px) { + .hero-features { + margin-top: 0; + margin-left: 4rem; } } -/* Brutalist modern key style for buttons, adapting Hermes 4 feel */ -.btn-primary { - background: #f4b459; /* Amber/Python focus */ - color: #000000; - border: 2px solid transparent; - box-shadow: 0 4px 0 #b45309, 0 10px 20px -5px rgba(245, 158, 11, 0.4); +.feature-card { + display: flex; + align-items: flex-start; + background: rgba(15, 15, 15, 0.65); + border: 1px solid rgba(255, 255, 255, 0.08); + border-radius: 1rem; + padding: 1.25rem; + backdrop-filter: blur(20px); + -webkit-backdrop-filter: blur(20px); + box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3); + transition: transform 0.2s ease, background 0.2s ease, border-color 0.2s ease; } -.btn-primary:hover { - background: #fcd34d; - box-shadow: 0 6px 0 #d97706, 0 15px 30px -5px rgba(245, 158, 11, 0.6); - transform: translateY(-2px); +.feature-card:hover { + background: rgba(25, 25, 25, 0.85); + transform: translateX(-4px); + border-color: rgba(255, 255, 255, 0.2); } -.btn-primary:active { - box-shadow: 0 0px 0 #b45309, 0 5px 10px -5px rgba(245, 158, 11, 0.4); - transform: translateY(4px); +.feature-icon { + font-size: 1.5rem; + margin-right: 1.25rem; + background: rgba(255, 255, 255, 0.05); + padding: 0.5rem; + border-radius: 0.5rem; + border: 1px solid rgba(255, 255, 255, 0.05); } -.btn-secondary { - background: rgba(255, 255, 255, 0.03); - backdrop-filter: blur(12px); - -webkit-backdrop-filter: blur(12px); - color: #ffffff; - border: 1px solid rgba(255, 255, 255, 0.2); - box-shadow: 0 4px 0 rgba(255, 255, 255, 0.1), 0 10px 30px rgba(0, 0, 0, 0.2); +.feature-text { + flex: 1; } -.btn-secondary:hover { - background: rgba(255, 255, 255, 0.08); - border-color: rgba(255, 255, 255, 0.4); - box-shadow: 0 6px 0 rgba(255, 255, 255, 0.2), 0 15px 40px rgba(0, 0, 0, 0.3); - transform: translateY(-2px); +.feature-title { + color: #fff; + font-size: 1rem; + font-weight: 600; + margin: 0 0 0.5rem 0; + line-height: 1.2; } -.btn-secondary:active { - box-shadow: 0 0px 0 rgba(255, 255, 255, 0.2), 0 5px 10px rgba(0, 0, 0, 0.2); - transform: translateY(4px); +.feature-details { + color: #d1d5db; + font-size: 0.9rem; + margin: 0; + line-height: 1.6; + text-shadow: 0 1px 2px rgba(0, 0, 0, 0.8); +} + +.feature-details :deep(code) { + background: rgba(255, 255, 255, 0.1); + padding: 0.1rem 0.3rem; + border-radius: 4px; + font-family: var(--vp-font-family-mono); + font-size: 0.8em; +} + +@keyframes fadeIn { + from { opacity: 0; } + to { opacity: 1; } } /* ---------------------------------------------------------------- @@ -303,6 +499,10 @@ onBeforeUnmount(() => { animation-delay: 0.4s; } +.delay-3 { + animation-delay: 0.6s; +} + /* Disable all decorative animations for motion-sensitive users */ @media (prefers-reduced-motion: reduce) { .fade-up { diff --git a/docs/index.md b/docs/index.md index 73790a76..7967f887 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1,19 +1,6 @@ --- layout: home -features: - - icon: ๐Ÿ”’ - title: Full Type Safety - details: TypeScript definitions generated directly from Python source analysis via AST โ€” no manual type writing. - - icon: ๐ŸŒ - title: Multi-Runtime - details: One API across Node.js, Bun, Deno (subprocess), and browsers (Pyodide WebAssembly). - - icon: โšก - title: Rich Data Types - details: First-class support for numpy, pandas, scipy, torch, and sklearn with Apache Arrow binary transport. - - icon: ๐Ÿ›  - title: Zero-Config CLI - details: Run `npx tywrap generate` and get production-ready TypeScript wrappers with a single command. --- ## Quick Start diff --git a/docs/public/llms-full.txt b/docs/public/llms-full.txt index 24dbfea9..a7ab63e1 100644 --- a/docs/public/llms-full.txt +++ b/docs/public/llms-full.txt @@ -413,14 +413,14 @@ const [sinValue, cosValue, tanValue] = await Promise.all([ ## Next Steps -- [Configuration Guide](/guide/configuration) - Complete configuration reference -- [Runtime Guides](/guide/runtimes/node) - Platform-specific setup -- [Examples](/examples/) - Usage patterns and examples -- [Troubleshooting](/troubleshooting/) - Common issues and solutions +- [Configuration Guide](https://bbopen.github.io/tywrap/guide/configuration) - Complete configuration reference +- [Runtime Guides](https://bbopen.github.io/tywrap/guide/runtimes/node) - Platform-specific setup +- [Examples](https://bbopen.github.io/tywrap/examples/) - Usage patterns and examples +- [Troubleshooting](https://bbopen.github.io/tywrap/troubleshooting/) - Common issues and solutions ## Support -- [Troubleshooting Guide](/troubleshooting/) +- [Troubleshooting Guide](https://bbopen.github.io/tywrap/troubleshooting/) - [GitHub Issues](https://github.com/bbopen/tywrap/issues) - [GitHub Discussions](https://github.com/bbopen/tywrap/discussions) @@ -790,7 +790,7 @@ export default defineConfig({ }); ``` -See [Environment Variables](/reference/env-vars) for the full implemented list. +See [Environment Variables](https://bbopen.github.io/tywrap/reference/env-vars) for the full implemented list. ## Advanced Configuration Patterns @@ -1001,13 +1001,13 @@ python3 -c "import your_module; print(your_module.__file__)" } ``` -For more troubleshooting, see [Troubleshooting Guide](/troubleshooting/). +For more troubleshooting, see [Troubleshooting Guide](https://bbopen.github.io/tywrap/troubleshooting/). ## Next Steps -- [Runtime Guides](/guide/runtimes/node) - Platform-specific configuration -- [Examples](/examples/) - Configuration examples -- [API Reference](/reference/api/) - Complete API documentation +- [Runtime Guides](https://bbopen.github.io/tywrap/guide/runtimes/node) - Platform-specific configuration +- [Examples](https://bbopen.github.io/tywrap/examples/) - Configuration examples +- [API Reference](https://bbopen.github.io/tywrap/reference/api/) - Complete API documentation --- @@ -1696,10 +1696,10 @@ function getNextBridge() { ## Next Steps -- [Configuration Guide](/guide/configuration) - Complete configuration reference -- [Examples](/examples/) - Usage examples and patterns -- [Troubleshooting](/troubleshooting/) - Common issues and solutions -- [API Reference](/reference/api/) - Complete API documentation +- [Configuration Guide](https://bbopen.github.io/tywrap/guide/configuration) - Complete configuration reference +- [Examples](https://bbopen.github.io/tywrap/examples/) - Usage examples and patterns +- [Troubleshooting](https://bbopen.github.io/tywrap/troubleshooting/) - Common issues and solutions +- [API Reference](https://bbopen.github.io/tywrap/reference/api/) - Complete API documentation --- @@ -1782,7 +1782,7 @@ setRuntimeBridge(new NodeBridge({ ## Environment Variables -The same `TYWRAP_*` env vars work under Bun. See the [environment variables reference](/reference/env-vars). +The same `TYWRAP_*` env vars work under Bun. See the [environment variables reference](https://bbopen.github.io/tywrap/reference/env-vars). ## Troubleshooting @@ -1804,8 +1804,8 @@ tywrap works with [Deno](https://deno.land/) 1.46+ using the same `NodeBridge` a **Deno Deploy does NOT support subprocess execution.** Because `NodeBridge` spawns a Python subprocess, it cannot run in Deno Deploy. **Alternatives for Deno Deploy:** -- Use [`PyodideBridge`](/guide/runtimes/browser) โ€” runs Python in-browser via WebAssembly (no subprocess) -- Use [`HttpBridge`](/guide/runtimes/http) โ€” connects to a remote Python server over HTTP +- Use [`PyodideBridge`](https://bbopen.github.io/tywrap/guide/runtimes/browser) โ€” runs Python in-browser via WebAssembly (no subprocess) +- Use [`HttpBridge`](https://bbopen.github.io/tywrap/guide/runtimes/http) โ€” connects to a remote Python server over HTTP ## Installation @@ -1864,13 +1864,13 @@ See the [Node.js guide](./node) for the full `NodeBridgeOptions` reference โ€” a ## Environment Variables -The same `TYWRAP_*` env vars work under Deno. See the [environment variables reference](/reference/env-vars). +The same `TYWRAP_*` env vars work under Deno. See the [environment variables reference](https://bbopen.github.io/tywrap/reference/env-vars). ## Troubleshooting **`PermissionDenied: Requires run access to "python3"`** โ€” Add `--allow-run=python3` to your `deno run` command. -**`NotSupported: Subprocess access is not allowed`** โ€” You are running in Deno Deploy. Switch to [`PyodideBridge`](/guide/runtimes/browser) or [`HttpBridge`](/guide/runtimes/http). +**`NotSupported: Subprocess access is not allowed`** โ€” You are running in Deno Deploy. Switch to [`PyodideBridge`](https://bbopen.github.io/tywrap/guide/runtimes/browser) or [`HttpBridge`](https://bbopen.github.io/tywrap/guide/runtimes/http). See the [Node.js troubleshooting guide](./node) for additional patterns. @@ -2002,7 +2002,7 @@ setRuntimeBridge(new HttpBridge({ `HttpBridge` expects a server that accepts POST requests with JSON/Arrow payloads. You must implement or deploy a compatible server endpoint. The protocol is stateless โ€” each call is an independent POST request. -> **Note:** A built-in server command is not yet available. See the [API reference](/reference/api/) for the expected request/response format. +> **Note:** A built-in server command is not yet available. See the [API reference](https://bbopen.github.io/tywrap/reference/api/) for the expected request/response format. ## Apache Arrow @@ -2022,7 +2022,7 @@ registerArrowDecoder(bytes => tableFromIPC(bytes)); | `TYWRAP_CODEC_FALLBACK=json` | Disable Arrow, use JSON only | | `TYWRAP_CODEC_MAX_BYTES` | Cap max response size | -See the [environment variables reference](/reference/env-vars). +See the [environment variables reference](https://bbopen.github.io/tywrap/reference/env-vars). ## Security @@ -2161,7 +2161,7 @@ export default defineConfig({ }); ``` -See the [Configuration guide](/guide/configuration) for the full config surface. +See the [Configuration guide](https://bbopen.github.io/tywrap/guide/configuration) for the full config surface. --- @@ -2770,12 +2770,12 @@ await counter.disposeHandle(); ## More Docs -- [Getting started](/guide/getting-started) -- [Configuration](/guide/configuration) -- [Node runtime](/guide/runtimes/node) -- [Browser runtime](/guide/runtimes/browser) -- [Troubleshooting](/troubleshooting/) -- [Type mapping](/reference/type-mapping) +- [Getting started](https://bbopen.github.io/tywrap/guide/getting-started) +- [Configuration](https://bbopen.github.io/tywrap/guide/configuration) +- [Node runtime](https://bbopen.github.io/tywrap/guide/runtimes/node) +- [Browser runtime](https://bbopen.github.io/tywrap/guide/runtimes/browser) +- [Troubleshooting](https://bbopen.github.io/tywrap/troubleshooting/) +- [Type mapping](https://bbopen.github.io/tywrap/reference/type-mapping) --- @@ -3429,6 +3429,6 @@ npx tsc --noEmit --traceResolution ``` This troubleshooting guide covers the most common issues. For runtime-specific detail, see: -- [Node.js Runtime](/guide/runtimes/node) -- [Browser Runtime (Pyodide)](/guide/runtimes/browser) +- [Node.js Runtime](https://bbopen.github.io/tywrap/guide/runtimes/node) +- [Browser Runtime (Pyodide)](https://bbopen.github.io/tywrap/guide/runtimes/browser) - [Build Tool Issues](#build-tool-issues) diff --git a/scripts/generate-llms-full.mjs b/scripts/generate-llms-full.mjs index bfb816e6..bf6ee16c 100644 --- a/scripts/generate-llms-full.mjs +++ b/scripts/generate-llms-full.mjs @@ -77,7 +77,8 @@ async function main() { const sections = []; for (const file of orderedDocs) { - const text = await readFile(file, 'utf8'); + let text = await readFile(file, 'utf8'); + text = text.replaceAll('](/', '](https://bbopen.github.io/tywrap/'); sections.push(`\n${text.trimEnd()}\n`); } From d62b06472100f07969de941b7efd01e1627171d2 Mon Sep 17 00:00:00 2001 From: bbopen Date: Sat, 21 Mar 2026 16:25:39 -0700 Subject: [PATCH 2/3] fix(docs): address CodeRabbit review feedback on link generation and scrollRafId --- docs/.vitepress/theme/components/Hero3D.vue | 1 + docs/public/llms-full.txt | 27 ++++++--------------- scripts/generate-llms-full.mjs | 22 ++++++++++++++++- 3 files changed, 29 insertions(+), 21 deletions(-) diff --git a/docs/.vitepress/theme/components/Hero3D.vue b/docs/.vitepress/theme/components/Hero3D.vue index 5db40ec6..226fec78 100644 --- a/docs/.vitepress/theme/components/Hero3D.vue +++ b/docs/.vitepress/theme/components/Hero3D.vue @@ -7,6 +7,7 @@ const { site } = useData() const canvasRef = ref(null) let threeScene: ThreeSceneReturn | null = null let scrollTicking = false +let scrollRafId: number | null = null const features = [ { icon: '๐Ÿ”’', title: 'Full Type Safety', details: 'TypeScript definitions generated directly from Python source analysis via AST โ€” no manual type writing.' }, diff --git a/docs/public/llms-full.txt b/docs/public/llms-full.txt index a7ab63e1..35799255 100644 --- a/docs/public/llms-full.txt +++ b/docs/public/llms-full.txt @@ -7,19 +7,6 @@ --- layout: home -features: - - icon: ๐Ÿ”’ - title: Full Type Safety - details: TypeScript definitions generated directly from Python source analysis via AST โ€” no manual type writing. - - icon: ๐ŸŒ - title: Multi-Runtime - details: One API across Node.js, Bun, Deno (subprocess), and browsers (Pyodide WebAssembly). - - icon: โšก - title: Rich Data Types - details: First-class support for numpy, pandas, scipy, torch, and sklearn with Apache Arrow binary transport. - - icon: ๐Ÿ›  - title: Zero-Config CLI - details: Run `npx tywrap generate` and get production-ready TypeScript wrappers with a single command. --- ## Quick Start @@ -1054,9 +1041,9 @@ Do you need subprocess-based Python execution? | Bridge | Export | Guide | |--------|--------|-------| -| `NodeBridge` | `tywrap/node` | [Node.js](./node) ยท [Bun](./bun) ยท [Deno](./deno) | -| `PyodideBridge` | `tywrap/pyodide` | [Browser](./browser) | -| `HttpBridge` | `tywrap/http` | [HTTP](./http) | +| `NodeBridge` | `tywrap/node` | [Node.js](https://bbopen.github.io/tywrap/guide/runtimes/node) ยท [Bun](https://bbopen.github.io/tywrap/guide/runtimes/bun) ยท [Deno](https://bbopen.github.io/tywrap/guide/runtimes/deno) | +| `PyodideBridge` | `tywrap/pyodide` | [Browser](https://bbopen.github.io/tywrap/guide/runtimes/browser) | +| `HttpBridge` | `tywrap/http` | [HTTP](https://bbopen.github.io/tywrap/guide/runtimes/http) | --- @@ -1732,7 +1719,7 @@ setRuntimeBridge(new NodeBridge({ ## Configuration Options -`NodeBridge` accepts the same options under Bun as under Node.js. See the [Node.js guide](./node) for the full option reference. +`NodeBridge` accepts the same options under Bun as under Node.js. See the [Node.js guide](https://bbopen.github.io/tywrap/guide/runtimes/node) for the full option reference. Key options: @@ -1790,7 +1777,7 @@ The same `TYWRAP_*` env vars work under Bun. See the [environment variables refe **Subprocess times out** โ€” Increase `timeoutMs`. Verify `pip install tywrap-ir` ran in the correct environment. -See the [Node.js troubleshooting guide](./node) for additional patterns โ€” all apply equally to Bun. +See the [Node.js troubleshooting guide](https://bbopen.github.io/tywrap/guide/runtimes/node) for additional patterns โ€” all apply equally to Bun. --- @@ -1852,7 +1839,7 @@ deno check src/index.ts ## Configuration Options -See the [Node.js guide](./node) for the full `NodeBridgeOptions` reference โ€” all options work identically in Deno. +See the [Node.js guide](https://bbopen.github.io/tywrap/guide/runtimes/node) for the full `NodeBridgeOptions` reference โ€” all options work identically in Deno. ## When to Use Each Bridge in Deno @@ -1872,7 +1859,7 @@ The same `TYWRAP_*` env vars work under Deno. See the [environment variables ref **`NotSupported: Subprocess access is not allowed`** โ€” You are running in Deno Deploy. Switch to [`PyodideBridge`](https://bbopen.github.io/tywrap/guide/runtimes/browser) or [`HttpBridge`](https://bbopen.github.io/tywrap/guide/runtimes/http). -See the [Node.js troubleshooting guide](./node) for additional patterns. +See the [Node.js troubleshooting guide](https://bbopen.github.io/tywrap/guide/runtimes/node) for additional patterns. --- diff --git a/scripts/generate-llms-full.mjs b/scripts/generate-llms-full.mjs index bf6ee16c..2e060583 100644 --- a/scripts/generate-llms-full.mjs +++ b/scripts/generate-llms-full.mjs @@ -78,7 +78,27 @@ async function main() { const sections = []; for (const file of orderedDocs) { let text = await readFile(file, 'utf8'); - text = text.replaceAll('](/', '](https://bbopen.github.io/tywrap/'); + + // Resolve relative links based on the file's directory path + const dirMatch = file.match(/^docs\/(.*\/)/); + const dirPath = dirMatch ? dirMatch[1] : ''; + const baseUrl = `https://bbopen.github.io/tywrap/${dirPath}`; + + text = text.replace(/\]\(([^)]+)\)/g, (match, href) => { + if (/^(https?:|mailto:|#)/.test(href)) { + return match; + } + if (href.startsWith('/')) { + return `](https://bbopen.github.io/tywrap${href})`; + } + try { + const url = new URL(href, baseUrl); + return `](${url.href})`; + } catch (e) { + return match; + } + }); + sections.push(`\n${text.trimEnd()}\n`); } From ce56ad10cfbebf29a907021d55e622eee11e85e1 Mon Sep 17 00:00:00 2001 From: bbopen Date: Sat, 21 Mar 2026 16:28:14 -0700 Subject: [PATCH 3/3] fix(docs): resolve CodeRabbit nitpicks regarding copyTimeout and base URL config --- docs/.vitepress/theme/components/Hero3D.vue | 9 +++++++-- scripts/generate-llms-full.mjs | 12 ++++++++++-- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/docs/.vitepress/theme/components/Hero3D.vue b/docs/.vitepress/theme/components/Hero3D.vue index 226fec78..15e4fa52 100644 --- a/docs/.vitepress/theme/components/Hero3D.vue +++ b/docs/.vitepress/theme/components/Hero3D.vue @@ -21,7 +21,7 @@ function getBase(): string { } const copied = ref(false) -let copyTimeout: number +let copyTimeout: number | null = null async function copyPrompt() { try { @@ -32,9 +32,10 @@ async function copyPrompt() { await navigator.clipboard.writeText(text) copied.value = true - if (copyTimeout) clearTimeout(copyTimeout) + if (copyTimeout !== null) window.clearTimeout(copyTimeout) copyTimeout = window.setTimeout(() => { copied.value = false + copyTimeout = null }, 2500) } catch (err) { console.error('Failed to copy prompt: ', err) @@ -83,6 +84,10 @@ function onResize() { } onBeforeUnmount(() => { + if (copyTimeout !== null) { + window.clearTimeout(copyTimeout) + copyTimeout = null + } if (scrollRafId !== null) { window.cancelAnimationFrame(scrollRafId) scrollRafId = null diff --git a/scripts/generate-llms-full.mjs b/scripts/generate-llms-full.mjs index 2e060583..8b901bab 100644 --- a/scripts/generate-llms-full.mjs +++ b/scripts/generate-llms-full.mjs @@ -75,6 +75,13 @@ async function main() { '', ].join('\n'); + // Derive the canonical site base from the shared VitePress config + const configText = await readFile('docs/.vitepress/config.ts', 'utf8'); + const baseMatch = configText.match(/base:\s*['"]([^'"]+)['"]/); + const basePath = baseMatch ? baseMatch[1] : '/'; + const siteHost = 'https://bbopen.github.io'; + const canonicalBase = new URL(basePath, siteHost).href; + const sections = []; for (const file of orderedDocs) { let text = await readFile(file, 'utf8'); @@ -82,14 +89,15 @@ async function main() { // Resolve relative links based on the file's directory path const dirMatch = file.match(/^docs\/(.*\/)/); const dirPath = dirMatch ? dirMatch[1] : ''; - const baseUrl = `https://bbopen.github.io/tywrap/${dirPath}`; + const baseUrl = new URL(dirPath, canonicalBase).href; text = text.replace(/\]\(([^)]+)\)/g, (match, href) => { if (/^(https?:|mailto:|#)/.test(href)) { return match; } if (href.startsWith('/')) { - return `](https://bbopen.github.io/tywrap${href})`; + // Root-relative links resolve against the canonical base (removing the leading slash) + return `](${new URL(href.slice(1), canonicalBase).href})`; } try { const url = new URL(href, baseUrl);