nandi/frqpublic Fork 0
9a5c2a8
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.

Size a preview against the window it is shown in

A picture in the conversation was capped at 260 points however big the
window was. That is a stamp on a laptop and most of the screen on a
phone, and the pictures that actually arrive here are phone screenshots
— 1080x2400, whose height is what binds, so a low cap draws them as a
strip too narrow to read a word of.

The height comes from the window now, polled off the same tick that
already follows its width: `screen-size` reports both, and only what a
component derefs re-renders, so a drag of the window's edge resizes the
pictures and touches nothing else. Four fifths of the height, clamped,
with the old 260 standing in until the first poll lands.

The width is bounded the same way, which is what keeps a wide, short
picture from taking the column. Neither is a stretch: `:image` fits to
whichever bound it meets first, and never past the picture's own pixels.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
nandi committed 2026-08-31T22:59:36-07:00 Browse files
9a5c2a8 parent: 03d5a6b
modified src/frq/app.jolt +41 -3
@@ -496,6 +496,36 @@
496496 (= :failed (:status pr)) [:dim-label {:label "No Bluesky profile found"}])]
497497 [:dim-label {:label "Click for the full profile"}]]))
498498
499+(defn- preview-height
500+ "How tall a picture in the conversation may be.
501+
502+ Against the window rather than a fixed 260: on a phone-sized window a
503+ preview that tall is the whole screen, and on a laptop one it is a stamp of
504+ something worth looking at.
505+
506+ Four fifths of the window, because the pictures that arrive here are mostly
507+ phone screenshots — 1080x2400, whose height is what binds, and any smaller
508+ share draws them as a strip too narrow to read a word of. A picture is what
509+ the message is; the line above it is enough context to place it, and the
510+ scroll is how the rest is reached.
511+
512+ Clamped at both ends, and falling back to the old fixed height until the
513+ first poll has landed: a preview is a preview either way, and the lightbox
514+ is what full size is for."
515+ []
516+ (let [h @s/window-height]
517+ (if (pos? h) (min 900 (max 240 (long (* 0.8 h)))) 260)))
518+
519+(defn- preview-width
520+ "How wide a picture in the conversation may be.
521+
522+ The height alone leaves a wide, short picture to take the column and push
523+ the words around it; this holds it inside the conversation the same way.
524+ Fitted, never stretched — `:image` scales to whichever bound it meets first."
525+ []
526+ (let [w @s/window-width]
527+ (if (pos? w) (min 900 (max 240 (long (* 0.95 w)))) 320)))
528+
499529 (defn message-row
500530 "One message: who said it, when, what you can do to it, and the words.
501531
@@ -618,7 +648,8 @@
618648 (when-let [path (media/path-when-ready url)]
619649 [:image {:key url
620650 :src path
621- :max-height 260
651+ :max-height (preview-height)
652+ :max-width (preview-width)
622653 :on-click #(reset! s/lightbox {:path path :url url})}]))))]
623654 ;; Reactions go last, under whatever the message turned out to be: a
624655 ;; line with a picture on it is the picture, and pills between the words
@@ -1256,9 +1287,16 @@
12561287 ;; delivered: the backend reports a size by writing it onto the window node,
12571288 ;; and only what a component derefs re-renders — so the layout follows a drag
12581289 ;; of the window's edge without every frame touching the tree.
1259- (vidya/every! 200 #(let [w (vidya/window-width)]
1290+ ;;
1291+ ;; The height comes off the same tick, from `screen-size` rather than a
1292+ ;; second call: it is the window's content size, and the pictures in the
1293+ ;; conversation are sized against it.
1294+ (vidya/every! 200 #(let [w (vidya/window-width)
1295+ h (long (second (vidya/screen-size)))]
12601296 (when (not= w @s/window-width)
1261- (reset! s/window-width w))))
1297+ (reset! s/window-width w))
1298+ (when (not= h @s/window-height)
1299+ (reset! s/window-height h))))
12621300 ;; The nick in the window title, so a second window of this client is told
12631301 ;; apart from the first by the one thing that differs — and so the answer to
12641302 ;; "who am I here?" is on screen without opening Settings.
@@ -496,6 +496,36 @@
496 (= :failed (:status pr)) [:dim-label {:label "No Bluesky profile found"}])]496 (= :failed (:status pr)) [:dim-label {:label "No Bluesky profile found"}])]
497 [:dim-label {:label "Click for the full profile"}]]))497 [:dim-label {:label "Click for the full profile"}]]))
498 498
499+(defn- preview-height
500+ "How tall a picture in the conversation may be.
501+
502+ Against the window rather than a fixed 260: on a phone-sized window a
503+ preview that tall is the whole screen, and on a laptop one it is a stamp of
504+ something worth looking at.
505+
506+ Four fifths of the window, because the pictures that arrive here are mostly
507+ phone screenshots — 1080x2400, whose height is what binds, and any smaller
508+ share draws them as a strip too narrow to read a word of. A picture is what
509+ the message is; the line above it is enough context to place it, and the
510+ scroll is how the rest is reached.
511+
512+ Clamped at both ends, and falling back to the old fixed height until the
513+ first poll has landed: a preview is a preview either way, and the lightbox
514+ is what full size is for."
515+ []
516+ (let [h @s/window-height]
517+ (if (pos? h) (min 900 (max 240 (long (* 0.8 h)))) 260)))
518+
519+(defn- preview-width
520+ "How wide a picture in the conversation may be.
521+
522+ The height alone leaves a wide, short picture to take the column and push
523+ the words around it; this holds it inside the conversation the same way.
524+ Fitted, never stretched — `:image` scales to whichever bound it meets first."
525+ []
526+ (let [w @s/window-width]
527+ (if (pos? w) (min 900 (max 240 (long (* 0.95 w)))) 320)))
528+
499 (defn message-row529 (defn message-row
500 "One message: who said it, when, what you can do to it, and the words.530 "One message: who said it, when, what you can do to it, and the words.
501 531
@@ -618,7 +648,8 @@
618 (when-let [path (media/path-when-ready url)]648 (when-let [path (media/path-when-ready url)]
619 [:image {:key url649 [:image {:key url
620 :src path650 :src path
621- :max-height 260651+ :max-height (preview-height)
652+ :max-width (preview-width)
622 :on-click #(reset! s/lightbox {:path path :url url})}]))))]653 :on-click #(reset! s/lightbox {:path path :url url})}]))))]
623 ;; Reactions go last, under whatever the message turned out to be: a654 ;; Reactions go last, under whatever the message turned out to be: a
624 ;; line with a picture on it is the picture, and pills between the words655 ;; line with a picture on it is the picture, and pills between the words
@@ -1256,9 +1287,16 @@
1256 ;; delivered: the backend reports a size by writing it onto the window node,1287 ;; delivered: the backend reports a size by writing it onto the window node,
1257 ;; and only what a component derefs re-renders — so the layout follows a drag1288 ;; and only what a component derefs re-renders — so the layout follows a drag
1258 ;; of the window's edge without every frame touching the tree.1289 ;; of the window's edge without every frame touching the tree.
1259- (vidya/every! 200 #(let [w (vidya/window-width)]1290+ ;;
1291+ ;; The height comes off the same tick, from `screen-size` rather than a
1292+ ;; second call: it is the window's content size, and the pictures in the
1293+ ;; conversation are sized against it.
1294+ (vidya/every! 200 #(let [w (vidya/window-width)
1295+ h (long (second (vidya/screen-size)))]
1260 (when (not= w @s/window-width)1296 (when (not= w @s/window-width)
1261- (reset! s/window-width w))))1297+ (reset! s/window-width w))
1298+ (when (not= h @s/window-height)
1299+ (reset! s/window-height h))))
1262 ;; The nick in the window title, so a second window of this client is told1300 ;; The nick in the window title, so a second window of this client is told
1263 ;; apart from the first by the one thing that differs — and so the answer to1301 ;; apart from the first by the one thing that differs — and so the answer to
1264 ;; "who am I here?" is on screen without opening Settings.1302 ;; "who am I here?" is on screen without opening Settings.
modified src/frq/state.jolt +6 -0
@@ -108,6 +108,12 @@
108108 ;; list and the conversation are both on screen instead of taking turns.
109109 (defonce window-width (atom 0))
110110
111+;; The window's content height, polled beside the width and for the same
112+;; reason. What it is for is the pictures in the conversation: a preview sized
113+;; against the window is a picture on a laptop and a thumbnail on a phone,
114+;; where one fixed height is only ever right on one of them.
115+(defonce window-height (atom 0))
116+
111117 ;; Where the second pane starts paying for itself. Below this a 300pt list
112118 ;; beside a conversation leaves the messages narrower than the phone layout
113119 ;; they were written for.
@@ -108,6 +108,12 @@
108 ;; list and the conversation are both on screen instead of taking turns.108 ;; list and the conversation are both on screen instead of taking turns.
109 (defonce window-width (atom 0))109 (defonce window-width (atom 0))
110 110
111+;; The window's content height, polled beside the width and for the same
112+;; reason. What it is for is the pictures in the conversation: a preview sized
113+;; against the window is a picture on a laptop and a thumbnail on a phone,
114+;; where one fixed height is only ever right on one of them.
115+(defonce window-height (atom 0))
116+
111 ;; Where the second pane starts paying for itself. Below this a 300pt list117 ;; Where the second pane starts paying for itself. Below this a 300pt list
112 ;; beside a conversation leaves the messages narrower than the phone layout118 ;; beside a conversation leaves the messages narrower than the phone layout
113 ;; they were written for.119 ;; they were written for.