feat: add CSS globals, format utils, and queryClient
This commit is contained in:
34
app/src/lib/format.ts
Normal file
34
app/src/lib/format.ts
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
export function abbrev(pk: string | null | undefined): string {
|
||||||
|
if (!pk) return '—'
|
||||||
|
return `${pk.slice(0, 4)}…${pk.slice(-4)}`
|
||||||
|
}
|
||||||
|
|
||||||
|
export function fmtSol(lamports: bigint | number): string {
|
||||||
|
const v = Number(lamports) / 1e9
|
||||||
|
return v.toLocaleString(undefined, { maximumFractionDigits: 4 }) + ' SOL'
|
||||||
|
}
|
||||||
|
|
||||||
|
export function fmtTok(raw: bigint | number, decimals: number, symbol: string): string {
|
||||||
|
const v = Number(raw) / Math.pow(10, decimals)
|
||||||
|
return v.toLocaleString(undefined, { maximumFractionDigits: Math.min(decimals, 2) }) + ' ' + symbol
|
||||||
|
}
|
||||||
|
|
||||||
|
export function relTime(ts: number): string {
|
||||||
|
const d = Math.floor(Date.now() / 1000) - ts
|
||||||
|
if (d < 60) return `${d}s ago`
|
||||||
|
if (d < 3600) return `${Math.floor(d / 60)}m ago`
|
||||||
|
if (d < 86400) return `${Math.floor(d / 3600)}h ago`
|
||||||
|
return `${Math.floor(d / 86400)}d ago`
|
||||||
|
}
|
||||||
|
|
||||||
|
export function exact(ts: number): string {
|
||||||
|
return new Date(ts * 1000).toUTCString()
|
||||||
|
}
|
||||||
|
|
||||||
|
export function priceStr(
|
||||||
|
currency: { __kind: 'Sol' } | { __kind: 'Spl'; decimals: number; symbol?: string },
|
||||||
|
price: bigint | number,
|
||||||
|
): string {
|
||||||
|
if (currency.__kind === 'Sol') return fmtSol(price)
|
||||||
|
return fmtTok(price, currency.decimals, (currency as { symbol?: string }).symbol ?? 'SPL')
|
||||||
|
}
|
||||||
11
app/src/lib/queryClient.ts
Normal file
11
app/src/lib/queryClient.ts
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
import { QueryClient } from '@tanstack/react-query'
|
||||||
|
|
||||||
|
export const queryClient = new QueryClient({
|
||||||
|
defaultOptions: {
|
||||||
|
queries: {
|
||||||
|
staleTime: 10_000,
|
||||||
|
gcTime: 5 * 60 * 1000,
|
||||||
|
retry: 2,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
6
app/src/lib/utils.ts
Normal file
6
app/src/lib/utils.ts
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
import { clsx, type ClassValue } from 'clsx'
|
||||||
|
import { twMerge } from 'tailwind-merge'
|
||||||
|
|
||||||
|
export function cn(...inputs: ClassValue[]) {
|
||||||
|
return twMerge(clsx(inputs))
|
||||||
|
}
|
||||||
58
app/src/styles/globals.css
Normal file
58
app/src/styles/globals.css
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
@import "tailwindcss";
|
||||||
|
|
||||||
|
@import url('https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500;600&display=swap');
|
||||||
|
|
||||||
|
:root {
|
||||||
|
--bg: oklch(0.165 0.022 282);
|
||||||
|
--bg2: oklch(0.205 0.026 282);
|
||||||
|
--bg3: oklch(0.25 0.03 283);
|
||||||
|
--bd: oklch(0.33 0.032 286);
|
||||||
|
--bdSoft: oklch(0.27 0.028 284);
|
||||||
|
--navbg: oklch(0.18 0.024 282 / .82);
|
||||||
|
--tx: oklch(0.96 0.008 285);
|
||||||
|
--mut: oklch(0.68 0.022 284);
|
||||||
|
--radius: 13px;
|
||||||
|
--acc: #9945FF;
|
||||||
|
--acc2: #14F195;
|
||||||
|
--acc2light: #7df5c4;
|
||||||
|
--accGlow: rgba(153,69,255,.55);
|
||||||
|
--accSoft: rgba(153,69,255,.13);
|
||||||
|
--accBd: rgba(153,69,255,.4);
|
||||||
|
--danger: #FF7A59;
|
||||||
|
--dangerSoft: rgba(255,122,89,.12);
|
||||||
|
--font-body: 'Space Grotesk', system-ui, sans-serif;
|
||||||
|
--font-mono: 'JetBrains Mono', monospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Tailwind theme tokens for connectorkit components */
|
||||||
|
@theme {
|
||||||
|
--color-primary: var(--acc);
|
||||||
|
--color-primary-foreground: #0b0613;
|
||||||
|
--color-background: var(--bg);
|
||||||
|
--color-foreground: var(--tx);
|
||||||
|
--color-popover: var(--bg2);
|
||||||
|
--color-popover-foreground: var(--tx);
|
||||||
|
--color-border: var(--bd);
|
||||||
|
--color-input: var(--bd);
|
||||||
|
--color-muted: var(--bg3);
|
||||||
|
--color-accent: var(--bg3);
|
||||||
|
--color-accent-foreground: var(--tx);
|
||||||
|
--color-destructive: var(--danger);
|
||||||
|
}
|
||||||
|
|
||||||
|
* { box-sizing: border-box; }
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
background: var(--bg);
|
||||||
|
color: var(--tx);
|
||||||
|
font-family: var(--font-body);
|
||||||
|
}
|
||||||
|
input, button, select, textarea { font-family: inherit; font-size: inherit; color: inherit; }
|
||||||
|
button { cursor: pointer; border: none; background: none; }
|
||||||
|
::selection { background: rgba(153,69,255,.35); }
|
||||||
|
::-webkit-scrollbar { width: 10px; height: 10px; }
|
||||||
|
::-webkit-scrollbar-thumb { background: rgba(255,255,255,.13); border-radius: 8px; }
|
||||||
|
::-webkit-scrollbar-track { background: transparent; }
|
||||||
|
@keyframes scToast { from { opacity: 0; transform: translate(-50%,10px); } to { opacity: 1; transform: translate(-50%,0); } }
|
||||||
|
@keyframes scSpin { to { transform: rotate(360deg); } }
|
||||||
|
@keyframes scPulse { 0%,100% { opacity: 1; } 50% { opacity: .45; } }
|
||||||
Reference in New Issue
Block a user