Merge Playground and Gallery into a combined stac_playground app (#484) - #485
Conversation
* feat: merge playground and gallery into stac_playground example
- Move the Stac Playground app (console web UI) into examples/stac_playground
- Merge all Stac Gallery widget examples into a combined entry index:
screens + 76 components with search, grouped index, and descriptions
- Responsive mobile UI from the Console mobile designs: explore list
(dark/light), component detail with Preview/Dart/JSON tabs, fullscreen
preview, and links drawer
- Dart DSL sources generated for gallery examples (35 verified compiling
via lib/dsl; remaining 42 stubbed pending migration), loaded alongside
JSON assets; stac/stac_core consumed as workspace path deps
- Remove examples/stac_gallery (superseded) and its melos build scope
* fix: align mobile UI with Console mobile designs
- Explore: token-based light/dark palettes (white-alpha containers with
hairline borders), circular logo and icon chips, Figtree type scale per
design (23px medium hero, 13px tracked label, 16/14 cards), 48px search
field with 8px radius
- Detail: surface-bright header and centered tab bar with accent-green
active underline; crop/code/file-code tab icons at design sizes
- Compile embed screen only on web via conditional import (dart:js_interop
is unavailable on native platforms); add non-web stub
- Fix AppIcon asset catalog casing for iOS builds
* fix: move dark theme toggle to the end of the mobile drawer
* feat: restore per-component icons in the mobile explore list
Carry each gallery entry's original material/cupertino icon through the
registry and render it via Stac's icon parser inside the card chip;
fall back to the square glyph when an entry has no icon.
* fix: mobile detail screen refinements
- Dart tab uses the Dart logo mark from the design instead of a glyph
- Header theme icon toggles only the component preview theme; the app
theme stays on the explore drawer switch
- Smaller detail title (16px)
- Code views follow the app theme with a VS Code Light+ palette and
explicit base text color in light mode
* fix: show result count label while searching the explore list
* feat: full-screen menu overlay and exact Figma theme tokens
- Replace the explore drawer with the designed blurred overlay menu:
top bar with close action, plain link rows with hairline dividers,
and a Theme row showing the current mode
- Correct the light palette to the Figma theme variables (#F3F3F3
surface, #07090A on-surface base, #15803D secondary) and align the
dark on-surface-variant alpha; accent green now varies per theme
* chore: remove accidentally committed local tooling directory
Drop the .claude/ worktree snapshot from the branch (a stale local copy
of the repo, no private content) and gitignore the directory. Also
remove the private deploy mapping (.firebaserc) from the public app.
* fix: soften detail header action icons to on-surface-variant
* fix: center-crop the Dart tab logo instead of letterboxing
* fix: replace Dart tab logo with the square Dart mark in grayscale
* feat(playground): live Dart editing and complete DSL examples
Every widget example now ships real Stac DSL beside its JSON, and the Dart
pane is a first-class editor rather than a read-only reference.
- Fill in all 42 placeholder lib/dsl files from their JSON sources. 36
round-trip to their asset exactly; the rest differ only by no-op keys the
DSL drops and null placeholders for empty {} actions.
- Add a DSL-subset parser (data/dsl_to_json.dart) so editing Dart drives the
live preview. `stac build` needs a Dart VM to execute the screen and call
toJson(), which the web runtime cannot do, so the parser maps the
declarative constructor tree to JSON structurally instead. Source that
needs evaluation (helper functions) keeps the last good preview and says
why. Covered by tests across all 77 examples.
- Default the editor to Dart, and make it editable.
- Approximate VS Code semantic highlighting for Dart: types, parameters,
members and calls are no longer plain foreground text.
- Fix the Code Diff toggle's selected background not filling its height.
- Rename the index sections to EXAMPLES and WIDGETS.
- Swap phosphor_flutter for phosphoricons_flutter (2.1.0 extends IconData,
final as of Flutter 3.44) and bump re_editor to 0.10.0 for the current
TextInputClient contract; both broke the build.
* fix(playground): inline helper calls when previewing Dart
The DSL parser rejected any function call, so editing hello_stac or
form_screen — the first two screens in the index — showed "needs
evaluation" instead of updating the preview, because both build their
content through private helpers (_socialRow, _fieldDecoration).
Resolve calls to single-expression top-level helpers by binding the
arguments to the parameter names and parsing the helper's returned
expression in that scope, with a depth guard for self-recursion. Handles
no-arg, positional and named signatures, which covers every helper in the
examples.
All 77 DSL files now parse (navigation and table included); the 36 that
reproduce their JSON asset exactly still do. Variables, conditionals and
interpolation still report that they need a Dart runtime.
* refactor: promote stac_playground out of examples
The playground is the public sandbox for Stac, not a sample app, so move it
to the repository root and register it with melos directly. Its package path
dependencies drop one level accordingly.
stac_gallery is gone as of the playground merge; this also clears the stale
working copy left behind on disk.
* ci: make analyze and format pass for stac_playground
`dart analyze .` fails on info-level lints, and the playground reported 176:
- Exclude the vendored JSON editor. Its lexer, scanner and linked-list
utilities are derived from the Dart SDK and are better kept close to
upstream than restyled; only JsonElement is still used from it, the editor
widget itself having been superseded by re_editor.
- Exclude build/. lib/dsl ships as an asset bundle, so Flutter copies every
example in there and each one was reported several times over.
- Migrate the theme off deprecated ColorScheme.background/onBackground and
surfaceVariant, AppBarTheme.color and TooltipThemeData.height. The app
reads its palette through the AppColors extension, not ColorScheme, so
behaviour is unchanged.
- Silence deprecated_member_use in the bottom_nav_bar example, whose JSON
intentionally uses the deprecated navigation types.
Formatting was drifting in three files, and stac_playground's lockfile did
not match a melos bootstrap, which is what the format job compares against.
* fix(playground): address review findings
Two of these break only on a case-sensitive filesystem, which nothing
currently exercises — no CI job builds the playground.
- Recase 84 platform and asset files (AndroidManifest.xml, ios/Runner/**,
CMakeLists.txt, web/icons/Icon-*.png, ...). Every embedded reference in
the pbxproj files, Podfiles and CMake lists already used the capitalised
names, so these were pointing at paths that do not exist off macOS; the
fix is renames only, no content edits. Two were live bugs rather than
latent: pubspec declares assets/fonts/Figtree.ttf against a committed
figtree.ttf, and web/index.html and manifest.json ask for Icon-*.png,
which Firebase Hosting serves case-sensitively.
- Repoint refresh_indicator at stac_playground/assets/json/list_view_example.json.
It fetched the copy under examples/stac_gallery, which this branch deletes,
so it would have 404'd on merge. The moved file is byte-identical. A local
asset path is not an option: networkWidget goes through Dio over HTTP.
- Drop the vendored JSON editor (22 files). Only JsonElement escaped the
directory, and it was a lossy Map -> Map round trip: every caller decoded
toPrettyString() and re-encoded, while the wrapper silently dropped keys
whose value was null and rendered whole doubles as ints. HomeState now
carries a plain Map. This also retires the missing Dart SDK BSD notices on
scanner.dart, link.dart and link_implementation.dart, and lets the analyzer
exclusion go.
- Treat $ as literal inside raw strings in the DSL parser.
- Point the image example at assets that exist; the three it referenced were
never in the repo.
- Refresh the stale gallery references in the example README and launch.json,
and drop an unrelated movie_app file.
* fix(playground): give empty DSL actions a real no-op action
The 40 `null /* TODO: {} */` placeholders were not equivalent to the `{}` the
source JSON carries. StacAction.fromJson({}) returns a non-null action, and
parsers branch on `model.onPressed == null` — so the elevated_button example,
which contrasts rows with and without an action, rendered every button
disabled from the Dart tab while the JSON tab showed half of them enabled.
Use `StacAction()` for an empty action and `StacAction(jsonData: {...})` for
the four that carry a raw action map, and teach the DSL parser that
StacAction serializes as its jsonData rather than as a wrapper around it.
Examples reproducing their JSON asset exactly go from 36 to 48.
* perf(playground): debounce the live preview
Every keystroke reparsed the whole source and rebuilt the Stac tree, which is
wasted work on the larger examples — backdrop_filter is 62 nodes. Coalesce
bursts of typing behind a 200ms timer, cancelled on dispose.
The dirty indicator still updates immediately, so only the parse and re-render
wait for typing to settle.
* feat(playground): render the real webView example, fix docs and add a build job
The web_view example shipped a placeholder because StacWebView lives in the
stac_webview plugin rather than stac_core. The gallery it replaced depended on
that plugin and registered its parser, so restore the same arrangement: the DSL
now reads StacWebView(url: ...) and round-trips to its JSON asset exactly,
bringing the examples that match byte for byte to 49.
Registration is skipped on web. webview_flutter supports android, iOS and macOS
only, and the widget builds its controller in initState — outside the
framework's try/catch — so registering it there would render a Flutter error box
in the preview. Left unregistered, Stac logs an unsupported-type warning and
degrades quietly, while mobile and macOS get a working webview.
Also correct four docs pages that referenced a StacNetworkRequestAction class
that does not exist (it is StacNetworkRequest) and an "actionType": "request"
that should be "networkRequest".
Add a build_playground CI job. Nothing built this app, which is how the
lowercased platform paths and the missing font asset went unnoticed; running it
on Linux is also what catches casing that only works on a case-insensitive
filesystem.
* fix(playground): render inline samples that are const maps
form_screen (and any inline-sample entry) showed "Stac Parse Error" cards on
its buttons — TypeError: ImmutableMap<dynamic, dynamic> is not a subtype of
Map<String, dynamic>.
The inline previews (helloStacSample, formSample) are const map literals, so
their nested maps — empty {} action maps especially — are typed
<dynamic, dynamic>. Stac's generated fromJson does
`json['child'] as Map<String, dynamic>`, which rejects them. The live DSL and
JSON editor paths were unaffected because both produce real Map<String,dynamic>
trees (the parser builds them, jsonDecode returns them); only the const samples
hit it.
Round-trip the samples through jsonDecode(jsonEncode(...)) before they become
jsonData, which rebuilds every node as Map<String,dynamic>/List<dynamic>.
Verified the buttons render with zero parse errors on both the VM and a real
browser (flutter test --platform chrome).
* chore(assets): update Stac Playground social banner
Replace assets/playground.png with the new 1200x630 Stac Playground banner,
used as the og:image / twitter:image for the playground web app.
* feat(playground): show per-entry icons in the desktop index
The desktop index rendered a uniform brackets icon for every row while the
mobile list showed each entry's own icon. Render the entry icon through Stac's
icon parser on desktop too (same path as mobile), so the two stay in sync.
* refactor(playground): drop the tablet and desktop preview sizes
The preview only needs the mobile frame, so remove the device selector from
the toolbar. Nothing else read the device, so the PreviewDevice enum, the
HomeState field and setDevice go with it rather than leaving the enum wired to
a control that no longer exists; the frame now uses the mobile size directly.
* refactor(playground): build the index row from ListTile
The row was a hand-rolled InkWell + Container + Row that mapped exactly onto
ListTile's leading/title/trailing slots, so use the real thing: the selected
state now carries proper semantics for screen readers, and the label grows with
the OS text scale instead of clipping against a hard-coded 24px height.
Keeping the IDE-style density does cost a block of overrides, since ListTile's
Material defaults are much roomier than a 24px file-list row.
---------
Co-authored-by: Divyanshu Bhargava <divyanshub024@gmail.com>
|
Important Review skippedToo many files! This PR contains 279 files, which is 129 over the limit of 150. To get a review, narrow the scope: Upgrade to a paid plan to raise the limit. This review couldn't start because sufficient usage credits or metered capacity aren't available. Add credits or update usage-based reviews in the billing tab, then retry. ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: ⛔ Files ignored due to path filters (55)
📒 Files selected for processing (301)
You can disable this status message by setting the ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
fix: move dark theme toggle to the end of the mobile drawer
feat: restore per-component icons in the mobile explore list
Carry each gallery entry's original material/cupertino icon through the registry and render it via Stac's icon parser inside the card chip; fall back to the square glyph when an entry has no icon.
fix: show result count label while searching the explore list
feat: full-screen menu overlay and exact Figma theme tokens
Drop the .claude/ worktree snapshot from the branch (a stale local copy of the repo, no private content) and gitignore the directory. Also remove the private deploy mapping (.firebaserc) from the public app.
fix: soften detail header action icons to on-surface-variant
fix: center-crop the Dart tab logo instead of letterboxing
fix: replace Dart tab logo with the square Dart mark in grayscale
feat(playground): live Dart editing and complete DSL examples
Every widget example now ships real Stac DSL beside its JSON, and the Dart pane is a first-class editor rather than a read-only reference.
stac buildneeds a Dart VM to execute the screen and call toJson(), which the web runtime cannot do, so the parser maps the declarative constructor tree to JSON structurally instead. Source that needs evaluation (helper functions) keeps the last good preview and says why. Covered by tests across all 77 examples.The DSL parser rejected any function call, so editing hello_stac or form_screen — the first two screens in the index — showed "needs evaluation" instead of updating the preview, because both build their content through private helpers (_socialRow, _fieldDecoration).
Resolve calls to single-expression top-level helpers by binding the arguments to the parameter names and parsing the helper's returned expression in that scope, with a depth guard for self-recursion. Handles no-arg, positional and named signatures, which covers every helper in the examples.
All 77 DSL files now parse (navigation and table included); the 36 that reproduce their JSON asset exactly still do. Variables, conditionals and interpolation still report that they need a Dart runtime.
The playground is the public sandbox for Stac, not a sample app, so move it to the repository root and register it with melos directly. Its package path dependencies drop one level accordingly.
stac_gallery is gone as of the playground merge; this also clears the stale working copy left behind on disk.
dart analyze .fails on info-level lints, and the playground reported 176:Formatting was drifting in three files, and stac_playground's lockfile did not match a melos bootstrap, which is what the format job compares against.
Two of these break only on a case-sensitive filesystem, which nothing currently exercises — no CI job builds the playground.
Recase 84 platform and asset files (AndroidManifest.xml, ios/Runner/**, CMakeLists.txt, web/icons/Icon-.png, ...). Every embedded reference in the pbxproj files, Podfiles and CMake lists already used the capitalised names, so these were pointing at paths that do not exist off macOS; the fix is renames only, no content edits. Two were live bugs rather than latent: pubspec declares assets/fonts/Figtree.ttf against a committed figtree.ttf, and web/index.html and manifest.json ask for Icon-.png, which Firebase Hosting serves case-sensitively.
Repoint refresh_indicator at stac_playground/assets/json/list_view_example.json. It fetched the copy under examples/stac_gallery, which this branch deletes, so it would have 404'd on merge. The moved file is byte-identical. A local asset path is not an option: networkWidget goes through Dio over HTTP.
Drop the vendored JSON editor (22 files). Only JsonElement escaped the directory, and it was a lossy Map -> Map round trip: every caller decoded toPrettyString() and re-encoded, while the wrapper silently dropped keys whose value was null and rendered whole doubles as ints. HomeState now carries a plain Map. This also retires the missing Dart SDK BSD notices on scanner.dart, link.dart and link_implementation.dart, and lets the analyzer exclusion go.
Treat $ as literal inside raw strings in the DSL parser.
Point the image example at assets that exist; the three it referenced were never in the repo.
Refresh the stale gallery references in the example README and launch.json, and drop an unrelated movie_app file.
The 40
null /* TODO: {} */placeholders were not equivalent to the{}the source JSON carries. StacAction.fromJson({}) returns a non-null action, and parsers branch onmodel.onPressed == null— so the elevated_button example, which contrasts rows with and without an action, rendered every button disabled from the Dart tab while the JSON tab showed half of them enabled.Use
StacAction()for an empty action andStacAction(jsonData: {...})for the four that carry a raw action map, and teach the DSL parser that StacAction serializes as its jsonData rather than as a wrapper around it.Examples reproducing their JSON asset exactly go from 36 to 48.
Every keystroke reparsed the whole source and rebuilt the Stac tree, which is wasted work on the larger examples — backdrop_filter is 62 nodes. Coalesce bursts of typing behind a 200ms timer, cancelled on dispose.
The dirty indicator still updates immediately, so only the parse and re-render wait for typing to settle.
The web_view example shipped a placeholder because StacWebView lives in the stac_webview plugin rather than stac_core. The gallery it replaced depended on that plugin and registered its parser, so restore the same arrangement: the DSL now reads StacWebView(url: ...) and round-trips to its JSON asset exactly, bringing the examples that match byte for byte to 49.
Registration is skipped on web. webview_flutter supports android, iOS and macOS only, and the widget builds its controller in initState — outside the framework's try/catch — so registering it there would render a Flutter error box in the preview. Left unregistered, Stac logs an unsupported-type warning and degrades quietly, while mobile and macOS get a working webview.
Also correct four docs pages that referenced a StacNetworkRequestAction class that does not exist (it is StacNetworkRequest) and an "actionType": "request" that should be "networkRequest".
Add a build_playground CI job. Nothing built this app, which is how the lowercased platform paths and the missing font asset went unnoticed; running it on Linux is also what catches casing that only works on a case-insensitive filesystem.
form_screen (and any inline-sample entry) showed "Stac Parse Error" cards on its buttons — TypeError: ImmutableMap<dynamic, dynamic> is not a subtype of Map<String, dynamic>.
The inline previews (helloStacSample, formSample) are const map literals, so their nested maps — empty {} action maps especially — are typed <dynamic, dynamic>. Stac's generated fromJson does
json['child'] as Map<String, dynamic>, which rejects them. The live DSL and JSON editor paths were unaffected because both produce real Map<String,dynamic> trees (the parser builds them, jsonDecode returns them); only the const samples hit it.Round-trip the samples through jsonDecode(jsonEncode(...)) before they become jsonData, which rebuilds every node as Map<String,dynamic>/List. Verified the buttons render with zero parse errors on both the VM and a real browser (flutter test --platform chrome).
Replace assets/playground.png with the new 1200x630 Stac Playground banner, used as the og:image / twitter:image for the playground web app.
The desktop index rendered a uniform brackets icon for every row while the mobile list showed each entry's own icon. Render the entry icon through Stac's icon parser on desktop too (same path as mobile), so the two stay in sync.
The preview only needs the mobile frame, so remove the device selector from the toolbar. Nothing else read the device, so the PreviewDevice enum, the HomeState field and setDevice go with it rather than leaving the enum wired to a control that no longer exists; the frame now uses the mobile size directly.
The row was a hand-rolled InkWell + Container + Row that mapped exactly onto ListTile's leading/title/trailing slots, so use the real thing: the selected state now carries proper semantics for screen readers, and the label grows with the OS text scale instead of clipping against a hard-coded 24px height.
Keeping the IDE-style density does cost a block of overrides, since ListTile's Material defaults are much roomier than a 24px file-list row.
Description
Related Issues
Closes #
Type of Change