Skip to content

BlueVue: Grow the package into a BlueOS extension kit - #2

Merged
ArturoManzoli merged 12 commits into
masterfrom
extension-kit
Aug 14, 2026
Merged

BlueVue: Grow the package into a BlueOS extension kit#2
ArturoManzoli merged 12 commits into
masterfrom
extension-kit

Conversation

@ArturoManzoli

@ArturoManzoli ArturoManzoli commented Aug 13, 2026

Copy link
Copy Markdown
Collaborator
  • Turns the package from a set of controls into the kit an extension is written with: BlueApp paints the backdrop, centres a card and mounts the notice bar and the blocking wait, so a page raises either from anywhere without wiring them.
  • Adds the primitives everything else is built on: BlueButton, BlueIcon, BlueTooltip, BlueSpinner, BlueProgressBar.
  • Puts every dialog on one surface, BlueDialog, and adds BlueConfirmDialog and BlueStepsDialog beside the prompt and loading ones, which now build on it too.
  • Completes the form vocabulary: BlueCheckbox, BlueRadioGroup, BlueTextarea, BlueTabs, BlueTable, BlueChip, BlueFileDrop, BlueWindRose.
  • Reaches BlueOS without configuring anything: blueOsService wraps a service by name, useBlueOs reads the vehicle's name, version, primary colour, dark and pirate mode, and useBlueOsSetting keeps a value on the vehicle rather than in whichever browser opened the extension.
  • BlueApp takes the vehicle's primary colour unless the page asks it not to.
  • npx @bluerobotics/bluevue <name> copies a Vite frontend already wired to the kit, a FastAPI backend that answers /register_service with relative paths, a Dockerfile carrying the labels BlueOS installs from, and a GitHub workflow that builds the image.
  • Turns the playground into the documentation site published at bluerobotics.github.io/BlueVue: a gallery of live components on the front page, and a page per component with what it is for, when to reach for it, a runnable demo and its API.
  • Nothing from 0.1.1 was removed or renamed, so the version goes to 0.2.0 and existing consumers are untouched.

The pieces every extension reaches for and had to borrow from a UI framework
until now. A button with no colour of its own is a secondary action and reads as
a barely-there fill, the filled one is what the panel is asking for, and out of
reach either becomes the same flat grey chip; an icon is a square box rather
than a glyph, so a row of them lines up; and the tooltip opens in the top layer,
where a panel clipping its own overflow cannot cut it off.
The controls each carried their own hover panel, absolutely positioned inside a
row that clips what overflows it and stacked against the page with a z-index of
its own. One component now owns all of them, and the top layer places it, so a
hint at the edge of a panel is no longer cut off by it.
The gallery is the front page, every component live on the surface it was drawn
for, and each card opens a page saying what the component is, when to reach for
it and what it takes, with a snippet to paste. One view renders every page from
a catalogue entry, so documenting a new component is a demo and a data entry
rather than a page of its own. Routing is by hash and the site is deployed to
Pages on every push to master, since a project page has no rewrite rule to make
a deep link resolve.
A dialog is now a panel with a header, a body and a footer, and the prompt and
loading overlays are two arrangements of it rather than two copies of the same
native modal handling. Two more arrangements come with it: a confirmation for
anything that cannot be taken back, and a job report for work with stages to
it, whose log follows its own tail unless the reader has scrolled up to read
something.
Three ways of telling the reader something, which every extension writes for
itself today. Notices are raised from wherever they happen and rendered by one
bar at the root, where a failure waits to be dismissed and a repeat counts up
instead of stacking; the blocking wait is one piece of state, so two operations
cannot each raise their own; and the banner, built for the SITL manager, comes
along with the group that lays a row of them out.
An extension now starts as one component: BlueApp paints BlueOS's backdrop,
centres a card on it and mounts the notice bar and the blocking wait, so a page
raises either from anywhere without wiring them. Under it are the pieces that
card is filled with, a section for a subject and a stat for a fact, plus the
theme call that repaints the tokens in an extension's own colours and the two
file helpers every configuration page ends up writing.
The controls an extension reaches for once it is past a few fields: a checkbox
and a radio group for the choices a switch and a button track cannot phrase, a
textarea for what does not fit on one line, tabs for a view with several pages,
a table that orders itself, a chip for a state worth naming, and a zone that
takes a file by drop or by picker. Each of them is a page in the docs beside
the ones already there.
An extension is served from BlueOS's own origin, so blueOsService wraps a
service by name and a relative path finds it, with a host override for the one
case that has no vehicle behind it, a page being developed. Over that sit the
two things a page wants: what the vehicle calls itself, and a setting kept on
the vehicle rather than in whichever browser happened to open the extension.
The readme now opens on what an extension gets, points at the gallery for the
live version of each component, and lists everything the package exports under
the part of the page it belongs to.
The package is now a kit rather than a set of controls: a page shell, the
dialogs and notices, the rest of the form vocabulary, and the calls that reach
BlueOS. Nothing that was in 0.1.1 was taken away or renamed.
npx @bluerobotics/bluevue <name> copies a Vite frontend already wired to the
kit, a FastAPI backend that answers /register_service with relative paths, a
Dockerfile carrying the labels BlueOS installs from, and a GitHub workflow
that builds the image. The generated page is a BlueApp, so notices and waits
work from the first line.
BlueApp takes the primary the vehicle is painted in unless the page asks it
not to, so an extension sits in the same palette as the rest of BlueOS. Dark
and pirate mode come along as flags, for anything an extension only shows when
the vehicle itself would. Each field stays at its default when that particular
call fails, so a page opened off the vehicle still renders.
@ArturoManzoli
ArturoManzoli merged commit 381fd4f into master Aug 14, 2026
1 check passed
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