diff --git a/.github/workflows/workflow-website.yml b/.github/workflows/workflow-website.yml index 0b460bc32f..b38e78cc6f 100644 --- a/.github/workflows/workflow-website.yml +++ b/.github/workflows/workflow-website.yml @@ -46,6 +46,21 @@ jobs: rm -rf website/doc_build/repl mkdir -p website/doc_build cp -r packages/repl/dist website/doc_build/repl + - name: Build A2UI dependencies + run: | + pnpm turbo --filter a2ui-playground^... build + - name: Build A2UI Lynx bundle + run: | + pnpm --filter a2ui-playground build:lynx + - name: Build A2UI Playground + run: | + BASE_PATH='${{ steps.pages.outputs.base_path }}' + export ASSET_PREFIX="${BASE_PATH%/}/a2ui/" + pnpm --filter a2ui-playground build + - name: Copy A2UI Playground into website output + run: | + rm -rf website/doc_build/a2ui + cp -r packages/genui/a2ui-playground/dist website/doc_build/a2ui - name: Upload artifact uses: actions/upload-pages-artifact@7b1f4a764d45c48632c6b24a0339c27f5614fb0b # v4 with: diff --git a/packages/genui/a2ui-playground/rsbuild.config.ts b/packages/genui/a2ui-playground/rsbuild.config.ts index e339c77bae..3169ebe5b6 100644 --- a/packages/genui/a2ui-playground/rsbuild.config.ts +++ b/packages/genui/a2ui-playground/rsbuild.config.ts @@ -43,6 +43,9 @@ export default defineConfig({ render: './src/render.tsx', }, }, + output: { + assetPrefix: process.env.ASSET_PREFIX, + }, server: { port: PORT, host: '0.0.0.0', @@ -52,7 +55,7 @@ export default defineConfig({ publicDir: [ { name: 'www', - copyOnBuild: false, + copyOnBuild: true, watch: true, }, ], diff --git a/packages/genui/a2ui-playground/src/pages/DemosPage.tsx b/packages/genui/a2ui-playground/src/pages/DemosPage.tsx index 7228845025..2b7e7d2899 100644 --- a/packages/genui/a2ui-playground/src/pages/DemosPage.tsx +++ b/packages/genui/a2ui-playground/src/pages/DemosPage.tsx @@ -92,7 +92,7 @@ export function DemosPage(props: { protocol: ProtocolVersion }) { const [lynxDevQrError, setLynxDevQrError] = useState(''); const [lynxDevCopied, setLynxDevCopied] = useState(false); - const origin = window.location.origin; + const baseUrl = window.location.href.replace(/#.*$/, ''); const rspeedyDevUrl = useRspeedyDevUrl(); const lynxUrlSeqRef = useRef(0); @@ -115,7 +115,7 @@ export function DemosPage(props: { protocol: ProtocolVersion }) { const actionMocks = scenario?.actionMocks; const url = buildRenderUrl( { protocol, demoUrl: DEFAULT_DEMO_URL, messages: parsed, actionMocks }, - origin, + baseUrl, ); setRenderUrl(url); @@ -174,7 +174,7 @@ export function DemosPage(props: { protocol: ProtocolVersion }) { // "View on Device" QR is scannable. render.html already supports // messagesUrl / actionMocksUrl query params. if (messagesUrlAbs) { - const r = new URL('/render.html', origin); + const r = new URL('render.html', baseUrl); r.searchParams.set('protocol', protocol); r.searchParams.set('demoUrl', DEFAULT_DEMO_URL); r.searchParams.set('messagesUrl', messagesUrlAbs); @@ -189,7 +189,7 @@ export function DemosPage(props: { protocol: ProtocolVersion }) { } })(); }, - [origin, protocol, rspeedyDevUrl], + [baseUrl, protocol, rspeedyDevUrl], ); useEffect(() => { diff --git a/packages/genui/a2ui-playground/src/utils/demoUrl.ts b/packages/genui/a2ui-playground/src/utils/demoUrl.ts index f2f1aaceab..054a339bf2 100644 --- a/packages/genui/a2ui-playground/src/utils/demoUrl.ts +++ b/packages/genui/a2ui-playground/src/utils/demoUrl.ts @@ -1,4 +1,4 @@ // Copyright 2026 The Lynx Authors. All rights reserved. // Licensed under the Apache License Version 2.0 that can be found in the // LICENSE file in the root directory of this source tree. -export const DEFAULT_DEMO_URL = '/main.web.js'; +export const DEFAULT_DEMO_URL = './main.web.js'; diff --git a/packages/genui/a2ui-playground/src/utils/renderUrl.ts b/packages/genui/a2ui-playground/src/utils/renderUrl.ts index 571bac83ab..4ea1b9b34f 100644 --- a/packages/genui/a2ui-playground/src/utils/renderUrl.ts +++ b/packages/genui/a2ui-playground/src/utils/renderUrl.ts @@ -11,19 +11,22 @@ export interface RenderInit { actionMocks?: unknown; } -export function buildRenderUrl(init: RenderInit, baseOrigin: string): string { - const params = new URLSearchParams(); - params.set('protocol', init.protocol); - params.set('demoUrl', init.demoUrl); +export function buildRenderUrl(init: RenderInit, baseUrl: string): string { + const url = new URL('render.html', baseUrl); + url.searchParams.set('protocol', init.protocol); + url.searchParams.set('demoUrl', init.demoUrl); // Use base64url to avoid URL-encoding overhead for JSON payloads. - params.set('messages', encodeBase64Url(JSON.stringify(init.messages))); + url.searchParams.set( + 'messages', + encodeBase64Url(JSON.stringify(init.messages)), + ); if (init.actionMocks !== undefined) { - params.set( + url.searchParams.set( 'actionMocks', encodeBase64Url(JSON.stringify(init.actionMocks)), ); } - return `${baseOrigin}/render.html?${params.toString()}`; + return url.toString(); } diff --git a/website/rspress.config.ts b/website/rspress.config.ts index f463fa73a2..adeb5ae6c6 100644 --- a/website/rspress.config.ts +++ b/website/rspress.config.ts @@ -751,6 +751,10 @@ const config: UserConfig = defineConfig({ text: 'REPL', link: '/repl', }, + { + text: 'A2UI', + link: '/a2ui', + }, { text: 'API', items: [