clean code metric page
This commit is contained in:
parent
b6d8342898
commit
97d3b168bb
106
src/lib/components/Table/MetricTable.svelte
Normal file
106
src/lib/components/Table/MetricTable.svelte
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
<script>
|
||||||
|
import { abbreviateNumber } from "$lib/utils";
|
||||||
|
|
||||||
|
export let title = "";
|
||||||
|
export let dateData = [];
|
||||||
|
export let names = [];
|
||||||
|
export let categoryValues = [];
|
||||||
|
export let growthValues = [];
|
||||||
|
export let getHref = (name) => "#"; // optional, for linking revenue names
|
||||||
|
|
||||||
|
// Helper to format dates consistently.
|
||||||
|
const formatDate = (d) => {
|
||||||
|
const date = new Date(d);
|
||||||
|
return isNaN(date)
|
||||||
|
? "Invalid Date"
|
||||||
|
: date.toLocaleString("en-US", {
|
||||||
|
month: "short",
|
||||||
|
day: "numeric",
|
||||||
|
year: "numeric",
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Format a growth value for display.
|
||||||
|
const formatGrowth = (growthValue) => {
|
||||||
|
if (growthValue === null || growthValue === undefined) return "n/a";
|
||||||
|
return (growthValue > 0 ? "+" : "") + growthValue.toFixed(2) + "%";
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<section class="my-10">
|
||||||
|
<h2 class="mt-5 text-xl sm:text-2xl font-bold mb-4">{title}</h2>
|
||||||
|
|
||||||
|
<div
|
||||||
|
class="no-scrollbar flex justify-start items-center w-screen sm:w-full mt-6 m-auto overflow-x-auto pr-5 sm:pr-0"
|
||||||
|
>
|
||||||
|
<table
|
||||||
|
class="table table-sm table-compact no-scrollbar rounded-none sm:rounded-md w-full border border-gray-300 dark:border-gray-800 m-auto"
|
||||||
|
>
|
||||||
|
<thead class="text-muted dark:text-white dark:bg-default">
|
||||||
|
<tr>
|
||||||
|
<th
|
||||||
|
class="border-b border-r border-gray-300 dark:border-gray-800 font-semibold text-sm text-start"
|
||||||
|
>
|
||||||
|
Period Ending
|
||||||
|
</th>
|
||||||
|
{#each dateData as item}
|
||||||
|
<th
|
||||||
|
class="z-20 border-b border-r min-w-[120px] border-gray-300 dark:border-gray-800 font-semibold text-sm text-end"
|
||||||
|
>
|
||||||
|
{formatDate(item)}
|
||||||
|
</th>
|
||||||
|
{/each}
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody class="shadow-md">
|
||||||
|
{#each names as name, index}
|
||||||
|
<tr class="odd:bg-[#F6F7F8] dark:odd:bg-odd">
|
||||||
|
<th
|
||||||
|
class="whitespace-nowrap text-sm sm:text-[1rem] font-normal text-start border-b border-r border-gray-300 dark:border-gray-800"
|
||||||
|
>
|
||||||
|
{#if title !== "Revenue by Geography" && getHref}
|
||||||
|
<a
|
||||||
|
href={getHref(name)}
|
||||||
|
class="sm:hover:text-blue-700 dark:sm:hover:text-blue-400 cursor-pointer underline underline-offset-4"
|
||||||
|
>
|
||||||
|
{name} Revenue
|
||||||
|
</a>
|
||||||
|
{:else}
|
||||||
|
{name} Revenue
|
||||||
|
{/if}
|
||||||
|
</th>
|
||||||
|
{#each categoryValues[index] as value}
|
||||||
|
<td
|
||||||
|
class="whitespace-nowrap text-sm sm:text-[1rem] text-end border-b border-r border-gray-300 dark:border-gray-800"
|
||||||
|
>
|
||||||
|
{@html value !== null && value !== undefined && value !== 0
|
||||||
|
? abbreviateNumber(value, false, true)
|
||||||
|
: "n/a"}
|
||||||
|
</td>
|
||||||
|
{/each}
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td
|
||||||
|
class="whitespace-nowrap text-sm sm:text-[1rem] font-normal text-start border-b border-r border-gray-300 dark:border-gray-800"
|
||||||
|
>
|
||||||
|
<span class="ml-2">{name} Revenue Growth</span>
|
||||||
|
</td>
|
||||||
|
{#each growthValues[index] as growthValue}
|
||||||
|
<td
|
||||||
|
class="text-sm sm:text-[1rem] text-end
|
||||||
|
{growthValue > 0
|
||||||
|
? 'text-green-800 dark:text-[#00FC50]'
|
||||||
|
: growthValue < 0
|
||||||
|
? 'text-red-800 dark:text-[#FF2F1F]'
|
||||||
|
: ''}
|
||||||
|
border-b border-r border-gray-300 dark:border-gray-800"
|
||||||
|
>
|
||||||
|
{formatGrowth(growthValue)}
|
||||||
|
</td>
|
||||||
|
{/each}
|
||||||
|
</tr>
|
||||||
|
{/each}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
@ -1,8 +1,9 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { displayCompanyName, stockTicker } from "$lib/store";
|
import { displayCompanyName, stockTicker } from "$lib/store";
|
||||||
import { abbreviateNumber } from "$lib/utils";
|
import { removeCompanyStrings } from "$lib/utils";
|
||||||
import Infobox from "$lib/components/Infobox.svelte";
|
import Infobox from "$lib/components/Infobox.svelte";
|
||||||
import SEO from "$lib/components/SEO.svelte";
|
import SEO from "$lib/components/SEO.svelte";
|
||||||
|
import MetricTable from "$lib/components/Table/MetricTable.svelte";
|
||||||
|
|
||||||
export let data;
|
export let data;
|
||||||
|
|
||||||
@ -77,241 +78,43 @@
|
|||||||
<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:pl-7 sm:pb-7 sm:pt-7 w-full m-auto mt-2 sm:mt-0">
|
<div class="sm:pl-7 sm:pb-7 w-full m-auto mt-2 sm:mt-0">
|
||||||
{#if revenueNames?.length !== 0 || geographicNames?.length !== 0}
|
{#if revenueNames?.length !== 0 || geographicNames?.length !== 0}
|
||||||
<h2 class="mt-5 text-xl sm:text-2xl font-bold mb-4">
|
{#if revenueNames?.length}
|
||||||
{$displayCompanyName} Revenue Breakdown
|
<MetricTable
|
||||||
</h2>
|
title="{removeCompanyStrings(
|
||||||
|
$displayCompanyName,
|
||||||
<div
|
)} Revenue Breakdown"
|
||||||
class="no-scrollbar flex justify-start items-center w-screen sm:w-full mt-6 m-auto overflow-x-auto pr-5 sm:pr-0"
|
dateData={xData}
|
||||||
>
|
names={revenueNames}
|
||||||
<table
|
{categoryValues}
|
||||||
class="table table-sm table-compact no-scrollbar rounded-none sm:rounded-md w-full border border-gray-300 dark:border-gray-800 m-auto"
|
{growthValues}
|
||||||
>
|
{getHref}
|
||||||
<thead class="text-muted dark:text-white dark:bg-default">
|
/>
|
||||||
<tr>
|
|
||||||
<th
|
|
||||||
class=" border-b border-gray-300 dark:border-gray-800 font-semibold text-sm sm:text-[1rem] text-start"
|
|
||||||
>Quarter</th
|
|
||||||
>
|
|
||||||
{#each xData as item}
|
|
||||||
<th
|
|
||||||
class="z-20 border-b border-gray-300 dark:border-gray-800 font-semibold text-sm text-center"
|
|
||||||
>{new Date(item ?? null)?.toLocaleString("en-US", {
|
|
||||||
month: "short",
|
|
||||||
day: "numeric",
|
|
||||||
year: "numeric",
|
|
||||||
})}</th
|
|
||||||
>
|
|
||||||
{/each}
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody class="shadow-md">
|
|
||||||
{#each revenueNames as name, index}
|
|
||||||
<tr class=" odd:bg-[#F6F7F8] dark:odd:bg-odd">
|
|
||||||
<th
|
|
||||||
class="whitespace-nowrap odd:bg-[#F6F7F8] dark:odd:bg-odd text-sm sm:text-[1rem] font-normal text-start border-b border-gray-300 dark:border-gray-800"
|
|
||||||
>
|
|
||||||
<a
|
|
||||||
href={getHref(name)}
|
|
||||||
class="sm:hover:text-blue-700 dark:sm:hover:text-blue-400 cursor-pointer underline underline-offset-4"
|
|
||||||
>
|
|
||||||
{name} Revenue
|
|
||||||
</a>
|
|
||||||
</th>
|
|
||||||
{#each categoryValues[index] as value}
|
|
||||||
<td
|
|
||||||
class=" text-sm sm:text-[1rem] text-end border-b border-gray-300 dark:border-gray-800"
|
|
||||||
>
|
|
||||||
{@html value !== null && value !== undefined
|
|
||||||
? abbreviateNumber(value, false, true)
|
|
||||||
: "n/a"}
|
|
||||||
</td>
|
|
||||||
{/each}
|
|
||||||
</tr>
|
|
||||||
<tr class="">
|
|
||||||
<td
|
|
||||||
class=" whitespace-nowrap text-sm sm:text-[1rem] text-start border-b border-gray-300 dark:border-gray-800"
|
|
||||||
>
|
|
||||||
<span class="ml-2">{name} Revenue Growth</span>
|
|
||||||
</td>
|
|
||||||
{#each growthValues[index] as growthValue}
|
|
||||||
<td
|
|
||||||
class="text-sm sm:text-[1rem] text-end {growthValue > 0
|
|
||||||
? 'text-green-800 dark:text-[#00FC50]'
|
|
||||||
: growthValue < 0
|
|
||||||
? 'text-red-800 dark:text-[#FF2F1F]'
|
|
||||||
: ''} border-b border-gray-300 dark:border-gray-800"
|
|
||||||
>
|
|
||||||
{growthValue > 0 ? "+" : ""}{growthValue !== null &&
|
|
||||||
growthValue !== undefined
|
|
||||||
? growthValue?.toFixed(2) + "%"
|
|
||||||
: "n/a"}
|
|
||||||
</td>
|
|
||||||
{/each}
|
|
||||||
</tr>
|
|
||||||
{/each}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{#if geographicNames?.length !== 0}
|
|
||||||
<h2 class="mt-10 text-xl sm:text-2xl font-bold mb-4">
|
|
||||||
Revenue by Geography
|
|
||||||
</h2>
|
|
||||||
|
|
||||||
<div
|
|
||||||
class="no-scrollbar flex justify-start items-center w-screen sm:w-full mt-6 m-auto overflow-x-auto ovef pr-5 sm:pr-0"
|
|
||||||
>
|
|
||||||
<table
|
|
||||||
class="table table-sm table-compact no-scrollbar rounded-none sm:rounded-md w-full border border-gray-300 dark:border-gray-800 m-auto"
|
|
||||||
>
|
|
||||||
<thead class="text-muted dark:text-white dark:bg-default">
|
|
||||||
<tr>
|
|
||||||
<th
|
|
||||||
class=" border-b border-gray-300 dark:border-gray-800 font-semibold text-sm sm:text-[1rem] text-start"
|
|
||||||
>Quarter</th
|
|
||||||
>
|
|
||||||
{#each geographicXData as item}
|
|
||||||
<th
|
|
||||||
class="z-20 border-b border-gray-300 dark:border-gray-800 font-semibold text-sm text-center"
|
|
||||||
>{new Date(item ?? null)?.toLocaleString("en-US", {
|
|
||||||
month: "short",
|
|
||||||
day: "numeric",
|
|
||||||
year: "numeric",
|
|
||||||
})}</th
|
|
||||||
>
|
|
||||||
{/each}
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody class="shadow-md">
|
|
||||||
{#each geographicNames as name, index}
|
|
||||||
<tr class=" odd:bg-[#F6F7F8] dark:odd:bg-odd">
|
|
||||||
<th
|
|
||||||
class="whitespace-nowrap dark:odd:bg-odd text-sm sm:text-[1rem] font-normal text-start border-b border-gray-300 dark:border-gray-800"
|
|
||||||
>{name} Revenue</th
|
|
||||||
>
|
|
||||||
{#each geographiCategoryValues[index] as value}
|
|
||||||
<td
|
|
||||||
class="whitespace-nowrap text-sm sm:text-[1rem] font-normal text-center border-b border-gray-300 dark:border-gray-800"
|
|
||||||
>
|
|
||||||
{@html value !== null &&
|
|
||||||
value !== 0 &&
|
|
||||||
value !== undefined
|
|
||||||
? abbreviateNumber(value, false, true)
|
|
||||||
: "n/a"}
|
|
||||||
</td>
|
|
||||||
{/each}
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td
|
|
||||||
class="whitespace-nowrap text-sm sm:text-[1rem] font-normal text-start border-b border-gray-300 dark:border-gray-800"
|
|
||||||
>
|
|
||||||
<span class="ml-2">{name} Revenue Growth</span>
|
|
||||||
</td>
|
|
||||||
{#each geographicGrowthValues[index] as growthValue}
|
|
||||||
<td
|
|
||||||
class="text-sm sm:text-[1rem] text-center {growthValue >
|
|
||||||
0
|
|
||||||
? 'text-green-800 dark:text-[#00FC50]'
|
|
||||||
: growthValue < 0
|
|
||||||
? 'text-red-800 dark:text-[#FF2F1F]'
|
|
||||||
: ''} border-b border-gray-300 dark:border-gray-800"
|
|
||||||
>
|
|
||||||
{growthValue > 0 ? "+" : ""}{growthValue !== null &&
|
|
||||||
growthValue !== 0 &&
|
|
||||||
growthValue !== undefined
|
|
||||||
? growthValue?.toFixed(2) + "%"
|
|
||||||
: "n/a"}
|
|
||||||
</td>
|
|
||||||
{/each}
|
|
||||||
</tr>
|
|
||||||
{/each}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
{#if operatingExpensesNames?.length !== 0}
|
{#if geographicNames?.length}
|
||||||
<h2 class="mt-10 text-xl sm:text-2xl font-bold mb-4">
|
<MetricTable
|
||||||
Operating Expense Breakdown
|
title="Revenue by Geography"
|
||||||
</h2>
|
dateData={geographicXData}
|
||||||
|
names={geographicNames}
|
||||||
|
categoryValues={geographiCategoryValues}
|
||||||
|
growthValues={geographicGrowthValues}
|
||||||
|
/>
|
||||||
|
{/if}
|
||||||
|
|
||||||
<div
|
{#if operatingExpensesNames?.length}
|
||||||
class="no-scrollbar flex justify-start items-center w-screen sm:w-full mt-6 m-auto overflow-x-auto pr-5 sm:pr-0"
|
<MetricTable
|
||||||
>
|
title="Operating Expense Breakdown"
|
||||||
<table
|
dateData={operatingExpensesXData}
|
||||||
class="table table-sm table-compact no-scrollbar rounded-none sm:rounded-md w-full border border-gray-300 dark:border-gray-800 m-auto"
|
names={operatingExpensesNames}
|
||||||
>
|
categoryValues={operatingExpensesCategoryValues}
|
||||||
<thead class="text-muted dark:text-white dark:bg-default">
|
growthValues={operatingExpensesGrowthValues}
|
||||||
<tr>
|
/>
|
||||||
<th
|
|
||||||
class=" border-b border-gray-300 dark:border-gray-800 font-semibold text-sm sm:text-[1rem] text-start"
|
|
||||||
>Quarter</th
|
|
||||||
>
|
|
||||||
{#each operatingExpensesXData as item}
|
|
||||||
<th
|
|
||||||
class="z-20 border-b border-gray-300 dark:border-gray-800 font-semibold text-sm text-center"
|
|
||||||
>{new Date(item ?? null)?.toLocaleString("en-US", {
|
|
||||||
month: "short",
|
|
||||||
day: "numeric",
|
|
||||||
year: "numeric",
|
|
||||||
})}</th
|
|
||||||
>
|
|
||||||
{/each}
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody class="shadow-md">
|
|
||||||
{#each operatingExpensesNames as name, index}
|
|
||||||
<tr class=" odd:bg-[#F6F7F8] dark:odd:bg-odd">
|
|
||||||
<th
|
|
||||||
class="whitespace-nowrap odd:bg-[#F6F7F8] dark:odd:bg-odd text-sm sm:text-[1rem] font-normal text-start border-b border-gray-300 dark:border-gray-800"
|
|
||||||
>{name} Revenue</th
|
|
||||||
>
|
|
||||||
{#each operatingExpensesCategoryValues[index] as value}
|
|
||||||
<td
|
|
||||||
class=" whitespace-nowrap text-sm sm:text-[1rem] text-center border-b border-gray-300 dark:border-gray-800"
|
|
||||||
>
|
|
||||||
{@html value !== null &&
|
|
||||||
value !== 0 &&
|
|
||||||
value !== undefined
|
|
||||||
? abbreviateNumber(value, false, true)
|
|
||||||
: "n/a"}
|
|
||||||
</td>
|
|
||||||
{/each}
|
|
||||||
</tr>
|
|
||||||
<tr class="">
|
|
||||||
<td
|
|
||||||
class="whitespace-nowrap text-sm sm:text-[1rem] font-normal text-start border-b border-gray-300 dark:border-gray-800"
|
|
||||||
>
|
|
||||||
<span class="ml-2">{name} Revenue Growth</span>
|
|
||||||
</td>
|
|
||||||
{#each operatingExpensesGrowthValues[index] as growthValue}
|
|
||||||
<td
|
|
||||||
class="text-sm sm:text-[1rem] text-center {growthValue >
|
|
||||||
0
|
|
||||||
? 'text-green-800 dark:text-[#00FC50]'
|
|
||||||
: growthValue < 0
|
|
||||||
? 'text-red-800 dark:text-[#FF2F1F]'
|
|
||||||
: ''} border-b border-gray-300 dark:border-gray-800"
|
|
||||||
>
|
|
||||||
{growthValue > 0 ? "+" : ""}{growthValue !== null &&
|
|
||||||
growthValue !== 0 &&
|
|
||||||
growthValue !== undefined
|
|
||||||
? growthValue?.toFixed(2) + "%"
|
|
||||||
: "n/a"}
|
|
||||||
</td>
|
|
||||||
{/each}
|
|
||||||
</tr>
|
|
||||||
{/each}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
{/if}
|
{/if}
|
||||||
{:else}
|
{:else}
|
||||||
<Infobox
|
<Infobox
|
||||||
text={`Currently, there are no business metrics available for ${$stockTicker}.`}
|
text={`Currently, there are no business metrics available for ${removeCompanyStrings($displayCompanyName)}.`}
|
||||||
/>
|
/>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -38,7 +38,6 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
function plotData() {
|
function plotData() {
|
||||||
console.log(dataset);
|
|
||||||
const plotDataset = [...dataset]?.sort(
|
const plotDataset = [...dataset]?.sort(
|
||||||
(a, b) => new Date(a?.date) - new Date(b?.date),
|
(a, b) => new Date(a?.date) - new Date(b?.date),
|
||||||
);
|
);
|
||||||
@ -125,7 +124,6 @@
|
|||||||
// Loop through each point in the shared tooltip
|
// Loop through each point in the shared tooltip
|
||||||
this.points.forEach((point) => {
|
this.points.forEach((point) => {
|
||||||
tooltipContent += `
|
tooltipContent += `
|
||||||
<span style="display:inline-block; width:10px; height:10px; background-color:${point.color}; border-radius:50%; margin-right:5px;"></span>
|
|
||||||
<span class="font-semibold text-sm">${point.series.name}:</span>
|
<span class="font-semibold text-sm">${point.series.name}:</span>
|
||||||
<span class="font-normal text-sm">${abbreviateNumber(point.y)}</span><br>`;
|
<span class="font-normal text-sm">${abbreviateNumber(point.y)}</span><br>`;
|
||||||
});
|
});
|
||||||
@ -155,6 +153,7 @@
|
|||||||
name: "Revenue",
|
name: "Revenue",
|
||||||
data: valueList,
|
data: valueList,
|
||||||
color: $mode === "light" ? "#2C6288" : "white",
|
color: $mode === "light" ? "#2C6288" : "white",
|
||||||
|
borderRadius: "2",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
legend: {
|
legend: {
|
||||||
@ -221,10 +220,18 @@
|
|||||||
>
|
>
|
||||||
<thead class="text-muted dark:text-white dark:bg-default">
|
<thead class="text-muted dark:text-white dark:bg-default">
|
||||||
<tr class="border-b border-gray-300 dark:border-gray-800">
|
<tr class="border-b border-gray-300 dark:border-gray-800">
|
||||||
<th class=" font-semibold text-start text-sm">Quarter</th>
|
<th class=" font-semibold text-start text-sm sm:text-[1rem]"
|
||||||
<th class=" font-semibold text-end text-sm">Value</th>
|
>Quarter</th
|
||||||
<th class=" font-semibold text-end text-sm"> Change </th>
|
>
|
||||||
<th class=" font-semibold text-end text-sm">Growth</th>
|
<th class=" font-semibold text-end text-sm sm:text-[1rem]"
|
||||||
|
>Value</th
|
||||||
|
>
|
||||||
|
<th class=" font-semibold text-end text-sm sm:text-[1rem]">
|
||||||
|
Change
|
||||||
|
</th>
|
||||||
|
<th class=" font-semibold text-end text-sm sm:text-[1rem]"
|
||||||
|
>Growth</th
|
||||||
|
>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user