Files
diff.tootaio.com/notion/index.html
xiaomai e9fcd411a7 feat(theme): add style switcher and centralize diff logic
Extract duplicated diff rendering logic into shared/diff-page.js
Implement theme switcher component across all templates
2026-04-08 14:39:39 +08:00

381 lines
13 KiB
HTML

<!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>Diff Checker - Notion Style</title>
<!-- Highlight.js 主题 (GitHub 风格最接近 Notion 的代码块) -->
<link
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/github.min.css"
/>
<!-- Diff2Html 核心样式 -->
<link
rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/diff2html@3.4.47/bundles/css/diff2html.min.css"
/>
<!-- 引入 Inter 字体 (Notion 默认英文字体) -->
<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=Inter:wght@400;500;600&display=swap"
rel="stylesheet"
/>
<!-- 引入 Tailwind CSS -->
<script src="https://cdn.tailwindcss.com"></script>
<!-- 配置 Tailwind -->
<script>
tailwind.config = {
theme: {
extend: {
colors: {
notion: {
text: "#37352f" /* Notion 默认文字黑 */,
gray: "#787774" /* Notion 默认次要文字灰 */,
lightGray: "#9a9a97" /* 更浅的灰 */,
bg: "#ffffff" /* 纯白背景 */,
hover: "#efefed" /* 悬浮浅灰背景 */,
codeBg: "#f7f7f5" /* 代码块背景灰 */,
border: "#e9e9e7" /* 极细边框灰 */,
blue: "#2383e2" /* Notion 链接/按钮蓝 */,
diffAdd: "#edf3ec" /* 低饱和度绿 */,
diffDel: "#fbe4e4" /* 低饱和度红 */,
},
},
fontFamily: {
sans: [
'"Inter"',
"-apple-system",
"BlinkMacSystemFont",
'"Segoe UI"',
"sans-serif",
],
mono: [
'"SFMono-Regular"',
"Menlo",
"Monaco",
"Consolas",
'"Liberation Mono"',
'"Courier New"',
"monospace",
],
},
},
},
};
</script>
<style type="text/tailwindcss">
@layer components {
/* Notion 风格按钮 */
.notion-btn {
@apply px-3 py-1.5 rounded-[4px] text-sm font-medium transition-colors duration-200 flex items-center gap-1.5 cursor-pointer select-none;
}
.notion-btn-ghost {
@apply text-notion-text bg-transparent hover:bg-notion-hover active:bg-[#e1e1df];
}
.notion-btn-primary {
@apply text-white bg-[#2f2f2f] hover:bg-[#454545] active:bg-[#1a1a1a];
}
/* 视图切换按钮 */
.view-option {
@apply px-2.5 py-1 rounded-[4px] text-sm text-notion-gray hover:bg-notion-hover transition-colors cursor-pointer select-none;
}
.view-option.active {
@apply text-notion-text font-medium bg-notion-hover;
}
.style-switcher {
@apply flex items-center gap-2;
}
.style-switcher-label {
@apply text-sm text-notion-gray;
}
.style-switcher-select {
@apply bg-transparent hover:bg-notion-hover px-2 py-1 rounded-[4px] text-sm text-notion-text outline-none cursor-pointer transition-colors appearance-none;
}
/* Notion 代码块输入框 */
.notion-input-wrapper {
@apply bg-notion-codeBg rounded-[4px] border border-transparent focus-within:border-notion-border transition-colors flex flex-col;
}
}
/* ==========================================
深度定制 Diff2Html 样式 (Notion 极简风)
========================================== */
.d2h-wrapper {
font-family:
"SFMono-Regular", Menlo, Monaco, Consolas, monospace !important;
color: #37352f !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-[13px] !important;
color: #37352f !important;
}
/* 移除所有表格边框 */
tbody,
td,
.d2h-code-linenumber,
.d2h-info,
.d2h-emptyplaceholder {
border: none !important;
}
/* 差异行背景色 (Notion 低饱和度色彩) */
.d2h-ins {
background-color: #edf3ec !important;
}
.d2h-del {
background-color: #fbe4e4 !important;
}
/* 行号区域极简处理 */
.d2h-code-linenumber {
background-color: #f7f7f5 !important;
color: rgba(55, 53, 47, 0.4) !important;
padding-right: 12px !important;
}
.d2h-info {
background-color: #ffffff !important;
color: rgba(55, 53, 47, 0.4) !important;
}
.d2h-emptyplaceholder {
background-color: #f7f7f5 !important;
}
/* 滚动条极简处理 */
::-webkit-scrollbar {
width: 8px;
height: 8px;
}
::-webkit-scrollbar-track {
background: transparent;
}
::-webkit-scrollbar-thumb {
background: #d3d1cb;
border-radius: 4px;
border: 2px solid #fff;
}
::-webkit-scrollbar-thumb:hover {
background: #aeaca6;
}
/* 选中文本颜色 */
::selection {
background: rgba(35, 131, 226, 0.28);
}
</style>
</head>
<body
class="bg-notion-bg text-notion-text font-sans min-h-screen flex flex-col items-center selection:bg-[#cce2ff]"
>
<!-- 页面容器 (限制最大宽度,类似 Notion 页面) -->
<div class="max-w-[1100px] w-full px-6 py-12 md:py-20 flex flex-col gap-8">
<!-- 标题区 (大字号,带 Emoji) -->
<header class="flex flex-col gap-2">
<h1 class="text-4xl font-bold tracking-tight flex items-center gap-3">
<span class="text-4xl">⚖️</span> Diff Checker
</h1>
<p class="text-notion-gray text-base mt-2">
Paste your code below to compare changes. Supports syntax
highlighting.
</p>
</header>
<!-- 双栏输入区 -->
<div class="flex flex-col lg:flex-row gap-6">
<!-- 左侧面板 -->
<div class="flex-1 notion-input-wrapper">
<div
class="flex items-center justify-between px-4 py-2 border-b border-notion-border/50"
>
<label class="text-sm text-notion-gray font-medium">Original</label>
<button
id="clearLeftBtn"
class="text-xs text-notion-lightGray hover:text-notion-text transition-colors"
>
Clear
</button>
</div>
<textarea
id="leftTextarea"
class="w-full flex-1 min-h-[260px] h-[300px] p-4 bg-transparent font-mono text-[13px] leading-relaxed resize-y outline-none placeholder:text-notion-lightGray"
spellcheck="false"
>
function hello() {
console.log("Hello World");
return "Hi";
}</textarea
>
</div>
<!-- 右侧面板 -->
<div class="flex-1 notion-input-wrapper">
<div
class="flex items-center justify-between px-4 py-2 border-b border-notion-border/50"
>
<label class="text-sm text-notion-gray font-medium">Modified</label>
<button
id="clearRightBtn"
class="text-xs text-notion-lightGray hover:text-notion-text transition-colors"
>
Clear
</button>
</div>
<textarea
id="rightTextarea"
class="w-full flex-1 min-h-[260px] h-[300px] p-4 bg-transparent font-mono text-[13px] leading-relaxed resize-y outline-none placeholder:text-notion-lightGray"
spellcheck="false"
>
function hello() {
console.log("Hello, Diff Checker!");
return "Hey there";
}</textarea
>
</div>
</div>
<!-- 工具栏 (极简分割线上下) -->
<div
class="flex flex-wrap items-center justify-between gap-4 py-2 border-y border-notion-border"
>
<div class="flex flex-wrap items-center gap-4">
<!-- 语言选择 -->
<div class="flex items-center gap-2">
<span class="text-sm text-notion-gray">Language</span>
<select
id="languageSelect"
class="bg-transparent hover:bg-notion-hover px-2 py-1 rounded-[4px] text-sm text-notion-text outline-none cursor-pointer transition-colors 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">Plain Text</option>
</select>
</div>
<div class="w-[1px] h-4 bg-notion-border hidden md:block"></div>
<!-- 视图切换 -->
<div class="flex items-center gap-1" id="viewToggle">
<button class="view-option active" data-view="side-by-side">
Split view
</button>
<button class="view-option" data-view="line-by-line">
Unified view
</button>
</div>
<div class="w-[1px] h-4 bg-notion-border hidden md:block"></div>
<div data-style-switcher></div>
</div>
<!-- 操作按钮 -->
<div class="flex gap-2 flex-wrap">
<button id="swapBtn" class="notion-btn notion-btn-ghost">
<svg
class="w-4 h-4"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M8 7h12m0 0l-4-4m4 4l-4 4m0 6H4m0 0l4 4m-4-4l4-4"
></path>
</svg>
Swap
</button>
<button id="exampleBtn" class="notion-btn notion-btn-ghost">
Demo
</button>
<button id="compareBtn" class="notion-btn notion-btn-primary ml-2">
Compare
</button>
</div>
</div>
<!-- 差异结果区域 -->
<div class="flex flex-col gap-2">
<div class="flex items-center justify-between py-1">
<h2 class="text-lg font-semibold">Result</h2>
<span id="diffStats" class="text-sm text-notion-gray"></span>
</div>
<div class="notion-input-wrapper overflow-hidden">
<div id="diff-output" class="overflow-x-auto min-h-[100px]">
<div class="p-8 text-center text-notion-lightGray text-sm">
Click "Compare" to see the differences.
</div>
</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>
<script src="../shared/diff-page.js"></script>
<script>
window.initDiffPage({
themeId: "notion",
currentThemePath: "notion/index.html",
switcherLabel: "Style",
switcherAriaLabel: "Switch Notion style",
fileLabels: {
left: "Original",
right: "Modified",
},
example: {
left: `function hello() {\n console.log("Hello World");\n return "Hi";\n}`,
right: `function hello() {\n console.log("Hello, Diff Checker!");\n return "Hey there";\n}`,
language: "javascript",
},
messages: {
generateError: (error) =>
`<div class="p-8 text-center text-[#eb5757] text-sm">Error: ${error.message}</div>`,
renderError: () =>
'<div class="p-8 text-center text-[#eb5757] text-sm">Render Failed</div>',
blankResult:
'<div class="p-8 text-center text-notion-lightGray text-sm">Files are identical.</div>',
blankStats: "Identical",
},
formatStats: ({ added, deleted, identical }) => {
if (identical) {
return "No changes";
}
return `<span style="color:#448361">${added} additions</span>, <span style="color:#e03e3e">${deleted} deletions</span>`;
},
});
</script>
</body>
</html>