731 lines
32 KiB
HTML
731 lines
32 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="en">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>Code Reviewer Agent for Claude Code: Automated Code Quality & Security Expert</title>
|
||
|
||
<!-- Google tag (gtag.js) -->
|
||
<script async src="https://www.googletagmanager.com/gtag/js?id=G-YWW6FV2SGN"></script>
|
||
<script>
|
||
window.dataLayer = window.dataLayer || [];
|
||
function gtag(){dataLayer.push(arguments);}
|
||
gtag('js', new Date());
|
||
|
||
gtag('config', 'G-YWW6FV2SGN');
|
||
</script>
|
||
|
||
<!-- Favicon -->
|
||
<link rel="icon" type="image/x-icon" href="../../static/favicon/favicon.ico">
|
||
<link rel="icon" type="image/png" sizes="16x16" href="../../static/favicon/favicon-16x16.png">
|
||
<link rel="icon" type="image/png" sizes="32x32" href="../../static/favicon/favicon-32x32.png">
|
||
<link rel="apple-touch-icon" sizes="180x180" href="../../static/favicon/apple-touch-icon.png">
|
||
<link rel="icon" type="image/png" sizes="192x192" href="../../static/favicon/android-chrome-192x192.png">
|
||
<link rel="icon" type="image/png" sizes="512x512" href="../../static/favicon/android-chrome-512x512.png">
|
||
|
||
<meta name="description" content="Install the Code Reviewer Agent for Claude Code to automate code reviews, detect security vulnerabilities, and enforce best practices. AI-powered code quality analysis with actionable feedback.">
|
||
|
||
<!-- Open Graph / Facebook -->
|
||
<meta property="og:type" content="article">
|
||
<meta property="og:url" content="https://aitmpl.com/blog/code-reviewer-agent/">
|
||
<meta property="og:title" content="Code Reviewer Agent for Claude Code: Automated Code Quality & Security">
|
||
<meta property="og:description" content="Install the Code Reviewer Agent for Claude Code to automate code reviews, detect security vulnerabilities, and enforce best practices. AI-powered code quality analysis with actionable feedback.">
|
||
<meta property="og:image" content="https://aitmpl.com/blog/assets/code-reviewer-agent-cover.png">
|
||
<meta property="og:image:width" content="1200">
|
||
<meta property="og:image:height" content="630">
|
||
<meta property="article:author" content="Claude Code Templates">
|
||
<meta property="article:section" content="Agents">
|
||
<meta property="article:tag" content="Claude Code">
|
||
<meta property="article:tag" content="Code Review">
|
||
<meta property="article:tag" content="Security">
|
||
<meta property="article:tag" content="Code Quality">
|
||
|
||
<!-- Twitter -->
|
||
<meta name="twitter:card" content="summary_large_image">
|
||
<meta name="twitter:url" content="https://aitmpl.com/blog/code-reviewer-agent/">
|
||
<meta name="twitter:title" content="Code Reviewer Agent for Claude Code: Automated Code Quality & Security">
|
||
<meta name="twitter:description" content="Install the Code Reviewer Agent for Claude Code to automate code reviews, detect security vulnerabilities, and enforce best practices. AI-powered code quality analysis with actionable feedback.">
|
||
<meta name="twitter:image" content="https://aitmpl.com/blog/assets/code-reviewer-agent-cover.png">
|
||
|
||
<!-- Additional SEO -->
|
||
<meta name="keywords" content="Claude Code agent, Code Reviewer Agent, Claude Code code review, automated code review, security scanning, code quality, AI code review, vulnerability detection, best practices, OWASP, code audit, static analysis, Claude Code security">
|
||
<meta name="author" content="Claude Code Templates">
|
||
<link rel="canonical" href="https://aitmpl.com/blog/code-reviewer-agent/">
|
||
|
||
<link rel="stylesheet" href="../../css/styles.css">
|
||
<link rel="stylesheet" href="../../css/blog.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=Inter:wght@300;400;500;600;700&display=swap" rel="stylesheet">
|
||
|
||
<!-- Hotjar Tracking Code for https://aitmpl.com -->
|
||
<script>
|
||
(function(h,o,t,j,a,r){
|
||
h.hj=h.hj||function(){(h.hj.q=h.hj.q||[]).push(arguments)};
|
||
h._hjSettings={hjid:6519181,hjsv:6};
|
||
a=o.getElementsByTagName('head')[0];
|
||
r=o.createElement('script');r.async=1;
|
||
r.src=t+h._hjSettings.hjid+j+h._hjSettings.hjsv;
|
||
a.appendChild(r);
|
||
})(window,document,'https://static.hotjar.com/c/hotjar-','.js?sv=');
|
||
</script>
|
||
|
||
<!-- Structured Data -->
|
||
<script type="application/ld+json">
|
||
{
|
||
"@context": "https://schema.org",
|
||
"@type": "BlogPosting",
|
||
"headline": "Code Reviewer Agent for Claude Code: Automated Code Quality & Security Expert",
|
||
"description": "Install the Code Reviewer Agent for Claude Code to automate code reviews, detect security vulnerabilities, and enforce best practices. AI-powered code quality analysis with actionable feedback.",
|
||
"image": "https://aitmpl.com/blog/assets/code-reviewer-agent-cover.png",
|
||
"author": {
|
||
"@type": "Organization",
|
||
"name": "Claude Code Templates"
|
||
},
|
||
"publisher": {
|
||
"@type": "Organization",
|
||
"name": "Claude Code Templates",
|
||
"logo": {
|
||
"@type": "ImageObject",
|
||
"url": "https://aitmpl.com/static/img/logo.svg"
|
||
}
|
||
},
|
||
"mainEntityOfPage": {
|
||
"@type": "WebPage",
|
||
"@id": "https://aitmpl.com/blog/code-reviewer-agent/"
|
||
},
|
||
"keywords": "Claude Code agent, Code Reviewer Agent, automated code review, security scanning, code quality, AI code review, Claude Code security",
|
||
"wordCount": "600",
|
||
"articleSection": "Claude Code Agents",
|
||
"about": [
|
||
{
|
||
"@type": "Thing",
|
||
"name": "Claude Code"
|
||
},
|
||
{
|
||
"@type": "Thing",
|
||
"name": "Code Review Agent"
|
||
},
|
||
{
|
||
"@type": "Thing",
|
||
"name": "Code Quality"
|
||
},
|
||
{
|
||
"@type": "Thing",
|
||
"name": "Security Analysis"
|
||
},
|
||
{
|
||
"@type": "SoftwareApplication",
|
||
"name": "Claude Code",
|
||
"applicationCategory": "DeveloperApplication"
|
||
}
|
||
]
|
||
}
|
||
</script>
|
||
</head>
|
||
<body>
|
||
<header class="header">
|
||
<div class="container">
|
||
<div class="header-content">
|
||
<div class="terminal-header">
|
||
<div class="ascii-title">
|
||
<pre class="ascii-art">
|
||
██████╗ ██╗ ██████╗ ██████╗
|
||
██╔══██╗██║ ██╔═══██╗██╔════╝
|
||
██████╔╝██║ ██║ ██║██║ ███╗
|
||
██╔══██╗██║ ██║ ██║██║ ██║
|
||
██████╔╝███████╗╚██████╔╝╚██████╔╝
|
||
╚═════╝ ╚══════╝ ╚═════╝ ╚═════╝</pre>
|
||
</div>
|
||
</div>
|
||
<div class="header-actions">
|
||
<a href="../../index.html" class="header-btn">
|
||
<svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor">
|
||
<path d="M10,20V14H14V20H19V12H22L12,3L2,12H5V20H10Z"/>
|
||
</svg>
|
||
Home
|
||
</a>
|
||
<a href="../index.html" class="header-btn">
|
||
<svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor">
|
||
<path d="M14,2H6A2,2 0 0,0 4,4V20A2,2 0 0,0 6,22H18A2,2 0 0,0 20,20V8L14,2M18,20H6V4H13V9H18V20Z"/>
|
||
</svg>
|
||
Blog
|
||
</a>
|
||
<a href="https://github.com/davila7/claude-code-templates" target="_blank" class="header-btn">
|
||
<svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor">
|
||
<path d="M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.30 3.297-1.30.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z"/>
|
||
</svg>
|
||
GitHub
|
||
</a>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</header>
|
||
|
||
<main class="terminal">
|
||
<header class="article-header">
|
||
<div class="container">
|
||
<!-- Copy Markdown Button -->
|
||
<button id="copy-markdown-btn" class="copy-markdown-button" title="Copy post as Markdown">
|
||
<svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor">
|
||
<path d="M16 1H4c-1.1 0-2 .9-2 2v14h2V3h12V1zm3 4H8c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h11c1.1 0 2-.9 2-2V7c0-1.1-.9-2-2-2zm0 16H8V7h11v14z"/>
|
||
</svg>
|
||
Copy as Markdown
|
||
</button>
|
||
|
||
<h1 class="article-title">Code Reviewer Agent for Claude Code: Automated Code Quality & Security</h1>
|
||
<p class="article-subtitle">Learn how to install and use the Code Reviewer Agent for Claude Code to automate code reviews, detect security vulnerabilities, and enforce best practices with AI-powered analysis and actionable feedback.</p>
|
||
<div class="article-meta-full">
|
||
<span class="read-time">4 min read</span>
|
||
<div class="article-tags">
|
||
<span class="tag">Claude Code</span>
|
||
<span class="tag">Agent</span>
|
||
<span class="tag">Code Review</span>
|
||
<span class="tag">Security</span>
|
||
<span class="tag">Quality</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</header>
|
||
|
||
<article class="article-body">
|
||
<img src="../assets/code-reviewer-agent-cover.png" alt="Code Reviewer Agent for Claude Code" class="article-cover" loading="lazy">
|
||
|
||
<div class="article-content-full">
|
||
<h2>What is the Code Reviewer Agent?</h2>
|
||
|
||
<p>The Code Reviewer Agent is a specialized Claude Code agent focused on automated code quality and security analysis. It provides expert code reviews, detects security vulnerabilities, enforces best practices, and delivers actionable feedback to improve your codebase quality and maintainability.</p>
|
||
|
||
<!-- Mermaid Diagram -->
|
||
<div class="mermaid-diagram" style="background: #1a1a1a; border: 1px solid #333; border-radius: 8px; padding: 2rem; margin: 2rem 0; text-align: center;">
|
||
<pre class="mermaid">
|
||
graph LR
|
||
A[📝 Your Code] --> B[🔍 Code Reviewer Agent]
|
||
B --> C[🛡️ Security & Quality Report]
|
||
C --> D[✅ Improved Codebase]
|
||
|
||
style B fill:#F97316,stroke:#fff,color:#000
|
||
</pre>
|
||
</div>
|
||
|
||
<h2>Key Capabilities</h2>
|
||
<ul>
|
||
<li><strong>Automated Code Reviews</strong> (analyzes git diff for recent changes)</li>
|
||
<li><strong>Security Vulnerability Detection</strong> (exposed secrets, API keys, input validation)</li>
|
||
<li><strong>Code Quality Analysis</strong> (readability, naming conventions, duplication)</li>
|
||
<li><strong>Best Practices Enforcement</strong> (error handling, test coverage, performance)</li>
|
||
<li><strong>Prioritized Feedback</strong> (critical issues, warnings, suggestions)</li>
|
||
<li><strong>Actionable Recommendations</strong> (specific examples of how to fix issues)</li>
|
||
</ul>
|
||
|
||
<h2>Installation</h2>
|
||
|
||
<p>Install the Code Reviewer Agent using the Claude Code Templates CLI:</p>
|
||
|
||
<pre><code class="language-bash">npx claude-code-templates@latest --agent development-tools/code-reviewer</code></pre>
|
||
|
||
<p><strong>Where is the agent installed?</strong></p>
|
||
<p>The agent is saved in <code>.claude/agents/code-reviewer.md</code> in your project directory:</p>
|
||
|
||
<pre><code class="language-bash">your-project/
|
||
├── .claude/
|
||
│ └── agents/
|
||
│ └── code-reviewer.md # ← Agent installed here
|
||
├── src/
|
||
│ └── components/
|
||
├── package.json
|
||
└── README.md</code></pre>
|
||
|
||
<h2>How to Use the Agent</h2>
|
||
|
||
<p>Start Claude Code and explicitly request the agent in your prompt:</p>
|
||
|
||
<pre><code class="language-bash"># Start Claude Code
|
||
claude
|
||
|
||
# Then write your prompt requesting the agent
|
||
> Use the code-reviewer agent to review my recent changes for security issues and code quality</code></pre>
|
||
|
||
<p>The agent will automatically:</p>
|
||
<ul>
|
||
<li>Run <code>git diff</code> to see recent changes</li>
|
||
<li>Focus review on modified files</li>
|
||
<li>Provide feedback organized by priority (critical, warnings, suggestions)</li>
|
||
<li>Include specific examples of how to fix identified issues</li>
|
||
</ul>
|
||
|
||
<h2>Usage Examples</h2>
|
||
|
||
<h3>Example 1: Security Audit Before Commit</h3>
|
||
<pre><code class="language-bash">claude
|
||
|
||
> Use the code-reviewer agent to check for security vulnerabilities in my code before I commit. Focus on exposed secrets, API keys, and input validation</code></pre>
|
||
|
||
<p><strong>Result:</strong> Comprehensive security review identifying exposed credentials, missing input validation, and SQL injection risks with specific fixes for each issue.</p>
|
||
|
||
<h3>Example 2: Code Quality Review</h3>
|
||
<pre><code class="language-bash">claude
|
||
|
||
> Use the code-reviewer agent to review this pull request for code quality. Check for duplicated code, naming conventions, and error handling</code></pre>
|
||
|
||
<p><strong>Result:</strong> Detailed quality analysis highlighting code duplication, suggesting better variable names, and identifying missing error handling with refactoring examples.</p>
|
||
|
||
<h3>Example 3: Performance and Best Practices</h3>
|
||
<pre><code class="language-bash">claude
|
||
|
||
> Use the code-reviewer agent to analyze performance issues and verify we're following best practices for this Node.js API</code></pre>
|
||
|
||
<p><strong>Result:</strong> Performance analysis identifying N+1 queries, missing database indexes, and inefficient loops with optimization recommendations and code examples.</p>
|
||
|
||
<h2>Review Checklist</h2>
|
||
|
||
<p>The Code Reviewer Agent evaluates code against this comprehensive checklist:</p>
|
||
|
||
<ul>
|
||
<li>✓ Code is simple and readable</li>
|
||
<li>✓ Functions and variables are well-named</li>
|
||
<li>✓ No duplicated code</li>
|
||
<li>✓ Proper error handling implemented</li>
|
||
<li>✓ No exposed secrets or API keys</li>
|
||
<li>✓ Input validation present</li>
|
||
<li>✓ Good test coverage</li>
|
||
<li>✓ Performance considerations addressed</li>
|
||
</ul>
|
||
|
||
<h2>Official Documentation</h2>
|
||
<p>For more information about agents in Claude Code, see the <a href="https://code.claude.com/docs/en/sub-agents?utm_source=aitmpl&utm_medium=referral&utm_campaign=blog" target="_blank">official sub-agents documentation</a>.</p>
|
||
|
||
<!-- Explore Components Banner -->
|
||
<div class="explore-components-banner">
|
||
<h3>Explore 800+ Claude Code Components</h3>
|
||
<p>Discover agents, commands, MCPs, settings, hooks, skills and templates to supercharge your Claude Code workflow</p>
|
||
<a href="../../index.html">Browse All Components</a>
|
||
</div>
|
||
|
||
</div>
|
||
|
||
<div class="article-nav">
|
||
<a href="../index.html" class="back-to-blog">
|
||
<svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor">
|
||
<path d="M20,11V13H8L13.5,18.5L12.08,19.92L4.16,12L12.08,4.08L13.5,5.5L8,11H20Z"/>
|
||
</svg>
|
||
Back to Blog
|
||
</a>
|
||
</div>
|
||
</article>
|
||
</main>
|
||
|
||
<footer class="footer">
|
||
<div class="container">
|
||
<div class="footer-content">
|
||
<div class="footer-left">
|
||
<div class="footer-ascii">
|
||
<pre class="footer-ascii-art"> █████╗ ██╗████████╗███╗ ███╗██████╗ ██╗
|
||
██╔══██╗██║╚══██╔══╝████╗ ████║██╔══██╗██║
|
||
███████║██║ ██║ ██╔████╔██║██████╔╝██║
|
||
██╔══██║██║ ██║ ██║╚██╔╝██║██╔═══╝ ██║
|
||
██║ ██║██║ ██║ ██║ ╚═╝ ██║██║ ███████╗
|
||
╚═╝ ╚═╝╚═╝ ╚═╝ ╚═╝ ╚═╝╚═╝ ╚══════╝</pre>
|
||
<p class="footer-tagline">Supercharge Anthropic's Claude Code</p>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="footer-right">
|
||
<p class="footer-copyright">© 2026 Claude Code Templates. Open source project.</p>
|
||
<div class="footer-links">
|
||
<a href="../../trending.html" class="footer-link">
|
||
<svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor">
|
||
<path d="M16,6L18.29,8.29L13.41,13.17L9.41,9.17L2,16.59L3.41,18L9.41,12L13.41,16L19.71,9.71L22,12V6H16Z"/>
|
||
</svg>
|
||
Trending
|
||
</a>
|
||
<a href="https://docs.aitmpl.com/" target="_blank" class="footer-link">
|
||
<svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor">
|
||
<path d="M14,2H6A2,2 0 0,0 4,4V20A2,2 0 0,0 6,22H18A2,2 0 0,0 20,20V8L14,2M18,20H6V4H13V9H18V20Z"/>
|
||
</svg>
|
||
Documentation
|
||
</a>
|
||
<a href="https://github.com/davila7/claude-code-templates" target="_blank" class="footer-link">
|
||
<svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor">
|
||
<path d="M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.30 3.297-1.30.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z"/>
|
||
</svg>
|
||
GitHub
|
||
</a>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</footer>
|
||
|
||
<!-- Code Copy Functionality -->
|
||
<script>
|
||
// Code Copy Functionality for Blog Articles
|
||
class CodeCopy {
|
||
constructor() {
|
||
this.initCodeBlocks();
|
||
this.setupCopyFunctionality();
|
||
}
|
||
|
||
initCodeBlocks() {
|
||
// Convert existing pre elements to new code-block structure
|
||
const preElements = document.querySelectorAll('.article-content-full pre:not(.converted)');
|
||
|
||
preElements.forEach(pre => {
|
||
const code = pre.querySelector('code');
|
||
if (!code) return;
|
||
|
||
// Detect language from class or content
|
||
const language = this.detectLanguage(code);
|
||
const isTerminal = language === 'bash' || language === 'terminal';
|
||
|
||
// Create new code block structure
|
||
const codeBlock = document.createElement('div');
|
||
codeBlock.className = isTerminal ? 'code-block terminal-block' : 'code-block';
|
||
|
||
// Create header
|
||
const header = document.createElement('div');
|
||
header.className = 'code-header';
|
||
|
||
const languageSpan = document.createElement('span');
|
||
languageSpan.className = 'code-language';
|
||
languageSpan.textContent = language;
|
||
|
||
const copyButton = document.createElement('button');
|
||
copyButton.className = 'copy-button';
|
||
copyButton.innerHTML = `
|
||
<svg width="14" height="14" viewBox="0 0 24 24" fill="currentColor">
|
||
<path d="M16 1H4c-1.1 0-2 .9-2 2v14h2V3h12V1zm3 4H8c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h11c1.1 0 2-.9 2-2V7c0-1.1-.9-2-2-2zm0 16H8V7h11v14z"/>
|
||
</svg>
|
||
Copy
|
||
`;
|
||
|
||
header.appendChild(languageSpan);
|
||
header.appendChild(copyButton);
|
||
|
||
// Clone and prepare the pre element
|
||
const newPre = pre.cloneNode(true);
|
||
newPre.classList.add('converted');
|
||
|
||
// Assemble new structure
|
||
codeBlock.appendChild(header);
|
||
codeBlock.appendChild(newPre);
|
||
|
||
// Replace original pre
|
||
pre.parentNode.replaceChild(codeBlock, pre);
|
||
});
|
||
}
|
||
|
||
detectLanguage(codeElement) {
|
||
// Check for class-based language detection
|
||
const className = codeElement.className;
|
||
if (className.includes('language-')) {
|
||
return className.match(/language-(\w+)/)[1];
|
||
}
|
||
|
||
// Check content patterns
|
||
const content = codeElement.textContent;
|
||
|
||
if (content.includes('npm ') || content.includes('$ ') || content.includes('claude-code ')) {
|
||
return 'bash';
|
||
}
|
||
if (content.includes('import ') && content.includes('from ')) {
|
||
return 'javascript';
|
||
}
|
||
if (content.includes('CREATE TABLE') || content.includes('SELECT ')) {
|
||
return 'sql';
|
||
}
|
||
if (content.includes('{') && content.includes('"')) {
|
||
return 'json';
|
||
}
|
||
if (content.includes('def ') || content.includes('import ')) {
|
||
return 'python';
|
||
}
|
||
|
||
return 'text';
|
||
}
|
||
|
||
setupCopyFunctionality() {
|
||
document.addEventListener('click', async (e) => {
|
||
if (!e.target.closest('.copy-button')) return;
|
||
|
||
const button = e.target.closest('.copy-button');
|
||
const codeBlock = button.closest('.code-block');
|
||
const pre = codeBlock.querySelector('pre');
|
||
const code = pre.querySelector('code');
|
||
|
||
if (!code) return;
|
||
|
||
try {
|
||
// Get clean text content
|
||
let textToCopy = code.textContent;
|
||
|
||
// Clean up terminal prompts if it's a terminal block
|
||
if (codeBlock.classList.contains('terminal-block')) {
|
||
textToCopy = this.cleanTerminalOutput(textToCopy);
|
||
}
|
||
|
||
await navigator.clipboard.writeText(textToCopy);
|
||
|
||
// Update button state
|
||
const originalContent = button.innerHTML;
|
||
button.innerHTML = `
|
||
<svg width="14" height="14" viewBox="0 0 24 24" fill="currentColor">
|
||
<path d="M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z"/>
|
||
</svg>
|
||
Copied!
|
||
`;
|
||
button.classList.add('copied');
|
||
|
||
// Reset after 2 seconds
|
||
setTimeout(() => {
|
||
button.innerHTML = originalContent;
|
||
button.classList.remove('copied');
|
||
}, 2000);
|
||
|
||
} catch (err) {
|
||
console.error('Failed to copy code:', err);
|
||
|
||
// Fallback: select text
|
||
const selection = window.getSelection();
|
||
const range = document.createRange();
|
||
range.selectNodeContents(code);
|
||
selection.removeAllRanges();
|
||
selection.addRange(range);
|
||
}
|
||
});
|
||
}
|
||
|
||
cleanTerminalOutput(text) {
|
||
// Remove common terminal prompts and clean output
|
||
return text
|
||
.split('\n')
|
||
.map(line => {
|
||
// Remove prompts like "$ ", "❯ ", "claude-code> "
|
||
line = line.replace(/^[\$❯]\s*/, '').replace(/^claude-code>\s*/, '');
|
||
|
||
// Remove output/result comments (lines starting with # ✓)
|
||
if (line.trim().startsWith('# ✓') ||
|
||
line.trim().startsWith('# Start using') ||
|
||
line.trim().startsWith('# Your .claude') ||
|
||
line.trim().startsWith('# This will') ||
|
||
line.includes('Components will be installed') ||
|
||
line.includes('directory now contains')) {
|
||
return '';
|
||
}
|
||
|
||
return line;
|
||
})
|
||
.filter(line => line.trim() !== '') // Remove empty lines
|
||
.join('\n')
|
||
.trim();
|
||
}
|
||
}
|
||
|
||
// Initialize when DOM is loaded
|
||
if (document.readyState === 'loading') {
|
||
document.addEventListener('DOMContentLoaded', () => new CodeCopy());
|
||
} else {
|
||
new CodeCopy();
|
||
}
|
||
|
||
// Explore components banner hover effect
|
||
document.addEventListener('DOMContentLoaded', () => {
|
||
const banner = document.querySelector('.explore-components-banner a');
|
||
if (banner) {
|
||
banner.addEventListener('mouseenter', () => {
|
||
banner.style.background = '#00cc33';
|
||
banner.style.transform = 'translateY(-2px)';
|
||
});
|
||
banner.addEventListener('mouseleave', () => {
|
||
banner.style.background = '#00ff41';
|
||
banner.style.transform = 'translateY(0)';
|
||
});
|
||
}
|
||
});
|
||
|
||
// Copy Markdown functionality
|
||
class MarkdownCopier {
|
||
constructor() {
|
||
this.setupButton();
|
||
}
|
||
|
||
setupButton() {
|
||
const button = document.getElementById('copy-markdown-btn');
|
||
if (!button) return;
|
||
|
||
button.addEventListener('click', async () => {
|
||
const markdown = this.extractMarkdown();
|
||
|
||
try {
|
||
await navigator.clipboard.writeText(markdown);
|
||
|
||
// Update button state
|
||
const originalContent = button.innerHTML;
|
||
button.innerHTML = `
|
||
<svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor">
|
||
<path d="M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z"/>
|
||
</svg>
|
||
✓
|
||
`;
|
||
button.classList.add('copied');
|
||
|
||
// Reset after 2 seconds
|
||
setTimeout(() => {
|
||
button.innerHTML = originalContent;
|
||
button.classList.remove('copied');
|
||
}, 2000);
|
||
|
||
} catch (err) {
|
||
console.error('Failed to copy markdown:', err);
|
||
}
|
||
});
|
||
}
|
||
|
||
extractMarkdown() {
|
||
const title = document.querySelector('.article-title')?.textContent || '';
|
||
const subtitle = document.querySelector('.article-subtitle')?.textContent || '';
|
||
const date = document.querySelector('time')?.textContent || '';
|
||
const content = document.querySelector('.article-content-full');
|
||
|
||
let markdown = `# ${title}\n\n`;
|
||
|
||
if (subtitle) {
|
||
markdown += `${subtitle}\n\n`;
|
||
}
|
||
|
||
if (date) {
|
||
markdown += `*${date}*\n\n`;
|
||
}
|
||
|
||
if (!content) return markdown;
|
||
|
||
// Process content elements
|
||
const elements = content.children;
|
||
|
||
for (const element of elements) {
|
||
markdown += this.processElement(element) + '\n\n';
|
||
}
|
||
|
||
return markdown.trim();
|
||
}
|
||
|
||
processElement(element) {
|
||
const tagName = element.tagName.toLowerCase();
|
||
|
||
switch (tagName) {
|
||
case 'h2':
|
||
return `## ${element.textContent}`;
|
||
case 'h3':
|
||
return `### ${element.textContent}`;
|
||
case 'h4':
|
||
return `#### ${element.textContent}`;
|
||
case 'p':
|
||
return element.textContent;
|
||
case 'ul':
|
||
return this.processList(element, '-');
|
||
case 'ol':
|
||
return this.processList(element, '1.');
|
||
case 'table':
|
||
return this.processTable(element);
|
||
case 'pre':
|
||
return this.processCodeBlock(element);
|
||
case 'div':
|
||
if (element.classList.contains('code-block')) {
|
||
return this.processCodeBlock(element.querySelector('pre'));
|
||
}
|
||
// Skip newsletter CTAs and other divs
|
||
if (element.classList.contains('newsletter-cta')) {
|
||
return '';
|
||
}
|
||
return element.textContent || '';
|
||
case 'img':
|
||
const alt = element.getAttribute('alt') || '';
|
||
const src = element.getAttribute('src') || '';
|
||
return ``;
|
||
default:
|
||
return element.textContent || '';
|
||
}
|
||
}
|
||
|
||
processList(listElement, marker) {
|
||
const items = listElement.querySelectorAll('li');
|
||
return Array.from(items)
|
||
.map(item => `${marker} ${item.textContent}`)
|
||
.join('\n');
|
||
}
|
||
|
||
processTable(table) {
|
||
const rows = table.querySelectorAll('tr');
|
||
if (rows.length === 0) return '';
|
||
|
||
let markdown = '';
|
||
|
||
// Process header
|
||
const headerRow = rows[0];
|
||
const headers = headerRow.querySelectorAll('th, td');
|
||
const headerText = Array.from(headers).map(h => h.textContent.trim()).join(' | ');
|
||
markdown += `| ${headerText} |\n`;
|
||
|
||
// Add separator
|
||
const separator = Array.from(headers).map(() => '---').join(' | ');
|
||
markdown += `| ${separator} |\n`;
|
||
|
||
// Process body rows
|
||
for (let i = 1; i < rows.length; i++) {
|
||
const row = rows[i];
|
||
const cells = row.querySelectorAll('td, th');
|
||
const cellText = Array.from(cells).map(c => c.textContent.trim()).join(' | ');
|
||
markdown += `| ${cellText} |\n`;
|
||
}
|
||
|
||
return markdown;
|
||
}
|
||
|
||
processCodeBlock(preElement) {
|
||
if (!preElement) return '';
|
||
|
||
const code = preElement.querySelector('code');
|
||
const codeText = code ? code.textContent : preElement.textContent;
|
||
|
||
// Detect language from parent code-block or code element classes
|
||
const codeBlock = preElement.closest('.code-block');
|
||
let language = '';
|
||
|
||
if (codeBlock) {
|
||
const languageSpan = codeBlock.querySelector('.code-language');
|
||
if (languageSpan) {
|
||
language = languageSpan.textContent.toLowerCase();
|
||
}
|
||
} else if (code && code.className.includes('language-')) {
|
||
language = code.className.match(/language-(\w+)/)?.[1] || '';
|
||
}
|
||
|
||
return `\`\`\`${language}\n${codeText}\n\`\`\``;
|
||
}
|
||
}
|
||
|
||
// Initialize markdown copier
|
||
document.addEventListener('DOMContentLoaded', () => {
|
||
new MarkdownCopier();
|
||
});
|
||
</script>
|
||
|
||
<!-- Mermaid Diagram Support -->
|
||
<script type="module">
|
||
import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.esm.min.mjs';
|
||
mermaid.initialize({
|
||
startOnLoad: true,
|
||
theme: 'dark',
|
||
themeVariables: {
|
||
primaryColor: '#F97316',
|
||
primaryTextColor: '#fff',
|
||
primaryBorderColor: '#F97316',
|
||
lineColor: '#00ff41',
|
||
secondaryColor: '#1a1a1a',
|
||
tertiaryColor: '#2d2d2d'
|
||
}
|
||
});
|
||
</script>
|
||
</body>
|
||
</html>
|