Skip to content

feat(settings,home): rework the settings and the rail from the design - #1519

Draft
lollipopkit wants to merge 47 commits into
mainfrom
feat/settings-from-design
Draft

lollipopkit wants to merge 47 commits into
mainfrom
feat/settings-from-design

Conversation

@lollipopkit

@lollipopkit lollipopkit commented Sep 19, 2026

Copy link
Copy Markdown
Owner
image

Settings become a surface beside the rail rather than a route over it; the rail is laid out here at 55pt an item; the form is named groups in two columns, and the search looks through the rows themselves.

fl_lib: lollipopkit/fl_lib@eeca4e8

The settings are shown where a tab is shown rather than pushed over the
whole window, which used to take away the rail they were reached from. The
rail itself is laid out here rather than by `NavigationRail`, at 55pt an item
against 88: its vertical spacing is private to the M3 implementation, and the
connection count now hangs off the indicator's corner instead of the glyph.

The form is named groups — one card each, with the rows that were folded
behind tiles called "More" under a heading that says what they are — laid out
in two columns. Every row carries the label the search reads, so the search
looks through the settings themselves and draws what it finds as the row it
is: a switch found by searching is a switch.
@coderabbitai

coderabbitai Bot commented Sep 19, 2026

Copy link
Copy Markdown
Contributor

Important

Draft PR not reviewed

Draft PRs are not automatically reviewed by default.

  • Trigger a manual review

To automatically review draft PRs, update your CodeRabbit configuration:

reviews:
  auto_review:
    drafts: true

Comment @coderabbitai help to get the list of available commands.

Shut it is an icon in a pill and nothing else — 39pt an item against 55,
with the name as its tooltip — and it opens over the tab beside it rather
than widening the column, so a tab is never laid out to two widths.

The pill's geometry is read off the animation and only its fill is implicit:
an `AnimatedContainer` easing the width towards this frame's number while the
row inside was already laid out for it is a `RenderFlex` overflow, reported
with a whole widget tree on every frame of the opening. Nothing fades through
an `Opacity` either — two `saveLayer`s an item, sixty times a second, is what
made opening it stutter.
Four things about an item differed between the two shapes by a point or
three — the pill's height, its padding, the glyph's size and the gap under
it — so every frame re-rasterised the icon a fraction smaller and a fraction
further along. A filled glyph on a filled pill shows that as crawling rather
than as sliding, which is why only the selected one looked wrong.

The pill's width is the only measurement the opening changes now. The badge
hangs off the glyph rather than off the pill's far edge, which travels 124
points and used to take the badge with it, across the name arriving under it.
Which item is lit crosses over on its own animation — the fill, both colours
and the weight together — rather than the fill easing under a label that
snapped.
…e rest as rows

The four rings are gone. A card is now what the detail page is at a
smaller size: the reading that matters drawn as a headline and a window
of it, with everything else as a labelled bar underneath — so what is on
a card is what opening it shows more of rather than a summary of
something else.

Tapping a row promotes it, which is the one thing a card lets you do to
it without leaving the list. The choice is kept per server, because the
answer differs per machine: a database is watched for its disk and a
build box for its CPU.

Which rows appear is fixed — CPU, memory, disk, one varying slot, network
— so the numbers line up down a column of six cards. The varying slot
goes to whatever is over the line first, then to what this machine has
and most do not, and a machine reporting more than fits says how many
rather than growing taller than its neighbours.

The chart series get the palette the board recommends: the set they
replace had CPU and disk read one hue step apart, and a memory green
brighter than the CPU blue on a dark background, so an overlay was
always green over blue whatever the numbers said. They live in one place
now instead of three.
The server tab and a server's own page were two pages, reached by
pushing one over the other or by putting a pane beside it. They are one
now: tapping a card gives it the width of the page while the rest of the
grid makes way, and what is on screen is still the list with one of its
cards open.

So the pane, the rail of rows beside it and the flight that carried a
card into it are all gone, and with them the two layouts the page had to
answer for. What is left is the grid at every width, plus a strip of the
other machines over the open one and a switcher in the bar for when
there are more of them than pills that fit.

The detail's own chrome arrives once the card has stopped growing and
leaves before it starts shrinking, so only one thing is ever moving; the
card and the page it becomes are the same shape by then — one reading
drawn large over the rest as rows — which is what the crossing between
them has to carry.

A narrow window still pushes: one column has nothing to grow into.
The space below a short list of servers was blank. The question it
leaves is not about any one machine — whether anything has happened —
so it now carries four totals over the list as filtered (up, over the
line, memory, traffic) and the last day's connection attempts.

Connection attempts because that table is the only thing in the app that
records when something happened. A reading crossing its threshold is on
the card it belongs to and in the count above; nothing keeps a history
of when it crossed, so nothing here claims to.
A list of forty servers was forty cards. It is now a line each, or a
tile each, and which of the three it is follows the count unless the
user says otherwise — per tag, because a tag is a set of machines and
#prod with forty in it wants a different answer from #local with two.

The shapes share the card's own vocabulary rather than being three
layouts: the same reading is drawn in each, at the size each has room
for, and opening one still grows it into the page. Past a text scale of
1 the tightest is ruled out, since a name in a 44pt tile is the first
thing to stop fitting.

Every card's height is animated now, which is what a list of them
needed anyway: a server connecting, a reading promoted or a row arriving
used to move every card below it between one frame and the next.
A long press flipped a card over to four power buttons; a right-click
did the same; the other two densities had nothing at all. There is one
set now — edit, whatever this server can be used for, copy, share,
connect or disconnect, power, delete — in one order, raised as a popup
where the pointer is, and as a sheet at the bottom of a phone, where the
middle of the screen is the card being acted on and the top half is out
of a thumb's reach.

What a server can be used for is the function row's own list, run
through the same runServerFunc: a Terminal that behaves differently
depending on where it was opened from is two features.
…t say why

CPU, alerts first and uptime — the three an operator reaches for, and
the three the old set could not express. Alerts first is a partition
rather than a comparison, since 'what is wrong, last' is not something
anyone wants, and only the stored arrangement may be dragged into
another one: a drag under a comparison moves a card and has the
comparison put it straight back.

An empty page now names what is empty, says why, and offers one way out
— in that order. The three cases were one sentence each and a filter
with nothing under it read as having lost the servers.

The sort no longer watches every server's readings when the field does
not need them, which was a rebuild of the whole page on every poll.
A set is started by holding a modifier and clicking, or — on a device
with nothing to hold — from the menu a long press already opens, whose
first row is now Select. With a set up, the bar becomes the set: how
many of how many, and what can be done to all of them. Which is the
single-machine list minus everything that cannot be done to several:
there is no one terminal for three machines and no one address to copy.

Escape is the way out of both a set and an open machine, and the bracket
keys step through the list without going back to it. Only what acts on
the page as a whole: reaching one machine's actions from the keyboard
needs a card to be focusable first, which is its own piece of work.

Movement follows the platform's own switch for it now: what that asks
for is not stillness but that nothing travel far enough to follow, so a
card that would have grown across the page cross-fades instead.
…a switcher that scales

Promoting a row on a card and promoting one on the page were two pieces
of state, so a database watched for its disk in the list opened onto its
CPU. They are one stored choice now, per machine, read and written by
both.

And the machine switcher is a sheet that can be typed into and is
grouped by tag, rather than a flat list: the strip of pills over an open
card answers this for a handful, and past that they stop fitting. ⌘K
opens it from inside a machine, where the bar's own search is not the
thing wanted.
A card lower down the grid moved to the top of it while the viewport
stayed where it was, so the movement happened off screen. The two travel
together now.

And the test that measures the card's width partway through is what
found that it was not growing at all: it stopped at the width of the
column it had left — see the masonry fix in fl_lib.
… draws them

Nine points of corner against a card's thirteen, next to nothing between
two lines, and the design's five between tiles — so a wall of them reads
as a wall rather than as a grid of little cards.
With a set being built up, tapping a row promoted its reading instead of
adding the machine — the one part of a card that did something other
than what every other part of it did.
…ing handed a picture of themselves

The card grew to its full width and then the page took over at two
thirds of it, because the page keeps 330pt beside the readings for the
facts about the machine. So the chart visibly shrank at the handover and
the whole thing read as a replacement.

The card now lays itself out as the page's readings block at the far end
of the movement: the facts column's width is reserved while it is still
growing, the blocks become cards of their own as the card's own surface
fades away, the readings the card had no room for grow into the list,
and the number travels from the end of the label's line down into a
headline. Every measurement that differs between the two ends is a lerp,
and the line above the chart is a stated height at both ends rather than
whatever is in it — the page puts a window picker up there and the card
has none, which was six points of the page landing lower than the card
had it.

Held by a test that measures the focus label and a row on the last frame
of the card and the first of the page.
A cross-fade cannot, and which way through the list a step went is the
reason a list has an order. The machine being left withdraws the way the
new one came from, shrinking and going faint from the edge it is
travelling towards; the new one comes in from the other side at the same
pace. The pills, the switcher sheet and the bracket keys all feed it the
same direction.

Kept apart from the crossing above it: that one is the card becoming the
page, and this is a movement of its own.
Whether the facts sit beside the readings was answered from the card's
eventual width on one side and from the page's box on the other, and the
two differ by what the page keeps clear at its edges — so a window in
between had the card reserve nothing and the page take 330.
… left to cross

A bar sparkline cannot become a line chart by moving, and that was the
jarring part: the box travelled and grew, and then what was in it was
swapped for something drawn a different way.

The chart is one widget now, pulled out of the detail page into a
library both use — same axis arithmetic, same line, same gutter — and
the card crosses its sparkline over to it while it grows. By the time
the page takes over, what the card is drawing *is* what the page draws,
in the same box, so the crossing has nothing to carry. Held by the same
test that holds the rest of the handover.

The surfaces no longer fade past each other either: the blocks are drawn
on the card's own surface, so both at half strength left the middle of
the movement washed out. The blocks come in over the first half and the
card's surface goes over the second.
The card drew bars and the page drew a line, and the rows were two
widgets built from the same numbers — so however well the boxes were
lined up, the handover still had to swap what was in them, which is what
reads as the page having been rebuilt.

There is one chart now and one row. The chart's chrome — the scale down
the left, the lines across, the padding, the touch — fades in on a
number rather than being switched on, and the gutter it sits in is a
width, so the plot narrows into it instead of the line jumping when it
appears. A card the height of two lines of text shows none of it, which
is what it had before, drawn by the widget the page uses.

Also: the surfaces were lerped towards `ThemeData.cardColor`, which is
the Material 2 field and a step darker than the `surfaceContainerLow` a
Card actually resolves to — so the block under the chart came out darker
than both the card around it and the page it was turning into.
… others

Coming back from a machine set the whole grid off: every other card grew
in from nothing and shuffled into place, because they were taken out of
the list while one was open and so left and arrived again. They stay in
it now and fade, their slots held for them, and the inset the growing
card needs comes from its own padding rather than from the grid's —
which would have changed every column's width and slid all of them
sideways.

The strip of machines is lined up with the page under it: it is a row of
the list that has made way, so its first pill starts where the cards
start rather than five points from the window.
A button brings 7 of its own and the switcher label holds its glyph 14
off the edge, so the first thing in the bar moved left by half that
whenever a machine was open.
The card no longer turns over: every density raises the same menu at the
row, line or tile, which stays where it is and goes the highlight colour
so the menu's position reads as "this one". A tile is too small to say
which machine, so its menu carries a head; a single column under a finger
gets the sheet. The function row is out of the menu — it is on the
machine's own page, and a dozen entries that open a page sat above the
four that act on the record.
…icked

Oklch: the first series is the theme colour at the one lightness this
theme reads at, the other five fan out 60 degrees apart at 72% of the
chroma the first actually got. A fixed palette beside a seed the user
chose was six colours that had nothing to do with it — the accent ended
up the one colour no chart used. Device colours stay fixed: there the
colour is which disk, not which reading.
…rest are a tint

A reading no longer carries a colour: what it is drawn in depends on
whether it is the one drawn in full above the others, which is not
something a reading knows about itself. Two dozen machines each in the
hue of whatever it happens to promote is two dozen hues that say
nothing — the eye is comparing how high the bars are, and which reading
each one is, is written beside it.
…rule

A reading carries no colour anywhere now: the detail page asks whether
it is the one in focus, the same question the card asks, through one
ChartPalette.reading — a card grows into that page, and a reading that
changed colour at the handover reads as a different reading. A chart
with two lines falls back to the fixed palette, where the colour is
saying which line rather than which is watched. The fleet strip is one
colour for all three bars: they are lengths to compare, each already
named at its own head.
…ment

The bulk bar's missing action. Dragging is how one server is moved, and
forty is where dragging stops being a way to do anything. Both ends and
nothing between: a position to insert at is a number nobody has. It
switches the sort back to manual, since under a comparison the move
would have nothing to show and read as having failed.
…keeps its own view

A switch under the five sort options, orthogonal to them: an order is
which machine comes first, grouping is which are read together. A
masonry per section rather than headings inside one, since a heading
spans the row and a masonry lays its children into columns.

The order and the grouping are now remembered per tag, as the density
already was — forty machines under #prod want busiest-first, two under
#local want the arrangement they were given. An install that chose an
order before this has that answer read as the answer for the list with
no tag on it.
4a·2·C. A tile has room for one bar, and the question was which reading
gets it — the answer is that none does: a box at 4% CPU with a full disk
is not idle. The three are laid end to end, memory and disk at half
weight because they sit high all day while the CPU is what moves, and a
machine carrying everything at once runs past the end and is clipped.
Full is full; a view asking which one is under load owes no distinction
between loaded and more loaded.
…, not swapping them

ShapeCross fades one over the other at a height between the two, so a
row growing into a card is part of the movement rather than a frame
where everything below it jumps. The grid is handed a MasonryMemory, so
the way back out places the cards under the open one where they will
land instead of where the expanded card left them.
…place

3a·1. A line's right column is the state and the one thing to do about
it, through the same conn mapping the card's title row uses — a chevron
said only that a row opens, and said it forty times. The middle of a
line with no bar to draw is a progress line, or what the far end
actually said: "Connection refused" against "No route to host" is the
difference between a machine to look at now and one to look at later.

A tile's one word is short enough to fit beside a name and coloured, and
its bar greys with the readings when sampling stops. A card fills over
377ms with its blocks arriving 20ms apart, so a machine answering is one
movement rather than a box growing and then filling.
@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Sep 20, 2026

Copy link
Copy Markdown

Deploying sbmd with  Cloudflare Pages  Cloudflare Pages

Latest commit: a909626
Status:🚫  Build failed.

View logs

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Sep 20, 2026

Copy link
Copy Markdown

Deploying serverbox with  Cloudflare Pages  Cloudflare Pages

Latest commit: aaf8045
Status:🚫  Build failed.

View logs

A card's readings fill block by block when its machine first answers,
and that ran whenever the blocks were mounted. Opening a machine in
place mounts them again three times: the grid is dropped while the page
has the readings and mounted for the way back, the open card's body went
into a Row at any openness above 0, and every other card was wrapped to
be faded and unwrapped after. So the readings went out and came back
before the card started shrinking, and again once it had landed.

The clock is the card's now (_Arrival), started by the readings arriving
on a card that was on screen without them. A card mounted with readings
already had them.

The same branch-at-the-end pattern was in four more places, each a
different parent on the first or last frame of the movement:

- the function bar, which HideOnScroll keeps off screen for the first
  frames after a mount, so it blinked as the card started to shrink
- the strip, whose pills lost their scroll position and faded edges
- the detail page's facts and tables, rebuilt and laid out again
- RefreshIndicator around the body on mobile, toggled by the selection

All five keep one structure throughout; at rest the layers cost nothing.
…side its name

The rows under the reading drawn in full are folded by default and a
press on the line under them unfolds them, remembered per server in
serverCardExpanded. Kept in the store rather than in the card: the grid
is dropped while a machine is open and mounted again on the way back, so
a card that remembered it for itself came back folded from every visit.

Pressing a row was the only way to choose what is drawn in full, and a
folded card has no rows. A control beside the reading's name raises the
rest of them, each with what it reads now, including the ones the card
has no slot for. It writes the same ServerPromoted a row does.

The count on that line is what is not drawn, rather than what did not
fit in the five slots: a reading promoted from outside them is on screen
and was still being counted.
…is what "UI Fold" says

Folded, the control is at the end of the line under the chart instead of
on a line of its own under a rule, which was a third of the card's
height spent on saying there is more. The note starts at the left then,
because it is sharing the line. Unfolded, the line is the note's alone
and it travels to the middle while the control closes beside it and the
card grows, all over one stretch on one curve. The line's height is
stated, so the control arriving or leaving does not move the text.

What a card nobody has touched rests at is collapseUIDefault rather than
always folded. The list of unfolded ids could not say "follow the
setting", so it is a map of what somebody has said about a server
(serverCardExpandedOverride) and absent means the setting. A press that
puts a card back to the setting removes its entry: an entry would hold
that one card against the setting being switched later. The tab listens
for the setting, being kept alive behind the page that changes it.

serverCardExpanded was never pushed, so there is nothing to migrate.
…t is narrow

Below 760 the three bars become one: CPU, memory and disk laid end to
end at the weights a tile in the list draws a machine with, so the bar
over the list can be read against the bars in it. They used to be
dropped instead, memory and then the disk, and a phone was told about
the processors and nothing else. The names are in the colours of their
stretches; the numbers go from the right as the width does and the bar
stays, which is how a line in the list shares its bar.

The bar was a private method of ServerCard. It is PressureBar now, with
pressureOf for shares that are not one machine's readings, so the tile,
the line and the strip are one implementation of one reading.

The control at the right is a dot and the way in rather than a count.
The count was of a list capped at three, so it said "+3" on every
install with a day behind it; what a line with no room for words most
needs to say is how the last thing went. A reading over its line
outranks that, and the list then opens with which one, since a dot
that opened onto connections that went fine had not said why it was
amber. With room for the words the dot is at the head of them and the
control keeps only the way in.
…s white

Btn.icon took the ambient IconTheme's colour, which this app's theme
leaves at ThemeData's default: pure white on dark. The four buttons at
the right of the server tab's bar were brighter than the switcher and
the segmented control beside them, which both ask for onSurfaceVariant.
Fixed in fl_lib (f549786), where it is wrong for every bar that uses
one.
Cards while they all fit, a line each while those do, and a tile each
after. It was the count alone, six and twenty-four, which is what one
desktop window of about 1200 by 800 holds, so every other window got
that window's answer: a wide one went to lines with room for a dozen
more cards, and a phone kept cards it could show two of.

Columns by the masonry's own rule, and how tall a card is by whether
cards rest folded ("UI Fold") rather than by each card's own state: a
press that unfolds one card must not be what turns the list into lines.
One column is given a second screen of cards, or a phone would hardly
ever be given any. The two heights are held against a card as drawn by
a test; the first guess at the unfolded one was fifty points short.

The grid is where the list's size is known, so it resolves the density
there and tells the bar what auto came to once the frame is over. The
bar's button and the sheet's "Auto · N → X" say that rather than asking
again with a different box.
The density control rests as the position it is set to and opens to all
four under a pointer (SegmentedTabs.collapse, fl_lib 0337b2c). It is
changed once in a while and sits beside things used all the time: four
labelled positions were the widest and the brightest thing in the bar,
to say what one of them says. The room for all four is still what
decides between this and the button, because it opens where it stands.
A spinner in the action slot and a progress line under the title were
the same answer twice, which a line in the list already declines to do
by giving up its spinner for the line across its middle. The card keeps
the spinner.

The card was held to 30 tall, from when that line made up the
difference. The title is 23, so without it the other 7 sat under the
title as a gap with nothing in it: the inset over the name and half as
much again below, on every card with nothing to report. It is as tall
as what is in it now.
…hing in it

A reading the history does not keep, or a machine nothing has been
polled from yet, has a number and nothing to plot. The card held the
chart's 44 points and the gap over them anyway, and a box with nothing
in it reads as a chart that failed to load. Only at rest: the page has
a chart's room whatever is in it, so the box grows from nothing on the
way there, the way the rows that are not on the card do.

One sample is enough. MetricChart draws a lone sample as a point, since
no line can be drawn through one and with the dots off the first poll's
worth of a machine was an empty plot until the second arrived. Holding
out for the line would be a poll's wait on every connection. From two
on it is the line, with no dots on it.
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