Add cursors to example
This commit is contained in:
parent
9c79ebc653
commit
f73cd057be
5 changed files with 243 additions and 41 deletions
222
examples/website/src/index.html
Normal file
222
examples/website/src/index.html
Normal file
|
|
@ -0,0 +1,222 @@
|
|||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta
|
||||
name="viewport"
|
||||
content="width=device-width, initial-scale=1.0, viewport-fit=cover"
|
||||
/>
|
||||
<meta
|
||||
name="description"
|
||||
content="3-way text merging that automatically resolves conflicts. No more Git conflict markers — just clean, merged results."
|
||||
/>
|
||||
<meta property="og:title" content="3-Way Text Merge" />
|
||||
<meta
|
||||
property="og:description"
|
||||
content="3-way text merging that automatically resolves conflicts. No more Git conflict markers — just clean, merged results."
|
||||
/>
|
||||
<meta property="og:type" content="website" />
|
||||
<meta property="og:url" content="https://schmelczer.dev/reconcile" />
|
||||
<meta property="og:image" content="/favicon.ico" />
|
||||
<link rel="icon" type="image/x-icon" href="favicon.ico" />
|
||||
<title>Reconcile: conflict-free text merging</title>
|
||||
<link inline inline-asset="index.css" inline-asset-delete />
|
||||
</head>
|
||||
<body>
|
||||
<div class="background"></div>
|
||||
|
||||
<div class="scroll-container">
|
||||
<div class="page-wrapper">
|
||||
<header>
|
||||
<h1>Reconcile-text: conflict-free 3-way text merging</h1>
|
||||
<p>
|
||||
Think
|
||||
<a
|
||||
href="https://www.gnu.org/software/diffutils/manual/html_node/Invoking-diff3.html"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>diff3</a
|
||||
>
|
||||
or <code>git merge</code>, but with intelligent conflict resolution that
|
||||
requires no user intervention. The
|
||||
<a
|
||||
href="https://github.com/schmelczer/reconcile"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>Reconcile</a
|
||||
>
|
||||
library tackles a fundamental challenge in collaborative editing: what happens
|
||||
when multiple users edit the same text simultaneously, but the conflict
|
||||
resolver only has access to the final results, not the intermediate steps?
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Where traditional merge tools leave you with conflict markers to resolve
|
||||
manually, Reconcile automatically weaves changes together. The
|
||||
<code>reconcile(parent, left, right)</code> function takes conflicting edits
|
||||
and produces clean, unified results using an algorithm inspired by Operational
|
||||
Transformation. No more <code><<<<<<<</code> markers
|
||||
cluttering your text.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The process starts with your chosen tokenisation strategy, then applies Myers'
|
||||
diff algorithm to compare the original with both modified versions. These
|
||||
diffs are optimised and transformed to preserve meaningful changes, before a
|
||||
final merge strategy combines all modifications without losing any edits.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Ready to dive deeper? Check out the
|
||||
<a
|
||||
href="https://github.com/schmelczer/reconcile"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>documentation</a
|
||||
>
|
||||
or try editing the text boxes below to see Reconcile in action.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Use the tokenisation options below to experiment with different approaches —
|
||||
the library also supports custom tokenisers.
|
||||
</p>
|
||||
</header>
|
||||
|
||||
<main>
|
||||
<section class="tokenizer-selector">
|
||||
<div class="radio-group" role="radiogroup" aria-label="Tokenization strategy">
|
||||
<label class="radio-option">
|
||||
<input
|
||||
type="radio"
|
||||
name="tokenizer"
|
||||
value="Character"
|
||||
id="tokenizer-character"
|
||||
/>
|
||||
<span class="radio-custom" aria-hidden="true"></span>
|
||||
<div class="radio-content">
|
||||
<span class="radio-label">Character</span>
|
||||
<span class="radio-description">Fine-grained merging</span>
|
||||
</div>
|
||||
</label>
|
||||
<label class="radio-option">
|
||||
<input
|
||||
type="radio"
|
||||
name="tokenizer"
|
||||
value="Word"
|
||||
id="tokenizer-word"
|
||||
checked
|
||||
/>
|
||||
<span class="radio-custom" aria-hidden="true"></span>
|
||||
<div class="radio-content">
|
||||
<span class="radio-label">Word</span>
|
||||
<span class="radio-description">Retain full words (default)</span>
|
||||
</div>
|
||||
</label>
|
||||
<label class="radio-option">
|
||||
<input type="radio" name="tokenizer" value="Line" id="tokenizer-line" />
|
||||
<span class="radio-custom" aria-hidden="true"></span>
|
||||
<div class="radio-content">
|
||||
<span class="radio-label">Line</span>
|
||||
<span class="radio-description"
|
||||
>Line-by-line, like <code>git merge</code></span
|
||||
>
|
||||
</div>
|
||||
</label>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div class="text-area-card diamond-parent">
|
||||
<label
|
||||
for="original"
|
||||
title="The original text before any concurrent edits were made."
|
||||
>Original</label
|
||||
>
|
||||
<textarea id="original" name="original"></textarea>
|
||||
</div>
|
||||
|
||||
<div class="text-area-card diamond-left">
|
||||
<label
|
||||
for="left"
|
||||
title="First user's edits — changes from this box appear in green in the result."
|
||||
>
|
||||
First user's edits
|
||||
<div class="box Left"></div>
|
||||
</label>
|
||||
<textarea id="left" name="left"></textarea>
|
||||
</div>
|
||||
|
||||
<div class="text-area-card diamond-right">
|
||||
<label
|
||||
for="right"
|
||||
title="Second user's edits — changes from this box appear in blue in the result."
|
||||
>
|
||||
Second user's edits
|
||||
<div class="box Right"></div>
|
||||
</label>
|
||||
<textarea id="right" name="right"></textarea>
|
||||
</div>
|
||||
|
||||
<div class="text-area-card diamond-result">
|
||||
<label
|
||||
for="merged"
|
||||
title="The automatically merged result — edit the boxes above to see changes in real-time."
|
||||
>
|
||||
Merged result
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
|
||||
<path
|
||||
d="M10 10l-6 6v4h4l6 -6m1.99 -1.99l2.504 -2.504a2.828 2.828 0 1 0 -4 -4l-2.5 2.5"
|
||||
></path>
|
||||
<path d="M13.5 6.5l4 4"></path>
|
||||
<path d="M3 3l18 18"></path>
|
||||
</svg>
|
||||
</label>
|
||||
<div id="merged" role="textbox" aria-readonly="true" aria-live="polite"></div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<footer>
|
||||
<p>2025 Andras Schmelczer</p>
|
||||
<a
|
||||
href="https://github.com/schmelczer/reconcile"
|
||||
class="github-link"
|
||||
aria-label="GitHub repository"
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
>
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
|
||||
<path
|
||||
d="M9 19c-4.3 1.4 -4.3 -2.5 -6 -3m12 5v-3.5c0 -1 .1 -1.4 -.5 -2c2.8 -.3 5.5 -1.4 5.5 -6a4.6 4.6 0 0 0 -1.3 -3.2a4.2 4.2 0 0 0 -.1 -3.2s-1.1 -.3 -3.5 1.3a12.3 12.3 0 0 0 -6.2 0c-2.4 -1.6 -3.5 -1.3 -3.5 -1.3a4.2 4.2 0 0 0 -.1 3.2a4.6 4.6 0 0 0 -1.3 3.2c0 4.6 2.7 5.7 5.5 6c-.6 .6 -.6 1.2 -.5 2v3.5"
|
||||
/>
|
||||
</svg>
|
||||
</a>
|
||||
</footer>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<noscript>JavaScript is required for this website to function properly.</noscript>
|
||||
|
||||
<script inline inline-asset="index.js" inline-asset-delete></script>
|
||||
</body>
|
||||
</html>
|
||||
Loading…
Add table
Add a link
Reference in a new issue