为typecho添加代码块样式
摘要
常常需要粘贴代码到文章,美化一下代码块,所以添加了typecho的代码块样式,具有复制和下载功能。如果有需要可以复制下载,随意修改。
源代码
<style>
/* 代码块容器 */
.code-block-wrapper {
position: relative;
margin: 2em 0;
border-radius: 12px;
box-shadow: 0 10px 30px -10px rgba(0, 0, 0, 0.5);
border: 1px solid rgba(255, 255, 255, 0.05);
background: transparent;
}
/* 工具栏 - 粘性,紧凑 */
.code-toolbar {
position: sticky;
top: 0;
z-index: 10;
display: flex;
align-items: center;
justify-content: space-between;
padding: 6px 16px;
background: rgba(22, 27, 34, 0.95);
backdrop-filter: blur(4px);
color: #e6edf3;
font-family: 'SF Mono', 'JetBrains Mono', 'Fira Code', monospace;
font-size: 0.8rem;
border-top-left-radius: 12px;
border-top-right-radius: 12px;
border-bottom: 1px solid #30363d;
}
/* 语言标签 - 胶囊 */
.code-language {
background: rgba(88, 166, 255, 0.15);
padding: 2px 10px;
border-radius: 20px;
font-weight: 500;
letter-spacing: 0.2px;
color: #58a6ff;
border: 1px solid rgba(88, 166, 255, 0.2);
font-size: 0.75rem;
line-height: 1.5;
}
/* 按钮组 */
.code-actions {
display: flex;
gap: 4px;
}
/* 图标按钮 */
.code-actions button {
background: transparent;
border: none;
color: #8b949e;
cursor: pointer;
width: 28px;
height: 28px;
border-radius: 6px;
font-size: 1.1rem;
display: flex;
align-items: center;
justify-content: center;
transition: all 0.2s ease;
border: 1px solid transparent;
padding: 0;
}
.code-actions button:hover {
background: #30363d;
color: #f0f6fc;
border-color: #58a6ff;
transform: scale(1.05);
}
.code-actions button:active {
transform: scale(0.95);
}
/* 复制成功状态 */
.code-actions button.copied {
background: #238636;
color: white;
border-color: #2ea043;
position: relative;
}
.code-actions button.copied::before {
content: "✓";
font-size: 1rem;
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
}
.code-actions button.copied span {
display: none; /* 隐藏原有图标 */
}
/* 代码内容区域 - 横向滚动 */
.code-block-wrapper pre {
margin: 0;
padding: 16px 20px;
background: #0d1117;
color: #e6edf3;
font-family: 'JetBrains Mono', 'Fira Code', 'Cascadia Code', 'Roboto Mono', monospace;
font-size: 0.9rem;
line-height: 1.6;
overflow-x: auto;
white-space: pre;
tab-size: 2;
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.3);
border-bottom-left-radius: 12px;
border-bottom-right-radius: 12px;
border: 1px solid #30363d;
border-top: none;
}
/* 语法高亮颜色(如果您使用 Prism/Highlight.js,可保留此部分) */
.code-block-wrapper .token.comment,
.code-block-wrapper .token.prolog,
.code-block-wrapper .token.doctype,
.code-block-wrapper .token.cdata {
color: #8b949e;
}
.code-block-wrapper .token.punctuation {
color: #79c0ff;
}
.code-block-wrapper .token.property,
.code-block-wrapper .token.tag,
.code-block-wrapper .token.boolean,
.code-block-wrapper .token.number,
.code-block-wrapper .token.constant,
.code-block-wrapper .token.symbol,
.code-block-wrapper .token.deleted {
color: #79c0ff;
}
.code-block-wrapper .token.selector,
.code-block-wrapper .token.attr-name,
.code-block-wrapper .token.string,
.code-block-wrapper .token.char,
.code-block-wrapper .token.builtin,
.code-block-wrapper .token.inserted {
color: #a5d6ff;
}
.code-block-wrapper .token.operator,
.code-block-wrapper .token.entity,
.code-block-wrapper .token.url,
.code-block-wrapper .token.variable {
color: #d2a8ff;
}
.code-block-wrapper .token.function,
.code-block-wrapper .token.class-name {
color: #ffa657;
}
.code-block-wrapper .token.keyword {
color: #ff7b72;
}
.code-block-wrapper .token.regex,
.code-block-wrapper .token.important {
color: #f2cc60;
}
</style>
<script>
(function() {
// 语言映射表,用于下载文件扩展名
const langMap = {
'javascript': 'js', 'js': 'js',
'python': 'py', 'py': 'py',
'html': 'html', 'css': 'css',
'php': 'php', 'java': 'java',
'cpp': 'cpp', 'c': 'c',
'ruby': 'rb', 'go': 'go',
'rust': 'rs', 'swift': 'swift',
'kotlin': 'kt', 'typescript': 'ts', 'ts': 'ts',
'json': 'json', 'xml': 'xml',
'yaml': 'yml', 'markdown': 'md', 'md': 'md',
'bash': 'sh', 'sh': 'sh', 'shell': 'sh',
'sql': 'sql'
};
function getFileExtension(language) {
const lang = language.toLowerCase();
return langMap[lang] || 'txt';
}
// 处理所有代码块
function enhanceCodeBlocks() {
document.querySelectorAll('pre code').forEach((codeBlock) => {
const pre = codeBlock.parentNode;
// 避免重复处理
if (pre.classList.contains('code-block-enhanced')) return;
pre.classList.add('code-block-enhanced');
// 获取语言
let language = 'text';
const classList = codeBlock.classList;
for (let cls of classList) {
if (cls.startsWith('language-')) {
language = cls.replace('language-', '');
break;
}
}
const codeText = codeBlock.innerText;
// 创建包裹容器
const wrapper = document.createElement('div');
wrapper.className = 'code-block-wrapper';
// 创建工具栏
const toolbar = document.createElement('div');
toolbar.className = 'code-toolbar';
const langSpan = document.createElement('span');
langSpan.className = 'code-language';
langSpan.textContent = language;
const actionsDiv = document.createElement('div');
actionsDiv.className = 'code-actions';
// 复制按钮(仅图标)
const copyBtn = document.createElement('button');
copyBtn.innerHTML = '📋';
copyBtn.title = '复制代码';
copyBtn.addEventListener('click', (e) => {
e.stopPropagation();
navigator.clipboard.writeText(codeText).then(() => {
copyBtn.classList.add('copied');
setTimeout(() => {
copyBtn.classList.remove('copied');
}, 2000);
}).catch(() => {
alert('复制失败,请手动复制');
});
});
// 下载按钮(仅图标)
const downloadBtn = document.createElement('button');
downloadBtn.innerHTML = '⬇️';
downloadBtn.title = '下载代码';
downloadBtn.addEventListener('click', (e) => {
e.stopPropagation();
const ext = getFileExtension(language);
const filename = `code.${ext}`;
const blob = new Blob([codeText], { type: 'text/plain' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = filename;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
URL.revokeObjectURL(url);
});
actionsDiv.appendChild(copyBtn);
actionsDiv.appendChild(downloadBtn);
toolbar.appendChild(langSpan);
toolbar.appendChild(actionsDiv);
// 将 pre 移动到 wrapper 中
pre.parentNode.insertBefore(wrapper, pre);
wrapper.appendChild(toolbar);
wrapper.appendChild(pre);
});
}
// 移除其他插件生成的复制按钮(通用检测)
function removeDuplicateCopyButtons() {
// 等待一段时间让所有插件渲染完成
setTimeout(() => {
document.querySelectorAll('button').forEach(btn => {
// 跳过我们自己的按钮(在 .code-actions 内)
if (btn.closest('.code-actions')) return;
// 检查是否可能是复制按钮:文本包含“复制”或图标
const btnText = btn.innerText.trim();
const btnHTML = btn.innerHTML;
if (btnText.includes('复制') || btnText.includes('Copy') || btnHTML.includes('📋')) {
btn.style.display = 'none'; // 隐藏而不是移除,避免影响布局
}
});
}, 1000); // 延迟1秒确保插件加载完毕
}
// 初始化
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', () => {
enhanceCodeBlocks();
removeDuplicateCopyButtons();
});
} else {
enhanceCodeBlocks();
removeDuplicateCopyButtons();
}
})();
</script>如何使用
在编辑当前外观中,选择~footer.php~,在</body>前插入以上代码。
使用时用Markdown代码或者<pre><code class=language-XXX>标签,放在标签里,保存以后就可以看到代码块样式了。