<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Codelens - Trend Report</title>
<script src="https://cdn.jsdelivr.net/npm/chart.js@4"></script>
<style>
:root {
--bg-primary: #0d1117; --bg-secondary: #161b22; --bg-tertiary: #21262d;
--text-primary: #f0f6fc; --text-secondary: #8b949e;
--accent-blue: #58a6ff; --accent-green: #3fb950; --accent-yellow: #d29922;
--accent-purple: #a371f7; --accent-red: #f85149;
}
* { box-sizing: border-box; margin: 0; padding: 0; }
body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; background: var(--bg-primary); color: var(--text-primary); line-height: 1.6; }
.container { max-width: 1400px; margin: 0 auto; padding: 2rem; }
header { text-align: center; margin-bottom: 3rem; padding-bottom: 2rem; border-bottom: 1px solid var(--bg-tertiary); }
header h1 { font-size: 2.5rem; background: linear-gradient(135deg, var(--accent-green), var(--accent-blue)); -webkit-background-clip: text; -webkit-text-fill-color: transparent; background-clip: text; }
.snapshot-info { display: flex; justify-content: center; gap: 2rem; margin-top: 1rem; color: var(--text-secondary); }
.snapshot-info .arrow { color: var(--accent-blue); font-size: 1.5rem; }
.stats-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); gap: 1.5rem; margin-bottom: 3rem; }
.stat-card { background: var(--bg-secondary); border-radius: 12px; padding: 1.5rem; text-align: center; border: 1px solid var(--bg-tertiary); }
.stat-card .value { font-size: 1.6rem; font-weight: bold; }
.stat-card .label { color: var(--text-secondary); font-size: 0.85rem; margin-top: 0.5rem; }
.stat-card .delta { font-size: 0.9rem; margin-top: 0.3rem; }
.positive { color: var(--accent-green); }
.negative { color: var(--accent-red); }
.neutral { color: var(--text-secondary); }
.charts-section { display: grid; grid-template-columns: repeat(auto-fit, minmax(400px, 1fr)); gap: 2rem; margin-bottom: 3rem; }
.chart-container { background: var(--bg-secondary); border-radius: 12px; padding: 1.5rem; border: 1px solid var(--bg-tertiary); }
.chart-container h3 { margin-bottom: 1rem; color: var(--text-secondary); }
table { width: 100%; border-collapse: collapse; background: var(--bg-secondary); border-radius: 12px; overflow: hidden; margin-bottom: 2rem; }
th, td { padding: 0.8rem 1rem; text-align: left; border-bottom: 1px solid var(--bg-tertiary); }
th { background: var(--bg-tertiary); font-weight: 600; color: var(--text-secondary); }
tr:hover { background: var(--bg-tertiary); }
.status-added { color: var(--accent-green); }
.status-removed { color: var(--accent-red); }
.status-changed { color: var(--accent-blue); }
footer { text-align: center; padding: 2rem; color: var(--text-secondary); border-top: 1px solid var(--bg-tertiary); margin-top: 3rem; }
</style>
</head>
<body>
<div class="container">
<header>
<h1>Trend Report</h1>
<div class="snapshot-info">
<span>{{ from_date }} {{ from_label }}</span>
<span class="arrow">→</span>
<span>{{ to_date }} {{ to_label }}</span>
</div>
</header>
<section class="stats-grid">
{% for m in metrics %}
<div class="stat-card">
<div class="value">{{ m.to_value }}</div>
<div class="label">{{ m.label }}</div>
<div class="delta {% if m.signed_delta > 0 %}positive{% else if m.signed_delta < 0 %}negative{% else %}neutral{% endif %}">
{{ m.delta_display }} ({{ m.percent_display }})
</div>
</div>
{% endfor %}
</section>
<section class="charts-section">
<div class="chart-container">
<h3>Before vs After</h3>
<canvas id="compareChart"></canvas>
</div>
{% if !by_language.is_empty() %}
<div class="chart-container">
<h3>Language Changes</h3>
<canvas id="langChart"></canvas>
</div>
{% endif %}
</section>
{% if !by_language.is_empty() %}
<section>
<h2 style="margin-bottom: 1rem">By Language</h2>
<table>
<thead><tr><th>Language</th><th>Status</th><th>Before</th><th>After</th><th>Delta</th></tr></thead>
<tbody>
{% for lt in by_language %}
<tr>
<td><strong>{{ lt.language }}</strong></td>
<td class="{% if lt.status == "+" %}status-added{% else if lt.status == "-" %}status-removed{% else %}status-changed{% endif %}">{{ lt.status }}</td>
<td>{{ lt.code_from }}</td>
<td>{{ lt.code_to }}</td>
<td class="{% if lt.code_delta > 0 %}positive{% else if lt.code_delta < 0 %}negative{% else %}neutral{% endif %}">{{ lt.code_delta_display }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</section>
{% endif %}
<footer>
<p>Generated by <a href="https://github.com/DropFan/codelens" style="color: var(--accent-blue)"><strong>Codelens</strong></a> by <a href="https://github.com/DropFan" style="color: var(--accent-blue)">Tiger</a> | High-performance code analysis tool powered by Rust</p>
</footer>
</div>
<script>
const metrics = [
{% for m in metrics %}
{ label: "{{ m.label }}", from: {{ m.from_value }}, to: {{ m.to_value }} },
{% endfor %}
];
new Chart(document.getElementById('compareChart'), {
type: 'bar',
data: {
labels: metrics.map(m => m.label),
datasets: [
{ label: 'Before', data: metrics.map(m => m.from), backgroundColor: '#8b949e', borderRadius: 4 },
{ label: 'After', data: metrics.map(m => m.to), backgroundColor: '#58a6ff', borderRadius: 4 },
]
},
options: {
responsive: true,
scales: {
y: { ticks: { color: '#8b949e' }, grid: { color: '#21262d' } },
x: { ticks: { color: '#8b949e' }, grid: { display: false } }
},
plugins: { legend: { labels: { color: '#f0f6fc' } } }
}
});
{% if !by_language.is_empty() %}
const langs = [
{% for lt in by_language %}
{ name: "{{ lt.language }}", from: {{ lt.code_from }}, to: {{ lt.code_to }} },
{% endfor %}
];
new Chart(document.getElementById('langChart'), {
type: 'bar',
data: {
labels: langs.map(l => l.name),
datasets: [
{ label: 'Before', data: langs.map(l => l.from), backgroundColor: '#8b949e', borderRadius: 4 },
{ label: 'After', data: langs.map(l => l.to), backgroundColor: '#58a6ff', borderRadius: 4 },
]
},
options: {
responsive: true,
scales: {
y: { ticks: { color: '#8b949e' }, grid: { color: '#21262d' } },
x: { ticks: { color: '#8b949e' }, grid: { display: false } }
},
plugins: { legend: { labels: { color: '#f0f6fc' } } }
}
});
{% endif %}
</script>
</body>
</html>