refactor etf page
This commit is contained in:
parent
ac175c037f
commit
12f52be6ff
@ -1,176 +0,0 @@
|
|||||||
<script lang="ts">
|
|
||||||
|
|
||||||
import ETFProfileCard from '$lib/components/ETFProfileCard.svelte';
|
|
||||||
import SimilarETFCard from '$lib/components/SimilarETFCard.svelte';
|
|
||||||
import TopHoldingCard from '$lib/components/TopHoldingCard.svelte';
|
|
||||||
import { similarTickerClicked } from '$lib/store';
|
|
||||||
import DividendCard from './DividendCard.svelte';
|
|
||||||
|
|
||||||
export let etfProfile;
|
|
||||||
export let data;
|
|
||||||
export let similarTicker;
|
|
||||||
export let topHoldingList;
|
|
||||||
export let dividendList;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
$: {
|
|
||||||
if($similarTickerClicked)
|
|
||||||
{
|
|
||||||
const closePopup = document.getElementById("similarTickerModal");
|
|
||||||
|
|
||||||
closePopup?.dispatchEvent(new MouseEvent('click'))
|
|
||||||
$similarTickerClicked = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</script>
|
|
||||||
|
|
||||||
|
|
||||||
<section class="mt-4">
|
|
||||||
|
|
||||||
|
|
||||||
<div class="grid grid-cols-3 gap-x-4 gap-y-2">
|
|
||||||
<label for="tickerModal" class="w-auto border border-gray-300 flex px-4 py-2 mb-2 justify-center items-center text-xs font-medium rounded-xl text-gray-200">
|
|
||||||
Details
|
|
||||||
</label>
|
|
||||||
|
|
||||||
<label for="topHoldingModal" class="w-auto border border-gray-300 flex px-4 py-2 mb-2 justify-center items-center text-xs font-medium rounded-xl text-gray-200">
|
|
||||||
Holdings
|
|
||||||
</label>
|
|
||||||
|
|
||||||
<label for="dividendModal" class="w-auto border border-gray-300 flex px-4 py-2 mb-2 justify-center items-center text-xs font-medium rounded-xl text-gray-200">
|
|
||||||
Dividends
|
|
||||||
</label>
|
|
||||||
<label for="similarTickerModal" class="w-auto border border-gray-300 flex px-4 py-2 mb-2 justify-center items-center text-xs font-medium rounded-xl text-gray-200">
|
|
||||||
Similar
|
|
||||||
</label>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
</section>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<!--Start ETF Modal-->
|
|
||||||
<div class="drawer drawer-end z-40 overflow-hidden w-screen">
|
|
||||||
<input id="tickerModal" type="checkbox" class="drawer-toggle"/>
|
|
||||||
<div class="drawer-side overflow-hidden">
|
|
||||||
|
|
||||||
|
|
||||||
<div class="bg-[#000] min-h-screen w-screen pb-20 overflow-hidden">
|
|
||||||
|
|
||||||
<label for="tickerModal" class="absolute left-6 top-6">
|
|
||||||
<svg class="w-6 h-6 inline-block mb-0.5" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path fill="#fff" d="M9.125 21.1L.7 12.7q-.15-.15-.213-.325T.425 12q0-.2.063-.375T.7 11.3l8.425-8.425q.35-.35.875-.35t.9.375q.375.375.375.875t-.375.875L3.55 12l7.35 7.35q.35.35.35.863t-.375.887q-.375.375-.875.375t-.875-.375Z"/></svg>
|
|
||||||
</label>
|
|
||||||
|
|
||||||
|
|
||||||
<div class="w-screen overflow-y-scroll" >
|
|
||||||
|
|
||||||
<ETFProfileCard data={data} etfProfile = {etfProfile}/>
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<!--End ETF Modal-->
|
|
||||||
|
|
||||||
|
|
||||||
<!--Start Similar Modal-->
|
|
||||||
<div class="drawer drawer-end z-40 overflow-hidden w-screen">
|
|
||||||
<input id="similarTickerModal" type="checkbox" class="drawer-toggle"/>
|
|
||||||
<div class="drawer-side overflow-hidden">
|
|
||||||
|
|
||||||
|
|
||||||
<div class="bg-[#000] min-h-screen w-screen pb-20 overflow-hidden">
|
|
||||||
|
|
||||||
<label for="similarTickerModal" class="absolute left-6 top-6">
|
|
||||||
<svg class="w-6 h-6 inline-block mb-0.5" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path fill="#fff" d="M9.125 21.1L.7 12.7q-.15-.15-.213-.325T.425 12q0-.2.063-.375T.7 11.3l8.425-8.425q.35-.35.875-.35t.9.375q.375.375.375.875t-.375.875L3.55 12l7.35 7.35q.35.35.35.863t-.375.887q-.375.375-.875.375t-.875-.375Z"/></svg>
|
|
||||||
</label>
|
|
||||||
|
|
||||||
|
|
||||||
<div class="w-screen overflow-y-scroll" >
|
|
||||||
<SimilarETFCard similarTicker={similarTicker}/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<!--End Similar Modal-->
|
|
||||||
|
|
||||||
|
|
||||||
<!--Start Top Holding Modal-->
|
|
||||||
<div class="drawer drawer-end z-40 overflow-hidden w-screen">
|
|
||||||
<input id="topHoldingModal" type="checkbox" class="drawer-toggle"/>
|
|
||||||
<div class="drawer-side overflow-hidden">
|
|
||||||
|
|
||||||
|
|
||||||
<div class="bg-[#000] min-h-screen w-screen pb-20 overflow-hidden">
|
|
||||||
|
|
||||||
<label for="topHoldingModal" class="absolute left-6 top-6">
|
|
||||||
<svg class="w-6 h-6 inline-block mb-0.5" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path fill="#fff" d="M9.125 21.1L.7 12.7q-.15-.15-.213-.325T.425 12q0-.2.063-.375T.7 11.3l8.425-8.425q.35-.35.875-.35t.9.375q.375.375.375.875t-.375.875L3.55 12l7.35 7.35q.35.35.35.863t-.375.887q-.375.375-.875.375t-.875-.375Z"/></svg>
|
|
||||||
</label>
|
|
||||||
|
|
||||||
<!--Start Header-->
|
|
||||||
<div class="bg-[#09090B] w-full p-1 flex flex-col items-center pb-5 h-auto rounded-b-[30px]">
|
|
||||||
<h2 class="text-center m-auto text-[1.1rem] font-medium text-white mt-5">
|
|
||||||
Top Holdings
|
|
||||||
</h2>
|
|
||||||
<div class="flex flex-col items-center mt-8 w-full">
|
|
||||||
<span class="text-white text-center text-md text-opacity-[0.8] pl-8 pr-8">
|
|
||||||
Discover the primary holdings within the ETF's composition.
|
|
||||||
</span>
|
|
||||||
|
|
||||||
<div class="flex flex-row justify-center items-center w-full mt-5">
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
<!--End Header-->
|
|
||||||
|
|
||||||
|
|
||||||
<div class="w-screen overflow-y-scroll" >
|
|
||||||
|
|
||||||
<TopHoldingCard topHoldingList = {topHoldingList}/>
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<!--End Top Holding Modal-->
|
|
||||||
|
|
||||||
|
|
||||||
<!--Start Dividend Modal-->
|
|
||||||
<div class="drawer drawer-end z-40 overflow-hidden w-screen">
|
|
||||||
<input id="dividendModal" type="checkbox" class="drawer-toggle"/>
|
|
||||||
<div class="drawer-side overflow-hidden">
|
|
||||||
|
|
||||||
|
|
||||||
<div class="bg-[#000] min-h-screen w-screen pb-20 overflow-hidden">
|
|
||||||
|
|
||||||
<label for="dividendModal" class="absolute left-6 top-6">
|
|
||||||
<svg class="w-6 h-6 inline-block mb-0.5" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path fill="#fff" d="M9.125 21.1L.7 12.7q-.15-.15-.213-.325T.425 12q0-.2.063-.375T.7 11.3l8.425-8.425q.35-.35.875-.35t.9.375q.375.375.375.875t-.375.875L3.55 12l7.35 7.35q.35.35.35.863t-.375.887q-.375.375-.875.375t-.875-.375Z"/></svg>
|
|
||||||
</label>
|
|
||||||
|
|
||||||
|
|
||||||
<div class="w-screen overflow-y-scroll" >
|
|
||||||
|
|
||||||
<DividendCard dividendList = {dividendList}/>
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<!--End Dividend Modal-->
|
|
||||||
305
src/lib/components/ETFSidecard.svelte
Normal file
305
src/lib/components/ETFSidecard.svelte
Normal file
@ -0,0 +1,305 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import { etfTicker, stockTicker, cryptoTicker } from "$lib/store";
|
||||||
|
import { formatETFName, formatString, abbreviateNumber } from "$lib/utils";
|
||||||
|
import defaultLogo from "$lib/images/stocks/logo/default_logo.png";
|
||||||
|
|
||||||
|
import { goto } from "$app/navigation";
|
||||||
|
|
||||||
|
export let data;
|
||||||
|
|
||||||
|
let info;
|
||||||
|
let topHoldingList = [];
|
||||||
|
let description = "";
|
||||||
|
let website = "-";
|
||||||
|
let snippet;
|
||||||
|
|
||||||
|
let ipoDate = "n/a";
|
||||||
|
let assetClass = "-";
|
||||||
|
let provider = "-";
|
||||||
|
let showFullText = false;
|
||||||
|
let totalAssetPercentage = 0;
|
||||||
|
|
||||||
|
let dividendHistoryList = [];
|
||||||
|
let dividendYield;
|
||||||
|
|
||||||
|
async function stockSelector(ticker: string) {
|
||||||
|
if (ticker?.length !== 0 && !["BTC", "USD"]?.includes(ticker)) {
|
||||||
|
window?.scroll({ top: 0, left: 0, behavior: "smooth" });
|
||||||
|
stockTicker.update((value) => ticker);
|
||||||
|
goto("/stocks/" + ticker + "/");
|
||||||
|
} else if (ticker === "BTC") {
|
||||||
|
window?.scroll({ top: 0, left: 0, behavior: "smooth" });
|
||||||
|
cryptoTicker.update((value) => "BTCUSD");
|
||||||
|
goto("/crypto/BTCUSD");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$: {
|
||||||
|
if ($etfTicker && typeof window !== "undefined") {
|
||||||
|
info = data?.getETFProfile?.at(0);
|
||||||
|
topHoldingList = data?.getETFHoldings;
|
||||||
|
dividendHistoryList = data?.getStockDividend?.history;
|
||||||
|
dividendYield = data?.getStockDividend?.dividendYield;
|
||||||
|
provider = info?.etfProvider;
|
||||||
|
assetClass = info?.assetClass;
|
||||||
|
ipoDate =
|
||||||
|
info?.inceptionDate !== null
|
||||||
|
? new Date(info?.inceptionDate)?.toLocaleString("en-US", {
|
||||||
|
month: "short",
|
||||||
|
day: "numeric",
|
||||||
|
year: "numeric",
|
||||||
|
daySuffix: "2-digit",
|
||||||
|
})
|
||||||
|
: "n/a";
|
||||||
|
|
||||||
|
description =
|
||||||
|
info?.description ??
|
||||||
|
"A detailed description of the company is not yet available.";
|
||||||
|
website = info?.website;
|
||||||
|
snippet = description?.slice(0, 450) + "...";
|
||||||
|
|
||||||
|
totalAssetPercentage = topHoldingList
|
||||||
|
?.slice(0, 5)
|
||||||
|
?.reduce((acc, current) => acc + current?.weightPercentage, 0)
|
||||||
|
?.toFixed(2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="px-0.5 lg:px-0">
|
||||||
|
<h2 class="mb-2 text-2xl text-white font-semibold">
|
||||||
|
About {$etfTicker}
|
||||||
|
</h2>
|
||||||
|
<p class="text-gray-200">
|
||||||
|
{#if showFullText}
|
||||||
|
{description}
|
||||||
|
{:else}
|
||||||
|
{snippet}
|
||||||
|
{/if}
|
||||||
|
</p>
|
||||||
|
{#if description.length !== 0}
|
||||||
|
<div class="inline-block">
|
||||||
|
<label
|
||||||
|
on:click={() => (showFullText = !showFullText)}
|
||||||
|
class="w-full text-md mt-1 cursor-pointer font-medium sm:hover:text-white text-blue-400 sm:hover:underline"
|
||||||
|
>
|
||||||
|
{#if showFullText}
|
||||||
|
[Show less]
|
||||||
|
{:else}
|
||||||
|
[Show more]
|
||||||
|
{/if}
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
<div
|
||||||
|
class="mt-3 grid grid-cols-2 gap-3 w-full border-b border-gray-600 lg:border-none pb-8 lg:pb-0"
|
||||||
|
>
|
||||||
|
<div class="col-span-1 text-gray-200">
|
||||||
|
<span class="block font-semibold">Asset Class</span>
|
||||||
|
<span class=" text-white">{assetClass}</span>
|
||||||
|
</div>
|
||||||
|
<div class="col-span-1 text-gray-200">
|
||||||
|
<span class="block font-semibold">Ticker Symbol</span>
|
||||||
|
{$etfTicker}
|
||||||
|
</div>
|
||||||
|
<div class="col-span-1 text-gray-200">
|
||||||
|
<span class="block font-semibold">Inception Date</span>
|
||||||
|
<span>{ipoDate}</span>
|
||||||
|
</div>
|
||||||
|
<div class="col-span-1 text-gray-200">
|
||||||
|
<span class="block font-semibold">Provider</span>
|
||||||
|
<a
|
||||||
|
href={`/etf/etf-providers/${provider}`}
|
||||||
|
class="sm:hover:text-blue-400 text-white underline underline-offset-4"
|
||||||
|
>{formatETFName(provider)}</a
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-span-1 whitespace-nowrap text-gray-200">
|
||||||
|
<span class="block font-semibold">Website</span>
|
||||||
|
<a
|
||||||
|
href={website}
|
||||||
|
class="sm:hover:text-blue-400 text-white underline underline-offset-4"
|
||||||
|
target="_blank">Fund Home Page</a
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{#if topHoldingList?.length !== 0}
|
||||||
|
<div
|
||||||
|
class="space-y-3 sm:pt-5 hidden sm:block sm:{(topHoldingList?.length ?? [])
|
||||||
|
?.length !== 0
|
||||||
|
? ''
|
||||||
|
: 'hidden'}"
|
||||||
|
>
|
||||||
|
<div class="h-auto w-full">
|
||||||
|
<!--Start Content-->
|
||||||
|
<div class="w-auto lg:w-full flex flex-col m-auto">
|
||||||
|
<h2
|
||||||
|
class="mb-2 text-2xl text-white font-semibold flex flex-row items-center"
|
||||||
|
>
|
||||||
|
<span>Top Holdings</span>
|
||||||
|
<span class="text-white font-semibold ml-auto text-sm">
|
||||||
|
{totalAssetPercentage}% of assets
|
||||||
|
</span>
|
||||||
|
</h2>
|
||||||
|
|
||||||
|
<div class="mt-2 w-full">
|
||||||
|
<table class="table table-sm table-compact w-full">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th
|
||||||
|
class="text-white font-semibold text-sm text-start bg-[#000] lg:bg-[#09090B]"
|
||||||
|
>Company</th
|
||||||
|
>
|
||||||
|
|
||||||
|
<th
|
||||||
|
class="text-white font-semibold text-sm text-end bg-[#000] lg:bg-[#09090B]"
|
||||||
|
>Portfolio</th
|
||||||
|
>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{#each topHoldingList?.slice(0, 5) as item}
|
||||||
|
{#if item?.asset !== null}
|
||||||
|
<tr
|
||||||
|
on:click={() => stockSelector(item?.asset)}
|
||||||
|
class="lg:shake-ticker sm:hover:text-white text-blue-400 cursor-pointer lg:hover:bg-[#245073] lg:hover:bg-opacity-[0.2] bg-[#000] lg:bg-[#09090B] border-b border-[#000] lg:border-[#27272A]"
|
||||||
|
>
|
||||||
|
<td class="">
|
||||||
|
<div class="flex flex-row items-center">
|
||||||
|
<div
|
||||||
|
class="rounded-full w-10 h-10 relative flex items-center justify-center"
|
||||||
|
>
|
||||||
|
<img
|
||||||
|
style="clip-path: circle(50%);"
|
||||||
|
class="w-6 h-6 rounded-full"
|
||||||
|
src={item?.asset?.length !== 0
|
||||||
|
? `https://financialmodelingprep.com/image-stock/${item?.asset}.png`
|
||||||
|
: defaultLogo}
|
||||||
|
loading="lazy"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col ml-3 w-full">
|
||||||
|
<span class="text-sm font-medium"
|
||||||
|
>{item?.asset ?? "-"}</span
|
||||||
|
>
|
||||||
|
<span class="text-white text-sm">
|
||||||
|
{#if typeof item?.name !== "undefined"}
|
||||||
|
{item?.name?.length > 20
|
||||||
|
? formatString(item?.name?.slice(0, 20)) + "..."
|
||||||
|
: formatString(item?.name)}
|
||||||
|
{:else}
|
||||||
|
n/a
|
||||||
|
{/if}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<td class="text-white font-semibold text-end">
|
||||||
|
{abbreviateNumber(item?.weightPercentage?.toFixed(2))}%
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{/if}
|
||||||
|
{/each}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<a
|
||||||
|
href={`/etf/${$etfTicker}/holdings`}
|
||||||
|
class="rounded cursor-pointer w-full m-auto py-2 h-full mt-6 text-lg text-center font-semibold text-black sm:hover:hover:bg-gray-300 bg-[#ffff] transition duration-100"
|
||||||
|
>
|
||||||
|
All Holdings
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
{#if dividendHistoryList?.length !== 0}
|
||||||
|
<div
|
||||||
|
class="space-y-3 sm:pt-5 hidden sm:block sm:{(
|
||||||
|
dividendHistoryList?.length ?? []
|
||||||
|
)?.length !== 0
|
||||||
|
? ''
|
||||||
|
: 'hidden'}"
|
||||||
|
>
|
||||||
|
<div class="h-auto w-full">
|
||||||
|
<!--Start Content-->
|
||||||
|
<div class="w-auto lg:w-full flex flex-col m-auto">
|
||||||
|
<h2
|
||||||
|
class="mb-2 text-2xl text-white font-semibold flex flex-row items-center"
|
||||||
|
>
|
||||||
|
<span>Dividends</span>
|
||||||
|
<span class="text-white font-semibold ml-auto text-sm">
|
||||||
|
Dividend Yield {dividendYield ?? "0"}%
|
||||||
|
</span>
|
||||||
|
</h2>
|
||||||
|
|
||||||
|
<div class="mt-2 w-full">
|
||||||
|
<table class="table table-sm table-compact text-start flex w-full">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th
|
||||||
|
class="text-white font-semibold text-sm text-start bg-[#000] lg:bg-[#09090B]"
|
||||||
|
>Ex-Dividend</th
|
||||||
|
>
|
||||||
|
<th
|
||||||
|
class="text-white font-semibold text-sm text-end bg-[#000] lg:bg-[#09090B]"
|
||||||
|
>Payment Date</th
|
||||||
|
>
|
||||||
|
<th
|
||||||
|
class="text-white font-semibold text-sm text-end bg-[#000] lg:bg-[#09090B]"
|
||||||
|
>Amount</th
|
||||||
|
>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
|
||||||
|
<tbody>
|
||||||
|
{#each dividendHistoryList?.slice(0, 5) as item}
|
||||||
|
<tr
|
||||||
|
class="text-white bg-[#000] lg:bg-[#09090B] border-b border-[#000] lg:border-[#27272A]"
|
||||||
|
>
|
||||||
|
<td class="text-start text-sm text-white font-medium">
|
||||||
|
{new Date(item?.date)?.toLocaleString("en-US", {
|
||||||
|
month: "short",
|
||||||
|
day: "numeric",
|
||||||
|
year: "numeric",
|
||||||
|
daySuffix: "2-digit",
|
||||||
|
})}
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<td class="text-end text-sm text-white font-medium">
|
||||||
|
{item?.paymentDate?.length !== 0
|
||||||
|
? new Date(item?.paymentDate)?.toLocaleString("en-US", {
|
||||||
|
month: "short",
|
||||||
|
day: "numeric",
|
||||||
|
year: "numeric",
|
||||||
|
daySuffix: "2-digit",
|
||||||
|
})
|
||||||
|
: "n/a"}
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<td class="text-end text-sm text-white font-medium">
|
||||||
|
${item?.adjDividend?.toFixed(2)}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{/each}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<a
|
||||||
|
href={`/etf/${$etfTicker}/dividends`}
|
||||||
|
class="rounded cursor-pointer w-full m-auto py-2 h-full mt-6 text-lg text-center font-semibold text-black sm:hover:hover:bg-gray-300 bg-[#ffff] transition duration-100"
|
||||||
|
>
|
||||||
|
Full Dividend History
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
@ -1,5 +1,5 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { stockTicker } from "$lib/store";
|
import { stockTicker, etfTicker } from "$lib/store";
|
||||||
|
|
||||||
export let data;
|
export let data;
|
||||||
|
|
||||||
@ -57,7 +57,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
$: {
|
$: {
|
||||||
if ($stockTicker && typeof window !== "undefined") {
|
if (($stockTicker || $etfTicker) && typeof window !== "undefined") {
|
||||||
rawData = data?.getNews;
|
rawData = data?.getNews;
|
||||||
newsList = rawData?.slice(0, 20) ?? [];
|
newsList = rawData?.slice(0, 20) ?? [];
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,7 +2,6 @@
|
|||||||
import { goto } from "$app/navigation";
|
import { goto } from "$app/navigation";
|
||||||
import { numberOfUnreadNotification, screenWidth } from "$lib/store";
|
import { numberOfUnreadNotification, screenWidth } from "$lib/store";
|
||||||
import { abbreviateNumber } from "$lib/utils";
|
import { abbreviateNumber } from "$lib/utils";
|
||||||
import { page } from "$app/stores";
|
|
||||||
import logo from "$lib/images/box_logo.png";
|
import logo from "$lib/images/box_logo.png";
|
||||||
import ArrowLogo from "lucide-svelte/icons/move-up-right";
|
import ArrowLogo from "lucide-svelte/icons/move-up-right";
|
||||||
import { onMount } from "svelte";
|
import { onMount } from "svelte";
|
||||||
|
|||||||
@ -1,14 +1,9 @@
|
|||||||
export const config = {
|
|
||||||
runtime: "nodejs20.x",
|
|
||||||
};
|
|
||||||
|
|
||||||
const cleanString = (input) => {
|
const cleanString = (input) => {
|
||||||
const substringsToRemove = [
|
const substringsToRemove = [
|
||||||
"Depositary",
|
"Depositary",
|
||||||
"Inc.",
|
"Inc.",
|
||||||
"Incorporated",
|
"Incorporated",
|
||||||
"Holdings",
|
"Holdings",
|
||||||
"Corporation",
|
|
||||||
"Corporations",
|
"Corporations",
|
||||||
"LLC",
|
"LLC",
|
||||||
"Holdings plc American Depositary Shares",
|
"Holdings plc American Depositary Shares",
|
||||||
@ -47,51 +42,48 @@ const fetchWatchlist = async (pb, userId) => {
|
|||||||
return output;
|
return output;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const load = async ({ params, locals, setHeaders }) => {
|
export const load = async ({ params, locals }) => {
|
||||||
const { apiURL, apiKey, pb, user } = locals;
|
const { apiURL, apiKey, pb, user } = locals;
|
||||||
const { tickerID } = params;
|
const { tickerID } = params;
|
||||||
|
|
||||||
const endpoints = [
|
const endpoints = [
|
||||||
"/etf-profile",
|
"/etf-profile",
|
||||||
"/similar-etfs",
|
|
||||||
"/etf-country-weighting",
|
|
||||||
"/etf-holdings",
|
"/etf-holdings",
|
||||||
"/stock-dividend",
|
"/stock-dividend",
|
||||||
"/stock-quote",
|
"/stock-quote",
|
||||||
"/wiim",
|
"/wiim",
|
||||||
"/one-day-price",
|
"/one-day-price",
|
||||||
|
"/stock-news",
|
||||||
];
|
];
|
||||||
|
|
||||||
const promises = [
|
const promises = [
|
||||||
...endpoints.map((endpoint) =>
|
...endpoints.map((endpoint) =>
|
||||||
fetchData(apiURL, apiKey, endpoint, tickerID)
|
fetchData(apiURL, apiKey, endpoint, tickerID),
|
||||||
),
|
),
|
||||||
fetchWatchlist(pb, user?.id),
|
fetchWatchlist(pb, user?.id),
|
||||||
//fetchFromFastify(fastifyURL, '/get-portfolio-data', user?.id)
|
|
||||||
];
|
];
|
||||||
|
|
||||||
const [
|
const [
|
||||||
getETFProfile,
|
getETFProfile,
|
||||||
getSimilarETFs,
|
|
||||||
getCountryWeighting,
|
|
||||||
getETFHoldings,
|
getETFHoldings,
|
||||||
getStockDividend,
|
getStockDividend,
|
||||||
getStockQuote,
|
getStockQuote,
|
||||||
getWhyPriceMoved,
|
getWhyPriceMoved,
|
||||||
getOneDayPrice,
|
getOneDayPrice,
|
||||||
|
getNews,
|
||||||
getUserWatchlist,
|
getUserWatchlist,
|
||||||
] = await Promise.all(promises);
|
] = await Promise.all(promises);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
getETFProfile,
|
getETFProfile,
|
||||||
getSimilarETFs,
|
|
||||||
getCountryWeighting,
|
|
||||||
getETFHoldings,
|
getETFHoldings,
|
||||||
getStockDividend,
|
getStockDividend,
|
||||||
getStockQuote,
|
getStockQuote,
|
||||||
getWhyPriceMoved,
|
getWhyPriceMoved,
|
||||||
getOneDayPrice,
|
getOneDayPrice,
|
||||||
|
getNews,
|
||||||
getUserWatchlist,
|
getUserWatchlist,
|
||||||
companyName: cleanString(getETFProfile?.at(0)?.name),
|
companyName: cleanString(getETFProfile?.at(0)?.name),
|
||||||
|
getParams: params.tickerID,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,58 +1,45 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import {
|
import {
|
||||||
searchBarData,
|
wsBidPrice,
|
||||||
|
wsAskPrice,
|
||||||
globalForm,
|
globalForm,
|
||||||
screenWidth,
|
screenWidth,
|
||||||
openPriceAlert,
|
openPriceAlert,
|
||||||
currentPortfolioPrice,
|
currentPortfolioPrice,
|
||||||
wsBidPrice,
|
|
||||||
wsAskPrice,
|
|
||||||
realtimePrice,
|
realtimePrice,
|
||||||
isCrosshairMoveActive,
|
isCrosshairMoveActive,
|
||||||
currentPrice,
|
currentPrice,
|
||||||
priceIncrease,
|
priceIncrease,
|
||||||
displayCompanyName,
|
|
||||||
traded,
|
|
||||||
etfTicker,
|
etfTicker,
|
||||||
assetType,
|
displayCompanyName,
|
||||||
isOpen,
|
isOpen,
|
||||||
|
shouldUpdatePriceChart,
|
||||||
|
priceChartData,
|
||||||
} from "$lib/store";
|
} from "$lib/store";
|
||||||
|
|
||||||
import { onMount, onDestroy, afterUpdate } from "svelte";
|
import { onMount, onDestroy, afterUpdate } from "svelte";
|
||||||
import { goto } from "$app/navigation";
|
|
||||||
import { page } from "$app/stores";
|
import { page } from "$app/stores";
|
||||||
import toast from "svelte-french-toast";
|
import toast from "svelte-french-toast";
|
||||||
import ETFProfileCard from "$lib/components/ETFProfileCard.svelte";
|
|
||||||
import SimilarETFCard from "$lib/components/SimilarETFCard.svelte";
|
|
||||||
import Markethour from "$lib/components/Markethour.svelte";
|
import Markethour from "$lib/components/Markethour.svelte";
|
||||||
import TopHoldingCard from "$lib/components/TopHoldingCard.svelte";
|
|
||||||
import DividendCard from "$lib/components/DividendCard.svelte";
|
|
||||||
|
|
||||||
export let data;
|
export let data;
|
||||||
|
$: $realtimePrice = data?.getStockQuote?.price?.toFixed(2);
|
||||||
//$assetType = 'etf';
|
|
||||||
//$etfTicker = data?.getTicker;
|
|
||||||
$realtimePrice = null;
|
|
||||||
|
|
||||||
let previousRealtimePrice = null;
|
let previousRealtimePrice = null;
|
||||||
let previousTicker;
|
let previousTicker;
|
||||||
let socket;
|
let socket;
|
||||||
|
|
||||||
let isScrolled = false;
|
let isScrolled = false;
|
||||||
|
let y;
|
||||||
|
|
||||||
let userWatchList = data?.getUserWatchlist ?? [];
|
let userWatchList = data?.getUserWatchlist ?? [];
|
||||||
let isTickerIncluded;
|
let isTickerIncluded = false;
|
||||||
let userPortfolio = data?.getUserPortfolio ?? [];
|
//let userPortfolio = data?.getUserPortfolio ?? [];
|
||||||
let holdingShares = 0;
|
//let holdingShares = 0;
|
||||||
let availableCash = 0;
|
//let availableCash = 0;
|
||||||
|
|
||||||
let displaySection = "";
|
let displaySection = "";
|
||||||
|
|
||||||
let etfProfile = [];
|
|
||||||
let similarTicker = [];
|
|
||||||
let topHoldingList = [];
|
|
||||||
let dividendList = [];
|
|
||||||
|
|
||||||
function shareContent(url) {
|
function shareContent(url) {
|
||||||
if (navigator.share) {
|
if (navigator.share) {
|
||||||
navigator
|
navigator
|
||||||
@ -69,33 +56,15 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleTypeOfTrade(state: string) {
|
function changeSection(state) {
|
||||||
if (state === "buy") {
|
|
||||||
const closePopup = document.getElementById("buyTradeModal");
|
|
||||||
closePopup?.dispatchEvent(new MouseEvent("click"));
|
|
||||||
} else if (state === "sell") {
|
|
||||||
const closePopup = document.getElementById("sellTradeModal");
|
|
||||||
closePopup?.dispatchEvent(new MouseEvent("click"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function scrollToItem(itemId) {
|
|
||||||
const item = document.getElementById(itemId);
|
|
||||||
if (item) {
|
|
||||||
item.scrollIntoView({ behavior: "smooth" });
|
|
||||||
window.scrollTo(0, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function changeSection(state, item) {
|
|
||||||
scrollToItem(item);
|
|
||||||
|
|
||||||
const sectionMap = {
|
const sectionMap = {
|
||||||
|
insider: "/insider",
|
||||||
options: "/options",
|
options: "/options",
|
||||||
holdings: "/holdings",
|
|
||||||
forecast: "/forecast",
|
|
||||||
dividends: "/dividends",
|
dividends: "/dividends",
|
||||||
stats: "/stats",
|
statistics: "/statistics",
|
||||||
|
metrics: "metrics",
|
||||||
|
forecast: "/forecast",
|
||||||
|
financials: "/financials",
|
||||||
news: "/news",
|
news: "/news",
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -164,11 +133,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleScroll() {
|
|
||||||
// Check the scroll position
|
|
||||||
isScrolled = window.scrollY > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
function sendMessage(message) {
|
function sendMessage(message) {
|
||||||
if (socket && socket.readyState === WebSocket.OPEN) {
|
if (socket && socket.readyState === WebSocket.OPEN) {
|
||||||
socket.send(message);
|
socket.send(message);
|
||||||
@ -193,25 +157,24 @@
|
|||||||
const data = event.data;
|
const data = event.data;
|
||||||
//console.log('Received message:', data);
|
//console.log('Received message:', data);
|
||||||
try {
|
try {
|
||||||
$realtimePrice =
|
const parsedData = JSON.parse(data);
|
||||||
typeof JSON.parse(data)?.lp !== "undefined"
|
const { type, lp, time, bp, ap } = parsedData || {};
|
||||||
? JSON.parse(data)?.lp
|
|
||||||
: null;
|
|
||||||
$wsBidPrice =
|
|
||||||
typeof JSON.parse(data)?.bp !== "undefined"
|
|
||||||
? JSON.parse(data)?.bp
|
|
||||||
: null;
|
|
||||||
$wsAskPrice =
|
|
||||||
typeof JSON.parse(data)?.ap !== "undefined"
|
|
||||||
? JSON.parse(data)?.ap
|
|
||||||
: null;
|
|
||||||
//console.log('Received message:', $realtimePrice);
|
|
||||||
|
|
||||||
if ($realtimePrice > previousRealtimePrice) {
|
if (type === "T") {
|
||||||
$priceIncrease = true;
|
$realtimePrice = typeof lp !== "undefined" ? lp : null;
|
||||||
previousRealtimePrice = $realtimePrice;
|
$priceChartData = {
|
||||||
} else if ($realtimePrice < previousRealtimePrice) {
|
time: typeof time !== "undefined" ? time : null,
|
||||||
$priceIncrease = false;
|
price: typeof lp !== "undefined" ? Number(lp) : null,
|
||||||
|
};
|
||||||
|
shouldUpdatePriceChart.set(true);
|
||||||
|
} else if (type === "Q") {
|
||||||
|
$wsBidPrice = typeof bp !== "undefined" ? bp : null;
|
||||||
|
$wsAskPrice = typeof ap !== "undefined" ? ap : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update price increase state
|
||||||
|
if ($realtimePrice !== previousRealtimePrice) {
|
||||||
|
$priceIncrease = $realtimePrice > previousRealtimePrice;
|
||||||
previousRealtimePrice = $realtimePrice;
|
previousRealtimePrice = $realtimePrice;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -244,22 +207,10 @@
|
|||||||
PriceAlert = (await import("$lib/components/PriceAlert.svelte")).default;
|
PriceAlert = (await import("$lib/components/PriceAlert.svelte")).default;
|
||||||
}
|
}
|
||||||
|
|
||||||
//const startTime = currentDateTime.set({ hour: 15, minute: 30 });
|
|
||||||
//const endTime = currentDateTime.set({ hour: 22, minute: 0 });
|
|
||||||
// Check if it's not a weekend and the current time is within the specified range
|
|
||||||
|
|
||||||
if ($isOpen) {
|
if ($isOpen) {
|
||||||
//&& currentDateTime > startTime && currentDateTime < endTime
|
//&& currentDateTime > startTime && currentDateTime < endTime
|
||||||
await websocketRealtimeData();
|
await websocketRealtimeData();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add a scroll event listener
|
|
||||||
window.addEventListener("scroll", handleScroll);
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
// Remove the event listener when the component is unmounted
|
|
||||||
window.removeEventListener("scroll", handleScroll);
|
|
||||||
};
|
|
||||||
});
|
});
|
||||||
|
|
||||||
afterUpdate(async () => {
|
afterUpdate(async () => {
|
||||||
@ -268,7 +219,7 @@
|
|||||||
//socket.send('close')
|
//socket.send('close')
|
||||||
socket?.close();
|
socket?.close();
|
||||||
await new Promise((resolve, reject) => {
|
await new Promise((resolve, reject) => {
|
||||||
socket.addEventListener("close", resolve);
|
socket?.addEventListener("close", resolve);
|
||||||
});
|
});
|
||||||
|
|
||||||
if (socket?.readyState === WebSocket?.CLOSED) {
|
if (socket?.readyState === WebSocket?.CLOSED) {
|
||||||
@ -294,7 +245,7 @@
|
|||||||
$priceIncrease = null;
|
$priceIncrease = null;
|
||||||
$wsAskPrice = null;
|
$wsAskPrice = null;
|
||||||
$wsBidPrice = null;
|
$wsBidPrice = null;
|
||||||
$traded = false;
|
//$traded = false
|
||||||
});
|
});
|
||||||
|
|
||||||
$: {
|
$: {
|
||||||
@ -304,42 +255,16 @@
|
|||||||
typeof window !== "undefined"
|
typeof window !== "undefined"
|
||||||
) {
|
) {
|
||||||
// add a check to see if running on client-side
|
// add a check to see if running on client-side
|
||||||
etfProfile = [];
|
|
||||||
|
|
||||||
etfProfile = data?.getETFProfile;
|
|
||||||
similarTicker = data?.getSimilarETFs;
|
|
||||||
topHoldingList = data?.getETFHoldings;
|
|
||||||
dividendList = data?.getStockDividend;
|
|
||||||
$currentPortfolioPrice = data?.getStockQuote?.price;
|
$currentPortfolioPrice = data?.getStockQuote?.price;
|
||||||
|
|
||||||
const asyncFunctions = [];
|
|
||||||
|
|
||||||
Promise.all(asyncFunctions)
|
|
||||||
.then((results) => {})
|
|
||||||
.catch((error) => {
|
|
||||||
console.error("An error occurred:", error);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$: {
|
$: isTickerIncluded = userWatchList?.some(
|
||||||
if (userWatchList) {
|
(item) => item.user === data?.user?.id && item.ticker?.includes($etfTicker),
|
||||||
isTickerIncluded = userWatchList?.some(
|
|
||||||
(item) =>
|
|
||||||
item.user === data?.user?.id && item?.ticker?.includes($etfTicker),
|
|
||||||
);
|
);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let charNumber = 50;
|
$: charNumber = $screenWidth < 640 ? 15 : 25;
|
||||||
|
|
||||||
$: {
|
|
||||||
if ($screenWidth < 640) {
|
|
||||||
charNumber = 15;
|
|
||||||
} else {
|
|
||||||
charNumber = 50;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$: {
|
$: {
|
||||||
if (
|
if (
|
||||||
@ -352,15 +277,16 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
$: {
|
$: {
|
||||||
if ($page.url.pathname) {
|
if ($page?.url?.pathname && typeof window !== "undefined") {
|
||||||
const parts = $page?.url?.pathname?.split("/");
|
const parts = $page?.url?.pathname?.split("/");
|
||||||
const sectionMap = {
|
const sectionMap = {
|
||||||
stats: "stats",
|
statistics: "statistics",
|
||||||
forecast: "forecast",
|
financials: "financials",
|
||||||
options: "options",
|
options: "options",
|
||||||
holdings: "holdings",
|
metrics: "metrics",
|
||||||
|
insider: "insider",
|
||||||
dividends: "dividends",
|
dividends: "dividends",
|
||||||
"congress-trading": "congress-trading",
|
forecast: "forecast",
|
||||||
news: "news",
|
news: "news",
|
||||||
};
|
};
|
||||||
displaySection =
|
displaySection =
|
||||||
@ -369,13 +295,17 @@
|
|||||||
] || "overview";
|
] || "overview";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$: isScrolled = y > 0;
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<svelte:window bind:scrollY={y} />
|
||||||
|
|
||||||
<body
|
<body
|
||||||
class="bg-[#09090B] pb-40 w-full max-w-screen min-h-screen sm:max-w-7xl xl:max-w-screen-2xl overflow-hidden"
|
class="bg-[#09090B] w-full max-w-screen sm:max-w-7xl min-h-screen xl:max-w-screen-2xl overflow-hidden"
|
||||||
>
|
>
|
||||||
<!-- Page wrapper -->
|
<!-- Page wrapper -->
|
||||||
<div class="flex flex-col w-full">
|
<div class="flex flex-col w-full mt-5 relative w-full">
|
||||||
<main class="grow w-full">
|
<main class="grow w-full">
|
||||||
<section class="w-full">
|
<section class="w-full">
|
||||||
<div class="w-full">
|
<div class="w-full">
|
||||||
@ -391,10 +321,7 @@
|
|||||||
<div
|
<div
|
||||||
class="flex-1 flex-shrink-0 flex flex-row items-center justify-between -mt-2"
|
class="flex-1 flex-shrink-0 flex flex-row items-center justify-between -mt-2"
|
||||||
>
|
>
|
||||||
<label
|
<a href="/" class="ml-2 cursor-pointer">
|
||||||
on:click={() => goto("/")}
|
|
||||||
class="ml-2 cursor-pointer"
|
|
||||||
>
|
|
||||||
<svg
|
<svg
|
||||||
class="w-5 h-5 inline-block"
|
class="w-5 h-5 inline-block"
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
@ -406,7 +333,7 @@
|
|||||||
/></g
|
/></g
|
||||||
></svg
|
></svg
|
||||||
>
|
>
|
||||||
</label>
|
</a>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
class={!isScrolled
|
class={!isScrolled
|
||||||
@ -420,12 +347,9 @@
|
|||||||
</span>
|
</span>
|
||||||
<span class="text-white font-medium text-sm">
|
<span class="text-white font-medium text-sm">
|
||||||
{#if $currentPortfolioPrice !== null && $currentPortfolioPrice !== 0}
|
{#if $currentPortfolioPrice !== null && $currentPortfolioPrice !== 0}
|
||||||
{$etfTicker?.includes(".DE") ||
|
{$currentPortfolioPrice}
|
||||||
$etfTicker?.includes(".F")
|
|
||||||
? `${$currentPortfolioPrice}€`
|
|
||||||
: ` $${$currentPortfolioPrice}`}
|
|
||||||
{:else}
|
{:else}
|
||||||
---
|
{data?.getStockQuote?.price}
|
||||||
{/if}
|
{/if}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
@ -452,9 +376,7 @@
|
|||||||
<label
|
<label
|
||||||
class="mr-4"
|
class="mr-4"
|
||||||
on:click={() =>
|
on:click={() =>
|
||||||
shareContent(
|
shareContent("https://stocknear.com/etf/" + $etfTicker)}
|
||||||
"https://stocknear.com/stocks/" + $etfTicker,
|
|
||||||
)}
|
|
||||||
>
|
>
|
||||||
<svg
|
<svg
|
||||||
class="w-6 h-6 inline-block"
|
class="w-6 h-6 inline-block"
|
||||||
@ -473,6 +395,7 @@
|
|||||||
<!--End Share Button-->
|
<!--End Share Button-->
|
||||||
|
|
||||||
<!--Start Watchlist-->
|
<!--Start Watchlist-->
|
||||||
|
|
||||||
{#if data?.user}
|
{#if data?.user}
|
||||||
<div class="flex flex-col mr-4">
|
<div class="flex flex-col mr-4">
|
||||||
{#if userWatchList?.length !== 0}
|
{#if userWatchList?.length !== 0}
|
||||||
@ -580,21 +503,20 @@
|
|||||||
</div>
|
</div>
|
||||||
<!--End Mobile Navbar-->
|
<!--End Mobile Navbar-->
|
||||||
|
|
||||||
<div
|
<div class="pt-14 sm:pt-0 w-full max-w-7xl px-3 sm:px-0">
|
||||||
class="pt-20 sm:pt-0 w-auto max-w-3xl lg:max-w-content 2xl:max-w-6xl px-3 sm:px-0"
|
|
||||||
>
|
|
||||||
<div
|
<div
|
||||||
class="md:flex md:justify-between md:divide-x md:divide-slate-800"
|
class="md:flex md:justify-between md:divide-x md:divide-slate-800"
|
||||||
>
|
>
|
||||||
<!-- Main content -->
|
<!-- Main content -->
|
||||||
<div class="pb-12 md:pb-20 w-full 2xl:max-w-5xl">
|
<div class="pb-12 md:pb-20 w-full max-w-7xl">
|
||||||
<div class="md:pr-6 lg:pr-10">
|
<div class="md:pr-6 lg:pr-10">
|
||||||
<!-----Start-Header-CandleChart-Indicators------>
|
<!-----Start-Header-CandleChart-Indicators------>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
class="m-auto pl-0 sm:pl-4 max-w-5xl overflow-hidden mb-5 md:mt-10"
|
class="m-auto pl-0 sm:pl-4 overflow-hidden mb-3 md:mt-10 xl:pr-7"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="hidden sm:flex flex-row w-full justify-between items-center pb-10"
|
class="hidden sm:flex flex-row w-full justify-between items-center"
|
||||||
>
|
>
|
||||||
<Markethour />
|
<Markethour />
|
||||||
|
|
||||||
@ -604,7 +526,7 @@
|
|||||||
<div class="flex flex-col ml-auto mr-2">
|
<div class="flex flex-col ml-auto mr-2">
|
||||||
{#if userWatchList?.length !== 0}
|
{#if userWatchList?.length !== 0}
|
||||||
<div
|
<div
|
||||||
class="flex-shrink-0 rounded-full hover:bg-white hover:bg-opacity-[0.02] transition ease-out w-12 h-12 relative bg-[#09090B] flex items-center justify-center"
|
class="flex-shrink-0 rounded-full sm:hover:bg-white sm:hover:bg-opacity-[0.02] transition ease-out w-12 h-12 relative bg-[#09090B] flex items-center justify-center"
|
||||||
>
|
>
|
||||||
<label
|
<label
|
||||||
for="addWatchListModal"
|
for="addWatchListModal"
|
||||||
@ -648,7 +570,7 @@
|
|||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
viewBox="0 0 16 16"
|
viewBox="0 0 16 16"
|
||||||
><path
|
><path
|
||||||
fill="#9DED1E"
|
fill="#fff"
|
||||||
d="M3.612 15.443c-.386.198-.824-.149-.746-.592l.83-4.73L.173 6.765c-.329-.314-.158-.888.283-.95l4.898-.696L7.538.792c.197-.39.73-.39.927 0l2.184 4.327l4.898.696c.441.062.612.636.282.95l-3.522 3.356l.83 4.73c.078.443-.36.79-.746.592L8 13.187l-4.389 2.256z"
|
d="M3.612 15.443c-.386.198-.824-.149-.746-.592l.83-4.73L.173 6.765c-.329-.314-.158-.888.283-.95l4.898-.696L7.538.792c.197-.39.73-.39.927 0l2.184 4.327l4.898.696c.441.062.612.636.282.95l-3.522 3.356l.83 4.73c.078.443-.36.79-.746.592L8 13.187l-4.389 2.256z"
|
||||||
/></svg
|
/></svg
|
||||||
>
|
>
|
||||||
@ -724,27 +646,16 @@
|
|||||||
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||||
<!-- svelte-ignore a11y-label-has-associated-control -->
|
<!-- svelte-ignore a11y-label-has-associated-control -->
|
||||||
|
|
||||||
<div class="flex items-center">
|
<div class="flex items-center w-full mt-3">
|
||||||
<div
|
<div
|
||||||
class="flex flex-row justify-start items-center mb-5 mt-2"
|
class="flex flex-row justify-start w-full items-center"
|
||||||
>
|
>
|
||||||
<div
|
|
||||||
class="rounded-full w-10 h-10 relative bg-[#141417] flex items-center justify-center border border-slate-800"
|
|
||||||
>
|
|
||||||
<img
|
|
||||||
style="clip-path: circle(50%);"
|
|
||||||
class="w-6 h-6"
|
|
||||||
src={`https://financialmodelingprep.com/image-stock/${$etfTicker?.toUpperCase()}.png`}
|
|
||||||
loading="lazy"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="flex flex-col items-start ml-2 sm:ml-3">
|
<div class="flex flex-col items-start ml-2 sm:ml-3">
|
||||||
<span class="text-xs text-blue-400">
|
<span class="text-md sm:text-lg text-blue-400">
|
||||||
{$etfTicker?.toUpperCase()}
|
{$etfTicker?.toUpperCase()}
|
||||||
</span>
|
</span>
|
||||||
<span
|
<span
|
||||||
class="text-sm sm:text-xl font-medium text-slate-100"
|
class="text-xl sm:text-2xl font-semibold sm:font-bold text-white"
|
||||||
>
|
>
|
||||||
{$displayCompanyName?.length > charNumber
|
{$displayCompanyName?.length > charNumber
|
||||||
? $displayCompanyName?.slice(0, charNumber) +
|
? $displayCompanyName?.slice(0, charNumber) +
|
||||||
@ -753,33 +664,6 @@
|
|||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="ml-auto sm:hidden">
|
|
||||||
<Markethour />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!--Start Trade-->
|
|
||||||
<!--
|
|
||||||
<div class="hidden sm:flex ml-auto">
|
|
||||||
{#if holdingShares !== 0 && data?.user}
|
|
||||||
|
|
||||||
<label for="{!data?.user ? 'userLogin' : userPortfolio?.length !== 0 ? 'typeOfTrade' : ''}" class="py-2 px-3 text-sm sm:text-[1rem] cursor-pointer mr-1 flex flex-row ease-in-out duration-100 rounded-full shadow-lg bg-[#09090B] hover:bg-[#313131] border border-slate-800 normal-case cursor-pointer items-center">
|
|
||||||
<svg class="w-5 h-5 mr-2" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path fill="white" d="M8 2.5a.5.5 0 0 0-1 0V7H2.5a.5.5 0 0 0 0 1H7v4.5a.5.5 0 0 0 1 0V8h4.5a.5.5 0 0 0 0-1H8z"/></svg>
|
|
||||||
<span class="text-white font-medium">
|
|
||||||
Portfolio
|
|
||||||
</span>
|
|
||||||
</label>
|
|
||||||
{:else}
|
|
||||||
<label for="{!data?.user ? 'userLogin' : userPortfolio?.length === 0 ? 'addPortfolio' : 'buyTradeModal'}" class="py-2 px-3 text-sm sm:text-[1rem] cursor-pointer mr-1 flex flex-row ease-in-out duration-100 rounded-full shadow-lg bg-[#09090B] hover:bg-[#313131] border border-slate-800 normal-case cursor-pointer items-center">
|
|
||||||
<svg class="w-5 h-5 mr-2" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path fill="white" d="M8 2.5a.5.5 0 0 0-1 0V7H2.5a.5.5 0 0 0 0 1H7v4.5a.5.5 0 0 0 1 0V8h4.5a.5.5 0 0 0 0-1H8z"/></svg>
|
|
||||||
<span class="text-white font-medium">
|
|
||||||
Portfolio
|
|
||||||
</span>
|
|
||||||
</label>
|
|
||||||
{/if}
|
|
||||||
</div>
|
|
||||||
-->
|
|
||||||
<!--End Trade-->
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-----End-Header-CandleChart-Indicators------>
|
<!-----End-Header-CandleChart-Indicators------>
|
||||||
@ -787,228 +671,104 @@
|
|||||||
<!--Start Ticker Section-->
|
<!--Start Ticker Section-->
|
||||||
|
|
||||||
<!--<div class="w-full max-w-3xl sm:max-w-2xl m-auto pt-2 pb-5 sm:pl-3 sticky z-20 bg-[#09090B]" style="top: {$screenWidth < 520 && $isScrollingUp ? '4rem' : '0rem'};">-->
|
<!--<div class="w-full max-w-3xl sm:max-w-2xl m-auto pt-2 pb-5 sm:pl-3 sticky z-20 bg-[#09090B]" style="top: {$screenWidth < 520 && $isScrollingUp ? '4rem' : '0rem'};">-->
|
||||||
<div
|
<nav
|
||||||
class="sm:ml-4 w-screen sm:w-full {$screenWidth < 640
|
class="sm:ml-4 border-b-[2px] overflow-x-scroll md:overflow-hidden whitespace-nowrap"
|
||||||
? 'overflow-auto scrollbar no-scrollbar'
|
|
||||||
: ''} mb-2"
|
|
||||||
>
|
>
|
||||||
<ul
|
<ul
|
||||||
class="pr-4 sm:pr-0 w-screen font-medium flex flex-row items-center bg-[#09090B] space-x-3 rtl:space-x-reverse py-2"
|
class="flex flex-row items-center w-full text-[1rem] text-white"
|
||||||
>
|
>
|
||||||
<li class="cursor-pointer flex flex-col items-center">
|
|
||||||
<a
|
<a
|
||||||
href={`/etf/${$etfTicker}`}
|
href={`/etf/${$etfTicker}`}
|
||||||
id="item1"
|
on:click={() => changeSection("overview")}
|
||||||
on:click={() => changeSection("overview", "item1")}
|
class="p-2 px-5 cursor-pointer {displaySection ===
|
||||||
class="px-2 text-sm sm:text-[1rem] font-medium text-gray-400 sm:hover:text-white {displaySection ===
|
|
||||||
'overview'
|
'overview'
|
||||||
? 'text-white '
|
? 'text-white bg-[#27272A] sm:hover:bg-opacity-[0.95]'
|
||||||
: 'bg-[#09090B]'}"
|
: 'text-gray-400 sm:hover:text-white sm:hover:bg-[#27272A] sm:hover:bg-opacity-[0.95]'}"
|
||||||
>
|
>
|
||||||
Overview
|
Overview
|
||||||
</a>
|
</a>
|
||||||
<div
|
|
||||||
class="{displaySection === 'overview'
|
|
||||||
? 'bg-[#75D377]'
|
|
||||||
: 'bg-[#09090B]'} mt-1 h-[3px] rounded-full w-[3.5rem]"
|
|
||||||
/>
|
|
||||||
</li>
|
|
||||||
<li class="cursor-pointer flex flex-col items-center">
|
|
||||||
<a
|
<a
|
||||||
href={`/etf/${$etfTicker}/stats`}
|
href={`/etf/${$etfTicker}/financials`}
|
||||||
id="item2"
|
on:click={() => changeSection("financials")}
|
||||||
on:click={() => changeSection("stats", "item2")}
|
class="p-2 px-5 cursor-pointer {displaySection ===
|
||||||
class="px-2 text-sm sm:text-[1rem] font-medium text-gray-400 sm:hover:text-white {displaySection ===
|
'financials'
|
||||||
'stats'
|
? 'text-white bg-[#27272A] sm:hover:bg-opacity-[0.95]'
|
||||||
? 'text-white '
|
: 'text-gray-400 sm:hover:text-white sm:hover:bg-[#27272A] sm:hover:bg-opacity-[0.95]'}"
|
||||||
: 'bg-[#09090B]'}"
|
|
||||||
>
|
>
|
||||||
Stats
|
Financials
|
||||||
</a>
|
</a>
|
||||||
<div
|
<a
|
||||||
class="{displaySection === 'stats'
|
href={`/etf/${$etfTicker}/statistics`}
|
||||||
? 'bg-[#75D377]'
|
on:click={() => changeSection("statistics")}
|
||||||
: 'bg-[#09090B]'} mt-1 h-[3px] rounded-full w-[2rem]"
|
class="p-2 px-5 cursor-pointer {displaySection ===
|
||||||
/>
|
'statistics'
|
||||||
</li>
|
? 'text-white bg-[#27272A] sm:hover:bg-opacity-[0.95]'
|
||||||
<li class="cursor-pointer flex flex-col items-center">
|
: 'text-gray-400 sm:hover:text-white sm:hover:bg-[#27272A] sm:hover:bg-opacity-[0.95]'}"
|
||||||
|
>Statistics</a
|
||||||
|
>
|
||||||
|
|
||||||
|
{#if ["amd", "save", "ba", "adbe", "nflx", "pltr", "msft", "meta", "tsla", "nvda", "aapl", "gme"]?.includes($etfTicker?.toLowerCase())}
|
||||||
|
<a
|
||||||
|
href={`/etf/${$etfTicker}/metrics`}
|
||||||
|
on:click={() => changeSection("metrics")}
|
||||||
|
class="p-2 px-5 cursor-pointer {displaySection ===
|
||||||
|
'metrics'
|
||||||
|
? 'text-white bg-[#27272A] sm:hover:bg-opacity-[0.95]'
|
||||||
|
: 'text-gray-400 sm:hover:text-white sm:hover:bg-[#27272A] sm:hover:bg-opacity-[0.95]'}"
|
||||||
|
>Metrics</a
|
||||||
|
>
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
{#if Object?.keys(data?.getAnalystRating ?? {})?.length > 0}
|
||||||
<a
|
<a
|
||||||
href={`/etf/${$etfTicker}/forecast`}
|
href={`/etf/${$etfTicker}/forecast`}
|
||||||
id="item10"
|
on:click={() => changeSection("forecast")}
|
||||||
on:click={() => changeSection("forecast", "item10")}
|
class="p-2 px-5 cursor-pointer {displaySection ===
|
||||||
class="px-2 text-sm sm:text-[1rem] font-medium text-gray-400 sm:hover:text-white {displaySection ===
|
|
||||||
'forecast'
|
'forecast'
|
||||||
? 'text-white '
|
? 'text-white bg-[#27272A] sm:hover:bg-opacity-[0.95]'
|
||||||
: 'bg-[#09090B]'}"
|
: 'text-gray-400 sm:hover:text-white sm:hover:bg-[#27272A] sm:hover:bg-opacity-[0.95]'}"
|
||||||
>
|
>
|
||||||
Forecast
|
Forecast
|
||||||
</a>
|
</a>
|
||||||
<div
|
{/if}
|
||||||
class="{displaySection === 'forecast'
|
|
||||||
? 'bg-[#75D377]'
|
|
||||||
: 'bg-[#09090B]'} mt-1 h-[3px] rounded-full w-[3rem]"
|
|
||||||
/>
|
|
||||||
</li>
|
|
||||||
<li class="cursor-pointer flex flex-col items-center">
|
|
||||||
<a
|
<a
|
||||||
href={`/etf/${$etfTicker}/options`}
|
href={`/etf/${$etfTicker}/options`}
|
||||||
id="item3"
|
on:click={() => changeSection("options")}
|
||||||
on:click={() => changeSection("options", "item3")}
|
class="p-2 px-5 cursor-pointer {displaySection ===
|
||||||
class="px-2 text-sm sm:text-[1rem] font-medium text-gray-400 sm:hover:text-white {displaySection ===
|
|
||||||
'options'
|
'options'
|
||||||
? 'text-white '
|
? 'text-white bg-[#27272A] sm:hover:bg-opacity-[0.95]'
|
||||||
: 'bg-[#09090B]'}"
|
: 'text-gray-400 sm:hover:text-white sm:hover:bg-[#27272A] sm:hover:bg-opacity-[0.95]'}"
|
||||||
>
|
>
|
||||||
Options
|
Options
|
||||||
</a>
|
</a>
|
||||||
<div
|
|
||||||
class="{displaySection === 'options'
|
|
||||||
? 'bg-[#75D377]'
|
|
||||||
: 'bg-[#09090B]'} mt-1 h-[3px] rounded-full w-[3rem]"
|
|
||||||
/>
|
|
||||||
</li>
|
|
||||||
<li class="cursor-pointer flex flex-col items-center">
|
|
||||||
<a
|
<a
|
||||||
href={`/etf/${$etfTicker}/holdings`}
|
href={`/etf/${$etfTicker}/insider`}
|
||||||
id="item4"
|
on:click={() => changeSection("insider")}
|
||||||
on:click={() => changeSection("holdings", "item4")}
|
class="p-2 px-5 cursor-pointer {displaySection ===
|
||||||
class="px-2 text-sm sm:text-[1rem] font-medium text-gray-400 sm:hover:text-white {displaySection ===
|
'insider'
|
||||||
'holdings'
|
? 'text-white bg-[#27272A] sm:hover:bg-opacity-[0.95]'
|
||||||
? 'text-white '
|
: 'text-gray-400 sm:hover:text-white sm:hover:bg-[#27272A] sm:hover:bg-opacity-[0.95]'}"
|
||||||
: 'bg-[#09090B]'}"
|
|
||||||
>
|
|
||||||
Holdings
|
|
||||||
</a>
|
|
||||||
<div
|
|
||||||
class="{displaySection === 'holdings'
|
|
||||||
? 'bg-[#75D377]'
|
|
||||||
: 'bg-[#09090B]'} mt-1 h-[3px] rounded-full w-[3rem]"
|
|
||||||
/>
|
|
||||||
</li>
|
|
||||||
<li class="cursor-pointer flex flex-col items-center">
|
|
||||||
<a
|
|
||||||
href={`/etf/${$etfTicker}/dividends`}
|
|
||||||
id="item5"
|
|
||||||
on:click={() => changeSection("dividends", "item5")}
|
|
||||||
class="px-2 text-sm sm:text-[1rem] font-medium text-gray-400 sm:hover:text-white {displaySection ===
|
|
||||||
'dividends'
|
|
||||||
? 'text-white '
|
|
||||||
: 'bg-[#09090B]'}"
|
|
||||||
>
|
|
||||||
Dividends
|
|
||||||
</a>
|
|
||||||
<div
|
|
||||||
class="{displaySection === 'dividends'
|
|
||||||
? 'bg-[#75D377]'
|
|
||||||
: 'bg-[#09090B]'} mt-1 h-[3px] rounded-full w-[3rem]"
|
|
||||||
/>
|
|
||||||
</li>
|
|
||||||
<li class="cursor-pointer flex flex-col items-center">
|
|
||||||
<a
|
|
||||||
href={`/etf/${$etfTicker}/congress-trading`}
|
|
||||||
id="item5"
|
|
||||||
on:click={() =>
|
|
||||||
changeSection("congress-trading", "item5")}
|
|
||||||
class="px-2 text-sm sm:text-[1rem] font-medium text-gray-400 sm:hover:text-white {displaySection ===
|
|
||||||
'congress-trading'
|
|
||||||
? 'text-white '
|
|
||||||
: 'bg-[#09090B]'}"
|
|
||||||
>
|
>
|
||||||
Insider
|
Insider
|
||||||
</a>
|
</a>
|
||||||
<div
|
|
||||||
class="{displaySection === 'congress-trading'
|
|
||||||
? 'bg-[#75D377]'
|
|
||||||
: 'bg-[#09090B]'} mt-1 h-[3px] rounded-full w-[3rem]"
|
|
||||||
/>
|
|
||||||
</li>
|
|
||||||
<li
|
|
||||||
class="cursor-pointer flex flex-col items-center pr-6"
|
|
||||||
>
|
|
||||||
<a
|
<a
|
||||||
href={`/etf/${$etfTicker}/news`}
|
href={`/etf/${$etfTicker}/dividends`}
|
||||||
id="item7"
|
on:click={() => changeSection("dividends")}
|
||||||
on:click={() => changeSection("news", "item7")}
|
class="p-2 px-5 cursor-pointer {displaySection ===
|
||||||
class="px-2 text-sm sm:text-[1rem] font-medium text-gray-400 sm:hover:text-white {displaySection ===
|
'dividends'
|
||||||
'news'
|
? 'text-white bg-[#27272A] sm:hover:bg-opacity-[0.95]'
|
||||||
? 'text-white '
|
: 'text-gray-400 sm:hover:text-white sm:hover:bg-[#27272A] sm:hover:bg-opacity-[0.95]'}"
|
||||||
: 'bg-[#09090B]'}"
|
|
||||||
>
|
>
|
||||||
News
|
Dividends
|
||||||
</a>
|
</a>
|
||||||
<div
|
|
||||||
class="{displaySection === 'news'
|
|
||||||
? 'bg-[#75D377]'
|
|
||||||
: 'bg-[#09090B]'} mt-1 h-[3px] rounded-full w-[2rem]"
|
|
||||||
/>
|
|
||||||
</li>
|
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</nav>
|
||||||
|
|
||||||
<!--Start-Main Content-->
|
<!--Start-Main Content-->
|
||||||
<slot />
|
<slot />
|
||||||
<!--End Main Content-->
|
<!--End Main Content-->
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<aside
|
|
||||||
class="hidden lg:block w-fit max-w-xl 2xl:w-[120px] m-auto sm:m-0 md:shrink-0 md:pt-10 pb-12 md:pb-20"
|
|
||||||
>
|
|
||||||
<div class="sm:pl-10">
|
|
||||||
<!--Start Company Info -->
|
|
||||||
|
|
||||||
<ETFProfileCard {data} {etfProfile} />
|
|
||||||
|
|
||||||
<div class={topHoldingList?.length === 0 ? "hidden" : ""}>
|
|
||||||
<TopHoldingCard {topHoldingList} />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div
|
|
||||||
class={dividendList?.history?.length === 0
|
|
||||||
? "hidden"
|
|
||||||
: ""}
|
|
||||||
>
|
|
||||||
<DividendCard {dividendList} />
|
|
||||||
</div>
|
|
||||||
<div class={similarTicker.length === 0 ? "hidden" : ""}>
|
|
||||||
<SimilarETFCard {similarTicker} />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!--End Company Info -->
|
|
||||||
</div>
|
|
||||||
</aside>
|
|
||||||
<!--
|
|
||||||
{#if $screenWidth < 640 && MobileETFNavbar}
|
|
||||||
<MobileETFNavbar
|
|
||||||
holdingShares={holdingShares}
|
|
||||||
userPortfolio={userPortfolio}
|
|
||||||
etfProfile={etfProfile}
|
|
||||||
similarTicker={similarTicker}
|
|
||||||
topHoldingList={topHoldingList}
|
|
||||||
dividendList={dividendList}
|
|
||||||
data={data}
|
|
||||||
/>
|
|
||||||
{/if}
|
|
||||||
-->
|
|
||||||
|
|
||||||
<!--
|
|
||||||
<div class="sm:hidden fixed z-20 bottom-8 sm:bottom-10 right-5">
|
|
||||||
<div class="h-full mx-auto">
|
|
||||||
<div class="flex items-center justify-end">
|
|
||||||
{#if holdingShares !== 0 && data?.user}
|
|
||||||
<label for="{!data?.user ? 'userLogin' : userPortfolio?.length !== 0 ? 'typeOfTrade' : ''}" class="inline-flex items-center justify-center w-32 h-11 border border-[#000] ring-[#000] bg-[#0DDE00] text-[0.95rem] font-medium rounded-full text-[#09090B]">
|
|
||||||
Invest
|
|
||||||
</label>
|
|
||||||
{:else}
|
|
||||||
<label for="{!data?.user ? 'userLogin' : userPortfolio?.length === 0 ? 'addPortfolio' : 'buyTradeModal'}"
|
|
||||||
class="inline-flex items-center justify-center w-32 h-11 border border-[#000] ring-[#000] bg-[#0DDE00] text-[0.95rem] font-medium rounded-full text-[#09090B]">
|
|
||||||
Invest
|
|
||||||
</label>
|
|
||||||
{/if}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
-->
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -1024,135 +784,11 @@
|
|||||||
{/if}
|
{/if}
|
||||||
<!--End Login Modal-->
|
<!--End Login Modal-->
|
||||||
|
|
||||||
<!--
|
<!--Start SellTrade Modal-->
|
||||||
{#if BuyTrade}
|
|
||||||
<BuyTrade
|
|
||||||
data = {data}
|
|
||||||
holdingShares={holdingShares}
|
|
||||||
availableCash = {availableCash}
|
|
||||||
/>
|
|
||||||
{/if}
|
|
||||||
|
|
||||||
{#if SellTrade}
|
|
||||||
<SellTrade
|
|
||||||
data = {data}
|
|
||||||
holdingShares={holdingShares}
|
|
||||||
availableCash = {availableCash}
|
|
||||||
/>
|
|
||||||
{/if}
|
|
||||||
|
|
||||||
{#if AddPortfolio}
|
|
||||||
<AddPortfolio data={data}/>
|
|
||||||
{/if}
|
|
||||||
-->
|
|
||||||
|
|
||||||
{#if PriceAlert}
|
{#if PriceAlert}
|
||||||
<PriceAlert {data} />
|
<PriceAlert {data} />
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<!--Start Type of Trade-->
|
|
||||||
|
|
||||||
<input type="checkbox" id="typeOfTrade" class="modal-toggle" />
|
|
||||||
|
|
||||||
<dialog
|
|
||||||
id="typeOfTrade"
|
|
||||||
class="modal modal-bottom sm:modal-middle overflow-hidden"
|
|
||||||
>
|
|
||||||
<label
|
|
||||||
for="typeOfTrade"
|
|
||||||
class="cursor-pointer modal-backdrop bg-[#fff] bg-opacity-[0.08]"
|
|
||||||
></label>
|
|
||||||
|
|
||||||
<div class="modal-box w-full bg-[#000] border border-slate-600 pb-10">
|
|
||||||
<div class="flex flex-col">
|
|
||||||
<div class="text-white text-md flex flex-col flex-shrink-0">
|
|
||||||
<div class="rounded-full w-10 h-10 relative bg-gray-900 mb-2">
|
|
||||||
<img
|
|
||||||
class="rounded-full w-6 h-6 absolute inset-1/2 transform -translate-x-1/2 -translate-y-1/2"
|
|
||||||
src={`https://financialmodelingprep.com/image-stock/${$etfTicker}.png`}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<span class="mb-1">
|
|
||||||
{$displayCompanyName?.length > 30
|
|
||||||
? $displayCompanyName?.slice(0, 30) + "..."
|
|
||||||
: $displayCompanyName}
|
|
||||||
</span>
|
|
||||||
<div class="flex flex-row items-center mb-10">
|
|
||||||
<span class="mb-1 text-sm font-medium">
|
|
||||||
Current Price: ${$currentPortfolioPrice}
|
|
||||||
</span>
|
|
||||||
<span class="text-blue-400 text-sm font-medium ml-auto">
|
|
||||||
Holding Shares: {holdingShares}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="text-white">
|
|
||||||
<h3 class="font-bold text-2xl mb-5">Type of Trade</h3>
|
|
||||||
|
|
||||||
<ul class="menu dropdown-content text-white bg-[#000] rounded -ml-6">
|
|
||||||
<li class="mb-3">
|
|
||||||
<label
|
|
||||||
for="typeOfTrade"
|
|
||||||
on:click={() => handleTypeOfTrade("buy")}
|
|
||||||
class="cursor-pointer flex flex-row justify-start items-center"
|
|
||||||
>
|
|
||||||
<div class="rounded-full w-10 h-10 relative bg-gray-800">
|
|
||||||
<svg
|
|
||||||
class="h-5 w-5 absolute inset-1/2 transform -translate-x-1/2 -translate-y-1/2"
|
|
||||||
viewBox="0 0 16 16"
|
|
||||||
version="1.1"
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
|
||||||
fill="green"
|
|
||||||
><g id="SVGRepo_bgCarrier" stroke-width="0"></g><g
|
|
||||||
id="SVGRepo_tracerCarrier"
|
|
||||||
stroke-linecap="round"
|
|
||||||
stroke-linejoin="round"
|
|
||||||
></g><g id="SVGRepo_iconCarrier">
|
|
||||||
<rect width="16" height="16" id="icon-bound" fill="none"
|
|
||||||
></rect>
|
|
||||||
<path
|
|
||||||
d="M0,11h11.2l-2.6,2.6L10,15l6-6H0V11z M4.8,5l2.6-2.6L6,1L0,7h16V5H4.8z"
|
|
||||||
></path>
|
|
||||||
</g></svg
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
<span class="ml-1 text-white text-lg font-medium"
|
|
||||||
>Buy {$etfTicker} Shares</span
|
|
||||||
>
|
|
||||||
</label>
|
|
||||||
</li>
|
|
||||||
<li class="mb-3">
|
|
||||||
<label
|
|
||||||
for="typeOfTrade"
|
|
||||||
on:click={() => handleTypeOfTrade("sell")}
|
|
||||||
class="cursor-pointer flex flex-row justify-start items-center"
|
|
||||||
>
|
|
||||||
<div class="rounded-full w-10 h-10 relative bg-gray-800">
|
|
||||||
<svg
|
|
||||||
class="h-5 w-5 absolute inset-1/2 transform -translate-x-1/2 -translate-y-1/2"
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
viewBox="0 0 24 24"
|
|
||||||
><path
|
|
||||||
fill="red"
|
|
||||||
d="M14.25 21.4q-.575.575-1.425.575T11.4 21.4l-8.8-8.8q-.275-.275-.438-.65T2 11.15V4q0-.825.588-1.413T4 2h7.15q.425 0 .8.163t.65.437l8.8 8.825q.575.575.575 1.413T21.4 14.25l-7.15 7.15ZM6.5 8q.625 0 1.063-.438T8 6.5q0-.625-.438-1.063T6.5 5q-.625 0-1.063.438T5 6.5q0 .625.438 1.063T6.5 8Z"
|
|
||||||
/></svg
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
<span class="ml-1 text-white text-lg font-medium">
|
|
||||||
Sell {$etfTicker} Shares
|
|
||||||
</span>
|
|
||||||
</label>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</dialog>
|
|
||||||
|
|
||||||
<!--End Type of Trade-->
|
|
||||||
|
|
||||||
<!--Start Add Watchlist Modal-->
|
<!--Start Add Watchlist Modal-->
|
||||||
<input type="checkbox" id="addWatchListModal" class="modal-toggle" />
|
<input type="checkbox" id="addWatchListModal" class="modal-toggle" />
|
||||||
|
|
||||||
@ -1222,7 +858,6 @@
|
|||||||
<title>ic_fluent_checkmark_circle_48_filled</title>
|
<title>ic_fluent_checkmark_circle_48_filled</title>
|
||||||
<desc>Created with Sketch.</desc>
|
<desc>Created with Sketch.</desc>
|
||||||
<g
|
<g
|
||||||
id="🔍-Product-Icons"
|
|
||||||
stroke="none"
|
stroke="none"
|
||||||
stroke-width="1"
|
stroke-width="1"
|
||||||
fill="none"
|
fill="none"
|
||||||
@ -1235,7 +870,6 @@
|
|||||||
>
|
>
|
||||||
<path
|
<path
|
||||||
d="M24,4 C35.045695,4 44,12.954305 44,24 C44,35.045695 35.045695,44 24,44 C12.954305,44 4,35.045695 4,24 C4,12.954305 12.954305,4 24,4 Z M32.6338835,17.6161165 C32.1782718,17.1605048 31.4584514,17.1301307 30.9676119,17.5249942 L30.8661165,17.6161165 L20.75,27.732233 L17.1338835,24.1161165 C16.6457281,23.6279612 15.8542719,23.6279612 15.3661165,24.1161165 C14.9105048,24.5717282 14.8801307,25.2915486 15.2749942,25.7823881 L15.3661165,25.8838835 L19.8661165,30.3838835 C20.3217282,30.8394952 21.0415486,30.8698693 21.5323881,30.4750058 L21.6338835,30.3838835 L32.6338835,19.3838835 C33.1220388,18.8957281 33.1220388,18.1042719 32.6338835,17.6161165 Z"
|
d="M24,4 C35.045695,4 44,12.954305 44,24 C44,35.045695 35.045695,44 24,44 C12.954305,44 4,35.045695 4,24 C4,12.954305 12.954305,4 24,4 Z M32.6338835,17.6161165 C32.1782718,17.1605048 31.4584514,17.1301307 30.9676119,17.5249942 L30.8661165,17.6161165 L20.75,27.732233 L17.1338835,24.1161165 C16.6457281,23.6279612 15.8542719,23.6279612 15.3661165,24.1161165 C14.9105048,24.5717282 14.8801307,25.2915486 15.2749942,25.7823881 L15.3661165,25.8838835 L19.8661165,30.3838835 C20.3217282,30.8394952 21.0415486,30.8698693 21.5323881,30.4750058 L21.6338835,30.3838835 L32.6338835,19.3838835 C33.1220388,18.8957281 33.1220388,18.1042719 32.6338835,17.6161165 Z"
|
||||||
id="🎨-Color"
|
|
||||||
>
|
>
|
||||||
</path>
|
</path>
|
||||||
</g>
|
</g>
|
||||||
|
|||||||
@ -1,11 +1,11 @@
|
|||||||
import {
|
import {
|
||||||
displayCompanyName,
|
|
||||||
etfTicker,
|
|
||||||
assetType,
|
|
||||||
isOpen,
|
isOpen,
|
||||||
isAfterMarketClose,
|
isAfterMarketClose,
|
||||||
isBeforeMarketOpen,
|
isBeforeMarketOpen,
|
||||||
isWeekend,
|
isWeekend,
|
||||||
|
etfTicker,
|
||||||
|
displayCompanyName,
|
||||||
|
assetType,
|
||||||
} from "$lib/store";
|
} from "$lib/store";
|
||||||
|
|
||||||
const checkMarketHour = async () => {
|
const checkMarketHour = async () => {
|
||||||
@ -52,9 +52,9 @@ const checkMarketHour = async () => {
|
|||||||
isAfterMarketClose.set(isAfterMarketCloseValue);
|
isAfterMarketClose.set(isAfterMarketCloseValue);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const load = async ({ params, data }) => {
|
export const load = async ({ data }) => {
|
||||||
etfTicker.update((value) => params.tickerID?.toUpperCase());
|
etfTicker.set(data?.getParams?.toUpperCase());
|
||||||
assetType.update((value) => "etf");
|
assetType.set("etf");
|
||||||
displayCompanyName.update((value) => data?.companyName);
|
displayCompanyName.set(data?.companyName);
|
||||||
await checkMarketHour();
|
await checkMarketHour();
|
||||||
};
|
};
|
||||||
|
|||||||
@ -34,10 +34,10 @@ export const actions = {
|
|||||||
error(err.status, err.message);
|
error(err.status, err.message);
|
||||||
}
|
}
|
||||||
|
|
||||||
redirect(301, "/");
|
redirect(302, "/");
|
||||||
},
|
},
|
||||||
|
|
||||||
register: async ({ locals, request, params }) => {
|
register: async ({ locals, request }) => {
|
||||||
const { formData, errors } = await validateData(
|
const { formData, errors } = await validateData(
|
||||||
await request.formData(),
|
await request.formData(),
|
||||||
registerUserSchema,
|
registerUserSchema,
|
||||||
@ -59,6 +59,7 @@ await locals.pb?.collection('users').update(
|
|||||||
'tier': 'Pro', //Give new users a free trial for the Pro Subscription
|
'tier': 'Pro', //Give new users a free trial for the Pro Subscription
|
||||||
});
|
});
|
||||||
*/
|
*/
|
||||||
|
|
||||||
await locals.pb.collection("users").requestVerification(formData.email);
|
await locals.pb.collection("users").requestVerification(formData.email);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log("Error: ", err);
|
console.log("Error: ", err);
|
||||||
@ -74,7 +75,7 @@ await locals.pb?.collection('users').update(
|
|||||||
error(err.status, err.message);
|
error(err.status, err.message);
|
||||||
}
|
}
|
||||||
|
|
||||||
redirect(303, "/etf/" + params.tickerID);
|
redirect(303, "/");
|
||||||
},
|
},
|
||||||
|
|
||||||
oauth2: async ({ url, locals, request, cookies, params }) => {
|
oauth2: async ({ url, locals, request, cookies, params }) => {
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -12,7 +12,7 @@
|
|||||||
wsBidPrice,
|
wsBidPrice,
|
||||||
wsAskPrice,
|
wsAskPrice,
|
||||||
currentPortfolioPrice,
|
currentPortfolioPrice,
|
||||||
stockTicker,
|
etfTicker,
|
||||||
displayCompanyName,
|
displayCompanyName,
|
||||||
isOpen,
|
isOpen,
|
||||||
isBeforeMarketOpen,
|
isBeforeMarketOpen,
|
||||||
@ -156,7 +156,7 @@
|
|||||||
//==========================//
|
//==========================//
|
||||||
|
|
||||||
$: {
|
$: {
|
||||||
if ($stockTicker && typeof window !== "undefined") {
|
if ($etfTicker && typeof window !== "undefined") {
|
||||||
// add a check to see if running on client-side
|
// add a check to see if running on client-side
|
||||||
if ($realtimePrice !== null && $realtimePrice !== 0) {
|
if ($realtimePrice !== null && $realtimePrice !== 0) {
|
||||||
$realtimePrice =
|
$realtimePrice =
|
||||||
@ -291,7 +291,7 @@
|
|||||||
let maxPrice = [];
|
let maxPrice = [];
|
||||||
|
|
||||||
async function historicalPrice(timePeriod: string) {
|
async function historicalPrice(timePeriod: string) {
|
||||||
const cachedData = getCache($stockTicker, "historicalPrice" + timePeriod);
|
const cachedData = getCache($etfTicker, "historicalPrice" + timePeriod);
|
||||||
if (cachedData) {
|
if (cachedData) {
|
||||||
switch (timePeriod) {
|
switch (timePeriod) {
|
||||||
case "one-week":
|
case "one-week":
|
||||||
@ -316,7 +316,7 @@
|
|||||||
output = null;
|
output = null;
|
||||||
|
|
||||||
const postData = {
|
const postData = {
|
||||||
ticker: $stockTicker,
|
ticker: $etfTicker,
|
||||||
timePeriod: timePeriod,
|
timePeriod: timePeriod,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -362,7 +362,7 @@
|
|||||||
default:
|
default:
|
||||||
console.log(`Unsupported time period: ${timePeriod}`);
|
console.log(`Unsupported time period: ${timePeriod}`);
|
||||||
}
|
}
|
||||||
setCache($stockTicker, mappedData, "historicalPrice" + timePeriod);
|
setCache($etfTicker, mappedData, "historicalPrice" + timePeriod);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log(e);
|
console.log(e);
|
||||||
}
|
}
|
||||||
@ -423,7 +423,7 @@
|
|||||||
|
|
||||||
async function getPrePostQuote() {
|
async function getPrePostQuote() {
|
||||||
if (!$isOpen) {
|
if (!$isOpen) {
|
||||||
const postData = { ticker: $stockTicker, path: "pre-post-quote" };
|
const postData = { ticker: $etfTicker, path: "pre-post-quote" };
|
||||||
const response = await fetch("/api/ticker-data", {
|
const response = await fetch("/api/ticker-data", {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
@ -636,7 +636,7 @@
|
|||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
},
|
},
|
||||||
body: JSON.stringify({ ticker: $stockTicker, timePeriod: timePeriod }),
|
body: JSON.stringify({ ticker: $etfTicker, timePeriod: timePeriod }),
|
||||||
});
|
});
|
||||||
|
|
||||||
exportList = await response.json();
|
exportList = await response.json();
|
||||||
@ -670,7 +670,7 @@
|
|||||||
const a = document.createElement("a");
|
const a = document.createElement("a");
|
||||||
a.setAttribute("hidden", "");
|
a.setAttribute("hidden", "");
|
||||||
a.setAttribute("href", url);
|
a.setAttribute("href", url);
|
||||||
a.setAttribute("download", `${$stockTicker}_${timePeriod}.csv`);
|
a.setAttribute("download", `${$etfTicker}_${timePeriod}.csv`);
|
||||||
document.body.appendChild(a);
|
document.body.appendChild(a);
|
||||||
a.click();
|
a.click();
|
||||||
document.body.removeChild(a);
|
document.body.removeChild(a);
|
||||||
@ -738,7 +738,7 @@
|
|||||||
});
|
});
|
||||||
|
|
||||||
$: {
|
$: {
|
||||||
if ($stockTicker && typeof window !== "undefined") {
|
if ($etfTicker && typeof window !== "undefined") {
|
||||||
// add a check to see if running on client-side
|
// add a check to see if running on client-side
|
||||||
shouldUpdatePriceChart.set(false);
|
shouldUpdatePriceChart.set(false);
|
||||||
oneDayPrice = [];
|
oneDayPrice = [];
|
||||||
@ -769,21 +769,21 @@
|
|||||||
<meta name="viewport" content="width=device-width" />
|
<meta name="viewport" content="width=device-width" />
|
||||||
<title>
|
<title>
|
||||||
{$numberOfUnreadNotification > 0 ? `(${$numberOfUnreadNotification})` : ""}
|
{$numberOfUnreadNotification > 0 ? `(${$numberOfUnreadNotification})` : ""}
|
||||||
{$displayCompanyName} ({$stockTicker}) Stock Price, Quote & News · stocknear
|
{$displayCompanyName} ({$etfTicker}) Stock Price, Quote & News · stocknear
|
||||||
</title>
|
</title>
|
||||||
|
|
||||||
<meta
|
<meta
|
||||||
name="description"
|
name="description"
|
||||||
content={`Get a real-time ${$displayCompanyName} (${$stockTicker}) stock chart, price quote with breaking news, financials, statistics, charts and more.`}
|
content={`Get a real-time ${$displayCompanyName} (${$etfTicker}) stock chart, price quote with breaking news, financials, statistics, charts and more.`}
|
||||||
/>
|
/>
|
||||||
<!-- Other meta tags -->
|
<!-- Other meta tags -->
|
||||||
<meta
|
<meta
|
||||||
property="og:title"
|
property="og:title"
|
||||||
content={`${$displayCompanyName} (${$stockTicker}) Stock Price, Quote & News · stocknear`}
|
content={`${$displayCompanyName} (${$etfTicker}) Stock Price, Quote & News · stocknear`}
|
||||||
/>
|
/>
|
||||||
<meta
|
<meta
|
||||||
property="og:description"
|
property="og:description"
|
||||||
content={`Get a real-time ${$displayCompanyName} (${$stockTicker}) stock chart, price quote with breaking news, financials, statistics, charts and more.`}
|
content={`Get a real-time ${$displayCompanyName} (${$etfTicker}) stock chart, price quote with breaking news, financials, statistics, charts and more.`}
|
||||||
/>
|
/>
|
||||||
<!--<meta property="og:image" content="https://stocknear-pocketbase.s3.amazonaws.com/logo/meta_logo.jpg"/>-->
|
<!--<meta property="og:image" content="https://stocknear-pocketbase.s3.amazonaws.com/logo/meta_logo.jpg"/>-->
|
||||||
<meta property="og:type" content="website" />
|
<meta property="og:type" content="website" />
|
||||||
@ -793,11 +793,11 @@
|
|||||||
<meta name="twitter:card" content="summary_large_image" />
|
<meta name="twitter:card" content="summary_large_image" />
|
||||||
<meta
|
<meta
|
||||||
name="twitter:title"
|
name="twitter:title"
|
||||||
content={`${$displayCompanyName} (${$stockTicker}) Stock Price, Quote & News · stocknear`}
|
content={`${$displayCompanyName} (${$etfTicker}) Stock Price, Quote & News · stocknear`}
|
||||||
/>
|
/>
|
||||||
<meta
|
<meta
|
||||||
name="twitter:description"
|
name="twitter:description"
|
||||||
content={`Get a real-time ${$displayCompanyName} (${$stockTicker}) stock chart, price quote with breaking news, financials, statistics, charts and more.`}
|
content={`Get a real-time ${$displayCompanyName} (${$etfTicker}) stock chart, price quote with breaking news, financials, statistics, charts and more.`}
|
||||||
/>
|
/>
|
||||||
<!--<meta name="twitter:image" content="https://stocknear-pocketbase.s3.amazonaws.com/logo/meta_logo.jpg"/>-->
|
<!--<meta name="twitter:image" content="https://stocknear-pocketbase.s3.amazonaws.com/logo/meta_logo.jpg"/>-->
|
||||||
<!-- Add more Twitter meta tags as needed -->
|
<!-- Add more Twitter meta tags as needed -->
|
||||||
@ -907,7 +907,7 @@
|
|||||||
<div
|
<div
|
||||||
class="hidden sm:flex flex-row items-center pl-1 sm:pl-6 w-full mt-4"
|
class="hidden sm:flex flex-row items-center pl-1 sm:pl-6 w-full mt-4"
|
||||||
>
|
>
|
||||||
{#if !$stockTicker?.includes(".")}
|
{#if !$etfTicker?.includes(".")}
|
||||||
<DropdownMenu.Root>
|
<DropdownMenu.Root>
|
||||||
<DropdownMenu.Trigger asChild let:builder>
|
<DropdownMenu.Trigger asChild let:builder>
|
||||||
<Button
|
<Button
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user