This commit is contained in:
MuslemRahimi 2025-03-03 17:16:21 +01:00
parent a9c381f39d
commit 23981d7458

View File

@ -234,32 +234,24 @@
} }
</script> </script>
<div class="table-container"> <div class="w-full overflow-x-auto">
<div class="table"> <!-- Set a min-width on smaller screens so the grid can show all columns -->
<VirtualList <div class="min-w-[1000px]">
width="100%" <!-- Header row using grid -->
height={$screenWidth < 640 <div
? data?.user?.tier === "Pro" class="grid grid-cols-16 sticky top-0 z-40 border border-gray-800 bg-default text-white font-bold text-xs uppercase"
? 550
: 250
: data?.user?.tier === "Pro"
? 850
: 250}
itemCount={displayedData.length}
itemSize={40}
> >
<div slot="header" class="tr th sticky z-40 top-0 border border-gray-800">
<!-- Table headers -->
<div <div
on:click={() => sortData("time")} on:click={() => sortData("time")}
class="td cursor-pointer select-none bg-default text-white font-bold text-xs text-start uppercase" class="cursor-pointer p-2 text-center whitespace-nowrap"
> >
Time Time
<svg <svg
class="shrink-0 w-4 h-4 inline-block {sortOrders['time'] === class="shrink-0 w-4 h-4 -mt-1 {sortOrders['time'] === 'asc'
'asc' ? 'rotate-180 inline-block'
? 'rotate-180' : sortOrders['time'] === 'desc'
: ''} " ? 'inline-block'
: 'hidden'} "
viewBox="0 0 20 20" viewBox="0 0 20 20"
fill="currentColor" fill="currentColor"
style="max-width:50px" style="max-width:50px"
@ -272,15 +264,14 @@
</div> </div>
<div <div
on:click={() => sortData("ticker")} on:click={() => sortData("ticker")}
class="td cursor-pointer select-none bg-default font-bold text-white text-xs text-start uppercase" class="cursor-pointer p-2 text-center select-none"
> >
Symbol Symbol
<svg <svg
class="shrink-0 w-4 h-4 inline-block {sortOrders['ticker'] === class="shrink-0 w-4 h-4 -mt-1 {sortOrders['ticker'] === 'asc'
'asc' ? 'rotate-180 inline-block'
? 'rotate-180'
: sortOrders['ticker'] === 'desc' : sortOrders['ticker'] === 'desc'
? '' ? 'inline-block'
: 'hidden'} " : 'hidden'} "
viewBox="0 0 20 20" viewBox="0 0 20 20"
fill="currentColor" fill="currentColor"
@ -292,22 +283,19 @@
></path></svg ></path></svg
> >
</div> </div>
<div
class="td select-none bg-default text-white font-bold text-xs text-start uppercase" <div class="cursor-pointer p-2 text-center whitespace-nowrap">Save</div>
>
Save
</div>
<div <div
on:click={() => sortData("expiry")} on:click={() => sortData("expiry")}
class="td cursor-pointer select-none bg-default text-white font-bold text-xs text-start uppercase" class="cursor-pointer p-2 text-center whitespace-nowrap"
> >
Expiry Expiry
<svg <svg
class="shrink-0 w-4 h-4 inline-block {sortOrders['expiry'] === class="shrink-0 w-4 h-4 -mt-1 {sortOrders['expiry'] === 'asc'
'asc' ? 'rotate-180 inline-block'
? 'rotate-180'
: sortOrders['expiry'] === 'desc' : sortOrders['expiry'] === 'desc'
? '' ? 'inline-block'
: 'hidden'} " : 'hidden'} "
viewBox="0 0 20 20" viewBox="0 0 20 20"
fill="currentColor" fill="currentColor"
@ -319,17 +307,17 @@
></path></svg ></path></svg
> >
</div> </div>
<div <div
on:click={() => sortData("dte")} on:click={() => sortData("dte")}
class="td cursor-pointer select-none bg-default text-white font-bold text-xs text-start uppercase" class="cursor-pointer p-2 text-center whitespace-nowrap"
> >
DTE dte
<svg <svg
class="shrink-0 w-4 h-4 inline-block {sortOrders['dte'] === class="shrink-0 w-4 h-4 -mt-1 {sortOrders['dte'] === 'asc'
'asc' ? 'rotate-180 inline-block'
? 'rotate-180'
: sortOrders['dte'] === 'desc' : sortOrders['dte'] === 'desc'
? '' ? 'inline-block'
: 'hidden'} " : 'hidden'} "
viewBox="0 0 20 20" viewBox="0 0 20 20"
fill="currentColor" fill="currentColor"
@ -341,17 +329,17 @@
></path></svg ></path></svg
> >
</div> </div>
<div <div
on:click={() => sortData("strike")} on:click={() => sortData("strike")}
class="td cursor-pointer select-none bg-default text-white font-bold text-xs text-start uppercase" class="cursor-pointer p-2 text-center whitespace-nowrap"
> >
Strike strike
<svg <svg
class="shrink-0 w-4 h-4 inline-block {sortOrders['strike'] === class="shrink-0 w-4 h-4 -mt-1 {sortOrders['strike'] === 'asc'
'asc' ? 'rotate-180 inline-block'
? 'rotate-180'
: sortOrders['strike'] === 'desc' : sortOrders['strike'] === 'desc'
? '' ? 'inline-block'
: 'hidden'} " : 'hidden'} "
viewBox="0 0 20 20" viewBox="0 0 20 20"
fill="currentColor" fill="currentColor"
@ -363,17 +351,17 @@
></path></svg ></path></svg
> >
</div> </div>
<div <div
on:click={() => sortData("callPut")} on:click={() => sortData("callPut")}
class="td cursor-pointer select-none bg-default text-white font-bold text-xs text-start uppercase" class="cursor-pointer p-2 text-center whitespace-nowrap"
> >
C/P C/P
<svg <svg
class="shrink-0 w-4 h-4 inline-block {sortOrders['callPut'] === class="shrink-0 w-4 h-4 -mt-1 {sortOrders['callPut'] === 'asc'
'asc' ? 'rotate-180 inline-block'
? 'rotate-180'
: sortOrders['callPut'] === 'desc' : sortOrders['callPut'] === 'desc'
? '' ? 'inline-block'
: 'hidden'} " : 'hidden'} "
viewBox="0 0 20 20" viewBox="0 0 20 20"
fill="currentColor" fill="currentColor"
@ -385,18 +373,17 @@
></path></svg ></path></svg
> >
</div> </div>
<div <div
on:click={() => sortData("sentiment")} on:click={() => sortData("sentiment")}
class="td cursor-pointer select-none bg-default text-white font-bold text-xs text-start uppercase" class="cursor-pointer p-2 text-center whitespace-nowrap"
> >
Sent. Sent.
<svg <svg
class="shrink-0 w-4 h-4 inline-block {sortOrders[ class="shrink-0 w-4 h-4 -mt-1 {sortOrders['sentiment'] === 'asc'
'sentiment' ? 'rotate-180 inline-block'
] === 'asc'
? 'rotate-180'
: sortOrders['sentiment'] === 'desc' : sortOrders['sentiment'] === 'desc'
? '' ? 'inline-block'
: 'hidden'} " : 'hidden'} "
viewBox="0 0 20 20" viewBox="0 0 20 20"
fill="currentColor" fill="currentColor"
@ -408,17 +395,17 @@
></path></svg ></path></svg
> >
</div> </div>
<div <div
on:click={() => sortData("spot")} on:click={() => sortData("spot")}
class="td cursor-pointer select-none bg-default text-white font-bold text-xs text-start uppercase" class="cursor-pointer p-2 text-center whitespace-nowrap"
> >
Spot Spot
<svg <svg
class="shrink-0 w-4 h-4 inline-block {sortOrders['spot'] === class="shrink-0 w-4 h-4 -mt-1 {sortOrders['spot'] === 'asc'
'asc' ? 'rotate-180 inline-block'
? 'rotate-180'
: sortOrders['spot'] === 'desc' : sortOrders['spot'] === 'desc'
? '' ? 'inline-block'
: 'hidden'} " : 'hidden'} "
viewBox="0 0 20 20" viewBox="0 0 20 20"
fill="currentColor" fill="currentColor"
@ -430,17 +417,17 @@
></path></svg ></path></svg
> >
</div> </div>
<div <div
on:click={() => sortData("price")} on:click={() => sortData("price")}
class="td cursor-pointer select-none bg-default text-white font-bold text-xs text-start uppercase" class="cursor-pointer p-2 text-center select-none"
> >
Price Price
<svg <svg
class="shrink-0 w-4 h-4 inline-block {sortOrders['price'] === class="shrink-0 w-4 h-4 -mt-1 {sortOrders['price'] === 'asc'
'asc' ? 'rotate-180 inline-block'
? 'rotate-180'
: sortOrders['price'] === 'desc' : sortOrders['price'] === 'desc'
? '' ? 'inline-block'
: 'hidden'} " : 'hidden'} "
viewBox="0 0 20 20" viewBox="0 0 20 20"
fill="currentColor" fill="currentColor"
@ -454,15 +441,14 @@
</div> </div>
<div <div
on:click={() => sortData("premium")} on:click={() => sortData("premium")}
class="td cursor-pointer select-none bg-default text-white font-bold text-xs text-start uppercase" class="cursor-pointer p-2 text-center select-none"
> >
Prem Premium
<svg <svg
class="shrink-0 w-4 h-4 inline-block {sortOrders['premium'] === class="shrink-0 w-4 h-4 -mt-1 {sortOrders['premium'] === 'asc'
'asc' ? 'rotate-180 inline-block'
? 'rotate-180'
: sortOrders['premium'] === 'desc' : sortOrders['premium'] === 'desc'
? '' ? 'inline-block'
: 'hidden'} " : 'hidden'} "
viewBox="0 0 20 20" viewBox="0 0 20 20"
fill="currentColor" fill="currentColor"
@ -474,17 +460,17 @@
></path></svg ></path></svg
> >
</div> </div>
<div <div
on:click={() => sortData("type")} on:click={() => sortData("type")}
class="td cursor-pointer select-none bg-default text-white font-bold text-xs text-start uppercase" class="cursor-pointer p-2 text-center whitespace-nowrap"
> >
Type Type
<svg <svg
class="shrink-0 w-4 h-4 inline-block {sortOrders['type'] === class="shrink-0 w-4 h-4 -mt-1 {sortOrders['type'] === 'asc'
'asc' ? 'rotate-180 inline-block'
? 'rotate-180'
: sortOrders['type'] === 'desc' : sortOrders['type'] === 'desc'
? '' ? 'inline-block'
: 'hidden'} " : 'hidden'} "
viewBox="0 0 20 20" viewBox="0 0 20 20"
fill="currentColor" fill="currentColor"
@ -496,17 +482,17 @@
></path></svg ></path></svg
> >
</div> </div>
<div <div
on:click={() => sortData("exec")} on:click={() => sortData("exec")}
class="td cursor-pointer select-none bg-default text-white font-bold text-xs text-start uppercase" class="cursor-pointer p-2 text-center whitespace-nowrap"
> >
Exec Exec.
<svg <svg
class="shrink-0 w-4 h-4 inline-block {sortOrders['exec'] === class="shrink-0 w-4 h-4 -mt-1 {sortOrders['exec'] === 'asc'
'asc' ? 'rotate-180 inline-block'
? 'rotate-180'
: sortOrders['exec'] === 'desc' : sortOrders['exec'] === 'desc'
? '' ? 'inline-block'
: 'hidden'} " : 'hidden'} "
viewBox="0 0 20 20" viewBox="0 0 20 20"
fill="currentColor" fill="currentColor"
@ -518,17 +504,17 @@
></path></svg ></path></svg
> >
</div> </div>
<div <div
on:click={() => sortData("size")} on:click={() => sortData("size")}
class="td cursor-pointer select-none bg-default text-white font-bold text-xs text-start uppercase" class="cursor-pointer p-2 text-center select-none"
> >
Size Size
<svg <svg
class="shrink-0 w-4 h-4 inline-block {sortOrders['size'] === class="shrink-0 w-4 h-4 -mt-1 {sortOrders['size'] === 'asc'
'asc' ? 'rotate-180 inline-block'
? 'rotate-180'
: sortOrders['size'] === 'desc' : sortOrders['size'] === 'desc'
? '' ? 'inline-block'
: 'hidden'} " : 'hidden'} "
viewBox="0 0 20 20" viewBox="0 0 20 20"
fill="currentColor" fill="currentColor"
@ -542,15 +528,14 @@
</div> </div>
<div <div
on:click={() => sortData("vol")} on:click={() => sortData("vol")}
class="td cursor-pointer select-none bg-default text-white font-bold text-xs text-start uppercase" class="cursor-pointer p-2 text-center select-none"
> >
Vol Vol
<svg <svg
class="shrink-0 w-4 h-4 inline-block {sortOrders['vol'] === class="shrink-0 w-4 h-4 -mt-1 {sortOrders['vol'] === 'asc'
'asc' ? 'rotate-180 inline-block'
? 'rotate-180'
: sortOrders['vol'] === 'desc' : sortOrders['vol'] === 'desc'
? '' ? 'inline-block'
: 'hidden'} " : 'hidden'} "
viewBox="0 0 20 20" viewBox="0 0 20 20"
fill="currentColor" fill="currentColor"
@ -562,17 +547,17 @@
></path></svg ></path></svg
> >
</div> </div>
<div <div
on:click={() => sortData("oi")} on:click={() => sortData("oi")}
class="td cursor-pointer select-none bg-default text-white font-bold text-xs text-start uppercase" class="cursor-pointer p-2 text-center select-none"
> >
OI OI
<svg <svg
class="shrink-0 w-4 h-4 inline-block {sortOrders['oi'] === class="shrink-0 w-4 h-4 -mt-1 {sortOrders['oi'] === 'asc'
'asc' ? 'rotate-180 inline-block'
? 'rotate-180'
: sortOrders['oi'] === 'desc' : sortOrders['oi'] === 'desc'
? '' ? 'inline-block'
: 'hidden'} " : 'hidden'} "
viewBox="0 0 20 20" viewBox="0 0 20 20"
fill="currentColor" fill="currentColor"
@ -586,29 +571,37 @@
</div> </div>
</div> </div>
<VirtualList
width="100%"
height={$screenWidth < 640
? data?.user?.tier === "Pro"
? 550
: 250
: data?.user?.tier === "Pro"
? 850
: 250}
itemCount={displayedData.length}
itemSize={40}
>
<div <div
slot="item" slot="item"
let:index let:index
let:style let:style
{style} {style}
class="tr {index % 2 === 0 ? 'bg-[#19191F]' : 'bg-[#121217]'} {index + class="grid grid-cols-16 gap-0"
1 === class:bg-[#19191F]={index % 2 === 0}
rawData?.length && data?.user?.tier !== 'Pro' class:bg-[#121217]={index % 2 !== 0}
? 'opacity-[0.3]' class:opacity-30={index + 1 === rawData?.length &&
: ''}" data?.user?.tier !== "Pro"}
> >
<!-- Row data -->
<div <div
style="justify-content: center;" class="p-2 text-center text-white text-xs sm:text-sm whitespace-nowrap"
class="td text-white text-xs sm:text-sm text-start m-auto whitespace-nowrap"
> >
{formatTime(displayedData[index]?.time)} {formatTime(displayedData[index]?.time)}
</div> </div>
<div <div
on:click|stopPropagation on:click|stopPropagation
style="justify-content: center;" class="p-2 text-center text-white text-xs sm:text-sm whitespace-nowrap"
class="td text-sm sm:hover:text-white sm:text-[1rem] text-blue-400 font-normal"
> >
<HoverStockChart <HoverStockChart
symbol={displayedData[index]?.ticker} symbol={displayedData[index]?.ticker}
@ -620,8 +613,7 @@
id={displayedData[index]?.id} id={displayedData[index]?.id}
on:click|stopPropagation={() => on:click|stopPropagation={() =>
addToWatchlist(displayedData[index]?.id)} addToWatchlist(displayedData[index]?.id)}
style="justify-content: center;" class="p-2 text-center text-white text-xs sm:text-sm whitespace-nowrap {optionsWatchlist.optionsId?.includes(
class="td {optionsWatchlist.optionsId?.includes(
displayedData[index]?.id, displayedData[index]?.id,
) )
? 'text-[#FBCE3C]' ? 'text-[#FBCE3C]'
@ -641,15 +633,13 @@
</div> </div>
<div <div
style="justify-content: center;" class="p-2 text-center text-white text-xs sm:text-sm whitespace-nowrap"
class="td text-sm sm:text-[1rem] text-white text-start"
> >
{reformatDate(displayedData[index]?.date_expiration)} {reformatDate(displayedData[index]?.date_expiration)}
</div> </div>
<div <div
style="justify-content: center;" class="p-2 text-center text-white text-xs sm:text-sm whitespace-nowrap"
class="td text-sm sm:text-[1rem] text-white text-start"
> >
{displayedData[index]?.dte < 0 {displayedData[index]?.dte < 0
? "expired" ? "expired"
@ -657,51 +647,47 @@
</div> </div>
<div <div
style="justify-content: center;" class="p-2 text-center text-white text-xs sm:text-sm whitespace-nowrap"
class="td text-sm sm:text-[1rem] text-white text-start"
> >
{displayedData[index]?.strike_price} {displayedData[index]?.strike_price}
</div> </div>
<div <div
style="justify-content: center;" class="p-2 text-center text-white text-xs sm:text-sm whitespace-nowrap {displayedData[
class="td text-sm sm:text-[1rem] {displayedData[index]?.put_call === index
'Calls' ]?.put_call === 'Calls'
? 'text-[#00FC50]' ? 'text-[#00FC50]'
: 'text-[#c44536]'} text-start" : 'text-[#c44536]'} "
> >
{displayedData[index]?.put_call} {displayedData[index]?.put_call}
</div> </div>
<div <div
style="justify-content: center;" class="p-2 text-center text-white text-xs sm:text-sm whitespace-nowrap {displayedData[
class="td text-sm sm:text-[1rem] {displayedData[index]?.sentiment === index
'Bullish' ]?.sentiment === 'Bullish'
? 'text-[#00FC50]' ? 'text-[#00FC50]'
: displayedData[index]?.sentiment === 'Bearish' : displayedData[index]?.sentiment === 'Bearish'
? 'text-[#FF2F1F]' ? 'text-[#FF2F1F]'
: 'text-[#C6A755]'} text-start" : 'text-[#C6A755]'} "
> >
{displayedData[index]?.sentiment} {displayedData[index]?.sentiment}
</div> </div>
<div <div
style="justify-content: center;" class="p-2 text-center text-white text-xs sm:text-sm whitespace-nowrap"
class="td text-sm sm:text-[1rem] text-start text-white"
> >
{displayedData[index]?.underlying_price} {displayedData[index]?.underlying_price}
</div> </div>
<div <div
style="justify-content: center;" class="p-2 text-center text-white text-xs sm:text-sm whitespace-nowrap"
class="td text-sm sm:text-[1rem] text-start text-white"
> >
{displayedData[index]?.price} {displayedData[index]?.price}
</div> </div>
<div <div
style="justify-content: center;" class="p-2 text-center text-white text-xs sm:text-sm whitespace-nowrap"
class="td text-sm sm:text-[1rem] text-start text-white"
> >
{@html abbreviateNumberWithColor( {@html abbreviateNumberWithColor(
displayedData[index]?.cost_basis, displayedData[index]?.cost_basis,
@ -711,8 +697,7 @@
</div> </div>
<div <div
style="justify-content: center;" class="p-2 text-center text-white text-xs sm:text-sm whitespace-nowrap uppercase {displayedData[
class="td text-sm sm:text-[1rem] uppercase text-start {displayedData[
index index
]?.option_activity_type === 'Sweep' ]?.option_activity_type === 'Sweep'
? 'text-[#C6A755]' ? 'text-[#C6A755]'
@ -722,8 +707,7 @@
</div> </div>
<div <div
style="justify-content: center;" class="p-2 text-center text-white text-xs sm:text-sm whitespace-nowrap uppercase {[
class="td text-sm sm:text-[1rem] uppercase text-start {[
'At Ask', 'At Ask',
'Above Ask', 'Above Ask',
]?.includes(displayedData[index]?.execution_estimate) ]?.includes(displayedData[index]?.execution_estimate)
@ -742,8 +726,7 @@
</div> </div>
<div <div
style="justify-content: center;" class="p-2 text-center text-white text-xs sm:text-sm whitespace-nowrap"
class="td text-sm sm:text-[1rem] text-white text-end"
> >
{new Intl.NumberFormat("en", { {new Intl.NumberFormat("en", {
minimumFractionDigits: 0, minimumFractionDigits: 0,
@ -752,8 +735,7 @@
</div> </div>
<div <div
style="justify-content: center;" class="p-2 text-center text-white text-xs sm:text-sm whitespace-nowrap"
class="td text-sm sm:text-[1rem] text-white text-end"
> >
{new Intl.NumberFormat("en", { {new Intl.NumberFormat("en", {
minimumFractionDigits: 0, minimumFractionDigits: 0,
@ -762,8 +744,7 @@
</div> </div>
<div <div
style="justify-content: center;" class="p-2 text-center text-white text-xs sm:text-sm whitespace-nowrap"
class="td text-sm sm:text-[1rem] text-white text-end"
> >
{new Intl.NumberFormat("en", { {new Intl.NumberFormat("en", {
minimumFractionDigits: 0, minimumFractionDigits: 0,
@ -774,89 +755,3 @@
</VirtualList> </VirtualList>
</div> </div>
</div> </div>
<style>
.table-container {
width: 100%;
overflow-x: auto;
}
.table :global(.virtual-list-inner) {
width: 100%;
display: flex;
flex-direction: column;
}
@media (max-width: 768px) {
.table {
width: 1000px;
}
}
.table .virtual-list-inner {
flex-flow: column nowrap;
font-size: 0.8rem;
line-height: 1.5;
flex: 1 1 auto;
}
.th {
display: none;
font-weight: 700;
}
.th > .td {
white-space: nowrap;
justify-content: center;
}
.tr {
width: 100%;
display: flex;
flex-flow: row nowrap;
}
.tr.even {
background-color: #2a2e39;
}
.tr.odd {
background-color: #09090b;
}
.td {
display: flex;
flex-flow: row nowrap;
grow: 1;
flex-basis: 0;
padding: 0.5em;
word-break: break-word;
overflow: hidden;
text-overflow: ellipsis;
min-width: 0px;
white-space: nowrap;
}
.heartbeat {
animation: heartbeat-animation 0.3s;
animation-timing-function: ease-in-out;
}
@keyframes heartbeat-animation {
0% {
transform: rotate(0deg) scale(0.95);
}
25% {
transform: rotate(10deg) scale(1.05);
}
50% {
transform: rotate(0deg) scale(1.2);
}
75% {
transform: rotate(-10deg) scale(1.05);
}
100% {
transform: rotate(0deg) scale(0.95);
}
}
</style>