Use a spacer element for console scroll headroom

Replace the padding-top scroll headroom with a dedicated .console-spacer
element so the pin-to-bottom keeps working without padding inflating the
measured height, and trim the style.css comments.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
bbassieandClaude Opus 4.8 committed 2026-06-29 22:01:06 +00:00
1 parent 2dedb44372
commit 5cde390c24
2 files changed
+27 -24

No files matched your search

+18 -12
View File
@@ -10,9 +10,7 @@ import ControlContext from "./ControlContext";
const { Paragraph } = Typography;
const consoleHeightKey = "instance-console-height";
// With border-box the height includes the pin-to-bottom padding, so this is the
// full rendered height (matching the previous content-box default of 300 + 300).
const defaultConsoleHeight = 600;
const defaultConsoleHeight = 300;
type Parsed = {
format: string;
@@ -109,12 +107,20 @@ export default function LogConsole(props: LogConsoleProps) {
const consoleHeightRef = useRef(consoleHeight);
consoleHeightRef.current = consoleHeight;
// Persist the height the user drag-resizes the console to, so it is restored
// on the next visit. The scroll container is the <code> element wrapping the
// anchor.
// The console is resized with the browser's native resize handle, which owns
// the element's inline height. Driving the height from React would rewrite
// that inline style on every re-render and fight the drag (locking the size),
// so the height is only read here (on mount) and persisted (on resize), never
// written back through React. The scroll container is the <code> element
// wrapping the anchor.
useEffect(() => {
const element = anchor.current?.parentElement as HTMLElement | undefined;
if (!element || typeof ResizeObserver === "undefined") {
if (!element) {
return undefined;
}
element.style.height = `${consoleHeightRef.current}px`;
if (typeof ResizeObserver === "undefined") {
return undefined;
}
const observer = new ResizeObserver(() => {
@@ -191,11 +197,11 @@ export default function LogConsole(props: LogConsoleProps) {
]);
return <>
<Paragraph
code
className="instance-console"
style={{ "--console-height": `${consoleHeight}px` } as React.CSSProperties}
>
<Paragraph code className="instance-console">
{/* Scrollable spacer (one console-height tall) that keeps short output
pinned to the bottom and leaves room to scroll up. Unlike a
padding-top it is scroll content, so it does not constrain resize. */}
<div className="console-spacer" key="spacer" />
{pastLines}
{lines}
<div className="scroll-anchor" key="anchor" ref={anchor} />
+9 -12
View File
@@ -166,28 +166,25 @@ body {
height: 1px;
}
/* Scroll headroom above the output so short output sits at the bottom; it is
scroll content, not box padding, so it does not block dragging smaller. */
.instance-console code .console-spacer {
height: 100%;
}
.instance-console code {
display: block;
margin: 0;
background: #000;
border-color: #252525;
/* Height is driven by --console-height (set from the persisted user choice)
so the console can be drag-resized; the resize handle needs a non-visible
overflow, which overflow-y: scroll provides. border-box keeps padding-top
inside the height so the resize-observer measurement (offsetHeight) does
not include it; otherwise the padding inflates the measured height and the
console can no longer be dragged smaller. */
/* Drag-resizable (the native handle needs the scroll overflow); height is set
imperatively in LogConsole, border-box keeps padding out of offsetHeight. */
box-sizing: border-box;
height: var(--console-height, 600px);
height: 300px;
min-height: 100px;
resize: vertical;
overflow-y: scroll;
white-space: pre-wrap;
/* Make sure there's at least one pixel of scroll space, this */
/* is necessary for the view to stick on the scroll anchor. Tracks the */
/* height so the pin-to-bottom keeps working at any size. */
padding-top: var(--console-height, 600px);
}
.instance-console .factorio-time {