initial commit
This commit is contained in:
602
matrix/index.html
Normal file
602
matrix/index.html
Normal file
@@ -0,0 +1,602 @@
|
||||
<!doctype html>
|
||||
<html lang="zh">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta
|
||||
name="viewport"
|
||||
content="width=device-width, initial-scale=1.0, maximum-scale=1.5, user-scalable=yes"
|
||||
/>
|
||||
<title>MATRIX // DIFF_PROTOCOL</title>
|
||||
|
||||
<!-- Highlight.js 主题 (暗黑基础) -->
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/github-dark.min.css"
|
||||
/>
|
||||
<!-- Diff2Html 核心样式 -->
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://cdn.jsdelivr.net/npm/diff2html@3.4.47/bundles/css/diff2html.min.css"
|
||||
/>
|
||||
|
||||
<!-- 引入极客等宽字体 -->
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css2?family=Share+Tech+Mono&display=swap"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
|
||||
<!-- 引入 Tailwind CSS -->
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
|
||||
<!-- 配置 Tailwind -->
|
||||
<script>
|
||||
tailwind.config = {
|
||||
theme: {
|
||||
extend: {
|
||||
colors: {
|
||||
matrix: {
|
||||
bg: "#000000",
|
||||
green: "#00FF41",
|
||||
darkGreen: "#008F11",
|
||||
darkestGreen: "#003B00",
|
||||
red: "#FF003C",
|
||||
darkRed: "#3B0000",
|
||||
},
|
||||
},
|
||||
fontFamily: {
|
||||
mono: ['"Share Tech Mono"', "monospace", "Courier New"],
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style type="text/tailwindcss">
|
||||
@layer components {
|
||||
/* 矩阵面板 */
|
||||
.matrix-panel {
|
||||
@apply bg-black/85 backdrop-blur-sm border border-matrix-darkGreen shadow-[0_0_10px_rgba(0,143,17,0.2)] relative;
|
||||
}
|
||||
/* 矩阵输入框 */
|
||||
.matrix-input {
|
||||
@apply bg-transparent text-matrix-green border-none outline-none resize-y placeholder:text-matrix-darkGreen/50 focus:shadow-[inset_0_0_20px_rgba(0,255,65,0.05)];
|
||||
text-shadow: 0 0 2px rgba(0, 255, 65, 0.4);
|
||||
}
|
||||
/* 矩阵按钮 */
|
||||
.matrix-btn {
|
||||
@apply bg-transparent text-matrix-green border border-matrix-darkGreen px-4 py-1 font-mono uppercase tracking-widest hover:bg-matrix-green hover:text-black hover:shadow-[0_0_15px_#00FF41] transition-all duration-200 cursor-pointer;
|
||||
}
|
||||
/* 视图切换按钮 */
|
||||
.view-option {
|
||||
@apply px-3 py-1 text-matrix-darkGreen hover:text-matrix-green transition-colors;
|
||||
}
|
||||
.view-option.active {
|
||||
@apply text-black bg-matrix-green shadow-[0_0_10px_#00FF41];
|
||||
}
|
||||
}
|
||||
|
||||
/* ==========================================
|
||||
全局 CRT 扫描线滤镜
|
||||
========================================== */
|
||||
body::after {
|
||||
content: " ";
|
||||
display: block;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
background:
|
||||
linear-gradient(rgba(18, 16, 16, 0) 50%, rgba(0, 0, 0, 0.25) 50%),
|
||||
linear-gradient(
|
||||
90deg,
|
||||
rgba(255, 0, 0, 0.06),
|
||||
rgba(0, 255, 0, 0.02),
|
||||
rgba(0, 0, 255, 0.06)
|
||||
);
|
||||
z-index: 999;
|
||||
background-size:
|
||||
100% 2px,
|
||||
3px 100%;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
/* ==========================================
|
||||
覆盖 Diff2Html 样式 (黑客帝国化)
|
||||
========================================== */
|
||||
.d2h-wrapper {
|
||||
font-family: "Share Tech Mono", monospace !important;
|
||||
color: #00ff41 !important;
|
||||
}
|
||||
.d2h-file-header {
|
||||
display: none !important;
|
||||
}
|
||||
.d2h-file-wrapper {
|
||||
border: none !important;
|
||||
background: transparent !important;
|
||||
margin-bottom: 0 !important;
|
||||
}
|
||||
.d2h-code-line-ctn {
|
||||
@apply font-mono text-[15px] !important;
|
||||
color: #00ff41 !important;
|
||||
text-shadow: 0 0 2px rgba(0, 255, 65, 0.3);
|
||||
}
|
||||
|
||||
/* 差异行背景色 */
|
||||
.d2h-ins {
|
||||
background-color: rgba(0, 59, 0, 0.8) !important;
|
||||
border-color: #00ff41 !important;
|
||||
color: #00ff41 !important;
|
||||
}
|
||||
.d2h-del {
|
||||
background-color: rgba(59, 0, 0, 0.8) !important;
|
||||
border-color: #ff003c !important;
|
||||
color: #ff003c !important;
|
||||
text-shadow: 0 0 2px rgba(255, 0, 60, 0.5);
|
||||
}
|
||||
|
||||
/* 行号区域 */
|
||||
.d2h-code-linenumber {
|
||||
background-color: #000 !important;
|
||||
border-color: #008f11 !important;
|
||||
color: #008f11 !important;
|
||||
}
|
||||
.d2h-info {
|
||||
background-color: #001100 !important;
|
||||
color: #008f11 !important;
|
||||
border-color: #008f11 !important;
|
||||
}
|
||||
.d2h-emptyplaceholder {
|
||||
background-color: #000 !important;
|
||||
border-color: #008f11 !important;
|
||||
}
|
||||
tbody {
|
||||
border-color: #008f11 !important;
|
||||
}
|
||||
td {
|
||||
border-color: #008f11 !important;
|
||||
}
|
||||
|
||||
/* 覆盖 highlight.js 的默认颜色,强制偏绿 (保留部分语法高亮但统一色调) */
|
||||
.hljs-keyword,
|
||||
.hljs-built_in {
|
||||
color: #fff !important;
|
||||
text-shadow: 0 0 5px #fff;
|
||||
}
|
||||
.hljs-string,
|
||||
.hljs-title {
|
||||
color: #00ff41 !important;
|
||||
}
|
||||
.hljs-comment {
|
||||
color: #008f11 !important;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
/* 矩阵滚动条 */
|
||||
::-webkit-scrollbar {
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
}
|
||||
::-webkit-scrollbar-track {
|
||||
background: #000;
|
||||
border-left: 1px solid #008f11;
|
||||
}
|
||||
::-webkit-scrollbar-thumb {
|
||||
background: #003b00;
|
||||
border: 1px solid #008f11;
|
||||
}
|
||||
::-webkit-scrollbar-thumb:hover {
|
||||
background: #00ff41;
|
||||
}
|
||||
|
||||
/* 选中文本颜色 */
|
||||
::selection {
|
||||
background: #00ff41;
|
||||
color: #000;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body
|
||||
class="bg-matrix-bg font-mono p-4 md:p-8 min-h-screen flex flex-col items-center text-matrix-green selection:bg-matrix-green selection:text-black relative overflow-x-hidden"
|
||||
>
|
||||
<!-- HTML5 Canvas 矩阵数字雨背景 -->
|
||||
<canvas id="matrix-canvas" class="fixed inset-0 z-[-1] opacity-40"></canvas>
|
||||
|
||||
<!-- 主窗口 -->
|
||||
<div class="max-w-[1600px] w-full flex flex-col gap-6 z-10">
|
||||
<!-- 标题区 -->
|
||||
<header
|
||||
class="border-b-2 border-matrix-darkGreen pb-4 flex justify-between items-end"
|
||||
>
|
||||
<div>
|
||||
<h1
|
||||
class="text-3xl md:text-4xl font-bold tracking-widest drop-shadow-[0_0_8px_#00FF41]"
|
||||
>
|
||||
WAKE_UP_NEO <span class="animate-pulse">_</span>
|
||||
</h1>
|
||||
<p class="text-matrix-darkGreen mt-2 tracking-[0.2em] text-sm">
|
||||
SYSTEM.DIFF_PROTOCOL // V.1.0.0
|
||||
</p>
|
||||
</div>
|
||||
<div
|
||||
class="hidden md:block text-right text-xs text-matrix-darkGreen tracking-widest"
|
||||
>
|
||||
CONNECTION: SECURE<br />
|
||||
ENCRYPTION: RSA-4096
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<!-- 双栏输入区 -->
|
||||
<div class="flex flex-col lg:flex-row gap-6">
|
||||
<!-- 左侧面板 -->
|
||||
<div class="flex-1 flex flex-col matrix-panel">
|
||||
<div
|
||||
class="flex items-center justify-between px-4 py-2 border-b border-matrix-darkGreen bg-matrix-darkestGreen/50"
|
||||
>
|
||||
<label class="text-sm tracking-widest flex items-center gap-2">
|
||||
> SOURCE_FILE.TXT
|
||||
</label>
|
||||
<button
|
||||
id="clearLeftBtn"
|
||||
class="text-xs text-matrix-darkGreen hover:text-matrix-green transition-colors tracking-widest"
|
||||
>
|
||||
[ PURGE ]
|
||||
</button>
|
||||
</div>
|
||||
<textarea
|
||||
id="leftTextarea"
|
||||
class="matrix-input w-full flex-1 min-h-[260px] h-[300px] p-4 text-[15px] leading-relaxed"
|
||||
spellcheck="false"
|
||||
>
|
||||
function enterMatrix() {
|
||||
console.log("Follow the white rabbit.");
|
||||
return "Ignorance is bliss.";
|
||||
}</textarea
|
||||
>
|
||||
</div>
|
||||
|
||||
<!-- 右侧面板 -->
|
||||
<div class="flex-1 flex flex-col matrix-panel">
|
||||
<div
|
||||
class="flex items-center justify-between px-4 py-2 border-b border-matrix-darkGreen bg-matrix-darkestGreen/50"
|
||||
>
|
||||
<label class="text-sm tracking-widest flex items-center gap-2">
|
||||
> TARGET_FILE.TXT
|
||||
</label>
|
||||
<button
|
||||
id="clearRightBtn"
|
||||
class="text-xs text-matrix-darkGreen hover:text-matrix-green transition-colors tracking-widest"
|
||||
>
|
||||
[ PURGE ]
|
||||
</button>
|
||||
</div>
|
||||
<textarea
|
||||
id="rightTextarea"
|
||||
class="matrix-input w-full flex-1 min-h-[260px] h-[300px] p-4 text-[15px] leading-relaxed"
|
||||
spellcheck="false"
|
||||
>
|
||||
function enterMatrix() {
|
||||
console.log("There is no spoon.");
|
||||
decodeConstruct();
|
||||
return "I know Kung Fu.";
|
||||
}</textarea
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 工具栏 -->
|
||||
<div
|
||||
class="matrix-panel p-4 flex flex-wrap items-center justify-between gap-4"
|
||||
>
|
||||
<div class="flex flex-wrap items-center gap-6">
|
||||
<!-- 语言选择 -->
|
||||
<div class="flex items-center gap-3">
|
||||
<label class="text-sm tracking-widest text-matrix-darkGreen"
|
||||
>PARSER:</label
|
||||
>
|
||||
<select
|
||||
id="languageSelect"
|
||||
class="bg-black border border-matrix-darkGreen text-matrix-green px-3 py-1 text-sm outline-none cursor-pointer hover:border-matrix-green focus:border-matrix-green focus:shadow-[0_0_10px_#00FF41] transition-all appearance-none"
|
||||
>
|
||||
<option value="javascript" selected>JAVASCRIPT</option>
|
||||
<option value="typescript">TYPESCRIPT</option>
|
||||
<option value="html">HTML</option>
|
||||
<option value="css">CSS</option>
|
||||
<option value="json">JSON</option>
|
||||
<option value="python">PYTHON</option>
|
||||
<option value="java">JAVA</option>
|
||||
<option value="cpp">C++</option>
|
||||
<option value="plaintext">RAW_TEXT</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<!-- 视图切换 -->
|
||||
<div
|
||||
class="flex items-center border border-matrix-darkGreen p-0.5"
|
||||
id="viewToggle"
|
||||
>
|
||||
<button class="view-option active" data-view="side-by-side">
|
||||
SPLIT
|
||||
</button>
|
||||
<button class="view-option" data-view="line-by-line">
|
||||
UNIFIED
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 操作按钮 -->
|
||||
<div class="flex gap-4 flex-wrap">
|
||||
<button id="swapBtn" class="matrix-btn">[ INVERT ]</button>
|
||||
<button id="exampleBtn" class="matrix-btn">
|
||||
[ LOAD_SIMULATION ]
|
||||
</button>
|
||||
<button
|
||||
id="compareBtn"
|
||||
class="matrix-btn font-bold bg-matrix-darkestGreen hover:bg-matrix-green hover:text-black shadow-[0_0_10px_rgba(0,255,65,0.2)]"
|
||||
>
|
||||
[ EXECUTE_DIFF ]
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 差异结果区域 -->
|
||||
<div class="matrix-panel flex flex-col">
|
||||
<div
|
||||
class="px-4 py-2 border-b border-matrix-darkGreen bg-matrix-darkestGreen/50 flex items-center justify-between"
|
||||
>
|
||||
<span class="tracking-widest text-sm">> ANALYSIS_RESULT</span>
|
||||
<span id="diffStats" class="text-xs tracking-wider"></span>
|
||||
</div>
|
||||
<div id="diff-output" class="overflow-x-auto min-h-[150px]">
|
||||
<div
|
||||
class="p-12 text-center text-matrix-darkGreen tracking-widest animate-pulse"
|
||||
>
|
||||
WAITING FOR COMMAND...
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 依赖库 -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/diff@5.1.0/dist/diff.min.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/diff2html@3.4.47/bundles/js/diff2html.min.js"></script>
|
||||
|
||||
<!-- 矩阵数字雨 Canvas 脚本 -->
|
||||
<script>
|
||||
const canvas = document.getElementById("matrix-canvas");
|
||||
const ctx = canvas.getContext("2d");
|
||||
|
||||
canvas.width = window.innerWidth;
|
||||
canvas.height = window.innerHeight;
|
||||
|
||||
const katakana =
|
||||
"アァカサタナハマヤャラワガザダバパイィキシチニヒミリヰギジヂビピウゥクスツヌフムユュルグズブヅプエェケセテネヘメレゲゼデベペオォコソトノホモヨョロゴゾドボポヴッン";
|
||||
const latin = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||
const nums = "0123456789";
|
||||
const alphabet = katakana + latin + nums;
|
||||
|
||||
const fontSize = 16;
|
||||
const columns = canvas.width / fontSize;
|
||||
|
||||
const rainDrops = [];
|
||||
for (let x = 0; x < columns; x++) {
|
||||
rainDrops[x] = 1;
|
||||
}
|
||||
|
||||
const draw = () => {
|
||||
ctx.fillStyle = "rgba(0, 0, 0, 0.05)";
|
||||
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
||||
|
||||
ctx.fillStyle = "#0F0";
|
||||
ctx.font = fontSize + "px monospace";
|
||||
|
||||
for (let i = 0; i < rainDrops.length; i++) {
|
||||
const text = alphabet.charAt(
|
||||
Math.floor(Math.random() * alphabet.length),
|
||||
);
|
||||
ctx.fillText(text, i * fontSize, rainDrops[i] * fontSize);
|
||||
|
||||
if (
|
||||
rainDrops[i] * fontSize > canvas.height &&
|
||||
Math.random() > 0.975
|
||||
) {
|
||||
rainDrops[i] = 0;
|
||||
}
|
||||
rainDrops[i]++;
|
||||
}
|
||||
};
|
||||
|
||||
setInterval(draw, 30);
|
||||
|
||||
window.addEventListener("resize", () => {
|
||||
canvas.width = window.innerWidth;
|
||||
canvas.height = window.innerHeight;
|
||||
});
|
||||
</script>
|
||||
|
||||
<!-- 核心对比逻辑 -->
|
||||
<script>
|
||||
(function () {
|
||||
"use strict";
|
||||
|
||||
const leftTextarea = document.getElementById("leftTextarea");
|
||||
const rightTextarea = document.getElementById("rightTextarea");
|
||||
const compareBtn = document.getElementById("compareBtn");
|
||||
const swapBtn = document.getElementById("swapBtn");
|
||||
const exampleBtn = document.getElementById("exampleBtn");
|
||||
const clearLeftBtn = document.getElementById("clearLeftBtn");
|
||||
const clearRightBtn = document.getElementById("clearRightBtn");
|
||||
const languageSelect = document.getElementById("languageSelect");
|
||||
const diffOutput = document.getElementById("diff-output");
|
||||
const diffStats = document.getElementById("diffStats");
|
||||
const viewOptions = document.querySelectorAll(".view-option");
|
||||
|
||||
let currentView = "side-by-side";
|
||||
|
||||
function getSelectedLanguage() {
|
||||
return languageSelect.value;
|
||||
}
|
||||
|
||||
function getHighlightConfig() {
|
||||
const lang = getSelectedLanguage();
|
||||
if (lang === "plaintext") return false;
|
||||
return { enabled: true, language: lang };
|
||||
}
|
||||
|
||||
function generateUnifiedDiff(original, modified) {
|
||||
return Diff.createTwoFilesPatch(
|
||||
"SOURCE",
|
||||
"TARGET",
|
||||
original || "",
|
||||
modified || "",
|
||||
"",
|
||||
"",
|
||||
{ context: 4 },
|
||||
);
|
||||
}
|
||||
|
||||
function renderDiff() {
|
||||
const leftText = leftTextarea.value;
|
||||
const rightText = rightTextarea.value;
|
||||
|
||||
let diffString;
|
||||
try {
|
||||
diffString = generateUnifiedDiff(leftText, rightText);
|
||||
} catch (e) {
|
||||
diffOutput.innerHTML = `<div class="p-12 text-center text-matrix-red tracking-widest">FATAL_ERROR: ${e.message}</div>`;
|
||||
diffStats.textContent = "ERR";
|
||||
return;
|
||||
}
|
||||
|
||||
const configuration = {
|
||||
drawFileList: false,
|
||||
matching: "lines",
|
||||
outputFormat: currentView,
|
||||
highlight: getHighlightConfig(),
|
||||
renderNothingWhenEmpty: false,
|
||||
};
|
||||
|
||||
let diffHtml = "";
|
||||
try {
|
||||
diffHtml = Diff2Html.html(diffString, configuration);
|
||||
} catch (e) {
|
||||
diffOutput.innerHTML = `<div class="p-12 text-center text-matrix-red tracking-widest">RENDER_FAILURE</div>`;
|
||||
diffStats.textContent = "ERR";
|
||||
return;
|
||||
}
|
||||
|
||||
diffOutput.innerHTML = diffHtml;
|
||||
|
||||
const selectedLang = getSelectedLanguage();
|
||||
if (selectedLang !== "plaintext") {
|
||||
const codeBlocks = diffOutput.querySelectorAll("code");
|
||||
if (codeBlocks.length > 0 && window.hljs) {
|
||||
codeBlocks.forEach((block) => {
|
||||
block.classList.forEach((cls) => {
|
||||
if (cls.startsWith("language-")) block.classList.remove(cls);
|
||||
});
|
||||
block.classList.add(`language-${selectedLang}`);
|
||||
if (block.dataset.highlighted) {
|
||||
delete block.dataset.highlighted;
|
||||
}
|
||||
try {
|
||||
hljs.highlightElement(block);
|
||||
} catch (e) {}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const addedLines = diffOutput.querySelectorAll(".d2h-ins").length;
|
||||
const deletedLines = diffOutput.querySelectorAll(".d2h-del").length;
|
||||
if (addedLines === 0 && deletedLines === 0) {
|
||||
diffStats.innerHTML =
|
||||
"<span class='text-matrix-darkGreen'>MATCH_FOUND // NO_ANOMALIES</span>";
|
||||
} else {
|
||||
diffStats.innerHTML = `<span class='text-matrix-green'>+${addedLines} INJECTED</span> <span class='text-matrix-darkGreen mx-2'>|</span> <span class='text-matrix-red'>-${deletedLines} PURGED</span>`;
|
||||
}
|
||||
|
||||
if (!diffHtml.trim() || diffOutput.innerText.trim() === "") {
|
||||
diffOutput.innerHTML =
|
||||
'<div class="p-12 text-center text-matrix-darkGreen tracking-widest">DATA_STREAMS_ARE_IDENTICAL.</div>';
|
||||
diffStats.innerHTML =
|
||||
"<span class='text-matrix-darkGreen'>SYNCED</span>";
|
||||
}
|
||||
}
|
||||
|
||||
function setActiveView(view) {
|
||||
currentView = view;
|
||||
viewOptions.forEach((btn) => {
|
||||
const val = btn.getAttribute("data-view");
|
||||
if (val === view) {
|
||||
btn.classList.add("active");
|
||||
} else {
|
||||
btn.classList.remove("active");
|
||||
}
|
||||
});
|
||||
if (
|
||||
diffOutput.querySelector(".d2h-wrapper") ||
|
||||
diffOutput.children.length > 0
|
||||
) {
|
||||
renderDiff();
|
||||
}
|
||||
}
|
||||
|
||||
function loadExample() {
|
||||
leftTextarea.value = `function enterMatrix() {\n console.log("Follow the white rabbit.");\n return "Ignorance is bliss.";\n}`;
|
||||
rightTextarea.value = `function enterMatrix() {\n console.log("There is no spoon.");\n decodeConstruct();\n return "I know Kung Fu.";\n}`;
|
||||
languageSelect.value = "javascript";
|
||||
renderDiff();
|
||||
}
|
||||
|
||||
function swapTexts() {
|
||||
const temp = leftTextarea.value;
|
||||
leftTextarea.value = rightTextarea.value;
|
||||
rightTextarea.value = temp;
|
||||
renderDiff();
|
||||
}
|
||||
|
||||
function clearLeft() {
|
||||
leftTextarea.value = "";
|
||||
renderDiff();
|
||||
}
|
||||
function clearRight() {
|
||||
rightTextarea.value = "";
|
||||
renderDiff();
|
||||
}
|
||||
|
||||
compareBtn.addEventListener("click", renderDiff);
|
||||
swapBtn.addEventListener("click", swapTexts);
|
||||
exampleBtn.addEventListener("click", loadExample);
|
||||
clearLeftBtn.addEventListener("click", clearLeft);
|
||||
clearRightBtn.addEventListener("click", clearRight);
|
||||
|
||||
languageSelect.addEventListener("change", () => {
|
||||
if (
|
||||
diffOutput.querySelector(".d2h-wrapper") ||
|
||||
diffOutput.children.length > 0
|
||||
)
|
||||
renderDiff();
|
||||
});
|
||||
|
||||
viewOptions.forEach((btn) => {
|
||||
btn.addEventListener("click", (e) => {
|
||||
setActiveView(e.currentTarget.getAttribute("data-view"));
|
||||
});
|
||||
});
|
||||
|
||||
document.addEventListener("keydown", (e) => {
|
||||
if ((e.ctrlKey || e.metaKey) && e.key === "Enter") {
|
||||
e.preventDefault();
|
||||
renderDiff();
|
||||
}
|
||||
});
|
||||
|
||||
window.addEventListener("DOMContentLoaded", renderDiff);
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user