nandi/frqpublic Fork 0
8c76dd9
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.

Offer the reply on every message, not the first of a run

Answering was offered where the sender was named, which meant once per run: a
second line from the same person could not be answered at all, and the reply
you got was to whatever they said first.

Each message carries its own now, at the right of its own line, laid out from
that edge so the text takes the width left beside it. The text keeps a column
of its own — a wrapping label placed directly in a row wraps against the row —
and a system line, which nobody can answer, has a space where the button would
be rather than a button.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
nandi committed 2026-08-30T12:38:41-07:00 Browse files
8c76dd9 parent: 3cc5331
modified src/frq/app.jolt +15 -10
@@ -304,16 +304,21 @@
304304 [:label {:label (:from m)}]
305305 (when-let [at (:at m)]
306306 [:dim-label {:label (clock/clock-time at)}])
307- ;; Answering is offered where the sender is named — a run of lines
308- ;; from one person is answered as the thing it is — and against the
309- ;; right edge, out of the way of the name and the time, which are what
310- ;; the eye is going down the column for.
311- [:hbox {:key :reply-action :align :end}
312- (when (:id m)
313- [:button {:label "↩" :on-click #(s/reply-to! m)}])]])]
314- [:vbox {:key :text :spacing 2}
315- (map-indexed (fn [j run] (run-node j run (:system? m)))
316- (text-runs (:text m)))]
307+ ])]
308+ ;; Every message can be answered, not only the one that opened a run —
309+ ;; laid out from the right so the action sits at the edge and the text
310+ ;; takes the width that is left. The text keeps a column of its own:
311+ ;; a wrapping label directly in a row wraps against the row.
312+ [:hbox {:key :line :align :end :spacing 6}
313+ ;; The button sits in the row itself rather than in a box of its own:
314+ ;; a box with no width takes the rest of the row and puts the text on a
315+ ;; line below it, and one with a width takes the column's whole height.
316+ (if (:id m)
317+ [:button {:key :reply :label "↩" :on-click #(s/reply-to! m)}]
318+ [:spacer {:key :reply :size 0}])
319+ [:vbox {:key :text :spacing 2}
320+ (map-indexed (fn [j run] (run-node j run (:system? m)))
321+ (text-runs (:text m)))]]
317322 ;; Pictures under the line that linked them. The link stays: it is what a
318323 ;; failed fetch, an unsupported format, or a phone with no TLS leaves you.
319324 [:vbox {:key :images :spacing 4}
@@ -304,16 +304,21 @@
304 [:label {:label (:from m)}]304 [:label {:label (:from m)}]
305 (when-let [at (:at m)]305 (when-let [at (:at m)]
306 [:dim-label {:label (clock/clock-time at)}])306 [:dim-label {:label (clock/clock-time at)}])
307- ;; Answering is offered where the sender is named — a run of lines307+ ])]
308- ;; from one person is answered as the thing it is — and against the308+ ;; Every message can be answered, not only the one that opened a run —
309- ;; right edge, out of the way of the name and the time, which are what309+ ;; laid out from the right so the action sits at the edge and the text
310- ;; the eye is going down the column for.310+ ;; takes the width that is left. The text keeps a column of its own:
311- [:hbox {:key :reply-action :align :end}311+ ;; a wrapping label directly in a row wraps against the row.
312- (when (:id m)312+ [:hbox {:key :line :align :end :spacing 6}
313- [:button {:label "↩" :on-click #(s/reply-to! m)}])]])]313+ ;; The button sits in the row itself rather than in a box of its own:
314- [:vbox {:key :text :spacing 2}314+ ;; a box with no width takes the rest of the row and puts the text on a
315- (map-indexed (fn [j run] (run-node j run (:system? m)))315+ ;; line below it, and one with a width takes the column's whole height.
316- (text-runs (:text m)))]316+ (if (:id m)
317+ [:button {:key :reply :label "↩" :on-click #(s/reply-to! m)}]
318+ [:spacer {:key :reply :size 0}])
319+ [:vbox {:key :text :spacing 2}
320+ (map-indexed (fn [j run] (run-node j run (:system? m)))
321+ (text-runs (:text m)))]]
317 ;; Pictures under the line that linked them. The link stays: it is what a322 ;; Pictures under the line that linked them. The link stays: it is what a
318 ;; failed fetch, an unsupported format, or a phone with no TLS leaves you.323 ;; failed fetch, an unsupported format, or a phone with no TLS leaves you.
319 [:vbox {:key :images :spacing 4}324 [:vbox {:key :images :spacing 4}