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
6 changes: 3 additions & 3 deletions apps/web-app/index.html
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<!DOCTYPE html>
<html lang="en">
<!doctype html>
<html lang="en" class="overflow-x-hidden">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
Expand All @@ -13,7 +13,7 @@
<link rel="manifest" href="/manifest.json" />
<title>%VITE_APP_TITLE%</title>
</head>
<body>
<body class="w-full">
<div id="app"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
Expand Down
1 change: 1 addition & 0 deletions apps/web-app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
"@radix-ui/react-checkbox": "^1.3.3",
"@radix-ui/react-collapsible": "^1.1.12",
"@radix-ui/react-dialog": "^1.1.15",
"@radix-ui/react-dropdown-menu": "^2.1.16",
"@radix-ui/react-label": "2.1.7",
"@radix-ui/react-select": "2.2.6",
"@radix-ui/react-slider": "1.3.6",
Expand Down
82 changes: 82 additions & 0 deletions apps/web-app/src/components/Footer/Footer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
export const Footer = () => {
return (
<footer className="w-full pt-9 pb-12 mt-10 px-4 flex flex-col lg:flex-row gap-4 justify-start text-center text-sm text-black dark:text-slate-500 border-t border-t-stone-200 dark:border-t-stone-800 z-[1000]">
<div className="flex flex-row flex-wrap justify-between items-start gap-8 lg:w-1/3 lg:flex-row lg:flex-nowrap">
<div className="text-left">
<h3 className="font-medium dark:text-gray-50 mb-3">
Help & Feedback
</h3>
<ul className="flex flex-col gap-2">
<li>
<a href="#">Contact Support</a>
</li>
<li>
<a href="#">X</a>
</li>
<li>
<a href="#">Discord</a>
</li>
<li>
<a href="#">Telegram</a>
</li>
</ul>
</div>

<div className="text-left">
<h3 className="font-medium dark:text-gray-50 mb-3">Resources</h3>
<ul className="flex flex-col gap-2">
<li>
<a href="#">Getting started</a>
</li>
<li>
<a href="#">Fees</a>
</li>
<li>
<a href="#">Blog</a>
</li>
<li>
<a href="#">FAQ</a>
</li>
</ul>
</div>

<div className="text-left">
<h3 className="font-medium dark:text-gray-50 mb-3">Legal</h3>
<ul className="flex flex-col gap-2">
<li>
<a href="#">Terms of Service</a>
</li>
<li>
<a href="#">Privacy Policy</a>
</li>
<li>
<a href="#">Disclaimer</a>
</li>
</ul>
</div>
</div>

<div className="flex flex-row mt-8 justify-start items-center gap-4 lg:items-start lg:order-first lg:w-1/3 lg:mt-0 lg:flex-col lg:justify-between">
<div className="shrink-0 grow-0 flex items-center justify-center">
<svg
width="32"
height="30"
viewBox="0 0 32 30"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M32 19.733C32 20.6167 31.2837 21.333 30.4 21.333H22.933C22.0494 21.333 21.333 22.0494 21.333 22.933V28.2662C21.333 29.1499 20.6167 29.8662 19.733 29.8662H1.6C0.716345 29.8662 0 29.1499 0 28.2662V10.1332C0 9.24955 0.716344 8.5332 1.6 8.5332H9.06699C9.95065 8.5332 10.667 7.81686 10.667 6.9332V1.6C10.667 0.716344 11.3833 0 12.267 0H30.4C31.2837 0 32 0.716344 32 1.6V19.733Z"
fill="#FF4500"
/>
</svg>
</div>

<div className="shrink-0 flex flex-col items-start justify-center">
<div className="lg:hidden">Sovryn Dex</div>
<div className="text-xs lg:text-sm">Copyright {new Date().getFullYear()}</div>
</div>
</div>
</footer>
);
};
25 changes: 0 additions & 25 deletions apps/web-app/src/components/Header.tsx

This file was deleted.

92 changes: 92 additions & 0 deletions apps/web-app/src/components/Header/Header.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import { usePrivy } from '@privy-io/react-auth';
import { Link } from '@tanstack/react-router';
import { Power, PowerOff } from 'lucide-react';
import { useAccount, useDisconnect } from 'wagmi';
import { ModeToggle } from '../theme-toggle';
import { Button } from '../ui/button';
import { Links } from './Links';
import { SocialLinks } from './SocialLinks';

export default function Header() {
return (
<>
<header className="z-50 sticky top-0 bg-background w-full px-4 py-4 lg:py-6 flex gap-4 flex-row items-center justify-between border-b border-b-stone-200 dark:border-b-stone-800">
<div className="flex flex-row items-center justify-start gap-8">
<Link
to="/"
className="flex flex-row items-center justify-start gap-4"
>
<svg
width="32"
height="30"
viewBox="0 0 32 30"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M32 19.7999C32 20.6836 31.2837 21.3999 30.4 21.3999H22.933C22.0494 21.3999 21.333 22.1162 21.333 22.9999V28.3331C21.333 29.2168 20.6167 29.9331 19.733 29.9331H1.6C0.716345 29.9331 0 29.2168 0 28.3331V10.2001C0 9.31644 0.716344 8.6001 1.6 8.6001H9.06699C9.95065 8.6001 10.667 7.88375 10.667 7.0001V1.66689C10.667 0.783239 11.3833 0.0668945 12.267 0.0668945H30.4C31.2837 0.0668945 32 0.783239 32 1.66689V19.7999Z"
fill="#FF4500"
/>
</svg>
<span className="hidden lg:block text-base text-black dark:text-white">
Sovryn Dex
</span>
</Link>

<div className="hidden lg:block">
<SocialLinks />
</div>
</div>

<Links />

<div className="flex flex-row items-center justify-end gap-4">
<ModeToggle />
<ConnectButton />
</div>
</header>
{/* <div className="h-16 lg:hidden bg-background" /> */}
</>
);
}

function ConnectButton() {
const { ready, authenticated, login, logout } = usePrivy();

const { address } = useAccount();
const { disconnect } = useDisconnect();

const handleDisconnect = () => {
disconnect();
logout();
};

if (!authenticated) {
return (
<Button onClick={login} disabled={!ready}>
<Power className="lg:hidden" />
<span className="hidden lg:block">Connect Wallet</span>
</Button>
);
}

if (authenticated) {
return (
<div className="flex flex-row gap-4 items-center">
<div className="hidden lg:block">
{address?.substring(0, 6)}...{address?.substring(address.length - 4)}
</div>
<Button
variant="outline"
onClick={handleDisconnect}
disabled={!ready}
size="icon"
>
<PowerOff />
</Button>
</div>
);
}

return <></>;
}
159 changes: 159 additions & 0 deletions apps/web-app/src/components/Header/Links.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
import { cn } from '@/lib/utils';
import { Link, linkOptions } from '@tanstack/react-router';
import { ChevronDown, Menu, X } from 'lucide-react';
import { useMemo, useReducer, type MouseEvent } from 'react';
import { Button } from '../ui/button';
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from '../ui/dropdown-menu';

const items = linkOptions([
// {
// to: '/',
// label: 'Home',
// activeOptions: { exact: true },
// },
{
to: '/convert',
label: 'Convert',
content: 'Convert assets instantly',
},
{
to: '/lend',
label: 'Lend',
content: 'Lend assets to earn yield',
},
{
to: '/stake',
label: 'Stake',
content: 'Stake assets to earn rewards',
},
{
to: '/demo/tanstack-query',
label: 'TanStack Query',
content: 'Demo of TanStack Query',
},
{
to: '/demo/form/simple',
label: 'Simple form',
content: 'Demo of Simple form',
},
{
to: '/demo/form/address',
label: 'Address form',
content: 'Demo of Address form',
},
]);

export const Links = () => {
const main = useMemo(() => items.slice(0, 3), [items]);
const others = useMemo(() => items.slice(3), [items]);
Comment on lines +52 to +53
Copy link

Copilot AI Oct 8, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The dependency array [items] is unnecessary since items is a constant defined outside the component. These useMemo calls can be simplified or the dependency array can be removed.

Suggested change
const main = useMemo(() => items.slice(0, 3), [items]);
const others = useMemo(() => items.slice(3), [items]);
const main = items.slice(0, 3);
const others = items.slice(3);

Copilot uses AI. Check for mistakes.
Comment on lines +52 to +53
Copy link

Copilot AI Oct 9, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The useMemo dependencies include 'items' which is a constant array defined outside the component. This will cause unnecessary recalculations on every render. Remove the dependency array or move 'items' inside the component if it needs to be memoized.

Suggested change
const main = useMemo(() => items.slice(0, 3), [items]);
const others = useMemo(() => items.slice(3), [items]);
const main = useMemo(() => items.slice(0, 3), []);
const others = useMemo(() => items.slice(3), []);

Copilot uses AI. Check for mistakes.

const [isOpen, toggleMenu] = useReducer((state) => !state, false);
const closeMenu = (e: MouseEvent<HTMLAnchorElement>) => {
e.stopPropagation();
toggleMenu();
};

return (
<div className="w-full lg:w-auto">
<Button
variant="outline"
size="icon"
className="lg:hidden justify-self-start self-start"
onClick={toggleMenu}
>
<Menu
className={cn(
'!h-[1.2rem] !w-[1.2rem] rotate-0 scale-100 transition-all',
isOpen && '-rotate-90 scale-0',
)}
/>
<X
className={cn(
'absolute !h-[1.2rem] !w-[1.2rem] rotate-90 scale-0 transition-all',
isOpen && 'rotate-0 scale-100',
)}
/>
<span className="sr-only">Toggle menu</span>
</Button>
{/* Mobile menu */}
<nav
className={cn(
'hidden absolute bg-background p-4 top-17 left-0 right-0 z-10 flex-row flex-wrap justify-start items-center gap-4 border-t border-b border-slate-200 dark:border-slate-800 rounded-b-xl shadow-lg overflow-y-auto',
isOpen && 'flex lg:hidden',
)}
>
{items.map((item) => (
<Link
to={item.to}
className="w-full px-4 py-2 rounded-xl font-medium border flex flex-col items-start justify-start shrink-0 text-sm"
activeProps={{
className:
'bg-slate-100 text-slate-900 hover:bg-slate-300 dark:bg-slate-100 dark:text-slate-900 dark:hover:bg-slate-200',
}}
inactiveProps={{
className:
'hover:bg-slate-200 hover:text-slate-900 dark:hover:bg-slate-800 dark:hover:text-slate-100',
}}
key={item.to}
onClick={closeMenu}
>
{item.label}
{item.content && (
<span className="text-muted text-xs">{item.content}</span>
Copy link

Copilot AI Oct 9, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The class 'text-muted' appears to be a custom class that may not be defined in the CSS. Consider using standard Tailwind classes like 'text-muted-foreground' for consistency with the design system.

Suggested change
<span className="text-muted text-xs">{item.content}</span>
<span className="text-muted-foreground text-xs">{item.content}</span>

Copilot uses AI. Check for mistakes.
)}
</Link>
))}
</nav>

{/* Desktop menu */}
<nav className="hidden lg:flex flex-row gap-3">
{main.map((item) => (
<Link
to={item.to}
className="px-4 py-2 rounded-xl font-medium"
activeProps={{
className:
'bg-slate-100 text-slate-900 hover:bg-slate-300 dark:bg-slate-100 dark:text-slate-900 dark:hover:bg-slate-200',
}}
inactiveProps={{
className:
'hover:bg-slate-200 hover:text-slate-900 dark:hover:bg-slate-800 dark:hover:text-slate-100',
}}
key={item.to}
>
{item.label}
</Link>
))}
{items.length > 3 && (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<button className="px-4 py-2 rounded-xl font-medium hover:bg-slate-200 hover:text-slate-900 dark:hover:bg-slate-800 dark:hover:text-slate-100 flex flex-row items-center gap-2">
More <ChevronDown />
</button>
</DropdownMenuTrigger>
<DropdownMenuContent>
{others.map((item) => (
<DropdownMenuItem key={item.to} asChild>
<Link
to={item.to}
activeProps={{
className:
'bg-slate-100 text-slate-900 dark:bg-slate-100 dark:text-slate-900',
}}
>
{item.label}
</Link>
</DropdownMenuItem>
))}
</DropdownMenuContent>
</DropdownMenu>
)}
</nav>
</div>
);
};
Loading