276 lines
12 KiB
Svelte
276 lines
12 KiB
Svelte
<script lang="ts">
|
|
import { Chart } from "svelte-echarts";
|
|
import { init, use } from "echarts/core";
|
|
import { LineChart, CustomChart } from "echarts/charts";
|
|
import { GridComponent, TooltipComponent } from "echarts/components";
|
|
import { CanvasRenderer } from "echarts/renderers";
|
|
import { abbreviateNumber, computeGrowthSingleList } from "$lib/utils";
|
|
use([
|
|
LineChart,
|
|
CustomChart,
|
|
GridComponent,
|
|
TooltipComponent,
|
|
CanvasRenderer,
|
|
]);
|
|
|
|
export let userTier;
|
|
export let title;
|
|
export let options;
|
|
export let tableDataList;
|
|
export let highDataList;
|
|
export let avgDataList;
|
|
export let lowDataList;
|
|
|
|
export let avgGrowthList = [];
|
|
export let graphType = null;
|
|
</script>
|
|
|
|
{#if graphType !== "growth"}
|
|
<div>
|
|
<h2 class="mb-2 text-xl font-bold">{title} Forecast</h2>
|
|
<div class="rounded-sm border p-2 border-gray-600">
|
|
<div class="app h-[275px] w-full">
|
|
{#if options !== null}
|
|
<Chart {init} {options} class="chart" />
|
|
{/if}
|
|
</div>
|
|
<div class="mt-3 overflow-x-auto p-0 text-center sm:p-0.5 lg:mt-3.5">
|
|
<table class="w-full text-right">
|
|
<thead
|
|
><tr
|
|
class="border-b border-gray-600 align-bottom text-white font-normal"
|
|
><th class="p-1 text-left font-semibold text-sm sm:text-[1rem]"
|
|
>{title}</th
|
|
>
|
|
{#each tableDataList as date, index}
|
|
<th class="p-1 font-semibold text-sm sm:text-[1rem]">
|
|
{#if index !== 0}{date}{/if}</th
|
|
>
|
|
{/each}
|
|
</tr></thead
|
|
>
|
|
<tbody
|
|
><tr class="border-b border-gray-600 last:border-0"
|
|
><td class="whitespace-nowrap px-1 py-[3px] text-left">High</td>
|
|
{#each highDataList as item, index}
|
|
<td class="px-1 py-[3px] text-sm sm:text-[1rem]">
|
|
{#if index !== 0}
|
|
{#if userTier !== "Pro" && index >= highDataList?.length - 2}
|
|
<a class="inline-block ml-0.5 text-white" href="/pricing"
|
|
>Pro<svg
|
|
class="w-4 h-4 ml-0.5 mb-1 inline-block text-[#A3A3A3]"
|
|
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
|
|
></a
|
|
>
|
|
{:else}
|
|
{abbreviateNumber(item?.val)}
|
|
{/if}
|
|
{/if}
|
|
</td>
|
|
{/each}
|
|
</tr><tr class="border-b border-gray-600 last:border-0"
|
|
><td class="whitespace-nowrap px-1 py-[3px] text-left">Avg</td>
|
|
{#each avgDataList as item, index}
|
|
<td class="px-1 py-[3px] text-sm sm:text-[1rem]">
|
|
{#if index !== 0}
|
|
{#if userTier !== "Pro" && index >= avgDataList?.length - 2}
|
|
<a class="inline-block ml-0.5 text-white" href="/pricing"
|
|
>Pro<svg
|
|
class="w-4 h-4 ml-0.5 mb-1 inline-block text-[#A3A3A3]"
|
|
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
|
|
></a
|
|
>
|
|
{:else}
|
|
{abbreviateNumber(item?.val)}
|
|
{/if}
|
|
{/if}
|
|
</td>
|
|
{/each}
|
|
</tr><tr class="border-b border-gray-600 last:border-0"
|
|
><td class="whitespace-nowrap px-1 py-[3px] text-left">Low</td>
|
|
{#each lowDataList as item, index}
|
|
<td class="px-1 py-[3px] text-sm sm:text-[1rem]">
|
|
{#if index !== 0}
|
|
{#if userTier !== "Pro" && index >= lowDataList?.length - 2}
|
|
<a class="inline-block ml-0.5 text-white" href="/pricing"
|
|
>Pro<svg
|
|
class="w-4 h-4 ml-0.5 mb-1 inline-block text-[#A3A3A3]"
|
|
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
|
|
></a
|
|
>
|
|
{:else}
|
|
{abbreviateNumber(item?.val)}
|
|
{/if}
|
|
{/if}
|
|
</td>
|
|
{/each}
|
|
</tr></tbody
|
|
>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{:else}
|
|
<div>
|
|
<h2 class="mb-2 text-xl font-bold">{title}</h2>
|
|
<div class="rounded-sm border p-2 border-gray-600">
|
|
<div class="app h-[275px] w-full">
|
|
{#if options !== null}
|
|
<Chart {init} {options} class="chart" />
|
|
{/if}
|
|
</div>
|
|
<div class="mt-3 overflow-x-auto p-0 text-center sm:p-0.5 lg:mt-3.5">
|
|
<table class="w-full text-right">
|
|
<thead
|
|
><tr
|
|
class="border-b border-gray-600 align-bottom text-white font-normal whitespace-nowrap"
|
|
><th class="p-1 text-left font-semibold text-sm sm:text-[1rem]"
|
|
>{title}</th
|
|
>
|
|
{#each tableDataList as date, index}
|
|
<th class="p-1 font-semibold text-sm sm:text-[1rem]"
|
|
>{#if index !== 0}{date}{/if}</th
|
|
>
|
|
{/each}
|
|
</tr></thead
|
|
>
|
|
<tbody
|
|
><tr class="border-b border-gray-600 last:border-0"
|
|
><td class="whitespace-nowrap px-1 py-[3px] text-left">High</td>
|
|
{#each computeGrowthSingleList(highDataList, avgDataList) as item, index}
|
|
<td class="px-1 py-[3px] text-sm sm:text-[1rem]">
|
|
{#if index !== 0}
|
|
{#if userTier !== "Pro" && index >= highDataList?.length - 2}
|
|
<a class="inline-block ml-0.5 text-white" href="/pricing"
|
|
>Pro<svg
|
|
class="w-4 h-4 ml-0.5 mb-1 inline-block text-[#A3A3A3]"
|
|
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
|
|
></a
|
|
>
|
|
{:else}
|
|
<span
|
|
class={item?.growth !== null && item?.growth > 0
|
|
? "text-[#00FC50] before:content-['+']"
|
|
: item?.growth < 0
|
|
? "text-[#FF2F1F]"
|
|
: "text-white"}
|
|
>
|
|
{item?.growth !== null && Math.abs(item?.growth - 0) > 0
|
|
? abbreviateNumber(item?.growth) + "%"
|
|
: "-"}
|
|
</span>
|
|
{/if}
|
|
{/if}
|
|
</td>
|
|
{/each}
|
|
</tr><tr class="border-b border-gray-600 last:border-0"
|
|
><td class="whitespace-nowrap px-1 py-[3px] text-left">Avg</td>
|
|
{#each avgGrowthList?.filter((item) => item.FY >= 25) as item, index}
|
|
<td class="px-1 py-[3px] text-sm sm:text-[1rem]">
|
|
{#if index !== 0}
|
|
{#if userTier !== "Pro" && index >= avgDataList?.length - 2}
|
|
<a class="inline-block ml-0.5 text-white" href="/pricing"
|
|
>Pro<svg
|
|
class="w-4 h-4 ml-0.5 mb-1 inline-block text-[#A3A3A3]"
|
|
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
|
|
></a
|
|
>
|
|
{:else}
|
|
<span
|
|
class={item?.growth !== null && item?.growth > 0
|
|
? "text-[#00FC50] before:content-['+']"
|
|
: item?.growth < 0
|
|
? "text-[#FF2F1F]"
|
|
: "text-white"}
|
|
>
|
|
{item?.growth !== null && Math.abs(item?.growth - 0) > 0
|
|
? abbreviateNumber(item?.growth) + "%"
|
|
: "-"}
|
|
</span>
|
|
{/if}
|
|
{/if}
|
|
</td>
|
|
{/each}
|
|
</tr><tr class="border-b border-gray-600 last:border-0"
|
|
><td class="whitespace-nowrap px-1 py-[3px] text-left">Low</td>
|
|
{#each computeGrowthSingleList(lowDataList, avgDataList) as item, index}
|
|
<td class="px-1 py-[3px] text-sm sm:text-[1rem]">
|
|
{#if index !== 0}
|
|
{#if userTier !== "Pro" && index >= lowDataList?.length - 2}
|
|
<a class="inline-block ml-0.5 text-white" href="/pricing"
|
|
>Pro<svg
|
|
class="w-4 h-4 ml-0.5 mb-1 inline-block text-[#A3A3A3]"
|
|
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
|
|
></a
|
|
>
|
|
{:else}
|
|
<span
|
|
class={item?.growth !== null && item?.growth > 0
|
|
? "text-[#00FC50] before:content-['+']"
|
|
: item?.growth < 0
|
|
? "text-[#FF2F1F]"
|
|
: "text-white"}
|
|
>
|
|
{item?.growth !== null && Math.abs(item?.growth - 0) > 0
|
|
? abbreviateNumber(item?.growth) + "%"
|
|
: "-"}
|
|
</span>
|
|
{/if}
|
|
{/if}
|
|
</td>
|
|
{/each}
|
|
</tr></tbody
|
|
>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{/if}
|
|
|
|
<style>
|
|
.app {
|
|
height: 300px;
|
|
max-width: 100%; /* Ensure chart width doesn't exceed the container */
|
|
}
|
|
|
|
@media (max-width: 640px) {
|
|
.app {
|
|
height: 210px;
|
|
}
|
|
}
|
|
|
|
.chart {
|
|
width: 100%;
|
|
}
|
|
</style>
|