Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 12 additions & 10 deletions src/frontend/analytics.js
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,8 @@ async function renderAnalytics(container) {
var multiplier = data.totalCost / totalPaid;
var savingsPositive = savings > 0;
var breakdown = subEntries.map(function(e) {
return escHtml(e.plan || 'Sub') + ' $' + parseFloat(e.paid).toFixed(0);
var prefix = e.service ? escHtml(e.service) + ' ' : '';
return prefix + escHtml(e.plan || 'Sub') + ' $' + parseFloat(e.paid).toFixed(0);
}).join(' + ');
html += '<div class="sub-comparison">';
html += '<div class="sub-card sub-paid"><span class="sub-val">$' + totalPaid.toFixed(2) + '</span><span class="sub-label">Paid (' + breakdown + ')</span></div>';
Expand All @@ -240,23 +241,24 @@ async function renderAnalytics(container) {
if (serviceLabel) html += '<span class="sub-entry-service">' + escHtml(serviceLabel) + '</span>';
html += '<span class="sub-entry-plan">' + escHtml(e.plan || '\u2014') + '</span>';
html += '<span class="sub-entry-paid">$' + parseFloat(e.paid || 0).toFixed(2) + '/mo</span>';
html += '<span class="sub-entry-from">' + (e.from ? 'from ' + e.from : 'no date') + '</span>';
html += '<span class="sub-entry-from">' + (e.from ? 'from ' + escHtml(e.from) : 'no date') + '</span>';
html += '<button class="sub-entry-remove" onclick="removeSubEntry(' + i + ')" title="Remove">\u00d7</button>';
html += '</div>';
});
}
html += '</div>';

// Add form
var serviceOptions = '<option value="">— service —</option>' +
Object.keys(SERVICE_PLANS).map(function(k) {
return '<option value="' + k + '">' + SERVICE_PLANS[k].label + '</option>';
}).join('');
var serviceDatalistOpts = Object.keys(SERVICE_PLANS).map(function(k) {
return '<option value="' + escHtml(k) + '">';
}).join('');
html += '<div class="sub-add-form">';
html += '<select id="sub-new-service" onchange="onSubServiceChange()">' + serviceOptions + '</select>';
html += '<select id="sub-new-plan" onchange="onSubPlanChange()"><option value="">— plan —</option></select>';
html += '<input id="sub-new-paid" type="number" min="0" step="0.01" placeholder="$/mo" />';
html += '<input id="sub-new-from" type="date" title="Start date of this billing period" />';
html += '<datalist id="sub-service-opts">' + serviceDatalistOpts + '</datalist>';
html += '<datalist id="sub-plan-opts"></datalist>';
html += '<input id="sub-new-service" list="sub-service-opts" placeholder="Service" aria-label="Service name" oninput="onSubServiceChange()" autocomplete="off" />';
html += '<input id="sub-new-plan" list="sub-plan-opts" placeholder="Plan" aria-label="Plan name" oninput="onSubPlanChange()" autocomplete="off" />';
html += '<input id="sub-new-paid" type="number" min="0" step="0.01" placeholder="$/mo" aria-label="Monthly price in dollars" />';
html += '<input id="sub-new-from" type="date" title="Start date of this billing period" aria-label="Subscription start date" />';
html += '<button onclick="addSubEntry()">+ Add period</button>';
html += '</div>';
html += '</div>';
Expand Down
24 changes: 14 additions & 10 deletions src/frontend/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -248,18 +248,17 @@ var SERVICE_PLANS = {

function onSubServiceChange() {
var serviceEl = document.getElementById('sub-new-service');
var planEl = document.getElementById('sub-new-plan');
var planOpts = document.getElementById('sub-plan-opts');
var service = serviceEl ? serviceEl.value.trim() : '';
if (!planOpts) return;
planOpts.innerHTML = '';
var paidEl = document.getElementById('sub-new-paid');
var service = serviceEl ? serviceEl.value : '';
if (!planEl) return;
planEl.innerHTML = '<option value="">— select plan —</option>';
paidEl.value = '';
if (paidEl) paidEl.value = '';
if (service && SERVICE_PLANS[service]) {
SERVICE_PLANS[service].plans.forEach(function(p) {
var opt = document.createElement('option');
opt.value = p.name;
opt.textContent = p.name + ' ($' + p.price + '/mo)';
planEl.appendChild(opt);
planOpts.appendChild(opt);
});
}
}
Expand All @@ -268,10 +267,11 @@ function onSubPlanChange() {
var serviceEl = document.getElementById('sub-new-service');
var planEl = document.getElementById('sub-new-plan');
var paidEl = document.getElementById('sub-new-paid');
var service = serviceEl ? serviceEl.value : '';
var planName = planEl ? planEl.value : '';
var service = serviceEl ? serviceEl.value.trim() : '';
var planName = planEl ? planEl.value.trim() : '';
if (service && planName && SERVICE_PLANS[service]) {
var found = SERVICE_PLANS[service].plans.find(function(p) { return p.name === planName; });
var planLower = planName.toLowerCase();
var found = SERVICE_PLANS[service].plans.find(function(p) { return p.name.toLowerCase() === planLower; });
if (found && paidEl) paidEl.value = found.price;
}
}
Expand All @@ -293,13 +293,17 @@ function addSubEntry() {
var paid = parseFloat(document.getElementById('sub-new-paid').value) || 0;
var from = (document.getElementById('sub-new-from').value || '').trim();
if (!paid) return;
_analyticsHtmlCache = null;
_analyticsCacheUrl = null;
var cfg = getSubscriptionConfig();
cfg.entries.push({ service: service || '', plan: plan || 'Subscription', paid: paid, from: from });
cfg.entries.sort(function(a,b){return (a.from||'').localeCompare(b.from||'');});
saveSubscriptionConfig(cfg);
render();
}
function removeSubEntry(idx) {
_analyticsHtmlCache = null;
_analyticsCacheUrl = null;
var cfg = getSubscriptionConfig();
cfg.entries.splice(idx, 1);
saveSubscriptionConfig(cfg);
Expand Down
14 changes: 3 additions & 11 deletions src/frontend/styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
/* ── CSS Custom Properties (Dark Theme — Default) ──────────────── */

:root {
color-scheme: dark;
--bg-primary: #1a1d23;
--bg-secondary: #22262e;
--bg-card: #2a2e37;
Expand Down Expand Up @@ -3116,17 +3117,8 @@ body {
font-size: 13px;
}

.sub-add-form select {
background: var(--bg-card);
border: 1px solid var(--border);
border-radius: 6px;
padding: 6px 10px;
color: var(--text);
font-size: 13px;
cursor: pointer;
}
.sub-add-form select:first-child { width: 170px; }
.sub-add-form select:nth-child(2) { width: 150px; }
#sub-new-service { width: 180px; }
#sub-new-plan { width: 130px; }
.sub-add-form input[type="number"] { width: 80px; }
.sub-add-form input[type="date"] { width: 140px; }

Expand Down
Loading