Update example website

This commit is contained in:
Andras Schmelczer 2025-06-15 14:46:51 +01:00
parent 3e87a68dfd
commit 4851e85986
No known key found for this signature in database
GPG key ID: FC8F2C3D3D1A718C
3 changed files with 245 additions and 225 deletions

View file

@ -3,88 +3,75 @@
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta
name="description"
content="Easily merge three versions of a text document with this 3-way text merge tool."
/>
<meta property="og:title" content="3-Way Text Merge" />
<meta
property="og:description"
content="Easily merge three versions of a text document with this 3-way text merge tool."
/>
<meta property="og:type" content="website" />
<meta
property="og:url"
content="https://github.com/schmelczer/reconcile"
/>
<meta property="og:image" content="/favicon.ico" />
<link rel="icon" type="image/x-icon" href="favicon.ico" />
<title>3-Way Text Merge</title>
<link rel="stylesheet" href="style.css" />
</head>
<body>
<div class="container">
<header>
<h1>3-Way Text Merge</h1>
<div class="diamond-layout">
<div class="diamond-row diamond-row-top">
<p>Use this tool to merge three versions of a text.</p>
</header>
<main>
<div class="text-area diamond-parent">
<label for="original">Original</label>
<textarea id="original" rows="10"></textarea>
<textarea id="original" name="original"></textarea>
</div>
</div>
<div class="diamond-row diamond-row-middle">
<div class="text-area diamond-left">
<label for="left">Left</label>
<textarea id="left" rows="10"></textarea>
<label for="left">First concurrent edit</label>
<textarea id="left" name="left"></textarea>
</div>
<div class="text-area diamond-right">
<label for="right">Right</label>
<textarea id="right" rows="10"></textarea>
<label for="right">Second concurrent edit</label>
<textarea id="right" name="right"></textarea>
</div>
</div>
<div class="diamond-row diamond-row-bottom">
<div class="diamond-bottom-content">
<button id="merge-button">Merge</button>
<button id="merge-button" type="button">Merge</button>
<div class="text-area diamond-result">
<label for="merged">Merged</label>
<textarea id="merged" rows="10" readonly></textarea>
<label for="merged">Deconflicted result (readonly)</label>
<textarea id="merged" name="merged" readonly></textarea>
</div>
</div>
</div>
</div>
</div>
<script type="module">
import init, { mergeText } from "./reconcile.js";
</main>
async function run() {
await init();
<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"
>
<path
d="M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z"
/>
</svg>
</a>
</footer>
const originalTextArea = document.getElementById("original");
const leftTextArea = document.getElementById("left");
const rightTextArea = document.getElementById("right");
const mergedTextArea = document.getElementById("merged");
const mergeButton = document.getElementById("merge-button");
const sampleTexts = [
"The quick brown fox jumps over the lazy dog.",
"Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
"Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium.",
"A journey of a thousand miles begins with a single step.",
"To be, or not to be, that is the question.",
];
function loadSample() {
const randomIndex = Math.floor(
Math.random() * sampleTexts.length
);
const text = sampleTexts[randomIndex];
originalTextArea.value = text;
leftTextArea.value = text;
rightTextArea.value = text;
mergedTextArea.value = "";
}
mergeButton.addEventListener("click", () => {
const original = originalTextArea.value;
const left = leftTextArea.value;
const right = rightTextArea.value;
try {
const result = mergeText(original, left, right);
mergedTextArea.value = result;
} catch (e) {
mergedTextArea.value = `Error: ${e}`;
}
});
window.addEventListener("load", loadSample);
}
run();
</script>
<script type="module" src="script.js"></script>
</body>
</html>

View file

@ -0,0 +1,41 @@
import init, { mergeText } from "./reconcile.js";
const originalTextArea = document.getElementById("original");
const leftTextArea = document.getElementById("left");
const rightTextArea = document.getElementById("right");
const mergedTextArea = document.getElementById("merged");
const mergeButton = document.getElementById("merge-button");
const sampleTexts = [
"The quick brown fox jumps over the lazy dog.",
"Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
"Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium.",
"A journey of a thousand miles begins with a single step.",
"To be, or not to be, that is the question.",
];
async function run() {
await init();
mergeButton.addEventListener("click", () => {
const original = originalTextArea.value;
const left = leftTextArea.value;
const right = rightTextArea.value;
const result = mergeText(original, left, right);
mergedTextArea.value = result;
});
loadSample();
}
function loadSample() {
const randomIndex = Math.floor(Math.random() * sampleTexts.length);
const text = sampleTexts[randomIndex];
originalTextArea.value = text;
leftTextArea.value = text;
rightTextArea.value = text;
mergedTextArea.value = "";
}
run();

View file

@ -1,200 +1,192 @@
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
* {
box-sizing: border-box;
margin: 0;
padding: 20px;
background-color: #f0f2f5;
color: #333;
}
.container {
max-width: 1200px;
margin: 0 auto;
html,
body {
height: 100%;
}
body {
font-family: "Segoe UI", Arial, sans-serif;
background: linear-gradient(135deg, #f8fafc 0%, #e0e7ef 100%);
color: #23272f;
display: flex;
flex-direction: column;
gap: 20px;
justify-content: space-between;
}
h1 {
header {
padding: 32px 20px 0 20px;
text-align: center;
color: #1c1e21;
}
.diamond-layout {
header > h1 {
font-size: 2.5rem;
font-weight: 700;
color: #2451a6;
margin-bottom: 8px;
}
header > p {
color: #5a6272;
font-size: 1.1rem;
margin-bottom: 0;
}
main {
flex: 1;
display: grid;
grid-template-rows: auto auto auto;
grid-template-columns: 1fr 1fr 1fr;
gap: 20px 20px;
grid-template-columns: 1fr auto 1fr;
gap: 20px;
justify-items: center;
align-items: center;
margin-bottom: 20px;
padding: 32px 12vw 32px 12vw;
min-height: 540px;
}
.diamond-row {
display: contents;
.diamond-parent {
grid-column: 1 / -1;
}
.diamond-row-top .diamond-parent {
grid-column: 2 / 3;
grid-row: 1 / 2;
.diamond-left {
grid-column: 1;
grid-row: 2;
}
.diamond-row-middle .diamond-left {
grid-column: 1 / 2;
grid-row: 2 / 3;
.diamond-right {
grid-column: 3;
grid-row: 2;
}
.diamond-row-middle .diamond-right {
grid-column: 3 / 4;
grid-row: 2 / 3;
#merge-button {
grid-column: 2;
grid-row: 2;
padding: 12px 36px;
border: none;
border-radius: 8px;
background: linear-gradient(90deg, #2451a6 0%, #3486eb 100%);
color: #fff;
font-size: 1.15rem;
font-weight: 600;
box-shadow: 0 2px 12px 0 rgba(36, 81, 166, 0.08);
cursor: pointer;
align-self: center;
transition: transform 0.2s;
margin: 0 32px;
}
.diamond-row-bottom .diamond-bottom-content {
#merge-button:hover {
transform: scale(1.1);
}
.diamond-right {
grid-column: 3;
grid-row: 2;
}
.diamond-result {
grid-column: 1 / -1;
grid-row: 3;
display: flex;
flex-direction: column;
align-items: center;
width: 100%;
gap: 10px;
grid-column: 2 / 3;
grid-row: 3 / 4;
}
.diamond-row-bottom .diamond-result {
width: 100%;
max-width: 100%;
flex: 1 1 100%;
}
.diamond-bottom-content {
width: 100%;
max-width: none;
display: flex;
flex-direction: column;
align-items: center;
gap: 10px;
}
.diamond-bottom-content .diamond-result {
width: 100%;
max-width: 100%;
}
.diamond-bottom-content textarea {
width: 100%;
max-width: 100%;
}
.diamond-parent, .diamond-result {
grid-column: 1 / -1 !important;
width: 100%;
max-width: none;
min-width: 0;
}
.diamond-left, .diamond-right {
min-width: 280px;
max-width: 500px;
width: 100%;
}
@media (max-width: 900px) {
.diamond-layout {
grid-template-columns: 1fr 1fr;
}
.diamond-row-top .diamond-parent,
.diamond-row-bottom .diamond-bottom-content {
grid-column: 1 / 3;
}
.diamond-row-middle .diamond-left {
grid-column: 1 / 2;
}
.diamond-row-middle .diamond-right {
grid-column: 2 / 3;
}
}
@media (max-width: 600px) {
.diamond-layout {
grid-template-columns: 1fr;
gap: 10px;
}
.diamond-row-top .diamond-parent,
.diamond-row-middle .diamond-left,
.diamond-row-middle .diamond-right,
.diamond-row-bottom .diamond-bottom-content {
grid-column: 1 / 2;
}
.diamond-row-bottom .diamond-bottom-content {
align-items: stretch;
}
.diamond-result textarea,
.diamond-parent textarea,
.diamond-left textarea,
.diamond-right textarea {
font-size: 1rem;
min-height: 100px;
}
button {
font-size: 1.1rem;
padding: 14px 0;
width: 100%;
}
.container {
padding: 8px;
}
}
@media (max-width: 600px) {
.diamond-layout {
grid-template-columns: 1fr;
gap: 10px;
}
.diamond-row-top .diamond-parent,
.diamond-row-middle .diamond-left,
.diamond-row-middle .diamond-right,
.diamond-row-bottom .diamond-result {
grid-column: 1 / 2;
}
pointer-events: none;
}
.text-area {
display: flex;
flex-direction: column;
align-items: center;
width: 100%;
height: 100%;
background: #fff;
border-radius: 10px;
box-shadow: 0 2px 12px 0 rgba(36, 81, 166, 0.06);
padding: 18px 20px 16px 20px;
margin-bottom: 0;
}
label {
margin-bottom: 5px;
font-weight: bold;
margin-bottom: 8px;
font-weight: 600;
color: #2451a6;
}
textarea {
width: 100%;
padding: 10px;
border: 1px solid #ccc;
border-radius: 6px;
border: none;
font-size: 1rem;
font-family: inherit;
color: #23272f;
box-sizing: border-box;
resize: none;
outline: none;
margin-bottom: 0;
height: 100%;
}
textarea[readonly] {
background-color: #e9ebee;
@media (max-width: 900px) {
main {
padding: 24px 2vw;
}
button {
padding: 10px 20px;
border: none;
border-radius: 6px;
background-color: #007bff;
color: white;
font-size: 1rem;
cursor: pointer;
align-self: center;
}
button:hover {
background-color: #0056b3;
}
@media (max-width: 768px) {
.text-areas {
main {
grid-template-columns: 1fr;
grid-template-rows: auto auto auto auto auto;
}
.diamond-parent {
grid-row: 1;
grid-column: 1;
}
.diamond-left {
grid-row: 2;
grid-column: 1;
}
.diamond-right {
grid-row: 3;
grid-column: 1;
}
#merge-button {
grid-row: 4;
grid-column: 1;
}
.diamond-result {
grid-row: 5;
grid-column: 1;
}
}
footer {
position: relative;
margin-top: 32px;
padding: 28px 0 18px 0;
text-align: center;
color: #5a6272;
font-size: 1rem;
box-shadow: 0 -4px 12px 0 rgba(28, 28, 87, 0.1),
0 -1px 2px 0 rgba(1, 1, 3, 0.1);
}
.github-link > svg {
position: absolute;
top: 50%;
right: 36px;
transform: translateY(-50%);
width: 32px;
height: 32px;
transition: transform 0.2s;
}
.github-link > svg:hover {
cursor: pointer;
transform: translateY(-50%) scale(1.15);
}