Handle resize

This commit is contained in:
Silvano Cerza 2025-02-13 17:54:59 +01:00
parent 9f62324c2a
commit 5edb8ca742
2 changed files with 90 additions and 69 deletions

View file

@ -1,7 +1,8 @@
import { setIcon } from "obsidian";
import { App, setIcon } from "obsidian";
import { useEffect, useState } from "react";
import { EditorView } from "@codemirror/view";
import { DiffResult } from "./diff";
import { usePlugin } from "../hooks";
interface DiffConnectionProps {
differences: DiffResult[];
@ -25,54 +26,81 @@ const DiffConnections: React.FC<DiffConnectionProps> = ({
modifiedEditor,
}) => {
const [connections, setConnections] = useState<ConnectionChunk[]>([]);
const plugin = usePlugin();
if (!plugin) {
// Unlikely to happen, makes TS happy though
throw new Error("Plugin is not initialized");
}
useEffect(() => {
if (!originalEditor || !modifiedEditor) return;
requestAnimationFrame(() => {
const originalContainer =
originalEditor.scrollDOM.getBoundingClientRect();
const modifiedContainer =
modifiedEditor.scrollDOM.getBoundingClientRect();
const updateConnections = () => {
requestAnimationFrame(() => {
const originalContainer =
originalEditor.scrollDOM.getBoundingClientRect();
const modifiedContainer =
modifiedEditor.scrollDOM.getBoundingClientRect();
// Group consecutive diffs into chunks
const chunks: ConnectionChunk[] = [];
let currentChunk: DiffResult[] = [];
// Group consecutive diffs into chunks
const chunks: ConnectionChunk[] = [];
let currentChunk: DiffResult[] = [];
differences.forEach((diff, i) => {
if (diff.type === "equal") {
if (currentChunk.length > 0) {
// Process the chunk
const chunk = processChunk(
currentChunk,
originalEditor,
modifiedEditor,
originalContainer,
modifiedContainer,
);
if (chunk) chunks.push(chunk);
currentChunk = [];
differences.forEach((diff, i) => {
if (diff.type === "equal") {
if (currentChunk.length > 0) {
// Process the chunk
const chunk = processChunk(
currentChunk,
originalEditor,
modifiedEditor,
originalContainer,
modifiedContainer,
);
if (chunk) chunks.push(chunk);
currentChunk = [];
}
} else {
currentChunk.push(diff);
}
} else {
currentChunk.push(diff);
});
// Process last chunk if exists
if (currentChunk.length > 0) {
const chunk = processChunk(
currentChunk,
originalEditor,
modifiedEditor,
originalContainer,
modifiedContainer,
);
if (chunk) chunks.push(chunk);
}
setConnections(chunks);
});
};
// Process last chunk if exists
if (currentChunk.length > 0) {
const chunk = processChunk(
currentChunk,
originalEditor,
modifiedEditor,
originalContainer,
modifiedContainer,
);
if (chunk) chunks.push(chunk);
}
// Initial update
updateConnections();
setConnections(chunks);
});
}, [differences, originalEditor, modifiedEditor]);
// Setup resize observer
const resizeObserver = new ResizeObserver(updateConnections);
resizeObserver.observe(originalEditor.scrollDOM);
resizeObserver.observe(modifiedEditor.scrollDOM);
// Listen to Obsidian layout changes
const layoutChangeHandler = () => {
updateConnections();
};
plugin.app.workspace.on("layout-change", layoutChangeHandler);
// Cleanup
return () => {
resizeObserver.disconnect();
plugin.app.workspace.off("layout-change", layoutChangeHandler);
};
}, [differences, originalEditor, modifiedEditor, plugin]);
const processChunk = (
chunk: DiffResult[],
@ -229,44 +257,35 @@ const ConnectionButtons: React.FC<{
chunk: ConnectionChunk;
onAction: (action: "left" | "right") => void;
}> = ({ chunk, onAction }) => {
const centerY =
(chunk.startTop + chunk.startBottom + chunk.endTop + chunk.endBottom) / 4;
const showLeftArrow = chunk.type === "modify" || chunk.type === "add";
const showRightArrow = chunk.type === "modify" || chunk.type === "remove";
return (
<foreignObject x="0" y={centerY - 8} width="50" height="16">
<div
style={{
display: "flex",
justifyContent:
showLeftArrow && showRightArrow
? "space-between"
: showLeftArrow
? "flex-end"
: "flex-start",
width: "100%",
height: "100%",
}}
>
{showRightArrow && (
<>
{showRightArrow && (
<foreignObject x="0" y={chunk.startTop} width="16" height="16">
<div
style={{ cursor: "pointer", width: 16, height: 16 }}
onClick={() => onAction("right")}
ref={(node) => node && setIcon(node, "arrow-right")}
ref={(node) => {
if (node) setIcon(node, "arrow-right");
}}
/>
)}
</foreignObject>
)}
{showLeftArrow && (
{showLeftArrow && (
<foreignObject x="34" y={chunk.endTop} width="16" height="16">
<div
style={{ cursor: "pointer", width: 16, height: 16 }}
onClick={() => onAction("left")}
ref={(node) => node && setIcon(node, "arrow-left")}
ref={(node) => {
if (node) setIcon(node, "arrow-left");
}}
/>
)}
</div>
</foreignObject>
</foreignObject>
)}
</>
);
};

View file

@ -2,6 +2,7 @@ import { IconName, ItemView, WorkspaceLeaf } from "obsidian";
import { Root, createRoot } from "react-dom/client";
import DiffView from "./component";
import GitHubSyncPlugin from "src/main";
import { PluginContext } from "../hooks";
export const CONFLICTS_RESOLUTION_VIEW_TYPE = "conflicts-resolution-view";
@ -59,12 +60,13 @@ export class ConflictsResolutionView extends ItemView {
container.empty();
const root: Root = createRoot(container);
root.render(
<DiffView
oldText={oldText1}
newText={newText1}
onResolve={(text) => console.log("Resolved:", text)}
// registerExtension={(ext) => this.plugin.registerEditorExtension(ext)}
/>,
<PluginContext.Provider value={this.plugin}>
<DiffView
oldText={oldText1}
newText={newText1}
onResolve={(text) => console.log("Resolved:", text)}
/>
</PluginContext.Provider>,
);
}