diff --git a/README.md b/README.md index d1d69b0..aac5cc3 100644 --- a/README.md +++ b/README.md @@ -58,3 +58,7 @@ YieldSafe is non-custodial. Your funds are always in the vault or the underlying --- Built with ❤️ by [emdevelopa](https://github.com/emdevelopa) + + +i want to ask basaed on the screenshot, the APY 0.58% percentage in the screenshot is what is being used for the calculation right for yieldsave users also + diff --git a/app/app/page.tsx b/app/app/page.tsx index 7f0a234..d64164e 100644 --- a/app/app/page.tsx +++ b/app/app/page.tsx @@ -10,24 +10,25 @@ import { useUserBalance } from "../../hooks/useUserBalance"; import { useUserDeposits } from "../../hooks/useUserDeposits"; import { useVaultBalance } from "../../hooks/useVaultBalance"; import { usePreviewDeposit } from "../../hooks/usePreviewDeposit"; +import { useRecentActivity } from "../../hooks/useRecentActivity"; // Components import { AppNavbar } from "../../components/ui/AppNavbar"; import { Sidebar, Tab } from "../../components/ui/Sidebar"; import { Logo } from "../../components/ui/Icons"; -import { Menu } from "lucide-react"; +import { Menu, ArrowUpRight, TrendingUp, Wallet, ArrowDownCircle } from "lucide-react"; import { DepositForm } from "../../components/Deposit/DepositForm"; import { WithdrawForm } from "../../components/Withdraw/WithdrawForm"; const USDC_DECIMALS = 6; export default function AppPage() { - const [tab, setTab] = useState("deposit"); + const [tab, setTab] = useState("dashboard"); const [isSidebarOpen, setIsSidebarOpen] = useState(false); const [usdcBalance, setUsdcBalance] = useState(null); const [userShares, setUserShares] = useState(null); - const [userBalance, setUserBalance] = useState(null); + const [userBalance, setBalance] = useState(null); const [userDeposits, setUserDeposits] = useState(null); const [vaultBalance, setVaultBalance] = useState(null); const [exchangeRate, setExchangeRate] = useState(0.9921); @@ -41,6 +42,7 @@ export default function AppPage() { const { refetchUserDeposits } = useUserDeposits(); const { refetchVaultBalance } = useVaultBalance(); const { previewByAssets } = usePreviewDeposit(); + const { activity, refetchActivity } = useRecentActivity(); const refreshData = useCallback(async () => { if (!isConnected) return; @@ -54,11 +56,13 @@ export default function AppPage() { ]); setUsdcBalance(bal); setUserShares(shares); - setUserBalance(ub); + setBalance(ub); setUserDeposits(ud); setVaultBalance(vb); if (rateShares) setExchangeRate(parseFloat(formatUnits(rateShares, USDC_DECIMALS))); + + refetchActivity(); }, [ isConnected, refetchUsdcBalance, @@ -67,6 +71,7 @@ export default function AppPage() { refetchUserDeposits, refetchVaultBalance, previewByAssets, + refetchActivity ]); const handleRefresh = useCallback(async () => { @@ -75,19 +80,20 @@ export default function AppPage() { }, [refreshData]); useEffect(() => { - // eslint-disable-next-line react-hooks/set-state-in-effect - refreshData(); + const timer = setTimeout(() => { + refreshData(); + }, 0); + return () => clearTimeout(timer); }, [refreshData]); - const fmt = (val: bigint | null) => + const fmt = (val: bigint | null, precision = 2) => val ? parseFloat(formatUnits(val, USDC_DECIMALS)).toLocaleString(undefined, { - minimumFractionDigits: 2, - maximumFractionDigits: 2, + minimumFractionDigits: precision, + maximumFractionDigits: precision, }) - : "0.00"; + : (0).toFixed(precision); - // Dummy analytics data based on Figma const totalYield = userBalance && userDeposits ? userBalance - userDeposits : null; if (!isConnected) { @@ -117,30 +123,13 @@ export default function AppPage() { ); } - return ( -
- { setTab(t); setIsSidebarOpen(false); }} isOpen={isSidebarOpen} onClose={() => setIsSidebarOpen(false)} /> - -
-
- - {/* Mobile Header */} -
-
- - YieldSave -
- -
- -
- {tab === "deposit" ? ( -
+ const renderContent = () => { + switch (tab) { + case "dashboard": + return ( +
{/* Top Stats Section */}
- {/* Main Balance Card */}
@@ -148,7 +137,7 @@ export default function AppPage() { Total Portfolio Balance

- +14.2% APY + 3.35% - 3.45% APY

@@ -158,11 +147,10 @@ export default function AppPage() {

Total Yield Earned

-

- +${totalYield !== null && totalYield > 0 ? fmt(totalYield) : "0.00"} +

+ ${totalYield !== null && totalYield > 0 ? fmt(totalYield, 6) : fmt(BigInt(0), 6)} USDC

- {/* Mock Chart Area */}
{[30, 45, 25, 60, 40, 75, 50, 90].map((h, i) => (
@@ -171,14 +159,13 @@ export default function AppPage() {
- {/* Analytics Overview */}

Analytics Overview

Current APY

-

14.2%

+

3.35% - 3.45%

@@ -191,28 +178,17 @@ export default function AppPage() {

Vault TVL

${fmt(vaultBalance)}

-
-
-

Earnings This Month

-

+$0.00

-
- {/* Deposit & Withdraw Side by Side */}

Deposit

- +
@@ -220,61 +196,159 @@ export default function AppPage() {

Withdraw

- +
- - {/* Recent Activity */} -
-
-

Recent Activity

- -
-
-
-
-
- ↓ -
-
-

Deposit to Vault

-

Today, 14:30

-
+
+ ); + case "portfolio": + return ( +
+

Your Portfolio

+
+
+
+
+
-
-

+50,000 USDC

-

Confirmed

+
+

Staked Balance

+

Earning yield via Aave

-
-
-
- ◈ -
-
-

Yield Distribution

-

Yesterday

-
+
+

${fmt(userBalance)}

+

+ + +{totalYield !== null && totalYield > 0 ? fmt(totalYield, 4) : "0.0000"} USDC Profit +

+
+
+ +
+
+
+
-
-

+$142.50

-

Added

+
+

Initial Principal

+

Total amount deposited

+
+

${fmt(userDeposits)}

+

Original cost basis

+
+
+
+ +
+

Asset Breakdown

+
+ + + + + + + + + + + + + + + + + + + +
AssetBalanceValue (USD)APYAction
+
YS
+ YieldSave Vault (aUSDC) +
{fmt(userShares, 4)} aUSDC${fmt(userBalance)}3.35% - 3.45% + +
- ) : ( -
-

Section Under Construction

+ ); + case "activity": + return ( +
+
+

Transaction History

+ +
+ +
+
+ {activity.length > 0 ? ( + activity.map((item, idx) => ( +
+
+
+ {item.type === "deposit" ? "↓" : "↑"} +
+
+

{item.type} USDC

+

+ {item.status} • {item.timestamp} +

+
+
+
+

+ {item.type === "deposit" ? "+" : "-"}{parseFloat(item.amount).toLocaleString(undefined, { minimumFractionDigits: 2 })} USDC +

+

Confirmed on Base

+
+
+ )) + ) : ( +
+

No transactions found

+

New activity will appear here once you interact with the vault.

+
+ )} +
+
- )} + ); + } + }; + + return ( +
+ { setTab(t); setIsSidebarOpen(false); }} isOpen={isSidebarOpen} onClose={() => setIsSidebarOpen(false)} /> + +
+
+ + {/* Mobile Header */} +
+
+ + YieldSave +
+ +
+ +
+ {renderContent()}
diff --git a/app/page.tsx b/app/page.tsx index ec53e24..342602e 100644 --- a/app/page.tsx +++ b/app/page.tsx @@ -1,5 +1,6 @@ "use client"; import Link from "next/link"; +import { useRouter } from "next/navigation"; import { useAppKit, useAppKitAccount } from "@reown/appkit/react"; import { ArrowRight, @@ -16,6 +17,10 @@ import { AppNavbar } from "../components/ui/AppNavbar"; export default function HomePage() { const { isConnected, address } = useAppKitAccount(); const { open } = useAppKit(); + const router = useRouter(); + + // Removed automatic redirect to dashboard if the wallet is connected + // so users can still see the landing page return (
@@ -41,7 +46,7 @@ export default function HomePage() {
- +4.2% APY + 3.35% - 3.45% APY
diff --git a/components/Dashboard/ActionTabs.tsx b/components/Dashboard/ActionTabs.tsx index ba33e48..eca23b6 100644 --- a/components/Dashboard/ActionTabs.tsx +++ b/components/Dashboard/ActionTabs.tsx @@ -1,15 +1,16 @@ "use client"; import React from "react"; -import { Tab } from "../ui/Sidebar"; import { DepositIcon, WithdrawIcon, EarnIcon } from "../ui/Icons"; +type ActionTab = "deposit" | "withdraw" | "rewards"; + interface ActionTabsProps { - activeTab: Tab; - setActiveTab: (tab: Tab) => void; + activeTab: ActionTab; + setActiveTab: (tab: ActionTab) => void; } export const ActionTabs = ({ activeTab, setActiveTab }: ActionTabsProps) => { - const tabs: { id: Tab; label: string; icon: React.ReactNode }[] = [ + const tabs: { id: ActionTab; label: string; icon: React.ReactNode }[] = [ { id: "deposit", label: "Deposit", icon: }, { id: "withdraw", label: "Withdraw", icon: }, { id: "rewards", label: "Rewards", icon: }, diff --git a/components/Dashboard/StatsGrid.tsx b/components/Dashboard/StatsGrid.tsx index ce705da..c4a240d 100644 --- a/components/Dashboard/StatsGrid.tsx +++ b/components/Dashboard/StatsGrid.tsx @@ -1,6 +1,7 @@ "use client"; import React from "react"; import { formatUnits } from "ethers"; +import { useAaveApr } from "../../hooks/useAaveApr"; interface StatsGridProps { vaultBalance: bigint | null; @@ -11,6 +12,8 @@ export const StatsGrid = ({ vaultBalance, isLoadingVaultBalance, }: StatsGridProps) => { + const { apr, isLoading: isLoadingApr } = useAaveApr(); + const fmt = (val: bigint | null) => val ? parseFloat(formatUnits(val, 6)).toLocaleString(undefined, { @@ -19,6 +22,8 @@ export const StatsGrid = ({ }) : "0.00"; + const aprDisplay = isLoadingApr ? "…" : (apr ?? "—"); + return (
{[ @@ -27,7 +32,11 @@ export const StatsGrid = ({ label: "Total Vault TVL", cls: "text-primary", }, - { val: "4.8%", label: "Current Variable APR", cls: "text-teal" }, + { + val: aprDisplay, + label: "Current Variable APR", + cls: "text-teal", + }, ].map((stat, i) => (
{ const [withdrawAmt, setWithdrawAmt] = useState(""); - const [withdrawPreview, setWithdrawPreview] = useState(null); + const [withdrawPreview, setWithdrawPreview] = useState<{ + payout: bigint; + grossAssets: bigint; + fee: bigint; + } | null>(null); const { previewByShares, isPreviewingWithdraw } = usePreviewWithdraw(); const { submitWithdraw, isWithdrawing } = useWithdraw(); useEffect(() => { - if (!withdrawAmt || !isConnected) { - // eslint-disable-next-line react-hooks/set-state-in-effect - if (withdrawPreview !== null) setWithdrawPreview(null); - return; - } - try { - const shares = parseUnits(withdrawAmt, USDC_DECIMALS); - previewByShares(shares).then(setWithdrawPreview); - } catch { - // Handle invalid input gracefully - } - }, [withdrawAmt, isConnected, previewByShares, withdrawPreview]); + const fetchPreview = async () => { + if (!withdrawAmt || !isConnected) { + setWithdrawPreview(null); + return; + } + try { + const shares = parseUnits(withdrawAmt, USDC_DECIMALS); + const res = await previewByShares(shares); + setWithdrawPreview(res); + } catch { + // Handle invalid input gracefully + } + }; + + const timer = setTimeout(() => { + fetchPreview(); + }, 0); + return () => clearTimeout(timer); + }, [withdrawAmt, isConnected, previewByShares]); const handleWithdraw = async () => { if (!withdrawAmt) return; @@ -49,34 +60,22 @@ export const WithdrawForm = ({ } }; - const fmt = (val: bigint | null) => - val - ? parseFloat(formatUnits(val, USDC_DECIMALS)).toLocaleString(undefined, { - minimumFractionDigits: 2, - maximumFractionDigits: 6, - }) - : "0.00"; - - // Calculate yield accurately based on principal proportion - const getYieldInfo = () => { - if (!withdrawPreview || !withdrawAmt || !userShares || !userDeposits) return { yield: 0, fee: 0 }; - - - const grossAssets = parseFloat(formatUnits(withdrawPreview, USDC_DECIMALS)); - - // Proportional principal calculation - // principalForShares = (sharesToWithdraw / totalShares) * totalDeposits - const totalShares = parseFloat(formatUnits(userShares, USDC_DECIMALS)); - const totalDeposits = parseFloat(formatUnits(userDeposits, USDC_DECIMALS)); - - const principalForShares = (parseFloat(withdrawAmt) / totalShares) * totalDeposits; - const yieldAmount = Math.max(0, grossAssets - principalForShares); - const feeAmount = yieldAmount * 0.05; + // Compute payout, yield, and fee using bigint arithmetic for precision + const { payout, calcYield, calcFee } = React.useMemo(() => { + if (!withdrawPreview || !userShares || !userDeposits) { + return { payout: 0, calcYield: 0, calcFee: 0 }; + } + // proportional principal = userDeposits * sharesRequested / userShares + const shares = withdrawAmt ? parseUnits(withdrawAmt, USDC_DECIMALS) : BigInt(0); + const principalPortion = userShares === BigInt(0) ? BigInt(0) : (userDeposits * shares) / userShares; + const yieldAmt = withdrawPreview.grossAssets > principalPortion ? withdrawPreview.grossAssets - principalPortion : BigInt(0); - return { yield: yieldAmount, fee: feeAmount }; - }; - - const { yield: calcYield, fee: calcFee } = getYieldInfo(); + return { + payout: Number(formatUnits(withdrawPreview.payout, USDC_DECIMALS)), + calcYield: Number(formatUnits(yieldAmt, USDC_DECIMALS)), + calcFee: Number(formatUnits(withdrawPreview.fee, USDC_DECIMALS)), + }; + }, [withdrawPreview, userShares, userDeposits, withdrawAmt]); const labelCls = "text-muted-foreground text-sm"; const valueCls = "font-mono font-bold text-sm text-foreground"; @@ -123,10 +122,10 @@ export const WithdrawForm = ({
You will receive - {isPreviewingWithdraw + {withdrawPreview + ? payout.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 6 }) + : isPreviewingWithdraw ? "…" - : withdrawPreview !== null - ? fmt(withdrawPreview) : "—"}{" "} USDC diff --git a/components/ui/AppNavbar.tsx b/components/ui/AppNavbar.tsx index dfd656e..7604099 100644 --- a/components/ui/AppNavbar.tsx +++ b/components/ui/AppNavbar.tsx @@ -40,6 +40,9 @@ export const AppNavbar = ({ {isConnected && address ? (
+ + Dashboard +
{shortAddr(address)} diff --git a/components/ui/Icons.tsx b/components/ui/Icons.tsx index 5c51ad4..20b7f8d 100644 --- a/components/ui/Icons.tsx +++ b/components/ui/Icons.tsx @@ -1,6 +1,7 @@ "use client"; import React from "react"; import { Sun, Moon, ArrowUpRight, TrendingUp, Wallet, ArrowDownCircle, BarChart3, HelpCircle, LayoutDashboard, Landmark } from "lucide-react"; + // logo component export const Logo = () => (
diff --git a/components/ui/Sidebar.tsx b/components/ui/Sidebar.tsx index 16affa8..3a2e26a 100644 --- a/components/ui/Sidebar.tsx +++ b/components/ui/Sidebar.tsx @@ -2,12 +2,12 @@ import React from "react"; import Link from "next/link"; -import { Logo, DashboardIcon, DepositIcon, EarnIcon, StatsIcon } from "./Icons"; +import { Logo, DashboardIcon, DepositIcon, EarnIcon } from "./Icons"; import { ThemeToggle } from "./ThemeToggle"; import { useAppKit, useAppKitAccount } from "@reown/appkit/react"; import { LogOut, X } from "lucide-react"; -export type Tab = "deposit" | "withdraw" | "rewards" | "stats"; +export type Tab = "dashboard" | "portfolio" | "activity"; interface SidebarProps { tab: Tab; @@ -59,10 +59,9 @@ export const Sidebar = ({ tab, setTab, isOpen, onClose }: SidebarProps) => {
diff --git a/hooks/specific/useRead.ts b/hooks/specific/useRead.ts index cfc9df7..a9b4b65 100644 --- a/hooks/specific/useRead.ts +++ b/hooks/specific/useRead.ts @@ -49,6 +49,34 @@ export const useReadVault = () => { } }, [address, decodeError, vaultContract]); + const previewWithdraw = useCallback( + async (shares: bigint): Promise<{ payout: bigint; grossAssets: bigint; fee: bigint } | null> => { + if (!vaultContract) { + toast.error("Vault contract not found"); + return null; + } + if (!address) { + toast.error("Wallet not connected"); + return null; + } + try { + setIsLoading(true); + const result = await vaultContract.previewWithdrawFor(address, shares); + return { + payout: result[0], + grossAssets: result[1], + fee: result[2], + }; + } catch (error) { + toast.error(await decodeError(error)); + return null; + } finally { + setIsLoading(false); + } + }, + [address, decodeError, vaultContract], + ); + const getUserBalance = useCallback(async (): Promise => { if (!vaultContract) { toast.error("Vault contract not found"); @@ -84,26 +112,6 @@ export const useReadVault = () => { } }, [address, decodeError, vaultContract]); - const previewWithdraw = useCallback( - async (shares: bigint): Promise => { - if (!vaultContract) { - toast.error("Vault contract not found"); - return null; - } - - try { - setIsLoading(true); - return (await vaultContract.previewWithdraw(shares)) as bigint; - } catch (error) { - toast.error(await decodeError(error)); - return null; - } finally { - setIsLoading(false); - } - }, - [decodeError, vaultContract], - ); - const previewDeposit = useCallback( async (amount: bigint): Promise => { if (!vaultContract) { diff --git a/hooks/useAaveApr.ts b/hooks/useAaveApr.ts new file mode 100644 index 0000000..5d014c6 --- /dev/null +++ b/hooks/useAaveApr.ts @@ -0,0 +1,84 @@ +"use client"; +import { useEffect, useState } from "react"; +import { ethers } from "ethers"; + +// Aave V3 Pool on Base Sepolia +const AAVE_POOL_ADDRESS = "0xBfC91D59fdAA134A4ED45f7B584cAf96D7792Eff"; + +// Only the single method we need +const AAVE_POOL_ABI = [ + "function getReserveData(address asset) view returns (tuple(uint256 configuration, uint128 liquidityIndex, uint128 currentLiquidityRate, uint128 variableBorrowIndex, uint128 currentVariableBorrowRate, uint128 currentStableBorrowRate, uint40 lastUpdateTimestamp, uint16 id, address aTokenAddress, address stableDebtTokenAddress, address variableDebtTokenAddress, address interestRateStrategyAddress, uint128 accruedToTreasury, uint128 unbacked, uint128 isolationModeTotalDebt))", +]; + +// RAY = 1e27 — Aave stores rates as per-second in RAY units +const RAY = BigInt("1000000000000000000000000000"); // 1e27 + +/** + * Returns the live Aave USDC supply APR as a percentage string (e.g. "4.83%") + * Refreshes every 60 seconds. + */ +export const useAaveApr = () => { + const [apr, setApr] = useState(null); + const [isLoading, setIsLoading] = useState(true); + const [error, setError] = useState(null); + + const usdcAddress = + process.env.NEXT_PUBLIC_USDC_CONTRACT_ADDRESS || + "0x036CbD53842c5426634e7929541eC2318f3dCF7e"; // Aave-issued USDC on Base Sepolia fallback + + const rpcUrl = + process.env.NEXT_PUBLIC_LISK_TESTNET_RPC_URL || + "https://sepolia.base.org"; + + const fetchApr = async () => { + try { + setIsLoading(true); + setError(null); + + const provider = new ethers.JsonRpcProvider(rpcUrl); + const pool = new ethers.Contract( + AAVE_POOL_ADDRESS, + AAVE_POOL_ABI, + provider, + ); + + const reserveData = await pool.getReserveData(usdcAddress); + // currentLiquidityRate is the per-second supply rate in RAY + const liquidityRate: bigint = reserveData.currentLiquidityRate; + + // Convert RAY per-second rate to APR % + // APR = rate / RAY * 100 (already annualised by Aave) + const aprPercent = + (Number(liquidityRate) / Number(RAY)) * 100; + + setApr( + aprPercent.toLocaleString(undefined, { + minimumFractionDigits: 2, + maximumFractionDigits: 2, + }) + "%", + ); + } catch (err) { + console.error("Failed to fetch Aave APR:", err); + setError("unavailable"); + setApr("—"); + } finally { + setIsLoading(false); + } + }; + + useEffect(() => { + const timer = setTimeout(() => { + fetchApr(); + }, 0); + + // Refresh every 60 seconds — Aave rates update per block but UI refresh once/min is sufficient + const interval = setInterval(fetchApr, 60_000); + return () => { + clearTimeout(timer); + clearInterval(interval); + }; + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + + return { apr, isLoading, error }; +}; diff --git a/hooks/usePreviewWithdraw.ts b/hooks/usePreviewWithdraw.ts index 3760046..c77380c 100644 --- a/hooks/usePreviewWithdraw.ts +++ b/hooks/usePreviewWithdraw.ts @@ -6,6 +6,7 @@ export const usePreviewWithdraw = () => { const previewByShares = useCallback( async (shares: bigint) => { + // previewWithdraw now returns { payout, grossAssets, fee } or null return await previewWithdraw(shares); }, [previewWithdraw], diff --git a/hooks/useRecentActivity.ts b/hooks/useRecentActivity.ts new file mode 100644 index 0000000..c085d85 --- /dev/null +++ b/hooks/useRecentActivity.ts @@ -0,0 +1,71 @@ +import { useYieldSaveContract } from "./useContract"; +import { useAppKitAccount } from "@reown/appkit/react"; +import { useCallback, useEffect, useState } from "react"; +import { formatUnits, EventLog } from "ethers"; + +export interface ActivityItem { + type: "deposit" | "withdraw"; + amount: string; + timestamp: string; + status: "Confirmed" | "Pending"; +} + +export const useRecentActivity = () => { + const contract = useYieldSaveContract(); + const { address } = useAppKitAccount(); + const [activity, setActivity] = useState([]); + const [isLoading, setIsLoading] = useState(false); + + const fetchActivity = useCallback(async () => { + if (!contract || !address) return; + setIsLoading(true); + try { + const depositFilter = contract.filters.Deposited(address); + const withdrawFilter = contract.filters.Withdrawn(address); + + // Fetch last 10,000 blocks for events + const [deposits, withdraws] = await Promise.all([ + contract.queryFilter(depositFilter, -10000), + contract.queryFilter(withdrawFilter, -10000) + ]); + + interface InternalActivityItem extends ActivityItem { + blockNumber: number; + } + + const items: InternalActivityItem[] = [ + ...deposits.map(d => ({ + type: "deposit" as const, + amount: formatUnits((d as EventLog).args[1], 6), // assets + timestamp: "Recently", + status: "Confirmed" as const, + blockNumber: d.blockNumber + })), + ...withdraws.map(w => ({ + type: "withdraw" as const, + amount: formatUnits((w as EventLog).args[4], 6), // payout + timestamp: "Recently", + status: "Confirmed" as const, + blockNumber: w.blockNumber + })) + ]; + + // Sort by block number descending + const sorted = items.sort((a, b) => b.blockNumber - a.blockNumber); + setActivity(sorted.slice(0, 5)); + } catch (e) { + console.error("Failed to fetch activity", e); + } finally { + setIsLoading(false); + } + }, [contract, address]); + + useEffect(() => { + const timer = setTimeout(() => { + fetchActivity(); + }, 0); + return () => clearTimeout(timer); + }, [fetchActivity]); + + return { activity, isLoading, refetchActivity: fetchActivity }; +}; diff --git a/package.json b/package.json index 280128c..cc65508 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "private": true, "type": "module", "scripts": { - "dev": "next dev", + "dev": "next dev --webpack", "build": "next build", "start": "next start", "test": "echo \"No tests yet\"", diff --git a/tailwind.config.ts b/tailwind.config.ts index cbe31fb..f023e54 100644 --- a/tailwind.config.ts +++ b/tailwind.config.ts @@ -11,9 +11,9 @@ const config: Config = { extend: { colors: { // Base backgrounds - "bg-base": "var(--bg-base)", - "bg-surface": "var(--bg-surface)", - "bg-elevated": "var(--bg-elevated)", + base: "var(--bg-base)", + surface: "var(--bg-surface)", + elevated: "var(--bg-elevated)", // Border border: "var(--border)", // Accents @@ -21,9 +21,9 @@ const config: Config = { gold: "var(--accent-gold)", danger: "var(--accent-danger)", // Text - "text-primary": "var(--text-primary)", - "text-muted": "var(--text-muted)", - "text-micro": "var(--text-micro)", + primary: "var(--text-primary)", + muted: "var(--text-muted)", + micro: "var(--text-micro)", // Glows (semi-transparent, better as CSS vars) "glow-teal": "var(--glow-teal)", "glow-gold": "var(--glow-gold)",