moving handlers into service. adding website
This commit is contained in:
137
internal/website/static/index.html
Normal file
137
internal/website/static/index.html
Normal file
@@ -0,0 +1,137 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
||||
<title>Portfolio — Samantha Friis</title>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Space+Mono:wght@400;700&family=Fraunces:ital,wght@0,300;0,400;0,600;1,300;1,400&display=swap" rel="stylesheet"/>
|
||||
<link rel="stylesheet" href="/style">
|
||||
<script src="https://unpkg.com/htmx.org@2.0.4"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
|
||||
<header>
|
||||
<a href="/" class="back">← back</a>
|
||||
<p class="tag">// portfolio</p>
|
||||
<h1>Investment<br/><span>Portfolio</span></h1>
|
||||
<p class="header-sub">Equity positions · Personal research</p>
|
||||
</header>
|
||||
|
||||
<!-- Health bar: polls every 60s, shows error on failure -->
|
||||
<div class="status-bar"
|
||||
hx-get="/health/fragment"
|
||||
hx-trigger="load, every 60s"
|
||||
hx-target="this"
|
||||
hx-swap="innerHTML"
|
||||
hx-on::response-error="this.innerHTML = '<span class=\'status-dot error\'></span><span>backend unreachable</span><span class=\'status-spacer\'></span><button class=\'refresh-btn\' hx-get=\'/health/fragment\' hx-target=\'closest .status-bar\' hx-swap=\'innerHTML\' onclick=\'htmx.process(this)\'>↺ retry</button>'"
|
||||
hx-on::send-error="this.innerHTML = '<span class=\'status-dot error\'></span><span>failed to connect</span><span class=\'status-spacer\'></span><button class=\'refresh-btn\' hx-get=\'/health/fragment\' hx-target=\'closest .status-bar\' hx-swap=\'innerHTML\' onclick=\'htmx.process(this)\'>↺ retry</button>'">
|
||||
<span class="status-dot loading"></span>
|
||||
<span>connecting to backend…</span>
|
||||
<span class="status-spacer"></span>
|
||||
<button class="refresh-btn"
|
||||
hx-get="/health/fragment"
|
||||
hx-target="closest .status-bar"
|
||||
hx-swap="innerHTML">↺ refresh</button>
|
||||
</div>
|
||||
|
||||
<!-- Summary cards -->
|
||||
<div class="cards"
|
||||
hx-get="/summary/fragment"
|
||||
hx-trigger="load"
|
||||
hx-swap="outerHTML">
|
||||
<div class="card"><p class="card-label">Positions</p><p class="card-value dim">…</p></div>
|
||||
<div class="card"><p class="card-label">Total Shares</p><p class="card-value dim">…</p></div>
|
||||
<div class="card"><p class="card-label">Total Trades</p><p class="card-value dim">…</p></div>
|
||||
<div class="card"><p class="card-label">Currencies</p><p class="card-value dim">…</p></div>
|
||||
</div>
|
||||
|
||||
<!-- Positions table -->
|
||||
<p class="section-label">// <span>positions</span></p>
|
||||
<div class="table-wrap">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Symbol</th><th>Currency</th><th>Shares</th>
|
||||
<th>Cost Basis</th><th>Weight</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody hx-get="/positions/fragment"
|
||||
hx-trigger="load"
|
||||
hx-swap="innerHTML">
|
||||
<tr class="state-row"><td colspan="5">loading…</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<!-- Companies table -->
|
||||
<p class="section-label">// <span>companies</span> — tracked universe</p>
|
||||
<div class="table-wrap">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Symbol</th><th>Currency</th><th>Price</th>
|
||||
<th>Shares Outstanding</th><th>Market Cap</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody hx-get="/company/fragment"
|
||||
hx-trigger="load"
|
||||
hx-swap="innerHTML">
|
||||
<tr class="state-row"><td colspan="5">loading…</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<!-- Trades accordion: lazy-loads on open -->
|
||||
<div class="trades-section">
|
||||
<button class="trades-toggle"
|
||||
aria-expanded="false"
|
||||
onclick="this.setAttribute('aria-expanded', this.getAttribute('aria-expanded')==='true'?'false':'true'); this.nextElementSibling.classList.toggle('open')">
|
||||
<span class="toggle-label">// <span>trade history</span> — all executed orders</span>
|
||||
<span class="toggle-icon">▾</span>
|
||||
</button>
|
||||
|
||||
<div class="trades-body" id="tradesAccordion">
|
||||
<div class="trades-inner">
|
||||
|
||||
<!-- Filter buttons swap only the tbody -->
|
||||
<div class="trades-filter" id="tradeFilters">
|
||||
<button class="filter-btn active"
|
||||
hx-get="/trade/fragment"
|
||||
hx-target="#tradesBody"
|
||||
hx-swap="innerHTML">All</button>
|
||||
</div>
|
||||
|
||||
<p class="trades-count"
|
||||
hx-get="/trade/count"
|
||||
hx-trigger="load from:#tradesAccordion"
|
||||
hx-swap="innerHTML">—</p>
|
||||
|
||||
<div class="trades-table-wrap">
|
||||
<table class="trades-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Symbol</th><th>Asset</th><th>Currency</th>
|
||||
<th>Date</th><th>Dir</th><th>Qty</th><th>Price</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="tradesBody"
|
||||
hx-get="/trade/fragment"
|
||||
hx-trigger="revealed"
|
||||
hx-swap="innerHTML">
|
||||
<tr class="state-row"><td colspan="7">expand to load trades</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<footer>
|
||||
<a href="mailto:me@samantha42.xyz">me@samantha42.xyz</a>
|
||||
<p class="footer-copy">© 2026 — All rights reserved</p>
|
||||
</footer>
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user