Files
cinny/src/app/utils/reactionOverflow.ts
T
jaredandClaude Opus 5 bf05751eca
CI / Build & Quality Checks (push) Successful in 1m36s
CI / Docker image build & smoke test (push) Skipped
CI / Secret scan (gitleaks) (push) Successful in 10s
CI / Trigger Desktop Build (push) Canceled after 0s
CI / Playwright smoke (e2e) (push) Canceled after 0s
feat(messages): collapse reactions to one row with a +N chip (#138)
Many distinct reactions used to wrap into a tall stack (16 reactions =
4 rows at phone width). Now only the first row is shown, ending in a
"+N" chip; tapping it expands inline and a "less" chip collapses again.
Expanded state is remembered per message for the session. Nothing changes
when the reactions already fit on one row.

Overflowing chips stay in the DOM (invisible, aria-hidden, untabbable,
clipped by max-height) so the container keeps its natural width — which
keeps shrink-to-fit bubble layout stable — and each chip stays measurable.
utils/reactionOverflow.ts holds the unit-tested fit calculation; a
ResizeObserver re-fits on width changes. "+N" is forced LTR for RTL UIs.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PPmy3tPq869XDW4njjVaKA
2026-09-19 23:54:52 -04:00

27 lines
985 B
TypeScript

/**
* [Gitea #138] How many reaction chips fit on one row next to a "+N" chip.
*
* Returns `undefined` when every chip fits on the first row (nothing to
* collapse). Otherwise returns the number of leading chips to show; the
* caller renders a "+N" chip after them. Always at least 1 chip.
*/
export function fitReactionRow(
chipWidths: number[],
moreChipWidth: number,
gap: number,
rowWidth: number,
): number | undefined {
const rowLength = (count: number, extra: number) => {
let total = extra;
for (let i = 0; i < count; i += 1) total += chipWidths[i] + (i > 0 || extra > 0 ? gap : 0);
return total;
};
if (rowLength(chipWidths.length, 0) <= rowWidth) return undefined;
let count = chipWidths.length - 1;
while (count > 1 && rowLength(count, 0) + gap + moreChipWidth > rowWidth) count -= 1;
return count;
}
/** Session-only memory of which messages have their reactions expanded. */
export const expandedReactionMessages = new Set<string>();