This commit is contained in:
nimrodkor
2025-07-07 16:14:35 +03:00
parent 3f6d64d6f6
commit 2677c73bdd
9 changed files with 656 additions and 16 deletions

1
.gitignore vendored
View File

@@ -2,3 +2,4 @@
vendor
_site
.jekyll-cache
.claude

34
CLAUDE.md Normal file
View File

@@ -0,0 +1,34 @@
# Awesome Reviewers Repository Guidelines
## Repository Structure & Technology Stack
### Technology Stack
- **GitHub Pages** repository
- **Jekyll** static site generator
- **GitHub Actions** for CI/CD
- Raw HTML with Jekyll templating
### Key Pages & Layouts
1. **Root Page** (`/`)
- Managed in `_layouts/default.html`
- Main landing page with reviewer grid
2. **Reviewer Detail Page** (`/reviewers/{slug}/`)
- Managed in `_layouts/reviewer.html`
- Individual reviewer drawer/detail view
### Directory Structure
- **Assets**: `assets/`
- CSS files: `assets/css/`
- Images: `assets/images/`
- **Content**: `_reviewers/`
- Individual reviewer prompt files
- Contains all the reviewer data and prompts
### Development Notes
- This is a Jekyll-based GitHub Pages site
- Changes to layouts, CSS, or reviewer content require Jekyll rebuild
- GitHub Actions handles the build and deployment process
- All styling should be done in the CSS files under `assets/css/`
- Reviewer content is stored as individual files in `_reviewers/` directory

View File

@@ -18,13 +18,13 @@
<div align="center">
📝 **474** Reviewers &nbsp;&nbsp;&nbsp;&nbsp; 💬 **Thousands** of Discussions &nbsp;&nbsp;&nbsp;&nbsp; ⭐ Popular OSS repositories &nbsp;&nbsp;&nbsp;&nbsp; 🚀 **15+** Languages
📝 **1K+** Reviewers &nbsp;&nbsp;&nbsp;&nbsp; 💬 **Thousands** of Discussions &nbsp;&nbsp;&nbsp;&nbsp; ⭐ Popular OSS repositories &nbsp;&nbsp;&nbsp;&nbsp; 🚀 **15+** Languages
</div>
## Features
* **🎯 Hundreds of Curated Prompts:** Over 470 specialized review prompts covering many languages and frameworks. Each prompt is distilled from actual pull request comments, ensuring practical, actionable advice grounded in real code review scenarios.
* **🎯 1K+ Curated Prompts:** Over 1,000 specialized review prompts covering many languages and frameworks. Each prompt is distilled from actual pull request comments, ensuring practical, actionable advice grounded in real code review scenarios.
* **📊 Real Open-Source Insights:** Every reviewer includes context from the open-source repository it came from, including a link to the source repo and stats like how many times that feedback appeared and the repos popularity. This transparency helps you trust the guidance its based on patterns that occurred in high-quality projects (e.g. a prompt might note **9** prior comments advocating a rule in a project with **16k⭐** on GitHub). In short, these AI prompts encapsulate community-agreed best practices.

View File

@@ -10,6 +10,8 @@
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
<link rel="stylesheet" href="{{ '/assets/css/main.css' | relative_url }}">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/github.min.css">
<link rel="stylesheet" href="{{ '/assets/css/highlight.css' | relative_url }}">
</head>
<body>
<header class="header">
@@ -424,6 +426,10 @@
content.innerHTML = html;
}
drawer.classList.add('open');
// Highlight any code blocks in the newly loaded content
if (typeof highlightNewContent === 'function') {
highlightNewContent(content);
}
});
}
@@ -545,13 +551,85 @@
}
}
function htmlToMarkdown(element) {
let markdown = '';
function processNode(node) {
if (node.nodeType === Node.TEXT_NODE) {
return node.textContent;
}
if (node.nodeType === Node.ELEMENT_NODE) {
const tagName = node.tagName.toLowerCase();
const children = Array.from(node.childNodes).map(processNode).join('');
switch (tagName) {
case 'h1': return `# ${children}\n\n`;
case 'h2': return `## ${children}\n\n`;
case 'h3': return `### ${children}\n\n`;
case 'h4': return `#### ${children}\n\n`;
case 'h5': return `##### ${children}\n\n`;
case 'h6': return `###### ${children}\n\n`;
case 'p': return `${children}\n\n`;
case 'strong': case 'b': return `**${children}**`;
case 'em': case 'i': return `*${children}*`;
case 'code':
// Check if this is inline code or part of a pre block
if (node.parentElement && node.parentElement.tagName.toLowerCase() === 'pre') {
return children;
}
return `\`${children}\``;
case 'pre':
const codeElement = node.querySelector('code');
if (codeElement) {
// Extract language from class (e.g., 'language-python' -> 'python')
const languageMatch = codeElement.className.match(/(?:language-|hljs-)(\w+)/);
const language = languageMatch ? languageMatch[1] : '';
return `\`\`\`${language}\n${codeElement.textContent}\n\`\`\`\n\n`;
}
return `\`\`\`\n${children}\n\`\`\`\n\n`;
case 'ul':
return `${children}\n`;
case 'ol':
return `${children}\n`;
case 'li':
const parent = node.parentElement;
if (parent.tagName.toLowerCase() === 'ol') {
// For ordered lists, we'll use '1.' for simplicity
return `1. ${children}\n`;
} else {
return `- ${children}\n`;
}
case 'blockquote':
return children.split('\n').map(line => `> ${line}`).join('\n') + '\n\n';
case 'br':
return '\n';
default:
return children;
}
}
return '';
}
markdown = processNode(element);
// Clean up extra newlines
markdown = markdown.replace(/\n{3,}/g, '\n\n').trim();
return markdown;
}
function copyPrompt() {
const promptContent = document.getElementById('prompt-content');
const copyButton = document.querySelector('.copy-button');
const copyText = document.getElementById('copy-text');
// Convert HTML content back to markdown format
const markdownContent = htmlToMarkdown(promptContent);
const textarea = document.createElement('textarea');
textarea.value = promptContent.textContent;
textarea.value = markdownContent;
document.body.appendChild(textarea);
textarea.select();
document.execCommand('copy');
@@ -605,6 +683,8 @@
}
</script>
{% include modal.html %}
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js"></script>
<script src="{{ '/assets/js/highlight-init.js' | relative_url }}"></script>
<script src="{{ '/assets/js/main.js' | relative_url }}"></script>
</body>
</html>

View File

@@ -60,7 +60,7 @@ layout: default
</div>
</div>
<div class="reviewer-prompt" id="prompt-content">{{ content | strip }}</div>
<div class="reviewer-prompt" id="prompt-content">{{ content }}</div>
</div>
<div class="stats-grid">
@@ -80,14 +80,86 @@ layout: default
</div>
<script>
function htmlToMarkdown(element) {
let markdown = '';
function processNode(node) {
if (node.nodeType === Node.TEXT_NODE) {
return node.textContent;
}
if (node.nodeType === Node.ELEMENT_NODE) {
const tagName = node.tagName.toLowerCase();
const children = Array.from(node.childNodes).map(processNode).join('');
switch (tagName) {
case 'h1': return `# ${children}\n\n`;
case 'h2': return `## ${children}\n\n`;
case 'h3': return `### ${children}\n\n`;
case 'h4': return `#### ${children}\n\n`;
case 'h5': return `##### ${children}\n\n`;
case 'h6': return `###### ${children}\n\n`;
case 'p': return `${children}\n\n`;
case 'strong': case 'b': return `**${children}**`;
case 'em': case 'i': return `*${children}*`;
case 'code':
// Check if this is inline code or part of a pre block
if (node.parentElement && node.parentElement.tagName.toLowerCase() === 'pre') {
return children;
}
return `\`${children}\``;
case 'pre':
const codeElement = node.querySelector('code');
if (codeElement) {
// Extract language from class (e.g., 'language-python' -> 'python')
const languageMatch = codeElement.className.match(/(?:language-|hljs-)(\w+)/);
const language = languageMatch ? languageMatch[1] : '';
return `\`\`\`${language}\n${codeElement.textContent}\n\`\`\`\n\n`;
}
return `\`\`\`\n${children}\n\`\`\`\n\n`;
case 'ul':
return `${children}\n`;
case 'ol':
return `${children}\n`;
case 'li':
const parent = node.parentElement;
if (parent.tagName.toLowerCase() === 'ol') {
// For ordered lists, we'll use '1.' for simplicity
return `1. ${children}\n`;
} else {
return `- ${children}\n`;
}
case 'blockquote':
return children.split('\n').map(line => `> ${line}`).join('\n') + '\n\n';
case 'br':
return '\n';
default:
return children;
}
}
return '';
}
markdown = processNode(element);
// Clean up extra newlines
markdown = markdown.replace(/\n{3,}/g, '\n\n').trim();
return markdown;
}
function copyPrompt() {
const promptContent = document.getElementById('prompt-content');
const copyButton = document.querySelector('.copy-button');
const copyText = document.getElementById('copy-text');
// Convert HTML content back to markdown format
const markdownContent = htmlToMarkdown(promptContent);
// Create a temporary textarea to copy the text
const textarea = document.createElement('textarea');
textarea.value = promptContent.textContent;
textarea.value = markdownContent;
document.body.appendChild(textarea);
textarea.select();
document.execCommand('copy');

227
assets/css/highlight.css Normal file
View File

@@ -0,0 +1,227 @@
/*
GitHub theme for Highlight.js - Custom for Awesome Reviewers
Based on GitHub's syntax highlighting
*/
/* Base styles */
.hljs {
color: #24292f;
background: var(--bg-primary) !important;
}
/* Dark theme adjustments */
[data-theme="dark"] .hljs {
color: #f1f5f9;
background: var(--bg-primary) !important;
}
/* Code block styling - integrates with existing reviewer-prompt styles */
.reviewer-prompt pre code.hljs {
background: none !important;
border: none;
padding: 0;
border-radius: 0;
font-size: inherit;
line-height: inherit;
}
.reviewer-prompt pre {
background: var(--bg-primary) !important;
border: 1px solid var(--border);
border-radius: 6px;
padding: 1rem;
margin: 1rem 0;
overflow-x: auto;
}
/* Ensure hljs backgrounds match our theme */
.reviewer-prompt .hljs {
background: var(--bg-primary) !important;
}
.reviewer-prompt pre.hljs {
background: var(--bg-primary) !important;
}
/* Inline code styling */
.reviewer-prompt :not(pre) > code.hljs {
background: var(--bg-primary) !important;
border: 1px solid var(--border);
border-radius: 4px;
padding: 0.125rem 0.25rem;
font-size: 0.8125rem;
white-space: normal;
}
/* Token colors - GitHub light theme */
.hljs-comment,
.hljs-quote {
color: #6a737d;
font-style: italic;
}
.hljs-variable,
.hljs-template-variable,
.hljs-attribute,
.hljs-tag,
.hljs-name,
.hljs-regexp,
.hljs-link,
.hljs-selector-id,
.hljs-selector-class {
color: #d73a49;
}
.hljs-number,
.hljs-meta,
.hljs-built_in,
.hljs-builtin-name,
.hljs-literal,
.hljs-type,
.hljs-params {
color: #005cc5;
}
.hljs-string,
.hljs-symbol,
.hljs-bullet {
color: #032f62;
}
.hljs-title,
.hljs-section {
color: #6f42c1;
}
.hljs-keyword,
.hljs-selector-tag {
color: #d73a49;
}
.hljs-function {
color: #6f42c1;
}
.hljs-class {
color: #005cc5;
}
.hljs-doctag {
color: #6a737d;
}
.hljs-addition {
color: #28a745;
background-color: #f0fff4;
}
.hljs-deletion {
color: #d73a49;
background-color: #ffeef0;
}
/* Dark theme token colors */
[data-theme="dark"] .hljs-comment,
[data-theme="dark"] .hljs-quote {
color: #8b949e;
}
[data-theme="dark"] .hljs-variable,
[data-theme="dark"] .hljs-template-variable,
[data-theme="dark"] .hljs-attribute,
[data-theme="dark"] .hljs-tag,
[data-theme="dark"] .hljs-name,
[data-theme="dark"] .hljs-regexp,
[data-theme="dark"] .hljs-link,
[data-theme="dark"] .hljs-selector-id,
[data-theme="dark"] .hljs-selector-class {
color: #ff7b72;
}
[data-theme="dark"] .hljs-number,
[data-theme="dark"] .hljs-meta,
[data-theme="dark"] .hljs-built_in,
[data-theme="dark"] .hljs-builtin-name,
[data-theme="dark"] .hljs-literal,
[data-theme="dark"] .hljs-type,
[data-theme="dark"] .hljs-params {
color: #79c0ff;
}
[data-theme="dark"] .hljs-string,
[data-theme="dark"] .hljs-symbol,
[data-theme="dark"] .hljs-bullet {
color: #a5d6ff;
}
[data-theme="dark"] .hljs-title,
[data-theme="dark"] .hljs-section {
color: #d2a8ff;
}
[data-theme="dark"] .hljs-keyword,
[data-theme="dark"] .hljs-selector-tag {
color: #ff7b72;
}
[data-theme="dark"] .hljs-function {
color: #d2a8ff;
}
[data-theme="dark"] .hljs-class {
color: #79c0ff;
}
[data-theme="dark"] .hljs-addition {
color: #7ee787;
background-color: rgba(46, 160, 67, 0.15);
}
[data-theme="dark"] .hljs-deletion {
color: #ffa198;
background-color: rgba(248, 81, 73, 0.15);
}
/* Language-specific adjustments */
.hljs-python .hljs-string {
color: #032f62;
}
[data-theme="dark"] .hljs-python .hljs-string {
color: #a5d6ff;
}
.hljs-rust .hljs-built_in {
color: #005cc5;
}
[data-theme="dark"] .hljs-rust .hljs-built_in {
color: #79c0ff;
}
.hljs-javascript .hljs-built_in,
.hljs-typescript .hljs-built_in {
color: #6f42c1;
}
[data-theme="dark"] .hljs-javascript .hljs-built_in,
[data-theme="dark"] .hljs-typescript .hljs-built_in {
color: #d2a8ff;
}
.hljs-go .hljs-built_in {
color: #005cc5;
}
[data-theme="dark"] .hljs-go .hljs-built_in {
color: #79c0ff;
}
/* Emphasis */
.hljs-emphasis {
font-style: italic;
}
.hljs-strong {
font-weight: bold;
}

View File

@@ -1027,16 +1027,93 @@ h1, h2, h3, h4, h5, h6 {
background: var(--bg-secondary);
border: 1px solid var(--border);
border-radius: 8px;
padding: 1.5rem;
font-family: 'Inter', sans-serif;
font-size: 0.875rem;
line-height: 1.6;
max-height: 400px;
overflow-y: auto;
color: var(--text-primary);
overflow-x: auto;
position: relative;
}
/* Markdown content styling within the prompt box */
.reviewer-prompt h1,
.reviewer-prompt h2,
.reviewer-prompt h3,
.reviewer-prompt h4,
.reviewer-prompt h5,
.reviewer-prompt h6 {
margin: 1.25rem 0 0.75rem 0;
font-weight: 600;
color: var(--text-primary);
}
.reviewer-prompt h1:first-child,
.reviewer-prompt h2:first-child,
.reviewer-prompt h3:first-child {
margin-top: 0;
}
.reviewer-prompt p {
margin: 0 0 1rem 0;
}
.reviewer-prompt ul,
.reviewer-prompt ol {
margin: 0 0 1rem 0;
padding-left: 1.5rem;
}
.reviewer-prompt li {
margin: 0.25rem 0;
}
.reviewer-prompt code {
background: var(--bg-primary);
border: 1px solid var(--border);
border-radius: 4px;
padding: 0.125rem 0.25rem;
font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, monospace;
font-size: 0.8125rem;
color: var(--text-primary);
}
.reviewer-prompt pre {
background: var(--bg-primary);
border: 1px solid var(--border);
border-radius: 6px;
padding: 1rem;
margin: 1rem 0;
overflow-x: auto;
font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, monospace;
font-size: 0.8125rem;
line-height: 1.4;
max-height: 300px;
overflow-y: auto;
color: var(--text-primary);
white-space: pre-wrap;
overflow-x: auto;
position: relative;
}
.reviewer-prompt pre code {
background: none;
border: none;
border-radius: 0;
padding: 0;
font-size: inherit;
}
.reviewer-prompt blockquote {
border-left: 4px solid var(--accent);
margin: 1rem 0;
padding: 0.5rem 1rem;
background: var(--bg-primary);
border-radius: 0 4px 4px 0;
}
.reviewer-prompt strong {
font-weight: 600;
}
.reviewer-prompt em {
font-style: italic;
}
.stats-grid {

View File

@@ -64,18 +64,95 @@
background: var(--bg-secondary);
border: 1px solid var(--border);
border-radius: 8px;
padding: 1rem;
padding: 1.5rem;
font-family: 'Inter', sans-serif;
font-size: 0.8125rem;
line-height: 1.4;
max-height: 300px;
font-size: 0.875rem;
line-height: 1.6;
max-height: 400px;
overflow-y: auto;
color: var(--text-primary);
white-space: pre-wrap;
overflow-x: auto;
position: relative;
}
/* Markdown content styling within the prompt box */
.reviewer-prompt h1,
.reviewer-prompt h2,
.reviewer-prompt h3,
.reviewer-prompt h4,
.reviewer-prompt h5,
.reviewer-prompt h6 {
margin: 1.25rem 0 0.75rem 0;
font-weight: 600;
color: var(--text-primary);
}
.reviewer-prompt h1:first-child,
.reviewer-prompt h2:first-child,
.reviewer-prompt h3:first-child {
margin-top: 0;
}
.reviewer-prompt p {
margin: 0 0 1rem 0;
}
.reviewer-prompt ul,
.reviewer-prompt ol {
margin: 0 0 1rem 0;
padding-left: 1.5rem;
}
.reviewer-prompt li {
margin: 0.25rem 0;
}
.reviewer-prompt code {
background: var(--bg-primary);
border: 1px solid var(--border);
border-radius: 4px;
padding: 0.125rem 0.25rem;
font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, monospace;
font-size: 0.8125rem;
color: var(--text-primary);
}
.reviewer-prompt pre {
background: var(--bg-primary);
border: 1px solid var(--border);
border-radius: 6px;
padding: 1rem;
margin: 1rem 0;
overflow-x: auto;
font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, monospace;
font-size: 0.8125rem;
line-height: 1.4;
}
.reviewer-prompt pre code {
background: none;
border: none;
border-radius: 0;
padding: 0;
font-size: inherit;
}
.reviewer-prompt blockquote {
border-left: 4px solid var(--accent);
margin: 1rem 0;
padding: 0.5rem 1rem;
background: var(--bg-primary);
border-radius: 0 4px 4px 0;
}
.reviewer-prompt strong {
font-weight: 600;
}
.reviewer-prompt em {
font-style: italic;
}
/* Mobile responsive adjustments for standalone page */
@media (max-width: 768px) {
.reviewer-detail {

View File

@@ -0,0 +1,72 @@
// Highlight.js initialization for Awesome Reviewers
// This script initializes syntax highlighting after the DOM is loaded
document.addEventListener('DOMContentLoaded', function() {
// Wait for hljs to be available (loaded from CDN)
if (typeof hljs !== 'undefined') {
// Configure highlight.js
hljs.configure({
// Don't highlight on load automatically - we'll do it manually
noHighlightRe: /^no-highlight$/i,
languageDetectRe: /\blang(?:uage)?-([\w-]+)\b/i,
classPrefix: 'hljs-',
// Languages we support
languages: ['c', 'cpp', 'csharp', 'css', 'html', 'json', 'yaml', 'toml',
'python', 'javascript', 'typescript', 'jsx', 'tsx', 'go',
'java', 'kotlin', 'php', 'ruby', 'rust']
});
// Highlight all code blocks
hljs.highlightAll();
// Also highlight any dynamically loaded content (for the drawer)
const observer = new MutationObserver(function(mutations) {
mutations.forEach(function(mutation) {
if (mutation.type === 'childList') {
mutation.addedNodes.forEach(function(node) {
if (node.nodeType === Node.ELEMENT_NODE) {
// Find any new code blocks and highlight them
const codeBlocks = node.querySelectorAll('pre code, code:not(.hljs)');
codeBlocks.forEach(function(block) {
if (!block.classList.contains('hljs')) {
hljs.highlightElement(block);
}
});
}
});
}
});
});
// Observe the drawer content for dynamic highlighting
const drawerContent = document.getElementById('drawer-content');
if (drawerContent) {
observer.observe(drawerContent, {
childList: true,
subtree: true
});
}
console.log('Highlight.js initialized with language support for:',
['C', 'C++', 'C#', 'CSS', 'HTML', 'JSON', 'YAML', 'TOML',
'Python', 'JavaScript', 'TypeScript', 'JSX', 'TSX', 'Go',
'Java', 'Kotlin', 'PHP', 'Ruby', 'Rust']);
} else {
console.warn('Highlight.js not loaded - syntax highlighting unavailable');
}
});
// Function to manually highlight new content (useful for dynamic content)
function highlightNewContent(container) {
if (typeof hljs !== 'undefined' && container) {
const codeBlocks = container.querySelectorAll('pre code, code:not(.hljs)');
codeBlocks.forEach(function(block) {
if (!block.classList.contains('hljs')) {
hljs.highlightElement(block);
}
});
}
}
// Export for use in other scripts if needed
window.highlightNewContent = highlightNewContent;