move next explorer to legacy dir + bootstrap new explorer

This commit is contained in:
fmtabbara
2024-12-04 15:42:03 +00:00
committed by Yana
parent 7fdba349ab
commit 6475282ebc
200 changed files with 8338 additions and 4375 deletions
+1 -1
View File
@@ -1,3 +1,3 @@
{
"extends": ["next/core-web-vitals"]
"extends": ["next/core-web-vitals", "next/typescript"]
}
+8 -4
View File
@@ -3,8 +3,12 @@
# dependencies
/node_modules
/.pnp
.pnp.js
.yarn/install-state.gz
.pnp.*
.yarn/*
!.yarn/patches
!.yarn/plugins
!.yarn/releases
!.yarn/versions
# testing
/coverage
@@ -25,8 +29,8 @@ npm-debug.log*
yarn-debug.log*
yarn-error.log*
# local env files
.env*.local
# env files (can opt-in for committing if needed)
.env*
# vercel
.vercel
+4 -4
View File
@@ -1,4 +1,4 @@
This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app).
This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next-app`](https://nextjs.org/docs/app/api-reference/cli/create-next-app).
## Getting Started
@@ -18,7 +18,7 @@ Open [http://localhost:3000](http://localhost:3000) with your browser to see the
You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.
This project uses [`next/font`](https://nextjs.org/docs/basic-features/font-optimization) to automatically optimize and load Inter, a custom Google Font.
This project uses [`next/font`](https://nextjs.org/docs/app/building-your-application/optimizing/fonts) to automatically optimize and load [Geist](https://vercel.com/font), a new font family for Vercel.
## Learn More
@@ -27,10 +27,10 @@ To learn more about Next.js, take a look at the following resources:
- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome!
You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js) - your feedback and contributions are welcome!
## Deploy on Vercel
The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details.
Check out our [Next.js deployment documentation](https://nextjs.org/docs/app/building-your-application/deploying) for more details.
+7
View File
@@ -0,0 +1,7 @@
import type { NextConfig } from "next";
const nextConfig: NextConfig = {
/* config options here */
};
export default nextConfig;
+12 -8
View File
@@ -1,19 +1,23 @@
{
"name": "@nymproject/network-explorer",
"version": "1.0.0",
"name": "@nymproject/explorer_v2",
"version": "0.1.0",
"scripts": {
"dev": "next dev",
"dev": "next dev --turbopack",
"build": "next build",
"build:prod": "yarn --cwd .. build && next build",
"start": "next start",
"lint": "next lint"
},
"dependencies": {
"@emotion/cache": "^11.13.5",
"@emotion/react": "^11.13.5",
"@emotion/styled": "^11.13.5",
"@mui/material": "^6.1.10",
"@mui/material-nextjs": "^6.1.9",
"next": "15.0.3",
"react": "19.0.0-rc-66855b96-20241106",
"react-dom": "19.0.0-rc-66855b96-20241106"
"@nymproject/react": "^1.0.0",
"@nymproject/nym-validator-client": "0.18.0",
"next": "14.1.4",
"react": "^18",
"react-dom": "^18",
"react-error-boundary": "^4.0.13",
"material-react-table": "^2.12.1",
"@mui/x-date-pickers": "7.1.1",
@@ -25,7 +29,7 @@
"@types/react": "^18",
"@types/react-dom": "^18",
"eslint": "^8",
"eslint-config-next": "14.1.4",
"eslint-config-next": "15.0.3",
"typescript": "^5"
}
}
+1
View File
@@ -0,0 +1 @@
<svg fill="none" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><path d="M14.5 13.5V5.41a1 1 0 0 0-.3-.7L9.8.29A1 1 0 0 0 9.08 0H1.5v13.5A2.5 2.5 0 0 0 4 16h8a2.5 2.5 0 0 0 2.5-2.5m-1.5 0v-7H8v-5H3v12a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1M9.5 5V2.12L12.38 5zM5.13 5h-.62v1.25h2.12V5zm-.62 3h7.12v1.25H4.5zm.62 3h-.62v1.25h7.12V11z" clip-rule="evenodd" fill="#666" fill-rule="evenodd"/></svg>

After

Width:  |  Height:  |  Size: 391 B

+1
View File
@@ -0,0 +1 @@
<svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><g clip-path="url(#a)"><path fill-rule="evenodd" clip-rule="evenodd" d="M10.27 14.1a6.5 6.5 0 0 0 3.67-3.45q-1.24.21-2.7.34-.31 1.83-.97 3.1M8 16A8 8 0 1 0 8 0a8 8 0 0 0 0 16m.48-1.52a7 7 0 0 1-.96 0H7.5a4 4 0 0 1-.84-1.32q-.38-.89-.63-2.08a40 40 0 0 0 3.92 0q-.25 1.2-.63 2.08a4 4 0 0 1-.84 1.31zm2.94-4.76q1.66-.15 2.95-.43a7 7 0 0 0 0-2.58q-1.3-.27-2.95-.43a18 18 0 0 1 0 3.44m-1.27-3.54a17 17 0 0 1 0 3.64 39 39 0 0 1-4.3 0 17 17 0 0 1 0-3.64 39 39 0 0 1 4.3 0m1.1-1.17q1.45.13 2.69.34a6.5 6.5 0 0 0-3.67-3.44q.65 1.26.98 3.1M8.48 1.5l.01.02q.41.37.84 1.31.38.89.63 2.08a40 40 0 0 0-3.92 0q.25-1.2.63-2.08a4 4 0 0 1 .85-1.32 7 7 0 0 1 .96 0m-2.75.4a6.5 6.5 0 0 0-3.67 3.44 29 29 0 0 1 2.7-.34q.31-1.83.97-3.1M4.58 6.28q-1.66.16-2.95.43a7 7 0 0 0 0 2.58q1.3.27 2.95.43a18 18 0 0 1 0-3.44m.17 4.71q-1.45-.12-2.69-.34a6.5 6.5 0 0 0 3.67 3.44q-.65-1.27-.98-3.1" fill="#666"/></g><defs><clipPath id="a"><path fill="#fff" d="M0 0h16v16H0z"/></clipPath></defs></svg>

After

Width:  |  Height:  |  Size: 1.0 KiB

+13
View File
@@ -0,0 +1,13 @@
<svg
width="15"
height="15"
viewBox="0 0 15 15"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path d="M3 3L-4.47035e-08 3L-8.31509e-07 6L3 6L3 3Z" fill="currentColor" />
<path d="M6 6L3 6L3 9L6 9L6 6Z" fill="currentColor" />
<path d="M9 9L6 9L6 12L9 12L9 9Z" fill="currentColor" />
<path d="M12 6L9 6L9 9L12 9L12 6Z" fill="currentColor" />
<path d="M15 3L12 3L12 6L15 6L15 3Z" fill="currentColor" />
</svg>

After

Width:  |  Height:  |  Size: 431 B

@@ -0,0 +1,14 @@
<svg
width="9"
height="5"
viewBox="0 0 9 5"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M0.828125 0.828125L4.5 4.5L8.17188 0.828125"
stroke="currentColor"
stroke-linecap="round"
stroke-linejoin="round"
/>
</svg>

After

Width:  |  Height:  |  Size: 256 B

+10
View File
@@ -0,0 +1,10 @@
<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 12 12" fill="none">
<g clip-path="url(#clip0_6568_5882)">
<path d="M4 8H8V9H4V8ZM4 6H8V7H4V6ZM7 1H3C2.45 1 2 1.45 2 2V10C2 10.55 2.445 11 2.995 11H9C9.55 11 10 10.55 10 10V4L7 1ZM9 10H3V2H6.5V4.5H9V10Z" fill="#242B2D" style="fill:#242B2D;fill:color(display-p3 0.1412 0.1686 0.1765);fill-opacity:1;"/>
</g>
<defs>
<clipPath id="clip0_6568_5882">
<rect width="12" height="12" fill="white" style="fill:white;fill-opacity:1;"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 526 B

@@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 12 12" fill="none">
<path d="M2.5 5H2V4H3V4.5H3.5V5H4V5.5H4.5V6H5V6.5H5.5V0.5H6.5V6.5H7V6H7.5V5.5H8V5H8.5V4.5H9V4H10V5H9.5V5.5H9V6H8.5V6.5H8V7H7.5V7.5H7V8H6.5V8.5H5.5V8H5V7.5H4.5V7H4V6.5H3.5V6H3V5.5H2.5V5Z" fill="#242B2D" style="fill:#242B2D;fill:color(display-p3 0.1412 0.1686 0.1765);fill-opacity:1;"/>
<path d="M11 10.5H1V11.5H11V10.5Z" fill="#242B2D" style="fill:#242B2D;fill:color(display-p3 0.1412 0.1686 0.1765);fill-opacity:1;"/>
</svg>

After

Width:  |  Height:  |  Size: 520 B

+14
View File
@@ -0,0 +1,14 @@
<svg viewBox="0 0 89 25" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
d="M0 2.73999C0 1.50288 1.00579 0.5 2.2465 0.5H10.4256C11.8792 0.5 13.1513 1.47412 13.5263 2.87439L18.7506 22.3815C18.8474 22.7432 19.3816 22.6733 19.3816 22.299V0.5H25.8001V22.2599C25.8001 23.497 24.7943 24.4999 23.5536 24.4999H15.314C13.8643 24.4999 12.5946 23.5308 12.216 22.1355L7.04928 3.0892C6.95141 2.72844 6.41855 2.79902 6.41855 3.17275V24.4999H0V2.73999Z"
fill="currentColor"
/>
<path
d="M55.5159 0.500025C54.2752 0.500025 53.2694 1.5029 53.2694 2.74002V24.4999H59.6879V3.18233C59.6879 2.79548 60.2483 2.74066 60.3237 3.12013L64.0601 21.9219C64.3579 23.4203 65.6762 24.4999 67.2082 24.4999L74.6942 24.4999C76.2294 24.4999 77.5496 23.4158 77.8439 21.9135L81.5171 3.16662C81.5916 2.78643 82.153 2.84061 82.153 3.22798V24.4999H88.5714V2.74002C88.5714 1.5029 87.5656 0.500025 86.3249 0.500025L78.3813 0.50002C76.859 0.500019 75.5461 1.56646 75.2383 3.05306L71.2361 22.3844C71.1655 22.7251 70.6773 22.7246 70.6074 22.3838L66.6405 3.05837C66.3349 1.56926 65.0208 0.500019 63.4964 0.50002L55.5159 0.500025Z"
fill="currentColor"
/>
<path
d="M26.5569 0.50009H33.3531L39.2253 13.0169C39.4563 13.5093 40.1589 13.5085 40.3888 13.0155L46.2237 0.50009H53.1458L41.8949 24.5H34.9858L39.4713 14.9H35.3564C34.1107 14.9 32.9775 14.1813 32.4496 13.0563L26.5569 0.50009Z"
fill="currentColor"
/>
</svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

+1 -1
View File
@@ -1 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 283 64"><path fill="black" d="M141 16c-11 0-19 7-19 18s9 18 20 18c7 0 13-3 16-7l-7-5c-2 3-6 4-9 4-5 0-9-3-10-7h28v-3c0-11-8-18-19-18zm-9 15c1-4 4-7 9-7s8 3 9 7h-18zm117-15c-11 0-19 7-19 18s9 18 20 18c6 0 12-3 16-7l-8-5c-2 3-5 4-8 4-5 0-9-3-11-7h28l1-3c0-11-8-18-19-18zm-10 15c2-4 5-7 10-7s8 3 9 7h-19zm-39 3c0 6 4 10 10 10 4 0 7-2 9-5l8 5c-3 5-9 8-17 8-11 0-19-7-19-18s8-18 19-18c8 0 14 3 17 8l-8 5c-2-3-5-5-9-5-6 0-10 4-10 10zm83-29v46h-9V5h9zM37 0l37 64H0L37 0zm92 5-27 48L74 5h10l18 30 17-30h10zm59 12v10l-3-1c-6 0-10 4-10 10v15h-9V17h9v9c0-5 6-9 13-9z"/></svg>
<svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1155 1000"><path d="m577.3 0 577.4 1000H0z" fill="#fff"/></svg>

Before

Width:  |  Height:  |  Size: 629 B

After

Width:  |  Height:  |  Size: 128 B

+1
View File
@@ -0,0 +1 @@
<svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path fill-rule="evenodd" clip-rule="evenodd" d="M1.5 2.5h13v10a1 1 0 0 1-1 1h-11a1 1 0 0 1-1-1zM0 1h16v11.5a2.5 2.5 0 0 1-2.5 2.5h-11A2.5 2.5 0 0 1 0 12.5zm3.75 4.5a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5M7 4.75a.75.75 0 1 1-1.5 0 .75.75 0 0 1 1.5 0m1.75.75a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5" fill="#666"/></svg>

After

Width:  |  Height:  |  Size: 385 B

+16
View File
@@ -0,0 +1,16 @@
import { Wrapper } from "@/components/wrapper";
import { Box, Typography } from "@mui/material";
export default function ExplorerPage() {
return (
<div>
<main>
<Box sx={{ p: 5 }}>
<Wrapper>
<Typography fontWeight="light">Explorer page</Typography>
</Wrapper>
</Box>
</main>
</div>
);
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

+37
View File
@@ -0,0 +1,37 @@
:root {
--max-width: 1120px;
--border-radius: 8px;
}
@media (prefers-color-scheme: dark) {
:root {
--background-start-rgb: 0, 0, 0;
--background-end-rgb: 0, 0, 0;
}
}
* {
box-sizing: border-box;
padding: 0;
margin: 0;
}
html,
body {
max-width: 100vw;
overflow-x: hidden;
}
a {
color: inherit;
text-decoration: none;
}
@media (prefers-color-scheme: dark) {
html {
color-scheme: dark;
}
}
.MuiCardActionArea-focusHighlight {
background: transparent;
}
+25
View File
@@ -0,0 +1,25 @@
import { Header } from "@/components/header";
import ThemeProvider from "@/providers/ThemeProvider";
import type { Metadata } from "next";
export const metadata: Metadata = {
title: "Create Next App",
description: "Generated by create next app",
};
export default function RootLayout({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
return (
<html lang="en">
<body>
<ThemeProvider>
<Header />
{children}
</ThemeProvider>
</body>
</html>
);
}
@@ -0,0 +1,16 @@
import { Wrapper } from "@/components/wrapper";
import { Box, Typography } from "@mui/material";
export default function OnboardingPage() {
return (
<div>
<main>
<Box sx={{ p: 5 }}>
<Wrapper>
<Typography fontWeight="light">Onboarding page</Typography>
</Wrapper>
</Box>
</main>
</div>
);
}
+18
View File
@@ -0,0 +1,18 @@
import { Wrapper } from "@/components/wrapper";
import { Box, Typography } from "@mui/material";
export default function Home() {
return (
<div>
<main>
<Box sx={{ p: 5 }}>
<Wrapper>
<Typography fontWeight="light">
🚀 EXPLORER 2.0, Let&apos;s go! 🚀
</Typography>
</Wrapper>
</Box>
</main>
</div>
);
}
+16
View File
@@ -0,0 +1,16 @@
import { Wrapper } from "@/components/wrapper";
import { Box, Typography } from "@mui/material";
export default function OnboardingPage() {
return (
<div>
<main>
<Box sx={{ p: 5 }}>
<Wrapper>
<Typography fontWeight="light">Stake page</Typography>
</Wrapper>
</Box>
</main>
</div>
);
}
@@ -0,0 +1,124 @@
"use client";
import { colours } from "@/theme/colours";
import { Button as MUIButton } from "@mui/material";
import CircularProgress from "@mui/material/CircularProgress";
import Typography from "@mui/material/Typography";
import type { Theme } from "@mui/material/styles";
import Link from "next/link";
import type { ButtonProps } from "./types";
export const Button = ({
text,
handleClick,
goToLink,
isSuccess,
isDisabled,
isTextButton,
isSmall,
isXtraSmall,
isFullWidth,
isSecondary,
isContrast,
sx,
buttonId,
type,
isLoading,
startIcon,
endIcon,
}: ButtonProps) => {
const onClick = () => {
if (goToLink) {
} else if (handleClick) {
handleClick();
}
};
const fontColor = (t: Theme) => {
if (isTextButton) return "primary.main";
if (isSecondary)
return isContrast ? "common.white" : "primary.contrastText";
return t.palette.mode === "light"
? t.palette.common.white
: t.palette.common.black;
};
const bgColor = (t: Theme) => {
if (isTextButton || isSecondary) return "transparent";
if (isDisabled)
return t.palette.mode === "light" ? colours.pine[200] : colours.pine[800];
return isSuccess ? "success.main" : "primary.main";
};
const hoverBgColor = () => {
if (isTextButton || isSecondary) return "transparent";
return isSuccess
? colours.green[500]
: colours.pine[isDisabled ? 200 : 950];
};
const padding = isTextButton
? "none"
: isXtraSmall
? "10px 23px"
: isSmall
? "11px 23px"
: "15px 23px";
const CustomButtom = (
<MUIButton
type={type}
sx={{
textDecoration: "none",
textAlign: "center",
p: padding,
borderRadius: 2,
width: isFullWidth ? "100%" : "fit-content",
height: isSmall ? 48 : 64,
color: (t) => fontColor(t),
letterSpacing: 0.45,
backgroundColor: (t) => bgColor(t),
border: isSecondary
? (t) =>
isDisabled
? `1px solid ${t.palette.primary.main}`
: `1px solid ${t.palette.primary.contrastText}`
: "1px solid transparent",
"&:hover": {
backgroundColor: (t) => hoverBgColor(t),
},
"&:disabled": {
color: "text.disabled",
},
...sx,
}}
disabled={isDisabled}
onClick={onClick}
id={buttonId}
startIcon={startIcon}
endIcon={endIcon}
>
{!isLoading ? (
<Typography
variant={isSmall ? "body1" : isXtraSmall ? "body2" : "button"}
sx={{
textTransform: "none",
fontWeight: "inherit",
letterSpacing: 0,
}}
>
{text}
</Typography>
) : (
<CircularProgress
size={isSmall ? 20 : 24}
sx={{ color: (t) => fontColor(t) }}
/>
)}
</MUIButton>
);
return goToLink ? (
<Link href={goToLink.path} target={goToLink.target}>
{CustomButtom}
</Link>
) : (
CustomButtom
);
};
@@ -0,0 +1,31 @@
import type { SxProps } from "@mui/system"; // Asegúrate de importar SxProps si estás usando @mui/system
export type CommonButtonProps = {
text: string;
isSuccess?: boolean;
isDisabled?: boolean;
isTextButton?: boolean;
isSmall?: boolean;
isXtraSmall?: boolean;
isFullWidth?: boolean;
isSecondary?: boolean;
isContrast?: boolean;
sx?: SxProps;
isLoading?: boolean;
buttonId?: string;
type?: "button" | "submit" | "reset";
startIcon?: React.ReactNode;
endIcon?: React.ReactNode;
};
export type ButtonWithClick = CommonButtonProps & {
handleClick: (() => void) | (() => Promise<void>) | (() => null);
goToLink?: never;
};
export type ButtonWithLink = CommonButtonProps & {
goToLink: { path: string; target: "_self" | "_blank" | "_parent" | "_top" };
handleClick?: never;
};
export type ButtonProps = ButtonWithClick | ButtonWithLink;
@@ -0,0 +1,63 @@
import Button, {
type ButtonProps as MUIButtonProps,
} from "@mui/material/Button";
import Link from "next/link";
import type React from "react";
interface ButtonOrLinkProps extends Omit<MUIButtonProps, "variant"> {
href?: string;
variant?: "outlined" | "contained" | "text";
isSelected?: boolean;
}
export const ButtonOrLink: React.FC<ButtonOrLinkProps> = ({
href,
variant = "contained",
isSelected,
children,
...props
}) => {
const selectedStyle = {
contained: {
outline: "1px solid",
outlineColor: "primary.main",
borderColor: "primary.main",
},
outlined: {
borderStyle: "solid",
backgroundColor: "primary.main",
color: "background.main",
"&:hover": {
backgroundColor: "primary.main",
},
},
text: {
color: "primary.main",
},
};
return href ? (
<Button
sx={{
...(isSelected && selectedStyle[variant]),
textAlign: "center",
}}
component={Link}
href={href}
variant={variant}
{...props}
>
{children}
</Button>
) : (
<Button
sx={{
...(isSelected && selectedStyle[variant]),
textAlign: "center",
}}
variant={variant}
{...props}
>
{children}
</Button>
);
};
@@ -0,0 +1,22 @@
import { Link } from "@/components/muiLink";
import type { Languages } from "@/i18n";
import UserIcon from "@/public/icons/user.svg";
export const AccountButton = ({ locale }: { locale: Languages }) => {
return (
<Link
href={`/${locale}/account/login`}
sx={{
display: "flex",
justifyContent: "center",
alignItems: "center",
aspectRatio: "1",
height: "30px",
width: "30px",
flexShrink: 0,
}}
>
<UserIcon />
</Link>
);
};
@@ -0,0 +1,105 @@
"use client";
import { Box, Button, Divider } from "@mui/material";
import type React from "react";
import { Wrapper } from "@/components/wrapper";
import { Link } from "@/components/muiLink";
import NymLogo from "@/components/icons/NymLogo";
import { subtitles } from "@/theme/typography";
const DUMMY_MENU_DATA = [
{
id: 1,
title: "Explorer",
url: "/explorer",
},
{
id: 2,
title: "Stake",
url: "/stake",
},
{
id: 3,
title: "Onboarding",
url: "/onboarding",
},
];
export const DesktopHeader = () => {
return (
<Box
sx={{
display: { xs: "none", lg: "block" },
height: "115px",
alignItems: "center",
}}
>
<Wrapper
sx={{
display: "flex",
justifyContent: "space-between",
alignItems: "center",
gap: "42px",
height: "100%",
}}
>
<Link
href={"/"}
style={{
display: "flex",
alignItems: "center",
width: "100px",
aspectRatio: "89/25",
}}
>
<NymLogo />
</Link>
<Box
sx={{
display: "flex",
flexGrow: 1,
alignItems: "center",
justifyContent: "start",
height: "100%",
gap: 5,
}}
>
{DUMMY_MENU_DATA.map((menu) => (
<Button
key={menu.title}
href={menu.url}
sx={{
borderRadius: 0,
padding: 0,
minWidth: "auto",
display: "flex",
justifyContent: "center",
alignItems: "center",
gap: "10px",
height: "100%",
...subtitles.subtitle1,
"& .MuiButton-endIcon": {
marginLeft: 0,
marginRight: 0,
},
"& .MuiButton-startIcon": {
marginLeft: 0,
marginRight: 0,
},
"&:hover": {
textDecoration: "none",
},
}}
>
{menu.title}
</Button>
))}
</Box>
<Button variant="contained" size="small">
Connect Wallet
</Button>
</Wrapper>
<Divider variant="fullWidth" sx={{ width: "100%" }} />
</Box>
);
};
@@ -0,0 +1,10 @@
import { DesktopHeader } from "./DesktopHeader";
export const Header = async () => {
return (
<header>
<DesktopHeader />
{/* Mobile header will go here */}
</header>
);
};
@@ -0,0 +1,7 @@
import Document from "@/public/icons/document.svg";
import Download from "@/public/icons/download.svg";
export const NavigationIcons = {
article: Document,
download: Download,
};
@@ -0,0 +1,14 @@
import Image from "next/image";
const ChevronMenu = () => {
return (
<Image
src="/icons/chevronMenu.svg"
alt="Chevron Menu"
width={24}
height={24}
/>
);
};
export default ChevronMenu;
@@ -0,0 +1,8 @@
import Image from "next/image";
const NymLogo = () => {
return (
<Image src="/icons/nym-logo.svg" alt="Nym Logo" width={90} height={25} />
);
};
export default NymLogo;
@@ -0,0 +1,28 @@
// Imports
import { Link as MuiLink, type LinkProps as MuiLinkProps } from "@mui/material";
import NextLink, { type LinkProps as NextLinkProps } from "next/link";
import type { ReactNode } from "react";
interface CustomLinkProps extends NextLinkProps, Omit<MuiLinkProps, "href"> {
href: string;
children: ReactNode;
}
// Component definition
export const Link = ({ href, children, ...props }: CustomLinkProps) => {
return (
<MuiLink
component={NextLink}
href={href}
{...props}
sx={{
display: "flex",
alignItems: "center",
...(props.sx || {}),
}}
>
{children}
</MuiLink>
);
};
@@ -0,0 +1,21 @@
import { Box } from "@mui/material";
import type { BoxProps } from "@mui/system";
export type WrapperProps = BoxProps;
export function Wrapper({ children, sx, ...props }: WrapperProps) {
return (
<Box
sx={{
mx: "auto",
maxWidth: "1378px",
width: "100%",
px: "30px",
...sx,
}}
{...props}
>
{children}
</Box>
);
}
@@ -0,0 +1,2 @@
Letters from Sweden End User License Agreement (EULA)
http://lettersfromsweden.se/license
@@ -0,0 +1,2 @@
Letters from Sweden End User License Agreement (EULA)
http://lettersfromsweden.se/license
+85
View File
@@ -0,0 +1,85 @@
// Fonts
import localFont from "next/font/local";
// LabGrotesqueMono
export const labGrotesqueMono = localFont({
src: [
{
path: "./LabGrotesqueMono/LabGrotesqueMono-Regular.woff2",
weight: "400",
style: "normal",
},
{
path: "./LabGrotesqueMono/LabGrotesqueMono-Bold.woff2",
weight: "700",
style: "normal",
},
],
});
// LabGrotesque
export const labGrotesque = localFont({
src: [
{
path: "./LabGrotesque/LabGrotesque-Thin.woff2",
weight: "100",
style: "normal",
},
{
path: "./LabGrotesque/LabGrotesque-ThinItalic.woff2",
weight: "100",
style: "italic",
},
{
path: "./LabGrotesque/LabGrotesque-Light.woff2",
weight: "300",
style: "normal",
},
{
path: "./LabGrotesque/LabGrotesque-LightItalic.woff2",
weight: "300",
style: "italic",
},
{
path: "./LabGrotesque/LabGrotesque-Regular.woff2",
weight: "400",
style: "normal",
},
{
path: "./LabGrotesque/LabGrotesque-Italic.woff2",
weight: "400",
style: "italic",
},
{
path: "./LabGrotesque/LabGrotesque-Medium.woff2",
weight: "500",
style: "normal",
},
{
path: "./LabGrotesque/LabGrotesque-MediumItalic.woff2",
weight: "500",
style: "italic",
},
{
path: "./LabGrotesque/LabGrotesque-Bold.woff2",
weight: "700",
style: "normal",
},
{
path: "./LabGrotesque/LabGrotesque-BoldItalic.woff2",
weight: "700",
style: "italic",
},
{
path: "./LabGrotesque/LabGrotesque-Black.woff2",
weight: "900",
style: "normal",
},
{
path: "./LabGrotesque/LabGrotesque-BlackItalic.woff2",
weight: "900",
style: "italic",
},
],
});
@@ -0,0 +1,18 @@
"use client";
import { AppRouterCacheProvider } from "@mui/material-nextjs/v15-appRouter";
import { CssBaseline } from "@mui/material";
import { ThemeProvider as MUIThemeProvider } from "@mui/material";
import { lightTheme } from "@/theme/theme";
const ThemeProvider = ({ children }: { children: React.ReactNode }) => {
return (
<AppRouterCacheProvider>
<MUIThemeProvider theme={lightTheme}>
<CssBaseline />
{children}
</MUIThemeProvider>
</AppRouterCacheProvider>
);
};
export default ThemeProvider;
+7
View File
@@ -0,0 +1,7 @@
import ThemeProvider from "./ThemeProvider";
const Providers = ({ children }: { children: React.ReactNode }) => {
return <ThemeProvider>{children}</ThemeProvider>;
};
export default Providers;
+27
View File
@@ -0,0 +1,27 @@
export const colours = {
alert: {
success: "#00CA33",
warning: "#F9BE2B",
error: "#E01400",
},
green: {
500: "#14e76f",
},
haze: {
200: "#DAE0EB",
300: "#C4CCDE",
},
pine: {
200: "#CAD6D7",
800: "#3E4A4C",
950: "#242B2D",
},
base: {
white: "#FFFFFF",
black: "#000000",
transparent: "transparent",
},
gray: {
50: "#F5F6F6",
},
};
@@ -0,0 +1,31 @@
.reactMarkDown {
padding: 0px;
margin: 0px;
margin-top: 0px;
line-height: unset;
border: 0px;
margin: 0px;
font-size: 16px;
display: inline;
}
.reactMarkDown p {
margin: 0px;
font-size: 16px;
}
.reactMarkDownLink {
display: inline;
}
.reactMarkDownLink p {
margin: 7px 0px;
font-size: 14px;
display: inline-block;
}
.reactMarkDownLink a {
font-size: 14px;
color: #fb6e4e;
display: inline;
}
+71
View File
@@ -0,0 +1,71 @@
import type { CSSProperties } from "react";
// Define allowed values for textTransform
type TextTransform = "none" | "capitalize" | "uppercase" | "lowercase";
// Define a custom type for typography variants that includes textTransform
type CustomTypography = CSSProperties & { textTransform?: TextTransform };
declare module "@mui/material/styles" {
interface Palette {
accent: Palette["primary"];
backgroundColor: Palette["background"];
medium: Palette["primary"];
light: Palette["primary"];
gray: Palette["primary"];
}
interface PaletteOptions {
accent?: PaletteOptions["primary"];
backgroundColor?: PaletteOptions["background"];
medium?: PaletteOptions["primary"];
light?: PaletteOptions["primary"];
gray?: PaletteOptions["primary"];
}
// Apply CustomTypography to TypographyVariants
interface TypographyVariants {
display: CustomTypography;
h1: CustomTypography;
h2: CustomTypography;
h3: CustomTypography;
h4: CustomTypography;
h5: CustomTypography;
h6: CustomTypography;
subtitle1: CustomTypography;
subtitle2: CustomTypography;
subtitle3: CustomTypography;
body3?: CustomTypography;
body4?: CustomTypography;
body5?: CustomTypography;
prose?: CustomTypography;
}
// Apply CustomTypography to TypographyVariantsOptions
interface TypographyVariantsOptions {
display?: CustomTypography;
h1?: CustomTypography;
h2?: CustomTypography;
h3?: CustomTypography;
h4?: CustomTypography;
h5?: CustomTypography;
h6?: CustomTypography;
subtitle1?: CustomTypography;
subtitle2?: CustomTypography;
subtitle3?: CustomTypography;
body3?: CustomTypography;
body4?: CustomTypography;
body5?: CustomTypography;
prose?: CustomTypography;
}
}
declare module "@mui/material/Typography" {
interface TypographyPropsVariantOverrides {
display: true;
subtitle3: true;
body3: true;
body4: true;
body5: true;
prose: true;
}
}
+288
View File
@@ -0,0 +1,288 @@
import { labGrotesque } from "@/fonts";
import { colours } from "@/theme/colours";
import { body, headings, subtitles } from "@/theme/typography";
import { type ThemeOptions, createTheme } from "@mui/material/styles";
const lightMode = {
mode: "light" as const,
accent: colours.green[500],
primary: colours.pine[950],
background: colours.haze[300],
medium: colours.haze[200],
light: colours.base.white,
};
const darkMode = {
mode: "dark" as const,
accent: colours.green[500],
primary: colours.base.white,
background: colours.pine[950],
medium: colours.pine[800],
light: colours.pine[200],
};
// createDesignTokens function to generate design tokens based on mode
const createDesignTokens = (mode: "light" | "dark") => {
const palette = mode === "light" ? lightMode : darkMode;
return {
palette: {
mode: palette.mode,
primary: {
main: palette.primary,
},
background: {
default: palette.background,
main: palette.background,
paper: palette.light,
},
secondary: {
main: palette.accent,
},
text: {
primary: palette.primary,
secondary: palette.medium,
},
success: {
main: colours.alert.success,
},
warning: {
main: colours.alert.warning,
},
error: {
main: colours.alert.error,
},
medium: {
main: palette.medium,
},
accent: {
main: palette.accent,
},
light: {
main: palette.light,
},
base: {
white: colours.base.white,
black: colours.base.black,
transparent: colours.base.transparent,
},
...colours.gray,
},
typography: {
fontFamily: labGrotesque?.style?.fontFamily,
weight: 300,
...headings,
...subtitles,
...body,
prose: {
...body.body2,
"& * > *": {
marginBlockEnd: "30px",
},
"& h1": {
...headings.h1,
},
"& h2": {
...headings.h2,
},
"& h3": {
...headings.h3,
},
"& h4": {
...headings.h4,
},
"& h5": {
...headings.h5,
},
"& h6": {
...headings.h6,
},
"& p": {
...body.body2,
},
"& a": {
color: palette.primary,
textDecoration: "underline",
},
"& ul, & ol": {
listStyleType: "disc",
paddingLeft: "1.5rem",
margin: "1rem 0",
},
"& li": {
marginBottom: "0.5rem",
},
"& blockquote": {
borderLeft: `4px solid ${palette.primary}`,
paddingLeft: "1rem",
margin: "1rem 0",
},
"& hr": {
border: 0,
height: 1,
borderTop: `1px dashed ${palette.primary}`,
},
"& table": {
width: "100%",
borderCollapse: "collapse",
borderSpacing: 0,
"& th, & td": {
borderBottom: `1px solid ${palette.background}`,
paddingBlock: "0.5rem",
textAlign: "left",
},
"& tr:last-of-type td": {
borderBottom: "none",
},
"& th": {
backgroundColor: palette.light,
fontWeight: 700,
color: palette.background,
},
},
},
},
};
};
// Function to create MUI theme with additional options
const getTheme = (mode: "light" | "dark"): ThemeOptions => {
const designTokens = createDesignTokens(mode);
return {
...designTokens,
components: {
// Add component customizations here if needed
MuiButtonBase: {
defaultProps: {
disableRipple: true,
disableTouchRipple: true,
},
},
MuiInputBase: {
styleOverrides: {
root: {
fontSize: "16px",
backgroundColor: colours.base.white,
color: designTokens.palette.background.main,
},
},
},
MuiButton: {
styleOverrides: {
root: {
...designTokens.typography.subtitle1,
boxShadow: "none",
outline: "none",
fontSize: "16px",
borderRadius: "32px",
padding: "16px 24px",
variants: [
{
props: { size: "medium" },
style: {
fontSize: "16px",
borderRadius: "32px",
padding: "16px 24px",
},
},
{
props: { size: "small" },
style: {
fontSize: "14px",
padding: "8px 16px",
},
},
{
props: { variant: "outlined" },
style: {
border: `1px dashed ${designTokens.palette.primary.main}`,
"&:hover": {
backgroundColor: "transparent",
borderStyle: "solid",
},
"&:active": {
borderStyle: "solid",
backgroundColor: designTokens.palette.primary.main,
color: designTokens.palette.background.main,
boxShadow: "none",
},
"&:focus-visible": {
boxShadow: `0 0 4px 0 ${designTokens.palette.primary.main}`,
borderStyle: "solid",
},
"&:disabled": {
border: `1px solid ${designTokens.palette.primary.main}`,
color: designTokens.palette.primary.main,
background: "transparent",
opacity: 0.5,
},
},
},
{
props: { variant: "contained" },
style: {
backgroundColor: designTokens.palette.accent.main,
color: designTokens.palette.base.black,
border: `1px solid ${designTokens.palette.accent.main}`,
"&:hover": {
borderColor: designTokens.palette.primary.main,
},
"&:focus-visible": {
boxShadow: `0 0 4px 0 ${designTokens.palette.primary.main}`,
borderStyle: "solid",
},
"&:active": {
outline: `1px solid ${designTokens.palette.primary.main}`,
},
"&:disabled": {
backgroundColor: designTokens.palette.primary.main,
color: designTokens.palette.background.main,
borderColor: designTokens.palette.primary.main,
opacity: 0.5,
},
},
},
{
props: { variant: "text" },
style: {
backgroundColor: "transparent",
color: designTokens.palette.primary.main,
"&:hover": {
backgroundColor: "transparent",
color: designTokens.palette.primary.main,
textDecoration: "underline",
},
"&:focus-visible": {
boxShadow: `0 0 4px 0 ${designTokens.palette.primary.main}`,
borderStyle: "solid",
},
"&:active": {
outline: "none",
borderColor: "transparent",
},
"&:disabled": {
color: designTokens.palette.primary.main,
opacity: 0.5,
},
},
},
],
},
},
},
// remove border radius from paper
MuiPaper: {
styleOverrides: {
root: {
borderRadius: 0,
},
},
},
},
};
};
// Create light and dark themes
const lightTheme = createTheme(getTheme("light"));
const darkTheme = createTheme(getTheme("dark"));
export { lightTheme, darkTheme, getTheme };
+133
View File
@@ -0,0 +1,133 @@
import { labGrotesque, labGrotesqueMono } from "@/fonts";
export const headings = {
display: {
fontFamily: labGrotesque?.style?.fontFamily,
fontWeight: 400,
fontSize: 208,
lineHeight: 1,
textTransform: "uppercase" as const,
"@media (max-width: 768px)": {
fontSize: 68,
},
},
h1: {
fontSize: 40,
lineHeight: 1.2,
fontWeight: 400,
textTransform: "uppercase" as const,
"@media (max-width: 768px)": {
fontSize: 24,
},
},
h2: {
fontSize: 32,
lineHeight: "38px",
fontWeight: 400,
textTransform: "uppercase" as const,
"@media (max-width: 768px)": {
fontSize: 24,
},
},
h3: {
fontFamily: labGrotesqueMono?.style?.fontFamily,
fontSize: 24,
lineHeight: "29px",
letterSpacing: "5%",
textTransform: "uppercase" as const,
"@media (max-width: 768px)": {
fontSize: 18,
},
},
h4: {
fontFamily: labGrotesqueMono?.style?.fontFamily,
fontSize: 20,
lineHeight: "24px",
letterSpacing: "5%",
textTransform: "uppercase" as const,
"@media (max-width: 768px)": {
fontSize: 18,
},
},
h5: {
fontFamily: labGrotesqueMono?.style?.fontFamily,
fontSize: 20,
lineHeight: "24px",
letterSpacing: "5%",
textTransform: "uppercase" as const,
"@media (max-width: 768px)": {
fontSize: 18,
},
},
h6: {
fontFamily: labGrotesqueMono?.style?.fontFamily,
fontSize: 20,
lineHeight: "24px",
letterSpacing: "5%",
textTransform: "uppercase" as const,
"@media (max-width: 768px)": {
fontSize: 18,
},
},
};
export const subtitles = {
subtitle1: {
fontFamily: labGrotesqueMono?.style?.fontFamily,
textTransform: "uppercase" as const,
fontWeight: 400,
size: 16,
lineHeight: "19px",
letterSpacing: "5%",
},
subtitle2: {
fontFamily: labGrotesqueMono?.style?.fontFamily,
textTransform: "uppercase" as const,
fontWeight: 400,
fontSize: 14,
lineHeight: "17px",
letterSpacing: "5%",
},
subtitle3: {
fontFamily: labGrotesqueMono?.style?.fontFamily,
textTransform: "uppercase" as const,
fontWeight: 400,
fontSize: 12,
lineHeight: "14.4px",
letterSpacing: "5%",
},
};
export const body = {
body1: {
fontSize: "24px",
lineHeight: "33.6px",
fontWeight: 400,
"@media (max-width: 768px)": {
fontSize: 18,
},
},
body2: {
fontSize: "20px",
lineHeight: "28px",
fontWeight: 300,
"@media (max-width: 768px)": {
fontSize: 18,
},
},
body3: {
fontSize: "16px",
lineHeight: "22.4px",
fontWeight: 300,
},
body4: {
fontSize: "14px",
lineHeight: 1.4,
fontWeight: 300,
},
body5: {
fontSize: "12px",
lineHeight: "16.8px",
fontWeight: 300,
},
};
+8 -21
View File
@@ -1,16 +1,14 @@
{
"compilerOptions": {
"lib": [
"dom",
"dom.iterable",
"esnext"
],
"target": "ES2017",
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"skipLibCheck": true,
"strict": true,
"noEmit": true,
"esModuleInterop": true,
"module": "CommonJS",
"module": "esnext",
"moduleResolution": "bundler",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "preserve",
@@ -21,23 +19,12 @@
}
],
"paths": {
"@/*": [
"./*"
],
"@/public/*": ["./public/*"],
"@/*": ["./src/*"],
"@assets/*": [
"../assets/*"
]
},
"moduleResolution": "node",
"target": "ES2017"
},
"include": [
"next-env.d.ts",
"**/*.ts",
"**/*.tsx",
".next/types/**/*.ts"
],
"exclude": [
"node_modules"
]
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
"exclude": ["node_modules"]
}
+3
View File
@@ -0,0 +1,3 @@
{
"extends": ["next/core-web-vitals"]
}
+36
View File
@@ -0,0 +1,36 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies
/node_modules
/.pnp
.pnp.js
.yarn/install-state.gz
# testing
/coverage
# next.js
/.next/
/out/
# production
/build
# misc
.DS_Store
*.pem
# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# local env files
.env*.local
# vercel
.vercel
# typescript
*.tsbuildinfo
next-env.d.ts
+36
View File
@@ -0,0 +1,36 @@
This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app).
## Getting Started
First, run the development server:
```bash
npm run dev
# or
yarn dev
# or
pnpm dev
# or
bun dev
```
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.
This project uses [`next/font`](https://nextjs.org/docs/basic-features/font-optimization) to automatically optimize and load Inter, a custom Google Font.
## Learn More
To learn more about Next.js, take a look at the following resources:
- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome!
## Deploy on Vercel
The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details.

Some files were not shown because too many files have changed in this diff Show More