From 4fd23c13780b736454fd4ccec73a987e1b08219d Mon Sep 17 00:00:00 2001 From: RedVeil Date: Wed, 7 Jan 2026 11:23:02 +0100 Subject: [PATCH 1/7] removed bvUSD --- frontend/app/src/app/page.tsx | 4 +- .../app/src/comps/AppLayout/BottomBar.tsx | 92 ++++++++++--------- frontend/app/src/comps/AppLayout/TopBar.tsx | 2 +- 3 files changed, 52 insertions(+), 46 deletions(-) diff --git a/frontend/app/src/app/page.tsx b/frontend/app/src/app/page.tsx index 292ca1a6b..144536fe4 100644 --- a/frontend/app/src/app/page.tsx +++ b/frontend/app/src/app/page.tsx @@ -1,5 +1,5 @@ -import { HomeScreen } from "@/src/screens/HomeScreen/HomeScreen"; +import { EarnPoolsListScreen } from "@/src/screens/EarnPoolsListScreen/EarnPoolsListScreen"; export default function Page() { - return ; + return ; } diff --git a/frontend/app/src/comps/AppLayout/BottomBar.tsx b/frontend/app/src/comps/AppLayout/BottomBar.tsx index 9c65027cb..a6927c263 100644 --- a/frontend/app/src/comps/AppLayout/BottomBar.tsx +++ b/frontend/app/src/comps/AppLayout/BottomBar.tsx @@ -58,7 +58,8 @@ export function BottomBar() { })} > - + <> + {/* bvUSD TVL{" "} {liquityStats.data && ( @@ -73,7 +74,8 @@ export function BottomBar() { } /> )} - + */} + @@ -94,47 +96,49 @@ export function BottomBar() { - {DISPLAYED_PRICES.map((symbol) => ( - - ))} - {account.address && ACCOUNT_SCREEN && ( - - - + <> + {/* <> + {DISPLAYED_PRICES.map((symbol) => ( + + ))} + {account.address && ACCOUNT_SCREEN && ( + + + - {shortenAddress(account.address, 3)} - - } - className={css({ - color: "content", - borderRadius: 4, - _focusVisible: { - outline: "2px solid token(colors.focused)", - }, - _active: { - translate: "0 1px", - }, - })} - /> - - )} - {/* + } + className={css({ + color: "content", + borderRadius: 4, + _focusVisible: { + outline: "2px solid token(colors.focused)", + }, + _active: { + translate: "0 1px", + }, + })} + /> + + )} + - */} + + */} + diff --git a/frontend/app/src/comps/AppLayout/TopBar.tsx b/frontend/app/src/comps/AppLayout/TopBar.tsx index bc8699a5b..1a4e94425 100644 --- a/frontend/app/src/comps/AppLayout/TopBar.tsx +++ b/frontend/app/src/comps/AppLayout/TopBar.tsx @@ -103,7 +103,7 @@ export function TopBar() { )} - + {/* */}
Date: Mon, 12 Jan 2026 12:08:21 +0100 Subject: [PATCH 2/7] updated footer + navbar --- .cursor/rules/cursor-rules.mdc | 53 +++ .cursor/rules/frontend-app.mdc | 37 ++ .cursor/rules/self-improve.mdc | 72 ++++ .../app/src/comps/AppLayout/AppLayout.tsx | 9 +- .../app/src/comps/AppLayout/BottomBar.tsx | 369 +++++++++--------- frontend/app/src/comps/AppLayout/TopBar.tsx | 37 +- 6 files changed, 365 insertions(+), 212 deletions(-) create mode 100644 .cursor/rules/cursor-rules.mdc create mode 100644 .cursor/rules/frontend-app.mdc create mode 100644 .cursor/rules/self-improve.mdc diff --git a/.cursor/rules/cursor-rules.mdc b/.cursor/rules/cursor-rules.mdc new file mode 100644 index 000000000..7dfae3de0 --- /dev/null +++ b/.cursor/rules/cursor-rules.mdc @@ -0,0 +1,53 @@ +--- +description: Guidelines for creating and maintaining Cursor rules to ensure consistency and effectiveness. +globs: .cursor/rules/*.mdc +alwaysApply: true +--- + +- **Required Rule Structure:** + ```markdown + --- + description: Clear, one-line description of what the rule enforces + globs: path/to/files/*.ext, other/path/**/* + alwaysApply: boolean + --- + + - **Main Points in Bold** + - Sub-points with details + - Examples and explanations + ``` + +- **File References:** + - Use `[filename](mdc:path/to/file)` ([filename](mdc:filename)) to reference files + - Example: [prisma.mdc](mdc:.cursor/rules/prisma.mdc) for rule references + - Example: [schema.prisma](mdc:prisma/schema.prisma) for code references + +- **Code Examples:** + - Use language-specific code blocks + ```typescript + // ✅ DO: Show good examples + const goodExample = true; + + // ❌ DON'T: Show anti-patterns + const badExample = false; + ``` + +- **Rule Content Guidelines:** + - Start with high-level overview + - Include specific, actionable requirements + - Show examples of correct implementation + - Reference existing code when possible + - Keep rules DRY by referencing other rules + +- **Rule Maintenance:** + - Update rules when new patterns emerge + - Add examples from actual codebase + - Remove outdated patterns + - Cross-reference related rules + +- **Best Practices:** + - Use bullet points for clarity + - Keep descriptions concise + - Include both DO and DON'T examples + - Reference actual code over theoretical examples + - Use consistent formatting across rules \ No newline at end of file diff --git a/.cursor/rules/frontend-app.mdc b/.cursor/rules/frontend-app.mdc new file mode 100644 index 000000000..fa04ca9f3 --- /dev/null +++ b/.cursor/rules/frontend-app.mdc @@ -0,0 +1,37 @@ +--- +description: Match existing React/TypeScript and formatting style used in frontend/app +globs: frontend/app/**/*.{ts,tsx,js,jsx} +alwaysApply: true +--- + +- **General TypeScript / imports** + - Use TypeScript with explicit types on public APIs and utility functions where it adds clarity; allow inference for simple component return types. + - Prefer `export function Name()` for components and utilities; use `export default function` for Next.js `page.tsx`/`layout.tsx`. + - Use **named imports** grouped and ordered: framework/libs (`react`, `next/*`), then aliased app imports (`@/src/...`, `@/styled-system/...`), then relative imports (`./Something`). + - Use **double quotes** for imports and strings in TS/TSX, and **semicolons** consistently. + - Prefer narrow types: literal template types for addresses (e.g. `` `0x${string}` ``) and specific maps (`Record`, `{ [symbol: string]: Vault }`). + +- **React components** + - For client components, start with `"use client";` on the first line when hooks or browser APIs are used. + - Declare props inline for small components: `export function Comp({ x }: { x: string }) { ... }`; use separate interfaces/types only when props are reused or complex. + - Place hooks at the top of the component in a logical order: data/config hooks, then price/balance hooks, then modal/router hooks. + - Keep JSX **return blocks compact and declarative**: minimal logic in JSX; derive values above and pass them down as props. + - Use descriptive, PascalCase component and screen names (`VaultPoolScreen`, `AppLayout`, `MobileScreen`). + +- **JSX & styling** + - Use `className={css({ ... })}` for styling with JS object syntax and camelCased CSS keys; keep style objects relatively flat and readable. + - When JSX props span multiple lines, format one prop per line and end the prop list with a trailing comma where allowed. + - Prefer semantic, readable JSX structure: outer layout wrapper(s), then main content, then panels/cards/sections; avoid deeply nested inline logic. + - For long JSX blocks (e.g. cards, panels), pass callbacks and configuration via props instead of inlining large chunks of logic inside the component. + +- **Utilities & data structures** + - Implement utilities as pure functions in `utils`-style modules with clear naming (`debounce`, `roundToDecimal`, `jsonStringifyWithBigInt`, `bigIntAbs`). + - Use small, focused helpers for domain operations (e.g. `getAllVaults` that returns `{ vaults, vaultAssets, vaultsArray }`) rather than mixing data derivation with rendering. + - Prefer `type` aliases for structured data (`Vault`, `Token`, `AppChainConfig`) and maps (`VaultMap`, `TokenMap`) and keep them grouped at the top of config files. + +- **Formatting & readability** + - Use 2-space indentation, trailing commas in multiline argument/prop lists and object literals, and break long expressions across lines for clarity. + - Keep comments minimal and purposeful (e.g. short behavioral notes like `// switch to mainnet if it's a bvUSD vault`), not redundant with the code. + - Keep files focused: screens/components in `screens` directories, layout in `AppLayout`, configuration in `config`/`env`, and services in `services`. + +I’ll follow this rule set for any future edits or new code under `frontend/app` so that my changes match the existing style and conventions. \ No newline at end of file diff --git a/.cursor/rules/self-improve.mdc b/.cursor/rules/self-improve.mdc new file mode 100644 index 000000000..701f3ec48 --- /dev/null +++ b/.cursor/rules/self-improve.mdc @@ -0,0 +1,72 @@ +--- +description: Guidelines for continuously improving Cursor rules based on emerging code patterns and best practices. +globs: **/* +alwaysApply: true +--- + +- **Rule Improvement Triggers:** + - New code patterns not covered by existing rules + - Repeated similar implementations across files + - Common error patterns that could be prevented + - New libraries or tools being used consistently + - Emerging best practices in the codebase + +- **Analysis Process:** + - Compare new code with existing rules + - Identify patterns that should be standardized + - Look for references to external documentation + - Check for consistent error handling patterns + - Monitor test patterns and coverage + +- **Rule Updates:** + - **Add New Rules When:** + - A new technology/pattern is used in 3+ files + - Common bugs could be prevented by a rule + - Code reviews repeatedly mention the same feedback + - New security or performance patterns emerge + + - **Modify Existing Rules When:** + - Better examples exist in the codebase + - Additional edge cases are discovered + - Related rules have been updated + - Implementation details have changed + +- **Example Pattern Recognition:** + ```typescript + // If you see repeated patterns like: + const data = await prisma.user.findMany({ + select: { id: true, email: true }, + where: { status: 'ACTIVE' } + }); + + // Consider adding to [prisma.mdc](mdc:.cursor/rules/prisma.mdc): + // - Standard select fields + // - Common where conditions + // - Performance optimization patterns + ``` + +- **Rule Quality Checks:** + - Rules should be actionable and specific + - Examples should come from actual code + - References should be up to date + - Patterns should be consistently enforced + +- **Continuous Improvement:** + - Monitor code review comments + - Track common development questions + - Update rules after major refactors + - Add links to relevant documentation + - Cross-reference related rules + +- **Rule Deprecation:** + - Mark outdated patterns as deprecated + - Remove rules that no longer apply + - Update references to deprecated rules + - Document migration paths for old patterns + +- **Documentation Updates:** + - Keep examples synchronized with code + - Update references to external docs + - Maintain links between related rules + - Document breaking changes +Follow [cursor_rules.mdc](mdc:.cursor/rules/cursor_rules.mdc) for proper rule formatting and structure. \ No newline at end of file diff --git a/frontend/app/src/comps/AppLayout/AppLayout.tsx b/frontend/app/src/comps/AppLayout/AppLayout.tsx index f09795a28..c5b16db57 100644 --- a/frontend/app/src/comps/AppLayout/AppLayout.tsx +++ b/frontend/app/src/comps/AppLayout/AppLayout.tsx @@ -56,7 +56,6 @@ export function AppLayout({ gap: 48, maxWidth: `calc(${LAYOUT_WIDTH}px + 48px)`, margin: "0 auto", - padding: "24px 0", width: "100%", })} > @@ -106,13 +105,11 @@ function MobileScreen() { gap: 16, width: "90%", height: "48px", - margin: "16px auto", + margin: "0px auto", padding: "0 16px", fontSize: 16, fontWeight: 500, - background: "fieldSurface", - border: "1px solid token(colors.fieldBorder)", - borderRadius: 16, + borderBottom: "1px solid token(colors.fieldBorder)", })} > }, + { label: "Telegram", href: "https://t.me/bitvaultann", icon: }, +]; export function BottomBar() { - const account = useAccount(); const liquityStats = useLiquityStats(); + const btcTvl = liquityStats.data?.btcTVL ? Number(liquityStats.data.btcTVL) : undefined; return ( -
- {/* */} +
+ + + Bitcoin TVL + + +
+
- - <> - {/* - bvUSD TVL{" "} - - {liquityStats.data && ( - - )} - */} - - - - - Bitcoin TVL{" "} - - {liquityStats.data && ( - - )} - - - - <> - {/* <> - {DISPLAYED_PRICES.map((symbol) => ( - +
+ +
+ {SOCIAL_LINKS.map((social) => ( + ))} - {account.address && ACCOUNT_SCREEN && ( - +
+ +
+ {FOOTER_LINKS.map((section) => ( +
+
- - + {section.title} +
+
+ {section.links.map((link) => ( + + {link.label} + + ))} +
+
+ ))} +
- {shortenAddress(account.address, 3)} - - } - className={css({ - color: "content", - borderRadius: 4, - _focusVisible: { - outline: "2px solid token(colors.focused)", - }, - _active: { - translate: "0 1px", - }, - })} - /> - - )} - - - - Redeem bvUSD - - } - className={css({ - color: "content", - borderRadius: 4, - _focusVisible: { - outline: "2px solid token(colors.focused)", - }, - _active: { - translate: "0 1px", - }, - })} - /> - - */} - - + + Back to Top + + + } + onClick={() => window.scrollTo({ top: 0, behavior: "smooth" })} + className={css({ + color: "#71717a", + fontSize: 14, + padding: 0, + transition: "color 0.15s", + _hover: { color: "#f39c12" }, + _focusVisible: { outline: "2px solid token(colors.focused)" }, + })} + />
-
-
- ); -} -function Price({ symbol }: { symbol: TokenSymbol }) { - const price = usePrice(symbol); - return ( - - - - {symbol} - - - +
+

+ Important Notice: This product is + intended for sophisticated and professional investors only. This does not constitute + investment, financial, legal, or tax advice. Past performance is not indicative of + future results. Capital at risk — you may lose some or all of your investment. Your + investment is not protected by any government deposit insurance scheme. Not available to + U.S. persons or residents of restricted jurisdictions. BV Labs Ltd. is incorporated in + the British Virgin Islands. +

+

© 2026 BV Labs Ltd. All rights reserved.

+
+
+ ); } -function BuildInfo() { - const about = useAbout(); +function SocialLink({ href, label, icon }: { href: string; label: string; icon: ReactNode }) { return ( -
- { - about.openModal(); - }} - className={css({ - color: "dimmed", - })} - style={{ - fontSize: 12, - }} - /> -
+ {icon} + + ); +} + +function XIcon() { + return ( + + ); +} + +function TelegramIcon() { + return ( + + ); +} + +function ArrowUpIcon() { + return ( + ); } diff --git a/frontend/app/src/comps/AppLayout/TopBar.tsx b/frontend/app/src/comps/AppLayout/TopBar.tsx index 1a4e94425..fee8ac726 100644 --- a/frontend/app/src/comps/AppLayout/TopBar.tsx +++ b/frontend/app/src/comps/AppLayout/TopBar.tsx @@ -2,12 +2,9 @@ import type { ComponentProps } from "react"; -import { Logo } from "@/src/comps/Logo/Logo"; -import { Tag } from "@/src/comps/Tag/Tag"; import content from "@/src/content"; -import { DEPLOYMENT_FLAVOR } from "@/src/env"; import { css } from "@/styled-system/css"; -import { IconBorrow, IconDashboard, IconEarn } from "@liquity2/uikit"; +import { IconDashboard, IconEarn } from "@liquity2/uikit"; import Link from "next/link"; import { AccountButton } from "./AccountButton"; import { Menu } from "./Menu"; @@ -24,11 +21,10 @@ const menuItems: ComponentProps["menuItems"] = [ export function TopBar() { return ( -
@@ -38,17 +34,13 @@ export function TopBar() { zIndex: 1, display: "flex", justifyContent: "space-between", - gap: 16, maxWidth: 1440, height: "100%", margin: "0 auto", - padding: "16px 24px", + padding: "12px 24px", fontSize: 16, fontWeight: 500, - background: "#141416", - boxShadow: "0px 4px 4px 0px rgba(0, 0, 0, 0.25)", - border: "1px solid var(--Neutral-100, #353945)", - borderRadius: 16, + borderBottom: "1px solid var(--Neutral-100, #353945)", })} > - {DEPLOYMENT_FLAVOR && ( -
- - {DEPLOYMENT_FLAVOR} - -
- )}
{/* */} @@ -115,6 +88,6 @@ export function TopBar() {
- + ); } From 4dcbd9d98a48178e665b3d3360c16c5dc79d757c Mon Sep 17 00:00:00 2001 From: RedVeil Date: Wed, 14 Jan 2026 11:22:34 +0100 Subject: [PATCH 3/7] design rework 1 --- frontend/app/package.json | 1 + frontend/app/src/app/page.tsx | 4 +- frontend/app/src/bitvault-utils.ts | 4 +- .../app/src/comps/AppLayout/AppLayout.tsx | 4 +- .../app/src/comps/AppLayout/BottomBar.tsx | 2 +- frontend/app/src/comps/AppLayout/TopBar.tsx | 2 +- frontend/app/src/comps/Field/Field.tsx | 2 +- .../app/src/comps/ProductCard/ProductCard.tsx | 141 ++-- .../comps/ProductCard/ProductCardGroup.tsx | 29 +- .../app/src/comps/ProgressBar/ProgressBar.tsx | 50 ++ frontend/app/src/comps/Screen/Screen.tsx | 38 +- frontend/app/src/comps/Tag/Tag.tsx | 10 +- .../VaultPositionSummary.tsx | 167 ++-- frontend/app/src/content.tsx | 7 +- .../EarnPoolsListScreen.tsx | 16 - .../app/src/screens/HomeScreen/HomeScreen.tsx | 442 +++++++++- .../screens/VaultScreen/PanelVaultUpdate.tsx | 213 ++--- .../src/screens/VaultScreen/VaultFAQPanel.tsx | 404 ++++++--- .../src/screens/VaultScreen/VaultPanel.tsx | 108 ++- .../src/screens/VaultScreen/VaultScreen.tsx | 50 +- frontend/uikit/src/InputField/InputField.tsx | 45 +- frontend/uikit/src/Tabs/Tabs.tsx | 14 +- pnpm-lock.yaml | 767 ++++++++++++++++-- 23 files changed, 1840 insertions(+), 680 deletions(-) create mode 100644 frontend/app/src/comps/ProgressBar/ProgressBar.tsx diff --git a/frontend/app/package.json b/frontend/app/package.json index 47717dffe..fa84cdab5 100644 --- a/frontend/app/package.json +++ b/frontend/app/package.json @@ -38,6 +38,7 @@ "next": "^14.2.23", "react": "18.3.1", "react-dom": "18.3.1", + "react-markdown": "^10.1.0", "recharts": "^2.15.2", "sharp": "^0.33.5", "ts-pattern": "^5.6.0", diff --git a/frontend/app/src/app/page.tsx b/frontend/app/src/app/page.tsx index 144536fe4..292ca1a6b 100644 --- a/frontend/app/src/app/page.tsx +++ b/frontend/app/src/app/page.tsx @@ -1,5 +1,5 @@ -import { EarnPoolsListScreen } from "@/src/screens/EarnPoolsListScreen/EarnPoolsListScreen"; +import { HomeScreen } from "@/src/screens/HomeScreen/HomeScreen"; export default function Page() { - return ; + return ; } diff --git a/frontend/app/src/bitvault-utils.ts b/frontend/app/src/bitvault-utils.ts index e5cccba23..55ed84a1e 100644 --- a/frontend/app/src/bitvault-utils.ts +++ b/frontend/app/src/bitvault-utils.ts @@ -57,8 +57,8 @@ export function useVault({ chainId, vaultAddress, vaultSymbol}: { chainId: numbe : dnZero return { - apr7d: vaultSymbol !== "sbvUSD" ? 0 : dnumOrNull(Number(stats.sbvUSD[0].apy7d) / 100, 4), - apr30d: vaultSymbol !== "sbvUSD" ? 0 : dnumOrNull(Number(stats.sbvUSD[0].apy30d) / 100, 4), + apr7d: vaultSymbol !== "sbvUSD" ? DNUM_0 : dnumOrNull(Number(stats.sbvUSD[0].apy7d) / 100, 4), + apr30d: vaultSymbol !== "sbvUSD" ? DNUM_0 : dnumOrNull(Number(stats.sbvUSD[0].apy30d) / 100, 4), collateral, totalDeposited: totalAssets, price: totalSupply > dnZero && totalAssets > dnZero ? dn.div(totalAssets, totalSupply, decimals) : dnOne, diff --git a/frontend/app/src/comps/AppLayout/AppLayout.tsx b/frontend/app/src/comps/AppLayout/AppLayout.tsx index c5b16db57..3c161251d 100644 --- a/frontend/app/src/comps/AppLayout/AppLayout.tsx +++ b/frontend/app/src/comps/AppLayout/AppLayout.tsx @@ -53,8 +53,8 @@ export function AppLayout({ className={css({ display: { base: "none", medium: "grid" }, gridTemplateRows: "auto 1fr auto", - gap: 48, - maxWidth: `calc(${LAYOUT_WIDTH}px + 48px)`, + gap: 4, + maxWidth: `calc(${LAYOUT_WIDTH}px + 4px)`, margin: "0 auto", width: "100%", })} diff --git a/frontend/app/src/comps/AppLayout/BottomBar.tsx b/frontend/app/src/comps/AppLayout/BottomBar.tsx index ae0f2a26f..dcf846a9a 100644 --- a/frontend/app/src/comps/AppLayout/BottomBar.tsx +++ b/frontend/app/src/comps/AppLayout/BottomBar.tsx @@ -47,7 +47,7 @@ export function BottomBar() {