diff --git a/app/static/css/cassandra.css b/app/static/css/cassandra.css index 7d5cb55..aaa420e 100644 --- a/app/static/css/cassandra.css +++ b/app/static/css/cassandra.css @@ -2336,79 +2336,93 @@ a.btn-secondary:hover { color: var(--accent); border-color: var(--accent); } #portfolio-panel.pf-editing .pf-row-del { display: inline; } #portfolio-panel.pf-editing .pf-row-del:hover { color: var(--err, #f55); } -/* Add-position form. */ +/* Add-position form — compact inline strip that visually sits above the + portfolio table rather than as a separate boxed form. */ .pf-add-form { - border: 1px solid var(--neu-dim, #333); - border-radius: 6px; - padding: 12px; - margin-bottom: 12px; - background: var(--surface-2, #1a1a1a); + margin-bottom: 6px; } -.pf-add-row { +.pf-add-strip { display: flex; - gap: 10px; - margin-bottom: 8px; - flex-wrap: wrap; - align-items: flex-end; -} -.pf-add-field { - display: flex; - flex-direction: column; - flex: 1 1 140px; + gap: 6px; + align-items: center; + flex-wrap: nowrap; font-size: 12px; } -.pf-add-label { - color: var(--neu-dim, #888); - margin-bottom: 2px; -} -.pf-add-field input[type="text"], -.pf-add-field input[type="number"], -.pf-add-field input[type="date"] { +.pf-add-input { background: var(--surface, #111); border: 1px solid var(--neu-dim, #444); color: var(--text, #ccc); - padding: 4px 6px; + padding: 3px 6px; border-radius: 3px; font-family: inherit; - font-size: 13px; -} -.pf-add-cost-mode { gap: 16px; } -.pf-add-radio { - display: inline-flex; - gap: 4px; - align-items: center; font-size: 12px; - cursor: pointer; + min-width: 0; +} +.pf-add-input:focus { + outline: none; + border-color: var(--accent, #5af); +} +.pf-add-input--ticker { width: 90px; text-transform: uppercase; } +.pf-add-input--qty { width: 70px; } +.pf-add-input--cost { width: 100px; } +.pf-add-input--date { width: 130px; } + +.pf-add-cost-wrap { + display: inline-flex; + align-items: center; + gap: 4px; } .pf-add-currency { color: var(--neu-dim, #888); font-size: 11px; - margin-top: 2px; + min-width: 28px; +} +.pf-add-icon-btn { + background: transparent; + border: 1px solid var(--neu-dim, #444); + color: var(--neu-dim, #888); + padding: 2px 4px; + border-radius: 3px; + cursor: pointer; + display: inline-flex; + align-items: center; +} +.pf-add-icon-btn:hover { + color: var(--text, #ccc); + border-color: var(--accent, #5af); } .pf-add-submit { background: var(--accent, #5af); color: var(--bg, #000); border: none; - padding: 6px 14px; + width: 26px; + height: 26px; border-radius: 3px; cursor: pointer; font-weight: 600; - align-self: flex-end; + font-size: 16px; + line-height: 1; + display: inline-flex; + align-items: center; + justify-content: center; } .pf-add-submit:disabled { background: var(--neu-dim, #444); cursor: not-allowed; } -.pf-add-status { - font-size: 11px; - margin-top: 2px; +.pf-add-meta { + display: flex; + gap: 12px; + margin-top: 3px; min-height: 14px; + font-size: 11px; } +.pf-add-status:empty { display: none; } .pf-add-status--pending { color: var(--neu-dim, #888); } .pf-add-status--ok { color: var(--ok, #6c6); } .pf-add-status--err { color: var(--err, #f55); } .pf-add-warning { color: var(--warn, #fb3); font-size: 11px; - margin-top: 8px; + margin-top: 3px; } diff --git a/app/static/js/portfolio_edit.js b/app/static/js/portfolio_edit.js index ff7b614..40c1cf4 100644 --- a/app/static/js/portfolio_edit.js +++ b/app/static/js/portfolio_edit.js @@ -177,32 +177,26 @@ } }); - // ---- Cost mode toggle + historical lookup -------------------------- + // ---- Calendar-icon → historical lookup ----------------------------- - const dateField = document.getElementById('pf-add-date-field'); + const dateBtn = document.getElementById('pf-add-date-btn'); const dateInput = document.getElementById('pf-add-date'); const dateStatus = document.getElementById('pf-add-date-status'); const costInput = document.getElementById('pf-add-cost'); - function onModeChange() { - const mode = document.querySelector( - 'input[name="pf-cost-mode"]:checked' - ).value; - if (mode === 'date') { - dateField.hidden = false; - costInput.readOnly = true; - costInput.placeholder = 'auto-filled from date'; + dateBtn.addEventListener('click', function () { + if (!validated) { + setStatus(dateStatus, 'enter a valid ticker first', 'err'); + return; + } + dateInput.hidden = !dateInput.hidden; + if (!dateInput.hidden) { + dateInput.focus(); + if (typeof dateInput.showPicker === 'function') dateInput.showPicker(); } else { - dateField.hidden = true; - costInput.readOnly = false; - costInput.placeholder = '150.25'; setStatus(dateStatus, '', ''); } - } - - document.querySelectorAll('input[name="pf-cost-mode"]').forEach(r => - r.addEventListener('change', onModeChange) - ); + }); async function fetchHistorical() { if (!validated) { @@ -212,8 +206,6 @@ const d = dateInput.value; if (!d) { setStatus(dateStatus, '', ''); - costInput.value = ''; - updateSubmitState(); return; } setStatus(dateStatus, 'looking up…', 'pending'); @@ -225,7 +217,6 @@ if (r.status === 400) { const j = await r.json().catch(() => ({detail: 'invalid date'})); setStatus(dateStatus, '✗ ' + (j.detail || 'invalid date'), 'err'); - costInput.value = ''; updateSubmitState(); return; } @@ -236,18 +227,18 @@ ? '✓ from ' + j.actual_date : '✓'; setStatus(dateStatus, tag, 'ok'); + // Hide the date picker after a successful fill — keeps the row clean. + dateInput.hidden = true; } else { setStatus(dateStatus, '✗ ' + (j.error || 'no data'), 'err'); - costInput.value = ''; } } catch (e) { setStatus(dateStatus, '✗ couldn\'t fetch — try again', 'err'); - costInput.value = ''; } updateSubmitState(); } - dateInput.addEventListener('blur', fetchHistorical); + dateInput.addEventListener('change', fetchHistorical); // ---- Per-row delete (event delegation) ----------------------------- diff --git a/app/templates/dashboard.html b/app/templates/dashboard.html index f9033e3..8162bea 100644 --- a/app/templates/dashboard.html +++ b/app/templates/dashboard.html @@ -61,42 +61,34 @@