Remove animated background (grid / orbs)
This commit is contained in:
+46
-257
@@ -20,13 +20,11 @@
|
||||
--text-muted:#6e7681;
|
||||
--border:#30363d;
|
||||
}
|
||||
|
||||
*{
|
||||
margin:0;
|
||||
padding:0;
|
||||
box-sizing:border-box;
|
||||
}
|
||||
|
||||
body{
|
||||
font-family:'Outfit',sans-serif;
|
||||
background:var(--bg-primary);
|
||||
@@ -34,62 +32,6 @@
|
||||
min-height:100vh;
|
||||
overflow-x:hidden;
|
||||
}
|
||||
|
||||
/* Animated background grid */
|
||||
.bg-grid {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-image:
|
||||
linear-gradient(var(--border) 1px, transparent 1px),
|
||||
linear-gradient(90deg, var(--border) 1px, transparent 1px);
|
||||
background-size: 50px 50px;
|
||||
opacity: 0.3;
|
||||
animation: gridMove 20s linear infinite;
|
||||
pointer-events: none;
|
||||
z-index: 0;
|
||||
}
|
||||
|
||||
@keyframes gridMove {
|
||||
0% { transform: translate(0, 0); }
|
||||
100% { transform: translate(50px, 50px); }
|
||||
}
|
||||
|
||||
/* Gradient orb effects */
|
||||
.orb {
|
||||
position: fixed;
|
||||
border-radius: 50%;
|
||||
filter: blur(80px);
|
||||
opacity: 0.15;
|
||||
pointer-events: none;
|
||||
z-index: 0;
|
||||
}
|
||||
|
||||
.orb-1 {
|
||||
width: 300px;
|
||||
height: 300px;
|
||||
background: var(--accent-green);
|
||||
top: -100px;
|
||||
right: -100px;
|
||||
animation: float 15s ease-in-out infinite;
|
||||
}
|
||||
|
||||
.orb-2 {
|
||||
width: 400px;
|
||||
height: 400px;
|
||||
background: var(--accent-blue);
|
||||
bottom: -150px;
|
||||
left: -150px;
|
||||
animation: float 20s ease-in-out infinite reverse;
|
||||
}
|
||||
|
||||
@keyframes float {
|
||||
0%, 100% { transform: translate(0, 0) scale(1); }
|
||||
50% { transform: translate(30px, -30px) scale(1.1); }
|
||||
}
|
||||
|
||||
.container{
|
||||
position:relative;
|
||||
z-index:1;
|
||||
@@ -97,32 +39,26 @@
|
||||
margin:0 auto;
|
||||
padding:20px;
|
||||
}
|
||||
|
||||
/* Header */
|
||||
header{
|
||||
text-align:center;
|
||||
padding:40px 0 30px;
|
||||
animation: slideDown 0.6s ease-out;
|
||||
animation:slideDown .6s ease-out;
|
||||
}
|
||||
|
||||
@keyframes slideDown{
|
||||
from{opacity:0;transform:translateY(-20px);}
|
||||
to{opacity:1;transform:translateY(0);}
|
||||
}
|
||||
|
||||
.logo-container{
|
||||
display:flex;
|
||||
flex-direction:column;
|
||||
align-items:center;
|
||||
gap:16px;
|
||||
}
|
||||
|
||||
.logo-image{
|
||||
width:clamp(180px,30vw,200px);
|
||||
height:auto;
|
||||
filter: drop-shadow(0 4px 12px rgba(0, 255, 136, 0.3));
|
||||
filter:drop-shadow(0 4px 12px rgba(0,255,136,.3));
|
||||
}
|
||||
|
||||
.logo{
|
||||
font-family:'JetBrains Mono',monospace;
|
||||
font-size:clamp(28px,6vw,42px);
|
||||
@@ -133,14 +69,11 @@
|
||||
background-clip:text;
|
||||
letter-spacing:-1px;
|
||||
}
|
||||
|
||||
.tagline{
|
||||
font-size:clamp(14px,3vw,16px);
|
||||
color:var(--text-secondary);
|
||||
font-weight:300;
|
||||
}
|
||||
|
||||
/* Login Card */
|
||||
.login-card{
|
||||
background:var(--bg-card);
|
||||
border:1px solid var(--border);
|
||||
@@ -148,37 +81,30 @@
|
||||
padding:clamp(24px,5vw,40px);
|
||||
margin:20px auto;
|
||||
max-width:500px;
|
||||
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4);
|
||||
animation: fadeInUp 0.6s ease-out 0.2s backwards;
|
||||
box-shadow:0 8px 32px rgba(0,0,0,.4);
|
||||
animation:fadeInUp .6s ease-out .2s backwards;
|
||||
}
|
||||
|
||||
@keyframes fadeInUp{
|
||||
from{opacity:0;transform:translateY(20px);}
|
||||
to{opacity:1;transform:translateY(0);}
|
||||
}
|
||||
|
||||
/* Trading Mode Toggle */
|
||||
.trading-mode-group{
|
||||
margin-bottom:24px;
|
||||
}
|
||||
|
||||
.mode-options{
|
||||
display:grid;
|
||||
grid-template-columns:1fr 1fr;
|
||||
gap:12px;
|
||||
}
|
||||
|
||||
.mode-option{
|
||||
position:relative;
|
||||
}
|
||||
|
||||
.mode-option input[type="radio"]{
|
||||
position:absolute;
|
||||
opacity:0;
|
||||
width:0;
|
||||
height:0;
|
||||
}
|
||||
|
||||
.mode-option-label{
|
||||
display:flex;
|
||||
flex-direction:column;
|
||||
@@ -189,19 +115,16 @@
|
||||
border:2px solid var(--border);
|
||||
border-radius:8px;
|
||||
cursor:pointer;
|
||||
transition: all 0.3s ease;
|
||||
transition:all .3s ease;
|
||||
}
|
||||
|
||||
.mode-option input[type="radio"]:checked+.mode-option-label{
|
||||
background: rgba(0, 255, 136, 0.1);
|
||||
background:rgba(0,255,136,.1);
|
||||
border-color:var(--accent-green);
|
||||
box-shadow: 0 0 0 3px rgba(0, 255, 136, 0.1);
|
||||
box-shadow:0 0 0 3px rgba(0,255,136,.1);
|
||||
}
|
||||
|
||||
.mode-option-label:hover{
|
||||
border-color:var(--accent-green);
|
||||
}
|
||||
|
||||
.mode-title{
|
||||
font-family:'JetBrains Mono',monospace;
|
||||
font-size:14px;
|
||||
@@ -209,17 +132,14 @@
|
||||
color:var(--text-primary);
|
||||
margin-bottom:4px;
|
||||
}
|
||||
|
||||
.mode-description{
|
||||
font-size:11px;
|
||||
color:var(--text-muted);
|
||||
text-align:center;
|
||||
}
|
||||
|
||||
.input-group{
|
||||
margin-bottom:20px;
|
||||
}
|
||||
|
||||
label{
|
||||
display:block;
|
||||
font-size:13px;
|
||||
@@ -227,11 +147,9 @@
|
||||
color:var(--text-secondary);
|
||||
margin-bottom:8px;
|
||||
text-transform:uppercase;
|
||||
letter-spacing: 0.5px;
|
||||
letter-spacing:.5px;
|
||||
}
|
||||
|
||||
input[type="password"],
|
||||
input[type="text"] {
|
||||
input[type="password"],input[type="text"]{
|
||||
width:100%;
|
||||
padding:14px 16px;
|
||||
background:var(--bg-secondary);
|
||||
@@ -240,22 +158,17 @@
|
||||
color:var(--text-primary);
|
||||
font-family:'JetBrains Mono',monospace;
|
||||
font-size:14px;
|
||||
transition: all 0.3s ease;
|
||||
transition:all .3s ease;
|
||||
}
|
||||
|
||||
input[type="password"]:focus,
|
||||
input[type="text"]:focus {
|
||||
input[type="password"]:focus,input[type="text"]:focus{
|
||||
outline:none;
|
||||
border-color:var(--accent-green);
|
||||
box-shadow: 0 0 0 3px rgba(0, 255, 136, 0.1);
|
||||
box-shadow:0 0 0 3px rgba(0,255,136,.1);
|
||||
}
|
||||
|
||||
/* Make text input look like password field */
|
||||
input[type="text"]#apiKey{
|
||||
-webkit-text-security:disc;
|
||||
text-security:disc;
|
||||
}
|
||||
|
||||
.btn-go{
|
||||
width:100%;
|
||||
padding:16px;
|
||||
@@ -269,48 +182,39 @@
|
||||
cursor:pointer;
|
||||
text-transform:uppercase;
|
||||
letter-spacing:1px;
|
||||
transition: all 0.3s ease;
|
||||
box-shadow: 0 4px 16px rgba(0, 255, 136, 0.3);
|
||||
transition:all .3s ease;
|
||||
box-shadow:0 4px 16px rgba(0,255,136,.3);
|
||||
}
|
||||
|
||||
.btn-go:hover{
|
||||
transform:translateY(-2px);
|
||||
box-shadow: 0 6px 24px rgba(0, 255, 136, 0.4);
|
||||
box-shadow:0 6px 24px rgba(0,255,136,.4);
|
||||
}
|
||||
|
||||
.btn-go:active{
|
||||
transform:translateY(0);
|
||||
}
|
||||
|
||||
.btn-go:disabled{
|
||||
opacity: 0.5;
|
||||
opacity:.5;
|
||||
cursor:not-allowed;
|
||||
}
|
||||
|
||||
.api-key-info{
|
||||
text-align:center;
|
||||
margin-top:12px;
|
||||
font-size:11px;
|
||||
color:var(--text-muted);
|
||||
}
|
||||
|
||||
.api-key-info a{
|
||||
color:var(--accent-green);
|
||||
text-decoration:none;
|
||||
transition: color 0.3s ease;
|
||||
transition:color .3s ease;
|
||||
}
|
||||
|
||||
.api-key-info a:hover{
|
||||
color:var(--accent-blue);
|
||||
text-decoration:underline;
|
||||
}
|
||||
|
||||
/* Dashboard */
|
||||
#dashboard{
|
||||
display:none;
|
||||
animation: fadeInUp 0.6s ease-out;
|
||||
animation:fadeInUp .6s ease-out;
|
||||
}
|
||||
|
||||
.dashboard-header{
|
||||
display:flex;
|
||||
justify-content:space-between;
|
||||
@@ -319,49 +223,42 @@
|
||||
flex-wrap:wrap;
|
||||
gap:12px;
|
||||
}
|
||||
|
||||
.account-info{
|
||||
display:flex;
|
||||
align-items:center;
|
||||
gap:12px;
|
||||
}
|
||||
|
||||
.status-badge{
|
||||
padding:6px 12px;
|
||||
border-radius:20px;
|
||||
font-size:12px;
|
||||
font-weight:600;
|
||||
text-transform:uppercase;
|
||||
letter-spacing: 0.5px;
|
||||
letter-spacing:.5px;
|
||||
}
|
||||
|
||||
.status-active{
|
||||
background: rgba(0, 255, 136, 0.15);
|
||||
background:rgba(0,255,136,.15);
|
||||
color:var(--accent-green);
|
||||
border:1px solid var(--accent-green);
|
||||
}
|
||||
|
||||
.account-number{
|
||||
font-family:'JetBrains Mono',monospace;
|
||||
color:var(--text-secondary);
|
||||
font-size:14px;
|
||||
cursor:pointer;
|
||||
transition: all 0.3s ease;
|
||||
transition:all .3s ease;
|
||||
user-select:none;
|
||||
position:relative;
|
||||
padding:4px 8px;
|
||||
border-radius:4px;
|
||||
}
|
||||
|
||||
.account-number:hover{
|
||||
color:var(--accent-green);
|
||||
background: rgba(0, 255, 136, 0.1);
|
||||
background:rgba(0,255,136,.1);
|
||||
}
|
||||
|
||||
.account-number:active{
|
||||
transform: scale(0.95);
|
||||
transform:scale(.95);
|
||||
}
|
||||
|
||||
.account-number.copied::after{
|
||||
content:'Copied!';
|
||||
position:absolute;
|
||||
@@ -376,13 +273,11 @@
|
||||
white-space:nowrap;
|
||||
animation:fadeOut 2s ease-out forwards;
|
||||
}
|
||||
|
||||
@keyframes fadeOut{
|
||||
0%{opacity:1;}
|
||||
70%{opacity:1;}
|
||||
100%{opacity:0;}
|
||||
}
|
||||
|
||||
.btn-logout{
|
||||
padding:8px 16px;
|
||||
background:transparent;
|
||||
@@ -391,32 +286,27 @@
|
||||
color:var(--text-secondary);
|
||||
font-size:14px;
|
||||
cursor:pointer;
|
||||
transition: all 0.3s ease;
|
||||
transition:all .3s ease;
|
||||
}
|
||||
|
||||
.btn-logout:hover{
|
||||
border-color:var(--accent-red);
|
||||
color:var(--accent-red);
|
||||
}
|
||||
|
||||
/* Stats Grid */
|
||||
.stats-grid{
|
||||
display:grid;
|
||||
grid-template-columns:repeat(auto-fit,minmax(250px,1fr));
|
||||
gap:16px;
|
||||
margin-bottom:24px;
|
||||
}
|
||||
|
||||
.stat-card{
|
||||
background:var(--bg-card);
|
||||
border:1px solid var(--border);
|
||||
border-radius:12px;
|
||||
padding:20px;
|
||||
transition: all 0.3s ease;
|
||||
transition:all .3s ease;
|
||||
position:relative;
|
||||
overflow:hidden;
|
||||
}
|
||||
|
||||
.stat-card::before{
|
||||
content:'';
|
||||
position:absolute;
|
||||
@@ -427,48 +317,39 @@
|
||||
background:linear-gradient(90deg,var(--accent-green),var(--accent-blue));
|
||||
transform:scaleX(0);
|
||||
transform-origin:left;
|
||||
transition: transform 0.3s ease;
|
||||
transition:transform .3s ease;
|
||||
}
|
||||
|
||||
.stat-card:hover::before{
|
||||
transform:scaleX(1);
|
||||
}
|
||||
|
||||
.stat-card:hover{
|
||||
transform:translateY(-4px);
|
||||
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.3);
|
||||
box-shadow:0 8px 24px rgba(0,0,0,.3);
|
||||
}
|
||||
|
||||
.stat-label{
|
||||
font-size:12px;
|
||||
color:var(--text-muted);
|
||||
text-transform:uppercase;
|
||||
letter-spacing: 0.5px;
|
||||
letter-spacing:.5px;
|
||||
margin-bottom:8px;
|
||||
}
|
||||
|
||||
.stat-value{
|
||||
font-family:'JetBrains Mono',monospace;
|
||||
font-size:clamp(20px,4vw,28px);
|
||||
font-weight:700;
|
||||
color:var(--text-primary);
|
||||
}
|
||||
|
||||
.stat-value.positive{
|
||||
color:var(--accent-green);
|
||||
}
|
||||
|
||||
.stat-value.negative{
|
||||
color:var(--accent-red);
|
||||
}
|
||||
|
||||
.stat-change{
|
||||
font-size:13px;
|
||||
margin-top:4px;
|
||||
font-weight:600;
|
||||
}
|
||||
|
||||
/* Positions Table */
|
||||
.section-title{
|
||||
font-size:18px;
|
||||
font-weight:700;
|
||||
@@ -477,7 +358,6 @@
|
||||
align-items:center;
|
||||
gap:8px;
|
||||
}
|
||||
|
||||
.section-title::before{
|
||||
content:'';
|
||||
width:4px;
|
||||
@@ -485,7 +365,6 @@
|
||||
background:var(--accent-green);
|
||||
border-radius:2px;
|
||||
}
|
||||
|
||||
.positions-container{
|
||||
background:var(--bg-card);
|
||||
border:1px solid var(--border);
|
||||
@@ -493,20 +372,16 @@
|
||||
overflow:hidden;
|
||||
margin-bottom:24px;
|
||||
}
|
||||
|
||||
.positions-scroll{
|
||||
overflow-x:auto;
|
||||
}
|
||||
|
||||
table{
|
||||
width:100%;
|
||||
border-collapse:collapse;
|
||||
}
|
||||
|
||||
thead{
|
||||
background:var(--bg-secondary);
|
||||
}
|
||||
|
||||
th{
|
||||
padding:16px;
|
||||
text-align:left;
|
||||
@@ -514,34 +389,28 @@
|
||||
font-weight:600;
|
||||
color:var(--text-secondary);
|
||||
text-transform:uppercase;
|
||||
letter-spacing: 0.5px;
|
||||
letter-spacing:.5px;
|
||||
white-space:nowrap;
|
||||
}
|
||||
|
||||
td{
|
||||
padding:16px;
|
||||
border-top:1px solid var(--border);
|
||||
font-size:14px;
|
||||
white-space:nowrap;
|
||||
}
|
||||
|
||||
.symbol{
|
||||
font-family:'JetBrains Mono',monospace;
|
||||
font-weight:700;
|
||||
color:var(--text-primary);
|
||||
}
|
||||
|
||||
.mono{
|
||||
font-family:'JetBrains Mono',monospace;
|
||||
}
|
||||
|
||||
/* Loading */
|
||||
.loading{
|
||||
text-align:center;
|
||||
padding:40px;
|
||||
color:var(--text-secondary);
|
||||
}
|
||||
|
||||
.spinner{
|
||||
border:3px solid var(--border);
|
||||
border-top:3px solid var(--accent-green);
|
||||
@@ -551,15 +420,12 @@
|
||||
animation:spin 1s linear infinite;
|
||||
margin:0 auto 16px;
|
||||
}
|
||||
|
||||
@keyframes spin{
|
||||
0%{transform:rotate(0deg);}
|
||||
100%{transform:rotate(360deg);}
|
||||
}
|
||||
|
||||
/* Error */
|
||||
.error{
|
||||
background: rgba(255, 68, 102, 0.1);
|
||||
background:rgba(255,68,102,.1);
|
||||
border:1px solid var(--accent-red);
|
||||
color:var(--accent-red);
|
||||
padding:16px;
|
||||
@@ -567,60 +433,45 @@
|
||||
margin-top:16px;
|
||||
font-size:14px;
|
||||
}
|
||||
|
||||
.empty-state{
|
||||
text-align:center;
|
||||
padding:60px 20px;
|
||||
color:var(--text-muted);
|
||||
}
|
||||
|
||||
.empty-state-icon{
|
||||
font-size:48px;
|
||||
margin-bottom:16px;
|
||||
opacity: 0.5;
|
||||
opacity:.5;
|
||||
}
|
||||
|
||||
/* Responsive */
|
||||
@media (max-width:768px){
|
||||
.container{
|
||||
padding:12px;
|
||||
}
|
||||
|
||||
header{
|
||||
padding:20px 0 20px;
|
||||
}
|
||||
|
||||
.stats-grid{
|
||||
grid-template-columns:1fr;
|
||||
}
|
||||
|
||||
th,td{
|
||||
padding:12px 8px;
|
||||
font-size:12px;
|
||||
}
|
||||
|
||||
.dashboard-header{
|
||||
flex-direction:column;
|
||||
align-items:flex-start;
|
||||
}
|
||||
}
|
||||
|
||||
/* Refresh animation */
|
||||
@keyframes pulse{
|
||||
0%,100%{opacity:1;}
|
||||
50% { opacity: 0.5; }
|
||||
50%{opacity:.5;}
|
||||
}
|
||||
|
||||
.refreshing{
|
||||
animation:pulse 1.5s ease-in-out infinite;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="bg-grid"></div>
|
||||
<div class="orb orb-1"></div>
|
||||
<div class="orb orb-2"></div>
|
||||
|
||||
<div class="container">
|
||||
<header>
|
||||
<div class="logo-container">
|
||||
@@ -630,11 +481,9 @@
|
||||
<div class="tagline">Real-time portfolio monitoring</div>
|
||||
</header>
|
||||
|
||||
<!-- Login Form -->
|
||||
<div id="loginForm">
|
||||
<div class="login-card">
|
||||
<form id="loginFormElement" onsubmit="login(event)">
|
||||
<!-- Trading Mode Selection -->
|
||||
<div class="trading-mode-group">
|
||||
<div class="mode-options">
|
||||
<div class="mode-option">
|
||||
@@ -654,26 +503,13 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- API Credentials -->
|
||||
<div class="input-group">
|
||||
<label for="apiKey">API Key</label>
|
||||
<input
|
||||
type="text"
|
||||
id="apiKey"
|
||||
name="username"
|
||||
placeholder="PK••••••••••••••••"
|
||||
autocomplete="username"
|
||||
>
|
||||
<input type="text" id="apiKey" name="username" placeholder="PK••••••••••••••••" autocomplete="username">
|
||||
</div>
|
||||
<div class="input-group">
|
||||
<label for="apiSecret">API Secret</label>
|
||||
<input
|
||||
type="password"
|
||||
id="apiSecret"
|
||||
name="password"
|
||||
placeholder="••••••••••••••••"
|
||||
autocomplete="current-password"
|
||||
>
|
||||
<input type="password" id="apiSecret" name="password" placeholder="••••••••••••••••" autocomplete="current-password">
|
||||
</div>
|
||||
<button type="submit" class="btn-go">GO!</button>
|
||||
<div class="api-key-info">
|
||||
@@ -684,23 +520,16 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Dashboard -->
|
||||
<div id="dashboard">
|
||||
<div class="dashboard-header">
|
||||
<div class="account-info">
|
||||
<span class="status-badge status-active">● LIVE</span>
|
||||
<span id="accountNumber" class="account-number"
|
||||
onmouseenter="revealAccountNumber()"
|
||||
onmouseleave="hideAccountNumber()"
|
||||
onclick="copyAccountNumber(event)"
|
||||
oncontextmenu="copyAccountNumber(event)">#PA••••••••</span>
|
||||
<span id="accountNumber" class="account-number" onmouseenter="revealAccountNumber()" onmouseleave="hideAccountNumber()" onclick="copyAccountNumber(event)" oncontextmenu="copyAccountNumber(event)">#PA••••••••</span>
|
||||
</div>
|
||||
<button class="btn-logout" onclick="logout()">Logout</button>
|
||||
</div>
|
||||
|
||||
<div class="stats-grid" id="statsGrid">
|
||||
<!-- Stats will be inserted here -->
|
||||
</div>
|
||||
<div class="stats-grid" id="statsGrid"></div>
|
||||
|
||||
<h2 class="section-title">Positions</h2>
|
||||
<div class="positions-container">
|
||||
@@ -713,13 +542,11 @@
|
||||
<th>Avg Cost</th>
|
||||
<th>Current Price</th>
|
||||
<th>Market Value</th>
|
||||
<th>P&L</th>
|
||||
<th>P&L %</th>
|
||||
<th>P&L</th>
|
||||
<th>P&L %</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="positionsBody">
|
||||
<!-- Positions will be inserted here -->
|
||||
</tbody>
|
||||
<tbody id="positionsBody"></tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
@@ -729,14 +556,13 @@
|
||||
<script>
|
||||
let API_KEY = '';
|
||||
let API_SECRET = '';
|
||||
let BASE_URL = 'https://paper-api.alpaca.markets'; // Default to paper trading
|
||||
let BASE_URL = 'https://paper-api.alpaca.markets';
|
||||
let ACCOUNT_NUMBER = '';
|
||||
let hideTimeout = null;
|
||||
let isRevealed = false;
|
||||
|
||||
async function login(event) {
|
||||
event.preventDefault(); // Prevent form submission
|
||||
|
||||
event.preventDefault();
|
||||
const apiKey = document.getElementById('apiKey').value.trim();
|
||||
const apiSecret = document.getElementById('apiSecret').value.trim();
|
||||
const errorDiv = document.getElementById('loginError');
|
||||
@@ -749,8 +575,6 @@
|
||||
|
||||
API_KEY = apiKey;
|
||||
API_SECRET = apiSecret;
|
||||
|
||||
// Set BASE_URL based on selected trading mode
|
||||
BASE_URL = tradingMode === 'paper'
|
||||
? 'https://paper-api.alpaca.markets'
|
||||
: 'https://api.alpaca.markets';
|
||||
@@ -767,7 +591,6 @@
|
||||
document.getElementById('loginForm').style.display = 'none';
|
||||
document.getElementById('dashboard').style.display = 'block';
|
||||
await loadDashboard();
|
||||
// Auto-refresh every 30 seconds
|
||||
setInterval(loadDashboard, 30000);
|
||||
return;
|
||||
}
|
||||
@@ -809,7 +632,6 @@
|
||||
|
||||
function displayAccount(account) {
|
||||
ACCOUNT_NUMBER = account.account_number;
|
||||
// Set initial display with first 3 characters visible
|
||||
updateAccountDisplay();
|
||||
|
||||
const equity = parseFloat(account.equity);
|
||||
@@ -819,27 +641,10 @@
|
||||
const plTodayPercent = (plToday / parseFloat(account.last_equity)) * 100;
|
||||
|
||||
const stats = [
|
||||
{
|
||||
label: 'Portfolio Value',
|
||||
value: formatCurrency(equity),
|
||||
class: ''
|
||||
},
|
||||
{
|
||||
label: 'Cash',
|
||||
value: formatCurrency(cash),
|
||||
class: ''
|
||||
},
|
||||
{
|
||||
label: 'Buying Power',
|
||||
value: formatCurrency(buyingPower),
|
||||
class: ''
|
||||
},
|
||||
{
|
||||
label: 'Today\'s P&L',
|
||||
value: formatCurrency(plToday),
|
||||
change: `${plTodayPercent >= 0 ? '+' : ''}${plTodayPercent.toFixed(2)}%`,
|
||||
class: plToday >= 0 ? 'positive' : 'negative'
|
||||
}
|
||||
{ label: 'Portfolio Value', value: formatCurrency(equity), class: '' },
|
||||
{ label: 'Cash', value: formatCurrency(cash), class: '' },
|
||||
{ label: 'Buying Power', value: formatCurrency(buyingPower), class: '' },
|
||||
{ label: "Today's P&L", value: formatCurrency(plToday), change: `${plToday >= 0 ? '+' : ''}${plTodayPercent.toFixed(2)}%`, class: plToday >= 0 ? 'positive' : 'negative' }
|
||||
];
|
||||
|
||||
const statsGrid = document.getElementById('statsGrid');
|
||||
@@ -853,8 +658,7 @@
|
||||
}
|
||||
|
||||
function getPartialAccountNumber() {
|
||||
// Show first 3 characters after # and mask the rest
|
||||
const prefix = ACCOUNT_NUMBER.substring(0, 2); // PA or similar
|
||||
const prefix = ACCOUNT_NUMBER.substring(0, 2);
|
||||
const dots = '•'.repeat(ACCOUNT_NUMBER.length - 2);
|
||||
return `#${prefix}${dots}`;
|
||||
}
|
||||
@@ -869,18 +673,15 @@
|
||||
}
|
||||
|
||||
function revealAccountNumber() {
|
||||
// Clear any pending hide timeout
|
||||
if (hideTimeout) {
|
||||
clearTimeout(hideTimeout);
|
||||
hideTimeout = null;
|
||||
}
|
||||
|
||||
isRevealed = true;
|
||||
updateAccountDisplay();
|
||||
}
|
||||
|
||||
function hideAccountNumber() {
|
||||
// Only hide if not clicked (click sets a 5 second timer)
|
||||
if (!hideTimeout) {
|
||||
isRevealed = false;
|
||||
updateAccountDisplay();
|
||||
@@ -890,30 +691,19 @@
|
||||
function copyAccountNumber(event) {
|
||||
event.preventDefault();
|
||||
const accountElement = document.getElementById('accountNumber');
|
||||
|
||||
// Reveal the account number
|
||||
isRevealed = true;
|
||||
updateAccountDisplay();
|
||||
|
||||
// Clear any existing timeout
|
||||
if (hideTimeout) {
|
||||
clearTimeout(hideTimeout);
|
||||
}
|
||||
|
||||
// Copy to clipboard
|
||||
navigator.clipboard.writeText(`#${ACCOUNT_NUMBER}`).then(() => {
|
||||
// Add copied class for visual feedback
|
||||
accountElement.classList.add('copied');
|
||||
|
||||
// Remove the copied class after animation completes
|
||||
setTimeout(() => {
|
||||
accountElement.classList.remove('copied');
|
||||
}, 2000);
|
||||
}).catch(err => {
|
||||
console.error('Failed to copy:', err);
|
||||
});
|
||||
|
||||
// Set a timeout to hide after 5 seconds
|
||||
hideTimeout = setTimeout(() => {
|
||||
isRevealed = false;
|
||||
updateAccountDisplay();
|
||||
@@ -942,7 +732,6 @@
|
||||
const pl = parseFloat(pos.unrealized_pl);
|
||||
const plPercent = parseFloat(pos.unrealized_plpc) * 100;
|
||||
const plClass = pl >= 0 ? 'positive' : 'negative';
|
||||
|
||||
return `
|
||||
<tr>
|
||||
<td class="symbol">${pos.symbol}</td>
|
||||
|
||||
Reference in New Issue
Block a user