201 lines
7.5 KiB
HTML
201 lines
7.5 KiB
HTML
<!doctype html>
|
||
<html lang="zh-CN">
|
||
<head>
|
||
<meta charset="utf-8" />
|
||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||
<title>Code Block Demo</title>
|
||
<style>
|
||
:root {
|
||
color-scheme: light;
|
||
--bg: #ffffff;
|
||
--text: #111111;
|
||
--muted: #6f6f6f;
|
||
--surface: #ffffff;
|
||
--border: rgba(0, 0, 0, 0.105);
|
||
--hover: rgba(0, 0, 0, 0.055);
|
||
--radius: 20px;
|
||
--mono: "SF Mono", "JetBrains Mono", "Menlo", "Monaco", "Consolas", monospace;
|
||
font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
|
||
}
|
||
|
||
:root[data-theme="dark"] {
|
||
color-scheme: dark;
|
||
--bg: #1a1a1a;
|
||
--text: #f3f3f3;
|
||
--muted: #9b9b9b;
|
||
--surface: #1a1a1a;
|
||
--border: rgba(255, 255, 255, 0.13);
|
||
--hover: rgba(255, 255, 255, 0.08);
|
||
}
|
||
|
||
* { box-sizing: border-box; }
|
||
body {
|
||
margin: 0;
|
||
min-height: 100vh;
|
||
background: var(--bg);
|
||
color: var(--text);
|
||
display: flex;
|
||
justify-content: center;
|
||
padding: 48px 24px;
|
||
}
|
||
button { font: inherit; }
|
||
.page { width: min(960px, 100%); }
|
||
.topbar { display: flex; align-items: center; justify-content: space-between; gap: 16px; margin-bottom: 24px; }
|
||
.title { margin: 0; font-size: 30px; line-height: 1.12; letter-spacing: -0.045em; font-weight: 680; }
|
||
.subtitle { margin: 6px 0 0; color: var(--muted); font-size: 14px; line-height: 1.35; }
|
||
.theme-toggle { height: 36px; border: 1px solid var(--border); border-radius: 999px; background: transparent; color: var(--text); padding: 0 13px; cursor: pointer; }
|
||
.theme-toggle:hover { background: var(--hover); }
|
||
.message { max-width: 860px; font-size: 16px; line-height: 1.65; }
|
||
.message p { margin: 0 0 14px; }
|
||
|
||
.code-block {
|
||
margin: 16px 0 28px;
|
||
border: 1px solid var(--border);
|
||
border-radius: var(--radius);
|
||
background: var(--surface);
|
||
overflow: hidden;
|
||
}
|
||
|
||
.code-top {
|
||
height: 44px;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
gap: 12px;
|
||
padding: 0 12px 0 18px;
|
||
background: var(--surface);
|
||
border-bottom: 1px solid var(--border);
|
||
}
|
||
|
||
.code-lang {
|
||
color: var(--muted);
|
||
font-size: 14px;
|
||
line-height: 1;
|
||
letter-spacing: -0.01em;
|
||
font-weight: 500;
|
||
}
|
||
|
||
.copy-btn {
|
||
width: 32px;
|
||
height: 32px;
|
||
border: 0;
|
||
border-radius: 10px;
|
||
background: transparent;
|
||
color: var(--muted);
|
||
display: grid;
|
||
place-items: center;
|
||
cursor: pointer;
|
||
transition: background 140ms ease, color 140ms ease;
|
||
}
|
||
.copy-btn:hover {
|
||
background: var(--hover);
|
||
color: var(--text);
|
||
}
|
||
|
||
.icon {
|
||
width: 18px;
|
||
height: 18px;
|
||
display: inline-block;
|
||
background: currentColor;
|
||
mask: var(--icon-url) center / contain no-repeat;
|
||
-webkit-mask: var(--icon-url) center / contain no-repeat;
|
||
}
|
||
.icon-copy { --icon-url: url("data:image/svg+xml,%3Csvg%20xmlns=%22http://www.w3.org/2000/svg%22%20viewBox=%220%200%2024%2024%22%20width=%2248%22%20height=%2248%22%20fill=%22none%22%20stroke=%22%23000000%22%20stroke-width=%222%22%20stroke-linecap=%22round%22%20stroke-linejoin=%22round%22%20style=%22opacity:1;%22%3E%3Crect%20width=%2214%22%20height=%2214%22%20x=%228%22%20y=%228%22%20rx=%222%22%20ry=%222%22/%3E%3Cpath%20d=%22M4%2016c-1.1%200-2-.9-2-2V4c0-1.1.9-2%202-2h10c1.1%200%202%20.9%202%202%22/%3E%3C/svg%3E"); }
|
||
.icon-check { --icon-url: url("data:image/svg+xml,%3Csvg%0A%20%20xmlns=%22http://www.w3.org/2000/svg%22%0A%20%20width=%2224%22%0A%20%20height=%2224%22%0A%20%20viewBox=%220%200%2024%2024%22%0A%20%20fill=%22none%22%0A%20%20stroke=%22currentColor%22%0A%20%20stroke-width=%222%22%0A%20%20stroke-linecap=%22round%22%0A%20%20stroke-linejoin=%22round%22%0A%3E%0A%20%20%3Cpath%20d=%22M20%206%209%2017l-5-5%22%20/%3E%0A%3C/svg%3E"); }
|
||
|
||
pre {
|
||
margin: 0;
|
||
padding: 24px 28px 28px;
|
||
background: var(--surface);
|
||
overflow: auto;
|
||
font-family: var(--mono);
|
||
font-size: 15px;
|
||
line-height: 1.64;
|
||
tab-size: 4;
|
||
}
|
||
code { font-family: inherit; color: var(--text); white-space: pre; }
|
||
|
||
.kw { color: #c13f7a; }
|
||
.fn { color: #6a45c2; }
|
||
.str { color: #08863f; }
|
||
.num { color: #8b5e00; }
|
||
.op { color: #c13f7a; }
|
||
:root[data-theme="dark"] .kw { color: #ff7ab2; }
|
||
:root[data-theme="dark"] .fn { color: #b69cff; }
|
||
:root[data-theme="dark"] .str { color: #5fd38d; }
|
||
:root[data-theme="dark"] .num { color: #e4b86a; }
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<main class="page">
|
||
<header class="topbar">
|
||
<div>
|
||
<h1 class="title">代码块 Demo</h1>
|
||
<p class="subtitle">顶部更矮;顶部和代码区同色;只用一条细线分割;不添加不存在的功能。</p>
|
||
</div>
|
||
<button class="theme-toggle" id="themeToggle" type="button">深色模式</button>
|
||
</header>
|
||
|
||
<section class="message">
|
||
<p>示例代码块:</p>
|
||
|
||
<div class="code-block">
|
||
<div class="code-top">
|
||
<span class="code-lang">Python</span>
|
||
<button class="copy-btn" type="button" title="复制代码" aria-label="复制代码" data-copy="pythonCode">
|
||
<span class="icon icon-copy" aria-hidden="true"></span>
|
||
</button>
|
||
</div>
|
||
<pre><code id="pythonCode"><span class="kw">import</span> random
|
||
<span class="kw">from</span> datetime <span class="kw">import</span> datetime
|
||
|
||
quotes <span class="op">=</span> [
|
||
<span class="str">"Stay curious."</span>,
|
||
<span class="str">"Code is poetry."</span>,
|
||
<span class="str">"Small steps every day."</span>,
|
||
<span class="str">"Debugging is detective work."</span>,
|
||
]
|
||
|
||
<span class="kw">def</span> <span class="fn">random_quote</span>():
|
||
now <span class="op">=</span> datetime.now().strftime(<span class="str">"%Y-%m-%d %H:%M:%S"</span>)
|
||
quote <span class="op">=</span> random.choice(quotes)
|
||
<span class="kw">return</span> <span class="str">f"[{now}] {quote}"</span>
|
||
|
||
<span class="kw">if</span> __name__ <span class="op">==</span> <span class="str">"__main__"</span>:
|
||
<span class="kw">for</span> i <span class="kw">in</span> range(<span class="num">3</span>):
|
||
print(random_quote())</code></pre>
|
||
</div>
|
||
|
||
<div class="code-block">
|
||
<div class="code-top">
|
||
<span class="code-lang">powershell</span>
|
||
<button class="copy-btn" type="button" title="复制代码" aria-label="复制代码" data-copy="psCode">
|
||
<span class="icon icon-copy" aria-hidden="true"></span>
|
||
</button>
|
||
</div>
|
||
<pre><code id="psCode">Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser -Force</code></pre>
|
||
</div>
|
||
</section>
|
||
</main>
|
||
|
||
<script>
|
||
const root = document.documentElement;
|
||
const themeToggle = document.getElementById('themeToggle');
|
||
themeToggle.addEventListener('click', () => {
|
||
const next = root.dataset.theme === 'dark' ? 'light' : 'dark';
|
||
root.dataset.theme = next;
|
||
themeToggle.textContent = next === 'dark' ? '浅色模式' : '深色模式';
|
||
});
|
||
|
||
document.querySelectorAll('.copy-btn').forEach((button) => {
|
||
button.addEventListener('click', () => {
|
||
// file:// 预览下不调用剪贴板 API,避免浏览器安全报错;这里只演示点击后的视觉反馈。
|
||
const icon = button.querySelector('.icon');
|
||
icon.className = 'icon icon-check';
|
||
setTimeout(() => { icon.className = 'icon icon-copy'; }, 1000);
|
||
});
|
||
});
|
||
</script>
|
||
</body>
|
||
</html>
|