fix(frontend): mobile layout for intro strip, info tips and card headers

- IconStepStrip stays a compact horizontal row on narrow screens (smaller
  tiles, label under icon, horizontal chevrons)
- tip-card-head stacks top-to-bottom with a smaller illustration
- InfoTip clamps to the viewport (collision padding clears the sticky
  header, flips below when no room above, max-height scroll)
- card headers wrap on narrow screens; security subtitle gets its own line
This commit is contained in:
Juan Denis committed 2026-11-03 08:51:20 -05:00
1 parent bddca28881
commit a4ea3fccbd
4 files changed
+54 -2

No files matched your search

+6
View File
@@ -1,6 +1,7 @@
import { useRef, useState } from 'react';
import { Info } from 'lucide-react';
import { Popover, PopoverTrigger, PopoverContent } from '@/components/ui/popover';
import useMediaQuery from '../hooks/useMediaQuery';
import { t } from '../i18n/t';
// An (i) button that holds the explanation a page used to print inline.
@@ -9,6 +10,9 @@ import { t } from '../i18n/t';
// (no button-in-button) and above Modal/Sheet (.info-tip__panel z-index).
export default function InfoTip({ children, label, side = 'top', size = 'sm', className = '' }) {
const [open, setOpen] = useState(false);
// Narrow screens: keep the panel clear of the sticky app header.
const narrow = useMediaQuery('(max-width: 640px)');
const collisionPadding = narrow ? { top: 72, right: 12, bottom: 12, left: 12 } : 8; // geometry: header 56px + safe area
const pinned = useRef(false);
const hoverable = (e) => e.pointerType === 'mouse';
@@ -37,6 +41,8 @@ export default function InfoTip({ children, label, side = 'top', size = 'sm', cl
</PopoverTrigger>
<PopoverContent
side={side}
avoidCollisions
collisionPadding={collisionPadding}
className="info-tip__panel"
onOpenAutoFocus={(e) => e.preventDefault()}
onCloseAutoFocus={(e) => e.preventDefault()}
@@ -15,6 +15,14 @@
.card-header {
@include flex-between();
margin-bottom: $space-4;
// Narrow: title takes the row, trailing chips/actions wrap below.
@include respond-to($breakpoint-sm) {
flex-wrap: wrap;
gap: $space-2;
> h3 { flex: 1 1 auto; min-width: 0; }
}
}
.card h3 {
+38 -2
View File
@@ -31,6 +31,8 @@
z-index: $z-tooltip + 10;
width: auto;
max-width: min(320px, calc(100vw - 24px));
max-height: var(--radix-popover-content-available-height, 60vh);
overflow-y: auto;
padding: $space-2 $space-3;
font-size: $text-sm;
font-weight: $font-weight-normal;
@@ -94,11 +96,32 @@
svg { width: 16px; height: 16px; } // geometry: connector icon
}
// Narrow: stay one compact row; label sits under a smaller tile.
@include respond-to($breakpoint-sm) {
flex-direction: column;
flex-wrap: wrap;
align-items: flex-start;
gap: $space-1;
&__arrow { transform: rotate(90deg); margin-inline-start: $space-3; }
&__step {
display: grid;
grid-template-columns: auto auto;
justify-content: center;
align-items: center;
gap: $space-1;
}
&__tile {
grid-column: 1 / -1;
justify-self: center;
width: 36px; // geometry: compact tile
height: 36px; // geometry: compact tile
svg { width: 18px; height: 18px; } // geometry: icon in compact tile
}
&__label { font-size: $text-xs; }
// Centre the 14px chevron on the 36px tile.
&__arrow { margin-block-start: 11px; svg { width: 14px; height: 14px; } } // geometry: connector
}
}
@@ -177,6 +200,19 @@
gap: $space-3;
&__text { flex: 1; min-width: 0; }
@include respond-to($breakpoint-sm) {
flex-direction: column;
align-items: flex-start;
gap: $space-2;
.tip-illustration {
width: 36px; // geometry: compact illustration
height: 36px; // geometry: compact illustration
}
&__text { flex: none; width: 100%; }
}
&__title { display: flex; align-items: center; gap: $space-1; color: $text-primary; font-weight: $font-weight-medium; }
&__line { margin: 0; color: $text-secondary; font-size: $text-sm; }
}
+2
View File
@@ -66,6 +66,8 @@
font-weight: $font-weight-medium;
color: var(--text-faint);
letter-spacing: 0;
@include respond-to($breakpoint-sm) { display: block; }
}
// Severity / state chip (mono uppercase on a semantic wash) —