nandi/frqpublic Fork 0
4a372ae
Commits
Clone
git clone https://git.rickub.com/nandi/frq.git
git clone ssh://git@rickub.com/nandi/frq.git

Host key fingerprint (ed25519): SHA256:iycHnxEyq0Q7uyVpB7JlznP0G7JrTPXLYRcAU5CSLhc — verify it before your first connect.

Lay the join row out from its right edge

The box asked for a fixed width and the button took what was left, which
holds only while the window is wider than that number. Under it the entry
took the row and the button wrapped to a line of its own — Join under the
box rather than beside it. Measuring the window instead moved the wrap
rather than removing it: the width is polled a few times a second, so a
drag wrapped for a tick and then resized.

So the row is laid out from the right: `:align :end` with the button
first, placed against that edge, and the box after it asking for whatever
remains where it stands. The box is the part that gives, at every width,
in the frame the drag happens. The search row goes the same way, its
clear button leading for the same reason.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
nandi committed 2026-09-01T21:48:14-07:00 Browse files
4a372ae parent: cb7f9f1
modified src/frq/app.jolt +20 -25
@@ -162,19 +162,6 @@
162162
163163 (def ^:private sidebar-width 320)
164164
165-(defn- control-entry-width
166- "How wide the join and search boxes ask to be.
167-
168- A fixed 380 is right on a window that holds the list alone, and too wide for
169- the list as a split view's left column: the row it sits on is only
170- `sidebar-width` across, and an entry that asks for more than remains pushes
171- the button beside it onto a row of its own — Join under the box rather than
172- next to it. Beside the entry go the button and the gap, and around the row
173- the card's and the page's padding, so the column's share is what is left of
174- the sidebar after those."
175- []
176- (if (s/wide?) (- sidebar-width 130) 380))
177-
178165 (defn- below-list []
179166 ;; What the strip under the list needs, counted: the gap after the list, the
180167 ;; separator, the gap under it, the tab bar's row of buttons and the margin
@@ -207,27 +194,35 @@
207194 ;; channel" header was doing.
208195 [:card {}
209196 [:vbox {:spacing 8}
210- [:hbox {:spacing 8}
197+ ;; Button first and `:align :end`, so the row is laid out from its
198+ ;; right edge: the button is placed against that edge and the box takes
199+ ;; what is left. An entry asks for whatever remains where it stands, so
200+ ;; a box placed first takes the row and pushes the button onto a line of
201+ ;; its own — Join under the box rather than beside it — and a box given
202+ ;; a fixed width only holds that off until the window is narrower than
203+ ;; the number. Laid out from the right the box is the part that gives,
204+ ;; at every width, in the frame the drag happens rather than the one
205+ ;; after the window is next measured.
206+ [:hbox {:spacing 8 :align :end}
207+ [:button {:label (if (str/starts-with? @s/join-input "@") "Message" "Join")
208+ :kind :primary
209+ :on-click #(do (s/join! @s/join-input) (reset! s/join-input ""))}]
211210 ;; Both kinds of conversation through one box: `#room` joins a
212211 ;; channel, `@nick` opens a message to a person.
213212 [:entry {:text @s/join-input
214- :width-request (control-entry-width)
215213 :placeholder "#channel or @nick"
216214 :on-change #(reset! s/join-input %)
217- :on-activate #(do (s/join! @s/join-input) (reset! s/join-input ""))}]
218- [:button {:label (if (str/starts-with? @s/join-input "@") "Message" "Join")
219- :kind :primary
220- :on-click #(do (s/join! @s/join-input) (reset! s/join-input ""))}]]
215+ :on-activate #(do (s/join! @s/join-input) (reset! s/join-input ""))}]]
221216 ;; The clear button only shows while there is something to clear: an
222217 ;; empty box has nothing to undo, and a dead button beside it reads as
223- ;; one that stopped working.
224- [:hbox {:spacing 8}
218+ ;; one that stopped working. It leads the row for the same reason the
219+ ;; Join button does, and the box gives up the width it takes.
220+ [:hbox {:spacing 8 :align :end}
221+ (when (seq @s/search)
222+ [:button {:label "✕" :on-click #(reset! s/search "")}])
225223 [:entry {:text @s/search
226- :width-request (control-entry-width)
227224 :placeholder "Search channels"
228- :on-change #(reset! s/search %)}]
229- (when (seq @s/search)
230- [:button {:label "✕" :on-click #(reset! s/search "")}])]]]]
225+ :on-change #(reset! s/search %)}]]]]]
231226 ;; `:fill-height` so the scroll inside is handed the rest of the window
232227 ;; rather than the one card it starts out holding, and `:reserve` to keep
233228 ;; the tabs' strip out of what it may take.
@@ -162,19 +162,6 @@
162 162
163 (def ^:private sidebar-width 320)163 (def ^:private sidebar-width 320)
164 164
165-(defn- control-entry-width
166- "How wide the join and search boxes ask to be.
167-
168- A fixed 380 is right on a window that holds the list alone, and too wide for
169- the list as a split view's left column: the row it sits on is only
170- `sidebar-width` across, and an entry that asks for more than remains pushes
171- the button beside it onto a row of its own — Join under the box rather than
172- next to it. Beside the entry go the button and the gap, and around the row
173- the card's and the page's padding, so the column's share is what is left of
174- the sidebar after those."
175- []
176- (if (s/wide?) (- sidebar-width 130) 380))
177-
178 (defn- below-list []165 (defn- below-list []
179 ;; What the strip under the list needs, counted: the gap after the list, the166 ;; What the strip under the list needs, counted: the gap after the list, the
180 ;; separator, the gap under it, the tab bar's row of buttons and the margin167 ;; separator, the gap under it, the tab bar's row of buttons and the margin
@@ -207,27 +194,35 @@
207 ;; channel" header was doing.194 ;; channel" header was doing.
208 [:card {}195 [:card {}
209 [:vbox {:spacing 8}196 [:vbox {:spacing 8}
210- [:hbox {:spacing 8}197+ ;; Button first and `:align :end`, so the row is laid out from its
198+ ;; right edge: the button is placed against that edge and the box takes
199+ ;; what is left. An entry asks for whatever remains where it stands, so
200+ ;; a box placed first takes the row and pushes the button onto a line of
201+ ;; its own — Join under the box rather than beside it — and a box given
202+ ;; a fixed width only holds that off until the window is narrower than
203+ ;; the number. Laid out from the right the box is the part that gives,
204+ ;; at every width, in the frame the drag happens rather than the one
205+ ;; after the window is next measured.
206+ [:hbox {:spacing 8 :align :end}
207+ [:button {:label (if (str/starts-with? @s/join-input "@") "Message" "Join")
208+ :kind :primary
209+ :on-click #(do (s/join! @s/join-input) (reset! s/join-input ""))}]
211 ;; Both kinds of conversation through one box: `#room` joins a210 ;; Both kinds of conversation through one box: `#room` joins a
212 ;; channel, `@nick` opens a message to a person.211 ;; channel, `@nick` opens a message to a person.
213 [:entry {:text @s/join-input212 [:entry {:text @s/join-input
214- :width-request (control-entry-width)
215 :placeholder "#channel or @nick"213 :placeholder "#channel or @nick"
216 :on-change #(reset! s/join-input %)214 :on-change #(reset! s/join-input %)
217- :on-activate #(do (s/join! @s/join-input) (reset! s/join-input ""))}]215+ :on-activate #(do (s/join! @s/join-input) (reset! s/join-input ""))}]]
218- [:button {:label (if (str/starts-with? @s/join-input "@") "Message" "Join")
219- :kind :primary
220- :on-click #(do (s/join! @s/join-input) (reset! s/join-input ""))}]]
221 ;; The clear button only shows while there is something to clear: an216 ;; The clear button only shows while there is something to clear: an
222 ;; empty box has nothing to undo, and a dead button beside it reads as217 ;; empty box has nothing to undo, and a dead button beside it reads as
223- ;; one that stopped working.218+ ;; one that stopped working. It leads the row for the same reason the
224- [:hbox {:spacing 8}219+ ;; Join button does, and the box gives up the width it takes.
220+ [:hbox {:spacing 8 :align :end}
221+ (when (seq @s/search)
222+ [:button {:label "✕" :on-click #(reset! s/search "")}])
225 [:entry {:text @s/search223 [:entry {:text @s/search
226- :width-request (control-entry-width)
227 :placeholder "Search channels"224 :placeholder "Search channels"
228- :on-change #(reset! s/search %)}]225+ :on-change #(reset! s/search %)}]]]]]
229- (when (seq @s/search)
230- [:button {:label "✕" :on-click #(reset! s/search "")}])]]]]
231 ;; `:fill-height` so the scroll inside is handed the rest of the window226 ;; `:fill-height` so the scroll inside is handed the rest of the window
232 ;; rather than the one card it starts out holding, and `:reserve` to keep227 ;; rather than the one card it starts out holding, and `:reserve` to keep
233 ;; the tabs' strip out of what it may take.228 ;; the tabs' strip out of what it may take.