changes:
- added retrieval, stock and weather tools and UI - switched to llama 3.1 for question suggestions
This commit is contained in:
parent
84c6074547
commit
1f945118c5
@ -1,7 +1,7 @@
|
|||||||
'use server';
|
'use server';
|
||||||
|
|
||||||
import { generateObject } from 'ai';
|
import { generateObject } from 'ai';
|
||||||
import { openai } from '@ai-sdk/openai';
|
import { createOpenAI as createGroq } from '@ai-sdk/openai';
|
||||||
import { z } from 'zod';
|
import { z } from 'zod';
|
||||||
|
|
||||||
export interface Message {
|
export interface Message {
|
||||||
@ -9,14 +9,19 @@ export interface Message {
|
|||||||
content: string;
|
content: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const groq = createGroq({
|
||||||
|
baseURL: 'https://api.groq.com/openai/v1',
|
||||||
|
apiKey: process.env.GROQ_API_KEY,
|
||||||
|
});
|
||||||
|
|
||||||
export async function suggestQuestions(history: Message[]) {
|
export async function suggestQuestions(history: Message[]) {
|
||||||
'use server';
|
'use server';
|
||||||
|
|
||||||
const { object } = await generateObject({
|
const { object } = await generateObject({
|
||||||
model: openai('gpt-4o-mini'),
|
model: groq('llama-3.1-70b-versatile'),
|
||||||
temperature: 0,
|
temperature: 0,
|
||||||
system:
|
system:
|
||||||
`You are a search engine query generator. You 'have' to create 3 questions for the search engine based on the message history which has been provided to you.
|
`You are a search engine query generator. You 'have' to create 3 questions for the search engine based on the message history which has been provided to you.
|
||||||
The questions should be open-ended and should encourage further discussion while maintaining the whole context. Limit it to 5-10 words per question.
|
The questions should be open-ended and should encourage further discussion while maintaining the whole context. Limit it to 5-10 words per question.
|
||||||
Always put the user input's context is some way so that the next search knows what to search for exactly.
|
Always put the user input's context is some way so that the next search knows what to search for exactly.
|
||||||
Never use pronouns in the questions as they blur the context.`,
|
Never use pronouns in the questions as they blur the context.`,
|
||||||
|
|||||||
@ -2,12 +2,14 @@ import { openai } from "@ai-sdk/openai";
|
|||||||
import { anthropic } from '@ai-sdk/anthropic'
|
import { anthropic } from '@ai-sdk/anthropic'
|
||||||
import { convertToCoreMessages, streamText, tool } from "ai";
|
import { convertToCoreMessages, streamText, tool } from "ai";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
import { geolocation } from '@vercel/functions'
|
||||||
|
|
||||||
// Allow streaming responses up to 30 seconds
|
// Allow streaming responses up to 30 seconds
|
||||||
export const maxDuration = 30;
|
export const maxDuration = 30;
|
||||||
|
|
||||||
export async function POST(req: Request) {
|
export async function POST(req: Request) {
|
||||||
const { messages, model } = await req.json();
|
const { messages, model } = await req.json();
|
||||||
|
const { latitude, longitude, city } = geolocation(req)
|
||||||
|
|
||||||
let ansmodel;
|
let ansmodel;
|
||||||
|
|
||||||
@ -22,12 +24,17 @@ export async function POST(req: Request) {
|
|||||||
messages: convertToCoreMessages(messages),
|
messages: convertToCoreMessages(messages),
|
||||||
system:
|
system:
|
||||||
"You are an AI web search engine that helps users find information on the internet." +
|
"You are an AI web search engine that helps users find information on the internet." +
|
||||||
|
"The user is located in " + city + " at latitude " + latitude + " and longitude " + longitude + "." +
|
||||||
|
"Use this geolocation data for weather tool." +
|
||||||
"You use the 'web_search' tool to search for information on the internet." +
|
"You use the 'web_search' tool to search for information on the internet." +
|
||||||
"Always call the 'web_search' tool to get the information, no need to do a chain of thought or say anything else, go straight to the point." +
|
"Always call the 'web_search' tool to get the information, no need to do a chain of thought or say anything else, go straight to the point." +
|
||||||
"Once you have found the information, you provide the user with the information you found in brief like a news paper detail." +
|
"Once you have found the information, you provide the user with the information you found in brief like a news paper detail." +
|
||||||
"The detail should be 3-5 paragraphs in 10-12 sentences, some time pointers, each with citations in the [Text](link) format always!" +
|
"The detail should be 3-5 paragraphs in 10-12 sentences, some time pointers, each with citations in the [Text](link) format always!" +
|
||||||
"Citations can be inline of the text like this: Hey there! [Google](https://google.com) is a search engine." +
|
"Citations can be inline of the text like this: Hey there! [Google](https://google.com) is a search engine." +
|
||||||
"Do not start the responses with newline characters, always start with the first sentence." +
|
"Do not start the responses with newline characters, always start with the first sentence." +
|
||||||
|
"When the user asks about a Stock, you should 'always' first gather news about it with web search tool, then show the chart and then write your response. Follow these steps in this order only!" +
|
||||||
|
"Never use the retrieve tool for general search. Always use it when the user provides an url! " +
|
||||||
|
"For weather related questions, use get_weather_data tool and write your response. No need to call any other tool. Put citation to OpenWeatherMaps API everytime." +
|
||||||
"The current date is: " +
|
"The current date is: " +
|
||||||
new Date()
|
new Date()
|
||||||
.toLocaleDateString("en-US", {
|
.toLocaleDateString("en-US", {
|
||||||
@ -84,6 +91,74 @@ export async function POST(req: Request) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
|
retrieve: tool({
|
||||||
|
description: 'Retrieve the information from the web search tool.',
|
||||||
|
parameters: z.object({
|
||||||
|
url: z.string().describe('The URL to retrieve the information from.')
|
||||||
|
}),
|
||||||
|
execute: async ({ url }: { url: string }) => {
|
||||||
|
let hasError = false
|
||||||
|
|
||||||
|
let results;
|
||||||
|
try {
|
||||||
|
const response = await fetch(`https://r.jina.ai/${url}`, {
|
||||||
|
method: 'GET',
|
||||||
|
headers: {
|
||||||
|
Accept: 'application/json',
|
||||||
|
'X-With-Generated-Alt': 'true'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
const json = await response.json()
|
||||||
|
if (!json.data || json.data.length === 0) {
|
||||||
|
hasError = true
|
||||||
|
} else {
|
||||||
|
// Limit the content to 5000 characters
|
||||||
|
if (json.data.content.length > 5000) {
|
||||||
|
json.data.content = json.data.content.slice(0, 5000)
|
||||||
|
}
|
||||||
|
results = {
|
||||||
|
results: [
|
||||||
|
{
|
||||||
|
title: json.data.title,
|
||||||
|
content: json.data.content,
|
||||||
|
url: json.data.url
|
||||||
|
}
|
||||||
|
],
|
||||||
|
query: '',
|
||||||
|
images: []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
hasError = true
|
||||||
|
console.error('Retrieve API error:', error)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasError || !results) {
|
||||||
|
return results
|
||||||
|
}
|
||||||
|
|
||||||
|
return results
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
get_weather_data: tool({
|
||||||
|
description: "Get the weather data for the given coordinates.",
|
||||||
|
parameters: z.object({
|
||||||
|
lat: z.number().describe('The latitude of the location.'),
|
||||||
|
lon: z.number().describe('The longitude of the location.')
|
||||||
|
}),
|
||||||
|
execute: async ({ lat, lon }: { lat: number, lon: number }) => {
|
||||||
|
const apiKey = process.env.OPENWEATHER_API_KEY
|
||||||
|
const response = await fetch(`https://api.openweathermap.org/data/2.5/forecast?lat=${lat}&lon=${lon}&appid=${apiKey}`)
|
||||||
|
const data = await response.json()
|
||||||
|
return data
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
stock_chart_ui: tool({
|
||||||
|
description: 'Display the stock chart for the given stock symbol after web search.',
|
||||||
|
parameters: z.object({
|
||||||
|
symbol: z.string().describe('The stock symbol to display the chart for.')
|
||||||
|
}),
|
||||||
|
}),
|
||||||
},
|
},
|
||||||
onFinish: async (event) => {
|
onFinish: async (event) => {
|
||||||
console.log(event.text);
|
console.log(event.text);
|
||||||
|
|||||||
199
app/page.tsx
199
app/page.tsx
@ -29,6 +29,8 @@ import {
|
|||||||
AlignLeft,
|
AlignLeft,
|
||||||
Newspaper,
|
Newspaper,
|
||||||
Copy,
|
Copy,
|
||||||
|
TrendingUp,
|
||||||
|
Cloud,
|
||||||
} from 'lucide-react';
|
} from 'lucide-react';
|
||||||
import {
|
import {
|
||||||
HoverCard,
|
HoverCard,
|
||||||
@ -57,8 +59,23 @@ import {
|
|||||||
} from "@/components/ui/dropdown-menu";
|
} from "@/components/ui/dropdown-menu";
|
||||||
import { Input } from '@/components/ui/input';
|
import { Input } from '@/components/ui/input';
|
||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
|
|
||||||
import { Badge } from '@/components/ui/badge';
|
import { Badge } from '@/components/ui/badge';
|
||||||
|
import StockChart from '@/components/stock-chart';
|
||||||
|
import { Line, LineChart, CartesianGrid, XAxis, YAxis, ResponsiveContainer } from "recharts";
|
||||||
|
import {
|
||||||
|
Card,
|
||||||
|
CardContent,
|
||||||
|
CardDescription,
|
||||||
|
CardFooter,
|
||||||
|
CardHeader,
|
||||||
|
CardTitle,
|
||||||
|
} from "@/components/ui/card";
|
||||||
|
import {
|
||||||
|
ChartConfig,
|
||||||
|
ChartContainer,
|
||||||
|
ChartTooltip,
|
||||||
|
ChartTooltipContent,
|
||||||
|
} from "@/components/ui/chart";
|
||||||
|
|
||||||
export default function Home() {
|
export default function Home() {
|
||||||
const inputRef = useRef<HTMLInputElement>(null);
|
const inputRef = useRef<HTMLInputElement>(null);
|
||||||
@ -78,7 +95,7 @@ export default function Home() {
|
|||||||
body: {
|
body: {
|
||||||
model: selectedModel === 'Speed' ? 'gpt-4o-mini' : selectedModel === 'Quality (GPT)' ? 'gpt-4o' : 'claude-3-5-sonnet-20240620',
|
model: selectedModel === 'Speed' ? 'gpt-4o-mini' : selectedModel === 'Quality (GPT)' ? 'gpt-4o' : 'claude-3-5-sonnet-20240620',
|
||||||
},
|
},
|
||||||
maxToolRoundtrips: 1,
|
maxToolRoundtrips: 2,
|
||||||
onFinish: async (message, { finishReason }) => {
|
onFinish: async (message, { finishReason }) => {
|
||||||
if (finishReason === 'stop') {
|
if (finishReason === 'stop') {
|
||||||
const newHistory: Message[] = [{ role: "user", content: lastSubmittedQuery, }, { role: "assistant", content: message.content }];
|
const newHistory: Message[] = [{ role: "user", content: lastSubmittedQuery, }, { role: "assistant", content: message.content }];
|
||||||
@ -87,6 +104,11 @@ export default function Home() {
|
|||||||
}
|
}
|
||||||
setIsAnimating(false);
|
setIsAnimating(false);
|
||||||
},
|
},
|
||||||
|
onToolCall({ toolCall, }) {
|
||||||
|
if (toolCall.toolName === 'stock_chart_ui') {
|
||||||
|
return 'Stock chart was shown to the user.';
|
||||||
|
}
|
||||||
|
},
|
||||||
onError: (error) => {
|
onError: (error) => {
|
||||||
console.error("Chat error:", error);
|
console.error("Chat error:", error);
|
||||||
toast.error("An error occurred. Please try again.");
|
toast.error("An error occurred. Please try again.");
|
||||||
@ -189,11 +211,180 @@ export default function Home() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface WeatherDataPoint {
|
||||||
|
date: string;
|
||||||
|
minTemp: number;
|
||||||
|
maxTemp: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
const WeatherChart: React.FC<{ result: any }> = React.memo(({ result }) => {
|
||||||
|
const { chartData, minTemp, maxTemp } = useMemo(() => {
|
||||||
|
const weatherData: WeatherDataPoint[] = result.list.map((item: any) => ({
|
||||||
|
date: new Date(item.dt * 1000).toLocaleDateString(),
|
||||||
|
minTemp: Number((item.main.temp_min - 273.15).toFixed(1)),
|
||||||
|
maxTemp: Number((item.main.temp_max - 273.15).toFixed(1)),
|
||||||
|
}));
|
||||||
|
|
||||||
|
// Group data by date and calculate min and max temperatures
|
||||||
|
const groupedData: { [key: string]: WeatherDataPoint } = weatherData.reduce((acc, curr) => {
|
||||||
|
if (!acc[curr.date]) {
|
||||||
|
acc[curr.date] = { ...curr };
|
||||||
|
} else {
|
||||||
|
acc[curr.date].minTemp = Math.min(acc[curr.date].minTemp, curr.minTemp);
|
||||||
|
acc[curr.date].maxTemp = Math.max(acc[curr.date].maxTemp, curr.maxTemp);
|
||||||
|
}
|
||||||
|
return acc;
|
||||||
|
}, {} as { [key: string]: WeatherDataPoint });
|
||||||
|
|
||||||
|
const chartData = Object.values(groupedData);
|
||||||
|
|
||||||
|
// Calculate overall min and max temperatures
|
||||||
|
const minTemp = Math.min(...chartData.map(d => d.minTemp));
|
||||||
|
const maxTemp = Math.max(...chartData.map(d => d.maxTemp));
|
||||||
|
|
||||||
|
return { chartData, minTemp, maxTemp };
|
||||||
|
}, [result]);
|
||||||
|
|
||||||
|
const chartConfig: ChartConfig = useMemo(() => ({
|
||||||
|
minTemp: {
|
||||||
|
label: "Min Temp.",
|
||||||
|
color: "hsl(var(--chart-1))",
|
||||||
|
},
|
||||||
|
maxTemp: {
|
||||||
|
label: "Max Temp.",
|
||||||
|
color: "hsl(var(--chart-2))",
|
||||||
|
},
|
||||||
|
}), []);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Card className="my-4 shadow-none">
|
||||||
|
<CardHeader>
|
||||||
|
<CardTitle>Weather Forecast for {result.city.name}</CardTitle>
|
||||||
|
<CardDescription>
|
||||||
|
Showing min and max temperatures for the next 5 days
|
||||||
|
</CardDescription>
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent>
|
||||||
|
<ChartContainer config={chartConfig}>
|
||||||
|
<ResponsiveContainer width="100%" height={300}>
|
||||||
|
<LineChart
|
||||||
|
data={chartData}
|
||||||
|
margin={{ top: 10, right: 30, left: 0, bottom: 0 }}
|
||||||
|
>
|
||||||
|
<CartesianGrid strokeDasharray="3 3" />
|
||||||
|
<XAxis
|
||||||
|
dataKey="date"
|
||||||
|
tickFormatter={(value) => new Date(value).toLocaleDateString(undefined, { month: 'short', day: 'numeric' })}
|
||||||
|
/>
|
||||||
|
<YAxis
|
||||||
|
domain={[Math.floor(minTemp) - 2, Math.ceil(maxTemp) + 2]}
|
||||||
|
tickFormatter={(value) => `${value}°C`}
|
||||||
|
/>
|
||||||
|
<ChartTooltip content={<ChartTooltipContent />} />
|
||||||
|
<Line
|
||||||
|
type="monotone"
|
||||||
|
dataKey="minTemp"
|
||||||
|
stroke="var(--color-minTemp)"
|
||||||
|
strokeWidth={2}
|
||||||
|
dot={false}
|
||||||
|
name="Min Temp."
|
||||||
|
/>
|
||||||
|
<Line
|
||||||
|
type="monotone"
|
||||||
|
dataKey="maxTemp"
|
||||||
|
stroke="var(--color-maxTemp)"
|
||||||
|
strokeWidth={2}
|
||||||
|
dot={false}
|
||||||
|
name="Max Temp."
|
||||||
|
/>
|
||||||
|
</LineChart>
|
||||||
|
</ResponsiveContainer>
|
||||||
|
</ChartContainer>
|
||||||
|
</CardContent>
|
||||||
|
<CardFooter>
|
||||||
|
<div className="flex w-full items-start gap-2 text-sm">
|
||||||
|
<div className="grid gap-2">
|
||||||
|
<div className="flex items-center gap-2 font-medium leading-none">
|
||||||
|
{result.city.name}, {result.city.country}
|
||||||
|
</div>
|
||||||
|
<div className="flex items-center gap-2 leading-none text-muted-foreground">
|
||||||
|
Next 5 days forecast
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</CardFooter>
|
||||||
|
</Card>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
WeatherChart.displayName = 'WeatherChart';
|
||||||
|
|
||||||
|
|
||||||
const renderToolInvocation = (toolInvocation: ToolInvocation, index: number) => {
|
const renderToolInvocation = (toolInvocation: ToolInvocation, index: number) => {
|
||||||
const args = JSON.parse(JSON.stringify(toolInvocation.args));
|
const args = JSON.parse(JSON.stringify(toolInvocation.args));
|
||||||
const result = 'result' in toolInvocation ? JSON.parse(JSON.stringify(toolInvocation.result)) : null;
|
const result = 'result' in toolInvocation ? JSON.parse(JSON.stringify(toolInvocation.result)) : null;
|
||||||
|
|
||||||
|
if (toolInvocation.toolName === 'stock_chart_ui') {
|
||||||
|
return (
|
||||||
|
<div className="my-4">
|
||||||
|
<div className="flex items-center gap-2 mb-2">
|
||||||
|
<TrendingUp className="h-5 w-5 text-primary" />
|
||||||
|
<h2 className="font-semibold text-base">{args.symbol}</h2>
|
||||||
|
</div>
|
||||||
|
<Card className='!border-none !shadow-none !bg-none'>
|
||||||
|
<CardContent className="p-0">
|
||||||
|
<StockChart props={args.symbol} />
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (toolInvocation.toolName === 'get_weather_data') {
|
||||||
|
if (!result) {
|
||||||
|
return (
|
||||||
|
<div className="flex items-center justify-between w-full">
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<Cloud className="h-5 w-5 text-neutral-700 animate-pulse" />
|
||||||
|
<span className="text-neutral-700 text-lg">Fetching weather data...</span>
|
||||||
|
</div>
|
||||||
|
<div className="flex space-x-1">
|
||||||
|
{[0, 1, 2].map((index) => (
|
||||||
|
<motion.div
|
||||||
|
key={index}
|
||||||
|
className="w-2 h-2 bg-muted-foreground rounded-full"
|
||||||
|
initial={{ opacity: 0.3 }}
|
||||||
|
animate={{ opacity: 1 }}
|
||||||
|
transition={{
|
||||||
|
repeat: Infinity,
|
||||||
|
duration: 0.8,
|
||||||
|
delay: index * 0.2,
|
||||||
|
repeatType: "reverse",
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isLoading) {
|
||||||
|
return (
|
||||||
|
<Card className="my-4 shadow-none">
|
||||||
|
<CardHeader>
|
||||||
|
<CardTitle className="h-6 w-3/4 bg-gray-200 rounded animate-pulse" />
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent>
|
||||||
|
<div className="h-[300px] bg-gray-200 rounded animate-pulse" />
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return <WeatherChart result={result} />;
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
{!result ? (
|
{!result ? (
|
||||||
@ -403,9 +594,9 @@ export default function Home() {
|
|||||||
}, [append, setMessages]);
|
}, [append, setMessages]);
|
||||||
|
|
||||||
const exampleQueries = [
|
const exampleQueries = [
|
||||||
"Meta Llama 3.1 405B",
|
"Weather in Doha",
|
||||||
"Latest on Paris Olympics",
|
"Latest on Paris Olympics",
|
||||||
"What is Github Models?",
|
"Summary: https://openai.com/index/gpt-4o-system-card/",
|
||||||
"OpenAI GPT-4o mini"
|
"OpenAI GPT-4o mini"
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|||||||
85
components/stock-chart.tsx
Normal file
85
components/stock-chart.tsx
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
/* eslint-disable react-hooks/exhaustive-deps */
|
||||||
|
// from https://github.com/bklieger-groq/stockbot-on-groq/blob/main/components/tradingview/stock-chart.tsx
|
||||||
|
'use client'
|
||||||
|
|
||||||
|
import React, { useEffect, useRef, memo } from 'react'
|
||||||
|
|
||||||
|
export function StockChart({ props: symbol }: { props: string }) {
|
||||||
|
const container = useRef<HTMLDivElement>(null)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!container.current) return
|
||||||
|
const script = document.createElement('script')
|
||||||
|
script.src =
|
||||||
|
'https://s3.tradingview.com/external-embedding/embed-widget-advanced-chart.js'
|
||||||
|
script.type = 'text/javascript'
|
||||||
|
script.async = true
|
||||||
|
script.innerHTML = JSON.stringify({
|
||||||
|
autosize: true,
|
||||||
|
symbol: symbol,
|
||||||
|
interval: 'D',
|
||||||
|
timezone: 'Etc/UTC',
|
||||||
|
theme: 'light',
|
||||||
|
style: '1',
|
||||||
|
locale: 'en',
|
||||||
|
backgroundColor: 'rgba(255, 255, 255, 1)',
|
||||||
|
gridColor: 'rgba(247, 247, 247, 1)',
|
||||||
|
withdateranges: true,
|
||||||
|
hide_side_toolbar: false,
|
||||||
|
allow_symbol_change: true,
|
||||||
|
calendar: false,
|
||||||
|
hide_top_toolbar: true,
|
||||||
|
support_host: 'https://www.tradingview.com'
|
||||||
|
})
|
||||||
|
|
||||||
|
container.current.appendChild(script)
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
if (container.current) {
|
||||||
|
container.current.removeChild(script)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [symbol])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div style={{ height: '500px' }}>
|
||||||
|
<div
|
||||||
|
className="tradingview-widget-container"
|
||||||
|
ref={container}
|
||||||
|
style={{ height: '100%', width: '100%', position: 'relative' }}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
className="tradingview-widget-container__widget"
|
||||||
|
style={{
|
||||||
|
height: 'calc(100% - 32px)',
|
||||||
|
width: '100%',
|
||||||
|
borderRadius: '1rem',
|
||||||
|
overflow: 'hidden'
|
||||||
|
}}
|
||||||
|
></div>
|
||||||
|
<div
|
||||||
|
className="tradingview-widget-copyright"
|
||||||
|
style={{
|
||||||
|
position: 'absolute',
|
||||||
|
bottom: 0,
|
||||||
|
left: 0,
|
||||||
|
right: 0,
|
||||||
|
padding: '4px',
|
||||||
|
textAlign: 'center',
|
||||||
|
fontSize: '12px'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<a
|
||||||
|
href="https://www.tradingview.com/"
|
||||||
|
rel="noopener nofollow"
|
||||||
|
target="_blank"
|
||||||
|
>
|
||||||
|
<span className="">Track all markets on TradingView</span>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default memo(StockChart)
|
||||||
370
components/ui/chart.tsx
Normal file
370
components/ui/chart.tsx
Normal file
@ -0,0 +1,370 @@
|
|||||||
|
"use client"
|
||||||
|
|
||||||
|
import * as React from "react"
|
||||||
|
import * as RechartsPrimitive from "recharts"
|
||||||
|
import {
|
||||||
|
NameType,
|
||||||
|
Payload,
|
||||||
|
ValueType,
|
||||||
|
} from "recharts/types/component/DefaultTooltipContent"
|
||||||
|
|
||||||
|
import { cn } from "@/lib/utils"
|
||||||
|
|
||||||
|
// Format: { THEME_NAME: CSS_SELECTOR }
|
||||||
|
const THEMES = { light: "", dark: ".dark" } as const
|
||||||
|
|
||||||
|
export type ChartConfig = {
|
||||||
|
[k in string]: {
|
||||||
|
label?: React.ReactNode
|
||||||
|
icon?: React.ComponentType
|
||||||
|
} & (
|
||||||
|
| { color?: string; theme?: never }
|
||||||
|
| { color?: never; theme: Record<keyof typeof THEMES, string> }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
type ChartContextProps = {
|
||||||
|
config: ChartConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
const ChartContext = React.createContext<ChartContextProps | null>(null)
|
||||||
|
|
||||||
|
function useChart() {
|
||||||
|
const context = React.useContext(ChartContext)
|
||||||
|
|
||||||
|
if (!context) {
|
||||||
|
throw new Error("useChart must be used within a <ChartContainer />")
|
||||||
|
}
|
||||||
|
|
||||||
|
return context
|
||||||
|
}
|
||||||
|
|
||||||
|
const ChartContainer = React.forwardRef<
|
||||||
|
HTMLDivElement,
|
||||||
|
React.ComponentProps<"div"> & {
|
||||||
|
config: ChartConfig
|
||||||
|
children: React.ComponentProps<
|
||||||
|
typeof RechartsPrimitive.ResponsiveContainer
|
||||||
|
>["children"]
|
||||||
|
}
|
||||||
|
>(({ id, className, children, config, ...props }, ref) => {
|
||||||
|
const uniqueId = React.useId()
|
||||||
|
const chartId = `chart-${id || uniqueId.replace(/:/g, "")}`
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ChartContext.Provider value={{ config }}>
|
||||||
|
<div
|
||||||
|
data-chart={chartId}
|
||||||
|
ref={ref}
|
||||||
|
className={cn(
|
||||||
|
"flex aspect-video justify-center text-xs [&_.recharts-cartesian-axis-tick_text]:fill-muted-foreground [&_.recharts-cartesian-grid_line[stroke='#ccc']]:stroke-border/50 [&_.recharts-curve.recharts-tooltip-cursor]:stroke-border [&_.recharts-dot[stroke='#fff']]:stroke-transparent [&_.recharts-layer]:outline-none [&_.recharts-polar-grid_[stroke='#ccc']]:stroke-border [&_.recharts-radial-bar-background-sector]:fill-muted [&_.recharts-rectangle.recharts-tooltip-cursor]:fill-muted [&_.recharts-reference-line_[stroke='#ccc']]:stroke-border [&_.recharts-sector[stroke='#fff']]:stroke-transparent [&_.recharts-sector]:outline-none [&_.recharts-surface]:outline-none",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
<ChartStyle id={chartId} config={config} />
|
||||||
|
<RechartsPrimitive.ResponsiveContainer>
|
||||||
|
{children}
|
||||||
|
</RechartsPrimitive.ResponsiveContainer>
|
||||||
|
</div>
|
||||||
|
</ChartContext.Provider>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
ChartContainer.displayName = "Chart"
|
||||||
|
|
||||||
|
const ChartStyle = ({ id, config }: { id: string; config: ChartConfig }) => {
|
||||||
|
const colorConfig = Object.entries(config).filter(
|
||||||
|
([_, config]) => config.theme || config.color
|
||||||
|
)
|
||||||
|
|
||||||
|
if (!colorConfig.length) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<style
|
||||||
|
dangerouslySetInnerHTML={{
|
||||||
|
__html: Object.entries(THEMES)
|
||||||
|
.map(
|
||||||
|
([theme, prefix]) => `
|
||||||
|
${prefix} [data-chart=${id}] {
|
||||||
|
${colorConfig
|
||||||
|
.map(([key, itemConfig]) => {
|
||||||
|
const color =
|
||||||
|
itemConfig.theme?.[theme as keyof typeof itemConfig.theme] ||
|
||||||
|
itemConfig.color
|
||||||
|
return color ? ` --color-${key}: ${color};` : null
|
||||||
|
})
|
||||||
|
.join("\n")}
|
||||||
|
}
|
||||||
|
`
|
||||||
|
)
|
||||||
|
.join("\n"),
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const ChartTooltip = RechartsPrimitive.Tooltip
|
||||||
|
|
||||||
|
const ChartTooltipContent = React.forwardRef<
|
||||||
|
HTMLDivElement,
|
||||||
|
React.ComponentProps<typeof RechartsPrimitive.Tooltip> &
|
||||||
|
React.ComponentProps<"div"> & {
|
||||||
|
hideLabel?: boolean
|
||||||
|
hideIndicator?: boolean
|
||||||
|
indicator?: "line" | "dot" | "dashed"
|
||||||
|
nameKey?: string
|
||||||
|
labelKey?: string
|
||||||
|
}
|
||||||
|
>(
|
||||||
|
(
|
||||||
|
{
|
||||||
|
active,
|
||||||
|
payload,
|
||||||
|
className,
|
||||||
|
indicator = "dot",
|
||||||
|
hideLabel = false,
|
||||||
|
hideIndicator = false,
|
||||||
|
label,
|
||||||
|
labelFormatter,
|
||||||
|
labelClassName,
|
||||||
|
formatter,
|
||||||
|
color,
|
||||||
|
nameKey,
|
||||||
|
labelKey,
|
||||||
|
},
|
||||||
|
ref
|
||||||
|
) => {
|
||||||
|
const { config } = useChart()
|
||||||
|
|
||||||
|
const tooltipLabel = React.useMemo(() => {
|
||||||
|
if (hideLabel || !payload?.length) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
const [item] = payload
|
||||||
|
const key = `${labelKey || item.dataKey || item.name || "value"}`
|
||||||
|
const itemConfig = getPayloadConfigFromPayload(config, item, key)
|
||||||
|
const value =
|
||||||
|
!labelKey && typeof label === "string"
|
||||||
|
? config[label as keyof typeof config]?.label || label
|
||||||
|
: itemConfig?.label
|
||||||
|
|
||||||
|
if (labelFormatter) {
|
||||||
|
return (
|
||||||
|
<div className={cn("font-medium", labelClassName)}>
|
||||||
|
{labelFormatter(value, payload)}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!value) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
return <div className={cn("font-medium", labelClassName)}>{value}</div>
|
||||||
|
}, [
|
||||||
|
label,
|
||||||
|
labelFormatter,
|
||||||
|
payload,
|
||||||
|
hideLabel,
|
||||||
|
labelClassName,
|
||||||
|
config,
|
||||||
|
labelKey,
|
||||||
|
])
|
||||||
|
|
||||||
|
if (!active || !payload?.length) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
const nestLabel = payload.length === 1 && indicator !== "dot"
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
ref={ref}
|
||||||
|
className={cn(
|
||||||
|
"grid min-w-[8rem] items-start gap-1.5 rounded-lg border border-border/50 bg-background px-2.5 py-1.5 text-xs shadow-xl",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
{!nestLabel ? tooltipLabel : null}
|
||||||
|
<div className="grid gap-1.5">
|
||||||
|
{payload.map((item, index) => {
|
||||||
|
const key = `${nameKey || item.name || item.dataKey || "value"}`
|
||||||
|
const itemConfig = getPayloadConfigFromPayload(config, item, key)
|
||||||
|
const indicatorColor = color || item.payload.fill || item.color
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
key={item.dataKey}
|
||||||
|
className={cn(
|
||||||
|
"flex w-full flex-wrap items-stretch gap-2 [&>svg]:h-2.5 [&>svg]:w-2.5 [&>svg]:text-muted-foreground",
|
||||||
|
indicator === "dot" && "items-center"
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
{formatter && item?.value !== undefined && item.name ? (
|
||||||
|
formatter(item.value, item.name, item, index, item.payload)
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
{itemConfig?.icon ? (
|
||||||
|
<itemConfig.icon />
|
||||||
|
) : (
|
||||||
|
!hideIndicator && (
|
||||||
|
<div
|
||||||
|
className={cn(
|
||||||
|
"shrink-0 rounded-[2px] border-[--color-border] bg-[--color-bg]",
|
||||||
|
{
|
||||||
|
"h-2.5 w-2.5": indicator === "dot",
|
||||||
|
"w-1": indicator === "line",
|
||||||
|
"w-0 border-[1.5px] border-dashed bg-transparent":
|
||||||
|
indicator === "dashed",
|
||||||
|
"my-0.5": nestLabel && indicator === "dashed",
|
||||||
|
}
|
||||||
|
)}
|
||||||
|
style={
|
||||||
|
{
|
||||||
|
"--color-bg": indicatorColor,
|
||||||
|
"--color-border": indicatorColor,
|
||||||
|
} as React.CSSProperties
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
)}
|
||||||
|
<div
|
||||||
|
className={cn(
|
||||||
|
"flex flex-1 justify-between leading-none",
|
||||||
|
nestLabel ? "items-end" : "items-center"
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<div className="grid gap-1.5">
|
||||||
|
{nestLabel ? tooltipLabel : null}
|
||||||
|
<span className="text-muted-foreground">
|
||||||
|
{itemConfig?.label || item.name}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
{item.value && (
|
||||||
|
<span className="font-mono font-medium tabular-nums text-foreground">
|
||||||
|
{item.value.toLocaleString()}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
ChartTooltipContent.displayName = "ChartTooltip"
|
||||||
|
|
||||||
|
const ChartLegend = RechartsPrimitive.Legend
|
||||||
|
|
||||||
|
const ChartLegendContent = React.forwardRef<
|
||||||
|
HTMLDivElement,
|
||||||
|
React.ComponentProps<"div"> &
|
||||||
|
Pick<RechartsPrimitive.LegendProps, "payload" | "verticalAlign"> & {
|
||||||
|
hideIcon?: boolean
|
||||||
|
nameKey?: string
|
||||||
|
}
|
||||||
|
>(
|
||||||
|
(
|
||||||
|
{ className, hideIcon = false, payload, verticalAlign = "bottom", nameKey },
|
||||||
|
ref
|
||||||
|
) => {
|
||||||
|
const { config } = useChart()
|
||||||
|
|
||||||
|
if (!payload?.length) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
ref={ref}
|
||||||
|
className={cn(
|
||||||
|
"flex items-center justify-center gap-4",
|
||||||
|
verticalAlign === "top" ? "pb-3" : "pt-3",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
{payload.map((item) => {
|
||||||
|
const key = `${nameKey || item.dataKey || "value"}`
|
||||||
|
const itemConfig = getPayloadConfigFromPayload(config, item, key)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
key={item.value}
|
||||||
|
className={cn(
|
||||||
|
"flex items-center gap-1.5 [&>svg]:h-3 [&>svg]:w-3 [&>svg]:text-muted-foreground"
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
{itemConfig?.icon && !hideIcon ? (
|
||||||
|
<itemConfig.icon />
|
||||||
|
) : (
|
||||||
|
<div
|
||||||
|
className="h-2 w-2 shrink-0 rounded-[2px]"
|
||||||
|
style={{
|
||||||
|
backgroundColor: item.color,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{itemConfig?.label}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
ChartLegendContent.displayName = "ChartLegend"
|
||||||
|
|
||||||
|
// Helper to extract item config from a payload.
|
||||||
|
function getPayloadConfigFromPayload(
|
||||||
|
config: ChartConfig,
|
||||||
|
payload: unknown,
|
||||||
|
key: string
|
||||||
|
) {
|
||||||
|
if (typeof payload !== "object" || payload === null) {
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
|
||||||
|
const payloadPayload =
|
||||||
|
"payload" in payload &&
|
||||||
|
typeof payload.payload === "object" &&
|
||||||
|
payload.payload !== null
|
||||||
|
? payload.payload
|
||||||
|
: undefined
|
||||||
|
|
||||||
|
let configLabelKey: string = key
|
||||||
|
|
||||||
|
if (
|
||||||
|
key in payload &&
|
||||||
|
typeof payload[key as keyof typeof payload] === "string"
|
||||||
|
) {
|
||||||
|
configLabelKey = payload[key as keyof typeof payload] as string
|
||||||
|
} else if (
|
||||||
|
payloadPayload &&
|
||||||
|
key in payloadPayload &&
|
||||||
|
typeof payloadPayload[key as keyof typeof payloadPayload] === "string"
|
||||||
|
) {
|
||||||
|
configLabelKey = payloadPayload[
|
||||||
|
key as keyof typeof payloadPayload
|
||||||
|
] as string
|
||||||
|
}
|
||||||
|
|
||||||
|
return configLabelKey in config
|
||||||
|
? config[configLabelKey]
|
||||||
|
: config[key as keyof typeof config]
|
||||||
|
}
|
||||||
|
|
||||||
|
export {
|
||||||
|
ChartContainer,
|
||||||
|
ChartTooltip,
|
||||||
|
ChartTooltipContent,
|
||||||
|
ChartLegend,
|
||||||
|
ChartLegendContent,
|
||||||
|
ChartStyle,
|
||||||
|
}
|
||||||
@ -20,6 +20,7 @@
|
|||||||
"@radix-ui/react-slot": "^1.1.0",
|
"@radix-ui/react-slot": "^1.1.0",
|
||||||
"@tailwindcss/typography": "^0.5.13",
|
"@tailwindcss/typography": "^0.5.13",
|
||||||
"@vercel/analytics": "^1.3.1",
|
"@vercel/analytics": "^1.3.1",
|
||||||
|
"@vercel/functions": "^1.4.0",
|
||||||
"ai": "latest",
|
"ai": "latest",
|
||||||
"class-variance-authority": "^0.7.0",
|
"class-variance-authority": "^0.7.0",
|
||||||
"clsx": "^2.1.1",
|
"clsx": "^2.1.1",
|
||||||
@ -30,6 +31,7 @@
|
|||||||
"react": "^18",
|
"react": "^18",
|
||||||
"react-dom": "^18",
|
"react-dom": "^18",
|
||||||
"react-markdown": "^9.0.1",
|
"react-markdown": "^9.0.1",
|
||||||
|
"recharts": "^2.12.7",
|
||||||
"remark-gfm": "^4.0.0",
|
"remark-gfm": "^4.0.0",
|
||||||
"sonner": "^1.5.0",
|
"sonner": "^1.5.0",
|
||||||
"tailwind-merge": "^2.4.0",
|
"tailwind-merge": "^2.4.0",
|
||||||
|
|||||||
246
pnpm-lock.yaml
246
pnpm-lock.yaml
@ -38,6 +38,9 @@ dependencies:
|
|||||||
'@vercel/analytics':
|
'@vercel/analytics':
|
||||||
specifier: ^1.3.1
|
specifier: ^1.3.1
|
||||||
version: 1.3.1(next@14.2.5)(react@18.3.1)
|
version: 1.3.1(next@14.2.5)(react@18.3.1)
|
||||||
|
'@vercel/functions':
|
||||||
|
specifier: ^1.4.0
|
||||||
|
version: 1.4.0
|
||||||
ai:
|
ai:
|
||||||
specifier: latest
|
specifier: latest
|
||||||
version: 3.3.5(react@18.3.1)(svelte@4.2.18)(vue@3.4.35)(zod@3.23.8)
|
version: 3.3.5(react@18.3.1)(svelte@4.2.18)(vue@3.4.35)(zod@3.23.8)
|
||||||
@ -68,6 +71,9 @@ dependencies:
|
|||||||
react-markdown:
|
react-markdown:
|
||||||
specifier: ^9.0.1
|
specifier: ^9.0.1
|
||||||
version: 9.0.1(@types/react@18.3.3)(react@18.3.1)
|
version: 9.0.1(@types/react@18.3.3)(react@18.3.1)
|
||||||
|
recharts:
|
||||||
|
specifier: ^2.12.7
|
||||||
|
version: 2.12.7(react-dom@18.3.1)(react@18.3.1)
|
||||||
remark-gfm:
|
remark-gfm:
|
||||||
specifier: ^4.0.0
|
specifier: ^4.0.0
|
||||||
version: 4.0.0
|
version: 4.0.0
|
||||||
@ -316,6 +322,13 @@ packages:
|
|||||||
'@babel/types': 7.25.2
|
'@babel/types': 7.25.2
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/@babel/runtime@7.25.0:
|
||||||
|
resolution: {integrity: sha512-7dRy4DwXwtzBrPbZflqxnvfxLF8kdZXPkhymtDeFoFqE6ldzjQFgYTtYIFARcLEYDrqfBfYcZt1WqFxRoyC9Rw==}
|
||||||
|
engines: {node: '>=6.9.0'}
|
||||||
|
dependencies:
|
||||||
|
regenerator-runtime: 0.14.1
|
||||||
|
dev: false
|
||||||
|
|
||||||
/@babel/types@7.25.2:
|
/@babel/types@7.25.2:
|
||||||
resolution: {integrity: sha512-YTnYtra7W9e6/oAZEHj0bJehPRUlLH9/fbpT5LfB0NhQXyALCRkRs3zH9v07IYhkgpqX6Z78FnuccZr/l4Fs4Q==}
|
resolution: {integrity: sha512-YTnYtra7W9e6/oAZEHj0bJehPRUlLH9/fbpT5LfB0NhQXyALCRkRs3zH9v07IYhkgpqX6Z78FnuccZr/l4Fs4Q==}
|
||||||
engines: {node: '>=6.9.0'}
|
engines: {node: '>=6.9.0'}
|
||||||
@ -1192,6 +1205,48 @@ packages:
|
|||||||
tailwindcss: 3.4.7
|
tailwindcss: 3.4.7
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/@types/d3-array@3.2.1:
|
||||||
|
resolution: {integrity: sha512-Y2Jn2idRrLzUfAKV2LyRImR+y4oa2AntrgID95SHJxuMUrkNXmanDSed71sRNZysveJVt1hLLemQZIady0FpEg==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/@types/d3-color@3.1.3:
|
||||||
|
resolution: {integrity: sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/@types/d3-ease@3.0.2:
|
||||||
|
resolution: {integrity: sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/@types/d3-interpolate@3.0.4:
|
||||||
|
resolution: {integrity: sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==}
|
||||||
|
dependencies:
|
||||||
|
'@types/d3-color': 3.1.3
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/@types/d3-path@3.1.0:
|
||||||
|
resolution: {integrity: sha512-P2dlU/q51fkOc/Gfl3Ul9kicV7l+ra934qBFXCFhrZMOL6du1TM0pm1ThYvENukyOn5h9v+yMJ9Fn5JK4QozrQ==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/@types/d3-scale@4.0.8:
|
||||||
|
resolution: {integrity: sha512-gkK1VVTr5iNiYJ7vWDI+yUFFlszhNMtVeneJ6lUTKPjprsvLLI9/tgEGiXJOnlINJA8FyA88gfnQsHbybVZrYQ==}
|
||||||
|
dependencies:
|
||||||
|
'@types/d3-time': 3.0.3
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/@types/d3-shape@3.1.6:
|
||||||
|
resolution: {integrity: sha512-5KKk5aKGu2I+O6SONMYSNflgiP0WfZIQvVUMan50wHsLG1G94JlxEVnCpQARfTtzytuY0p/9PXXZb3I7giofIA==}
|
||||||
|
dependencies:
|
||||||
|
'@types/d3-path': 3.1.0
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/@types/d3-time@3.0.3:
|
||||||
|
resolution: {integrity: sha512-2p6olUZ4w3s+07q3Tm2dbiMZy5pCDfYwtLXXHUnVzXgQlZ/OyPtUz6OL382BkOuGlLXqfT+wqv8Fw2v8/0geBw==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/@types/d3-timer@3.0.2:
|
||||||
|
resolution: {integrity: sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/@types/debug@4.1.12:
|
/@types/debug@4.1.12:
|
||||||
resolution: {integrity: sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==}
|
resolution: {integrity: sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==}
|
||||||
dependencies:
|
dependencies:
|
||||||
@ -1343,6 +1398,16 @@ packages:
|
|||||||
server-only: 0.0.1
|
server-only: 0.0.1
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/@vercel/functions@1.4.0:
|
||||||
|
resolution: {integrity: sha512-Ln6SpIkms1UJg306X2kbEMyG9ol+mjDr2xx389cvsBxgFyFMI9Bm+LYOG4N3TSik4FI59MECyyc4oz7AIAYmqQ==}
|
||||||
|
engines: {node: '>= 16'}
|
||||||
|
peerDependencies:
|
||||||
|
'@aws-sdk/credential-provider-web-identity': '*'
|
||||||
|
peerDependenciesMeta:
|
||||||
|
'@aws-sdk/credential-provider-web-identity':
|
||||||
|
optional: true
|
||||||
|
dev: false
|
||||||
|
|
||||||
/@vue/compiler-core@3.4.35:
|
/@vue/compiler-core@3.4.35:
|
||||||
resolution: {integrity: sha512-gKp0zGoLnMYtw4uS/SJRRO7rsVggLjvot3mcctlMXunYNsX+aRJDqqw/lV5/gHK91nvaAAlWFgdVl020AW1Prg==}
|
resolution: {integrity: sha512-gKp0zGoLnMYtw4uS/SJRRO7rsVggLjvot3mcctlMXunYNsX+aRJDqqw/lV5/gHK91nvaAAlWFgdVl020AW1Prg==}
|
||||||
dependencies:
|
dependencies:
|
||||||
@ -1839,6 +1904,77 @@ packages:
|
|||||||
/csstype@3.1.3:
|
/csstype@3.1.3:
|
||||||
resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==}
|
resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==}
|
||||||
|
|
||||||
|
/d3-array@3.2.4:
|
||||||
|
resolution: {integrity: sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==}
|
||||||
|
engines: {node: '>=12'}
|
||||||
|
dependencies:
|
||||||
|
internmap: 2.0.3
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/d3-color@3.1.0:
|
||||||
|
resolution: {integrity: sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==}
|
||||||
|
engines: {node: '>=12'}
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/d3-ease@3.0.1:
|
||||||
|
resolution: {integrity: sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==}
|
||||||
|
engines: {node: '>=12'}
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/d3-format@3.1.0:
|
||||||
|
resolution: {integrity: sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==}
|
||||||
|
engines: {node: '>=12'}
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/d3-interpolate@3.0.1:
|
||||||
|
resolution: {integrity: sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==}
|
||||||
|
engines: {node: '>=12'}
|
||||||
|
dependencies:
|
||||||
|
d3-color: 3.1.0
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/d3-path@3.1.0:
|
||||||
|
resolution: {integrity: sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==}
|
||||||
|
engines: {node: '>=12'}
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/d3-scale@4.0.2:
|
||||||
|
resolution: {integrity: sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==}
|
||||||
|
engines: {node: '>=12'}
|
||||||
|
dependencies:
|
||||||
|
d3-array: 3.2.4
|
||||||
|
d3-format: 3.1.0
|
||||||
|
d3-interpolate: 3.0.1
|
||||||
|
d3-time: 3.1.0
|
||||||
|
d3-time-format: 4.1.0
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/d3-shape@3.2.0:
|
||||||
|
resolution: {integrity: sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==}
|
||||||
|
engines: {node: '>=12'}
|
||||||
|
dependencies:
|
||||||
|
d3-path: 3.1.0
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/d3-time-format@4.1.0:
|
||||||
|
resolution: {integrity: sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==}
|
||||||
|
engines: {node: '>=12'}
|
||||||
|
dependencies:
|
||||||
|
d3-time: 3.1.0
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/d3-time@3.1.0:
|
||||||
|
resolution: {integrity: sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==}
|
||||||
|
engines: {node: '>=12'}
|
||||||
|
dependencies:
|
||||||
|
d3-array: 3.2.4
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/d3-timer@3.0.1:
|
||||||
|
resolution: {integrity: sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==}
|
||||||
|
engines: {node: '>=12'}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/damerau-levenshtein@1.0.8:
|
/damerau-levenshtein@1.0.8:
|
||||||
resolution: {integrity: sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==}
|
resolution: {integrity: sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==}
|
||||||
dev: true
|
dev: true
|
||||||
@ -1896,6 +2032,10 @@ packages:
|
|||||||
dependencies:
|
dependencies:
|
||||||
ms: 2.1.2
|
ms: 2.1.2
|
||||||
|
|
||||||
|
/decimal.js-light@2.5.1:
|
||||||
|
resolution: {integrity: sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/decode-named-character-reference@1.0.2:
|
/decode-named-character-reference@1.0.2:
|
||||||
resolution: {integrity: sha512-O8x12RzrUF8xyVcY0KJowWsmaJxQbmy0/EtnNtHRpsOcT7dFk5W598coHqBVpmWo1oQQfsCqfCmkZN5DJrZVdg==}
|
resolution: {integrity: sha512-O8x12RzrUF8xyVcY0KJowWsmaJxQbmy0/EtnNtHRpsOcT7dFk5W598coHqBVpmWo1oQQfsCqfCmkZN5DJrZVdg==}
|
||||||
dependencies:
|
dependencies:
|
||||||
@ -1994,6 +2134,13 @@ packages:
|
|||||||
esutils: 2.0.3
|
esutils: 2.0.3
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/dom-helpers@5.2.1:
|
||||||
|
resolution: {integrity: sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==}
|
||||||
|
dependencies:
|
||||||
|
'@babel/runtime': 7.25.0
|
||||||
|
csstype: 3.1.3
|
||||||
|
dev: false
|
||||||
|
|
||||||
/eastasianwidth@0.2.0:
|
/eastasianwidth@0.2.0:
|
||||||
resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==}
|
resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==}
|
||||||
|
|
||||||
@ -2446,6 +2593,10 @@ packages:
|
|||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/eventemitter3@4.0.7:
|
||||||
|
resolution: {integrity: sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/eventsource-parser@1.1.2:
|
/eventsource-parser@1.1.2:
|
||||||
resolution: {integrity: sha512-v0eOBUbiaFojBu2s2NPBfYUoRR9GjcDNvCXVaqEf5vVfpIAh9f8RCo4vXTP8c63QRKCFwoLpMpTdPwwhEKVgzA==}
|
resolution: {integrity: sha512-v0eOBUbiaFojBu2s2NPBfYUoRR9GjcDNvCXVaqEf5vVfpIAh9f8RCo4vXTP8c63QRKCFwoLpMpTdPwwhEKVgzA==}
|
||||||
engines: {node: '>=14.18'}
|
engines: {node: '>=14.18'}
|
||||||
@ -2459,6 +2610,11 @@ packages:
|
|||||||
resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==}
|
resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/fast-equals@5.0.1:
|
||||||
|
resolution: {integrity: sha512-WF1Wi8PwwSY7/6Kx0vKXtw8RwuSGoM1bvDaJbu7MxDlR1vovZjIAKrnzyrThgAjm6JDTu0fVgWXDlMGspodfoQ==}
|
||||||
|
engines: {node: '>=6.0.0'}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/fast-glob@3.3.2:
|
/fast-glob@3.3.2:
|
||||||
resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==}
|
resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==}
|
||||||
engines: {node: '>=8.6.0'}
|
engines: {node: '>=8.6.0'}
|
||||||
@ -2807,6 +2963,11 @@ packages:
|
|||||||
side-channel: 1.0.6
|
side-channel: 1.0.6
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/internmap@2.0.3:
|
||||||
|
resolution: {integrity: sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==}
|
||||||
|
engines: {node: '>=12'}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/invariant@2.2.4:
|
/invariant@2.2.4:
|
||||||
resolution: {integrity: sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==}
|
resolution: {integrity: sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==}
|
||||||
dependencies:
|
dependencies:
|
||||||
@ -3172,6 +3333,10 @@ packages:
|
|||||||
/lodash.merge@4.6.2:
|
/lodash.merge@4.6.2:
|
||||||
resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==}
|
resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==}
|
||||||
|
|
||||||
|
/lodash@4.17.21:
|
||||||
|
resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/longest-streak@3.1.0:
|
/longest-streak@3.1.0:
|
||||||
resolution: {integrity: sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==}
|
resolution: {integrity: sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==}
|
||||||
dev: false
|
dev: false
|
||||||
@ -4026,7 +4191,6 @@ packages:
|
|||||||
loose-envify: 1.4.0
|
loose-envify: 1.4.0
|
||||||
object-assign: 4.1.1
|
object-assign: 4.1.1
|
||||||
react-is: 16.13.1
|
react-is: 16.13.1
|
||||||
dev: true
|
|
||||||
|
|
||||||
/property-information@6.5.0:
|
/property-information@6.5.0:
|
||||||
resolution: {integrity: sha512-PgTgs/BlvHxOu8QuEN7wi5A0OmXaBcHpmCSTehcs6Uuu9IkDIEo13Hy7n898RHfrQ49vKCoGeWZSaAK01nwVig==}
|
resolution: {integrity: sha512-PgTgs/BlvHxOu8QuEN7wi5A0OmXaBcHpmCSTehcs6Uuu9IkDIEo13Hy7n898RHfrQ49vKCoGeWZSaAK01nwVig==}
|
||||||
@ -4052,7 +4216,6 @@ packages:
|
|||||||
|
|
||||||
/react-is@16.13.1:
|
/react-is@16.13.1:
|
||||||
resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==}
|
resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==}
|
||||||
dev: true
|
|
||||||
|
|
||||||
/react-markdown@9.0.1(@types/react@18.3.3)(react@18.3.1):
|
/react-markdown@9.0.1(@types/react@18.3.3)(react@18.3.1):
|
||||||
resolution: {integrity: sha512-186Gw/vF1uRkydbsOIkcGXw7aHq0sZOCRFFjGrr7b9+nVZg4UfA4enXCaxm4fUzecU38sWfrNDitGhshuU7rdg==}
|
resolution: {integrity: sha512-186Gw/vF1uRkydbsOIkcGXw7aHq0sZOCRFFjGrr7b9+nVZg4UfA4enXCaxm4fUzecU38sWfrNDitGhshuU7rdg==}
|
||||||
@ -4111,6 +4274,19 @@ packages:
|
|||||||
use-sidecar: 1.1.2(@types/react@18.3.3)(react@18.3.1)
|
use-sidecar: 1.1.2(@types/react@18.3.3)(react@18.3.1)
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/react-smooth@4.0.1(react-dom@18.3.1)(react@18.3.1):
|
||||||
|
resolution: {integrity: sha512-OE4hm7XqR0jNOq3Qmk9mFLyd6p2+j6bvbPJ7qlB7+oo0eNcL2l7WQzG6MBnT3EXY6xzkLMUBec3AfewJdA0J8w==}
|
||||||
|
peerDependencies:
|
||||||
|
react: ^16.8.0 || ^17.0.0 || ^18.0.0
|
||||||
|
react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0
|
||||||
|
dependencies:
|
||||||
|
fast-equals: 5.0.1
|
||||||
|
prop-types: 15.8.1
|
||||||
|
react: 18.3.1
|
||||||
|
react-dom: 18.3.1(react@18.3.1)
|
||||||
|
react-transition-group: 4.4.5(react-dom@18.3.1)(react@18.3.1)
|
||||||
|
dev: false
|
||||||
|
|
||||||
/react-style-singleton@2.2.1(@types/react@18.3.3)(react@18.3.1):
|
/react-style-singleton@2.2.1(@types/react@18.3.3)(react@18.3.1):
|
||||||
resolution: {integrity: sha512-ZWj0fHEMyWkHzKYUr2Bs/4zU6XLmq9HsgBURm7g5pAVfyn49DgUiNgY2d4lXRlYSiCif9YBGpQleewkcqddc7g==}
|
resolution: {integrity: sha512-ZWj0fHEMyWkHzKYUr2Bs/4zU6XLmq9HsgBURm7g5pAVfyn49DgUiNgY2d4lXRlYSiCif9YBGpQleewkcqddc7g==}
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
@ -4128,6 +4304,20 @@ packages:
|
|||||||
tslib: 2.6.3
|
tslib: 2.6.3
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/react-transition-group@4.4.5(react-dom@18.3.1)(react@18.3.1):
|
||||||
|
resolution: {integrity: sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==}
|
||||||
|
peerDependencies:
|
||||||
|
react: '>=16.6.0'
|
||||||
|
react-dom: '>=16.6.0'
|
||||||
|
dependencies:
|
||||||
|
'@babel/runtime': 7.25.0
|
||||||
|
dom-helpers: 5.2.1
|
||||||
|
loose-envify: 1.4.0
|
||||||
|
prop-types: 15.8.1
|
||||||
|
react: 18.3.1
|
||||||
|
react-dom: 18.3.1(react@18.3.1)
|
||||||
|
dev: false
|
||||||
|
|
||||||
/react@18.3.1:
|
/react@18.3.1:
|
||||||
resolution: {integrity: sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==}
|
resolution: {integrity: sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==}
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
@ -4146,6 +4336,31 @@ packages:
|
|||||||
dependencies:
|
dependencies:
|
||||||
picomatch: 2.3.1
|
picomatch: 2.3.1
|
||||||
|
|
||||||
|
/recharts-scale@0.4.5:
|
||||||
|
resolution: {integrity: sha512-kivNFO+0OcUNu7jQquLXAxz1FIwZj8nrj+YkOKc5694NbjCvcT6aSZiIzNzd2Kul4o4rTto8QVR9lMNtxD4G1w==}
|
||||||
|
dependencies:
|
||||||
|
decimal.js-light: 2.5.1
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/recharts@2.12.7(react-dom@18.3.1)(react@18.3.1):
|
||||||
|
resolution: {integrity: sha512-hlLJMhPQfv4/3NBSAyq3gzGg4h2v69RJh6KU7b3pXYNNAELs9kEoXOjbkxdXpALqKBoVmVptGfLpxdaVYqjmXQ==}
|
||||||
|
engines: {node: '>=14'}
|
||||||
|
peerDependencies:
|
||||||
|
react: ^16.0.0 || ^17.0.0 || ^18.0.0
|
||||||
|
react-dom: ^16.0.0 || ^17.0.0 || ^18.0.0
|
||||||
|
dependencies:
|
||||||
|
clsx: 2.1.1
|
||||||
|
eventemitter3: 4.0.7
|
||||||
|
lodash: 4.17.21
|
||||||
|
react: 18.3.1
|
||||||
|
react-dom: 18.3.1(react@18.3.1)
|
||||||
|
react-is: 16.13.1
|
||||||
|
react-smooth: 4.0.1(react-dom@18.3.1)(react@18.3.1)
|
||||||
|
recharts-scale: 0.4.5
|
||||||
|
tiny-invariant: 1.3.3
|
||||||
|
victory-vendor: 36.9.2
|
||||||
|
dev: false
|
||||||
|
|
||||||
/reflect.getprototypeof@1.0.6:
|
/reflect.getprototypeof@1.0.6:
|
||||||
resolution: {integrity: sha512-fmfw4XgoDke3kdI6h4xcUz1dG8uaiv5q9gcEwLS4Pnth2kxT+GZ7YehS1JTMGBQmtV7Y4GFGbs2re2NqhdozUg==}
|
resolution: {integrity: sha512-fmfw4XgoDke3kdI6h4xcUz1dG8uaiv5q9gcEwLS4Pnth2kxT+GZ7YehS1JTMGBQmtV7Y4GFGbs2re2NqhdozUg==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
@ -4159,6 +4374,10 @@ packages:
|
|||||||
which-builtin-type: 1.1.4
|
which-builtin-type: 1.1.4
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/regenerator-runtime@0.14.1:
|
||||||
|
resolution: {integrity: sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/regexp.prototype.flags@1.5.2:
|
/regexp.prototype.flags@1.5.2:
|
||||||
resolution: {integrity: sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw==}
|
resolution: {integrity: sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
@ -4643,6 +4862,10 @@ packages:
|
|||||||
dependencies:
|
dependencies:
|
||||||
any-promise: 1.3.0
|
any-promise: 1.3.0
|
||||||
|
|
||||||
|
/tiny-invariant@1.3.3:
|
||||||
|
resolution: {integrity: sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/to-fast-properties@2.0.0:
|
/to-fast-properties@2.0.0:
|
||||||
resolution: {integrity: sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==}
|
resolution: {integrity: sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==}
|
||||||
engines: {node: '>=4'}
|
engines: {node: '>=4'}
|
||||||
@ -4876,6 +5099,25 @@ packages:
|
|||||||
vfile-message: 4.0.2
|
vfile-message: 4.0.2
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/victory-vendor@36.9.2:
|
||||||
|
resolution: {integrity: sha512-PnpQQMuxlwYdocC8fIJqVXvkeViHYzotI+NJrCuav0ZYFoq912ZHBk3mCeuj+5/VpodOjPe1z0Fk2ihgzlXqjQ==}
|
||||||
|
dependencies:
|
||||||
|
'@types/d3-array': 3.2.1
|
||||||
|
'@types/d3-ease': 3.0.2
|
||||||
|
'@types/d3-interpolate': 3.0.4
|
||||||
|
'@types/d3-scale': 4.0.8
|
||||||
|
'@types/d3-shape': 3.1.6
|
||||||
|
'@types/d3-time': 3.0.3
|
||||||
|
'@types/d3-timer': 3.0.2
|
||||||
|
d3-array: 3.2.4
|
||||||
|
d3-ease: 3.0.1
|
||||||
|
d3-interpolate: 3.0.1
|
||||||
|
d3-scale: 4.0.2
|
||||||
|
d3-shape: 3.2.0
|
||||||
|
d3-time: 3.1.0
|
||||||
|
d3-timer: 3.0.1
|
||||||
|
dev: false
|
||||||
|
|
||||||
/vue@3.4.35(typescript@5.5.4):
|
/vue@3.4.35(typescript@5.5.4):
|
||||||
resolution: {integrity: sha512-+fl/GLmI4GPileHftVlCdB7fUL4aziPcqTudpTGXCT8s+iZWuOCeNEB5haX6Uz2IpRrbEXOgIFbe+XciCuGbNQ==}
|
resolution: {integrity: sha512-+fl/GLmI4GPileHftVlCdB7fUL4aziPcqTudpTGXCT8s+iZWuOCeNEB5haX6Uz2IpRrbEXOgIFbe+XciCuGbNQ==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user