diff --git a/frontend/src/hooks/useTheme.ts b/frontend/src/hooks/useTheme.ts index de6886fb..30ae073b 100644 --- a/frontend/src/hooks/useTheme.ts +++ b/frontend/src/hooks/useTheme.ts @@ -1,4 +1,4 @@ -import { createContext, use } from 'react'; +import { useThemeStore } from '../stores/themeStore'; export type Theme = 'light' | 'dark'; @@ -7,10 +7,16 @@ export interface ThemeContextType { toggleTheme: () => void; } -export const ThemeContext = createContext(undefined); - +/** + * useTheme hook — reads theme state from the zustand store. + * + * Components that call this hook will re-render when the theme changes. + * Theme persistence is handled by the zustand persist middleware. + */ export const useTheme = () => { - const context = use(ThemeContext); - if (!context) throw new Error('useTheme must be used within ThemeProvider'); - return context; -}; + const theme = useThemeStore((s) => s.theme as Theme); + const toggleTheme = useThemeStore((s) => s.toggleTheme); + const setTheme = useThemeStore((s) => s.setTheme); + + return { theme, toggleTheme, setTheme }; +}; \ No newline at end of file diff --git a/frontend/src/index.css b/frontend/src/index.css index d4d498c9..10e0a9f6 100644 --- a/frontend/src/index.css +++ b/frontend/src/index.css @@ -21,6 +21,41 @@ --accent2: #7c6ff7; --danger: #ff7b72; --success: #3fb950; + --warning: #ffd500; + --accent-alpha-06: rgba(74, 240, 184, 0.06); + --accent-alpha-08: rgba(74, 240, 184, 0.08); + --accent-alpha-10: rgba(74, 240, 184, 0.1); + --accent-alpha-12: rgba(74, 240, 184, 0.12); + --accent-alpha-15: rgba(74, 240, 184, 0.15); + --accent-alpha-20: rgba(74, 240, 184, 0.2); + --accent-alpha-30: rgba(74, 240, 184, 0.3); + --accent2-alpha-06: rgba(124, 111, 247, 0.06); + --accent2-alpha-10: rgba(124, 111, 247, 0.1); + --accent2-alpha-12: rgba(124, 111, 247, 0.12); + --accent2-alpha-15: rgba(124, 111, 247, 0.15); + --accent2-alpha-20: rgba(124, 111, 247, 0.2); + --accent2-alpha-25: rgba(124, 111, 247, 0.25); + --accent2-hover: #6657e8; + --danger-alpha-08: rgba(255, 123, 114, 0.08); + --danger-alpha-10: rgba(255, 123, 114, 0.1); + --danger-alpha-12: rgba(255, 123, 114, 0.12); + --danger-alpha-15: rgba(255, 123, 114, 0.15); + --danger-alpha-20: rgba(255, 123, 114, 0.2); + --danger-hover: #ff5b53; + --success-alpha-10: rgba(63, 185, 80, 0.1); + --success-alpha-12: rgba(63, 185, 80, 0.12); + --success-alpha-20: rgba(63, 185, 80, 0.2); + --warning-alpha-10: rgba(255, 213, 0, 0.1); + --warning-alpha-12: rgba(255, 213, 0, 0.12); + --warning-alpha-20: rgba(255, 213, 0, 0.2); + --accent-glow: 0 0 20px rgba(74, 240, 184, 0.3); + --glass-bg: rgba(255, 255, 255, 0.03); + --input-bg: rgba(255, 255, 255, 0.05); + --input-bg-hover: rgba(255, 255, 255, 0.08); + --row-hover: rgba(255, 255, 255, 0.02); + --scrim: rgba(0, 0, 0, 0.2); + --shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.35); + --shadow-md: 0 4px 12px rgba(0, 0, 0, 0.4); --header-h: 64px; --font-head: 'Syne', sans-serif; --font-body: 'Inter', sans-serif; @@ -40,6 +75,41 @@ --accent2: #6c5ce7; --danger: #d1242f; --success: #1a7f37; + --warning: #daa520; + --accent-alpha-06: rgba(13, 150, 104, 0.06); + --accent-alpha-08: rgba(13, 150, 104, 0.08); + --accent-alpha-10: rgba(13, 150, 104, 0.1); + --accent-alpha-12: rgba(13, 150, 104, 0.12); + --accent-alpha-15: rgba(13, 150, 104, 0.15); + --accent-alpha-20: rgba(13, 150, 104, 0.2); + --accent-alpha-30: rgba(13, 150, 104, 0.3); + --accent2-alpha-06: rgba(108, 92, 231, 0.06); + --accent2-alpha-10: rgba(108, 92, 231, 0.1); + --accent2-alpha-12: rgba(108, 92, 231, 0.12); + --accent2-alpha-15: rgba(108, 92, 231, 0.15); + --accent2-alpha-20: rgba(108, 92, 231, 0.2); + --accent2-alpha-25: rgba(108, 92, 231, 0.25); + --accent2-hover: #5a4bd6; + --danger-alpha-08: rgba(209, 36, 47, 0.08); + --danger-alpha-10: rgba(209, 36, 47, 0.1); + --danger-alpha-12: rgba(209, 36, 47, 0.12); + --danger-alpha-15: rgba(209, 36, 47, 0.15); + --danger-alpha-20: rgba(209, 36, 47, 0.2); + --danger-hover: #b71b26; + --success-alpha-10: rgba(26, 127, 55, 0.1); + --success-alpha-12: rgba(26, 127, 55, 0.12); + --success-alpha-20: rgba(26, 127, 55, 0.2); + --warning-alpha-10: rgba(218, 165, 32, 0.1); + --warning-alpha-12: rgba(218, 165, 32, 0.12); + --warning-alpha-20: rgba(218, 165, 32, 0.2); + --accent-glow: 0 0 20px rgba(13, 150, 104, 0.3); + --glass-bg: rgba(255, 255, 255, 0.7); + --input-bg: rgba(0, 0, 0, 0.03); + --input-bg-hover: rgba(0, 0, 0, 0.05); + --row-hover: rgba(0, 0, 0, 0.02); + --scrim: rgba(0, 0, 0, 0.4); + --shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.06); + --shadow-md: 0 4px 12px rgba(0, 0, 0, 0.08); --header-h: 64px; --font-head: 'Syne', sans-serif; --font-body: 'Inter', sans-serif; diff --git a/frontend/src/pages/CashFlowForecast.tsx b/frontend/src/pages/CashFlowForecast.tsx index f83a9209..3b087f0f 100644 --- a/frontend/src/pages/CashFlowForecast.tsx +++ b/frontend/src/pages/CashFlowForecast.tsx @@ -132,7 +132,7 @@ export default function CashFlowForecast() { const { direction } = forecast.trendAnalysis; if (direction === 'increasing') return ; if (direction === 'decreasing') return ; - return ; + return ; }; const getAlertIcon = (severity: BudgetAlert['severity']) => { @@ -146,7 +146,7 @@ export default function CashFlowForecast() {

Cash Flow Forecast

-

+

Analyze historical payroll data and project future cash flow requirements

@@ -156,14 +156,14 @@ export default function CashFlowForecast() { placeholder="Distribution Account" value={params.distributionAccount} onChange={(e) => setParams({ ...params, distributionAccount: e.target.value })} - className="px-4 py-2 bg-zinc-900 border border-zinc-800 rounded-lg text-white text-sm focus:outline-none focus:ring-2 focus:ring-blue-500 min-h-[44px]" + className="px-4 py-2 bg-zinc-900 border border-[var(--border-hi)] rounded-lg text-white text-sm focus:outline-none focus:ring-2 focus:ring-blue-500 min-h-[44px]" /> setParams({ ...params, assetIssuer: e.target.value })} - className="px-4 py-2 bg-zinc-900 border border-zinc-800 rounded-lg text-white text-sm focus:outline-none focus:ring-2 focus:ring-blue-500 min-h-[44px]" + className="px-4 py-2 bg-zinc-900 border border-[var(--border-hi)] rounded-lg text-white text-sm focus:outline-none focus:ring-2 focus:ring-blue-500 min-h-[44px]" /> setParams({ ...params, forecastDays: parseInt(e.target.value, 10) || 90 }) } - className="px-4 py-2 bg-zinc-900 border border-zinc-800 rounded-lg text-white text-sm focus:outline-none focus:ring-2 focus:ring-blue-500 w-24 min-h-[44px]" + className="px-4 py-2 bg-zinc-900 border border-[var(--border-hi)] rounded-lg text-white text-sm focus:outline-none focus:ring-2 focus:ring-blue-500 w-24 min-h-[44px]" /> ) : ( - + {address.slice(0, 6)}...{address.slice(-4)} )}
-
+
-
-
-
@@ -294,13 +294,13 @@ export default function CrossAssetPayment() {
{/* Quote Panel */} {(isLoadingPaths || paths.length > 0) && ( -
+

Available Conversion Paths

{isLoadingPaths ? ( -
+
Fetching conversion paths...
@@ -311,16 +311,16 @@ export default function CrossAssetPayment() { key={path.id} type="button" onClick={() => setSelectedPathId(path.id)} - className={`w-full text-left rounded-xl border px-4 py-3 transition ${selectedPathId === path.id ? 'border-emerald-500/60 bg-emerald-500/10' : 'border-zinc-800 hover:border-zinc-700'}`} + className={`w-full text-left rounded-xl border px-4 py-3 transition ${selectedPathId === path.id ? 'border-emerald-500/60 bg-emerald-500/10' : 'border-[var(--border-hi)] hover:border-zinc-700'}`} >
{path.hops.join(' -> ')} - {path.rate.toFixed(4)} rate + {path.rate.toFixed(4)} rate
-
+
Fee: {path.fee.toFixed(4)} {assetOut} | Slippage:{' '} {path.slippage.toFixed(2)}%
@@ -332,22 +332,22 @@ export default function CrossAssetPayment() { )} {selectedPath && ( -
+

Settlement Preview

-
+
Expected Delivery {selectedPath.estimatedDestinationAmount.toLocaleString()} {assetOut}
-
+
Fee {selectedPath.fee.toFixed(4)} {assetOut}
-
+
Slippage {selectedPath.slippage.toFixed(2)}%
@@ -356,7 +356,7 @@ export default function CrossAssetPayment() { )} {status !== 'idle' && ( -
+

Authentication

-

Wallet connected and signer ready

+

Wallet connected and signer ready

@@ -391,7 +391,7 @@ export default function CrossAssetPayment() {

Initiation

-

Contract call simulated and submitted

+

Contract call simulated and submitted

@@ -403,14 +403,14 @@ export default function CrossAssetPayment() {

Settlement

-

{liveStatusMessage}

+

{liveStatusMessage}

{submissionTxHash && ( -
-

+

+

Transaction Hash

{submissionTxHash}

diff --git a/frontend/src/pages/Login.tsx b/frontend/src/pages/Login.tsx index 5dec16bf..f6566a8d 100644 --- a/frontend/src/pages/Login.tsx +++ b/frontend/src/pages/Login.tsx @@ -43,7 +43,7 @@ const Login: React.FC = () => {
-
+

Secure · Encrypted · Non-Custodial

diff --git a/frontend/src/pages/RevenueSplitDashboard.tsx b/frontend/src/pages/RevenueSplitDashboard.tsx index 0ad56537..cac7fe84 100644 --- a/frontend/src/pages/RevenueSplitDashboard.tsx +++ b/frontend/src/pages/RevenueSplitDashboard.tsx @@ -190,12 +190,12 @@ export default function RevenueSplitDashboard() { return (
-
+

Revenue Split Dashboard

-

+

Contract-backed allocations and distribution history

@@ -211,14 +211,14 @@ export default function RevenueSplitDashboard() { Connect Wallet ) : ( - + Connected: {address.slice(0, 6)}...{address.slice(-4)} )}
{isLoading ? ( -

Loading revenue split dashboard...

+

Loading revenue split dashboard...

) : null} {error ?

{error}

: null} @@ -232,11 +232,11 @@ export default function RevenueSplitDashboard() { />
{allocations.length === 0 ? ( -

No allocation data loaded.

+

No allocation data loaded.

) : ( allocations.map((entry, idx) => ( // eslint-disable-next-line react-x/no-array-index-key -

+

{entry.recipient.slice(0, 6)}...{entry.recipient.slice(-4)} -{' '} {entry.percentage.toFixed(2)}%

@@ -276,7 +276,7 @@ export default function RevenueSplitDashboard() { value={entry.recipient} onChange={(event) => setAllocationField(idx, 'recipient', event.target.value)} placeholder="Recipient Stellar Address" - className="md:col-span-8 bg-[#0a0a0c] border border-zinc-800 rounded-lg px-3 py-2 text-xs" + className="md:col-span-8 bg-[var(--bg)] border border-[var(--border-hi)] rounded-lg px-3 py-2 text-xs" style={{ minHeight: '44px' }} />