ComponentsBlocksDocsExamples
Cards
Statistic CardsNewList CardsSoonTable CardsSoonTimeline CardsSoonForm CardsSoon
Charts
Line ChartsNewArea ChartsNewBar ChartsSoonPie ChartsSoonDoughnut ChartsSoonRadar ChartsSoon
Navigation
DropdownsSoonNavbarsSoonTabsSoonBreadcrumbsSoonVertical NavigationSoon
Lists
Stacked ListsSoonTablesSoonData GridsSoonTreesSoonFeedsSoon
Forms
Form LayoutsSoonForm WizardsSoonForm UploadsSoonAction FormsSoonModal FormsSoonDrawer FormsSoon
Feedback
AlertsSoonDialogsSoonNotificationsSoonEmpty StatesSoonLoading StatesSoonOverlay ContentSoon
Marketing
HeroNewPricing TablesSoonFeaturesSoonCall to ActionSoonTestimonialsSoon
Ecommerce
HeroNewPagesNewCartsNewPricing TablesSoonFeaturesSoonCall to ActionSoonTestimonialsSoon
Application
App-ShellNew
  1. Blocks
  2. Charts
  3. Area Charts
  4. area-chart-4

area-chart-4

Single block view - Copy and use this block in your project

area-chart-3
area-chart-5
Open in
Loading...
charts/area-charts/area-chart-4.tsx
'use client';

import React, { Fragment, useState } from 'react';
import { Card, CardContent, CardHeader, CardTitle, CardToolbar } from '@/registry/default/ui/card';
import { ChartConfig, ChartContainer, ChartTooltip } from '@/registry/default/ui/chart';
import { ToggleGroup, ToggleGroupItem } from '@/registry/default/ui/toggle-group';
import { CheckCircle, Clock, TrendingUp } from 'lucide-react';
import { Area, AreaChart, XAxis, YAxis } from 'recharts';

// Subscription revenue data for different periods
const revenueData = {
  day: [
    { period: '00:00', revenue: 1200 },
    { period: '04:00', revenue: 800 },
    { period: '08:00', revenue: 2100 },
    { period: '12:00', revenue: 3200 },
    { period: '16:00', revenue: 2800 },
    { period: '20:00', revenue: 1900 },
  ],
  week: [
    { period: 'Mon', revenue: 2400 },
    { period: 'Tue', revenue: 2800 },
    { period: 'Wed', revenue: 2200 },
    { period: 'Thu', revenue: 3200 },
    { period: 'Fri', revenue: 2900 },
    { period: 'Sat', revenue: 1800 },
    { period: 'Sun', revenue: 2600 },
  ],
  month: [
    { period: 'Week 1', revenue: 16800 },
    { period: 'Week 2', revenue: 18200 },
    { period: 'Week 3', revenue: 15600 },
    { period: 'Week 4', revenue: 19400 },
  ],
  year: [
    { period: 'Q1', revenue: 198000 },
    { period: 'Q2', revenue: 225000 },
    { period: 'Q3', revenue: 189000 },
    { period: 'Q4', revenue: 267000 },
  ],
};

const chartConfig = {
  revenue: {
    label: 'Revenue',
    color: 'var(--color-slate-600)',
  },
} satisfies ChartConfig;

// Custom Tooltip
interface TooltipProps {
  active?: boolean;
  payload?: Array<{
    dataKey: string;
    value: number;
    color: string;
  }>;
  label?: string;
}

const CustomTooltip = ({ active, payload }: TooltipProps) => {
  if (active && payload && payload.length) {
    return (
      <div className="rounded-lg bg-zinc-900 text-white p-3 shadow-lg">
        <div className="text-xs font-medium mb-1">Revenue:</div>
        <div className="text-sm font-semibold">${payload[0].value.toLocaleString()}</div>
      </div>
    );
  }
  return null;
};

// Period configuration
const PERIODS = {
  day: { key: 'day', label: 'Day' },
  week: { key: 'week', label: 'Week' },
  month: { key: 'month', label: 'Month' },
  year: { key: 'year', label: 'Year' },
} as const;

type PeriodKey = keyof typeof PERIODS;

// Statistics data
const statisticsData = [
  {
    id: 'finished',
    label: 'Finished',
    value: '18',
    change: '+4 tasks',
    changeType: 'positive',
    icon: CheckCircle,
  },
  {
    id: 'tracked',
    label: 'Tracked',
    value: '31h',
    change: '-6 hours',
    changeType: 'negative',
    icon: Clock,
  },
  {
    id: 'efficiency',
    label: 'Efficiency',
    value: '93%',
    change: '+12%',
    changeType: 'positive',
    icon: TrendingUp,
  },
] as const;

export default function AreaChart4() {
  const [selectedPeriod, setSelectedPeriod] = useState<PeriodKey>('day');

  // Get data for selected period
  const currentData = revenueData[selectedPeriod];

  return (
    <div className="min-h-screen flex items-center justify-center p-6 lg:p-8">
      <Card className="w-full lg:max-w-4xl rounded-2xl">
        <CardHeader className="min-h-auto py-6 border-0">
          <CardTitle className="text-xl font-semibold">Orders Overview</CardTitle>
          <CardToolbar>
            <ToggleGroup
              type="single"
              value={selectedPeriod}
              variant="outline"
              onValueChange={(value) => value && setSelectedPeriod(value as PeriodKey)}
              className=""
            >
              {Object.values(PERIODS).map((period) => (
                <ToggleGroupItem
                  key={period.key}
                  value={period.key}
                  className="px-3.5 first:rounded-s-full! last:rounded-e-full!"
                >
                  {period.label}
                </ToggleGroupItem>
              ))}
            </ToggleGroup>
          </CardToolbar>
        </CardHeader>

        <CardContent className="px-0">
          {/* Statistics Blocks */}
          <div className="flex items-center flex-wrap px-6 gap-10 mb-10">
            {statisticsData.map((stat) => {
              const IconComponent = stat.icon;
              return (
                <Fragment key={stat.id}>
                  <div className="h-10 w-px bg-border hidden lg:block first:hidden" />
                  <div key={stat.id} className="flex items-center gap-3">
                    <div className="flex items-center">
                      <div className="flex items-center gap-3">
                        <div className="flex items-center justify-center w-10 h-10 rounded-full bg-muted/60 border border-muted-foreground/10">
                          <IconComponent className="w-4.5 text-muted-foreground" />
                        </div>
                        <div>
                          <div className="text-sm text-muted-foreground mb-0.5">{stat.label}</div>
                          <div className="flex items-center gap-2">
                            <span className="text-2xl font-bold">{stat.value}</span>
                            <span
                              className={`text-sm font-medium ${
                                stat.changeType === 'positive' ? 'text-emerald-600' : 'text-red-600'
                              }`}
                            >
                              {stat.change}
                            </span>
                          </div>
                        </div>
                      </div>
                    </div>
                  </div>
                </Fragment>
              );
            })}
          </div>

          {/* Chart */}
          <div className="px-3.5 h-[300px] w-full">
            <ChartContainer
              config={chartConfig}
              className="h-full w-full overflow-visible [&_.recharts-curve.recharts-tooltip-cursor]:stroke-initial"
            >
              <AreaChart
                data={currentData}
                margin={{
                  top: 15,
                  right: 10,
                  left: 10,
                  bottom: 15,
                }}
                style={{ overflow: 'visible' }}
              >
                {/* SVG Pattern for chart area */}
                <defs>
                  {/* Grid pattern */}
                  <pattern id="gridPattern" x="0" y="0" width="20" height="40" patternUnits="userSpaceOnUse">
                    <path d="M 20 0 L 0 0 0 20" fill="none" stroke="var(--input)" strokeWidth="0.5" strokeOpacity="1" />
                  </pattern>

                  {/* Area gradient fill */}
                  <linearGradient id="areaGradient" x1="0" y1="0" x2="0" y2="1">
                    <stop offset="0%" stopColor={chartConfig.revenue.color} stopOpacity={0.3} />
                    <stop offset="100%" stopColor={chartConfig.revenue.color} stopOpacity={0.05} />
                  </linearGradient>

                  {/* Shadow filters for dots */}
                  <filter id="dotShadow" x="-100%" y="-100%" width="300%" height="300%">
                    <feDropShadow dx="2" dy="2" stdDeviation="3" floodColor="rgba(0,0,0,0.4)" />
                  </filter>
                  <filter id="activeDotShadow" x="-100%" y="-100%" width="300%" height="300%">
                    <feDropShadow dx="3" dy="3" stdDeviation="4" floodColor="rgba(0,0,0,0.5)" />
                  </filter>
                </defs>

                {/* Background pattern for chart area only */}
                <rect
                  x="60px"
                  y="-20px"
                  width="calc(100% - 75px)"
                  height="calc(100% - 10px)"
                  fill="url(#gridPattern)"
                  style={{ pointerEvents: 'none' }}
                />

                <XAxis
                  dataKey="period"
                  axisLine={false}
                  tickLine={false}
                  tick={{ fontSize: 12, fill: 'var(--muted-foreground)' }}
                  tickMargin={8}
                  interval={0}
                  includeHidden={true}
                />

                <YAxis
                  hide={true}
                  axisLine={false}
                  tickLine={false}
                  tick={{ fontSize: 11, fill: 'var(--muted-foreground)' }}
                  tickFormatter={(value) => `$${value >= 1000 ? `${(value / 1000).toFixed(0)}K` : value}`}
                  tickMargin={8}
                  domain={[0, 'dataMax']}
                  ticks={[0]}
                />

                <ChartTooltip
                  content={<CustomTooltip />}
                  cursor={{
                    stroke: chartConfig.revenue.color,
                    strokeWidth: 1,
                    strokeDasharray: 'none',
                  }}
                />

                <Area
                  type="monotone"
                  dataKey="revenue"
                  stroke={chartConfig.revenue.color}
                  strokeWidth={2}
                  fill="url(#areaGradient)"
                  dot={(props) => {
                    const { cx, cy, payload } = props;
                    // Show dots only for specific periods based on selected time range
                    const showDot =
                      (selectedPeriod === 'day' && (payload.period === '08:00' || payload.period === '16:00')) ||
                      (selectedPeriod === 'week' && (payload.period === 'Thu' || payload.period === 'Sat')) ||
                      (selectedPeriod === 'month' && payload.period === 'Week 2') ||
                      (selectedPeriod === 'year' && payload.period === 'Q2');

                    if (showDot) {
                      return (
                        <circle
                          key={`dot-${cx}-${cy}`}
                          cx={cx}
                          cy={cy}
                          r={4}
                          fill={chartConfig.revenue.color}
                          stroke="white"
                          strokeWidth={2}
                          filter="url(#dotShadow)"
                        />
                      );
                    }
                    return <g key={`dot-${cx}-${cy}`} />; // Return empty group for other points
                  }}
                  activeDot={{
                    r: 6,
                    fill: chartConfig.revenue.color,
                    stroke: 'white',
                    strokeWidth: 2,
                    filter: 'url(#dotShadow)',
                  }}
                />
              </AreaChart>
            </ChartContainer>
          </div>
        </CardContent>
      </Card>
    </div>
  );
}

Didn't find what you were looking for?

Suggest block

We use cookies

We use cookies to ensure you get the best experience on our website. For more information on how we use cookies, please see our cookie policy.

By clicking Accept, you agree to our use of cookies.
Learn more.

Token UI

Components

  • Overview
  • Pricing
  • Marketplace
  • Features
  • Integrations
  • Pricing

Blocks

  • Charts
  • Team
  • Blog
  • Careers
  • Contact
  • Privacy

Examples

  • Help
  • Sales
  • Advertise

Docs

  • Twitter
  • Instagram
  • LinkedIn

© 2025 TOUI.dev. All rights reserved.

  • Terms and Conditions
  • Privacy Policy