@php use App\Support\SymbolPresentation; @endphp @extends('portal.layouts.master') @section('title', 'Markets') @section('page-title', 'Markets') @section('extra-css') .markets-ticker { overflow: hidden; border-top: 1px solid var(--border); border-bottom: 1px solid var(--border); background: var(--bg-secondary); height: 52px; margin: 0 0 1rem; } .markets-ticker-track { display: flex; align-items: stretch; height: 100%; width: max-content; animation: markets-ticker-scroll 45s linear infinite; } .markets-ticker:hover .markets-ticker-track { animation-play-state: paused; } @keyframes markets-ticker-scroll { from { transform: translateX(0); } to { transform: translateX(-50%); } } .ticker-item { display: flex; align-items: center; gap: .55rem; padding: 0 1.15rem; height: 100%; border-right: 1px solid var(--border); white-space: nowrap; text-decoration: none; color: inherit; flex-shrink: 0; } .ticker-item:hover { background: rgba(255,255,255,.03); color: inherit; } .ticker-icon { width: 22px; height: 22px; border-radius: 50%; display: flex; align-items: center; justify-content: center; flex-shrink: 0; font-size: .7rem; overflow: hidden; } .ticker-icon img { width: 16px; height: 16px; object-fit: contain; } .ticker-name { font-weight: 600; font-size: .82rem; color: var(--text-primary); } .ticker-price { font-size: .82rem; color: var(--text-primary); font-variant-numeric: tabular-nums; } .ticker-chg { font-size: .78rem; font-variant-numeric: tabular-nums; } .ticker-chg.up { color: var(--green); } .ticker-chg.down { color: var(--red); } .price-freshness { display:block; margin-top:.15rem; font-size:.66rem; font-weight:500; color:var(--text-muted); } .price-freshness.live { color:var(--green); } .price-freshness.stale { color:#f59e0b; } .market-chart-cell { position:relative; } .market-chart-tooltip { position:absolute; z-index:5; left:50%; bottom:43px; transform:translateX(-50%); min-width:112px; padding:.35rem .5rem; border:1px solid var(--border); border-radius:6px; background:#11151b; color:var(--text-primary); box-shadow:0 5px 15px rgba(0,0,0,.35); font-size:.68rem; line-height:1.35; text-align:center; pointer-events:none; white-space:nowrap; opacity:0; visibility:hidden; transition:opacity .08s; } .market-chart-tooltip.visible { opacity:1; visibility:visible; } .market-chart-tooltip strong { display:block; font-size:.72rem; font-variant-numeric:tabular-nums; } .market-chart-tooltip span { color:var(--text-muted); } .markets-header { display: flex; align-items: center; justify-content: space-between; gap: 1rem; flex-wrap: wrap; margin-bottom: 1.15rem; } .market-tabs { display: flex; gap: .45rem; flex-wrap: wrap; } .market-tab { padding: .42rem 1.1rem; border-radius: 8px; font-size: .84rem; font-weight: 600; cursor: pointer; background: var(--bg-tertiary); color: var(--text-secondary); border: none; transition: background .15s, color .15s; line-height: 1.2; } .market-tab:hover { color: var(--text-primary); background: #353b45; } .market-tab.active { background: var(--accent); color: #fff; } .market-search { background: transparent; border: 1px solid var(--border); border-radius: 8px; padding: .5rem 1rem; font-size: .85rem; color: var(--text-primary); min-width: 240px; } .market-search:focus { border-color: var(--accent); outline: none; box-shadow: 0 0 0 2px rgba(59,130,246,.15); } .market-search::placeholder { color: var(--text-muted); } .market-row { cursor: pointer; transition: background .1s; } .market-row:hover { background: rgba(59,130,246,.04) !important; } .cat-badge { font-size: .65rem; font-weight: 600; padding: .2rem .5rem; border-radius: 4px; text-transform: uppercase; letter-spacing: .03em; } .cat-crypto { background: rgba(245,158,11,.12); color: #f59e0b; } .cat-forex { background: rgba(14,203,129,.12); color: var(--green); } .cat-stocks { background: rgba(59,130,246,.12); color: var(--accent); } .cat-commodities { background: rgba(168,85,247,.12); color: #a855f7; } @media (max-width: 768px) { .market-search { min-width: 100%; width: 100%; } } @endsection @section('content') @php $tickerSymbols = $symbols->take(16); @endphp
@foreach (range(1, $tickerSymbols->count() < 8 ? 4 : 2) as $loopCopy) @foreach ($tickerSymbols as $sym) @php $pair = SymbolPresentation::pairLabel($sym); [$tIcon, $tColor] = SymbolPresentation::baseIconPair($sym); $tIsImg = str_starts_with($tIcon, 'img:'); $tPrice = $sym->latestPrice->price ?? null; $tPct = $sym->latestPrice->change_24h_pct ?? null; if ($tPct === null && count($sym->sparkline ?? []) >= 2) { $first = (float) $sym->sparkline[0]; $last = (float) $sym->sparkline[count($sym->sparkline) - 1]; $tPct = $first != 0.0 ? (($last - $first) / $first) * 100 : null; } $tPct = $tPct !== null ? (float) $tPct : null; $tAbs = ($tPct !== null && $tPrice) ? ((float) $tPrice) * ($tPct / 100) : null; $tUp = $tPct !== null && $tPct >= 0; $tDp = (int) ($sym->decimal_places ?? 2); @endphp @if($tIsImg) {{ strtoupper(substr($pair,0,1)) }} @elseif($tIcon) @else {{ strtoupper(substr($pair,0,2)) }} @endif {{ $pair }} @if($tPrice !== null) {{ number_format((float) $tPrice, $tDp) }} @else — @endif @if($tPct !== null) {{ $tUp ? '+' : '' }}{{ $tAbs !== null ? number_format($tAbs, $tDp) : '' }} ({{ $tUp ? '+' : '' }}{{ number_format($tPct, 2) }}%) @else @endif @endforeach @endforeach
@forelse($symbols as $i => $sym) @empty @endforelse
# Instrument Symbol Category Price Price Chart Action
{{ $i + 1 }}
@php [$mIcon, $mColor] = SymbolPresentation::baseIconPair($sym); $mIsImg = str_starts_with($mIcon, 'img:'); $mImgUrl = $mIsImg ? substr($mIcon, 4) : ''; @endphp
@if($mIsImg) {{ strtoupper(substr($sym->name,0,2)) }} @elseif($mIcon) @else {{ strtoupper(substr($sym->name,0,2)) }} @endif
{{ $sym->name }}
{{ $sym->tv_symbol }} {{ ucfirst($sym->category) }} @if($sym->latestPrice) {{ number_format($sym->latestPrice->price, $sym->decimal_places) }} @php $initialStale = $sym->latestPrice->priced_at?->lt(now()->subMinutes($sym->category === 'crypto' ? 3 : 5)) ?? true; @endphp {{ $initialStale ? 'Delayed' : 'Live' }} @else — Unavailable @endif @php $points = collect($sym->chart_points ?? [])->pluck('price')->all(); $sparkSvg = ''; if (count($points) >= 2) { $min = min($points); $max = max($points); $range = $max - $min ?: 1; $w = 120; $h = 36; $pad = 2; $coords = []; foreach ($points as $idx => $val) { $x = round($pad + ($idx / (count($points) - 1)) * ($w - $pad * 2), 2); $y = round($pad + (1 - ($val - $min) / $range) * ($h - $pad * 2), 2); $coords[] = "$x,$y"; } $polyline = implode(' ', $coords); $isUp = end($points) >= $points[0]; $stroke = $isUp ? '#0ecb81' : '#f6465d'; $fillId = 'sf' . $sym->id; $areaCoords = "$pad,$h " . $polyline . " " . round($w - $pad, 2) . ",$h"; $sparkSvg = '' . '' . '' . '' . '' . '' . '' . ''; } @endphp @if($sparkSvg) {!! $sparkSvg !!} @else — @endif
No instruments available. Contact your account manager.
@endsection @section('page-js') @endsection