diff --git a/src/frontend/analytics.js b/src/frontend/analytics.js
index 0d7dc99..7763ac4 100644
--- a/src/frontend/analytics.js
+++ b/src/frontend/analytics.js
@@ -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 += '
';
html += '
$' + totalPaid.toFixed(2) + 'Paid (' + breakdown + ')
';
@@ -240,7 +241,7 @@ async function renderAnalytics(container) {
if (serviceLabel) html += '
' + escHtml(serviceLabel) + '';
html += '
' + escHtml(e.plan || '\u2014') + '';
html += '
$' + parseFloat(e.paid || 0).toFixed(2) + '/mo';
- html += '
' + (e.from ? 'from ' + e.from : 'no date') + '';
+ html += '
' + (e.from ? 'from ' + escHtml(e.from) : 'no date') + '';
html += '
';
html += '
';
});
@@ -248,15 +249,16 @@ async function renderAnalytics(container) {
html += '';
// Add form
- var serviceOptions = '' +
- Object.keys(SERVICE_PLANS).map(function(k) {
- return '';
- }).join('');
+ var serviceDatalistOpts = Object.keys(SERVICE_PLANS).map(function(k) {
+ return '— select plan —';
- 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);
});
}
}
@@ -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;
}
}
@@ -293,6 +293,8 @@ 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||'');});
@@ -300,6 +302,8 @@ function addSubEntry() {
render();
}
function removeSubEntry(idx) {
+ _analyticsHtmlCache = null;
+ _analyticsCacheUrl = null;
var cfg = getSubscriptionConfig();
cfg.entries.splice(idx, 1);
saveSubscriptionConfig(cfg);
diff --git a/src/frontend/styles.css b/src/frontend/styles.css
index 9ed604b..250c8cc 100644
--- a/src/frontend/styles.css
+++ b/src/frontend/styles.css
@@ -9,6 +9,7 @@
/* ── CSS Custom Properties (Dark Theme — Default) ──────────────── */
:root {
+ color-scheme: dark;
--bg-primary: #1a1d23;
--bg-secondary: #22262e;
--bg-card: #2a2e37;
@@ -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; }