Finance
Forex Card - Foreign Exchange Trading
Monitor foreign exchange rates and currency trading. Track FX exposure and hedging strategies.
Finance Forex Card
The Finance Forex Card displays real-time foreign exchange rates and currency trends, helping traders and businesses manage currency exposure.
Preview
Installation
npx shadcn@latest add https://vectormotion.vercel.app/registry/finance-forex-card.jsonFinance Forex Card
'use client'import React, { useState, useEffect } from 'react';import { RefreshCcw, ArrowRight, TrendingUp } from 'lucide-react';import { motion, AnimatePresence } from 'motion/react';import { clsx, type ClassValue } from "clsx"import { twMerge } from "tailwind-merge"import { ResponsiveContainer, AreaChart, Area, YAxis } from 'recharts';function cn(...inputs: ClassValue[]) { return twMerge(clsx(inputs))}// Simulated live value componentconst LiveValue = ({ baseValue }: { baseValue: number }) => { const [value, setValue] = useState(baseValue); const [prevValue, setPrevValue] = useState(baseValue); const [data, setData] = useState([0.9180, 0.9190, 0.9185, 0.9195, 0.9192, 0.9200, 0.9205]); useEffect(() => { const interval = setInterval(() => { const change = (Math.random() - 0.5) * 0.002; setPrevValue(value); const newValue = Number((value + change).toFixed(4)); setValue(newValue); setData(prev => [...prev.slice(1), newValue]); }, 2000); return () => clearInterval(interval); }, [value]); const direction = value > prevValue ? 'up' : 'down'; return ( <div className="flex flex-col items-end"> <div className="h-8 w-24 mb-1"> <ResponsiveContainer width="100%" height="100%"> <AreaChart data={data.map((v) => ({ value: v }))}> <defs> <linearGradient id="gradForex" x1="0" y1="0" x2="0" y2="1"> <stop offset="5%" stopColor="#10b981" stopOpacity={0.3} /> <stop offset="95%" stopColor="#10b981" stopOpacity={0} /> </linearGradient> </defs> <YAxis domain={['dataMin', 'dataMax']} hide /> <Area type="monotone" dataKey="value" stroke="#10b981" fill="url(#gradForex)" strokeWidth={2} /> </AreaChart> </ResponsiveContainer> </div> <AnimatePresence mode="popLayout"> <motion.p key={value} initial={{ opacity: 0 }} animate={{ opacity: 1 }} className={`font-mono text-lg font-medium ${direction === 'up' ? 'text-emerald-500' : 'text-foreground' }`} > {value.toFixed(4)} </motion.p> </AnimatePresence> </div> );};interface ForexCardProps { isInteractive?: boolean; className?: string; title?: string; statusLabel?: string; usdValue?: string; eurBaseValue?: number;}const DEFAULT_TITLE = "Exchange Rates";const DEFAULT_STATUS_LABEL = "Live Feed";const DEFAULT_USD_VALUE = "1.0000";const DEFAULT_EUR_BASE_VALUE = 0.9200;export const ForexCard: React.FC<ForexCardProps> = ({ isInteractive = true, className = "", title = DEFAULT_TITLE, statusLabel = DEFAULT_STATUS_LABEL, usdValue = DEFAULT_USD_VALUE, eurBaseValue = DEFAULT_EUR_BASE_VALUE,}) => { const index = 46; return ( <motion.div layoutId={isInteractive ? `card-${index}-${title}` : undefined} transition={{ duration: 0.4, ease: "easeOut" }} className={cn( "relative overflow-hidden rounded-xl border border-border bg-card text-card-foreground p-5 shadow-sm transition-all flex flex-col h-full group", isInteractive ? "cursor-pointer hover:border-primary/50 hover:shadow-md" : "", className )} > <div className="mb-2 flex items-start justify-between relative z-10"> <div> <h3 className="font-semibold text-lg text-foreground"> {title} </h3> <div className="flex items-center gap-2 mt-1"> <span className="text-xs text-muted-foreground">{statusLabel}</span> </div> </div> <div className="rounded-lg bg-emerald-500/10 p-2 text-emerald-500"> <RefreshCcw className="h-5 w-5" /> </div> </div> <div className="relative z-10 flex-1"> <div className="space-y-4 mt-2"> {/* USD */} <div className="flex items-center justify-between p-3 rounded-lg bg-muted"> <div className="flex items-center gap-3"> <div className="flex h-8 w-8 items-center justify-center rounded-full bg-white dark:bg-zinc-700 shadow-sm border border-zinc-100 dark:border-zinc-600 text-sm"> πΊπΈ </div> <div> <p className="text-sm font-bold text-foreground">USD</p> </div> </div> <div className="text-right"> <p className="font-mono text-lg font-medium text-foreground">{usdValue}</p> </div> </div> <div className="relative flex justify-center -my-5 z-20 pointer-events-none"> <div className="bg-card text-card-foreground border border-zinc-200 dark:border-zinc-700 rounded-full p-1 shadow-sm"> <ArrowRight className="h-3 w-3 text-muted-foreground rotate-90" /> </div> </div> {/* EUR */} <div className="flex items-center justify-between p-3 rounded-lg bg-muted"> <div className="flex items-center gap-3"> <div className="flex h-8 w-8 items-center justify-center rounded-full bg-white dark:bg-zinc-700 shadow-sm border border-zinc-100 dark:border-zinc-600 text-sm"> πͺπΊ </div> <div> <p className="text-sm font-bold text-foreground">EUR</p> </div> </div> <LiveValue baseValue={eurBaseValue} /> </div> </div> </div> </motion.div> );};Props
Prop
Type