Skip to content

Two doors, and a way to stop being offered our server (GRYT-894) - #372

Merged
sivert-io merged 3 commits into
mainfrom
claude/GRYT-894-add-server-redesign
Sep 3, 2026
Merged

Two doors, and a way to stop being offered our server (GRYT-894)#372
sivert-io merged 3 commits into
mainfrom
claude/GRYT-894-add-server-redesign

Conversation

@sivert-io

@sivert-io sivert-io commented Sep 3, 2026

Copy link
Copy Markdown
Member

The add-server dialog had never been redesigned. Three shapes were drawn and reviewed; this is the one that was picked.

Create and Join are two cards of equal weight

Joining used to be a label and a full-width button underneath the create row. The comment on the join step says most people arriving here have an invite in their clipboard — so the common path was the buried one.

Only the desktop app sees that screen. step = embeddedServerAvailable ? mode : "join" already sent a browser straight to Join, because there is no embedded server to create with and a door onto a dead end is worse than no door. The web shape is unchanged.

The server we run moved below an or rule

It is a third answer, not a step inside the first one. It stays the only tinted row on the screen, so the eye lands on it without it shouting.

Hiding it

The control is text above the card, not a cross inside it. You called this and you were right: a cross on the row sits inside the target somebody is reaching for, so the press that hides the server and the press that joins it end up a few pixels apart — and one of those is the one nobody wants to hit by accident. "Hide forever" sits at the top right of the card, says what it does, and is nowhere near it.

Moving it out had a second payoff. The first attempt put the cross inside the row and revealed it on hover, which needed the dismiss to be a sibling of the card's hit area rather than a child — a button nested in a button is invalid HTML and the inner one stops firing in Safari. With the control outside the card, the card goes back to being a plain <button> and all of that disappears.

Stored per device through setUserValue, beside the other UI preferences, rather than on the account. Which servers somebody declined is a UI choice, and the identity service has no business learning it.

It leaves one quiet dashed line with "Show it again." Removing every trace would be a trap: this row is the only place the address appears, so somebody who hid it by accident would have nothing to press. One text row against a tinted card is small enough that the thing they asked to stop seeing has stopped being a thing they see.

Checked against a running client

Both paths, on a throwaway server, with the live community.gryt.chat as the offer — it answers now, so this is the real card and the real name:

two doors same size (209×131), one row, same top
below 640px stacked, no horizontal scroll
"Hide forever" flush with the card's right edge, 4px above it, on both the desktop and web screens
hide card gone, officialServerHidden: true written, line appears
show it again card back, preference cleared
nesting the control is not inside the card's button

What to look at

  • "Hide forever" is the wording, not "Dismiss". It is the phrase you used first and it is honest about the permanence; a Dismiss that never comes back would understate itself. Easy to change.
  • The dashed line stays for good, not just for the session. If you would rather the row vanish completely with Settings as the only way back, say so — it is one condition.
  • The or rule and the tint mean the offer reads as a recommendation. That is deliberate, and it is the thing to push back on if it feels like too much for a server with one member on it.

tsc -b and eslint clean.

🤖 Generated with Claude Code

sivert-io and others added 2 commits September 3, 2026 22:23
The add-server dialog had never been redesigned. Three shapes were drawn and
reviewed; this is the one Sivert picked.

**Create and Join are two cards of equal weight.** Joining used to be a label
and a full-width button underneath the create row, which read as an
afterthought — while the comment on the join step says most people arriving
here have an invite in their clipboard. The common path was the buried one.

Only the desktop app sees that screen. `step` already sent a browser straight
to Join, because there is no embedded server to create with and a door onto a
dead end is worse than no door, so the web shape is unchanged.

**The server we run moved below an `or` rule** instead of sitting between the
two paths. It is a third answer, not a step inside the first one, and it stays
the only tinted row on the screen so the eye lands on it without it shouting.

**It can be hidden, and the control is text above the card rather than a cross
inside it.** A cross on the row sits inside the target somebody is reaching
for, so the press that hides the server and the press that joins it end up a
few pixels apart — and one of those is the one nobody wants to hit by accident.
"Hide forever" sits at the top right of the card, says what it does, and is
nowhere near it.

Stored per device through `setUserValue`, beside the other UI preferences,
rather than on the account. Which servers somebody declined is a UI choice and
the identity service has no business learning it.

Hiding it leaves one quiet dashed line with "Show it again". Removing every
trace would be a trap: this row is the only place the address appears, so
somebody who hid it by accident would have nothing to press.

Checked against a running client on both paths, not only typechecked: the two
doors render the same size on one row and stack below 640px with no horizontal
scroll; "Hide forever" sits flush with the card's right edge, four pixels above
it, on the desktop screen and on the web one; hiding removes the card, writes
the preference, and shows the line; "Show it again" brings it back and clears
the preference. The offer is the live community.gryt.chat, which answered.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The second half of the redesign. Both screens were carrying furniture that
explained what you could already see.

**Join.**

The three example chips are the placeholder now, cycling every three seconds.
They answer "is the thing on my clipboard one of these", which is a question
somebody has while the field is empty and never after, so they cost no height
and stop competing with the input for the same glance. Rotation stops the
moment there is anything in the field — text moving under somebody who is
typing is the one thing it must not do — and never starts under
`prefers-reduced-motion`.

Gone with them: the label and the asterisk over the only field on the screen,
the "Examples" heading over three examples, and the row offering to look on
your network. Discovery has had its own tab since GRYT-223; that row was a way
back to something that had already moved.

The preview card says what the server is, in the server's own words, clamped at
two lines. It used to print the member count and the address — the address you
had just typed into the field directly above it. The two facts about a server
now stack on one right edge: whether it costs you an account, then how big it
is. The count wears no chrome and is a size down, because two badges read as
two warnings.

The note to moderators keeps the condition it already had — only a server whose
join policy is `request`, which is the only place there is anybody to read it —
and loses the paragraph explaining why it helps. The label says it.

**The button is the server's answer, not a fixed string.** `Join` on an open
server, `Ask to join` where a person lets people in by hand, `Sign in to join`
where the server takes accounts only and you have none. That last one replaces
a dead end: the old path let you press Join and told you afterwards to "sign in
from the menu at the bottom left, then try again". Disabled is now reserved for
the cases where pressing it could do nothing at all — nothing typed, nothing
answered, or you are already there.

**Create.**

The generated icon sits beside the name it is drawn from rather than centred
above it at 80px, where it pushed the rest of the form out of view to show
something that is a preview rather than the subject of the step. Its caption
went with it: it changes as you type, which says the same thing.

The port field is 7rem, because a port is four characters, and its status sits
beside it on the same line — a status about a value belongs next to the value.
"Available" rather than "Free": on a product surface Free reads as a price.

One alignment bug found by measuring rather than looking: the width class on
`TextField` lands on the input while its wrapper stays full width, so the
status was sitting 256px from the field it describes. The width goes on a
wrapper now, and the gap is 12.

Checked against a running client with the live community.gryt.chat as the
subject: the placeholder cycles and stops on input, the card shows the server's
description with the facts on one right edge and the description clamped at two
lines, and an account-only server with no account gives an enabled "Sign in to
join".

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@sivert-io

sivert-io commented Sep 3, 2026

Copy link
Copy Markdown
Member Author

Second commit on the branch: the two screens behind the doors.

Folded in here rather than stacked on top — a stacked PR would merge into this one and never reach main.

Join

  • The examples became the placeholder, cycling every 3s. They answer "is the thing on my clipboard one of these", which is a question you have while the field is empty and never after. Rotation stops the moment there is anything in the field, and never starts under prefers-reduced-motion.
  • Gone: the label and * over the only field, the "Examples" heading over three examples, and the "look on your network" row — discovery has had its own tab since GRYT-223, so that row was a way back to something that had already moved.
  • The card says what the server is, in its own words, clamped at two lines. It used to print the address you had just typed into the field directly above it.
  • The two facts stack on one right edge: whether it costs you an account, then how big it is. The count wears no chrome and is a size down — two badges read as two warnings.
  • The moderator note keeps the condition it already had (joinPolicy === "request") and loses the paragraph explaining why it helps.

The button is the server's answer now:

situation button
open server Join
lets people in by hand Ask to join
accounts only, you have none Sign in to join — enabled, opens sign-in
already a member Already joined, secondary, disabled
nothing typed / nothing answered disabled

That third row replaces a dead end. Today you press Join and are told afterwards to "sign in from the menu at the bottom left, then try again".

Create

  • The generated icon sits beside the name it is drawn from rather than centred above it at 80px, where it pushed the form out of view to show a preview rather than the subject of the step. Its caption went too — it changes as you type, which says the same thing.
  • The port field is 7rem, because a port is four characters, and its status sits beside it on the same line.
  • "Available", not "Free". On a product surface Free reads as a price.

One bug measuring caught that looking would not

className="w-28" on TextField lands on the input; the wrapper stays full width. The port status was sitting 256px from the field it describes. Width goes on a wrapper now — gap is 12.

Checked against a running client

Live community.gryt.chat as the subject:

  • placeholder cycles gryt.chat/invite?host=…localhost:5001, and freezes on input
  • card renders the server's own description, facts flush on one right edge (offset 0), -webkit-line-clamp: 2
  • account-only server with no account → enabled Sign in to join
  • Create: port 110px, status on the same line, 12px gap, labels sharing a left edge

Create is desktop-only (if (!isAvailable) return null), so its layout was measured with the embedded-server bridge stubbed. The markup is what shipped; the behaviour behind it is untouched.

The first pass left a dashed line reading "The Gryt server is hidden. Show it
again" where the card had been. That is still the suggestion, still on screen,
for everybody who already said no — and it is on the screen they see every time
they add a server. Somebody who presses a control called Hide forever has said
what they want.

So the row goes and nothing takes its place.

The undo moves to Settings, under How Gryt looks, next to the other preferences
about what the interface offers. It is a stored per-device setting either way,
so it always had a natural home there; leaving the only route in the dialog was
what forced the dialog to keep nagging.

Somewhere findable on purpose is the right shape for this. A control that
undoes a deliberate choice does not belong in the flow that choice was made to
get out of.

Checked in a running client: with the preference set, the dialog is the title,
the field and Join, and the word "hidden" appears nowhere on it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@sivert-io

Copy link
Copy Markdown
Member Author

Third commit: Hide forever now means gone.

The first pass left a dashed line reading "The Gryt server is hidden. Show it again" where the card had been. That is still the suggestion, still on screen, for everybody who already said no — and it is on the screen they see every time they add a server.

So the row goes and nothing takes its place. The undo moves to Settings → How Gryt looks, beside the other preferences about what the interface offers. It was always a stored per-device setting, so it had a natural home there; keeping the only route inside the dialog is what forced the dialog to keep nagging. A control that undoes a deliberate choice does not belong in the flow that choice was made to get out of.

Verified in a running client: with the preference set, the dialog is the title, the field and Join, and the word "hidden" appears nowhere on it.

@sivert-io
sivert-io merged commit 289495d into main Sep 3, 2026
2 checks 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