Images: one card for controls and preview, chat sliders, wider softer shadow

- Controls and preview were two floating cards; they now share one card split by
  a divider. The Advanced dock stays separate since it toggles.
- SliderField wraps Chat's ParamSlider, so the sliders match Chat (label row with
  the value, full-width neutral track) instead of a green track with a spin box.
  All 14 call sites keep their props.
- panel-soft-surface goes from 0 2px 8px -2px /0.16 to 0 4px 22px -6px /0.10:
  lighter, spread wider.
This commit is contained in:
shimmyshimmer 2026-07-25 02:52:27 -07:00
commit e1077798ec
2 changed files with 20 additions and 35 deletions

View file

@ -61,6 +61,7 @@ import type {
ModelOption,
ModelSelectorChangeMeta,
} from "@/features/model-picker/components/model-selector/types";
import { ParamSlider } from "@/features/chat";
import { ModelLoadDescription } from "@/features/chat/components/model-load-status";
import { getHfToken, hfApiToken } from "@/features/hub/stores/hf-token-store";
import { formatBytes, formatEta } from "@/features/hub/lib/format";
@ -424,6 +425,7 @@ const IDLE_PROGRESS: DiffusionLoadProgress = {
// Mirrors the Train page's SliderRow (studio/sections/params-section.tsx):
// label + standard Slider + number input, same classes.
// The Images sliders are Chat's ParamSlider, so both pages share one control.
function SliderField({
label,
hint,
@ -442,34 +444,15 @@ function SliderField({
onChange: (v: number) => void;
}) {
return (
<div className="flex items-center justify-between">
<span className="flex items-center gap-1 text-xs font-medium text-muted-foreground">
{label}
{hint && <InfoHint>{hint}</InfoHint>}
</span>
<div className="flex items-center gap-3">
<Slider
value={[value]}
onValueChange={([v]) => onChange(v)}
min={min}
max={max}
step={step}
className="w-32"
/>
<input
type="number"
value={value}
onChange={(e) => onChange(Number(e.target.value))}
min={min}
max={max}
step={step}
// The slider is the primary control, so the native number spinners are redundant --
// and on this narrow field their arrows overlapped the value. Remove them on every
// engine: appearance:textfield for Firefox, zeroed webkit inner/outer spin buttons.
className="w-14 text-right font-mono text-xs font-medium bg-muted/50 border border-border rounded-lg px-1.5 py-0.5 focus:outline-none focus:ring-1 focus:ring-primary/30 [appearance:textfield] [&::-webkit-outer-spin-button]:m-0 [&::-webkit-outer-spin-button]:appearance-none [&::-webkit-inner-spin-button]:m-0 [&::-webkit-inner-spin-button]:appearance-none"
/>
</div>
</div>
<ParamSlider
label={label}
info={hint}
value={value}
min={min}
max={max}
step={step}
onChange={onChange}
/>
);
}
@ -2333,9 +2316,10 @@ export function ImagesPage({ active = true }: { active?: boolean }) {
(Export, Data Recipes): px-5 / sm:px-9, with a roomy bottom. pt-3 keeps the
cards off the model selector row. */
<div className="flex min-h-0 min-w-0 flex-1 gap-4 overflow-hidden px-5 pb-8 pt-6 sm:px-9">
{/* The controls rail. Plain card (the gray surface) with no header
the prompt + Generate button make the panel self-explanatory. */}
<div className="bg-card corner-squircle flex w-[340px] shrink-0 flex-col overflow-hidden rounded-3xl panel-soft-surface">
{/* Controls and preview share one card, split by a divider, so the page
reads as a single surface instead of two floating boxes. */}
<div className="bg-card corner-squircle flex min-h-0 min-w-0 flex-1 overflow-hidden rounded-3xl panel-soft-surface">
<div className="flex w-[340px] shrink-0 flex-col overflow-hidden border-r border-border/60">
<div className="flex min-h-0 flex-col gap-4 overflow-y-auto p-5">
{/* Workflow picker. Seven workflows don't fit a segmented strip in a 340px
rail, so it's a dropdown: the trigger carries the current workflow and
@ -2897,7 +2881,7 @@ export function ImagesPage({ active = true }: { active?: boolean }) {
</div>
</div>
<div className="bg-card corner-squircle relative flex min-w-0 flex-1 flex-col overflow-hidden rounded-3xl panel-soft-surface">
<div className="relative flex min-w-0 flex-1 flex-col overflow-hidden">
<div className="relative flex flex-1 items-center justify-center overflow-auto p-6">
{selected && selectedSrc ? (
<>
@ -3044,6 +3028,7 @@ export function ImagesPage({ active = true }: { active?: boolean }) {
</div>
)}
</div>
</div>
{/* Right-docked Advanced panel (mirrors Chat's settings panel): closed by default,
opened by the single fixed top-bar toggle above (which never moves between states,

View file

@ -1505,10 +1505,10 @@ html[data-chat-font] .aui-root {
box-shadow: none;
}
/* Panel cards: no outline, composer shadow in light, flat in dark (same
convention as .chat-composer-surface and the menus). */
/* Panel cards: no outline, flat in dark. Lighter than the composer's shadow
but spread wider, so a large card reads as lifted without a hard edge. */
.panel-soft-surface {
box-shadow: 0 2px 8px -2px rgba(0, 0, 0, 0.16);
box-shadow: 0 4px 22px -6px rgba(0, 0, 0, 0.1);
}
.dark .panel-soft-surface {