update etf page
This commit is contained in:
parent
6eb6b661ce
commit
89ae8e8e62
@ -201,17 +201,11 @@
|
|||||||
if (event.ctrlKey && event.key === "k") {
|
if (event.ctrlKey && event.key === "k") {
|
||||||
const keyboardSearch = document.getElementById("combobox-input");
|
const keyboardSearch = document.getElementById("combobox-input");
|
||||||
keyboardSearch?.dispatchEvent(new MouseEvent("click"));
|
keyboardSearch?.dispatchEvent(new MouseEvent("click"));
|
||||||
|
inputValue = "";
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleEscape = (event) => {
|
|
||||||
if (event.key === "Escape") {
|
|
||||||
// Escape key is pressed, close the modal
|
|
||||||
searchBarModalChecked = false;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
function saveRecentTicker() {
|
function saveRecentTicker() {
|
||||||
try {
|
try {
|
||||||
// Save the version along with the rules
|
// Save the version along with the rules
|
||||||
@ -233,10 +227,8 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
window.addEventListener("keydown", handleControlK);
|
window.addEventListener("keydown", handleControlK);
|
||||||
window.addEventListener("keydown", handleEscape);
|
|
||||||
return () => {
|
return () => {
|
||||||
window.removeEventListener("keydown", handleControlK);
|
window.removeEventListener("keydown", handleControlK);
|
||||||
window.removeEventListener("keydown", handleEscape);
|
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -319,6 +311,7 @@
|
|||||||
<Combobox.Input
|
<Combobox.Input
|
||||||
id="combobox-input"
|
id="combobox-input"
|
||||||
on:input={search}
|
on:input={search}
|
||||||
|
on:click={() => (inputValue = "")}
|
||||||
class="grow rounded-sm border border-gray-600 py-2 pl-9 text-[1rem] placeholder-gray-400 focus:border-default focus:shadow-lg focus:outline-none focus:ring-0 tiny:pl-8 xs:pl-10 text-white md:py-2 w-full bg-secondary focus:bg-secondary"
|
class="grow rounded-sm border border-gray-600 py-2 pl-9 text-[1rem] placeholder-gray-400 focus:border-default focus:shadow-lg focus:outline-none focus:ring-0 tiny:pl-8 xs:pl-10 text-white md:py-2 w-full bg-secondary focus:bg-secondary"
|
||||||
placeholder="Company or stock symbol..."
|
placeholder="Company or stock symbol..."
|
||||||
aria-label="Company or stock symbol..."
|
aria-label="Company or stock symbol..."
|
||||||
|
|||||||
@ -676,8 +676,8 @@
|
|||||||
on:click={() => changeSection("overview")}
|
on:click={() => changeSection("overview")}
|
||||||
class="p-2 px-5 cursor-pointer {displaySection ===
|
class="p-2 px-5 cursor-pointer {displaySection ===
|
||||||
'overview'
|
'overview'
|
||||||
? 'text-white bg-primary sm:hover:bg-opacity-[0.95]'
|
? 'text-white bg-secondary sm:hover:bg-opacity-[0.95]'
|
||||||
: 'text-gray-400 sm:hover:text-white sm:hover:bg-primary sm:hover:bg-opacity-[0.95]'}"
|
: 'text-gray-400 sm:hover:text-white sm:hover:bg-secondary sm:hover:bg-opacity-[0.95]'}"
|
||||||
>
|
>
|
||||||
Overview
|
Overview
|
||||||
</a>
|
</a>
|
||||||
@ -686,8 +686,8 @@
|
|||||||
on:click={() => changeSection("holdings")}
|
on:click={() => changeSection("holdings")}
|
||||||
class="p-2 px-5 cursor-pointer {displaySection ===
|
class="p-2 px-5 cursor-pointer {displaySection ===
|
||||||
'holdings'
|
'holdings'
|
||||||
? 'text-white bg-primary sm:hover:bg-opacity-[0.95]'
|
? 'text-white bg-secondary sm:hover:bg-opacity-[0.95]'
|
||||||
: 'text-gray-400 sm:hover:text-white sm:hover:bg-primary sm:hover:bg-opacity-[0.95]'}"
|
: 'text-gray-400 sm:hover:text-white sm:hover:bg-secondary sm:hover:bg-opacity-[0.95]'}"
|
||||||
>
|
>
|
||||||
Holdings
|
Holdings
|
||||||
</a>
|
</a>
|
||||||
@ -697,8 +697,8 @@
|
|||||||
on:click={() => changeSection("options")}
|
on:click={() => changeSection("options")}
|
||||||
class="p-2 px-5 cursor-pointer {displaySection ===
|
class="p-2 px-5 cursor-pointer {displaySection ===
|
||||||
'options'
|
'options'
|
||||||
? 'text-white bg-primary sm:hover:bg-opacity-[0.95]'
|
? 'text-white bg-secondary sm:hover:bg-opacity-[0.95]'
|
||||||
: 'text-gray-400 sm:hover:text-white sm:hover:bg-primary sm:hover:bg-opacity-[0.95]'}"
|
: 'text-gray-400 sm:hover:text-white sm:hover:bg-secondary sm:hover:bg-opacity-[0.95]'}"
|
||||||
>
|
>
|
||||||
Options
|
Options
|
||||||
</a>
|
</a>
|
||||||
@ -707,8 +707,8 @@
|
|||||||
on:click={() => changeSection("insider")}
|
on:click={() => changeSection("insider")}
|
||||||
class="p-2 px-5 cursor-pointer {displaySection ===
|
class="p-2 px-5 cursor-pointer {displaySection ===
|
||||||
'insider'
|
'insider'
|
||||||
? 'text-white bg-primary sm:hover:bg-opacity-[0.95]'
|
? 'text-white bg-secondary sm:hover:bg-opacity-[0.95]'
|
||||||
: 'text-gray-400 sm:hover:text-white sm:hover:bg-primary sm:hover:bg-opacity-[0.95]'}"
|
: 'text-gray-400 sm:hover:text-white sm:hover:bg-secondary sm:hover:bg-opacity-[0.95]'}"
|
||||||
>
|
>
|
||||||
Insider
|
Insider
|
||||||
</a>
|
</a>
|
||||||
@ -717,8 +717,8 @@
|
|||||||
on:click={() => changeSection("dividends")}
|
on:click={() => changeSection("dividends")}
|
||||||
class="p-2 px-5 cursor-pointer {displaySection ===
|
class="p-2 px-5 cursor-pointer {displaySection ===
|
||||||
'dividends'
|
'dividends'
|
||||||
? 'text-white bg-primary sm:hover:bg-opacity-[0.95]'
|
? 'text-white bg-secondary sm:hover:bg-opacity-[0.95]'
|
||||||
: 'text-gray-400 sm:hover:text-white sm:hover:bg-primary sm:hover:bg-opacity-[0.95]'}"
|
: 'text-gray-400 sm:hover:text-white sm:hover:bg-secondary sm:hover:bg-opacity-[0.95]'}"
|
||||||
>
|
>
|
||||||
Dividends
|
Dividends
|
||||||
</a>
|
</a>
|
||||||
|
|||||||
@ -1,11 +1,11 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
import { etfTicker } from "$lib/store";
|
||||||
import ArrowLogo from "lucide-svelte/icons/move-up-right";
|
import ArrowLogo from "lucide-svelte/icons/move-up-right";
|
||||||
|
import { formatDate } from "$lib/utils";
|
||||||
|
|
||||||
export let data;
|
export let data;
|
||||||
|
|
||||||
const similarStocks = data?.getSimilarStocks?.sort(
|
let newsList = data?.getNews ?? [];
|
||||||
(a, b) => b?.dividendYield - a?.dividendYield,
|
|
||||||
);
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<section class="w-auto overflow-hidden min-h-screen">
|
<section class="w-auto overflow-hidden min-h-screen">
|
||||||
@ -40,44 +40,29 @@
|
|||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
{#if similarStocks?.length > 0}
|
{#if newsList?.length !== 0}
|
||||||
<div
|
<div
|
||||||
class="w-full p-2 text-white border border-gray-600 rounded-md h-fit pb-4 mt-4 cursor-pointer"
|
class="w-full sm:hover:text-white text-white border border-gray-600 bg-primary rounded-md h-fit pb-4 mt-4 cursor-pointer"
|
||||||
>
|
>
|
||||||
<h3 class="p-2 pt-4 text-xl font-semibold">Related Stocks</h3>
|
<div class="p-4 text-sm">
|
||||||
<table class="table table-sm table-compact w-full text-white">
|
<h3 class="text-lg text-white font-semibold mb-3">
|
||||||
<thead class="text-white"
|
{$etfTicker} News
|
||||||
><tr
|
</h3>
|
||||||
><th
|
<ul class="text-white">
|
||||||
class="whitespace-nowrap border-b font-semibold text-sm text-left"
|
{#each newsList?.slice(0, 10) as item}
|
||||||
>Company</th
|
<li class="mb-3 last:mb-1">
|
||||||
>
|
{formatDate(item?.publishedDate)} ·
|
||||||
<th
|
<a
|
||||||
class="whitespace-nowrap border-b font-semibold text-sm text-right"
|
class="sm:hover:text-white text-blue-400"
|
||||||
>Dividend Yield</th
|
href={item?.url}
|
||||||
></tr
|
target="_blank"
|
||||||
></thead
|
rel="noopener noreferrer nofollow">{item?.title}</a
|
||||||
>
|
|
||||||
<tbody>
|
|
||||||
{#each similarStocks?.slice(0, 8) as item}
|
|
||||||
<tr class="border-gray-600 border-b"
|
|
||||||
><td class="text-left"
|
|
||||||
><a
|
|
||||||
href={`/stocks/${item?.symbol}`}
|
|
||||||
class="sm:hover:text-white text-blue-400"
|
|
||||||
>{item?.symbol}</a
|
|
||||||
></td
|
|
||||||
>
|
>
|
||||||
<td class="text-right cursor-normal"
|
- {item?.site}
|
||||||
>{item?.dividendYield !== null &&
|
</li>
|
||||||
item?.dividendYield !== undefined
|
|
||||||
? item?.dividendYield + "%"
|
|
||||||
: "n/a"}</td
|
|
||||||
>
|
|
||||||
</tr>
|
|
||||||
{/each}
|
{/each}
|
||||||
</tbody>
|
</ul>
|
||||||
</table>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
</aside>
|
</aside>
|
||||||
|
|||||||
@ -11,6 +11,8 @@
|
|||||||
import { LineChart, BarChart } from "echarts/charts";
|
import { LineChart, BarChart } from "echarts/charts";
|
||||||
import { GridComponent, TooltipComponent } from "echarts/components";
|
import { GridComponent, TooltipComponent } from "echarts/components";
|
||||||
import { CanvasRenderer } from "echarts/renderers";
|
import { CanvasRenderer } from "echarts/renderers";
|
||||||
|
import Infobox from "$lib/components/Infobox.svelte";
|
||||||
|
|
||||||
use([LineChart, BarChart, TooltipComponent, GridComponent, CanvasRenderer]);
|
use([LineChart, BarChart, TooltipComponent, GridComponent, CanvasRenderer]);
|
||||||
|
|
||||||
export let data;
|
export let data;
|
||||||
@ -112,6 +114,63 @@
|
|||||||
optionsDividend = await plotDividend();
|
optionsDividend = await plotDividend();
|
||||||
isLoaded = true;
|
isLoaded = true;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function generateDividendInfoHTML() {
|
||||||
|
const history = rawData?.history || [];
|
||||||
|
|
||||||
|
if (history.length !== 0) {
|
||||||
|
if (!dateDistance) {
|
||||||
|
const formattedExDividendDate = new Date(exDividendDate).toLocaleString(
|
||||||
|
"en-US",
|
||||||
|
{
|
||||||
|
month: "short",
|
||||||
|
day: "numeric",
|
||||||
|
year: "numeric",
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
const payoutFrequencyText =
|
||||||
|
payoutFrequency === 4
|
||||||
|
? "3 months"
|
||||||
|
: payoutFrequency === 2
|
||||||
|
? "6 months"
|
||||||
|
: payoutFrequency === 1
|
||||||
|
? "12 months"
|
||||||
|
: "n/a";
|
||||||
|
|
||||||
|
return `
|
||||||
|
<span>
|
||||||
|
${$displayCompanyName} has an annual dividend of $${annualDividend} per share, with a forward yield of ${dividendYield}%.
|
||||||
|
The dividend is paid every ${payoutFrequencyText} and the last ex-dividend date was ${formattedExDividendDate}.
|
||||||
|
</span>
|
||||||
|
`;
|
||||||
|
} else {
|
||||||
|
const latestDividendDate = new Date(history.at(0)?.date).toLocaleString(
|
||||||
|
"en-US",
|
||||||
|
{
|
||||||
|
month: "short",
|
||||||
|
day: "numeric",
|
||||||
|
year: "numeric",
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
return `
|
||||||
|
<span>
|
||||||
|
${$displayCompanyName} issued its most recent dividend on ${latestDividendDate}.
|
||||||
|
Since then, the company has not distributed any further dividends for over 12 months.
|
||||||
|
</span>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return `
|
||||||
|
<span>
|
||||||
|
No dividend history available for ${$displayCompanyName}.
|
||||||
|
</span>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const htmlOutput = generateDividendInfoHTML();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<svelte:head>
|
<svelte:head>
|
||||||
@ -163,55 +222,7 @@
|
|||||||
Dividends
|
Dividends
|
||||||
</h1>
|
</h1>
|
||||||
|
|
||||||
<div
|
<Infobox text={htmlOutput} />
|
||||||
class="w-full text-white text-start p-3 sm:p-5 mb-10 rounded-md sm:flex sm:flex-row sm:items-center border border-gray-600 text-sm sm:text-[1rem]"
|
|
||||||
>
|
|
||||||
<svg
|
|
||||||
class="w-6 h-6 flex-shrink-0 inline-block sm:mr-2"
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
viewBox="0 0 256 256"
|
|
||||||
><path
|
|
||||||
fill="#fff"
|
|
||||||
d="M128 24a104 104 0 1 0 104 104A104.11 104.11 0 0 0 128 24m-4 48a12 12 0 1 1-12 12a12 12 0 0 1 12-12m12 112a16 16 0 0 1-16-16v-40a8 8 0 0 1 0-16a16 16 0 0 1 16 16v40a8 8 0 0 1 0 16"
|
|
||||||
/></svg
|
|
||||||
>
|
|
||||||
|
|
||||||
{#if rawData?.history?.length !== 0}
|
|
||||||
{#if !dateDistance}
|
|
||||||
{$displayCompanyName} has an annual dividend of ${annualDividend}
|
|
||||||
per share, with a forward yield of
|
|
||||||
{dividendYield}%. The dividend is paid every
|
|
||||||
{payoutFrequency === 4
|
|
||||||
? "3 months"
|
|
||||||
: payoutFrequency === 2
|
|
||||||
? "6 months"
|
|
||||||
: payoutFrequency === 1
|
|
||||||
? "12 months"
|
|
||||||
: "n/a"}
|
|
||||||
and the last ex-dividend date was
|
|
||||||
{new Date(exDividendDate)?.toLocaleString("en-US", {
|
|
||||||
month: "short",
|
|
||||||
day: "numeric",
|
|
||||||
year: "numeric",
|
|
||||||
daySuffix: "2-digit",
|
|
||||||
})}
|
|
||||||
{:else}
|
|
||||||
{$displayCompanyName} issued its most recent dividend on
|
|
||||||
{new Date(rawData?.history?.at(0)?.date)?.toLocaleString(
|
|
||||||
"en-US",
|
|
||||||
{
|
|
||||||
month: "short",
|
|
||||||
day: "numeric",
|
|
||||||
year: "numeric",
|
|
||||||
daySuffix: "2-digit",
|
|
||||||
},
|
|
||||||
)}. Since then, the company has not distributed any further
|
|
||||||
dividends for over 12 months.
|
|
||||||
{/if}
|
|
||||||
{:else}
|
|
||||||
No dividend history available for {$displayCompanyName}.
|
|
||||||
{/if}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{#if rawData?.history?.length !== 0}
|
{#if rawData?.history?.length !== 0}
|
||||||
|
|||||||
@ -6,6 +6,7 @@
|
|||||||
} from "$lib/store";
|
} from "$lib/store";
|
||||||
import { formatString } from "$lib/utils";
|
import { formatString } from "$lib/utils";
|
||||||
import Table from "$lib/components/Table/Table.svelte";
|
import Table from "$lib/components/Table/Table.svelte";
|
||||||
|
import Infobox from "$lib/components/Infobox.svelte";
|
||||||
|
|
||||||
export let data;
|
export let data;
|
||||||
let rawData = data?.getETFHoldings?.holdings;
|
let rawData = data?.getETFHoldings?.holdings;
|
||||||
@ -32,6 +33,28 @@
|
|||||||
{ name: "% Weight", rule: "weightPercentage", type: "percent" },
|
{ name: "% Weight", rule: "weightPercentage", type: "percent" },
|
||||||
{ name: "Shares", rule: "sharesNumber", type: "int" },
|
{ name: "Shares", rule: "sharesNumber", type: "int" },
|
||||||
];
|
];
|
||||||
|
|
||||||
|
function generateStatementInfoHTML() {
|
||||||
|
if (rawData?.length > 0) {
|
||||||
|
return `
|
||||||
|
<span>
|
||||||
|
The ${$displayCompanyName} holds ${rawData?.length} different assets
|
||||||
|
and the largest one in the portfolio is ${formatString(
|
||||||
|
rawData?.at(0)?.name,
|
||||||
|
)}, making up ${rawData?.at(0)?.weightPercentage?.toFixed(2)}% of
|
||||||
|
the total.
|
||||||
|
</span>
|
||||||
|
`;
|
||||||
|
} else {
|
||||||
|
return `
|
||||||
|
<span>
|
||||||
|
No financial data available for ${$displayCompanyName}.
|
||||||
|
</span>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let htmlOutput = generateStatementInfoHTML();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<svelte:head>
|
<svelte:head>
|
||||||
@ -72,37 +95,15 @@
|
|||||||
</svelte:head>
|
</svelte:head>
|
||||||
|
|
||||||
<section
|
<section
|
||||||
class="bg-[#09090B] overflow-hidden text-white h-full min-h-screen mb-20 sm:mb-0 w-full mt-5 sm:mt-0"
|
class="bg-[#09090B] overflow-hidden text-white h-full min-h-screen mb-20 sm:mb-0 w-full mt-2 sm:mt-0"
|
||||||
>
|
>
|
||||||
<div class="flex justify-center m-auto h-full overflow-hidden w-full">
|
<div class="flex justify-center m-auto h-full overflow-hidden w-full">
|
||||||
<div
|
<div
|
||||||
class="relative flex justify-center items-center overflow-hidden w-full"
|
class="relative flex justify-center items-center overflow-hidden w-full"
|
||||||
>
|
>
|
||||||
<div class="sm:p-7 w-full m-auto mt-2 sm:mt-0">
|
<div class="sm:p-7 w-full m-auto">
|
||||||
<div class="mb-6">
|
<div class="mb-10">
|
||||||
<div
|
<Infobox text={htmlOutput} />
|
||||||
class="text-white p-3 sm:p-5 mb-10 rounded-md sm:flex sm:flex-row sm:items-center border border-gray-600 text-sm sm:text-[1rem]"
|
|
||||||
>
|
|
||||||
<svg
|
|
||||||
class="w-6 h-6 flex-shrink-0 inline-block sm:mr-2"
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
viewBox="0 0 256 256"
|
|
||||||
><path
|
|
||||||
fill="#fff"
|
|
||||||
d="M128 24a104 104 0 1 0 104 104A104.11 104.11 0 0 0 128 24m-4 48a12 12 0 1 1-12 12a12 12 0 0 1 12-12m12 112a16 16 0 0 1-16-16v-40a8 8 0 0 1 0-16a16 16 0 0 1 16 16v40a8 8 0 0 1 0 16"
|
|
||||||
/></svg
|
|
||||||
>
|
|
||||||
|
|
||||||
{#if rawData?.length !== 0}
|
|
||||||
The {$displayCompanyName} holds {rawData?.length} different assets
|
|
||||||
and the largest one in the portfolio is {formatString(
|
|
||||||
rawData?.at(0)?.name,
|
|
||||||
)}, making up {rawData?.at(0)?.weightPercentage?.toFixed(2)}% of
|
|
||||||
the total.
|
|
||||||
{:else}
|
|
||||||
No information available for {$displayCompanyName}.
|
|
||||||
{/if}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{#if rawData?.length !== 0}
|
{#if rawData?.length !== 0}
|
||||||
|
|||||||
@ -42,7 +42,7 @@
|
|||||||
|
|
||||||
{#if newsList?.length !== 0}
|
{#if newsList?.length !== 0}
|
||||||
<div
|
<div
|
||||||
class="w-full sm:hover:text-white text-white border border-gray-600 rounded-md h-fit pb-4 mt-4 cursor-pointer"
|
class="w-full sm:hover:text-white text-white border border-gray-600 bg-primary rounded-md h-fit pb-4 mt-4 cursor-pointer"
|
||||||
>
|
>
|
||||||
<div class="p-4 text-sm">
|
<div class="p-4 text-sm">
|
||||||
<h3 class="text-lg text-white font-semibold mb-3">
|
<h3 class="text-lg text-white font-semibold mb-3">
|
||||||
|
|||||||
@ -165,7 +165,7 @@
|
|||||||
>
|
>
|
||||||
<!--Start Buy/Sell-->
|
<!--Start Buy/Sell-->
|
||||||
<div
|
<div
|
||||||
class="flex flex-row items-center flex-wrap w-full px-3 sm:px-4 border border-gray-600 rounded-md h-20"
|
class="flex flex-row items-center flex-wrap w-full px-3 sm:px-4 border border-gray-600 bg-primary rounded-md h-20"
|
||||||
>
|
>
|
||||||
<div class="flex flex-col items-start">
|
<div class="flex flex-col items-start">
|
||||||
<span
|
<span
|
||||||
@ -227,7 +227,7 @@
|
|||||||
<!--End Buy/Sell-->
|
<!--End Buy/Sell-->
|
||||||
<!--Start Dem/Rep-->
|
<!--Start Dem/Rep-->
|
||||||
<div
|
<div
|
||||||
class="flex flex-row items-center flex-wrap w-full px-3 sm:px-4 border border-gray-600 rounded-md h-20"
|
class="flex flex-row items-center flex-wrap w-full px-3 sm:px-4 border border-gray-600 bg-primary rounded-md h-20"
|
||||||
>
|
>
|
||||||
<div class="flex flex-col items-start">
|
<div class="flex flex-col items-start">
|
||||||
<span
|
<span
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user