Hallmark Cobalt: unified light palette + Ubuntu fonts
Layout: Ubuntu + Ubuntu Mono (next/font/google), light mode CSS: Hallmark Cobalt palette — cool paper bg, hairlines, electric cobalt primary, slate secondary Cards: white bg, hairline borders, muted type badges Header/tabs: Ubuntu Mono labels, Ubuntu tab buttons Removed: dark mode, Inter/JetBrains Mono, purple gradients
This commit is contained in:
@@ -1,7 +1,5 @@
|
||||
@import "tailwindcss";
|
||||
|
||||
@custom-variant dark (&:is(.dark *));
|
||||
|
||||
@theme inline {
|
||||
--color-background: var(--background);
|
||||
--color-foreground: var(--foreground);
|
||||
@@ -30,49 +28,61 @@
|
||||
--radius-md: calc(var(--radius) - 2px);
|
||||
--radius-lg: var(--radius);
|
||||
--radius-xl: calc(var(--radius) + 4px);
|
||||
--font-sans: var(--font-inter), ui-sans-serif, system-ui, sans-serif;
|
||||
--font-mono: var(--font-jetbrains-mono), ui-monospace, monospace;
|
||||
--font-sans: var(--font-ubuntu), ui-sans-serif, system-ui, sans-serif;
|
||||
--font-mono: var(--font-ubuntu-mono), ui-monospace, monospace;
|
||||
}
|
||||
|
||||
/* ═══════════ Hallmark Cobalt — Light Palette ═══════════ */
|
||||
:root {
|
||||
--radius: 0.5rem;
|
||||
}
|
||||
|
||||
.dark {
|
||||
--background: oklch(0.0588 0.0162 269.6475);
|
||||
--foreground: oklch(0.985 0 0);
|
||||
--card: oklch(0.1059 0.0201 269.5991);
|
||||
--card-foreground: oklch(0.985 0 0);
|
||||
--popover: oklch(0.1059 0.0201 269.5991);
|
||||
--popover-foreground: oklch(0.985 0 0);
|
||||
--primary: oklch(0.985 0 0);
|
||||
--primary-foreground: oklch(0.0588 0.0162 269.6475);
|
||||
--secondary: oklch(0.1776 0 0);
|
||||
--secondary-foreground: oklch(0.985 0 0);
|
||||
--muted: oklch(0.1776 0 0);
|
||||
--muted-foreground: oklch(0.7559 0.0125 239.9659);
|
||||
--accent: oklch(0.1776 0 0);
|
||||
--accent-foreground: oklch(0.985 0 0);
|
||||
--destructive: oklch(0.602 0.2378 25.3312);
|
||||
--border: oklch(1 0 0 / 0.1);
|
||||
--input: oklch(1 0 0 / 0.15);
|
||||
--ring: oklch(0.7559 0.0125 239.9659);
|
||||
--chart-1: oklch(0.646 0.222 41.116);
|
||||
--chart-2: oklch(0.6 0.118 184.704);
|
||||
--chart-3: oklch(0.398 0.07 227.392);
|
||||
--chart-4: oklch(0.828 0.189 84.429);
|
||||
--chart-5: oklch(0.769 0.188 70.08);
|
||||
}
|
||||
|
||||
* {
|
||||
border-color: var(--border);
|
||||
outline-color: var(--ring);
|
||||
--radius: 0.25rem;
|
||||
|
||||
/* Engineered cool paper — never pure white */
|
||||
--background: #f8f9fb;
|
||||
--foreground: #1a1c23;
|
||||
|
||||
/* Cards: crisp white with hairline border */
|
||||
--card: #ffffff;
|
||||
--card-foreground: #1a1c23;
|
||||
|
||||
/* Popovers / overlays */
|
||||
--popover: #ffffff;
|
||||
--popover-foreground: #1a1c23;
|
||||
|
||||
/* Primary: electric cobalt signal */
|
||||
--primary: #0ea5e9;
|
||||
--primary-foreground: #ffffff;
|
||||
|
||||
/* Secondary: slate gray */
|
||||
--secondary: #e8eaf0;
|
||||
--secondary-foreground: #4a4f5c;
|
||||
|
||||
/* Muted: subtle backgrounds */
|
||||
--muted: #f1f3f7;
|
||||
--muted-foreground: #6e7381;
|
||||
|
||||
/* Accent: navy blue */
|
||||
--accent: #1e3a5f;
|
||||
--accent-foreground: #ffffff;
|
||||
|
||||
/* Destructive: coral red */
|
||||
--destructive: #e74c3c;
|
||||
|
||||
/* Borders: engineered hairlines */
|
||||
--border: #e0e4ec;
|
||||
--input: #e0e4ec;
|
||||
--ring: #0ea5e9;
|
||||
|
||||
/* Charts — Hallmark palette */
|
||||
--chart-1: #0ea5e9;
|
||||
--chart-2: #6366f1;
|
||||
--chart-3: #f59e0b;
|
||||
--chart-4: #10b981;
|
||||
--chart-5: #ef4444;
|
||||
}
|
||||
|
||||
/* Body defaults */
|
||||
body {
|
||||
font-family: var(--font-ubuntu), ui-sans-serif, system-ui, sans-serif;
|
||||
background: var(--background);
|
||||
color: var(--foreground);
|
||||
font-family: var(--font-sans);
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
@@ -1,26 +1,28 @@
|
||||
import type { Metadata } from "next";
|
||||
import { Inter, JetBrains_Mono } from "next/font/google";
|
||||
import { Ubuntu, Ubuntu_Mono } from "next/font/google";
|
||||
import "./globals.css";
|
||||
|
||||
const inter = Inter({
|
||||
const ubuntu = Ubuntu({
|
||||
subsets: ["latin"],
|
||||
variable: "--font-inter",
|
||||
weight: ["300", "400", "500", "700"],
|
||||
variable: "--font-ubuntu",
|
||||
});
|
||||
|
||||
const jetbrainsMono = JetBrains_Mono({
|
||||
const ubuntuMono = Ubuntu_Mono({
|
||||
subsets: ["latin"],
|
||||
variable: "--font-jetbrains-mono",
|
||||
weight: ["400", "700"],
|
||||
variable: "--font-ubuntu-mono",
|
||||
});
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "FTDT Quant Lab",
|
||||
description: "Professional quantitative trading dashboard — live testnet, paper mainnet, historical backtests",
|
||||
title: "Quant Dashboard",
|
||||
description: "Live testnet, paper mainnet, historical backtests",
|
||||
};
|
||||
|
||||
export default function RootLayout({ children }: { children: React.ReactNode }) {
|
||||
return (
|
||||
<html lang="en" className="dark">
|
||||
<body className={`${inter.variable} ${jetbrainsMono.variable} antialiased`}>
|
||||
<html lang="en">
|
||||
<body className={`${ubuntu.variable} ${ubuntuMono.variable} antialiased`}>
|
||||
{children}
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -307,14 +307,14 @@ export default function Dashboard() {
|
||||
<header className="sticky top-0 z-50 border-b border-[#e0e4ec] bg-[#f8f9fb]/95 backdrop-blur-sm">
|
||||
<div className="flex items-center justify-between px-6 h-12 max-w-[1440px] mx-auto">
|
||||
<div className="flex items-center gap-5">
|
||||
<span className="text-[11px] font-medium tracking-[0.04em] text-[#1a1c23]" style={{fontFamily:"JetBrains Mono, monospace"}}>
|
||||
<span className="text-[11px] font-medium tracking-[0.04em] text-[#1a1c23]" style={{fontFamily:"'Ubuntu Mono', monospace"}}>
|
||||
{tab === "live" ? "Live Testnet" : tab === "paper" ? "Paper Mainnet" : "Historical"}
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex items-center gap-4">
|
||||
<span className="flex items-center gap-1.5">
|
||||
<span className={`w-1.5 h-1.5 rounded-full ${liveConn ? "bg-[#0ea5e9]" : "bg-[#e5e7eb]"}`} />
|
||||
<span className="text-[9px] text-[#6e7381] font-medium tracking-[0.03em]" style={{fontFamily:"JetBrains Mono, monospace"}}>
|
||||
<span className="text-[9px] text-[#6e7381] font-medium tracking-[0.03em]" style={{fontFamily:"'Ubuntu Mono', monospace"}}>
|
||||
{liveConn ? "CONNECTED" : "OFFLINE"} · {liveData?.status ?? "···"}
|
||||
</span>
|
||||
</span>
|
||||
@@ -329,7 +329,7 @@ export default function Dashboard() {
|
||||
<button
|
||||
key={t}
|
||||
onClick={() => setTab(t)}
|
||||
style={{fontFamily:"Inter, sans-serif"}}
|
||||
style={{fontFamily:"'Ubuntu', sans-serif"}}
|
||||
className={`relative px-4 py-2.5 text-xs font-medium tracking-[0.02em] transition-colors cursor-pointer
|
||||
${tab === t
|
||||
? "text-[#1a1c23] after:absolute after:bottom-0 after:left-0 after:right-0 after:h-[2px] after:bg-[#0ea5e9]"
|
||||
|
||||
@@ -25,52 +25,51 @@ export function StrategyCard({ name, strategy, tab, onClick, badge, stats, pnlPc
|
||||
const pnlPctVal = strategy.pnl_pct ?? 0;
|
||||
// Type colors
|
||||
const typeColors: Record<string, string> = {
|
||||
reversal: "bg-blue-500/20 text-blue-400",
|
||||
momentum: "bg-amber-500/20 text-amber-400",
|
||||
stat_arb: "bg-purple-500/20 text-purple-400",
|
||||
carry: "bg-cyan-500/20 text-cyan-400",
|
||||
market_making: "bg-emerald-500/20 text-emerald-400",
|
||||
reversal: "bg-blue-100 text-blue-700",
|
||||
momentum: "bg-amber-100 text-amber-700",
|
||||
stat_arb: "bg-purple-100 text-purple-700",
|
||||
carry: "bg-cyan-100 text-cyan-700",
|
||||
market_making: "bg-emerald-100 text-emerald-700",
|
||||
};
|
||||
const typeColor = typeColors[strategy.type] || "bg-gray-500/20 text-gray-400";
|
||||
// Asset shorthand
|
||||
const typeColor = typeColors[strategy.type] || "bg-gray-100 text-gray-600";
|
||||
const assetShort = strategy.instrument?.split("-")[0] || "";
|
||||
|
||||
return (
|
||||
<Card
|
||||
className="p-4 cursor-pointer hover:border-primary/50 hover:shadow-md transition-all duration-200 hover:-translate-y-0.5 border-border"
|
||||
className="p-4 cursor-pointer hover:border-[#0ea5e9]/30 hover:shadow-sm transition-all duration-200 border-[#e0e4ec] bg-white"
|
||||
onClick={onClick}
|
||||
>
|
||||
<div className="flex items-start justify-between mb-2">
|
||||
<div>
|
||||
<p className="text-xs font-semibold leading-tight">{name}</p>
|
||||
<p className="text-xs font-medium leading-tight text-[#1a1c23]">{name}</p>
|
||||
<div className="flex gap-1 mt-0.5">
|
||||
<span className={`text-[8px] px-1.5 py-px rounded font-mono ${typeColor}`}>{strategy.type}</span>
|
||||
<span className="text-[9px] text-muted-foreground">{assetShort}</span>
|
||||
<span className={`text-[8px] px-1.5 py-px rounded font-medium font-mono ${typeColor}`}>{strategy.type}</span>
|
||||
<span className="text-[9px] text-[#6e7381]">{assetShort}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex gap-1">
|
||||
<Badge variant={strategy.status === "running" ? "default" : "secondary"} className="text-[8px] h-4 px-1.5">
|
||||
{strategy.status?.toUpperCase()}
|
||||
</Badge>
|
||||
<Badge variant="outline" className="text-[8px] h-4 px-1.5 border-border">
|
||||
<Badge variant="outline" className="text-[8px] h-4 px-1.5 border-[#e0e4ec]">
|
||||
{strategy.fee_model?.toUpperCase()}
|
||||
</Badge>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className={`text-xl font-mono font-bold mb-2 flex items-center gap-1 ${isUp ? "text-green-500" : "text-red-500"}`}>
|
||||
<div className={`text-xl font-mono font-bold mb-2 flex items-center gap-1 ${isUp ? "text-[#10b981]" : "text-[#ef4444]"}`}>
|
||||
{isUp ? <TrendingUp className="w-4 h-4" /> : <TrendingDown className="w-4 h-4" />}
|
||||
${equity.toFixed(2)}
|
||||
</div>
|
||||
|
||||
<div className="flex gap-3 text-[9px] text-muted-foreground flex-wrap">
|
||||
<span>PnL: <b className={pnlPctVal >= 0 ? "text-green-500" : "text-red-500"}>{pnl >= 0 ? "+" : ""}{pnl.toFixed(2)} ({pnlPctVal >= 0 ? "+" : ""}{pnlPctVal.toFixed(2)}%)</b></span>
|
||||
<div className="flex gap-3 text-[9px] text-[#6e7381] flex-wrap">
|
||||
<span>PnL: <b className={pnlPctVal >= 0 ? "text-[#10b981]" : "text-[#ef4444]"}>{pnl >= 0 ? "+" : ""}{pnl.toFixed(2)} ({pnlPctVal >= 0 ? "+" : ""}{pnlPctVal.toFixed(2)}%)</b></span>
|
||||
<span>Trades: <b>{strategy.trades_today ?? 0}</b></span>
|
||||
<span>Win: <b>{Math.round((strategy.win_rate ?? 0) * 100)}%</b></span>
|
||||
<span>Pos: <b>{(strategy.position ?? 0).toFixed(4)}</b></span>
|
||||
</div>
|
||||
|
||||
<div className="mt-2 pt-2 border-t border-border/50 text-[9px] text-muted-foreground leading-relaxed">
|
||||
<div className="mt-2 pt-2 border-t border-[#e0e4ec]/50 text-[9px] text-[#6e7381] leading-relaxed">
|
||||
<b>Alloc:</b> ${strategy.allocation} · <b>Max pos:</b> {strategy.max_position ?? "—"} · <b>Stop:</b> {strategy.stop_loss ?? "—"}
|
||||
</div>
|
||||
</Card>
|
||||
|
||||
Reference in New Issue
Block a user