clean(lme): remove third-party labels, contango badges, and refresh button
This commit is contained in:
parent
b6497a4b13
commit
9b1daf6f76
|
|
@ -101,7 +101,6 @@ def fetch_raw():
|
||||||
"three_months_str": p["three_months_str"],
|
"three_months_str": p["three_months_str"],
|
||||||
"spread": spread,
|
"spread": spread,
|
||||||
"spread_str": f"{spread:+,.2f}",
|
"spread_str": f"{spread:+,.2f}",
|
||||||
"market_condition": "Contango" if spread > 0 else ("Backwardation" if spread < 0 else "Flat"),
|
|
||||||
"stocks": s_data.get("stocks", 0),
|
"stocks": s_data.get("stocks", 0),
|
||||||
"stocks_str": s_data.get("stocks_str", "-"),
|
"stocks_str": s_data.get("stocks_str", "-"),
|
||||||
"stocks_change": s_data.get("change", 0),
|
"stocks_change": s_data.get("change", 0),
|
||||||
|
|
@ -133,8 +132,6 @@ def fetch_raw():
|
||||||
})
|
})
|
||||||
|
|
||||||
return {
|
return {
|
||||||
"source": "Westmetall GmbH / London Metal Exchange (LME)",
|
|
||||||
"source_url": "https://www.westmetall.com/en/markdaten.php",
|
|
||||||
"date": date_str or datetime.utcnow().strftime("%d. %B %Y"),
|
"date": date_str or datetime.utcnow().strftime("%d. %B %Y"),
|
||||||
"updated_at": datetime.utcnow().isoformat(),
|
"updated_at": datetime.utcnow().isoformat(),
|
||||||
"metals": combined_metals,
|
"metals": combined_metals,
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,11 @@
|
||||||
import { useState, useEffect, useMemo } from "react";
|
import { useState, useEffect, useMemo } from "react";
|
||||||
import {
|
import {
|
||||||
Search,
|
Search,
|
||||||
ExternalLink,
|
|
||||||
RefreshCw,
|
|
||||||
TrendingUp,
|
|
||||||
TrendingDown,
|
|
||||||
Warehouse,
|
Warehouse,
|
||||||
Coins,
|
Coins,
|
||||||
DollarSign,
|
DollarSign,
|
||||||
Layers,
|
Layers,
|
||||||
ArrowUpDown,
|
ArrowUpDown,
|
||||||
ShieldCheck,
|
|
||||||
Globe
|
Globe
|
||||||
} from "lucide-react";
|
} from "lucide-react";
|
||||||
import { API_BASE } from "@/lib/api";
|
import { API_BASE } from "@/lib/api";
|
||||||
|
|
@ -26,7 +21,6 @@ export interface LmeMetal {
|
||||||
three_months_str: string;
|
three_months_str: string;
|
||||||
spread: number;
|
spread: number;
|
||||||
spread_str: string;
|
spread_str: string;
|
||||||
market_condition: "Contango" | "Backwardation" | "Flat";
|
|
||||||
stocks: number;
|
stocks: number;
|
||||||
stocks_str: string;
|
stocks_str: string;
|
||||||
stocks_change: number;
|
stocks_change: number;
|
||||||
|
|
@ -46,8 +40,6 @@ export interface LmePrecious {
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface LmeData {
|
export interface LmeData {
|
||||||
source: string;
|
|
||||||
source_url: string;
|
|
||||||
date: string;
|
date: string;
|
||||||
updated_at: string;
|
updated_at: string;
|
||||||
metals: LmeMetal[];
|
metals: LmeMetal[];
|
||||||
|
|
@ -56,35 +48,29 @@ export interface LmeData {
|
||||||
precious_metals: LmePrecious[];
|
precious_metals: LmePrecious[];
|
||||||
}
|
}
|
||||||
|
|
||||||
const METAL_COLORS: Record<string, { border: string; bg: string; text: string; badge: string }> = {
|
const METAL_STYLES: Record<string, { border: string; bg: string; text: string }> = {
|
||||||
Copper: { border: "border-amber-500/30", bg: "from-amber-500/10 to-orange-500/5", text: "text-amber-500", badge: "bg-amber-500/10 text-amber-600 dark:text-amber-400" },
|
Copper: { border: "border-amber-500/30", bg: "from-amber-500/10 to-transparent", text: "text-amber-500" },
|
||||||
Aluminium: { border: "border-sky-500/30", bg: "from-sky-500/10 to-blue-500/5", text: "text-sky-500", badge: "bg-sky-500/10 text-sky-600 dark:text-sky-400" },
|
Aluminium: { border: "border-sky-500/30", bg: "from-sky-500/10 to-transparent", text: "text-sky-500" },
|
||||||
Zinc: { border: "border-emerald-500/30", bg: "from-emerald-500/10 to-teal-500/5", text: "text-emerald-500", badge: "bg-emerald-500/10 text-emerald-600 dark:text-emerald-400" },
|
Zinc: { border: "border-emerald-500/30", bg: "from-emerald-500/10 to-transparent", text: "text-emerald-500" },
|
||||||
Nickel: { border: "border-purple-500/30", bg: "from-purple-500/10 to-indigo-500/5", text: "text-purple-500", badge: "bg-purple-500/10 text-purple-600 dark:text-purple-400" },
|
Nickel: { border: "border-purple-500/30", bg: "from-purple-500/10 to-transparent", text: "text-purple-500" },
|
||||||
Lead: { border: "border-slate-500/30", bg: "from-slate-500/10 to-zinc-500/5", text: "text-slate-400", badge: "bg-slate-500/10 text-slate-600 dark:text-slate-300" },
|
Lead: { border: "border-slate-500/30", bg: "from-slate-500/10 to-transparent", text: "text-slate-400" },
|
||||||
Tin: { border: "border-cyan-500/30", bg: "from-cyan-500/10 to-teal-500/5", text: "text-cyan-500", badge: "bg-cyan-500/10 text-cyan-600 dark:text-cyan-400" },
|
Tin: { border: "border-cyan-500/30", bg: "from-cyan-500/10 to-transparent", text: "text-cyan-500" },
|
||||||
};
|
};
|
||||||
|
|
||||||
export function LmeView() {
|
export function LmeView() {
|
||||||
const [data, setData] = useState<LmeData | null>(null);
|
const [data, setData] = useState<LmeData | null>(null);
|
||||||
const [loading, setLoading] = useState<boolean>(true);
|
|
||||||
const [error, setError] = useState<string | null>(null);
|
const [error, setError] = useState<string | null>(null);
|
||||||
const [search, setSearch] = useState<string>("");
|
const [search, setSearch] = useState<string>("");
|
||||||
const [lastRefreshed, setLastRefreshed] = useState<string>("");
|
|
||||||
|
|
||||||
const loadData = async () => {
|
const loadData = async () => {
|
||||||
setLoading(true);
|
|
||||||
try {
|
try {
|
||||||
const res = await fetch(`${API}/api/lme`, { credentials: "include" });
|
const res = await fetch(`${API}/api/lme`, { credentials: "include" });
|
||||||
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
||||||
const json: LmeData = await res.json();
|
const json: LmeData = await res.json();
|
||||||
setData(json);
|
setData(json);
|
||||||
setError(null);
|
setError(null);
|
||||||
setLastRefreshed(new Date().toLocaleTimeString("fa-IR"));
|
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
setError(err.message || "خطا در دریافت دادههای LME");
|
setError(err.message || "خطا در دریافت دادههای LME");
|
||||||
} finally {
|
|
||||||
setLoading(false);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -107,50 +93,27 @@ export function LmeView() {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<main className="mx-auto max-w-6xl p-4 sm:p-6 space-y-6" dir="rtl">
|
<main className="mx-auto max-w-6xl p-4 sm:p-6 space-y-6" dir="rtl">
|
||||||
{/* Header Banner */}
|
{/* Clean Header */}
|
||||||
<div className="relative overflow-hidden rounded-2xl border border-border/60 bg-gradient-to-br from-card via-card/90 to-card/60 p-5 sm:p-6 backdrop-blur-xl shadow-lg">
|
<div className="flex flex-col sm:flex-row sm:items-center sm:justify-between gap-4 border-b border-border/60 pb-5">
|
||||||
<div className="flex flex-col sm:flex-row sm:items-center sm:justify-between gap-4">
|
<div className="flex items-center gap-3">
|
||||||
<div className="space-y-1.5">
|
<div className="w-10 h-10 rounded-xl bg-primary/10 border border-primary/20 grid place-items-center shrink-0">
|
||||||
<div className="flex items-center gap-2">
|
<Globe className="w-5 h-5 text-primary" />
|
||||||
<span className="flex h-2.5 w-2.5 rounded-full bg-emerald-500 animate-pulse" />
|
</div>
|
||||||
<span className="text-xs font-medium text-emerald-600 dark:text-emerald-400 tracking-wide uppercase">
|
<div>
|
||||||
بورس فلزات لندن (London Metal Exchange)
|
<h1 className="text-xl sm:text-2xl font-bold tracking-tight text-foreground">
|
||||||
</span>
|
بورس فلزات لندن (LME)
|
||||||
</div>
|
|
||||||
<h1 className="text-2xl sm:text-3xl font-bold tracking-tight text-foreground flex items-center gap-2.5">
|
|
||||||
<span>قیمتهای رسمی LME & موجودی انبارها</span>
|
|
||||||
</h1>
|
</h1>
|
||||||
<p className="text-xs sm:text-sm text-muted-foreground">
|
<p className="text-xs text-muted-foreground mt-0.5">
|
||||||
بروزرسانی روزانه قیمتهای تسویه نقدی (Cash Settlement)، قراردادهای ۳ ماهه و انبارداری از مرجع رسمی Westmetall
|
قیمتهای رسمی نقدی، قراردادهای ۳ ماهه و موجودی انبارها
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex flex-wrap items-center gap-2.5">
|
|
||||||
{data?.date && (
|
|
||||||
<div className="rounded-xl border border-border/80 bg-background/60 px-3 py-1.5 text-xs text-muted-foreground shadow-sm">
|
|
||||||
تاریخ بازار: <span className="font-semibold text-foreground">{data.date}</span>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
<button
|
|
||||||
onClick={loadData}
|
|
||||||
disabled={loading}
|
|
||||||
className="inline-flex items-center gap-1.5 rounded-xl border border-border/80 bg-background/60 px-3 py-1.5 text-xs font-medium text-foreground transition hover:bg-accent disabled:opacity-50 shadow-sm"
|
|
||||||
title="بروزرسانی دادهها"
|
|
||||||
>
|
|
||||||
<RefreshCw className={`w-3.5 h-3.5 ${loading ? "animate-spin text-primary" : ""}`} />
|
|
||||||
<span>{loading ? "در حال دریافت..." : "بروزرسانی"}</span>
|
|
||||||
</button>
|
|
||||||
<a
|
|
||||||
href="https://www.westmetall.com/en/markdaten.php"
|
|
||||||
target="_blank"
|
|
||||||
rel="noopener noreferrer"
|
|
||||||
className="inline-flex items-center gap-1.5 rounded-xl bg-primary px-3.5 py-1.5 text-xs font-medium text-primary-foreground shadow-sm transition hover:bg-primary/90"
|
|
||||||
>
|
|
||||||
<span>سایت Westmetall</span>
|
|
||||||
<ExternalLink className="w-3.5 h-3.5" />
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{data?.date && (
|
||||||
|
<div className="self-start sm:self-auto rounded-xl border border-border/80 bg-card/60 px-3.5 py-1.5 text-xs text-muted-foreground shadow-sm">
|
||||||
|
تاریخ: <span className="font-semibold text-foreground">{data.date}</span>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{error && (
|
{error && (
|
||||||
|
|
@ -162,34 +125,28 @@ export function LmeView() {
|
||||||
{/* KPI Cards Grid */}
|
{/* KPI Cards Grid */}
|
||||||
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4">
|
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4">
|
||||||
{data?.metals.map((m) => {
|
{data?.metals.map((m) => {
|
||||||
const style = METAL_COLORS[m.metal] || {
|
const style = METAL_STYLES[m.metal] || {
|
||||||
border: "border-border",
|
border: "border-border",
|
||||||
bg: "from-card to-card",
|
bg: "from-card to-transparent",
|
||||||
text: "text-primary",
|
text: "text-primary",
|
||||||
badge: "bg-primary/10 text-primary",
|
|
||||||
};
|
};
|
||||||
const isBackwardation = m.spread < 0;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
key={m.metal}
|
key={m.metal}
|
||||||
className={`relative overflow-hidden rounded-2xl border ${style.border} bg-gradient-to-br ${style.bg} p-5 backdrop-blur-md transition-all duration-200 hover:shadow-md hover:-translate-y-0.5`}
|
className={`relative overflow-hidden rounded-2xl border ${style.border} bg-gradient-to-b ${style.bg} bg-card/40 p-5 backdrop-blur-md transition-all duration-200 hover:shadow-md hover:-translate-y-0.5`}
|
||||||
>
|
>
|
||||||
<div className="flex items-start justify-between">
|
<div className="flex items-start justify-between">
|
||||||
<div>
|
<div>
|
||||||
<div className="text-base font-bold text-foreground">{m.name_fa}</div>
|
<div className="text-base font-bold text-foreground">{m.name_fa}</div>
|
||||||
<div className="text-xs text-muted-foreground font-mono">{m.metal} • {m.unit}</div>
|
<div className="text-xs text-muted-foreground font-mono mt-0.5">{m.metal} • USD/mt</div>
|
||||||
|
</div>
|
||||||
|
<div className="flex items-center gap-1 text-xs font-mono font-medium text-muted-foreground">
|
||||||
|
<ArrowUpDown className="w-3.5 h-3.5" />
|
||||||
|
<span className={m.spread < 0 ? "text-amber-500" : "text-emerald-500"}>
|
||||||
|
{m.spread_str} $
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<span
|
|
||||||
className={`text-[11px] font-semibold px-2.5 py-0.5 rounded-full ${
|
|
||||||
isBackwardation
|
|
||||||
? "bg-amber-500/15 text-amber-600 dark:text-amber-400 border border-amber-500/30"
|
|
||||||
: "bg-emerald-500/15 text-emerald-600 dark:text-emerald-400 border border-emerald-500/30"
|
|
||||||
}`}
|
|
||||||
title={isBackwardation ? "تقاضای فوری بیشتر از آتی (بکواردیشن)" : "قیمت آتی بیشتر از نقدی (کونتانگو)"}
|
|
||||||
>
|
|
||||||
{m.market_condition}
|
|
||||||
</span>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Prices Section */}
|
{/* Prices Section */}
|
||||||
|
|
@ -201,37 +158,31 @@ export function LmeView() {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<div className="text-[11px] text-muted-foreground">قرارداد ۳ ماهه (3M)</div>
|
<div className="text-[11px] text-muted-foreground">۳ ماهه (3-Month)</div>
|
||||||
<div className="text-lg font-bold font-mono text-foreground mt-0.5">
|
<div className="text-lg font-bold font-mono text-foreground mt-0.5">
|
||||||
${m.three_months_str}
|
${m.three_months_str}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Spread & Warehouse Stocks */}
|
{/* Warehouse Stocks */}
|
||||||
<div className="mt-3 flex items-center justify-between text-xs pt-2.5 border-t border-border/40 text-muted-foreground">
|
<div className="mt-3 flex items-center justify-between text-xs pt-2.5 border-t border-border/40 text-muted-foreground">
|
||||||
<div className="flex items-center gap-1.5">
|
<div className="flex items-center gap-1.5">
|
||||||
<ArrowUpDown className="w-3.5 h-3.5 text-muted-foreground" />
|
|
||||||
<span>اسپرد: </span>
|
|
||||||
<span className={`font-mono font-semibold ${isBackwardation ? "text-amber-500" : "text-emerald-500"}`}>
|
|
||||||
{m.spread_str} $
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
<div className="flex items-center gap-1.5" title="موجودی انبارهای بورس لندن و تغییرات روزانه">
|
|
||||||
<Warehouse className="w-3.5 h-3.5 text-muted-foreground" />
|
<Warehouse className="w-3.5 h-3.5 text-muted-foreground" />
|
||||||
<span className="font-mono font-medium text-foreground">{m.stocks_str} تن</span>
|
<span>موجودی انبار:</span>
|
||||||
{m.stocks_change !== 0 && (
|
<span className="font-mono font-semibold text-foreground">{m.stocks_str} تن</span>
|
||||||
<span
|
|
||||||
className={`text-[10px] font-mono font-bold px-1 rounded ${
|
|
||||||
m.stocks_change > 0
|
|
||||||
? "text-emerald-600 dark:text-emerald-400 bg-emerald-500/10"
|
|
||||||
: "text-rose-600 dark:text-rose-400 bg-rose-500/10"
|
|
||||||
}`}
|
|
||||||
>
|
|
||||||
{m.stocks_change_str}
|
|
||||||
</span>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
|
{m.stocks_change !== 0 && (
|
||||||
|
<span
|
||||||
|
className={`text-[11px] font-mono font-semibold ${
|
||||||
|
m.stocks_change > 0
|
||||||
|
? "text-emerald-600 dark:text-emerald-400"
|
||||||
|
: "text-rose-600 dark:text-rose-400"
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
{m.stocks_change > 0 ? "+" : ""}{m.stocks_change_str} تن
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
@ -243,7 +194,7 @@ export function LmeView() {
|
||||||
<div className="p-4 sm:p-5 border-b border-border/60 flex flex-col sm:flex-row sm:items-center sm:justify-between gap-3">
|
<div className="p-4 sm:p-5 border-b border-border/60 flex flex-col sm:flex-row sm:items-center sm:justify-between gap-3">
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<Layers className="w-4 h-4 text-primary" />
|
<Layers className="w-4 h-4 text-primary" />
|
||||||
<h2 className="text-base font-semibold text-foreground">جدول جامع مظنههای رسمی LME (Westmetall)</h2>
|
<h2 className="text-base font-semibold text-foreground">جدول مظنههای رسمی LME</h2>
|
||||||
</div>
|
</div>
|
||||||
<div className="relative w-full sm:w-64">
|
<div className="relative w-full sm:w-64">
|
||||||
<Search className="absolute right-3 top-2.5 w-4 h-4 text-muted-foreground" />
|
<Search className="absolute right-3 top-2.5 w-4 h-4 text-muted-foreground" />
|
||||||
|
|
@ -263,62 +214,47 @@ export function LmeView() {
|
||||||
<tr className="border-b border-border/60 bg-muted/40 text-muted-foreground font-medium">
|
<tr className="border-b border-border/60 bg-muted/40 text-muted-foreground font-medium">
|
||||||
<th className="py-3 px-4">فلز (Metal)</th>
|
<th className="py-3 px-4">فلز (Metal)</th>
|
||||||
<th className="py-3 px-4">تسویه نقدی (Cash)</th>
|
<th className="py-3 px-4">تسویه نقدی (Cash)</th>
|
||||||
<th className="py-3 px-4">۳ ماهه (3-Months)</th>
|
<th className="py-3 px-4">۳ ماهه (3-Month)</th>
|
||||||
<th className="py-3 px-4">اسپرد (3M - Cash)</th>
|
<th className="py-3 px-4">اسپرد (3M - Cash)</th>
|
||||||
<th className="py-3 px-4">وضعیت بازار</th>
|
<th className="py-3 px-4">موجودی انبارها (Stocks)</th>
|
||||||
<th className="py-3 px-4">موجودی انبارها (LME Stocks)</th>
|
|
||||||
<th className="py-3 px-4">تغییرات موجودی</th>
|
<th className="py-3 px-4">تغییرات موجودی</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody className="divide-y divide-border/40">
|
<tbody className="divide-y divide-border/40">
|
||||||
{filteredMetals.map((m) => {
|
{filteredMetals.map((m) => (
|
||||||
const isBackwardation = m.spread < 0;
|
<tr key={m.metal} className="transition-colors hover:bg-muted/30">
|
||||||
return (
|
<td className="py-3 px-4">
|
||||||
<tr key={m.metal} className="transition-colors hover:bg-muted/30">
|
<div className="font-semibold text-foreground">{m.name_fa}</div>
|
||||||
<td className="py-3 px-4">
|
<div className="text-[10px] text-muted-foreground font-mono">{m.metal}</div>
|
||||||
<div className="font-semibold text-foreground">{m.name_fa}</div>
|
</td>
|
||||||
<div className="text-[10px] text-muted-foreground font-mono">{m.metal}</div>
|
<td className="py-3 px-4 font-mono font-bold text-foreground">
|
||||||
</td>
|
${m.cash_str} <span className="text-[10px] text-muted-foreground font-normal">/ mt</span>
|
||||||
<td className="py-3 px-4 font-mono font-bold text-foreground">
|
</td>
|
||||||
${m.cash_str} <span className="text-[10px] text-muted-foreground font-normal">/ mt</span>
|
<td className="py-3 px-4 font-mono font-bold text-foreground">
|
||||||
</td>
|
${m.three_months_str} <span className="text-[10px] text-muted-foreground font-normal">/ mt</span>
|
||||||
<td className="py-3 px-4 font-mono font-bold text-foreground">
|
</td>
|
||||||
${m.three_months_str} <span className="text-[10px] text-muted-foreground font-normal">/ mt</span>
|
<td className={`py-3 px-4 font-mono font-semibold ${m.spread < 0 ? "text-amber-500" : "text-emerald-500"}`}>
|
||||||
</td>
|
{m.spread_str} $
|
||||||
<td className={`py-3 px-4 font-mono font-semibold ${isBackwardation ? "text-amber-500" : "text-emerald-500"}`}>
|
</td>
|
||||||
{m.spread_str} $
|
<td className="py-3 px-4 font-mono text-foreground font-medium">
|
||||||
</td>
|
{m.stocks_str} تن
|
||||||
<td className="py-3 px-4">
|
</td>
|
||||||
<span
|
<td className="py-3 px-4 font-mono font-semibold">
|
||||||
className={`text-[10px] font-semibold px-2 py-0.5 rounded-full ${
|
<span
|
||||||
isBackwardation
|
className={`inline-flex items-center gap-1 ${
|
||||||
? "bg-amber-500/15 text-amber-600 dark:text-amber-400"
|
m.stocks_change > 0
|
||||||
: "bg-emerald-500/15 text-emerald-600 dark:text-emerald-400"
|
? "text-emerald-600 dark:text-emerald-400"
|
||||||
}`}
|
: m.stocks_change < 0
|
||||||
>
|
? "text-rose-600 dark:text-rose-400"
|
||||||
{m.market_condition}
|
: "text-muted-foreground"
|
||||||
</span>
|
}`}
|
||||||
</td>
|
>
|
||||||
<td className="py-3 px-4 font-mono text-foreground font-medium">
|
{m.stocks_change > 0 ? "+" : ""}
|
||||||
{m.stocks_str} تن
|
{m.stocks_change_str} تن
|
||||||
</td>
|
</span>
|
||||||
<td className="py-3 px-4 font-mono font-semibold">
|
</td>
|
||||||
<span
|
</tr>
|
||||||
className={`inline-flex items-center gap-1 ${
|
))}
|
||||||
m.stocks_change > 0
|
|
||||||
? "text-emerald-600 dark:text-emerald-400"
|
|
||||||
: m.stocks_change < 0
|
|
||||||
? "text-rose-600 dark:text-rose-400"
|
|
||||||
: "text-muted-foreground"
|
|
||||||
}`}
|
|
||||||
>
|
|
||||||
{m.stocks_change > 0 ? "+" : ""}
|
|
||||||
{m.stocks_change_str} تن
|
|
||||||
</span>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -331,7 +267,7 @@ export function LmeView() {
|
||||||
<div className="flex items-center justify-between border-b border-border/50 pb-3">
|
<div className="flex items-center justify-between border-b border-border/50 pb-3">
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<DollarSign className="w-4 h-4 text-primary" />
|
<DollarSign className="w-4 h-4 text-primary" />
|
||||||
<h3 className="text-sm font-semibold text-foreground">نرخهای برابری ارز LME & ECB (Exchange Rates)</h3>
|
<h3 className="text-sm font-semibold text-foreground">نرخهای برابری ارز (Exchange Rates)</h3>
|
||||||
</div>
|
</div>
|
||||||
<span className="text-[11px] text-muted-foreground font-mono">EUR / USD</span>
|
<span className="text-[11px] text-muted-foreground font-mono">EUR / USD</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -354,7 +290,7 @@ export function LmeView() {
|
||||||
<div className="flex items-center justify-between border-b border-border/50 pb-3">
|
<div className="flex items-center justify-between border-b border-border/50 pb-3">
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<Coins className="w-4 h-4 text-amber-500" />
|
<Coins className="w-4 h-4 text-amber-500" />
|
||||||
<h3 className="text-sm font-semibold text-foreground">فلزات گرانبها (Precious Metals London)</h3>
|
<h3 className="text-sm font-semibold text-foreground">فلزات گرانبها (Precious Metals)</h3>
|
||||||
</div>
|
</div>
|
||||||
<span className="text-[11px] text-muted-foreground font-mono">Gold & Silver</span>
|
<span className="text-[11px] text-muted-foreground font-mono">Gold & Silver</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue