portfolio-chart
domain-ui/portfolio-chartFreeComponent
domain-ui publishes no description for this item.
Install it
npx shadcn@latest add https://raw.githubusercontent.com/teurons/domain-ui/main/apps/web/public/r/portfolio-chart.jsonSource
1"use client"23import * as React from "react"4import { Area, AreaChart, ResponsiveContainer, XAxis, YAxis } from "recharts"5import { cn } from "@/lib/utils"6import {7 ChartContainer,8 ChartTooltip,9 ChartTooltipContent,10 type ChartConfig,11} from "@/components/ui/chart"1213export interface PortfolioDataPoint {14 timestamp: number15 value: number16}1718export interface PortfolioChartProps {19 data: PortfolioDataPoint[]20 className?: string21 height?: number22 showGrid?: boolean23 showTooltip?: boolean24 timePeriods?: Array<{25 label: string26 value: string27 days: number28 }>29 onTimePeriodChange?: (period: string) => void30 selectedTimePeriod?: string31}3233const DEFAULT_TIME_PERIODS = [34 { label: "1D", value: "1D", days: 1 },35 { label: "1W", value: "1W", days: 7 },36 { label: "1M", value: "1M", days: 30 },37 { label: "3M", value: "3M", days: 90 },38 { label: "1Y", value: "1Y", days: 365 },39 { label: "ALL", value: "ALL", days: -1 }40]4142const chartConfig = {43 value: {44 label: "Portfolio Value",45 color: "hsl(var(--chart-1))",46 },47} satisfies ChartConfig4849export function PortfolioChart({50 data,51 className,52 height = 200,53 showGrid = true,54 showTooltip = true,55 timePeriods = DEFAULT_TIME_PERIODS,56 onTimePeriodChange,57 selectedTimePeriod = "1D"58}: PortfolioChartProps) {59 // Transform data for Recharts60 const chartData = React.useMemo(() => {61 return data.map((point) => ({62 timestamp: point.timestamp,63 value: point.value,64 date: new Date(point.timestamp).toLocaleDateString('en-US', {65 month: 'short',66 day: 'numeric',67 year: 'numeric'68 }),69 time: new Date(point.timestamp).toLocaleTimeString('en-US', {70 hour: '2-digit',71 minute: '2-digit'72 })73 }))74 }, [data])7576 // Determine if portfolio is up or down77 const isPositive = data.length > 1 &&78 data[data.length - 1]?.value !== undefined &&79 data[0]?.value !== undefined &&80 data[data.length - 1].value >= data[0].value81 const currentColor = isPositive ? "#00C805" : "#FF3B30"8283 // Format currency84 const formatCurrency = (value: number) => {85 return new Intl.NumberFormat('en-US', {86 style: 'currency',87 currency: 'USD',88 minimumFractionDigits: 289 }).format(value)90 }9192 // Calculate percentage change93 const calculateChange = () => {94 if (data.length < 2) return { amount: 0, percentage: 0 }95 const start = data[0]?.value || 096 const end = data[data.length - 1]?.value || 097// … truncated
Files it writes
More from domain-ui
All 16 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| pan-inputpan-input | domain-ui | Components | Free | no deps | |
| pan-input-incrementalpan-input-incremental | domain-ui | Components | Free | no deps | |
| passport-inputpassport-input | domain-ui | Components | Free | no deps | |
| passport-input-incrementalpassport-input-incremental | domain-ui | Components | Free | no deps | |
| phone-inputphone-input | domain-ui | Components | Free | 2 deps | |
| regex-inputregex-input | domain-ui | Components | Free | no deps · 2 files | |
| regex-input-incrementalregex-input-incremental | domain-ui | Components | Free | no deps · 5 files | |
| responsive-resizable-previewresponsive-resizable-preview | domain-ui | Components | Free | no deps · 3 files |
