mirror of
https://github.com/clusterio/clusterio.git
synced 2026-11-15 07:24:52 +09:00
Make the Web UI console resizable
The instance console was locked to a fixed 300px height. It can now be drag-resized vertically (native resize handle), and the chosen height is persisted with useLocalStorage so it is restored on the next visit. Both the height and the scroll-anchor padding are driven by a --console-height CSS variable, so the pin-to-bottom behaviour keeps working at any size. Closes #938 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
a274fe74e1
commit
3fe0c85055
2 files changed
+40
-4
No files matched your search
@@ -4,10 +4,14 @@ import { Select, Typography } from "antd";
|
||||
import * as lib from "@clusterio/lib";
|
||||
|
||||
import { useAccount } from "../model/account";
|
||||
import useLocalStorage from "../util/useLocalStorage";
|
||||
import ControlContext from "./ControlContext";
|
||||
|
||||
const { Paragraph } = Typography;
|
||||
|
||||
const consoleHeightKey = "instance-console-height";
|
||||
const defaultConsoleHeight = 300;
|
||||
|
||||
type Parsed = {
|
||||
format: string;
|
||||
type: string;
|
||||
@@ -99,6 +103,28 @@ export default function LogConsole(props: LogConsoleProps) {
|
||||
let anchor = useRef<any>();
|
||||
let [pastLines, setPastLines] = useState([<span key={0}>{"Loading past entries..."}<br/></span>]);
|
||||
let [lines, setLines] = useState<ReactElement[]>([]);
|
||||
const [consoleHeight, setConsoleHeight] = useLocalStorage(consoleHeightKey, defaultConsoleHeight);
|
||||
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.
|
||||
useEffect(() => {
|
||||
const element = anchor.current?.parentElement as HTMLElement | undefined;
|
||||
if (!element || typeof ResizeObserver === "undefined") {
|
||||
return undefined;
|
||||
}
|
||||
const observer = new ResizeObserver(() => {
|
||||
const next = Math.round(element.offsetHeight);
|
||||
if (next && next !== consoleHeightRef.current) {
|
||||
consoleHeightRef.current = next;
|
||||
setConsoleHeight(next);
|
||||
}
|
||||
});
|
||||
observer.observe(element);
|
||||
return () => observer.disconnect();
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
let logFilter = {
|
||||
@@ -163,7 +189,11 @@ export default function LogConsole(props: LogConsoleProps) {
|
||||
]);
|
||||
|
||||
return <>
|
||||
<Paragraph code className="instance-console">
|
||||
<Paragraph
|
||||
code
|
||||
className="instance-console"
|
||||
style={{ "--console-height": `${consoleHeight}px` } as React.CSSProperties}
|
||||
>
|
||||
{pastLines}
|
||||
{lines}
|
||||
<div className="scroll-anchor" key="anchor" ref={anchor} />
|
||||
|
||||
@@ -171,13 +171,19 @@ body {
|
||||
margin: 0;
|
||||
background: #000;
|
||||
border-color: #252525;
|
||||
height: 300px;
|
||||
/* 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. */
|
||||
height: var(--console-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. */
|
||||
padding-top: 300px;
|
||||
/* 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, 300px);
|
||||
}
|
||||
|
||||
.instance-console .factorio-time {
|
||||
|
||||
Reference in new issue
Block a user