06/05 Optimize app

This commit is contained in:
2026-06-05 17:50:46 -04:00
parent 025f3f8823
commit e4007348f8
6 changed files with 497 additions and 32 deletions
+82
View File
@@ -58,6 +58,17 @@
</div>
{% endif %}
<!-- Budget vs Actual chart -->
{% set chart_cats = summary | selectattr('has_budget') | list %}
{% if chart_cats %}
<div class="pcard mb-4">
<div style="font-size:13px;font-weight:600;margin-bottom:12px;">Budget vs Actual</div>
<div style="position:relative;height:{{ [[chart_cats|length * 42, 180]|max, 380]|min }}px;">
<canvas id="budgetChart"></canvas>
</div>
</div>
{% endif %}
<!-- Budget Items -->
{% if summary %}
<div class="pcard p-0">
@@ -148,3 +159,74 @@
</div>
{% endif %}
{% endblock %}
{% block extra_js %}
{% set chart_cats = summary | selectattr('has_budget') | list %}
{% if chart_cats %}
<script>
(function() {
const labels = {{ chart_cats | map(attribute='category') | map(attribute='name') | list | tojson }};
const spent = {{ chart_cats | map(attribute='spent') | list | tojson }};
const limits = {{ chart_cats | map(attribute='limit') | list | tojson }};
const colors = {{ chart_cats | map(attribute='category') | map(attribute='color') | list | tojson }};
const ctx = document.getElementById('budgetChart');
if (!ctx) return;
new Chart(ctx, {
type: 'bar',
data: {
labels: labels,
datasets: [
{
label: 'Spent',
data: spent,
backgroundColor: colors.map((c, i) => {
const pct = limits[i] > 0 ? spent[i] / limits[i] : 0;
return pct >= 1 ? '#ef4444cc' : pct >= 0.8 ? '#f59e0bcc' : '#10b981cc';
}),
borderRadius: 4,
barPercentage: 0.55,
categoryPercentage: 0.9,
},
{
label: 'Budget',
data: limits,
backgroundColor: '#e2e8f0cc',
borderRadius: 4,
barPercentage: 0.55,
categoryPercentage: 0.9,
},
],
},
options: {
indexAxis: 'y',
responsive: true,
maintainAspectRatio: false,
plugins: {
legend: { position: 'top', labels: { boxWidth: 10, font: { size: 11 } } },
tooltip: {
callbacks: {
label: ctx => {
const sym = '{{ current_user.currency_symbol }}';
return ` ${ctx.dataset.label}: ${sym}${ctx.parsed.x.toLocaleString('en-US', {minimumFractionDigits:2, maximumFractionDigits:2})}`;
}
}
},
},
scales: {
x: {
beginAtZero: true,
grid: { color: '#f1f5f9' },
ticks: {
font: { size: 10 },
callback: v => '{{ current_user.currency_symbol }}' + v.toLocaleString(),
},
},
y: { ticks: { font: { size: 11 } } },
},
},
});
})();
</script>
{% endif %}
{% endblock %}