diff --git a/components/dashboard/Chart.tsx b/components/dashboard/Chart.tsx
index e94e03a..8e4938d 100644
--- a/components/dashboard/Chart.tsx
+++ b/components/dashboard/Chart.tsx
@@ -2,8 +2,7 @@
import { useState, useMemo, useRef, useCallback, useEffect } from 'react'
import { useTheme } from '@ciphera-net/ui'
-import { Area, CartesianGrid, ComposedChart, Line, XAxis, YAxis, ReferenceLine } from 'recharts'
-import { ChartContainer, ChartTooltip, type ChartConfig } from '@/components/ui/line-charts-6'
+import { AreaChart as VisxAreaChart, Area as VisxArea, Grid as VisxGrid, XAxis as VisxXAxis, YAxis as VisxYAxis, ChartTooltip as VisxChartTooltip, type TooltipRow } from '@/components/ui/area-chart'
import { Card, CardContent, CardHeader } from '@/components/ui/card'
import { formatNumber, formatDuration, formatUpdatedAgo, DatePicker } from '@ciphera-net/ui'
import { Select, DownloadIcon, PlusIcon, XIcon } from '@ciphera-net/ui'
@@ -103,40 +102,11 @@ const METRIC_CONFIGS: {
{ key: 'avg_duration', label: 'Visit Duration', format: (v) => formatDuration(v) },
]
-const chartConfig = {
- visitors: { label: 'Unique Visitors', color: '#FD5E0F' },
- pageviews: { label: 'Total Pageviews', color: '#FD5E0F' },
- bounce_rate: { label: 'Bounce Rate', color: '#FD5E0F' },
- avg_duration: { label: 'Visit Duration', color: '#FD5E0F' },
-} satisfies ChartConfig
-
-// ─── Custom Tooltip ─────────────────────────────────────────────────
-
-interface TooltipProps {
- active?: boolean
- payload?: Array<{ dataKey: string; value: number; color: string }>
- label?: string
- metric: MetricType
-}
-
-function CustomTooltip({ active, payload, metric }: TooltipProps) {
- if (active && payload && payload.length) {
- const entry = payload[0]
- const config = METRIC_CONFIGS.find((m) => m.key === metric)
-
- if (config) {
- return (
-
-
-
-
{config.label}:
-
{config.format(entry.value)}
-
-
- )
- }
- }
- return null
+const CHART_COLORS: Record = {
+ visitors: '#FD5E0F',
+ pageviews: '#FD5E0F',
+ bounce_rate: '#FD5E0F',
+ avg_duration: '#FD5E0F',
}
// ─── Chart Component ─────────────────────────────────────────────────
@@ -227,6 +197,7 @@ export default function Chart({
return {
date: formattedDate,
+ dateObj: new Date(item.date),
originalDate: item.date,
pageviews: item.pageviews,
visitors: item.visitors,
@@ -450,103 +421,41 @@ export default function Chart({
) : (
-
[]}
+ xDataKey="dateObj"
+ aspectRatio="2.5 / 1"
+ margin={{ top: 20, right: 20, bottom: 40, left: 50 }}
>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- {
- const config = METRIC_CONFIGS.find((m) => m.key === metric)
- return config ? config.format(value) : value.toString()
- }}
- />
-
- } cursor={{ strokeDasharray: '3 3', stroke: '#9ca3af' }} />
-
-
- {/* Annotation reference lines */}
- {visibleAnnotationMarkers.map((marker) => {
- const primaryCategory = marker.annotations[0].category
- const color = ANNOTATION_COLORS[primaryCategory] || ANNOTATION_COLORS.other
- return (
-
- )
- })}
-
-
-
-
-
+
+
+
+
{
+ const config = METRIC_CONFIGS.find((m) => m.key === metric)
+ return config ? config.format(v) : v.toString()
+ }}
+ />
+ {
+ const config = METRIC_CONFIGS.find((m) => m.key === metric)
+ const value = point[metric] as number
+ return [{
+ color: CHART_COLORS[metric],
+ label: config?.label || metric,
+ value: config ? config.format(value) : value,
+ }]
+ }}
+ />
+
)}
diff --git a/components/ui/area-chart.tsx b/components/ui/area-chart.tsx
new file mode 100644
index 0000000..0515ed9
--- /dev/null
+++ b/components/ui/area-chart.tsx
@@ -0,0 +1,2292 @@
+"use client";
+
+import { localPoint } from "@visx/event";
+import { curveMonotoneX } from "@visx/curve";
+import { GridColumns, GridRows } from "@visx/grid";
+import { ParentSize } from "@visx/responsive";
+import { scaleLinear, scaleTime, type scaleBand } from "@visx/scale";
+import { AreaClosed, LinePath } from "@visx/shape";
+import { bisector } from "d3-array";
+import {
+ AnimatePresence,
+ motion,
+ useMotionTemplate,
+ useSpring,
+} from "motion/react";
+import {
+ Children,
+ createContext,
+ isValidElement,
+ useCallback,
+ useContext,
+ useEffect,
+ useId,
+ useLayoutEffect,
+ useMemo,
+ useRef,
+ useState,
+ type Dispatch,
+ type ReactElement,
+ type ReactNode,
+ type RefObject,
+ type SetStateAction,
+} from "react";
+import useMeasure from "react-use-measure";
+import { createPortal } from "react-dom";
+import { type ClassValue, clsx } from "clsx";
+import { twMerge } from "tailwind-merge";
+
+// ─── Utils ───────────────────────────────────────────────────────────────────
+
+function cn(...inputs: ClassValue[]) {
+ return twMerge(clsx(inputs));
+}
+
+// ─── Chart Context ───────────────────────────────────────────────────────────
+
+// biome-ignore lint/suspicious/noExplicitAny: d3 curve factory type
+type CurveFactory = any;
+
+type ScaleLinearType