Handle grid sizes in a nicer way

This commit is contained in:
Silvano Cerza 2025-02-20 14:25:54 +01:00
parent 6ff48b9517
commit 8b1d04d110
3 changed files with 96 additions and 72 deletions

View file

@ -6,14 +6,27 @@ interface ActionsGutterProps {
// This is essential to correctly draw the lines between
// the left and right editor
lineHeight: number;
width: number;
}
const ActionsGutter: React.FC<ActionsGutterProps> = ({
diffChunks,
lineHeight,
width,
}) => {
const [actualWidth, setActualWidth] = React.useState(0);
const containerRef = React.useRef<HTMLDivElement>(null);
React.useEffect(() => {
const resizeObserver = new ResizeObserver((entries) => {
setActualWidth(entries[0].contentRect.width);
});
if (containerRef.current) {
resizeObserver.observe(containerRef.current);
}
return () => resizeObserver.disconnect();
}, []);
const drawChunk = (chunk: DiffChunk, index: number) => {
const topLeft = (chunk.startLeftLine - 1) * lineHeight;
const bottomLeft = (chunk.endLeftLine - 1) * lineHeight;
@ -30,9 +43,9 @@ const ActionsGutter: React.FC<ActionsGutterProps> = ({
<path
d={`
M 0 ${topLeft}
C ${width * 0.4} ${topLeft}, ${width * 0.6} ${topRight}, ${width} ${topRight}
L ${width} ${bottomRight}
C ${width * 0.6} ${bottomRight}, ${width * 0.4} ${bottomLeft}, 0 ${bottomLeft}
C ${actualWidth * 0.4} ${topLeft}, ${actualWidth * 0.6} ${topRight}, ${actualWidth} ${topRight}
L ${actualWidth} ${bottomRight}
C ${actualWidth * 0.6} ${bottomRight}, ${actualWidth * 0.4} ${bottomLeft}, 0 ${bottomLeft}
Z
`}
fill={color}
@ -45,7 +58,7 @@ const ActionsGutter: React.FC<ActionsGutterProps> = ({
};
return (
<div style={{ width: width }}>
<div ref={containerRef} style={{ width: "100%" }}>
<svg
style={{
width: "100%",

View file

@ -43,49 +43,60 @@ const DiffView: React.FC<DiffViewProps> = ({
setLineHeight(editor.defaultLineHeight);
};
// const [leftWidth, setLeftWidth] = useState("33%");
const [gutterWidth, setGutterWidth] = useState(100);
// const [rightWidth, setRightWidth] = useState("33%");
const [actualWidth, setActualWidth] = React.useState(0);
const containerRef = React.useRef<HTMLDivElement>(null);
const [leftWidth, setLeftWidth] = useState("33%");
const [gutterWidth, setGutterWidth] = useState("33%");
const [rightWidth, setRightWidth] = useState("33%");
React.useEffect(() => {
const resizeObserver = new ResizeObserver((entries) => {
const actualWidth = entries[0].contentRect.width;
setActualWidth(actualWidth);
setLeftWidth(`${actualWidth / 3}px`);
setGutterWidth(`${actualWidth / 3}px`);
setRightWidth(`${actualWidth / 3}px`);
});
if (containerRef.current) {
resizeObserver.observe(containerRef.current);
}
return () => resizeObserver.disconnect();
}, []);
const diffs = diff(oldText, newText);
return (
<div
ref={containerRef}
style={{
width: "100%",
display: "grid",
gridTemplateColumns: "1fr auto 1fr",
gridTemplateColumns: `${leftWidth} ${gutterWidth} ${rightWidth}`,
gridTemplateRows: "1fr",
gap: "0px",
}}
>
<div>
<EditorPane
content={oldText}
highlightPluginSpec={{
diff: diffs,
isOriginal: true,
}}
onEditorUpdate={handleEditorReady}
onContentChange={onOldTextChange}
/>
</div>
<div>
<ActionsGutter
diffChunks={diffs}
lineHeight={lineHeight}
width={gutterWidth}
/>
</div>
<div>
<EditorPane
content={newText}
highlightPluginSpec={{
diff: diffs,
isOriginal: false,
}}
onContentChange={onNewTextChange}
/>
</div>
<EditorPane
content={oldText}
highlightPluginSpec={{
diff: diffs,
isOriginal: true,
}}
onEditorUpdate={handleEditorReady}
onContentChange={onOldTextChange}
/>
<ActionsGutter diffChunks={diffs} lineHeight={lineHeight} />
<EditorPane
content={newText}
highlightPluginSpec={{
diff: diffs,
isOriginal: false,
}}
onContentChange={onNewTextChange}
/>
</div>
);
};

View file

@ -14,45 +14,45 @@ interface EditorPaneProps {
onContentChange: (content: string) => void;
}
const EditorPane: React.FC<EditorPaneProps> = ({
content,
highlightPluginSpec,
onEditorUpdate,
onContentChange,
}) => {
const extensions = [
// basicSetup minus line numbers
// EditorView.lineWrapping,
EditorView.editable.of(true),
createDiffHighlightPlugin(highlightPluginSpec),
EditorView.theme({
"&": {
backgroundColor: "var(--background-primary)",
color: "var(--text-normal)",
},
".cm-content": {
padding: 0,
caretColor: "var(--caret-color)",
fontSize: "var(--font-text-size)",
fontFamily: "var(--font-text)",
},
"&.cm-focused .cm-selectionBackground, .cm-selectionBackground": {
background: "var(--text-selection)",
},
"&.cm-focused": {
outline: 0,
},
"&.cm-focused .cm-cursor": {
borderLeftColor: "var(--text-normal)",
},
}),
markdown(),
];
const EditorPane: React.FC<EditorPaneProps> = (props) => {
const { content, highlightPluginSpec, onEditorUpdate, onContentChange } =
props;
const extensions = React.useMemo(() => {
return [
// basicSetup minus line numbers
// EditorView.lineWrapping,
EditorView.editable.of(true),
createDiffHighlightPlugin(highlightPluginSpec),
EditorView.theme({
"&": {
backgroundColor: "var(--background-primary)",
color: "var(--text-normal)",
},
".cm-content": {
padding: 0,
caretColor: "var(--caret-color)",
fontSize: "var(--font-text-size)",
fontFamily: "var(--font-text)",
},
"&.cm-focused .cm-selectionBackground, .cm-selectionBackground": {
background: "var(--text-selection)",
},
"&.cm-focused": {
outline: 0,
},
"&.cm-focused .cm-cursor": {
borderLeftColor: "var(--text-normal)",
},
}),
markdown(),
];
}, [highlightPluginSpec]);
return (
<CodeMirror
value={content}
theme={"none"}
width={"100%"}
basicSetup={false}
extensions={extensions}
onUpdate={(viewUpdate: ViewUpdate) => {