update financial page by adding plot
This commit is contained in:
parent
0139c5d4c5
commit
0a0c17573b
@ -97,25 +97,37 @@
|
||||
},
|
||||
xAxis: {
|
||||
type: "datetime",
|
||||
min: startTime,
|
||||
max: endTime,
|
||||
tickLength: 0,
|
||||
min: startTime, // Force start at 9:30
|
||||
max: endTime, // Force end at 16:10
|
||||
crosshair: {
|
||||
color: $mode === "light" ? "#545454" : "white",
|
||||
width: 1,
|
||||
color: $mode === "light" ? "black" : "white", // Set the color of the crosshair line
|
||||
width: 1, // Adjust the line width as needed
|
||||
dashStyle: "Solid",
|
||||
},
|
||||
labels: {
|
||||
style: { color: $mode === "light" ? "#545454" : "white" },
|
||||
distance: 20,
|
||||
distance: 10, // Increases space between label and axis
|
||||
formatter: function () {
|
||||
const date = new Date(this?.value);
|
||||
return date?.toLocaleTimeString("en-US", {
|
||||
hour: "2-digit",
|
||||
minute: "2-digit",
|
||||
const timeString = date?.toLocaleTimeString("en-US", {
|
||||
hour: "numeric",
|
||||
hour12: true,
|
||||
});
|
||||
return `<span class="text-xs">${timeString.replace(/\s/g, " ")}</span>`;
|
||||
},
|
||||
},
|
||||
tickPositioner: function () {
|
||||
// Create custom tick positions with wider spacing
|
||||
const positions = [];
|
||||
const info = this.getExtremes();
|
||||
const tickCount = 5; // Reduce number of ticks displayed
|
||||
const interval = (info.max - info.min) / tickCount;
|
||||
|
||||
for (let i = 0; i <= tickCount; i++) {
|
||||
positions.push(info.min + i * interval);
|
||||
}
|
||||
return positions;
|
||||
},
|
||||
},
|
||||
yAxis: [
|
||||
{
|
||||
@ -203,6 +215,7 @@
|
||||
],
|
||||
},
|
||||
color: "#4681f4",
|
||||
borderColor: "4681f4",
|
||||
lineWidth: 1.3,
|
||||
yAxis: 0, // Use primary yAxis
|
||||
animation: false,
|
||||
|
||||
@ -1,9 +1,14 @@
|
||||
<script lang="ts">
|
||||
import { abbreviateNumber } from "$lib/utils";
|
||||
import { screenWidth, stockTicker } from "$lib/store";
|
||||
import { mode } from "mode-watcher";
|
||||
import highcharts from "$lib/highcharts.ts";
|
||||
|
||||
export let data: any[];
|
||||
export let fields: { label: string; key: string }[];
|
||||
|
||||
// Use a Set for fast margin lookup
|
||||
let config = null;
|
||||
|
||||
const marginKeys = new Set([
|
||||
/*
|
||||
"pretaxProfitMargin",
|
||||
@ -32,6 +37,117 @@
|
||||
const formatted = abbreviateNumber(value.toFixed(2));
|
||||
return isMargin ? formatted + "%" : formatted;
|
||||
}
|
||||
|
||||
function plotData(label, key) {
|
||||
const rawData = [...data]?.sort((a, b) => a?.fiscalYear - b?.fiscalYear);
|
||||
const dateList = rawData?.map((item) =>
|
||||
item?.period === "FY"
|
||||
? item?.fiscalYear
|
||||
: `${item?.period} FY ${item?.fiscalYear}`,
|
||||
);
|
||||
|
||||
const valueList = rawData?.map((item) => item[key]);
|
||||
|
||||
const options = {
|
||||
chart: {
|
||||
type: "column",
|
||||
backgroundColor: $mode === "light" ? "#fff" : "#09090B",
|
||||
plotBackgroundColor: $mode === "light" ? "#fff" : "#09090B",
|
||||
height: 360,
|
||||
animation: false,
|
||||
},
|
||||
credits: { enabled: false },
|
||||
legend: { enabled: false },
|
||||
plotOptions: {
|
||||
series: {
|
||||
color: "white",
|
||||
animation: false,
|
||||
dataLabels: {
|
||||
enabled: false,
|
||||
color: "white",
|
||||
style: {
|
||||
fontSize: "13px",
|
||||
fontWeight: "bold",
|
||||
},
|
||||
formatter: function () {
|
||||
return abbreviateNumber(this?.y);
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
title: {
|
||||
text: `<h3 class="mt-3 mb-1 sm:text-lg">${$stockTicker} ${label}</h3>`,
|
||||
useHTML: true,
|
||||
style: { color: $mode === "light" ? "black" : "white" },
|
||||
},
|
||||
xAxis: {
|
||||
endOnTick: false,
|
||||
categories: dateList,
|
||||
crosshair: {
|
||||
color: $mode === "light" ? "black" : "white", // Set the color of the crosshair line
|
||||
width: 1, // Adjust the line width as needed
|
||||
dashStyle: "Solid",
|
||||
},
|
||||
labels: {
|
||||
style: {
|
||||
color: $mode === "light" ? "#545454" : "white",
|
||||
},
|
||||
rotation: -45,
|
||||
distance: 10, // Increases space between label and axis
|
||||
},
|
||||
},
|
||||
yAxis: {
|
||||
gridLineWidth: 1,
|
||||
gridLineColor: $mode === "light" ? "#e5e7eb" : "#111827",
|
||||
labels: {
|
||||
style: { color: $mode === "light" ? "black" : "white" },
|
||||
formatter: function () {
|
||||
return abbreviateNumber(this.value);
|
||||
},
|
||||
},
|
||||
title: { text: null },
|
||||
opposite: true,
|
||||
},
|
||||
tooltip: {
|
||||
shared: true,
|
||||
useHTML: true,
|
||||
backgroundColor: "rgba(0, 0, 0, 0.8)",
|
||||
borderColor: "rgba(255, 255, 255, 0.2)",
|
||||
borderWidth: 1,
|
||||
style: {
|
||||
color: "#fff",
|
||||
fontSize: "16px",
|
||||
padding: "10px",
|
||||
},
|
||||
borderRadius: 4,
|
||||
formatter: function () {
|
||||
let tooltipContent = `<span class="text-white m-auto text-black text-[1rem] font-[501]">${this?.x}</span><br>`;
|
||||
this.points.forEach((point) => {
|
||||
tooltipContent += `<span class="text-white font-semibold text-sm">${point.series.name}:</span>
|
||||
<span class="text-white font-normal text-sm">${abbreviateNumber(
|
||||
point.y,
|
||||
)}</span><br>`;
|
||||
});
|
||||
return tooltipContent;
|
||||
},
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: label,
|
||||
data: valueList,
|
||||
color: $mode === "light" ? "#2C6288" : "white",
|
||||
borderColor: $mode === "light" ? "#2C6288" : "white",
|
||||
borderRadius: "1px",
|
||||
animation: false,
|
||||
},
|
||||
],
|
||||
};
|
||||
return options;
|
||||
}
|
||||
|
||||
async function handleChart(label, key) {
|
||||
config = plotData(label, key);
|
||||
}
|
||||
</script>
|
||||
|
||||
{#each computedFields as { label, key, isMargin } (key)}
|
||||
@ -39,14 +155,69 @@
|
||||
class="dark:sm:hover:bg-[#245073]/10 odd:bg-[#F6F7F8] dark:odd:bg-odd whitespace-nowrap"
|
||||
>
|
||||
<td
|
||||
class="text-start border-r border-gray-300 dark:border-gray-700 text-sm sm:text-[1rem]"
|
||||
class="text-start min-w-[220px] sm:min-w-[320px] border-r border-gray-300 dark:border-gray-700 text-sm sm:text-[1rem] w-full flex flex-row items-center justify-between"
|
||||
>
|
||||
{label}
|
||||
<span class="truncate w-fit max-w-40 sm:max-w-fit">{label}</span>
|
||||
<label
|
||||
for="financialPlotModal"
|
||||
on:click={() => handleChart(label, key)}
|
||||
class="cursor-pointer inline-block"
|
||||
>
|
||||
<svg
|
||||
class="w-5 h-5 text-gray-500 dark:text-gray-300"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
><g id="SVGRepo_bgCarrier" stroke-width="0"></g><g
|
||||
id="SVGRepo_tracerCarrier"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
></g><g id="SVGRepo_iconCarrier">
|
||||
<path
|
||||
d="M9 12H4.6C4.03995 12 3.75992 12 3.54601 12.109C3.35785 12.2049 3.20487 12.3578 3.10899 12.546C3 12.7599 3 13.0399 3 13.6V19.4C3 19.9601 3 20.2401 3.10899 20.454C3.20487 20.6422 3.35785 20.7951 3.54601 20.891C3.75992 21 4.03995 21 4.6 21H9M9 21H15M9 21L9 8.6C9 8.03995 9 7.75992 9.10899 7.54601C9.20487 7.35785 9.35785 7.20487 9.54601 7.10899C9.75992 7 10.0399 7 10.6 7H13.4C13.9601 7 14.2401 7 14.454 7.10899C14.6422 7.20487 14.7951 7.35785 14.891 7.54601C15 7.75992 15 8.03995 15 8.6V21M15 21H19.4C19.9601 21 20.2401 21 20.454 20.891C20.6422 20.7951 20.7951 20.6422 20.891 20.454C21 20.2401 21 19.9601 21 19.4V4.6C21 4.03995 21 3.75992 20.891 3.54601C20.7951 3.35785 20.6422 3.20487 20.454 3.10899C20.2401 3 19.9601 3 19.4 3H16.6C16.0399 3 15.7599 3 15.546 3.10899C15.3578 3.20487 15.2049 3.35785 15.109 3.54601C15 3.75992 15 4.03995 15 4.6V8"
|
||||
stroke="currentColor"
|
||||
stroke-width="1.8"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
></path>
|
||||
</g></svg
|
||||
>
|
||||
</label>
|
||||
</td>
|
||||
{#each data as item, index (index)}
|
||||
{#each data as item}
|
||||
<td class="text-sm sm:text-[1rem] text-end">
|
||||
{formatValue(item[key], isMargin)}
|
||||
</td>
|
||||
{/each}
|
||||
</tr>
|
||||
{/each}
|
||||
|
||||
<input type="checkbox" id="financialPlotModal" class="modal-toggle" />
|
||||
<dialog
|
||||
id="financialPlotModal"
|
||||
class="modal {$screenWidth < 640 ? 'modal-bottom ' : ''} bg-[#000]/40 sm:px-5"
|
||||
>
|
||||
<label for="financialPlotModal" class="cursor-pointer modal-backdrop"></label>
|
||||
|
||||
<div
|
||||
class="modal-box bg-white relative dark:bg-default w-full max-w-3xl rounded-md border-t sm:border border-gray-300 dark:border-gray-700 min-h-48 h-auto"
|
||||
>
|
||||
<label
|
||||
for="financialPlotModal"
|
||||
class="cursor-pointer text-[1.8rem] focus:outline-hidden absolute top-2 right-3"
|
||||
>
|
||||
<svg
|
||||
class="w-8 h-8 text-muted dark:text-white"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 24 24"
|
||||
><path
|
||||
fill="currentColor"
|
||||
d="m6.4 18.308l-.708-.708l5.6-5.6l-5.6-5.6l.708-.708l5.6 5.6l5.6-5.6l.708.708l-5.6 5.6l5.6 5.6l-.708.708l-5.6-5.6z"
|
||||
/>
|
||||
</svg>
|
||||
</label>
|
||||
{#if config}
|
||||
<div class="mt-2" use:highcharts={config}></div>
|
||||
{/if}
|
||||
</div>
|
||||
</dialog>
|
||||
|
||||
@ -7,7 +7,7 @@
|
||||
export let data;
|
||||
export let form;
|
||||
|
||||
let mode = false;
|
||||
let mode = true;
|
||||
const emailAddress = "support@stocknear.com";
|
||||
|
||||
function toggleMode() {
|
||||
|
||||
32
src/routes/stocks/[tickerID]/financials/+layout.server.ts
Normal file
32
src/routes/stocks/[tickerID]/financials/+layout.server.ts
Normal file
@ -0,0 +1,32 @@
|
||||
|
||||
|
||||
export const load = async ({ locals, params }) => {
|
||||
const { apiKey, apiURL } = locals;
|
||||
const postData = {
|
||||
ticker: params.tickerID,
|
||||
};
|
||||
|
||||
const getProfileData = async () => {
|
||||
|
||||
|
||||
// make the POST request to the endpoint
|
||||
const response = await fetch(apiURL + "/profile", {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
"X-API-KEY": apiKey,
|
||||
},
|
||||
body: JSON.stringify(postData),
|
||||
});
|
||||
|
||||
const output = await response.json();
|
||||
|
||||
return output;
|
||||
};
|
||||
|
||||
// Make sure to return a promise
|
||||
return {
|
||||
getProfileData: await getProfileData(),
|
||||
};
|
||||
};
|
||||
|
||||
@ -2,15 +2,15 @@ import { error, fail, redirect } from "@sveltejs/kit";
|
||||
import { validateData } from "$lib/utils";
|
||||
import { loginUserSchema, registerUserSchema } from "$lib/schemas";
|
||||
|
||||
|
||||
|
||||
export const load = async ({ locals, params }) => {
|
||||
const getData = async () => {
|
||||
const { apiKey, apiURL } = locals;
|
||||
const { apiKey, apiURL } = locals;
|
||||
const postData = {
|
||||
ticker: params.tickerID,
|
||||
};
|
||||
|
||||
|
||||
const getData = async () => {
|
||||
|
||||
// make the POST request to the endpoint
|
||||
const response = await fetch(apiURL + "/stock-income", {
|
||||
method: "POST",
|
||||
@ -26,6 +26,8 @@ export const load = async ({ locals, params }) => {
|
||||
return output;
|
||||
};
|
||||
|
||||
|
||||
|
||||
// Make sure to return a promise
|
||||
return {
|
||||
getData: await getData(),
|
||||
|
||||
@ -392,7 +392,7 @@
|
||||
<div class="grid grid-cols-1 gap-2">
|
||||
{#if financialData?.length > 0}
|
||||
<div
|
||||
class="mb-2 flex flex-row items-center w-full justify-end sm:justify-center"
|
||||
class="flex flex-row items-center w-full justify-end sm:justify-center"
|
||||
>
|
||||
<label
|
||||
class="inline-flex mt-2 sm:mt-0 cursor-pointer relative mr-auto"
|
||||
@ -415,14 +415,35 @@
|
||||
</label>
|
||||
|
||||
<div class="flex flex-row items-center w-fit sm:ml-auto">
|
||||
<div class="relative inline-block text-left grow">
|
||||
<!--
|
||||
<div class="ml-2 relative inline-block text-left">
|
||||
<Button
|
||||
class="shadow-sm w-full border-gray-300 dark:border-gray-600 border sm:hover:bg-gray-100 dark:sm:hover:bg-primary ease-out flex flex-row justify-between items-center px-5 rounded-md truncate"
|
||||
>
|
||||
<svg
|
||||
class="w-4 h-4 bp:w-5 bp:h-5 pointer-events-none"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
style="max-width:40px"
|
||||
><path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M8 7h12m0 0l-4-4m4 4l-4 4m0 6H4m0 0l4 4m-4-4l4-4"
|
||||
></path></svg
|
||||
>
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<div class="ml-2 relative inline-block text-left grow">
|
||||
<DropdownMenu.Root>
|
||||
<DropdownMenu.Trigger asChild let:builder>
|
||||
<Button
|
||||
builders={[builder]}
|
||||
class="shadow-sm w-full border-gray-300 dark:border-gray-600 border sm:hover:bg-gray-100 dark:sm:hover:bg-primary ease-out flex flex-row justify-between items-center px-3 py-2 rounded-md truncate"
|
||||
class="shadow-sm w-full border-gray-300 dark:border-gray-600 border sm:hover:bg-gray-100 dark:sm:hover:bg-primary ease-out flex flex-row justify-between items-center px-3 py-1.5 rounded-md truncate"
|
||||
>
|
||||
<span class="truncate">{$timeFrame}</span>
|
||||
<span class="truncate">Raw</span>
|
||||
<svg
|
||||
class="-mr-1 ml-1 h-5 w-5 xs:ml-2 inline-block"
|
||||
viewBox="0 0 20 20"
|
||||
@ -441,52 +462,30 @@
|
||||
<DropdownMenu.Content
|
||||
class="w-56 h-fit max-h-72 overflow-y-auto scroller"
|
||||
>
|
||||
<DropdownMenu.Label
|
||||
class="text-muted dark:text-gray-400"
|
||||
>
|
||||
Select time frame
|
||||
</DropdownMenu.Label>
|
||||
<DropdownMenu.Separator />
|
||||
<DropdownMenu.Group>
|
||||
<DropdownMenu.Item
|
||||
on:click={() => ($timeFrame = "5Y")}
|
||||
class="cursor-pointer sm:hover:bg-gray-300 dark:sm:hover:bg-primary"
|
||||
>
|
||||
5 years
|
||||
Billions
|
||||
</DropdownMenu.Item>
|
||||
<DropdownMenu.Item
|
||||
on:click={() => ($timeFrame = "10Y")}
|
||||
class="cursor-pointer sm:hover:bg-gray-300 dark:sm:hover:bg-primary"
|
||||
>
|
||||
10 years
|
||||
Millions
|
||||
</DropdownMenu.Item>
|
||||
<DropdownMenu.Item
|
||||
on:click={() => ($timeFrame = "MAX")}
|
||||
class="cursor-pointer sm:hover:bg-gray-300 dark:sm:hover:bg-primary"
|
||||
>
|
||||
Max
|
||||
Raw
|
||||
</DropdownMenu.Item>
|
||||
</DropdownMenu.Group>
|
||||
</DropdownMenu.Content>
|
||||
</DropdownMenu.Root>
|
||||
</div>
|
||||
<Button
|
||||
on:click={() => exportFundamentalData("csv")}
|
||||
class="shadow-sm ml-2 w-fit border-gray-300 dark:border-gray-600 border sm:hover:bg-gray-100 dark:sm:hover:bg-primary ease-out flex flex-row justify-between items-center px-3 py-2 rounded-md truncate"
|
||||
>
|
||||
<span class="truncate">Download</span>
|
||||
<svg
|
||||
class="{['Pro', 'Plus']?.includes(data?.user?.tier)
|
||||
? 'hidden'
|
||||
: ''} ml-1 -mt-0.5 w-3.5 h-3.5"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 24 24"
|
||||
><path
|
||||
fill="currentColor"
|
||||
d="M17 9V7c0-2.8-2.2-5-5-5S7 4.2 7 7v2c-1.7 0-3 1.3-3 3v7c0 1.7 1.3 3 3 3h10c1.7 0 3-1.3 3-3v-7c0-1.7-1.3-3-3-3M9 7c0-1.7 1.3-3 3-3s3 1.3 3 3v2H9z"
|
||||
/></svg
|
||||
>
|
||||
</Button>
|
||||
-->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -506,6 +505,91 @@
|
||||
{/each}
|
||||
</div>
|
||||
{:else}
|
||||
<div
|
||||
class="flex flex-col sm:flex-row items-start sm:items-center sm:justify-between"
|
||||
>
|
||||
<span
|
||||
class="text-sm order-1 sm:order-0 mt-5 sm:mt-0 text-gray-600 dark:text-gray-400 w-full"
|
||||
>
|
||||
Financials in {data?.getProfileData?.currency}. Fiscal year
|
||||
is
|
||||
{data?.getProfileData?.fiscalYearRange}.
|
||||
</span>
|
||||
<div class="flex flex-row items-center justify-end w-full">
|
||||
<div class="sm:ml-auto relative inline-block">
|
||||
<DropdownMenu.Root>
|
||||
<DropdownMenu.Trigger asChild let:builder>
|
||||
<Button
|
||||
builders={[builder]}
|
||||
class="shadow-sm w-full sm:w-fit border-gray-300 dark:border-gray-600 border sm:hover:bg-gray-100 dark:sm:hover:bg-primary ease-out flex flex-row justify-between items-center px-3 py-1.5 rounded-md truncate"
|
||||
>
|
||||
<span class="truncate">{$timeFrame}</span>
|
||||
<svg
|
||||
class="-mr-1 ml-1 h-5 w-5 xs:ml-2 inline-block"
|
||||
viewBox="0 0 20 20"
|
||||
fill="currentColor"
|
||||
style="max-width:40px"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z"
|
||||
clip-rule="evenodd"
|
||||
></path>
|
||||
</svg>
|
||||
</Button>
|
||||
</DropdownMenu.Trigger>
|
||||
<DropdownMenu.Content
|
||||
class="w-56 h-fit max-h-72 overflow-y-auto scroller"
|
||||
>
|
||||
<DropdownMenu.Label
|
||||
class="text-muted dark:text-gray-400"
|
||||
>
|
||||
Select time frame
|
||||
</DropdownMenu.Label>
|
||||
<DropdownMenu.Separator />
|
||||
<DropdownMenu.Group>
|
||||
<DropdownMenu.Item
|
||||
on:click={() => ($timeFrame = "5Y")}
|
||||
class="cursor-pointer sm:hover:bg-gray-300 dark:sm:hover:bg-primary"
|
||||
>
|
||||
5 years
|
||||
</DropdownMenu.Item>
|
||||
<DropdownMenu.Item
|
||||
on:click={() => ($timeFrame = "10Y")}
|
||||
class="cursor-pointer sm:hover:bg-gray-300 dark:sm:hover:bg-primary"
|
||||
>
|
||||
10 years
|
||||
</DropdownMenu.Item>
|
||||
<DropdownMenu.Item
|
||||
on:click={() => ($timeFrame = "MAX")}
|
||||
class="cursor-pointer sm:hover:bg-gray-300 dark:sm:hover:bg-primary"
|
||||
>
|
||||
Max
|
||||
</DropdownMenu.Item>
|
||||
</DropdownMenu.Group>
|
||||
</DropdownMenu.Content>
|
||||
</DropdownMenu.Root>
|
||||
</div>
|
||||
<Button
|
||||
on:click={() => exportFundamentalData("csv")}
|
||||
class="shadow-sm ml-2 w-fit border-gray-300 dark:border-gray-600 border sm:hover:bg-gray-100 dark:sm:hover:bg-primary ease-out flex flex-row justify-between items-center px-3 py-1.5 rounded-md truncate"
|
||||
>
|
||||
<span class="truncate">Download</span>
|
||||
<svg
|
||||
class="{['Pro', 'Plus']?.includes(data?.user?.tier)
|
||||
? 'hidden'
|
||||
: ''} ml-1 -mt-0.5 w-3.5 h-3.5"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 24 24"
|
||||
><path
|
||||
fill="currentColor"
|
||||
d="M17 9V7c0-2.8-2.2-5-5-5S7 4.2 7 7v2c-1.7 0-3 1.3-3 3v7c0 1.7 1.3 3 3 3h10c1.7 0 3-1.3 3-3v-7c0-1.7-1.3-3-3-3M9 7c0-1.7 1.3-3 3-3s3 1.3 3 3v2H9z"
|
||||
/></svg
|
||||
>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="w-full rounded-none sm:rounded-md m-auto overflow-x-auto no-scrollbar"
|
||||
>
|
||||
@ -513,25 +597,40 @@
|
||||
class="table table-sm table-compact no-scrollbar rounded-none sm:rounded-md w-full bg-white dark:bg-table border border-gray-300 dark:border-gray-800 m-auto"
|
||||
>
|
||||
<thead class="text-muted dark:text-white dark:bg-default">
|
||||
<tr class="">
|
||||
<tr class="border min-w-[250px]">
|
||||
<td class="text-start text-sm font-semibold pr-10"
|
||||
>Year</td
|
||||
>Fiscal Year</td
|
||||
>
|
||||
{#each financialData as cash}
|
||||
{#each financialData as item}
|
||||
{#if filterRule === "annual"}
|
||||
<td class=" font-semibold text-sm text-end">
|
||||
{"FY" + cash?.fiscalYear?.slice(-2)}
|
||||
<td
|
||||
class=" font-semibold text-sm text-end border-l border-gray-300 dark:border-gray-800"
|
||||
>
|
||||
{"FY" + " " + item?.fiscalYear}
|
||||
</td>
|
||||
{:else}
|
||||
<td class=" font-semibold text-sm text-end">
|
||||
{"FY" +
|
||||
cash?.fiscalYear?.slice(-2) +
|
||||
" " +
|
||||
cash?.period}
|
||||
{item?.period + " " + item?.fiscalYear}
|
||||
</td>
|
||||
{/if}
|
||||
{/each}
|
||||
</tr>
|
||||
<tr class="border min-w-[250px]">
|
||||
<td class="text-start text-sm font-semibold"
|
||||
>Period Ending</td
|
||||
>
|
||||
{#each financialData as item}
|
||||
<td
|
||||
class=" font-semibold text-sm text-end border-l border-gray-300 dark:border-gray-800"
|
||||
>
|
||||
{new Date(item?.date).toLocaleDateString("en-US", {
|
||||
month: "short",
|
||||
day: "numeric",
|
||||
year: "numeric",
|
||||
})}
|
||||
</td>
|
||||
{/each}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<!-- row -->
|
||||
|
||||
@ -422,7 +422,7 @@
|
||||
<div class="grid grid-cols-1 gap-2">
|
||||
{#if financialData?.length > 0}
|
||||
<div
|
||||
class="mb-2 flex flex-row items-center w-full justify-end sm:justify-center"
|
||||
class="flex flex-row items-center w-full justify-end sm:justify-center"
|
||||
>
|
||||
<label
|
||||
class="inline-flex mt-2 sm:mt-0 cursor-pointer relative mr-auto"
|
||||
@ -445,14 +445,35 @@
|
||||
</label>
|
||||
|
||||
<div class="flex flex-row items-center w-fit sm:ml-auto">
|
||||
<div class="relative inline-block text-left grow">
|
||||
<!--
|
||||
<div class="ml-2 relative inline-block text-left">
|
||||
<Button
|
||||
class="shadow-sm w-full border-gray-300 dark:border-gray-600 border sm:hover:bg-gray-100 dark:sm:hover:bg-primary ease-out flex flex-row justify-between items-center px-5 rounded-md truncate"
|
||||
>
|
||||
<svg
|
||||
class="w-4 h-4 bp:w-5 bp:h-5 pointer-events-none"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
style="max-width:40px"
|
||||
><path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M8 7h12m0 0l-4-4m4 4l-4 4m0 6H4m0 0l4 4m-4-4l4-4"
|
||||
></path></svg
|
||||
>
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<div class="ml-2 relative inline-block text-left grow">
|
||||
<DropdownMenu.Root>
|
||||
<DropdownMenu.Trigger asChild let:builder>
|
||||
<Button
|
||||
builders={[builder]}
|
||||
class="shadow-sm w-full border-gray-300 dark:border-gray-600 border sm:hover:bg-gray-100 dark:sm:hover:bg-primary ease-out flex flex-row justify-between items-center px-3 py-2 rounded-md truncate"
|
||||
class="shadow-sm w-full border-gray-300 dark:border-gray-600 border sm:hover:bg-gray-100 dark:sm:hover:bg-primary ease-out flex flex-row justify-between items-center px-3 py-1.5 rounded-md truncate"
|
||||
>
|
||||
<span class="truncate">{$timeFrame}</span>
|
||||
<span class="truncate">Raw</span>
|
||||
<svg
|
||||
class="-mr-1 ml-1 h-5 w-5 xs:ml-2 inline-block"
|
||||
viewBox="0 0 20 20"
|
||||
@ -471,52 +492,30 @@
|
||||
<DropdownMenu.Content
|
||||
class="w-56 h-fit max-h-72 overflow-y-auto scroller"
|
||||
>
|
||||
<DropdownMenu.Label
|
||||
class="text-muted dark:text-gray-400"
|
||||
>
|
||||
Select time frame
|
||||
</DropdownMenu.Label>
|
||||
<DropdownMenu.Separator />
|
||||
<DropdownMenu.Group>
|
||||
<DropdownMenu.Item
|
||||
on:click={() => ($timeFrame = "5Y")}
|
||||
class="cursor-pointer sm:hover:bg-gray-300 dark:sm:hover:bg-primary"
|
||||
>
|
||||
5 years
|
||||
Billions
|
||||
</DropdownMenu.Item>
|
||||
<DropdownMenu.Item
|
||||
on:click={() => ($timeFrame = "10Y")}
|
||||
class="cursor-pointer sm:hover:bg-gray-300 dark:sm:hover:bg-primary"
|
||||
>
|
||||
10 years
|
||||
Millions
|
||||
</DropdownMenu.Item>
|
||||
<DropdownMenu.Item
|
||||
on:click={() => ($timeFrame = "MAX")}
|
||||
class="cursor-pointer sm:hover:bg-gray-300 dark:sm:hover:bg-primary"
|
||||
>
|
||||
Max
|
||||
Raw
|
||||
</DropdownMenu.Item>
|
||||
</DropdownMenu.Group>
|
||||
</DropdownMenu.Content>
|
||||
</DropdownMenu.Root>
|
||||
</div>
|
||||
<Button
|
||||
on:click={() => exportFundamentalData("csv")}
|
||||
class="shadow-sm ml-2 w-fit border-gray-300 dark:border-gray-600 border sm:hover:bg-gray-100 dark:sm:hover:bg-primary ease-out flex flex-row justify-between items-center px-3 py-2 rounded-md truncate"
|
||||
>
|
||||
<span class="truncate">Download</span>
|
||||
<svg
|
||||
class="{['Pro', 'Plus']?.includes(data?.user?.tier)
|
||||
? 'hidden'
|
||||
: ''} ml-1 -mt-0.5 w-3.5 h-3.5"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 24 24"
|
||||
><path
|
||||
fill="currentColor"
|
||||
d="M17 9V7c0-2.8-2.2-5-5-5S7 4.2 7 7v2c-1.7 0-3 1.3-3 3v7c0 1.7 1.3 3 3 3h10c1.7 0 3-1.3 3-3v-7c0-1.7-1.3-3-3-3M9 7c0-1.7 1.3-3 3-3s3 1.3 3 3v2H9z"
|
||||
/></svg
|
||||
>
|
||||
</Button>
|
||||
-->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -536,6 +535,91 @@
|
||||
{/each}
|
||||
</div>
|
||||
{:else}
|
||||
<div
|
||||
class="flex flex-col sm:flex-row items-start sm:items-center sm:justify-between"
|
||||
>
|
||||
<span
|
||||
class="text-sm order-1 sm:order-0 mt-5 sm:mt-0 text-gray-600 dark:text-gray-400 w-full"
|
||||
>
|
||||
Financials in {data?.getProfileData?.currency}. Fiscal year
|
||||
is
|
||||
{data?.getProfileData?.fiscalYearRange}.
|
||||
</span>
|
||||
<div class="flex flex-row items-center justify-end w-full">
|
||||
<div class="sm:ml-auto relative inline-block">
|
||||
<DropdownMenu.Root>
|
||||
<DropdownMenu.Trigger asChild let:builder>
|
||||
<Button
|
||||
builders={[builder]}
|
||||
class="shadow-sm w-full sm:w-fit border-gray-300 dark:border-gray-600 border sm:hover:bg-gray-100 dark:sm:hover:bg-primary ease-out flex flex-row justify-between items-center px-3 py-1.5 rounded-md truncate"
|
||||
>
|
||||
<span class="truncate">{$timeFrame}</span>
|
||||
<svg
|
||||
class="-mr-1 ml-1 h-5 w-5 xs:ml-2 inline-block"
|
||||
viewBox="0 0 20 20"
|
||||
fill="currentColor"
|
||||
style="max-width:40px"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z"
|
||||
clip-rule="evenodd"
|
||||
></path>
|
||||
</svg>
|
||||
</Button>
|
||||
</DropdownMenu.Trigger>
|
||||
<DropdownMenu.Content
|
||||
class="w-56 h-fit max-h-72 overflow-y-auto scroller"
|
||||
>
|
||||
<DropdownMenu.Label
|
||||
class="text-muted dark:text-gray-400"
|
||||
>
|
||||
Select time frame
|
||||
</DropdownMenu.Label>
|
||||
<DropdownMenu.Separator />
|
||||
<DropdownMenu.Group>
|
||||
<DropdownMenu.Item
|
||||
on:click={() => ($timeFrame = "5Y")}
|
||||
class="cursor-pointer sm:hover:bg-gray-300 dark:sm:hover:bg-primary"
|
||||
>
|
||||
5 years
|
||||
</DropdownMenu.Item>
|
||||
<DropdownMenu.Item
|
||||
on:click={() => ($timeFrame = "10Y")}
|
||||
class="cursor-pointer sm:hover:bg-gray-300 dark:sm:hover:bg-primary"
|
||||
>
|
||||
10 years
|
||||
</DropdownMenu.Item>
|
||||
<DropdownMenu.Item
|
||||
on:click={() => ($timeFrame = "MAX")}
|
||||
class="cursor-pointer sm:hover:bg-gray-300 dark:sm:hover:bg-primary"
|
||||
>
|
||||
Max
|
||||
</DropdownMenu.Item>
|
||||
</DropdownMenu.Group>
|
||||
</DropdownMenu.Content>
|
||||
</DropdownMenu.Root>
|
||||
</div>
|
||||
<Button
|
||||
on:click={() => exportFundamentalData("csv")}
|
||||
class="shadow-sm ml-2 w-fit border-gray-300 dark:border-gray-600 border sm:hover:bg-gray-100 dark:sm:hover:bg-primary ease-out flex flex-row justify-between items-center px-3 py-1.5 rounded-md truncate"
|
||||
>
|
||||
<span class="truncate">Download</span>
|
||||
<svg
|
||||
class="{['Pro', 'Plus']?.includes(data?.user?.tier)
|
||||
? 'hidden'
|
||||
: ''} ml-1 -mt-0.5 w-3.5 h-3.5"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 24 24"
|
||||
><path
|
||||
fill="currentColor"
|
||||
d="M17 9V7c0-2.8-2.2-5-5-5S7 4.2 7 7v2c-1.7 0-3 1.3-3 3v7c0 1.7 1.3 3 3 3h10c1.7 0 3-1.3 3-3v-7c0-1.7-1.3-3-3-3M9 7c0-1.7 1.3-3 3-3s3 1.3 3 3v2H9z"
|
||||
/></svg
|
||||
>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="w-full rounded-none sm:rounded-md m-auto overflow-x-auto no-scrollbar"
|
||||
>
|
||||
@ -543,25 +627,40 @@
|
||||
class="table table-sm table-compact no-scrollbar rounded-none sm:rounded-md w-full bg-white dark:bg-table border border-gray-300 dark:border-gray-800 m-auto"
|
||||
>
|
||||
<thead class="text-muted dark:text-white dark:bg-default">
|
||||
<tr class="">
|
||||
<tr class="border min-w-[250px]">
|
||||
<td class="text-start text-sm font-semibold pr-10"
|
||||
>Year</td
|
||||
>Fiscal Year</td
|
||||
>
|
||||
{#each financialData as cash}
|
||||
{#each financialData as item}
|
||||
{#if filterRule === "annual"}
|
||||
<td class=" font-semibold text-sm text-end">
|
||||
{"FY" + cash?.fiscalYear?.slice(-2)}
|
||||
<td
|
||||
class=" font-semibold text-sm text-end border-l border-gray-300 dark:border-gray-800"
|
||||
>
|
||||
{"FY" + " " + item?.fiscalYear}
|
||||
</td>
|
||||
{:else}
|
||||
<td class=" font-semibold text-sm text-end">
|
||||
{"FY" +
|
||||
cash?.fiscalYear?.slice(-2) +
|
||||
" " +
|
||||
cash?.period}
|
||||
{item?.period + " " + item?.fiscalYear}
|
||||
</td>
|
||||
{/if}
|
||||
{/each}
|
||||
</tr>
|
||||
<tr class="border min-w-[250px]">
|
||||
<td class="text-start text-sm font-semibold"
|
||||
>Period Ending</td
|
||||
>
|
||||
{#each financialData as item}
|
||||
<td
|
||||
class=" font-semibold text-sm text-end border-l border-gray-300 dark:border-gray-800"
|
||||
>
|
||||
{new Date(item?.date).toLocaleDateString("en-US", {
|
||||
month: "short",
|
||||
day: "numeric",
|
||||
year: "numeric",
|
||||
})}
|
||||
</td>
|
||||
{/each}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<!-- row -->
|
||||
|
||||
@ -384,7 +384,7 @@
|
||||
<div class="grid grid-cols-1 gap-2">
|
||||
{#if financialData?.length > 0}
|
||||
<div
|
||||
class="mb-2 flex flex-row items-center w-full justify-end sm:justify-center"
|
||||
class="flex flex-row items-center w-full justify-end sm:justify-center"
|
||||
>
|
||||
<label
|
||||
class="inline-flex mt-2 sm:mt-0 cursor-pointer relative mr-auto"
|
||||
@ -407,14 +407,35 @@
|
||||
</label>
|
||||
|
||||
<div class="flex flex-row items-center w-fit sm:ml-auto">
|
||||
<div class="relative inline-block text-left grow">
|
||||
<!--
|
||||
<div class="ml-2 relative inline-block text-left">
|
||||
<Button
|
||||
class="shadow-sm w-full border-gray-300 dark:border-gray-600 border sm:hover:bg-gray-100 dark:sm:hover:bg-primary ease-out flex flex-row justify-between items-center px-5 rounded-md truncate"
|
||||
>
|
||||
<svg
|
||||
class="w-4 h-4 bp:w-5 bp:h-5 pointer-events-none"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
style="max-width:40px"
|
||||
><path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M8 7h12m0 0l-4-4m4 4l-4 4m0 6H4m0 0l4 4m-4-4l4-4"
|
||||
></path></svg
|
||||
>
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<div class="ml-2 relative inline-block text-left grow">
|
||||
<DropdownMenu.Root>
|
||||
<DropdownMenu.Trigger asChild let:builder>
|
||||
<Button
|
||||
builders={[builder]}
|
||||
class="shadow-sm w-full border-gray-300 dark:border-gray-600 border sm:hover:bg-gray-100 dark:sm:hover:bg-primary ease-out flex flex-row justify-between items-center px-3 py-2 rounded-md truncate"
|
||||
class="shadow-sm w-full border-gray-300 dark:border-gray-600 border sm:hover:bg-gray-100 dark:sm:hover:bg-primary ease-out flex flex-row justify-between items-center px-3 py-1.5 rounded-md truncate"
|
||||
>
|
||||
<span class="truncate">{$timeFrame}</span>
|
||||
<span class="truncate">Raw</span>
|
||||
<svg
|
||||
class="-mr-1 ml-1 h-5 w-5 xs:ml-2 inline-block"
|
||||
viewBox="0 0 20 20"
|
||||
@ -433,52 +454,30 @@
|
||||
<DropdownMenu.Content
|
||||
class="w-56 h-fit max-h-72 overflow-y-auto scroller"
|
||||
>
|
||||
<DropdownMenu.Label
|
||||
class="text-muted dark:text-gray-400"
|
||||
>
|
||||
Select time frame
|
||||
</DropdownMenu.Label>
|
||||
<DropdownMenu.Separator />
|
||||
<DropdownMenu.Group>
|
||||
<DropdownMenu.Item
|
||||
on:click={() => ($timeFrame = "5Y")}
|
||||
class="cursor-pointer sm:hover:bg-gray-300 dark:sm:hover:bg-primary"
|
||||
>
|
||||
5 years
|
||||
Billions
|
||||
</DropdownMenu.Item>
|
||||
<DropdownMenu.Item
|
||||
on:click={() => ($timeFrame = "10Y")}
|
||||
class="cursor-pointer sm:hover:bg-gray-300 dark:sm:hover:bg-primary"
|
||||
>
|
||||
10 years
|
||||
Millions
|
||||
</DropdownMenu.Item>
|
||||
<DropdownMenu.Item
|
||||
on:click={() => ($timeFrame = "MAX")}
|
||||
class="cursor-pointer sm:hover:bg-gray-300 dark:sm:hover:bg-primary"
|
||||
>
|
||||
Max
|
||||
Raw
|
||||
</DropdownMenu.Item>
|
||||
</DropdownMenu.Group>
|
||||
</DropdownMenu.Content>
|
||||
</DropdownMenu.Root>
|
||||
</div>
|
||||
<Button
|
||||
on:click={() => exportFundamentalData("csv")}
|
||||
class="shadow-sm ml-2 w-fit border-gray-300 dark:border-gray-600 border sm:hover:bg-gray-100 dark:sm:hover:bg-primary ease-out flex flex-row justify-between items-center px-3 py-2 rounded-md truncate"
|
||||
>
|
||||
<span class="truncate">Download</span>
|
||||
<svg
|
||||
class="{['Pro', 'Plus']?.includes(data?.user?.tier)
|
||||
? 'hidden'
|
||||
: ''} ml-1 -mt-0.5 w-3.5 h-3.5"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 24 24"
|
||||
><path
|
||||
fill="currentColor"
|
||||
d="M17 9V7c0-2.8-2.2-5-5-5S7 4.2 7 7v2c-1.7 0-3 1.3-3 3v7c0 1.7 1.3 3 3 3h10c1.7 0 3-1.3 3-3v-7c0-1.7-1.3-3-3-3M9 7c0-1.7 1.3-3 3-3s3 1.3 3 3v2H9z"
|
||||
/></svg
|
||||
>
|
||||
</Button>
|
||||
-->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -498,6 +497,91 @@
|
||||
{/each}
|
||||
</div>
|
||||
{:else}
|
||||
<div
|
||||
class="flex flex-col sm:flex-row items-start sm:items-center sm:justify-between"
|
||||
>
|
||||
<span
|
||||
class="text-sm order-1 sm:order-0 mt-5 sm:mt-0 text-gray-600 dark:text-gray-400 w-full"
|
||||
>
|
||||
Financials in {data?.getProfileData?.currency}. Fiscal year
|
||||
is
|
||||
{data?.getProfileData?.fiscalYearRange}.
|
||||
</span>
|
||||
<div class="flex flex-row items-center justify-end w-full">
|
||||
<div class="sm:ml-auto relative inline-block">
|
||||
<DropdownMenu.Root>
|
||||
<DropdownMenu.Trigger asChild let:builder>
|
||||
<Button
|
||||
builders={[builder]}
|
||||
class="shadow-sm w-full sm:w-fit border-gray-300 dark:border-gray-600 border sm:hover:bg-gray-100 dark:sm:hover:bg-primary ease-out flex flex-row justify-between items-center px-3 py-1.5 rounded-md truncate"
|
||||
>
|
||||
<span class="truncate">{$timeFrame}</span>
|
||||
<svg
|
||||
class="-mr-1 ml-1 h-5 w-5 xs:ml-2 inline-block"
|
||||
viewBox="0 0 20 20"
|
||||
fill="currentColor"
|
||||
style="max-width:40px"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z"
|
||||
clip-rule="evenodd"
|
||||
></path>
|
||||
</svg>
|
||||
</Button>
|
||||
</DropdownMenu.Trigger>
|
||||
<DropdownMenu.Content
|
||||
class="w-56 h-fit max-h-72 overflow-y-auto scroller"
|
||||
>
|
||||
<DropdownMenu.Label
|
||||
class="text-muted dark:text-gray-400"
|
||||
>
|
||||
Select time frame
|
||||
</DropdownMenu.Label>
|
||||
<DropdownMenu.Separator />
|
||||
<DropdownMenu.Group>
|
||||
<DropdownMenu.Item
|
||||
on:click={() => ($timeFrame = "5Y")}
|
||||
class="cursor-pointer sm:hover:bg-gray-300 dark:sm:hover:bg-primary"
|
||||
>
|
||||
5 years
|
||||
</DropdownMenu.Item>
|
||||
<DropdownMenu.Item
|
||||
on:click={() => ($timeFrame = "10Y")}
|
||||
class="cursor-pointer sm:hover:bg-gray-300 dark:sm:hover:bg-primary"
|
||||
>
|
||||
10 years
|
||||
</DropdownMenu.Item>
|
||||
<DropdownMenu.Item
|
||||
on:click={() => ($timeFrame = "MAX")}
|
||||
class="cursor-pointer sm:hover:bg-gray-300 dark:sm:hover:bg-primary"
|
||||
>
|
||||
Max
|
||||
</DropdownMenu.Item>
|
||||
</DropdownMenu.Group>
|
||||
</DropdownMenu.Content>
|
||||
</DropdownMenu.Root>
|
||||
</div>
|
||||
<Button
|
||||
on:click={() => exportFundamentalData("csv")}
|
||||
class="shadow-sm ml-2 w-fit border-gray-300 dark:border-gray-600 border sm:hover:bg-gray-100 dark:sm:hover:bg-primary ease-out flex flex-row justify-between items-center px-3 py-1.5 rounded-md truncate"
|
||||
>
|
||||
<span class="truncate">Download</span>
|
||||
<svg
|
||||
class="{['Pro', 'Plus']?.includes(data?.user?.tier)
|
||||
? 'hidden'
|
||||
: ''} ml-1 -mt-0.5 w-3.5 h-3.5"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 24 24"
|
||||
><path
|
||||
fill="currentColor"
|
||||
d="M17 9V7c0-2.8-2.2-5-5-5S7 4.2 7 7v2c-1.7 0-3 1.3-3 3v7c0 1.7 1.3 3 3 3h10c1.7 0 3-1.3 3-3v-7c0-1.7-1.3-3-3-3M9 7c0-1.7 1.3-3 3-3s3 1.3 3 3v2H9z"
|
||||
/></svg
|
||||
>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="w-full rounded-none sm:rounded-md m-auto overflow-x-auto no-scrollbar"
|
||||
>
|
||||
@ -505,25 +589,40 @@
|
||||
class="table table-sm table-compact no-scrollbar rounded-none sm:rounded-md w-full bg-white dark:bg-table border border-gray-300 dark:border-gray-800 m-auto"
|
||||
>
|
||||
<thead class="text-muted dark:text-white dark:bg-default">
|
||||
<tr class="">
|
||||
<tr class="border min-w-[250px]">
|
||||
<td class="text-start text-sm font-semibold pr-10"
|
||||
>Year</td
|
||||
>Fiscal Year</td
|
||||
>
|
||||
{#each financialData as cash}
|
||||
{#each financialData as item}
|
||||
{#if filterRule === "annual"}
|
||||
<td class=" font-semibold text-sm text-end">
|
||||
{"FY" + cash?.fiscalYear?.slice(-2)}
|
||||
<td
|
||||
class=" font-semibold text-sm text-end border-l border-gray-300 dark:border-gray-800"
|
||||
>
|
||||
{"FY" + " " + item?.fiscalYear}
|
||||
</td>
|
||||
{:else}
|
||||
<td class=" font-semibold text-sm text-end">
|
||||
{"FY" +
|
||||
cash?.fiscalYear?.slice(-2) +
|
||||
" " +
|
||||
cash?.period}
|
||||
{item?.period + " " + item?.fiscalYear}
|
||||
</td>
|
||||
{/if}
|
||||
{/each}
|
||||
</tr>
|
||||
<tr class="border min-w-[250px]">
|
||||
<td class="text-start text-sm font-semibold"
|
||||
>Period Ending</td
|
||||
>
|
||||
{#each financialData as item}
|
||||
<td
|
||||
class=" font-semibold text-sm text-end border-l border-gray-300 dark:border-gray-800"
|
||||
>
|
||||
{new Date(item?.date).toLocaleDateString("en-US", {
|
||||
month: "short",
|
||||
day: "numeric",
|
||||
year: "numeric",
|
||||
})}
|
||||
</td>
|
||||
{/each}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<!-- row -->
|
||||
|
||||
@ -306,8 +306,8 @@
|
||||
</script>
|
||||
|
||||
<SEO
|
||||
title={`${$displayCompanyName} (${$stockTicker}) Cash Flow Statement`}
|
||||
description={`Detailed cash flow statements for ${$displayCompanyName} (${$stockTicker}), including operating cash flow, capex and free cash flow.`}
|
||||
title={`${$displayCompanyName} (${$stockTicker}) Ratios Statement`}
|
||||
description={`Financial ratios and valuation metrics for ${$displayCompanyName} (${$stockTicker}). Includes annual, quarterly and trailing numbers with history and charts.`}
|
||||
/>
|
||||
|
||||
<section class=" w-full overflow-hidden h-full">
|
||||
@ -373,7 +373,7 @@
|
||||
<div class="grid grid-cols-1 gap-2">
|
||||
{#if financialData?.length > 0}
|
||||
<div
|
||||
class="mb-2 flex flex-row items-center w-full justify-end sm:justify-center"
|
||||
class="flex flex-row items-center w-full justify-end sm:justify-center"
|
||||
>
|
||||
<label
|
||||
class="inline-flex mt-2 sm:mt-0 cursor-pointer relative mr-auto"
|
||||
@ -396,14 +396,35 @@
|
||||
</label>
|
||||
|
||||
<div class="flex flex-row items-center w-fit sm:ml-auto">
|
||||
<div class="relative inline-block text-left grow">
|
||||
<!--
|
||||
<div class="ml-2 relative inline-block text-left">
|
||||
<Button
|
||||
class="shadow-sm w-full border-gray-300 dark:border-gray-600 border sm:hover:bg-gray-100 dark:sm:hover:bg-primary ease-out flex flex-row justify-between items-center px-5 rounded-md truncate"
|
||||
>
|
||||
<svg
|
||||
class="w-4 h-4 bp:w-5 bp:h-5 pointer-events-none"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
style="max-width:40px"
|
||||
><path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M8 7h12m0 0l-4-4m4 4l-4 4m0 6H4m0 0l4 4m-4-4l4-4"
|
||||
></path></svg
|
||||
>
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<div class="ml-2 relative inline-block text-left grow">
|
||||
<DropdownMenu.Root>
|
||||
<DropdownMenu.Trigger asChild let:builder>
|
||||
<Button
|
||||
builders={[builder]}
|
||||
class="shadow-sm w-full border-gray-300 dark:border-gray-600 border sm:hover:bg-gray-100 dark:sm:hover:bg-primary ease-out flex flex-row justify-between items-center px-3 py-2 rounded-md truncate"
|
||||
class="shadow-sm w-full border-gray-300 dark:border-gray-600 border sm:hover:bg-gray-100 dark:sm:hover:bg-primary ease-out flex flex-row justify-between items-center px-3 py-1.5 rounded-md truncate"
|
||||
>
|
||||
<span class="truncate">{$timeFrame}</span>
|
||||
<span class="truncate">Raw</span>
|
||||
<svg
|
||||
class="-mr-1 ml-1 h-5 w-5 xs:ml-2 inline-block"
|
||||
viewBox="0 0 20 20"
|
||||
@ -422,52 +443,30 @@
|
||||
<DropdownMenu.Content
|
||||
class="w-56 h-fit max-h-72 overflow-y-auto scroller"
|
||||
>
|
||||
<DropdownMenu.Label
|
||||
class="text-muted dark:text-gray-400"
|
||||
>
|
||||
Select time frame
|
||||
</DropdownMenu.Label>
|
||||
<DropdownMenu.Separator />
|
||||
<DropdownMenu.Group>
|
||||
<DropdownMenu.Item
|
||||
on:click={() => ($timeFrame = "5Y")}
|
||||
class="cursor-pointer sm:hover:bg-gray-300 dark:sm:hover:bg-primary"
|
||||
>
|
||||
5 years
|
||||
Billions
|
||||
</DropdownMenu.Item>
|
||||
<DropdownMenu.Item
|
||||
on:click={() => ($timeFrame = "10Y")}
|
||||
class="cursor-pointer sm:hover:bg-gray-300 dark:sm:hover:bg-primary"
|
||||
>
|
||||
10 years
|
||||
Millions
|
||||
</DropdownMenu.Item>
|
||||
<DropdownMenu.Item
|
||||
on:click={() => ($timeFrame = "MAX")}
|
||||
class="cursor-pointer sm:hover:bg-gray-300 dark:sm:hover:bg-primary"
|
||||
>
|
||||
Max
|
||||
Raw
|
||||
</DropdownMenu.Item>
|
||||
</DropdownMenu.Group>
|
||||
</DropdownMenu.Content>
|
||||
</DropdownMenu.Root>
|
||||
</div>
|
||||
<Button
|
||||
on:click={() => exportFundamentalData("csv")}
|
||||
class="shadow-sm ml-2 w-fit border-gray-300 dark:border-gray-600 border sm:hover:bg-gray-100 dark:sm:hover:bg-primary ease-out flex flex-row justify-between items-center px-3 py-2 rounded-md truncate"
|
||||
>
|
||||
<span class="truncate">Download</span>
|
||||
<svg
|
||||
class="{['Pro', 'Plus']?.includes(data?.user?.tier)
|
||||
? 'hidden'
|
||||
: ''} ml-1 -mt-0.5 w-3.5 h-3.5"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 24 24"
|
||||
><path
|
||||
fill="currentColor"
|
||||
d="M17 9V7c0-2.8-2.2-5-5-5S7 4.2 7 7v2c-1.7 0-3 1.3-3 3v7c0 1.7 1.3 3 3 3h10c1.7 0 3-1.3 3-3v-7c0-1.7-1.3-3-3-3M9 7c0-1.7 1.3-3 3-3s3 1.3 3 3v2H9z"
|
||||
/></svg
|
||||
>
|
||||
</Button>
|
||||
-->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -487,6 +486,91 @@
|
||||
{/each}
|
||||
</div>
|
||||
{:else}
|
||||
<div
|
||||
class="flex flex-col sm:flex-row items-start sm:items-center sm:justify-between"
|
||||
>
|
||||
<span
|
||||
class="text-sm order-1 sm:order-0 mt-5 sm:mt-0 text-gray-600 dark:text-gray-400 w-full"
|
||||
>
|
||||
Financials in {data?.getProfileData?.currency}. Fiscal year
|
||||
is
|
||||
{data?.getProfileData?.fiscalYearRange}.
|
||||
</span>
|
||||
<div class="flex flex-row items-center justify-end w-full">
|
||||
<div class="sm:ml-auto relative inline-block">
|
||||
<DropdownMenu.Root>
|
||||
<DropdownMenu.Trigger asChild let:builder>
|
||||
<Button
|
||||
builders={[builder]}
|
||||
class="shadow-sm w-full sm:w-fit border-gray-300 dark:border-gray-600 border sm:hover:bg-gray-100 dark:sm:hover:bg-primary ease-out flex flex-row justify-between items-center px-3 py-1.5 rounded-md truncate"
|
||||
>
|
||||
<span class="truncate">{$timeFrame}</span>
|
||||
<svg
|
||||
class="-mr-1 ml-1 h-5 w-5 xs:ml-2 inline-block"
|
||||
viewBox="0 0 20 20"
|
||||
fill="currentColor"
|
||||
style="max-width:40px"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z"
|
||||
clip-rule="evenodd"
|
||||
></path>
|
||||
</svg>
|
||||
</Button>
|
||||
</DropdownMenu.Trigger>
|
||||
<DropdownMenu.Content
|
||||
class="w-56 h-fit max-h-72 overflow-y-auto scroller"
|
||||
>
|
||||
<DropdownMenu.Label
|
||||
class="text-muted dark:text-gray-400"
|
||||
>
|
||||
Select time frame
|
||||
</DropdownMenu.Label>
|
||||
<DropdownMenu.Separator />
|
||||
<DropdownMenu.Group>
|
||||
<DropdownMenu.Item
|
||||
on:click={() => ($timeFrame = "5Y")}
|
||||
class="cursor-pointer sm:hover:bg-gray-300 dark:sm:hover:bg-primary"
|
||||
>
|
||||
5 years
|
||||
</DropdownMenu.Item>
|
||||
<DropdownMenu.Item
|
||||
on:click={() => ($timeFrame = "10Y")}
|
||||
class="cursor-pointer sm:hover:bg-gray-300 dark:sm:hover:bg-primary"
|
||||
>
|
||||
10 years
|
||||
</DropdownMenu.Item>
|
||||
<DropdownMenu.Item
|
||||
on:click={() => ($timeFrame = "MAX")}
|
||||
class="cursor-pointer sm:hover:bg-gray-300 dark:sm:hover:bg-primary"
|
||||
>
|
||||
Max
|
||||
</DropdownMenu.Item>
|
||||
</DropdownMenu.Group>
|
||||
</DropdownMenu.Content>
|
||||
</DropdownMenu.Root>
|
||||
</div>
|
||||
<Button
|
||||
on:click={() => exportFundamentalData("csv")}
|
||||
class="shadow-sm ml-2 w-fit border-gray-300 dark:border-gray-600 border sm:hover:bg-gray-100 dark:sm:hover:bg-primary ease-out flex flex-row justify-between items-center px-3 py-1.5 rounded-md truncate"
|
||||
>
|
||||
<span class="truncate">Download</span>
|
||||
<svg
|
||||
class="{['Pro', 'Plus']?.includes(data?.user?.tier)
|
||||
? 'hidden'
|
||||
: ''} ml-1 -mt-0.5 w-3.5 h-3.5"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 24 24"
|
||||
><path
|
||||
fill="currentColor"
|
||||
d="M17 9V7c0-2.8-2.2-5-5-5S7 4.2 7 7v2c-1.7 0-3 1.3-3 3v7c0 1.7 1.3 3 3 3h10c1.7 0 3-1.3 3-3v-7c0-1.7-1.3-3-3-3M9 7c0-1.7 1.3-3 3-3s3 1.3 3 3v2H9z"
|
||||
/></svg
|
||||
>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="w-full rounded-none sm:rounded-md m-auto overflow-x-auto no-scrollbar"
|
||||
>
|
||||
@ -494,25 +578,40 @@
|
||||
class="table table-sm table-compact no-scrollbar rounded-none sm:rounded-md w-full bg-white dark:bg-table border border-gray-300 dark:border-gray-800 m-auto"
|
||||
>
|
||||
<thead class="text-muted dark:text-white dark:bg-default">
|
||||
<tr class="">
|
||||
<tr class="border min-w-[250px]">
|
||||
<td class="text-start text-sm font-semibold pr-10"
|
||||
>Year</td
|
||||
>Fiscal Year</td
|
||||
>
|
||||
{#each financialData as cash}
|
||||
{#each financialData as item}
|
||||
{#if filterRule === "annual"}
|
||||
<td class=" font-semibold text-sm text-end">
|
||||
{"FY" + cash?.fiscalYear?.slice(-2)}
|
||||
<td
|
||||
class=" font-semibold text-sm text-end border-l border-gray-300 dark:border-gray-800"
|
||||
>
|
||||
{"FY" + " " + item?.fiscalYear}
|
||||
</td>
|
||||
{:else}
|
||||
<td class=" font-semibold text-sm text-end">
|
||||
{"FY" +
|
||||
cash?.fiscalYear?.slice(-2) +
|
||||
" " +
|
||||
cash?.period}
|
||||
{item?.period + " " + item?.fiscalYear}
|
||||
</td>
|
||||
{/if}
|
||||
{/each}
|
||||
</tr>
|
||||
<tr class="border min-w-[250px]">
|
||||
<td class="text-start text-sm font-semibold"
|
||||
>Period Ending</td
|
||||
>
|
||||
{#each financialData as item}
|
||||
<td
|
||||
class=" font-semibold text-sm text-end border-l border-gray-300 dark:border-gray-800"
|
||||
>
|
||||
{new Date(item?.date).toLocaleDateString("en-US", {
|
||||
month: "short",
|
||||
day: "numeric",
|
||||
year: "numeric",
|
||||
})}
|
||||
</td>
|
||||
{/each}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<!-- row -->
|
||||
|
||||
@ -5,7 +5,6 @@ import { loginUserSchema, registerUserSchema } from "$lib/schemas";
|
||||
|
||||
export const load = async ({ params, locals }) => {
|
||||
const getData = async () => {
|
||||
let newsList;
|
||||
|
||||
const { apiURL, apiKey } = locals;
|
||||
|
||||
@ -23,9 +22,9 @@ export const load = async ({ params, locals }) => {
|
||||
body: JSON.stringify(postData),
|
||||
});
|
||||
|
||||
newsList = await response.json();
|
||||
const output = await response.json();
|
||||
|
||||
return newsList;
|
||||
return output;
|
||||
};
|
||||
|
||||
// Make sure to return a promise
|
||||
|
||||
BIN
static/img/astronaut.png
Normal file
BIN
static/img/astronaut.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 639 KiB |
4
static/img/astronaut.png:Zone.Identifier
Normal file
4
static/img/astronaut.png:Zone.Identifier
Normal file
@ -0,0 +1,4 @@
|
||||
[ZoneTransfer]
|
||||
ZoneId=3
|
||||
ReferrerUrl=https://www.canva.com/
|
||||
HostUrl=https://export-download.canva.com/UUB-4/DAGjgDUUB-4/15/0/0001-8423318452819072229.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAQYCGKMUH5AO7UJ26%2F20250402%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20250402T140745Z&X-Amz-Expires=17707&X-Amz-Signature=761feacdef49bdff3e2ad98387de9793c888669042037eefeb34735ca106cdbb&X-Amz-SignedHeaders=host&response-content-disposition=attachment%3B%20filename%2A%3DUTF-8%27%27Kopie%2520von%2520Kopie%2520von%2520Beige%2520Gr%25C3%25BCn%2520Neutral%2520Organisch%2520Pitch%2520Deck%2520Marketing%2520Pr%25C3%25A4sentation.png&response-expires=Wed%2C%2002%20Apr%202025%2019%3A02%3A52%20GMT
|
||||
Loading…
x
Reference in New Issue
Block a user