ui fix
This commit is contained in:
parent
e116a9b24d
commit
41c0b85c99
@ -1,6 +1,7 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { displayCompanyName, stockTicker, screenWidth } from "$lib/store";
|
import { displayCompanyName, stockTicker, screenWidth } from "$lib/store";
|
||||||
import Infobox from "$lib/components/Infobox.svelte";
|
import Infobox from "$lib/components/Infobox.svelte";
|
||||||
|
import highcharts from "$lib/highcharts.ts";
|
||||||
|
|
||||||
import { Chart } from "svelte-echarts";
|
import { Chart } from "svelte-echarts";
|
||||||
import { init, use } from "echarts/core";
|
import { init, use } from "echarts/core";
|
||||||
@ -134,7 +135,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
function getPriceForecastChart() {
|
function getPriceForecastChart() {
|
||||||
const historicalData = data?.getAnalystSummary?.pastPriceList || [];
|
const historicalData = data?.getPriceAnalysis?.pastPriceList || [];
|
||||||
const forecastTargets = {
|
const forecastTargets = {
|
||||||
low: lowPriceTarget,
|
low: lowPriceTarget,
|
||||||
avg: avgPriceTarget,
|
avg: avgPriceTarget,
|
||||||
@ -142,139 +143,171 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Process historical data
|
// Process historical data
|
||||||
const processedHistorical = historicalData?.map((point) => ({
|
const processedHistorical = historicalData?.map((point) => [
|
||||||
date: point?.date,
|
new Date(point?.date).getTime(),
|
||||||
value: point?.close,
|
point?.close,
|
||||||
}));
|
]);
|
||||||
|
|
||||||
const currentDate = new Date(); // Get the current date
|
const currentDate = new Date();
|
||||||
const forecastDate = new Date(
|
const forecastDate = new Date(
|
||||||
currentDate.getFullYear() + 1,
|
currentDate.getFullYear() + 1,
|
||||||
currentDate.getMonth(),
|
currentDate.getMonth(),
|
||||||
currentDate.getDate(),
|
currentDate.getDate(),
|
||||||
); // Add one year
|
);
|
||||||
const forecastDateString = forecastDate.toISOString().split("T")[0]; // Format as 'YYYY-MM-DD'
|
const forecastTimestamp = forecastDate.getTime();
|
||||||
|
|
||||||
// Get the last historical data point
|
// Get the last historical data point
|
||||||
const lastHistoricalDate = historicalData[historicalData.length - 1]?.date;
|
const lastHistoricalDate = new Date(
|
||||||
|
historicalData[historicalData.length - 1]?.date,
|
||||||
|
).getTime();
|
||||||
const lastHistoricalClose =
|
const lastHistoricalClose =
|
||||||
historicalData[historicalData.length - 1]?.close;
|
historicalData[historicalData.length - 1]?.close;
|
||||||
|
|
||||||
// Create forecast points by appending them after the last historical date
|
// Create forecast points
|
||||||
const forecastHigh = [
|
const forecastHigh = [
|
||||||
{ date: lastHistoricalDate, value: lastHistoricalClose },
|
[lastHistoricalDate, lastHistoricalClose],
|
||||||
{ date: forecastDateString, value: forecastTargets.high },
|
[forecastTimestamp, forecastTargets.high],
|
||||||
];
|
];
|
||||||
|
|
||||||
const forecastAvg = [
|
const forecastAvg = [
|
||||||
{ date: lastHistoricalDate, value: lastHistoricalClose },
|
[lastHistoricalDate, lastHistoricalClose],
|
||||||
{ date: forecastDateString, value: forecastTargets.avg },
|
[forecastTimestamp, forecastTargets.avg],
|
||||||
];
|
];
|
||||||
|
|
||||||
const forecastLow = [
|
const forecastLow = [
|
||||||
{ date: lastHistoricalDate, value: lastHistoricalClose },
|
[lastHistoricalDate, lastHistoricalClose],
|
||||||
{ date: forecastDateString, value: forecastTargets.low },
|
[forecastTimestamp, forecastTargets.low],
|
||||||
];
|
];
|
||||||
|
|
||||||
const option = {
|
const options = {
|
||||||
animation: false,
|
tooltip: {
|
||||||
silent: true,
|
enabled: false,
|
||||||
grid: {
|
},
|
||||||
left: "2%",
|
plotOptions: {
|
||||||
right: "2%",
|
series: {
|
||||||
bottom: "10%",
|
enableMouseTracking: false,
|
||||||
top: "5%",
|
states: {
|
||||||
containLabel: true,
|
hover: {
|
||||||
|
enabled: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
marker: {
|
||||||
|
states: {
|
||||||
|
hover: {
|
||||||
|
enabled: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
chart: {
|
||||||
|
backgroundColor: "#09090B",
|
||||||
|
plotBackgroundColor: "#09090B",
|
||||||
|
height: 360,
|
||||||
|
animation: false,
|
||||||
|
},
|
||||||
|
title: {
|
||||||
|
text: `<div class="grid grid-cols-2 w-[200px] sm:w-[500px] -mb-3.5 text-xs font-[501] text-gray-400">
|
||||||
|
<h3 class="text-left">${$screenWidth && $screenWidth < 640 ? "Past Year" : "Past 12 Months"}</h3>
|
||||||
|
<h3 class="text-right">${$screenWidth && $screenWidth < 640 ? "Next Year" : "12 Month Forecast"}</h3>
|
||||||
|
</div>`,
|
||||||
|
style: {
|
||||||
|
color: "white",
|
||||||
|
width: "100%",
|
||||||
|
},
|
||||||
|
verticalAlign: "top",
|
||||||
|
useHTML: true,
|
||||||
},
|
},
|
||||||
|
|
||||||
xAxis: {
|
xAxis: {
|
||||||
type: "time",
|
gridLineWidth: 1,
|
||||||
axisLabel: {
|
gridLineColor: "#111827",
|
||||||
|
type: "datetime",
|
||||||
|
endOnTick: false,
|
||||||
|
labels: {
|
||||||
|
style: {
|
||||||
color: "#fff",
|
color: "#fff",
|
||||||
formatter: (value) => {
|
},
|
||||||
const date = new Date(value);
|
formatter: function () {
|
||||||
const isMobile = $screenWidth < 640; // Define your breakpoint for mobile
|
const date = new Date(this.value);
|
||||||
|
return date.toLocaleDateString("en-US", {
|
||||||
// Use a different date format for mobile screens
|
|
||||||
return isMobile
|
|
||||||
? date.toLocaleDateString("en-US", { month: "short" }) // Show only the month for mobile
|
|
||||||
: date.toLocaleDateString("en-US", {
|
|
||||||
month: "short",
|
month: "short",
|
||||||
year: "numeric",
|
year: "numeric",
|
||||||
}); // Full format for larger screens
|
});
|
||||||
},
|
|
||||||
},
|
|
||||||
axisPointer: {
|
|
||||||
type: "line", // Can enhance interaction on mobile
|
|
||||||
lineStyle: {
|
|
||||||
color: "#fff", // Customize pointer color if needed
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
yAxis: {
|
yAxis: {
|
||||||
type: "value",
|
title: {
|
||||||
axisLabel: {
|
text: "",
|
||||||
|
},
|
||||||
|
labels: {
|
||||||
|
style: {
|
||||||
color: "#fff",
|
color: "#fff",
|
||||||
formatter: (value) => `$${value.toFixed(0)}`,
|
},
|
||||||
|
formatter: function () {
|
||||||
|
return `$${this.value.toFixed(0)}`;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
gridLineWidth: 1,
|
||||||
|
gridLineColor: "#111827",
|
||||||
|
tickInterval: 20, // Adjust this value to reduce step size
|
||||||
},
|
},
|
||||||
|
|
||||||
splitLine: {
|
|
||||||
show: false,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
series: [
|
series: [
|
||||||
{
|
{
|
||||||
|
animation: false,
|
||||||
name: "Historical",
|
name: "Historical",
|
||||||
type: "line",
|
data: processedHistorical,
|
||||||
data: processedHistorical?.map((point) => [point.date, point.value]),
|
color: "#fff",
|
||||||
|
marker: {
|
||||||
symbol: "circle",
|
symbol: "circle",
|
||||||
symbolSize: 6,
|
radius: 4,
|
||||||
itemStyle: {
|
|
||||||
color: "#fff",
|
|
||||||
},
|
|
||||||
lineStyle: {
|
|
||||||
width: 2,
|
|
||||||
},
|
},
|
||||||
|
lineWidth: 2,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
animation: false,
|
||||||
name: "High",
|
name: "High",
|
||||||
type: "line",
|
data: forecastHigh,
|
||||||
data: forecastHigh?.map((point) => [point.date, point.value]),
|
|
||||||
symbol: "none",
|
|
||||||
lineStyle: {
|
|
||||||
type: "dashed",
|
|
||||||
color: "#31B800",
|
color: "#31B800",
|
||||||
|
dashStyle: "Dash",
|
||||||
|
marker: {
|
||||||
|
enabled: false,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
animation: false,
|
||||||
name: "Average",
|
name: "Average",
|
||||||
type: "line",
|
data: forecastAvg,
|
||||||
data: forecastAvg?.map((point) => [point.date, point.value]),
|
|
||||||
symbol: "none",
|
|
||||||
lineStyle: {
|
|
||||||
type: "dashed",
|
|
||||||
color: "#fff",
|
color: "#fff",
|
||||||
|
dashStyle: "Dash",
|
||||||
|
marker: {
|
||||||
|
enabled: false,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
animation: false,
|
||||||
name: "Low",
|
name: "Low",
|
||||||
type: "line",
|
data: forecastLow,
|
||||||
data: forecastLow?.map((point) => [point.date, point.value]),
|
|
||||||
symbol: "none",
|
|
||||||
lineStyle: {
|
|
||||||
type: "dashed",
|
|
||||||
color: "#D9220E",
|
color: "#D9220E",
|
||||||
|
dashStyle: "Dash",
|
||||||
|
marker: {
|
||||||
|
enabled: false,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
legend: {
|
||||||
|
enabled: false,
|
||||||
|
},
|
||||||
|
credits: {
|
||||||
|
enabled: false,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
return options;
|
||||||
return option;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let optionsPieChart = getPieChart() || null;
|
let optionsPieChart = getPieChart() || null;
|
||||||
let optionsPriceForecast = getPriceForecastChart() || null;
|
let config = getPriceForecastChart() || null;
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<SEO
|
<SEO
|
||||||
@ -316,6 +349,7 @@
|
|||||||
price of {price}.
|
price of {price}.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
<div>
|
||||||
<div>
|
<div>
|
||||||
<div class="app h-[160px]">
|
<div class="app h-[160px]">
|
||||||
{#if optionsPieChart !== null}
|
{#if optionsPieChart !== null}
|
||||||
@ -323,7 +357,7 @@
|
|||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
<div class="-mt-36 text-center text-xl font-semibold">
|
<div class="-mt-36 text-center text-xl font-semibold">
|
||||||
AI Consensus: <span
|
Analyst Consensus: <span
|
||||||
class="font-bold {['Strong Buy', 'Buy']?.includes(
|
class="font-bold {['Strong Buy', 'Buy']?.includes(
|
||||||
consensusRating,
|
consensusRating,
|
||||||
)
|
)
|
||||||
@ -335,40 +369,12 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
<div class="grow pt-2 md:pt-4 lg:pl-4 lg:pt-0">
|
<div class="grow pt-2 md:pt-4 lg:pl-4 lg:pt-0">
|
||||||
<div class="app h-[250px] xs:h-[275px]">
|
|
||||||
{#if data?.user?.tier !== "Pro"}
|
|
||||||
<div
|
<div
|
||||||
class="flex flex-row items-center justify-center m-auto h-full text-center font-bold"
|
class="chart mt-5 sm:mt-0 border border-gray-800 rounded"
|
||||||
>
|
use:highcharts={config}
|
||||||
<a
|
></div>
|
||||||
href="/pricing"
|
|
||||||
class="flex flex-row items-center sm:hover:text-blue-400 text-white"
|
|
||||||
>
|
|
||||||
<span class="m-auto"> Chart Forecast</span>
|
|
||||||
<svg
|
|
||||||
class="ml-1 size-5"
|
|
||||||
viewBox="0 0 20 20"
|
|
||||||
fill="currentColor"
|
|
||||||
style="max-width: 40px;"
|
|
||||||
>
|
|
||||||
<path
|
|
||||||
fill-rule="evenodd"
|
|
||||||
d="M5 9V7a5 5 0 0110 0v2a2 2 0 012 2v5a2 2 0 01-2 2H5a2 2 0 01-2-2v-5a2 2 0 012-2zm8-2v2H7V7a3 3 0 016 0z"
|
|
||||||
clip-rule="evenodd"
|
|
||||||
>
|
|
||||||
</path>
|
|
||||||
</svg>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
{:else if optionsPriceForecast !== null}
|
|
||||||
<Chart
|
|
||||||
{init}
|
|
||||||
options={optionsPriceForecast}
|
|
||||||
class="chart"
|
|
||||||
/>
|
|
||||||
{/if}
|
|
||||||
</div>
|
|
||||||
<div
|
<div
|
||||||
class="hide-scroll mb-1 mt-2 overflow-x-auto px-1.5 text-center md:mb-0 md:px-0 lg:mt-2"
|
class="hide-scroll mb-1 mt-2 overflow-x-auto px-1.5 text-center md:mb-0 md:px-0 lg:mt-2"
|
||||||
>
|
>
|
||||||
@ -397,112 +403,24 @@
|
|||||||
<tr class="text-sm sm:text-[1rem]"
|
<tr class="text-sm sm:text-[1rem]"
|
||||||
><td class="py-[3px] text-left lg:py-0.5">Change</td>
|
><td class="py-[3px] text-left lg:py-0.5">Change</td>
|
||||||
<td
|
<td
|
||||||
class={lowChange > 0 && data?.user?.tier === "Pro"
|
class={lowChange > 0
|
||||||
? "before:content-['+'] text-[#00FC50]"
|
? "before:content-['+'] text-[#00FC50]"
|
||||||
: "text-[#FF2F1F]"}
|
: "text-[#FF2F1F]"}>{lowChange}%</td
|
||||||
>
|
>
|
||||||
{#if data?.user?.tier !== "Pro"}
|
|
||||||
<a
|
|
||||||
href="/pricing"
|
|
||||||
class="text-white sm:hover:text-blue-400"
|
|
||||||
>
|
|
||||||
<svg
|
|
||||||
class="size-4 sm:size-5 text-end ml-auto"
|
|
||||||
viewBox="0 0 20 20"
|
|
||||||
fill="currentColor"
|
|
||||||
>
|
|
||||||
<path
|
|
||||||
fill-rule="evenodd"
|
|
||||||
d="M5 9V7a5 5 0 0110 0v2a2 2 0 012 2v5a2 2 0 01-2 2H5a2 2 0 01-2-2v-5a2 2 0 012-2zm8-2v2H7V7a3 3 0 016 0z"
|
|
||||||
clip-rule="evenodd"
|
|
||||||
>
|
|
||||||
</path>
|
|
||||||
</svg>
|
|
||||||
</a>
|
|
||||||
{:else}
|
|
||||||
{lowChange}%
|
|
||||||
{/if}
|
|
||||||
</td>
|
|
||||||
<td
|
<td
|
||||||
class={avgChange > 0 && data?.user?.tier === "Pro"
|
class={avgChange > 0
|
||||||
? "before:content-['+'] text-[#00FC50]"
|
? "before:content-['+'] text-[#00FC50]"
|
||||||
: "text-[#FF2F1F]"}
|
: "text-[#FF2F1F]"}>{avgChange}%</td
|
||||||
>
|
>
|
||||||
{#if data?.user?.tier !== "Pro"}
|
|
||||||
<a
|
|
||||||
href="/pricing"
|
|
||||||
class="text-white sm:hover:text-blue-400"
|
|
||||||
>
|
|
||||||
<svg
|
|
||||||
class="size-4 sm:size-5 text-end ml-auto"
|
|
||||||
viewBox="0 0 20 20"
|
|
||||||
fill="currentColor"
|
|
||||||
>
|
|
||||||
<path
|
|
||||||
fill-rule="evenodd"
|
|
||||||
d="M5 9V7a5 5 0 0110 0v2a2 2 0 012 2v5a2 2 0 01-2 2H5a2 2 0 01-2-2v-5a2 2 0 012-2zm8-2v2H7V7a3 3 0 016 0z"
|
|
||||||
clip-rule="evenodd"
|
|
||||||
>
|
|
||||||
</path>
|
|
||||||
</svg>
|
|
||||||
</a>
|
|
||||||
{:else}
|
|
||||||
{avgChange}%
|
|
||||||
{/if}
|
|
||||||
</td>
|
|
||||||
<td
|
<td
|
||||||
class={medianChange > 0 && data?.user?.tier === "Pro"
|
class={medianChange > 0
|
||||||
? "before:content-['+'] text-[#00FC50]"
|
? "before:content-['+'] text-[#00FC50]"
|
||||||
: "text-[#FF2F1F]"}
|
: "text-[#FF2F1F]"}>{medianChange}%</td
|
||||||
>
|
>
|
||||||
{#if data?.user?.tier !== "Pro"}
|
|
||||||
<a
|
|
||||||
href="/pricing"
|
|
||||||
class="text-white sm:hover:text-blue-400"
|
|
||||||
>
|
|
||||||
<svg
|
|
||||||
class="size-4 sm:size-5 text-end ml-auto"
|
|
||||||
viewBox="0 0 20 20"
|
|
||||||
fill="currentColor"
|
|
||||||
>
|
|
||||||
<path
|
|
||||||
fill-rule="evenodd"
|
|
||||||
d="M5 9V7a5 5 0 0110 0v2a2 2 0 012 2v5a2 2 0 01-2 2H5a2 2 0 01-2-2v-5a2 2 0 012-2zm8-2v2H7V7a3 3 0 016 0z"
|
|
||||||
clip-rule="evenodd"
|
|
||||||
>
|
|
||||||
</path>
|
|
||||||
</svg>
|
|
||||||
</a>
|
|
||||||
{:else}
|
|
||||||
{medianChange}%
|
|
||||||
{/if}
|
|
||||||
</td>
|
|
||||||
<td
|
<td
|
||||||
class={highChange > 0 && data?.user?.tier === "Pro"
|
class={highChange > 0
|
||||||
? "before:content-['+'] text-[#00FC50]"
|
? "before:content-['+'] text-[#00FC50]"
|
||||||
: "text-[#FF2F1F]"}
|
: "text-[#FF2F1F]"}>{highChange}%</td
|
||||||
>
|
|
||||||
{#if data?.user?.tier !== "Pro"}
|
|
||||||
<a
|
|
||||||
href="/pricing"
|
|
||||||
class="text-white sm:hover:text-blue-400"
|
|
||||||
>
|
|
||||||
<svg
|
|
||||||
class="size-4 sm:size-5 text-end ml-auto"
|
|
||||||
viewBox="0 0 20 20"
|
|
||||||
fill="currentColor"
|
|
||||||
>
|
|
||||||
<path
|
|
||||||
fill-rule="evenodd"
|
|
||||||
d="M5 9V7a5 5 0 0110 0v2a2 2 0 012 2v5a2 2 0 01-2 2H5a2 2 0 01-2-2v-5a2 2 0 012-2zm8-2v2H7V7a3 3 0 016 0z"
|
|
||||||
clip-rule="evenodd"
|
|
||||||
>
|
|
||||||
</path>
|
|
||||||
</svg>
|
|
||||||
</a>
|
|
||||||
{:else}
|
|
||||||
{highChange}%
|
|
||||||
{/if}</td
|
|
||||||
></tr
|
></tr
|
||||||
></tbody
|
></tbody
|
||||||
>
|
>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user