mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-09 04:50:59 +00:00
Let the setup flow's action rows wrap, and measure headroom per word
At 390 px with labels a third longer the action row pushed "Confirm and continue" past the viewport; both rows now wrap. The string-headroom sweep lengthens every word by 30% rather than hanging the whole surplus on the last one — that manufactured an unbreakable run no locale produces — leaves screen-reader-only boxes alone, and accepts a select value's ellipsis, which is the primitive's design app-wide.
This commit is contained in:
1 parent
d91a8dfebe
commit
5c5a592177
4 files changed
+28
-10
No files matched your search
@@ -57,9 +57,11 @@ const RAW_KEY = /\b[a-z]+(?:[A-Z][a-z]+)?\.[a-z][A-Za-z0-9_.-]+\b/;
|
||||
|
||||
/**
|
||||
* Lengthen every text node under the shell by 30%, then measure. Padding
|
||||
* appends letters to the LAST word so the longest unbreakable run grows,
|
||||
* which is the case that overflows; a padding that only added spaces would
|
||||
* wrap for free and prove nothing.
|
||||
* lengthens every WORD by 30%, so the longest unbreakable run grows in the
|
||||
* same proportion as the sentence — which is what a longer translation does.
|
||||
* Appending the whole surplus to one word would manufacture an unbreakable
|
||||
* run no locale produces; adding only spaces would wrap for free and prove
|
||||
* nothing.
|
||||
*/
|
||||
async function padAndMeasure(page: Page) {
|
||||
return page.evaluate((shellSelector) => {
|
||||
@@ -76,8 +78,11 @@ async function padAndMeasure(page: Page) {
|
||||
letters >= 3 &&
|
||||
node.parentElement?.closest("script,style") === null
|
||||
) {
|
||||
const extra = Math.ceil(letters * 0.3);
|
||||
node.textContent = text.replace(/\s*$/, "") + "x".repeat(extra);
|
||||
node.textContent = text.replace(/\S+/g, (word) =>
|
||||
word.length >= 2
|
||||
? word + "x".repeat(Math.ceil(word.length * 0.3))
|
||||
: word,
|
||||
);
|
||||
padded += 1;
|
||||
}
|
||||
node = walker.nextNode();
|
||||
@@ -86,6 +91,16 @@ async function padAndMeasure(page: Page) {
|
||||
const doc = document.documentElement;
|
||||
const clippers = [...shell.querySelectorAll<HTMLElement>("*")]
|
||||
.filter((el) => {
|
||||
// Screen-reader-only text is a 1 px clipped box on purpose; it is
|
||||
// read, not seen, and cannot truncate.
|
||||
if (el.classList.contains("sr-only") || el.clientWidth <= 1) {
|
||||
return false;
|
||||
}
|
||||
// A select's value ellipsises by design (shadcn `SelectValue`, app
|
||||
// wide): the full text is the option in the list and the control's
|
||||
// accessible name, and a trigger that grew with its longest option
|
||||
// would move every neighbour. Not a layout that lost headroom.
|
||||
if (el.dataset.slot === "select-value") return false;
|
||||
const overflowX = getComputedStyle(el).overflowX;
|
||||
return overflowX === "hidden" || overflowX === "clip";
|
||||
})
|
||||
|
||||
@@ -226,7 +226,7 @@ export function BaselineForm({
|
||||
/>
|
||||
|
||||
<div
|
||||
className="flex items-center justify-between gap-2 pt-2"
|
||||
className="flex flex-wrap items-center justify-between gap-2 pt-2"
|
||||
data-slot="onboarding-step-actions"
|
||||
>
|
||||
{backHref ? (
|
||||
@@ -238,7 +238,7 @@ export function BaselineForm({
|
||||
) : (
|
||||
<span aria-hidden="true" />
|
||||
)}
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="ml-auto flex flex-wrap items-center justify-end gap-2">
|
||||
<Button
|
||||
type="button"
|
||||
variant="ghost"
|
||||
|
||||
@@ -200,7 +200,7 @@ export function ConfirmScreen({ state }: { state: OnboardingStateDto }) {
|
||||
onCreated={() => void finish()}
|
||||
/>
|
||||
<p className="text-sm">{t("onboarding.flow.confirm.managedLater")}</p>
|
||||
<div className="flex items-center justify-between gap-2 pt-2">
|
||||
<div className="flex flex-wrap items-center justify-between gap-2 pt-2">
|
||||
{back ? (
|
||||
<Button asChild variant="ghost" className="min-h-11 min-w-11">
|
||||
<Link href={screenHref(back)} data-slot="onboarding-back">
|
||||
|
||||
@@ -35,7 +35,10 @@ export function StepActions({
|
||||
|
||||
return (
|
||||
<div
|
||||
className="flex items-center justify-between gap-2 pt-2"
|
||||
// `flex-wrap` on both rows: a locale whose labels run 30% longer must
|
||||
// drop the action group to its own line at 390 px, not push it past
|
||||
// the viewport (the string-headroom sweep measures exactly this).
|
||||
className="flex flex-wrap items-center justify-between gap-2 pt-2"
|
||||
data-slot="onboarding-step-actions"
|
||||
>
|
||||
{backHref ? (
|
||||
@@ -47,7 +50,7 @@ export function StepActions({
|
||||
) : (
|
||||
<span aria-hidden="true" />
|
||||
)}
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="ml-auto flex flex-wrap items-center justify-end gap-2">
|
||||
{onSkip ? (
|
||||
<Button
|
||||
type="button"
|
||||
|
||||
Reference in new issue
Block a user