@php use App\Support\SymbolPresentation; @endphp @extends('portal.layouts.master') @section('title', 'Portfolio') @section('page-title', 'Portfolio') @section('extra-css') /* ── Stat cards ── */ .pf-cards { display: grid; grid-template-columns: repeat(4, 1fr); gap: .75rem; margin-bottom: 1.1rem; } @media (max-width: 1100px) { .pf-cards { grid-template-columns: repeat(2, 1fr); } } @media (max-width: 600px) { .pf-cards { grid-template-columns: 1fr; } } .pf-card { background: var(--bg-card); border: 1px solid var(--border); border-radius: 10px; padding: 1rem 1.1rem .65rem; display: flex; flex-direction: column; min-height: 120px; position: relative; overflow: hidden; } .pf-card::before { content: ''; position: absolute; inset: 0; background: var(--pc-grad, transparent); opacity: .18; pointer-events: none; border-radius: 10px; } .pf-card--blue { --pc-grad: linear-gradient(135deg,#3b82f6,transparent 65%); } .pf-card--teal { --pc-grad: linear-gradient(135deg,#0d9488,transparent 65%); } .pf-card--green { --pc-grad: linear-gradient(135deg,#0ecb81,transparent 65%); } .pf-card--purple { --pc-grad: linear-gradient(135deg,#8b5cf6,transparent 65%); } .pf-card .pc-label { font-size: .6rem; font-weight: 700; letter-spacing: .07em; text-transform: uppercase; color: var(--text-secondary); margin-bottom: .3rem; } .pf-card .pc-value { font-size: 1.75rem; font-weight: 800; line-height: 1; letter-spacing: -.02em; color: var(--text-primary); margin-bottom: .1rem; } .pf-card--green .pc-value { color: #0ecb81; } .pf-card--purple .pc-value { color: #a78bfa; } .pf-card .pc-sub { font-size: .68rem; color: var(--text-muted); margin-bottom: auto; } .pf-card .pc-sub.profit { color: #0ecb81; } .pf-card .pc-sub.loss { color: #f6465d; } /* mini charts */ .pc-chart { margin-top: .6rem; height: 42px; overflow: hidden; } .pc-chart svg { width: 100%; height: 100%; display: block; } /* donut gauge */ .pc-gauge { display: flex; align-items: center; justify-content: center; flex: 1; padding: .2rem 0; } .pc-gauge svg { width: 68px; height: 68px; } .pc-gauge-track { fill: none; stroke: rgba(139,92,246,.2); stroke-width: 7; } .pc-gauge-fill { fill: none; stroke: #8b5cf6; stroke-width: 7; stroke-linecap: round; transform: rotate(-90deg); transform-origin: 50% 50%; } .pc-gauge-num { font-size: 1.1rem; font-weight: 800; fill: #a78bfa; } /* table */ .symbol-cell { display: flex; align-items: center; gap: .6rem; } .symbol-icon { width: 36px; height: 36px; border-radius: 50%; background: var(--bg-tertiary); display: flex; align-items: center; justify-content: center; font-size: .85rem; color: var(--text-secondary); font-weight: 600; flex-shrink: 0; overflow: hidden; } .symbol-icon img { width: 20px; height: 20px; object-fit: contain; border-radius: 50%; } .cat-badge { font-size: .62rem; font-weight: 600; padding: .18rem .5rem; border-radius: 4px; text-transform: uppercase; letter-spacing: .03em; } .cat-crypto { background: rgba(245,158,11,.15); color: #f59e0b; } .cat-forex { background: rgba(14,203,129,.15); color: #0ecb81; } .cat-stocks { background: rgba(59,130,246,.15); color: #3b82f6; } .cat-commodities { background: rgba(168,85,247,.15); color: #a855f7; } @endsection @section('content') @php $posCount = $positions->count(); $pnlSign = $totalPnl >= 0 ? '+' : ''; $pnlColor = $totalPnl >= 0 ? '#0ecb81' : '#f6465d'; /* gauge — fill circumference based on capped position count (max visual 10) */ $gaugeR = 24; $gaugeCircum = 2 * M_PI * $gaugeR; $gaugeFill = $posCount > 0 ? min(1, $posCount / max(1, $posCount)) : 0; // always full when >0 $gaugeDash = $gaugeCircum * 0.75; // fixed 75% arc to look nice when count >=1 if ($posCount === 0) { $gaugeDash = 0; } @endphp
{{-- 1. Total Invested --}}
Total Invested
${{ number_format($totalInvested, 2) }}
Cost basis
{{-- Dotted sparkline --}} @php $dotPts = [38,35,34,36,33,30,28,31,26,24,22,25,20,18,16,19,14,12,10,8]; @endphp @foreach($dotPts as $di => $dv) @endforeach
{{-- 2. Current Value --}}
Current Value
${{ number_format($totalValue, 2) }}
At market prices
{{-- 3. Total P&L --}}
Total P&L
{{ $pnlSign }}${{ number_format(abs($totalPnl), 2) }}
{{ $totalPnlPct >= 0 ? '+' : '' }}{{ number_format($totalPnlPct, 2) }}%
@php $bars = [10,14,8,18,12,22,16,28,20,32,24,36,28,34,30,38,32,36,34,40]; @endphp @foreach($bars as $bi => $bh) @endforeach
{{-- 4. Open Positions --}}
Open Positions
{{ $posCount }}
Active instruments
{{ $posCount }}
{{-- Positions table --}}
Open Positions
@if($positions->isEmpty())
No open positions yet.
Browse Markets
@else
@foreach($positions as $pos) @php $lp = (float)($pos->symbol?->latestPrice?->price ?? 0); $val = $pos->quantity * $lp; $pnl = ($lp - $pos->avg_price) * $pos->quantity; $pnlPct = $pos->avg_price > 0 ? (($lp - $pos->avg_price) / $pos->avg_price) * 100 : 0; [$icn, $icColor] = SymbolPresentation::baseIconPair($pos->symbol); $icIsImg = str_starts_with($icn, 'img:'); @endphp @endforeach
Instrument Category Quantity Avg Entry Current Price Value P&L ($) P&L (%) Actions
@if($icIsImg) {{ strtoupper(substr($pos->symbol->name??'?',0,2)) }} @elseif($icn) @else {{ strtoupper(substr($pos->symbol->name??'?',0,2)) }} @endif
{{ $pos->symbol->name ?? '-' }}
{{ $pos->symbol->base_currency ?? strtoupper(substr($pos->symbol->name??'',0,3)) }}
{{ ucfirst($pos->symbol->category ?? '-') }} {{ rtrim(rtrim(number_format($pos->quantity, 8), '0'), '.') }} {{ number_format($pos->avg_price, $pos->symbol->decimal_places ?? 2) }} {{ $lp > 0 ? number_format($lp, $pos->symbol->decimal_places ?? 2) : '—' }} {{ $lp > 0 ? '$'.number_format($val, 2) : '—' }} {{ $lp > 0 ? ($pnl >= 0 ? '+' : '').number_format($pnl, 2) : '—' }} {{ $lp > 0 ? ($pnlPct >= 0 ? '+' : '').number_format($pnlPct, 2).'%' : '—' }}
@endif
@endsection