Skip to content

feat: path URLs for the playground's components - #27

Merged
divyanshub024 merged 1 commit into
mainfrom
dv/playground-routing
Aug 24, 2026
Merged

feat: path URLs for the playground's components#27
divyanshub024 merged 1 commit into
mainfrom
dv/playground-routing

Conversation

@divyanshub024

@divyanshub024 divyanshub024 commented Aug 24, 2026

Copy link
Copy Markdown
Member

Summary

Every component in the playground now has an address. flowui.stac.dev/playground was one URL for eighteen views: selection lived in setState, so a component could not be linked, bookmarked, or reached with the back button. This puts the component in the path.

  • go_router with a single /:component route. Paths are the item's slug, the enum name in kebab-case: /playground/composer, /playground/full-chat, /playground/thinking-indicator.
  • The variant pills, the theme and the device frame stay out of the URL. They are workbench settings that travel with the person, not the link, so they remain shell state — including the per-item "remembers your last pill" memory.
  • The embed contract is untouched. index.html?embed=<slug>&variant=&theme= works byte-for-byte, so FlowDemo.astro, the 37 <FlowDemo> call sites and the ?theme pre-paint script needed no changes. main branches on ?embed= before the app is built, so embeds never reach the router, and usePathUrlStrategy() is called after that branch on purpose: under path strategy the iframe's /playground/index.html?embed=… would read as the route name /index.html, which the embed's plain Navigator cannot build.

Design notes worth a reviewer's eye:

  • One page, one constant key. The route's pageBuilder returns a NoTransitionPage under a constant ValueKey, so Page.canUpdate passes and the Navigator updates the page in place rather than pushing. _PlaygroundShellState survives navigation, and with it the variant memory, the device toggle and the code panel — including across browser back and forward.
  • Not ShellRoute. It would insert a nested Navigator and Overlay exactly where the stage sits, so FlowMenu and FlowModelSelector popovers would clip to the stage pane instead of the window. The phone stage's own nested Navigator stays untouched.
  • Slugs are computed on PlaygroundItem, and embed.dart now uses the same getter. The path and the embed id are the same string by construction, so they cannot drift.
  • /, a typo, or a stale link all redirect to /full-chat in one top-level rule, so there is no reachable error page and no nullable item threading through the shell.

Hosting

Component paths are routes, not files, so they need a rewrite. docs/public/_redirects adds one line per slug. Two details are load-bearing, both learned from wrangler pages dev rather than guessed, and both recorded in the file's comment:

  • /playground/* is rejected by Pages outright ("infinite loop detected", rule ignored, deep links 404) because it strips .html and /index from the destination and then sees it match the source again.
  • The destination must be the directory, not /playground/index.html. Naming index.html makes Pages normalise it into a 308 to /playground/, which throws the component away and lands every deep link on the default.

The dev-server equivalent extends the existing playground-dev-index integration in astro.config.mjs, matching extensionless paths only so main.dart.js, canvaskit/ and assets/ pass through.

Screenshots

/playground/markdown /playground/pill

How this was verified

flutter analyze clean in the package and the playground, dart format --set-exit-if-changed clean, and npm run build:site produces the same wasm build the deploy runs, with _redirects and <base href="/playground/"> in dist/.

Against a real wrangler pages dev dist, so the rules are exercised the way Cloudflare will run them: all 18 rules parse; deep links return 200 and serve the app with the URL preserved; main.dart.wasm, flutter_bootstrap.js, main.dart.js and assets/ still resolve; COOP and COEP survive the rewrite; both embed forms still boot; /playground/ and the docs pages are unaffected. Headless captures confirm /playground/markdown and /playground/pill stage the right component with the sidebar and code panel in step.

Checklist

  • flutter analyze lib and flutter analyze in example/ and playground/ are clean
  • dart format . applied
  • Exercised in the playground — with a stage demo added or updated if this is a new component or variant
  • No new entries under dependencies: in pubspec.yaml (Flutter SDK and flutter.dev packages only)
  • Nothing model-facing — no prompts, schemas, or provider/network calls
  • New public API is exported from lib/flow_ui.dart and documented in docs/ and the README table
  • CHANGELOG.md updated for user-facing changes, with breaking changes called out
  • PR title follows conventional commits (feat:, fix:, refactor:, docs:, chore:)

Note

Medium Risk
Production deep links depend on per-slug Cloudflare _redirects and dev middleware staying in sync when components are added; embed routing order is load-bearing but scoped to the playground/docs site, not the core package.

Overview
Playground components are now addressable by path (e.g. /playground/composer, /playground/full-chat) instead of living only in shell setState, so links, bookmarks, and the back button work. The app uses go_router with a single /:component route, usePathUrlStrategy() (after the embed branch), and PlaygroundItem.slug shared with embed parsing so path and ?embed= ids stay aligned. Variant, theme, and device stay in shell state; sidebar selection calls context.go.

The ?embed= iframe contract is unchangedmain still boots EmbedApp before the router. Docs hosting adds docs/public/_redirects (one explicit rule per slug for Cloudflare Pages) and extends the Astro playground-dev-index middleware for extensionless component paths in dev. READMEs document the two URL contracts; .wrangler/ is gitignored for local redirect verification.

Reviewed by Cursor Bugbot for commit 4ca609c. Bugbot is set up for automated code reviews on this repo. Configure here.

@divyanshub024
divyanshub024 merged commit 0467161 into main Aug 24, 2026
5 checks passed
@divyanshub024
divyanshub024 deleted the dv/playground-routing branch August 24, 2026 18:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant