diff --git a/client/src/components/cos/ReviewerPicker.jsx b/client/src/components/cos/ReviewerPicker.jsx index 3c05b6d964..80d254ce7e 100644 --- a/client/src/components/cos/ReviewerPicker.jsx +++ b/client/src/components/cos/ReviewerPicker.jsx @@ -26,6 +26,21 @@ const normalizeReviewerValue = (value) => normalizeReviewerSlug(value); // older build either. const CUSTOM_MODEL_OPTION = '[custom]'; +// Shared row grid, one template for the header and every row so their columns +// cannot drift apart. The wide form keeps minimum tracks for order, provider, +// model, effort, optional, max, and remove — together ~32rem, so the collapse is +// keyed to a CONTAINER query (`@xl`), not a viewport one: this picker also +// renders inside a narrow dashboard tile on a wide screen, where a viewport +// `sm:` was unconditionally true and forced the wide grid into a ~250px column. +// Below `@xl` a row collapses to a stacked 2-column label/value block, so a +// narrow container never scrolls horizontally. The header is wide-only — in the +// stacked form each cell carries its own inline label, since a header far above +// a stacked row doesn't associate. +const WIDE_TRACKS = '@xl:grid-cols-[2.5rem_minmax(5rem,1fr)_minmax(8rem,2fr)_minmax(7rem,1fr)_auto_3.25rem_auto]'; +const ROW_CLASS = `grid grid-cols-[auto_1fr] ${WIDE_TRACKS} items-center gap-x-2 gap-y-1 px-1.5 py-1.5 rounded border border-port-border bg-port-bg @xl:border-transparent @xl:bg-transparent @xl:py-0.5 @xl:rounded-none`; +const CELL_LABEL_CLASS = '@xl:hidden text-[10px] uppercase tracking-wide text-gray-600'; +const HEADER_CLASS = `hidden @xl:grid ${WIDE_TRACKS} items-center gap-x-2 px-1.5 text-[10px] uppercase tracking-wide text-gray-600`; + /** * Ordered multi-reviewer picker, rendered as one row per reviewer with the five * per-reviewer controls as columns: **Provider | Model | Effort | Optional | Max @@ -647,18 +662,8 @@ export default function ReviewerPicker({ emit({ reviewers: next }); }; - // Shared row grid. Desktop keeps minimum tracks for order, provider, model, - // effort, optional, max, and remove; under `sm` it collapses to a stacked - // 2-column label/value block so a narrow screen never needs horizontal - // scrolling. The header row is desktop-only — on mobile each cell carries - // its own inline label, since a header far above a stacked row doesn't - // associate. - const ROW_CLASS = 'grid grid-cols-[auto_1fr] sm:grid-cols-[2.5rem_minmax(5rem,1fr)_minmax(8rem,2fr)_minmax(7rem,1fr)_auto_3.25rem_auto] items-center gap-x-2 gap-y-1 px-1.5 py-1.5 rounded border border-port-border bg-port-bg sm:border-transparent sm:bg-transparent sm:py-0.5 sm:rounded-none'; - const CELL_LABEL_CLASS = 'sm:hidden text-[10px] uppercase tracking-wide text-gray-600'; - const HEADER_CLASS = 'hidden sm:grid sm:grid-cols-[2.5rem_minmax(5rem,1fr)_minmax(8rem,2fr)_minmax(7rem,1fr)_auto_3.25rem_auto] items-center gap-x-2 px-1.5 text-[10px] uppercase tracking-wide text-gray-600'; - return ( -
+
Reviewers (in order): {selected.length > 0 && ( @@ -672,14 +677,14 @@ export default function ReviewerPicker({ Max Remove
-
+
{selected.map((value, index) => (
o.value === value)?.description} > -
+
{index + 1}.
- + {reviewerLabel(value)} {renderUnavailableBadge(value)} @@ -716,7 +721,7 @@ export default function ReviewerPicker({
Max iterations
{renderMaxRounds(value, reviewerLabel(value))}
-
+