Improve style

This commit is contained in:
Andras Schmelczer 2025-06-24 22:05:57 +01:00
parent 5e64297cec
commit 763f74a0e2
No known key found for this signature in database
GPG key ID: FC8F2C3D3D1A718C
5 changed files with 63 additions and 30 deletions

View file

@ -2,7 +2,10 @@
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="UTF-8" /> <meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta
name="viewport"
content="width=device-width, initial-scale=1.0, viewport-fit=cover"
/>
<meta <meta
name="description" name="description"
content="Easily merge three versions of a text document with this 3-way text merge tool." content="Easily merge three versions of a text document with this 3-way text merge tool."

View file

@ -1,4 +1,4 @@
import init, { mergeText, mergeTextWithHistory } from "./reconcile.js"; import init, { mergeTextWithHistory } from "./reconcile.js";
const originalTextArea = document.getElementById("original"); const originalTextArea = document.getElementById("original");
const leftTextArea = document.getElementById("left"); const leftTextArea = document.getElementById("left");
@ -7,7 +7,7 @@ const mergedTextArea = document.getElementById("merged");
const sampleText = `The \`reconcile\` Rust library is embedded on this page a WASM module and it powers these text boxes. Experiment with the "Original", "First concurrent edit", and "Second concurrent edit" text boxes to watch competing changes merge in real-time within the "Deconflicted result" box. Here, you will see color-coded tokens marking the origin of each token, including ones that got deleted. The result highly depends on the tokenization strategy, for example, deciding how casing or white-spacing is taken into account.`; const sampleText = `The \`reconcile\` Rust library is embedded on this page a WASM module and it powers these text boxes. Experiment with the "Original", "First concurrent edit", and "Second concurrent edit" text boxes to watch competing changes merge in real-time within the "Deconflicted result" box. Here, you will see color-coded tokens marking the origin of each token, including ones that got deleted. The result highly depends on the tokenization strategy, for example, deciding how casing or white-spacing is taken into account.`;
async function run() { async function main() {
await init(); await init();
originalTextArea.addEventListener("input", updateMergedText); originalTextArea.addEventListener("input", updateMergedText);
@ -17,17 +17,17 @@ async function run() {
loadSample(); loadSample();
updateMergedText(); updateMergedText();
focusTextArea(leftTextArea);
// Put cursor at the end of the text in leftTextArea
leftTextArea.focus();
leftTextArea.selectionStart = leftTextArea.value.length;
leftTextArea.selectionEnd = leftTextArea.value.length;
} }
function resizeTextAreas() { function loadSample() {
autoResize(originalTextArea); originalTextArea.value = sampleText;
autoResize(leftTextArea); leftTextArea.value =
autoResize(rightTextArea); sampleText.replace("color", "colour") +
" Check out what's the most complex conflict you can come up with!";
rightTextArea.value = sampleText
.replace(", for example,", " such as")
.replace("WASM", "WebAssembly");
} }
function updateMergedText() { function updateMergedText() {
@ -50,14 +50,12 @@ function updateMergedText() {
} }
} }
function loadSample() { function resizeTextAreas() {
originalTextArea.value = sampleText; if (!CSS.supports("field-sizing", "content")) {
leftTextArea.value = autoResize(originalTextArea);
sampleText.replace("color", "colour") + autoResize(leftTextArea);
" Check out what's the most complex conflict you can come up with!"; autoResize(rightTextArea);
rightTextArea.value = sampleText }
.replace(", for example,", " such as")
.replace("WASM", "WebAssembly");
} }
function autoResize(textarea) { function autoResize(textarea) {
@ -65,4 +63,10 @@ function autoResize(textarea) {
textarea.style.height = textarea.scrollHeight + "px"; textarea.style.height = textarea.scrollHeight + "px";
} }
run(); function focusTextArea(textarea) {
textarea.focus();
textarea.selectionStart = textarea.value.length;
textarea.selectionEnd = textarea.value.length;
}
main();

View file

@ -20,8 +20,8 @@ body {
position: fixed; position: fixed;
top: 0; top: 0;
left: 0; left: 0;
width: 100%; width: 100vw;
height: 100%; height: 100vh;
z-index: -1; z-index: -1;
} }
@ -138,6 +138,7 @@ textarea {
resize: none; resize: none;
outline: none; outline: none;
margin-bottom: 0; margin-bottom: 0;
field-sizing: content; /* Doesn't work in Safari yet */
} }
#merged { #merged {
@ -145,26 +146,44 @@ textarea {
user-select: text; user-select: text;
} }
.Left, .Unchanged {
user-select: text;
}
.AddedFromLeft, .AddedFromLeft,
.RemovedFromLeft { .RemovedFromLeft {
user-select: text;
background: #12d197; background: #12d197;
} }
.Right, .Right,
.AddedFromRight, .AddedFromRight,
.RemovedFromRight { .RemovedFromRight {
user-select: text;
background: #85bff7; background: #85bff7;
} }
.RemovedFromLeft, .RemovedFromLeft,
.RemovedFromRight { .RemovedFromRight {
user-select: none;
text-decoration: line-through; text-decoration: line-through;
} }
@media (max-width: 900px) { @media (max-width: 900px) {
header {
padding: 32px 18px 0 18px;
}
header > h1 {
margin-bottom: 18px;
}
header > p {
font-size: 1rem;
}
main { main {
padding: 24px 2vw; padding: 18px;
} }
} }
@ -203,7 +222,6 @@ footer {
justify-content: center; justify-content: center;
align-items: center; align-items: center;
color: #5a6272; color: #5a6272;
border-radius: 32px;
} }
.github-link > svg { .github-link > svg {

View file

@ -11,4 +11,4 @@ cp -R pkg/reconcile_bg.wasm examples/website/
cd examples/website/ cd examples/website/
python3 -m http.server $1 python3 -m http.server $1 --bind 0.0.0.0

View file

@ -1,11 +1,9 @@
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
#[cfg(feature = "wasm")] #[cfg(feature = "wasm")]
use wasm_bindgen::prelude::*; use wasm_bindgen::prelude::*;
#[cfg_attr(feature = "wasm", wasm_bindgen)] #[cfg_attr(feature = "wasm", wasm_bindgen)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Debug, Clone, Copy, PartialEq, Eq)] #[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg(feature = "wasm")]
pub enum History { pub enum History {
Unchanged = "Unchanged", Unchanged = "Unchanged",
AddedFromLeft = "AddedFromLeft", AddedFromLeft = "AddedFromLeft",
@ -13,3 +11,13 @@ pub enum History {
RemovedFromLeft = "RemovedFromLeft", RemovedFromLeft = "RemovedFromLeft",
RemovedFromRight = "RemovedFromRight", RemovedFromRight = "RemovedFromRight",
} }
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg(not(feature = "wasm"))]
pub enum History {
Unchanged,
AddedFromLeft,
AddedFromRight,
RemovedFromLeft,
RemovedFromRight,
}