uodated charting
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -6,6 +6,7 @@
|
||||
*.key
|
||||
*.env
|
||||
*secrets.js
|
||||
secrets.js
|
||||
trahn-trade-frontend/src/auth/secrets.js*
|
||||
|
||||
# ============================================
|
||||
|
||||
@@ -5,8 +5,6 @@
|
||||
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>TRAHN Grid Trader</title>
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;600&family=Space+Grotesk:wght@400;600;700&display=swap" rel="stylesheet">
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
:root {
|
||||
--bg-primary: #0d1117;
|
||||
--bg-secondary: #161b22;
|
||||
--bg-tertiary: #21262d;
|
||||
--text-primary: #e6edf3;
|
||||
--text-secondary: #8b949e;
|
||||
--bg-primary: #000000;
|
||||
--bg-secondary: #070808;
|
||||
--bg-tertiary: #363737;
|
||||
--text-primary: #01ff3c;
|
||||
--text-secondary: #01ff3c;
|
||||
--text-muted: #484f58;
|
||||
--accent: #58a6ff;
|
||||
--green: #3fb950;
|
||||
@@ -22,7 +22,8 @@
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: 'Space Grotesk', -apple-system, BlinkMacSystemFont, sans-serif;
|
||||
font-family: 'Ac437_Rainbow100_re_132', monospace;
|
||||
font-size: 18px;
|
||||
background: var(--bg-primary);
|
||||
color: var(--text-primary);
|
||||
min-height: 100vh;
|
||||
@@ -35,21 +36,27 @@ body {
|
||||
}
|
||||
|
||||
header {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
text-align: center;
|
||||
margin-right: auto;
|
||||
margin-left: auto;
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
|
||||
.ascii-logo {
|
||||
font-family: 'JetBrains Mono', monospace;
|
||||
font-size: 0.65rem;
|
||||
line-height: 1.1;
|
||||
color: var(--accent);
|
||||
margin: 0;
|
||||
display: inline-block;
|
||||
.logo {
|
||||
margin-left: 32px;
|
||||
font-family: 'Ac437_Rainbow100_re_132', monospace;
|
||||
font-size: 9rem;
|
||||
font-weight: 700;
|
||||
color: var(--text-primary);
|
||||
text-align: center;
|
||||
letter-spacing: 0.25em;
|
||||
text-shadow: 0 10 30px rgba(88, 166, 255, 0.3);
|
||||
}
|
||||
|
||||
.subtitle {
|
||||
font-family: 'JetBrains Mono', monospace;
|
||||
font-family: 'Ac437_Rainbow100_re_132', monospace;
|
||||
font-size: 0.875rem;
|
||||
color: var(--text-secondary);
|
||||
letter-spacing: 0.05em;
|
||||
@@ -96,15 +103,16 @@ header {
|
||||
}
|
||||
|
||||
.date-label {
|
||||
display: block;
|
||||
font-size: 1.25rem;
|
||||
font-family: 'Ac437_Rainbow100_re_132';
|
||||
font-weight: 600;
|
||||
font-size: 1.45rem;
|
||||
font-weight: 600;
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
.date-status {
|
||||
display: block;
|
||||
font-family: 'JetBrains Mono', monospace;
|
||||
font-family: 'Ac437_Rainbow100_re_132', monospace;
|
||||
font-size: 0.75rem;
|
||||
color: var(--text-secondary);
|
||||
margin-top: 0.25rem;
|
||||
@@ -121,8 +129,15 @@ header {
|
||||
}
|
||||
|
||||
@keyframes pulse {
|
||||
0%, 100% { opacity: 1; }
|
||||
50% { opacity: 0.4; }
|
||||
|
||||
0%,
|
||||
100% {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
50% {
|
||||
opacity: 0.4;
|
||||
}
|
||||
}
|
||||
|
||||
/* Chart */
|
||||
@@ -145,7 +160,7 @@ header {
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 6px;
|
||||
padding: 0.5rem 0.75rem;
|
||||
font-family: 'JetBrains Mono', monospace;
|
||||
font-family: 'Ac437_Rainbow100_re_132', monospace;
|
||||
font-size: 0.75rem;
|
||||
pointer-events: none;
|
||||
opacity: 0;
|
||||
@@ -184,7 +199,7 @@ header {
|
||||
gap: 1rem;
|
||||
border-radius: 12px;
|
||||
color: var(--text-secondary);
|
||||
font-family: 'JetBrains Mono', monospace;
|
||||
font-family: 'Ac437_Rainbow100_re_132', monospace;
|
||||
z-index: 50;
|
||||
}
|
||||
|
||||
@@ -198,12 +213,15 @@ header {
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
to { transform: rotate(360deg); }
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
/* Stats */
|
||||
.stats {
|
||||
display: flex;
|
||||
font-size: 1.2rem;
|
||||
justify-content: space-between;
|
||||
gap: 1rem;
|
||||
margin-bottom: 1.5rem;
|
||||
@@ -211,6 +229,7 @@ header {
|
||||
|
||||
.stat {
|
||||
flex: 1;
|
||||
font-size: 1.2rem;
|
||||
background: var(--bg-secondary);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 8px;
|
||||
@@ -228,15 +247,26 @@ header {
|
||||
}
|
||||
|
||||
.stat-value {
|
||||
font-family: 'JetBrains Mono', monospace;
|
||||
font-family: 'Ac437_Rainbow100_re_132', monospace;
|
||||
font-size: 1.25rem;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.stat-value.high { color: var(--green); }
|
||||
.stat-value.low { color: var(--red); }
|
||||
.stat-value.buy { color: var(--yellow); }
|
||||
.stat-value.sell { color: var(--orange); }
|
||||
.stat-value.high {
|
||||
color: var(--green);
|
||||
}
|
||||
|
||||
.stat-value.low {
|
||||
color: var(--red);
|
||||
}
|
||||
|
||||
.stat-value.buy {
|
||||
color: var(--yellow);
|
||||
}
|
||||
|
||||
.stat-value.sell {
|
||||
color: var(--orange);
|
||||
}
|
||||
|
||||
/* Day indicators */
|
||||
.day-indicators {
|
||||
@@ -276,6 +306,7 @@ header {
|
||||
.legend-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-size: 1rem;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
@@ -307,7 +338,7 @@ header {
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 6px;
|
||||
padding: 0.5rem 0.75rem;
|
||||
font-family: 'JetBrains Mono', monospace;
|
||||
font-family: 'Ac437_Rainbow100_re_132', monospace;
|
||||
font-size: 0.75rem;
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
@@ -363,7 +394,7 @@ header {
|
||||
|
||||
.grid-levels-header {
|
||||
text-align: center;
|
||||
font-size: 0.875rem;
|
||||
font-size: 1.2rem;
|
||||
font-weight: 600;
|
||||
color: var(--text-secondary);
|
||||
margin-bottom: 1rem;
|
||||
@@ -385,7 +416,7 @@ header {
|
||||
}
|
||||
|
||||
.grid-column-header {
|
||||
font-size: 0.75rem;
|
||||
font-size: 1.2rem;
|
||||
font-weight: 600;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.05em;
|
||||
@@ -395,18 +426,20 @@ header {
|
||||
}
|
||||
|
||||
.grid-column-header.buy {
|
||||
font-size: 1.2rem;
|
||||
color: var(--yellow);
|
||||
background: rgba(240, 192, 0, 0.1);
|
||||
}
|
||||
|
||||
.grid-column-header.sell {
|
||||
font-size: 1.2rem;
|
||||
color: var(--orange);
|
||||
background: rgba(219, 109, 40, 0.1);
|
||||
}
|
||||
|
||||
.grid-level {
|
||||
font-family: 'JetBrains Mono', monospace;
|
||||
font-size: 0.8rem;
|
||||
font-family: 'Ac437_Rainbow100_re_132', monospace;
|
||||
font-size: 1.2rem;
|
||||
padding: 0.25rem 0.75rem;
|
||||
border-radius: 4px;
|
||||
min-width: 100px;
|
||||
@@ -415,6 +448,7 @@ header {
|
||||
|
||||
.grid-level.buy {
|
||||
color: var(--yellow);
|
||||
font-size: 1.2rem;
|
||||
background: rgba(240, 192, 0, 0.08);
|
||||
border: 1px solid rgba(240, 192, 0, 0.2);
|
||||
}
|
||||
@@ -449,7 +483,7 @@ header {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.auth-card .ascii-logo {
|
||||
.auth-card .logo {
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
@@ -588,6 +622,10 @@ header {
|
||||
|
||||
/* Logout Button */
|
||||
.logout-btn {
|
||||
height: 40px;
|
||||
width: 110px;
|
||||
font-size: 1.2rem;
|
||||
font-family: Ac437_Rainbow100_re_132;
|
||||
position: absolute;
|
||||
top: 1rem;
|
||||
right: 1rem;
|
||||
@@ -596,7 +634,6 @@ header {
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 6px;
|
||||
color: var(--text-secondary);
|
||||
font-size: 0.875rem;
|
||||
font-family: inherit;
|
||||
cursor: pointer;
|
||||
transition: border-color 0.2s, color 0.2s;
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
* Communicates with backend REST API
|
||||
*/
|
||||
|
||||
const API_BASE = 'http://localhost:3001/api';
|
||||
const API_BASE = 'http://localhost:3001/v1';
|
||||
|
||||
export const tradingApi = {
|
||||
/**
|
||||
|
||||
@@ -37,7 +37,6 @@ export function Chart({ prices, trades }) {
|
||||
return () => window.removeEventListener('resize', updateDimensions);
|
||||
}, []);
|
||||
|
||||
// Draw chart
|
||||
useEffect(() => {
|
||||
const canvas = canvasRef.current;
|
||||
if (!canvas || dimensions.width === 0) return;
|
||||
@@ -59,7 +58,7 @@ export function Chart({ prices, trades }) {
|
||||
|
||||
if (!prices || prices.length === 0) {
|
||||
ctx.fillStyle = COLORS.textMuted;
|
||||
ctx.font = '14px JetBrains Mono, monospace';
|
||||
ctx.font = '18px Ac437_Rainbow100_re_132, monospace';
|
||||
ctx.textAlign = 'center';
|
||||
ctx.fillText('No data for this day', width / 2, height / 2);
|
||||
return;
|
||||
@@ -108,7 +107,6 @@ export function Chart({ prices, trades }) {
|
||||
ctx.stroke();
|
||||
}
|
||||
|
||||
// Draw baseline
|
||||
const baselineY = priceToY(baselinePrice);
|
||||
ctx.strokeStyle = COLORS.baseline;
|
||||
ctx.setLineDash([4, 4]);
|
||||
@@ -118,7 +116,6 @@ export function Chart({ prices, trades }) {
|
||||
ctx.stroke();
|
||||
ctx.setLineDash([]);
|
||||
|
||||
// Draw gradient fill
|
||||
if (prices.length >= 2) {
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(timeToX(times[0]), baselineY);
|
||||
@@ -139,7 +136,6 @@ export function Chart({ prices, trades }) {
|
||||
ctx.fill();
|
||||
}
|
||||
|
||||
// Draw price line
|
||||
if (prices.length >= 2) {
|
||||
ctx.beginPath();
|
||||
ctx.strokeStyle = COLORS.line;
|
||||
@@ -154,9 +150,8 @@ export function Chart({ prices, trades }) {
|
||||
ctx.stroke();
|
||||
}
|
||||
|
||||
// Draw Y axis labels
|
||||
ctx.fillStyle = COLORS.text;
|
||||
ctx.font = '11px JetBrains Mono, monospace';
|
||||
ctx.font = '14px Ac437_Rainbow100_re_132, monospace';
|
||||
ctx.textAlign = 'left';
|
||||
|
||||
for (let price = startPrice; price <= maxPrice; price += priceStep) {
|
||||
@@ -164,7 +159,6 @@ export function Chart({ prices, trades }) {
|
||||
ctx.fillText(formatPrice(price), width - PADDING.right + 8, y + 4);
|
||||
}
|
||||
|
||||
// Draw X axis labels
|
||||
ctx.textAlign = 'center';
|
||||
const hourMs = 60 * 60 * 1000;
|
||||
const rangeMs = maxTime - minTime;
|
||||
@@ -183,7 +177,6 @@ export function Chart({ prices, trades }) {
|
||||
current += stepMs;
|
||||
}
|
||||
|
||||
// Draw trades
|
||||
for (const trade of (trades || [])) {
|
||||
const x = timeToX(trade.t || trade.timestamp);
|
||||
const y = priceToY(trade.price);
|
||||
@@ -193,7 +186,6 @@ export function Chart({ prices, trades }) {
|
||||
const color = trade.side === 'buy' ? COLORS.buy : COLORS.sell;
|
||||
const radius = 7;
|
||||
|
||||
// Glow
|
||||
ctx.beginPath();
|
||||
ctx.arc(x, y, radius + 4, 0, Math.PI * 2);
|
||||
ctx.fillStyle = color + '33';
|
||||
@@ -212,7 +204,6 @@ export function Chart({ prices, trades }) {
|
||||
ctx.fill();
|
||||
}
|
||||
|
||||
// Draw current price tag
|
||||
if (prices.length > 0) {
|
||||
const lastPrice = priceValues[priceValues.length - 1];
|
||||
const y = priceToY(lastPrice);
|
||||
@@ -226,14 +217,13 @@ export function Chart({ prices, trades }) {
|
||||
ctx.fill();
|
||||
|
||||
ctx.fillStyle = '#fff';
|
||||
ctx.font = 'bold 11px JetBrains Mono, monospace';
|
||||
ctx.font = 'bold 14px Ac437_Rainbow100_re_132, monospace';
|
||||
ctx.textAlign = 'left';
|
||||
ctx.fillText(formatPrice(lastPrice), x + 10, y + 4);
|
||||
}
|
||||
|
||||
}, [prices, trades, dimensions]);
|
||||
|
||||
// Mouse handling for tooltip
|
||||
const handleMouseMove = (e) => {
|
||||
if (!prices || prices.length === 0) {
|
||||
setTooltip(null);
|
||||
|
||||
BIN
trahn-trade-frontend/src/fonts/Ac437_Rainbow100_re_132.ttf
Normal file
BIN
trahn-trade-frontend/src/fonts/Ac437_Rainbow100_re_132.ttf
Normal file
Binary file not shown.
BIN
trahn-trade-frontend/src/fonts/Mx437_Compaq_Port3.ttf
Normal file
BIN
trahn-trade-frontend/src/fonts/Mx437_Compaq_Port3.ttf
Normal file
Binary file not shown.
BIN
trahn-trade-frontend/src/fonts/Px437_AMI_EGA_8x8.ttf
Normal file
BIN
trahn-trade-frontend/src/fonts/Px437_AMI_EGA_8x8.ttf
Normal file
Binary file not shown.
BIN
trahn-trade-frontend/src/fonts/Px437_Robotron_A7100.ttf
Normal file
BIN
trahn-trade-frontend/src/fonts/Px437_Robotron_A7100.ttf
Normal file
Binary file not shown.
@@ -1 +1,34 @@
|
||||
/* Reset handled in App.css */
|
||||
@font-face {
|
||||
font-family: 'Ac437_Rainbow100_re_1323';
|
||||
src: local('./fonts/Mx437_Compaq_Port3.ttf') format('truetype');
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Ac437_Rainbow100_re_1323';
|
||||
src: local('./fonts/Mx437_Compaq_Port3.ttf') format('truetype');
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Px437_AMI_EGA_8x8';
|
||||
src: local('Px437_AMI_EGA_8x8'), url(./fonts/Px437_AMI_EGA_8x8.ttf) format('truetype');
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Ac437_Rainbow100_re_132';
|
||||
src: local('Ac437_Rainbow100_re_132'), url(./fonts/Ac437_Rainbow100_re_132.ttf) format('truetype');
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Ac437_Rainbow100_re_132';
|
||||
src: local('Ac437_Rainbow100_re_132'), url(./fonts/Ac437_Rainbow100_re_132.ttf) format('truetype');
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
}
|
||||
@@ -52,13 +52,7 @@ export function Dashboard() {
|
||||
return (
|
||||
<div className="container">
|
||||
<header>
|
||||
<pre className="ascii-logo">{`
|
||||
████████╗██████╗ █████╗ ██╗ ██╗███╗ ██╗
|
||||
╚══██╔══╝██╔══██╗██╔══██╗██║ ██║████╗ ██║
|
||||
██║ ██████╔╝███████║███████║██╔██╗ ██║
|
||||
██║ ██╔══██╗██╔══██║██╔══██║██║╚██╗██║
|
||||
██║ ██║ ██║██║ ██║██║ ██║██║ ╚████║
|
||||
╚═╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚═╝ ╚═╝╚═╝ ╚═══╝`}</pre>
|
||||
<h1 className="logo">TRAHN</h1>
|
||||
<button className="logout-btn" onClick={logout}>Logout</button>
|
||||
</header>
|
||||
|
||||
|
||||
@@ -29,13 +29,7 @@ export function Login() {
|
||||
return (
|
||||
<div className="auth-container">
|
||||
<div className="auth-card">
|
||||
<pre className="ascii-logo">{`
|
||||
████████╗██████╗ █████╗ ██╗ ██╗███╗ ██╗
|
||||
╚══██╔══╝██╔══██╗██╔══██╗██║ ██║████╗ ██║
|
||||
██║ ██████╔╝███████║███████║██╔██╗ ██║
|
||||
██║ ██╔══██╗██╔══██║██╔══██║██║╚██╗██║
|
||||
██║ ██║ ██║██║ ██║██║ ██║██║ ╚████║
|
||||
╚═╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚═╝ ╚═╝╚═╝ ╚═══╝`}</pre>
|
||||
<h1 className="logo">TRAHN</h1>
|
||||
|
||||
<h2>Welcome Back</h2>
|
||||
|
||||
|
||||
@@ -38,13 +38,7 @@ export function Signup() {
|
||||
return (
|
||||
<div className="auth-container">
|
||||
<div className="auth-card">
|
||||
<pre className="ascii-logo">{`
|
||||
████████╗██████╗ █████╗ ██╗ ██╗███╗ ██╗
|
||||
╚══██╔══╝██╔══██╗██╔══██╗██║ ██║████╗ ██║
|
||||
██║ ██████╔╝███████║███████║██╔██╗ ██║
|
||||
██║ ██╔══██╗██╔══██║██╔══██║██║╚██╗██║
|
||||
██║ ██║ ██║██║ ██║██║ ██║██║ ╚████║
|
||||
╚═╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚═╝ ╚═╝╚═╝ ╚═══╝`}</pre>
|
||||
<h1 className="logo">TRAHN</h1>
|
||||
|
||||
{submitted ? (
|
||||
<>
|
||||
|
||||
Reference in New Issue
Block a user