Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion frontend/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<link rel="icon" type="image/svg+xml" href="/quantapool.svg" />
<link rel="apple-touch-icon" href="/apple-touch-icon.png" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="theme-color" content="#09090c" />
<meta name="theme-color" content="#080d16" />
<title>QuantaPool | Native QRL Pooled Staking on QRL 2.0</title>
<meta
name="description"
Expand Down
10 changes: 10 additions & 0 deletions frontend/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
},
"dependencies": {
"@fontsource-variable/instrument-sans": "^5.2.8",
"@fontsource-variable/inter": "^5.3.0",
"@fontsource-variable/jetbrains-mono": "^5.2.8",
"@fontsource-variable/sora": "^5.2.8",
"@noble/hashes": "^2.4.0",
Expand Down
4 changes: 4 additions & 0 deletions frontend/public/myqrlwallet-icon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 2 additions & 2 deletions frontend/public/quantapool.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
10 changes: 5 additions & 5 deletions frontend/public/social-card.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 2 additions & 2 deletions frontend/src/components/ActivityCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -114,13 +114,13 @@ export const ActivityCard = observer(() => {
recovery cash.
</p>
)}
<p className="font-data text-xs text-muted-foreground">
<p className="font-numeric text-xs text-muted-foreground">
Block {item.blockNumber.toString()}
</p>
</div>
<div className="text-right">
{item.qrlAmount !== null && (
<p className="font-data font-medium">
<p className="font-numeric font-medium">
{formatAmount(item.qrlAmount)} {NATIVE_UNIT}
</p>
)}
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/components/AmountInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ export function AmountInput({
const next = e.target.value.replace(",", ".");
if (next === "" || /^\d*\.?\d*$/.test(next)) onChange(next);
}}
className="font-data h-12 pr-16 text-lg"
className="font-numeric h-12 pr-16 text-lg"
/>
<span className="absolute right-3 top-1/2 -translate-y-1/2 text-sm font-medium text-muted-foreground">
{symbol}
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/components/StatsBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export const StatsBar = observer(() => {
{stats.map(([label, value]) => (
<div key={label} className="min-w-0 bg-background p-4">
<dt className="text-xs text-muted-foreground">{label}</dt>
<dd className="font-data mt-1 break-all text-sm font-semibold">
<dd className="font-numeric mt-1 break-all text-sm font-semibold">
{value === undefined ? "Unavailable" : `${formatAmount(value)} QRL`}
</dd>
</div>
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/components/UI/Button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ const buttonVariants = cva(
variants: {
variant: {
default:
"bg-primary text-primary-foreground shadow-[0_10px_24px_-12px_hsl(24_96%_45%/0.55),inset_0_1px_0_hsl(36_100%_80%/0.35)] hover:bg-primary/90",
"bg-primary text-primary-foreground shadow-[0_10px_24px_-12px_hsl(199_78%_45%/0.55),inset_0_1px_0_hsl(196_70%_86%/0.35)] hover:bg-primary/90",
secondary:
"bg-foreground/[0.06] text-foreground border border-foreground/10 hover:bg-foreground/10",
destructive:
Expand Down
16 changes: 12 additions & 4 deletions frontend/src/components/WalletPickerModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -49,12 +49,20 @@ export const WalletPickerModal = observer(() => {
className="cursor-pointer flex w-full items-center gap-3 rounded-md border border-border bg-muted/30 px-3 py-3 text-left transition-colors hover:border-primary/40 hover:bg-primary/10"
>
{w.icon ? (
<img src={w.icon} alt="" className="h-8 w-8 rounded-md" />
<img
src={w.icon}
alt=""
className="h-8 w-8 shrink-0 rounded-md"
/>
) : (
<span className="h-8 w-8 rounded-md bg-muted" />
<span className="h-8 w-8 shrink-0 rounded-md bg-muted" />
)}
<span className="flex-1 font-medium">{w.name}</span>
<span className="font-data text-xs text-identity-accent">{w.rdns}</span>
<span className="flex min-w-0 flex-1 flex-col">
<span className="truncate font-medium">{w.name}</span>
<span className="font-data truncate text-xs text-identity-accent">
{w.rdns}
</span>
</span>
</button>
))
)}
Expand Down
107 changes: 67 additions & 40 deletions frontend/src/index.css
Original file line number Diff line number Diff line change
@@ -1,17 +1,21 @@
/* Self-hosted variable fonts (Sora display / Instrument Sans body /
JetBrains Mono data) are imported in main.tsx: importing them here would
let the Tailwind postcss pipeline inline the @font-face rules without
/* Self-hosted variable fonts (Sora display / Instrument Sans body / Inter
numeric / JetBrains Mono data) are imported in main.tsx: importing them here
would let the Tailwind postcss pipeline inline the @font-face rules without
rewriting the package-relative woff2 URLs. */
@import "tailwindcss";

/* Theme customization for Tailwind v4 - "Obsidian & Ember" token values
mirror myqrlwallet-frontend so QuantaPool reads as part of the same
product family. */
/* Theme customization for Tailwind v4 - "QRL Blue" token values mirror
myqrlwallet-frontend so QuantaPool reads as part of the same product
family. */
@theme {
/* Typography */
--font-sans: "Instrument Sans Variable", ui-sans-serif, system-ui, sans-serif;
--font-display: "Sora Variable", ui-sans-serif, system-ui, sans-serif;
--font-mono: "JetBrains Mono Variable", ui-monospace, "SF Mono", monospace;
/* Numeric voice: balances, amounts, fees, counts. Inter matches the
extension surface and the wider wallet ecosystem. */
--font-numeric: "Inter Variable", "Instrument Sans Variable", ui-sans-serif,
system-ui, sans-serif;

/* Border radius */
--radius-lg: var(--radius);
Expand Down Expand Up @@ -55,50 +59,58 @@

/* CSS Custom Properties for theming.

"Obsidian & Ember": one deep warm-ink surface family, one ember-orange
action color (the QRL brand), champagne reserved for identity and informational
"QRL Blue": one deep navy surface family, QRL's sky blue as the single
action color, a pale ice blue reserved for identity and informational
states, and layered glow + grain atmosphere behind everything. Values
are the canonical set from myqrlwallet-frontend. */
@layer base {
:root {
--background: 235 15% 4%;
--foreground: 36 20% 95%;
--background: 222 45% 6%;
--foreground: 210 30% 96%;

--card: 235 13% 7%;
--card-foreground: 36 20% 95%;
--card: 222 38% 9%;
--card-foreground: 210 30% 96%;

--popover: 235 14% 6%;
--popover-foreground: 36 20% 95%;
--popover: 222 40% 7%;
--popover-foreground: 210 30% 96%;

/* Ember: the single action color */
--primary: 24 96% 55%;
--primary-foreground: 24 90% 6%;
/* QRL sky blue: the single action color */
--primary: 199 78% 55%;
--primary-foreground: 205 80% 8%;

/* QRL Orange kept as the brand accent token (rails, edges, badges) */
--secondary: 25 95% 53%;
--secondary-foreground: 24 90% 6%;
/* Brand accent token (rails, edges, badges), a sibling of primary */
--secondary: 200 82% 52%;
--secondary-foreground: 205 80% 8%;

/* Champagne matches the wallet identity and information palette. */
--identity-accent: 38 45% 76%;
--identity-accent-foreground: 38 60% 8%;
/* Ice blue: the identity color (addresses, account markers) and
informational states. Sky blue acts, ice blue identifies. */
--identity-accent: 196 60% 78%;
--identity-accent-foreground: 205 60% 8%;

--success: 152 55% 48%;
--success-foreground: 152 80% 8%;

--muted: 235 10% 12%;
--muted-foreground: 234 8% 64%;
--muted: 222 30% 13%;
--muted-foreground: 215 15% 66%;

--accent: 235 11% 13%;
--accent-foreground: 36 20% 95%;
--accent: 222 30% 14%;
--accent-foreground: 210 30% 96%;

--destructive: 0 68% 46%;
--destructive-foreground: 0 0% 98%;
/* Lifted off the palette base (0 70% 55%) so 12px destructive text and
destructive text on a /15 tint both clear WCAG AA. The paired
foreground is a deep maroon, matching how primary pairs a dark
foreground with a bright accent. */
--destructive: 0 72% 64%;
--destructive-foreground: 0 60% 10%;

--border: 235 10% 15%;
--input: 235 10% 17%;
--ring: 24 96% 55%;
--border: 220 30% 17%;
--input: 220 30% 20%;
--ring: 199 78% 55%;

--radius: 0.75rem;

/* Top edge of the hero-card gradient. */
--hero-top: 205 55% 16%;
}

/* Customized scrollbar */
Expand Down Expand Up @@ -144,9 +156,9 @@
background-color: hsl(var(--background));
background-image:
url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160' viewBox='0 0 160 160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23n)' opacity='0.05'/%3E%3C/svg%3E"),
radial-gradient(52rem 34rem at 12% -8%, hsl(24 96% 55% / 0.09), transparent 62%),
radial-gradient(44rem 30rem at 108% 112%, hsl(38 45% 76% / 0.04), transparent 60%),
radial-gradient(60rem 44rem at 50% 120%, hsl(236 40% 12% / 0.5), transparent 70%);
radial-gradient(52rem 34rem at 12% -8%, hsl(199 78% 55% / 0.09), transparent 62%),
radial-gradient(44rem 30rem at 108% 112%, hsl(196 60% 78% / 0.04), transparent 60%),
radial-gradient(60rem 44rem at 50% 120%, hsl(222 45% 12% / 0.5), transparent 70%);
background-attachment: fixed;
font-family: var(--font-sans);
font-feature-settings: "ss01" on;
Expand Down Expand Up @@ -214,13 +226,26 @@
outline-offset: 4px;
}

/* Data voice: addresses, hashes, balances. */
/* Data voice: addresses, hashes. Anything the user compares character by
character stays monospace. */
.font-data {
font-family: var(--font-mono);
font-variant-numeric: tabular-nums;
letter-spacing: -0.01em;
}

/* Numeric voice: every balance, amount, fee, exchange rate and count.
Inter with fixed-width digits so a changing balance does not jitter.
font-feature-settings is set explicitly because body turns on "ss01",
which in Inter swaps in alternate digit shapes; "tnum" here replaces
that list and keeps the digits plain and tabular. */
.font-numeric {
font-family: var(--font-numeric);
font-variant-numeric: tabular-nums;
font-feature-settings: "tnum" 1;
letter-spacing: normal;
}

/* Glass surface: the one card treatment used everywhere so pages stop
feeling stitched together. Solid-ish ink with a soft top sheen.
Deliberately NO backdrop-filter: it would give every card its own
Expand All @@ -234,17 +259,19 @@
border: 1px solid hsl(var(--foreground) / 0.08);
box-shadow:
0 1px 0 hsl(var(--foreground) / 0.05) inset,
0 18px 40px -24px hsl(235 30% 2% / 0.9);
0 18px 40px -24px hsl(222 50% 2% / 0.9);
}

/* Ember edge treatment for "hero" cards (the stake form). */
/* Lifted edge treatment for "hero" cards (the stake form). Utility name
kept from the previous theme so in-flight branches keep applying
cleanly; the values are now QRL Blue. */
.surface-ember {
background:
linear-gradient(180deg, hsl(var(--primary) / 0.07), transparent 46%), hsl(var(--card) / 0.86);
linear-gradient(180deg, hsl(var(--hero-top) / 0.85), transparent 46%), hsl(var(--card) / 0.86);
border: 1px solid hsl(var(--primary) / 0.22);
box-shadow:
0 1px 0 hsl(var(--primary) / 0.14) inset,
0 18px 44px -22px hsl(24 96% 40% / 0.28);
0 18px 44px -22px hsl(199 78% 40% / 0.28);
}
}

Expand Down
6 changes: 4 additions & 2 deletions frontend/src/main.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import { StrictMode } from "react";
import { createRoot } from "react-dom/client";
// Self-hosted variable fonts (CSP-safe, bundled by Vite): Sora = display,
// Instrument Sans = body, JetBrains Mono = data (addresses/amounts).
// Imported here, not in index.css, so Vite rewrites the woff2 asset URLs.
// Instrument Sans = body, Inter = numeric (balances/amounts/fees),
// JetBrains Mono = data (addresses/hashes). Imported here, not in index.css,
// so Vite rewrites the woff2 asset URLs.
import "@fontsource-variable/sora/index.css";
import "@fontsource-variable/instrument-sans/index.css";
import "@fontsource-variable/inter/index.css";
import "@fontsource-variable/jetbrains-mono/index.css";
import "./index.css";
import App from "./App";
Expand Down
4 changes: 2 additions & 2 deletions frontend/src/pages/StakePage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ export const StakePage = observer(() => {
<CardContent className="space-y-4">
<p className="text-xs text-muted-foreground">
Wallet balance:{" "}
<span className="font-data">
<span className="font-numeric">
{account
? `${formatAmount(account.qrlBalance)} QRL`
: "Connect your wallet"}
Expand Down Expand Up @@ -185,7 +185,7 @@ export const StakePage = observer(() => {
className="flex flex-wrap justify-between gap-x-3 gap-y-1 text-sm"
>
<dt className="text-muted-foreground">{label}</dt>
<dd className="font-data break-all font-medium">
<dd className="font-numeric break-all font-medium">
{formatAmount(value)} QRL
</dd>
</div>
Expand Down
6 changes: 3 additions & 3 deletions frontend/src/pages/StatsPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ export const StatsPage = observer(() => {
className="flex flex-wrap justify-between gap-2 text-sm"
>
<dt className="text-muted-foreground">{label}</dt>
<dd className="font-data break-all">
<dd className="font-numeric break-all">
{value === undefined
? "Unavailable"
: `${formatAmount(value)} QRL`}
Expand All @@ -65,7 +65,7 @@ export const StatsPage = observer(() => {
<CardContent className="space-y-3 text-sm">
<p>
Last applied execution block:{" "}
<span className="font-data">
<span className="font-numeric">
{pool?.lastCheckpointBlock.toString() ?? "Unavailable"}
</span>
</p>
Expand All @@ -85,7 +85,7 @@ export const StatsPage = observer(() => {
</p>
<p>
Accounting recovery deadline: slot{" "}
<span className="font-data">
<span className="font-numeric">
{pool?.poolRecoveryDeadlineSlot.toString() ?? "Unavailable"}
</span>
. Only a completed and applied pool checkpoint can extend this
Expand Down
Loading
Loading