摘要

常常需要粘贴代码到文章,美化一下代码块,所以添加了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>标签,放在标签里,保存以后就可以看到代码块样式了。

标签: none

添加新评论