update color scheme
This commit is contained in:
parent
990c818727
commit
e6d42b8f9d
@ -68,7 +68,7 @@
|
||||
class="stroke-current {score >= 7
|
||||
? 'text-[#00FC50]'
|
||||
: score >= 4
|
||||
? 'text-[#FF9E21]'
|
||||
? 'text-[#FBCE3C]'
|
||||
: 'text-[#FF2F1F]'}"
|
||||
stroke-width="3"
|
||||
stroke-dasharray="100.48"
|
||||
|
||||
@ -82,7 +82,7 @@
|
||||
<div class="fixed z-[100] bottom-8 sm:bottom-10 right-8 sm:right-16">
|
||||
<label
|
||||
for="feedbackInfo"
|
||||
class="inline-flex items-center justify-center w-12 h-12 sm:w-full sm:h-10 font-medium bg-gray-700 sm:bg-[#FFEDE5] ml-1 mr-0 sm:mr-2 rounded-full cursor-pointer"
|
||||
class="inline-flex items-center justify-center w-12 h-12 sm:w-full sm:h-10 font-semibold bg-gray-700 sm:bg-[#FBCE3C] ml-1 mr-0 sm:mr-2 rounded-full cursor-pointer"
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
@ -111,10 +111,10 @@
|
||||
>
|
||||
<label
|
||||
for="feedbackInfo"
|
||||
class="cursor-pointer modal-backdrop bg-[#fff] bg-opacity-[0.05]"
|
||||
class="cursor-pointer modal-backdrop bg-[#fff] bg-opacity-[0.1]"
|
||||
></label>
|
||||
|
||||
<div class="modal-box w-full bg-[#000]">
|
||||
<div class="modal-box w-full bg-[#09090B] border border-gray-600">
|
||||
<div class="flex flex-row items-center pt-5">
|
||||
<h1 class="text-white text-xl sm:text-2xl font-bold">
|
||||
Your Feedback matters!
|
||||
@ -185,10 +185,10 @@
|
||||
|
||||
<button
|
||||
on:click={() => sendFeedback()}
|
||||
class="mb-4 px-3 py-2 bg-purple-600 smhover:bg-purple-700 {rating?.length !==
|
||||
class="mb-4 px-3 py-2 bg-[#FBCE3C] sm:hover:bg-[#e8b305] {rating?.length !==
|
||||
0 && inputValue?.length !== 0
|
||||
? 'opacity-100 cursor-pointer'
|
||||
: 'opacity-60 cursor-not-allowed'} w-11/12 rounded-lg m-auto text-white font-semibold text-md"
|
||||
: 'opacity-60 cursor-not-allowed'} w-11/12 rounded-lg m-auto text-black font-semibold text-md"
|
||||
>
|
||||
Send Feedback
|
||||
</button>
|
||||
|
||||
@ -1,13 +1,20 @@
|
||||
<script lang="ts">
|
||||
import { governmentContractComponent, displayCompanyName, stockTicker, screenWidth, getCache, setCache } from '$lib/store';
|
||||
import InfoModal from '$lib/components/InfoModal.svelte';
|
||||
import { Chart } from 'svelte-echarts';
|
||||
import {
|
||||
governmentContractComponent,
|
||||
displayCompanyName,
|
||||
stockTicker,
|
||||
screenWidth,
|
||||
getCache,
|
||||
setCache,
|
||||
} from "$lib/store";
|
||||
import InfoModal from "$lib/components/InfoModal.svelte";
|
||||
import { Chart } from "svelte-echarts";
|
||||
import { abbreviateNumber } from "$lib/utils";
|
||||
|
||||
import { init, use } from 'echarts/core';
|
||||
import { BarChart } from 'echarts/charts';
|
||||
import { GridComponent } from 'echarts/components';
|
||||
import { CanvasRenderer } from 'echarts/renderers';
|
||||
import { init, use } from "echarts/core";
|
||||
import { BarChart } from "echarts/charts";
|
||||
import { GridComponent } from "echarts/components";
|
||||
import { CanvasRenderer } from "echarts/renderers";
|
||||
use([BarChart, GridComponent, CanvasRenderer]);
|
||||
|
||||
let isLoaded = false;
|
||||
@ -15,7 +22,7 @@
|
||||
let optionsData;
|
||||
let avgNumberOfContracts = 0;
|
||||
let displayMaxContracts = 0;
|
||||
let displayYear = 'n/a';
|
||||
let displayYear = "n/a";
|
||||
let totalAmount;
|
||||
let totalContract;
|
||||
|
||||
@ -31,41 +38,46 @@
|
||||
numList?.push(item?.numOfContracts);
|
||||
});
|
||||
|
||||
totalContract = rawData?.reduce((sum, item) => sum + item?.numOfContracts, 0);
|
||||
totalContract = rawData?.reduce(
|
||||
(sum, item) => sum + item?.numOfContracts,
|
||||
0,
|
||||
);
|
||||
totalAmount = rawData?.reduce((sum, item) => sum + item?.amount, 0);
|
||||
|
||||
avgNumberOfContracts = Math.floor(totalContract / rawData?.length);
|
||||
const { year: yearWithMaxContracts, numOfContracts: maxContracts } = rawData?.reduce(
|
||||
(max, contract) => (contract?.numOfContracts > max?.numOfContracts ? contract : max),
|
||||
rawData?.at(0)
|
||||
);
|
||||
const { year: yearWithMaxContracts, numOfContracts: maxContracts } =
|
||||
rawData?.reduce(
|
||||
(max, contract) =>
|
||||
contract?.numOfContracts > max?.numOfContracts ? contract : max,
|
||||
rawData?.at(0),
|
||||
);
|
||||
displayYear = yearWithMaxContracts;
|
||||
displayMaxContracts = maxContracts;
|
||||
|
||||
const option = {
|
||||
silent: true,
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
trigger: "axis",
|
||||
hideDelay: 100, // Set the delay in milliseconds
|
||||
},
|
||||
animation: false,
|
||||
grid: {
|
||||
left: '2%',
|
||||
right: $screenWidth < 640 ? '0%' : '2%',
|
||||
bottom: '0%',
|
||||
top: '10%',
|
||||
left: "2%",
|
||||
right: $screenWidth < 640 ? "0%" : "2%",
|
||||
bottom: "0%",
|
||||
top: "10%",
|
||||
containLabel: true,
|
||||
},
|
||||
xAxis: {
|
||||
data: dates,
|
||||
type: 'category',
|
||||
type: "category",
|
||||
axisLabel: {
|
||||
color: '#fff',
|
||||
color: "#fff",
|
||||
},
|
||||
},
|
||||
yAxis: [
|
||||
{
|
||||
type: 'value',
|
||||
type: "value",
|
||||
splitLine: {
|
||||
show: false, // Disable x-axis grid lines
|
||||
},
|
||||
@ -74,32 +86,32 @@
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'value',
|
||||
type: "value",
|
||||
splitLine: {
|
||||
show: false, // Disable x-axis grid lines
|
||||
},
|
||||
axisLabel: {
|
||||
show: false, // Hide y-axis labels
|
||||
},
|
||||
position: 'right',
|
||||
position: "right",
|
||||
},
|
||||
],
|
||||
series: [
|
||||
{
|
||||
name: '# of Contracts',
|
||||
name: "# of Contracts",
|
||||
data: numList,
|
||||
type: 'line',
|
||||
type: "line",
|
||||
yAxisIndex: 1,
|
||||
itemStyle: {
|
||||
color: '#fff', // Change bar color to white
|
||||
color: "#fff", // Change bar color to white
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'Amount',
|
||||
name: "Amount",
|
||||
data: amountList,
|
||||
type: 'bar',
|
||||
type: "bar",
|
||||
itemStyle: {
|
||||
color: '#FF9E21', // Change bar color to orange
|
||||
color: "#FBCE3C", // Change bar color to orange
|
||||
},
|
||||
},
|
||||
],
|
||||
@ -109,27 +121,27 @@
|
||||
}
|
||||
|
||||
const getGovernmentContract = async (ticker) => {
|
||||
const cachedData = getCache(ticker, 'getGovernmentContract');
|
||||
const cachedData = getCache(ticker, "getGovernmentContract");
|
||||
if (cachedData) {
|
||||
rawData = cachedData;
|
||||
} else {
|
||||
const postData = { ticker: ticker, path: 'government-contract' };
|
||||
const response = await fetch('/api/ticker-data', {
|
||||
method: 'POST',
|
||||
const postData = { ticker: ticker, path: "government-contract" };
|
||||
const response = await fetch("/api/ticker-data", {
|
||||
method: "POST",
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify(postData),
|
||||
});
|
||||
rawData = await response?.json();
|
||||
setCache(ticker, rawData, 'getGovernmentContract');
|
||||
setCache(ticker, rawData, "getGovernmentContract");
|
||||
}
|
||||
|
||||
governmentContractComponent.set(rawData?.length !== 0);
|
||||
};
|
||||
|
||||
$: {
|
||||
if ($stockTicker && typeof window !== 'undefined') {
|
||||
if ($stockTicker && typeof window !== "undefined") {
|
||||
isLoaded = false;
|
||||
const ticker = $stockTicker;
|
||||
const asyncFunctions = [getGovernmentContract(ticker)];
|
||||
@ -141,104 +153,114 @@
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('An error occurred:', error);
|
||||
console.error("An error occurred:", error);
|
||||
});
|
||||
isLoaded = true;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
|
||||
<section class="overflow-hidden text-white h-full pb-8">
|
||||
<main class="overflow-hidden ">
|
||||
|
||||
<div class="flex flex-row items-center">
|
||||
<label for="governmentContractInfo" class="mr-1 cursor-pointer flex flex-row items-center text-white text-xl sm:text-3xl font-bold">
|
||||
US Government Contract
|
||||
</label>
|
||||
<InfoModal
|
||||
title={"Government Contract"}
|
||||
content={"Government contracts are agreements between the local government and companies for goods or services. They can be substantial revenue sources for companies, particularly in sectors like defense, technology, and infrastructure. Winning contracts can enhance a company's stability and credibility, but it often involves competitive bidding and compliance with strict regulations."}
|
||||
id={"governmentContractInfo"}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{#if isLoaded}
|
||||
|
||||
{#if rawData?.length !== 0}
|
||||
|
||||
<section class="overflow-hidden text-white h-full pb-8">
|
||||
<main class="overflow-hidden">
|
||||
<div class="flex flex-row items-center">
|
||||
<label
|
||||
for="governmentContractInfo"
|
||||
class="mr-1 cursor-pointer flex flex-row items-center text-white text-xl sm:text-3xl font-bold"
|
||||
>
|
||||
US Government Contract
|
||||
</label>
|
||||
<InfoModal
|
||||
title={"Government Contract"}
|
||||
content={"Government contracts are agreements between the local government and companies for goods or services. They can be substantial revenue sources for companies, particularly in sectors like defense, technology, and infrastructure. Winning contracts can enhance a company's stability and credibility, but it often involves competitive bidding and compliance with strict regulations."}
|
||||
id={"governmentContractInfo"}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{#if isLoaded}
|
||||
{#if rawData?.length !== 0}
|
||||
<div class="w-full flex flex-col items-start">
|
||||
<div class="text-white text-sm sm:text-[1rem] mt-2 mb-2 w-full">
|
||||
Since 2015, {$displayCompanyName} has secured a total of {totalContract} government contracts, amassing {abbreviateNumber(totalAmount,true)} in revenue. The company has averaged {avgNumberOfContracts} contracts per year, with a peak of {displayMaxContracts} contracts in {displayYear}.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="pb-2 rounded-lg bg-[#09090B]">
|
||||
|
||||
|
||||
<div class="app w-full h-[300px] mt-5">
|
||||
<Chart {init} options={optionsData} class="chart" />
|
||||
<div class="text-white text-sm sm:text-[1rem] mt-2 mb-2 w-full">
|
||||
Since 2015, {$displayCompanyName} has secured a total of {totalContract}
|
||||
government contracts, amassing {abbreviateNumber(totalAmount, true)}
|
||||
in revenue. The company has averaged {avgNumberOfContracts} contracts
|
||||
per year, with a peak of {displayMaxContracts} contracts in {displayYear}.
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="flex flex-row items-center justify-between mx-auto mt-5 w-full sm:w-11/12">
|
||||
|
||||
<div class="mt-3.5 sm:mt-0 flex flex-col sm:flex-row items-center ml-3 sm:ml-0 w-1/2 justify-center">
|
||||
<div class="h-full transform -translate-x-1/2 " aria-hidden="true"></div>
|
||||
<div class="w-3 h-3 bg-[#fff] border-4 box-content border-[#27272A] rounded-full transform sm:-translate-x-1/2" aria-hidden="true"></div>
|
||||
<span class="mt-2 sm:mt-0 text-white text-center sm:text-start text-xs sm:text-md inline-block">
|
||||
# of Contracts
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col sm:flex-row items-center ml-3 sm:ml-0 w-1/2 justify-center">
|
||||
<div class="h-full transform -translate-x-1/2 " aria-hidden="true"></div>
|
||||
<div class="w-3 h-3 bg-[#FFAD24] border-4 box-content border-[#27272A] rounded-full transform sm:-translate-x-1/2" aria-hidden="true"></div>
|
||||
<span class="mt-2 sm:mt-0 text-white text-xs sm:text-md sm:font-medium inline-block">
|
||||
Amount
|
||||
</span>
|
||||
</div>
|
||||
<div class="pb-2 rounded-lg bg-[#09090B]">
|
||||
<div class="app w-full h-[300px] mt-5">
|
||||
<Chart {init} options={optionsData} class="chart" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
{/if}
|
||||
|
||||
{:else}
|
||||
<div class="flex justify-center items-center h-80">
|
||||
<div class="relative">
|
||||
<label class="bg-[#09090B] rounded-xl h-14 w-14 flex justify-center items-center absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2">
|
||||
<span class="loading loading-spinner loading-md text-gray-400"></span>
|
||||
</label>
|
||||
</div>
|
||||
<div
|
||||
class="flex flex-row items-center justify-between mx-auto mt-5 w-full sm:w-11/12"
|
||||
>
|
||||
<div
|
||||
class="mt-3.5 sm:mt-0 flex flex-col sm:flex-row items-center ml-3 sm:ml-0 w-1/2 justify-center"
|
||||
>
|
||||
<div
|
||||
class="h-full transform -translate-x-1/2"
|
||||
aria-hidden="true"
|
||||
></div>
|
||||
<div
|
||||
class="w-3 h-3 bg-[#fff] border-4 box-content border-[#27272A] rounded-full transform sm:-translate-x-1/2"
|
||||
aria-hidden="true"
|
||||
></div>
|
||||
<span
|
||||
class="mt-2 sm:mt-0 text-white text-center sm:text-start text-xs sm:text-md inline-block"
|
||||
>
|
||||
# of Contracts
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="flex flex-col sm:flex-row items-center ml-3 sm:ml-0 w-1/2 justify-center"
|
||||
>
|
||||
<div
|
||||
class="h-full transform -translate-x-1/2"
|
||||
aria-hidden="true"
|
||||
></div>
|
||||
<div
|
||||
class="w-3 h-3 bg-[#FFAD24] border-4 box-content border-[#27272A] rounded-full transform sm:-translate-x-1/2"
|
||||
aria-hidden="true"
|
||||
></div>
|
||||
<span
|
||||
class="mt-2 sm:mt-0 text-white text-xs sm:text-md sm:font-medium inline-block"
|
||||
>
|
||||
Amount
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
|
||||
</main>
|
||||
</section>
|
||||
|
||||
|
||||
|
||||
|
||||
<style>
|
||||
|
||||
{/if}
|
||||
{:else}
|
||||
<div class="flex justify-center items-center h-80">
|
||||
<div class="relative">
|
||||
<label
|
||||
class="bg-[#09090B] rounded-xl h-14 w-14 flex justify-center items-center absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2"
|
||||
>
|
||||
<span class="loading loading-spinner loading-md text-gray-400"
|
||||
></span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
</main>
|
||||
</section>
|
||||
|
||||
<style>
|
||||
.app {
|
||||
height: 300px;
|
||||
max-width: 100%; /* Ensure chart width doesn't exceed the container */
|
||||
|
||||
height: 300px;
|
||||
max-width: 100%; /* Ensure chart width doesn't exceed the container */
|
||||
}
|
||||
|
||||
|
||||
@media (max-width: 640px) {
|
||||
.app {
|
||||
height: 210px;
|
||||
.app {
|
||||
height: 210px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.chart {
|
||||
width: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
</style>
|
||||
</style>
|
||||
|
||||
@ -1,28 +1,33 @@
|
||||
<script lang="ts">
|
||||
import { abbreviateNumber } from "$lib/utils";
|
||||
import { swapComponent, stockTicker, screenWidth, getCache, setCache } from '$lib/store';
|
||||
import InfoModal from '$lib/components/InfoModal.svelte';
|
||||
import { Chart } from 'svelte-echarts';
|
||||
import { init, use } from 'echarts/core';
|
||||
import { ScatterChart } from 'echarts/charts';
|
||||
import { GridComponent, TooltipComponent } from 'echarts/components';
|
||||
import { CanvasRenderer } from 'echarts/renderers';
|
||||
import {
|
||||
swapComponent,
|
||||
stockTicker,
|
||||
screenWidth,
|
||||
getCache,
|
||||
setCache,
|
||||
} from "$lib/store";
|
||||
import InfoModal from "$lib/components/InfoModal.svelte";
|
||||
import { Chart } from "svelte-echarts";
|
||||
import { init, use } from "echarts/core";
|
||||
import { ScatterChart } from "echarts/charts";
|
||||
import { GridComponent, TooltipComponent } from "echarts/components";
|
||||
import { CanvasRenderer } from "echarts/renderers";
|
||||
export let data: any; // Add type for `data` if possible
|
||||
|
||||
use([ScatterChart, GridComponent, TooltipComponent, CanvasRenderer]);
|
||||
|
||||
let isLoaded = false;
|
||||
|
||||
const tabs = [
|
||||
{ title: "Effective Date" },
|
||||
{ title: "Expiration Date" },
|
||||
];
|
||||
const tabs = [{ title: "Effective Date" }, { title: "Expiration Date" }];
|
||||
|
||||
let activeIdx = 0;
|
||||
|
||||
function changeTab(index: number) {
|
||||
activeIdx = index;
|
||||
optionsData = getPlotOptions(activeIdx === 0 ? 'effectiveDate' : 'expirationDate');
|
||||
optionsData = getPlotOptions(
|
||||
activeIdx === 0 ? "effectiveDate" : "expirationDate",
|
||||
);
|
||||
}
|
||||
|
||||
let rawData: any[] = [];
|
||||
@ -30,71 +35,84 @@
|
||||
let avgNotionalAmount: number | undefined;
|
||||
let avgNotionalQuantity: number | undefined;
|
||||
|
||||
|
||||
function getPlotOptions(state: 'effectiveDate' | 'expirationDate') {
|
||||
function getPlotOptions(state: "effectiveDate" | "expirationDate") {
|
||||
const combinedData = rawData?.map((item) => ({
|
||||
date: state === 'effectiveDate' ? item['Effective Date'] : item['Expiration Date'],
|
||||
notionalAmount: item['Notional amount-Leg 1'],
|
||||
notionalQuantity: item['Total notional quantity-Leg 1'],
|
||||
date:
|
||||
state === "effectiveDate"
|
||||
? item["Effective Date"]
|
||||
: item["Expiration Date"],
|
||||
notionalAmount: item["Notional amount-Leg 1"],
|
||||
notionalQuantity: item["Total notional quantity-Leg 1"],
|
||||
}));
|
||||
|
||||
// Group data by date and sum the values
|
||||
const groupedData = combinedData.reduce((acc, curr) => {
|
||||
const { date, notionalAmount, notionalQuantity } = curr;
|
||||
const groupedData = combinedData.reduce(
|
||||
(acc, curr) => {
|
||||
const { date, notionalAmount, notionalQuantity } = curr;
|
||||
|
||||
if (acc[date]) {
|
||||
acc[date].notionalAmount += notionalAmount;
|
||||
acc[date].notionalQuantity += notionalQuantity;
|
||||
} else {
|
||||
acc[date] = {
|
||||
date,
|
||||
notionalAmount,
|
||||
notionalQuantity,
|
||||
};
|
||||
}
|
||||
if (acc[date]) {
|
||||
acc[date].notionalAmount += notionalAmount;
|
||||
acc[date].notionalQuantity += notionalQuantity;
|
||||
} else {
|
||||
acc[date] = {
|
||||
date,
|
||||
notionalAmount,
|
||||
notionalQuantity,
|
||||
};
|
||||
}
|
||||
|
||||
return acc;
|
||||
}, {} as Record<string, any>);
|
||||
return acc;
|
||||
},
|
||||
{} as Record<string, any>,
|
||||
);
|
||||
|
||||
const result = Object.values(groupedData);
|
||||
|
||||
result?.sort((a, b) => new Date(a?.date).getTime() - new Date(b?.date).getTime());
|
||||
result?.sort(
|
||||
(a, b) => new Date(a?.date).getTime() - new Date(b?.date).getTime(),
|
||||
);
|
||||
|
||||
const dates = result?.map((item) => item?.date);
|
||||
const notionalAmount = result?.map((item) => item?.notionalAmount);
|
||||
const notionalQuantity = result?.map((item) => item?.notionalQuantity);
|
||||
|
||||
const totalNotionalAmount = notionalAmount?.reduce((acc, item) => acc + item, 0);
|
||||
const totalNotionalAmount = notionalAmount?.reduce(
|
||||
(acc, item) => acc + item,
|
||||
0,
|
||||
);
|
||||
avgNotionalAmount = totalNotionalAmount / notionalAmount?.length;
|
||||
|
||||
const totalNotionalQuantity = notionalQuantity?.reduce((acc, item) => acc + item, 0);
|
||||
const totalNotionalQuantity = notionalQuantity?.reduce(
|
||||
(acc, item) => acc + item,
|
||||
0,
|
||||
);
|
||||
avgNotionalQuantity = totalNotionalQuantity / notionalQuantity?.length;
|
||||
|
||||
const option = {
|
||||
silent: true,
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
trigger: "axis",
|
||||
hideDelay: 100,
|
||||
},
|
||||
animation: false,
|
||||
grid: {
|
||||
left: '3%',
|
||||
right: '3%',
|
||||
bottom: '0%',
|
||||
top: '10%',
|
||||
left: "3%",
|
||||
right: "3%",
|
||||
bottom: "0%",
|
||||
top: "10%",
|
||||
containLabel: true,
|
||||
},
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
type: "category",
|
||||
boundaryGap: false,
|
||||
data: dates,
|
||||
axisLabel: {
|
||||
color: '#fff',
|
||||
color: "#fff",
|
||||
},
|
||||
},
|
||||
yAxis: [
|
||||
{
|
||||
type: 'value',
|
||||
type: "value",
|
||||
splitLine: {
|
||||
show: false,
|
||||
},
|
||||
@ -103,11 +121,11 @@
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'value',
|
||||
type: "value",
|
||||
splitLine: {
|
||||
show: false,
|
||||
},
|
||||
position: 'right',
|
||||
position: "right",
|
||||
axisLabel: {
|
||||
show: false,
|
||||
},
|
||||
@ -115,20 +133,20 @@
|
||||
],
|
||||
series: [
|
||||
{
|
||||
name: 'Notional Amount',
|
||||
type: 'scatter',
|
||||
name: "Notional Amount",
|
||||
type: "scatter",
|
||||
data: dates?.map((date, index) => [date, notionalAmount[index]]),
|
||||
itemStyle: {
|
||||
color: '#8F54F4',
|
||||
color: "#8F54F4",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'Notional Quantity',
|
||||
type: 'scatter',
|
||||
name: "Notional Quantity",
|
||||
type: "scatter",
|
||||
data: dates?.map((date, index) => [date, notionalQuantity[index]]),
|
||||
yAxisIndex: 1,
|
||||
itemStyle: {
|
||||
color: '#FF9E21',
|
||||
color: "#FBCE3C",
|
||||
},
|
||||
},
|
||||
],
|
||||
@ -138,35 +156,35 @@
|
||||
}
|
||||
|
||||
async function getSwapData(ticker: string) {
|
||||
const cachedData = getCache(ticker, 'getSwapData');
|
||||
const cachedData = getCache(ticker, "getSwapData");
|
||||
if (cachedData) {
|
||||
rawData = cachedData;
|
||||
} else {
|
||||
try {
|
||||
const postData = { ticker, path: 'swap-ticker' };
|
||||
const response = await fetch('/api/ticker-data', {
|
||||
method: 'POST',
|
||||
const postData = { ticker, path: "swap-ticker" };
|
||||
const response = await fetch("/api/ticker-data", {
|
||||
method: "POST",
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify(postData),
|
||||
});
|
||||
if (!response.ok) throw new Error('API request failed');
|
||||
if (!response.ok) throw new Error("API request failed");
|
||||
rawData = await response.json();
|
||||
setCache(ticker, rawData, 'getSwapData');
|
||||
setCache(ticker, rawData, "getSwapData");
|
||||
} catch (error) {
|
||||
console.error('Failed to fetch swap data:', error);
|
||||
console.error("Failed to fetch swap data:", error);
|
||||
rawData = [];
|
||||
}
|
||||
}
|
||||
$swapComponent = rawData?.length !== 0; // Correct the use of `$`
|
||||
}
|
||||
|
||||
$: if ($stockTicker && typeof window !== 'undefined') {
|
||||
$: if ($stockTicker && typeof window !== "undefined") {
|
||||
isLoaded = false;
|
||||
activeIdx = 0;
|
||||
getSwapData($stockTicker).then(() => {
|
||||
optionsData = getPlotOptions('effectiveDate');
|
||||
optionsData = getPlotOptions("effectiveDate");
|
||||
isLoaded = true;
|
||||
});
|
||||
}
|
||||
@ -174,119 +192,129 @@
|
||||
$: charNumber = $screenWidth < 640 ? 20 : 40;
|
||||
</script>
|
||||
|
||||
|
||||
<section class="overflow-hidden text-white h-full pb-8">
|
||||
<main class="overflow-hidden">
|
||||
<div class="flex flex-row items-center">
|
||||
<label
|
||||
for="swapInfo"
|
||||
class="mr-1 cursor-pointer flex flex-row items-center text-white text-xl sm:text-3xl font-bold"
|
||||
>
|
||||
Swap Data
|
||||
</label>
|
||||
<InfoModal
|
||||
title={"Swap Data"}
|
||||
content={"Swaps in the stock market are derivative contracts to exchange cash flows or assets, used for risk management, speculation, and enhancing market liquidity."}
|
||||
id={"swapInfo"}
|
||||
/>
|
||||
</div>
|
||||
|
||||
|
||||
<section class="overflow-hidden text-white h-full pb-8">
|
||||
<main class="overflow-hidden ">
|
||||
|
||||
<div class="flex flex-row items-center">
|
||||
<label for="swapInfo" class="mr-1 cursor-pointer flex flex-row items-center text-white text-xl sm:text-3xl font-bold">
|
||||
Swap Data
|
||||
</label>
|
||||
<InfoModal
|
||||
title={"Swap Data"}
|
||||
content={"Swaps in the stock market are derivative contracts to exchange cash flows or assets, used for risk management, speculation, and enhancing market liquidity."}
|
||||
id={"swapInfo"}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{#if isLoaded}
|
||||
|
||||
{#if rawData?.length !== 0}
|
||||
|
||||
{#if isLoaded}
|
||||
{#if rawData?.length !== 0}
|
||||
<div class="w-full flex flex-col items-start">
|
||||
<div class="text-white text-[1rem] mt-2 mb-2 w-full">
|
||||
The swap data from the past 100 days shows an average notional amount of {abbreviateNumber(avgNotionalAmount,true)} and an average notional quantity of {abbreviateNumber(avgNotionalQuantity)}.
|
||||
</div>
|
||||
<div class="text-white text-[1rem] mt-2 mb-2 w-full">
|
||||
The swap data from the past 100 days shows an average notional
|
||||
amount of {abbreviateNumber(avgNotionalAmount, true)} and an average
|
||||
notional quantity of {abbreviateNumber(avgNotionalQuantity)}.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="pb-2 rounded-lg bg-[#09090B]">
|
||||
|
||||
<div class="bg-[#313131] w-fit relative flex flex-wrap items-center justify-center rounded-lg p-1 mt-4">
|
||||
{#each tabs as item, i}
|
||||
<button
|
||||
on:click={() => changeTab(i)}
|
||||
class="group relative z-[1] rounded-full px-3 py-1 {activeIdx === i
|
||||
? 'z-0'
|
||||
: ''} ">
|
||||
{#if activeIdx === i}
|
||||
<div
|
||||
class="absolute inset-0 rounded-lg bg-purple-600"
|
||||
></div>
|
||||
{/if}
|
||||
<span
|
||||
class="relative text-sm block font-medium duration-200 text-white">
|
||||
{item.title}
|
||||
</span>
|
||||
</button>
|
||||
{/each}
|
||||
</div>
|
||||
|
||||
|
||||
<div class="app w-full h-[300px] mt-5">
|
||||
<Chart {init} options={optionsData} class="chart" />
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="flex flex-row items-center justify-between mx-auto mt-5 w-full sm:w-11/12">
|
||||
|
||||
<div class="mt-3.5 sm:mt-0 flex flex-col sm:flex-row items-center ml-3 sm:ml-0 w-1/2 justify-center">
|
||||
<div class="h-full transform -translate-x-1/2 " aria-hidden="true"></div>
|
||||
<div class="w-3 h-3 bg-[#8F54F4] border-4 box-content border-[#27272A] rounded-full transform sm:-translate-x-1/2" aria-hidden="true"></div>
|
||||
<span class="mt-2 sm:mt-0 text-white text-center sm:text-start text-xs sm:text-md inline-block">
|
||||
Notional Amount
|
||||
<div
|
||||
class="bg-[#313131] w-fit relative flex flex-wrap items-center justify-center rounded-lg p-1 mt-4"
|
||||
>
|
||||
{#each tabs as item, i}
|
||||
<button
|
||||
on:click={() => changeTab(i)}
|
||||
class="group relative z-[1] rounded-full px-3 py-1 {activeIdx ===
|
||||
i
|
||||
? 'z-0'
|
||||
: ''} "
|
||||
>
|
||||
{#if activeIdx === i}
|
||||
<div class="absolute inset-0 rounded-lg bg-purple-600"></div>
|
||||
{/if}
|
||||
<span
|
||||
class="relative text-sm block font-medium duration-200 text-white"
|
||||
>
|
||||
{item.title}
|
||||
</span>
|
||||
</div>
|
||||
</button>
|
||||
{/each}
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col sm:flex-row items-center ml-3 sm:ml-0 w-1/2 justify-center">
|
||||
<div class="h-full transform -translate-x-1/2 " aria-hidden="true"></div>
|
||||
<div class="w-3 h-3 bg-[#fff] border-4 box-content border-[#27272A] rounded-full transform sm:-translate-x-1/2" aria-hidden="true"></div>
|
||||
<span class="mt-2 sm:mt-0 text-white text-xs sm:text-md sm:font-medium inline-block">
|
||||
Notional Quantity
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="app w-full h-[300px] mt-5">
|
||||
<Chart {init} options={optionsData} class="chart" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
{/if}
|
||||
|
||||
{:else}
|
||||
<div class="flex justify-center items-center h-80">
|
||||
<div class="relative">
|
||||
<label class="bg-[#09090B] rounded-xl h-14 w-14 flex justify-center items-center absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2">
|
||||
<span class="loading loading-spinner loading-md text-gray-400"></span>
|
||||
</label>
|
||||
</div>
|
||||
<div
|
||||
class="flex flex-row items-center justify-between mx-auto mt-5 w-full sm:w-11/12"
|
||||
>
|
||||
<div
|
||||
class="mt-3.5 sm:mt-0 flex flex-col sm:flex-row items-center ml-3 sm:ml-0 w-1/2 justify-center"
|
||||
>
|
||||
<div
|
||||
class="h-full transform -translate-x-1/2"
|
||||
aria-hidden="true"
|
||||
></div>
|
||||
<div
|
||||
class="w-3 h-3 bg-[#8F54F4] border-4 box-content border-[#27272A] rounded-full transform sm:-translate-x-1/2"
|
||||
aria-hidden="true"
|
||||
></div>
|
||||
<span
|
||||
class="mt-2 sm:mt-0 text-white text-center sm:text-start text-xs sm:text-md inline-block"
|
||||
>
|
||||
Notional Amount
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="flex flex-col sm:flex-row items-center ml-3 sm:ml-0 w-1/2 justify-center"
|
||||
>
|
||||
<div
|
||||
class="h-full transform -translate-x-1/2"
|
||||
aria-hidden="true"
|
||||
></div>
|
||||
<div
|
||||
class="w-3 h-3 bg-[#fff] border-4 box-content border-[#27272A] rounded-full transform sm:-translate-x-1/2"
|
||||
aria-hidden="true"
|
||||
></div>
|
||||
<span
|
||||
class="mt-2 sm:mt-0 text-white text-xs sm:text-md sm:font-medium inline-block"
|
||||
>
|
||||
Notional Quantity
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
{/if}
|
||||
{:else}
|
||||
<div class="flex justify-center items-center h-80">
|
||||
<div class="relative">
|
||||
<label
|
||||
class="bg-[#09090B] rounded-xl h-14 w-14 flex justify-center items-center absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2"
|
||||
>
|
||||
<span class="loading loading-spinner loading-md text-gray-400"
|
||||
></span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
</main>
|
||||
</section>
|
||||
|
||||
|
||||
</main>
|
||||
</section>
|
||||
|
||||
|
||||
|
||||
|
||||
<style>
|
||||
|
||||
<style>
|
||||
.app {
|
||||
height: 300px;
|
||||
max-width: 100%; /* Ensure chart width doesn't exceed the container */
|
||||
|
||||
height: 300px;
|
||||
max-width: 100%; /* Ensure chart width doesn't exceed the container */
|
||||
}
|
||||
|
||||
|
||||
@media (max-width: 640px) {
|
||||
.app {
|
||||
height: 210px;
|
||||
.app {
|
||||
height: 210px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.chart {
|
||||
width: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
</style>
|
||||
</style>
|
||||
|
||||
@ -408,7 +408,7 @@
|
||||
type: "bar",
|
||||
showSymbol: false,
|
||||
itemStyle: {
|
||||
color: "#FF9E21", // Change bar color to white
|
||||
color: "#FBCE3C", // Change bar color to white
|
||||
},
|
||||
},
|
||||
{
|
||||
|
||||
@ -97,7 +97,7 @@
|
||||
|
||||
// Define categories in the exact order you specified
|
||||
const categories = ["Strong Sell", "Sell", "Hold", "Buy", "Strong Buy"];
|
||||
const colors = ["#9E190A", "#D9220E", "#FF9E21", "#31B800", "#008A00"];
|
||||
const colors = ["#9E190A", "#D9220E", "#FBCE3C", "#31B800", "#008A00"];
|
||||
|
||||
// Create a consistent mapping for data
|
||||
const formattedData = rawAnalystList.map((item) =>
|
||||
@ -216,7 +216,7 @@
|
||||
color: [
|
||||
[0.2, "#9E190A"],
|
||||
[0.4, "#D9220E"],
|
||||
[0.6, "#FF9E21"],
|
||||
[0.6, "#FBCE3C"],
|
||||
[0.8, "#31B800"],
|
||||
[1, "#008A00"],
|
||||
],
|
||||
@ -409,7 +409,7 @@
|
||||
symbol: "none",
|
||||
lineStyle: {
|
||||
type: "dashed",
|
||||
color: "#FF9E21",
|
||||
color: "#FBCE3C",
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -533,7 +533,7 @@
|
||||
? 'text-[#00FC50]'
|
||||
: ['Strong Sell', 'Sell']?.includes(consensusRating)
|
||||
? 'text-[#FF2F1F]'
|
||||
: 'text-[#FF9E21]'}">{consensusRating}</span
|
||||
: 'text-[#FBCE3C]'}">{consensusRating}</span
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user