From a4ea3fccbd33b36f0480e8a5f2f4da37ae7bc8cb Mon Sep 17 00:00:00 2001 From: Juan Denis Date: Tue, 3 Nov 2026 08:51:20 -0500 Subject: [PATCH] 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 --- frontend/src/components/InfoTip.jsx | 6 +++ frontend/src/styles/components/_cards.scss | 8 ++++ frontend/src/styles/components/_info-tip.scss | 40 ++++++++++++++++++- frontend/src/styles/pages/_security.scss | 2 + 4 files changed, 54 insertions(+), 2 deletions(-) diff --git a/frontend/src/components/InfoTip.jsx b/frontend/src/components/InfoTip.jsx index d88265ab..d26eda73 100644 --- a/frontend/src/components/InfoTip.jsx +++ b/frontend/src/components/InfoTip.jsx @@ -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 e.preventDefault()} onCloseAutoFocus={(e) => e.preventDefault()} diff --git a/frontend/src/styles/components/_cards.scss b/frontend/src/styles/components/_cards.scss index 50567076..c60e8bed 100644 --- a/frontend/src/styles/components/_cards.scss +++ b/frontend/src/styles/components/_cards.scss @@ -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 { diff --git a/frontend/src/styles/components/_info-tip.scss b/frontend/src/styles/components/_info-tip.scss index ea8fbcc2..22305b61 100644 --- a/frontend/src/styles/components/_info-tip.scss +++ b/frontend/src/styles/components/_info-tip.scss @@ -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; } } diff --git a/frontend/src/styles/pages/_security.scss b/frontend/src/styles/pages/_security.scss index d31b73ef..97726129 100644 --- a/frontend/src/styles/pages/_security.scss +++ b/frontend/src/styles/pages/_security.scss @@ -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) —