Skip to content

Commit b952f18

Browse files
chore(insights): add mobile menu component with styles and update stats rendering in PriceFeeds
1 parent 4e034a6 commit b952f18

20 files changed

+426
-77
lines changed

apps/insights/.env.development

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
DISABLE_ACCESSIBILITY_REPORTING=true

apps/insights/src/components/CopyButton/index.tsx

-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ export const CopyButton = ({ text, children, className, ...props }: Props) => {
2727
const [isCopied, setIsCopied] = useState(false);
2828
const logger = useLogger();
2929
const copy = useCallback(() => {
30-
// eslint-disable-next-line n/no-unsupported-features/node-builtins
3130
navigator.clipboard
3231
.writeText(text)
3332
.then(() => {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
@use "@pythnetwork/component-library/theme";
2+
3+
.mobileMenuTrigger {
4+
display: none;
5+
6+
@include theme.mobile {
7+
display: block;
8+
}
9+
}
10+
11+
.mobileMenuOverlay {
12+
background: rgb(0 0 0 / 40%);
13+
position: fixed;
14+
inset: 0;
15+
z-index: 999;
16+
}
17+
18+
.mobileMenuContainer {
19+
border-top-left-radius: theme.border-radius("2xl");
20+
border-top-right-radius: theme.border-radius("2xl");
21+
background: theme.color("background", "modal");
22+
position: absolute;
23+
bottom: 0;
24+
left: 0;
25+
right: 0;
26+
padding: 1rem;
27+
display: flex;
28+
flex-flow: column nowrap;
29+
gap: theme.spacing(4);
30+
}
31+
32+
.mobileMenuHandle {
33+
background: theme.color("background", "secondary");
34+
width: 33%;
35+
height: 6px;
36+
border-radius: theme.border-radius("full");
37+
align-self: center;
38+
}
39+
40+
.mobileThemeSwitcher {
41+
display: flex;
42+
flex-flow: row nowrap;
43+
justify-content: space-between;
44+
align-items: center;
45+
}
46+
47+
.mobileThemeSwitcherFeedback {
48+
display: flex;
49+
flex-flow: row nowrap;
50+
align-items: center;
51+
gap: theme.spacing(3);
52+
text-transform: capitalize;
53+
font-weight: theme.font-weight("medium");
54+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
"use client";
2+
import { Lifebuoy } from "@phosphor-icons/react/dist/ssr/Lifebuoy";
3+
import { List } from "@phosphor-icons/react/dist/ssr/List";
4+
import { X } from "@phosphor-icons/react/dist/ssr/X";
5+
import { Button } from "@pythnetwork/component-library/Button";
6+
import clsx from "clsx";
7+
import { useTheme } from "next-themes";
8+
import { useState } from "react";
9+
10+
import styles from "./mobile-menu.module.scss";
11+
import { SupportDrawer } from "../Root/support-drawer";
12+
import { ThemeSwitch } from "../Root/theme-switch";
13+
14+
export const MobileMenu = ({
15+
className,
16+
...props
17+
}: {
18+
className?: string | string[];
19+
}) => {
20+
const { theme } = useTheme();
21+
const [isOpen, setIsOpen] = useState(false);
22+
23+
const toggleMenu = () => {
24+
setIsOpen(!isOpen);
25+
};
26+
27+
return (
28+
<div className={clsx(styles.mobileMenuTrigger, className)} {...props}>
29+
<Button
30+
variant="ghost"
31+
size="sm"
32+
afterIcon={List}
33+
rounded
34+
onPress={toggleMenu}
35+
>
36+
Menu
37+
</Button>
38+
{isOpen && (
39+
<div className={styles.mobileMenuOverlay}>
40+
<div className={styles.mobileMenuContainer}>
41+
<div className={styles.mobileMenuHandle} />
42+
<Button
43+
href="https://docs.pyth.network"
44+
size="md"
45+
rounded
46+
target="_blank"
47+
>
48+
Dev Docs
49+
</Button>
50+
<SupportDrawer>
51+
<Button beforeIcon={Lifebuoy} variant="ghost" size="md" rounded>
52+
Support
53+
</Button>
54+
</SupportDrawer>
55+
<div className={styles.mobileThemeSwitcher}>
56+
<div>Theme</div>
57+
<div className={styles.mobileThemeSwitcherFeedback}>
58+
<div>{theme}</div>
59+
<ThemeSwitch />
60+
</div>
61+
</div>
62+
<Button
63+
variant="outline"
64+
afterIcon={X}
65+
rounded
66+
onPress={toggleMenu}
67+
>
68+
Close
69+
</Button>
70+
</div>
71+
</div>
72+
)}
73+
</div>
74+
);
75+
};

apps/insights/src/components/PriceFeeds/index.tsx

+31-28
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import { YesterdaysPricesProvider, ChangePercent } from "../ChangePercent";
2323
import { LivePrice } from "../LivePrices";
2424
import { PriceFeedIcon } from "../PriceFeedIcon";
2525
import { PriceFeedTag } from "../PriceFeedTag";
26+
import { Stats } from "../Stats";
2627

2728
const PRICE_FEEDS_ANCHOR = "priceFeeds";
2829

@@ -48,7 +49,7 @@ export const PriceFeeds = async () => {
4849
<div className={styles.priceFeeds}>
4950
<h1 className={styles.header}>Price Feeds</h1>
5051
<div className={styles.body}>
51-
<section className={styles.stats}>
52+
<Stats>
5253
<StatCard
5354
variant="primary"
5455
header="Active Feeds"
@@ -74,7 +75,7 @@ export const PriceFeeds = async () => {
7475
corner={<Info weight="fill" />}
7576
/>
7677
</AssetClassesDrawer>
77-
</section>
78+
</Stats>
7879
<YesterdaysPricesProvider
7980
feeds={Object.fromEntries(
8081
featuredRecentlyAdded.map(({ symbol, product }) => [
@@ -165,32 +166,34 @@ const FeaturedFeedsCard = <T extends ElementType>({
165166
}: FeaturedFeedsCardProps<T>) => (
166167
<Card {...props}>
167168
<div className={styles.featuredFeeds}>
168-
{feeds.map((feed) => (
169-
<Card
170-
key={feed.product.price_account}
171-
variant="tertiary"
172-
{...(linkFeeds && {
173-
href: `/price-feeds/${encodeURIComponent(feed.symbol)}`,
174-
})}
175-
>
176-
<div className={styles.feedCardContents}>
177-
<PriceFeedTag
178-
symbol={feed.product.display_symbol}
179-
description={feed.product.description}
180-
icon={<PriceFeedIcon symbol={feed.product.display_symbol} />}
181-
/>
182-
{showPrices && (
183-
<div className={styles.prices}>
184-
<LivePrice feedKey={feed.product.price_account} />
185-
<ChangePercent
186-
className={styles.changePercent}
187-
feedKey={feed.product.price_account}
188-
/>
189-
</div>
190-
)}
191-
</div>
192-
</Card>
193-
))}
169+
<Stats>
170+
{feeds.map((feed) => (
171+
<Card
172+
key={feed.product.price_account}
173+
variant="tertiary"
174+
{...(linkFeeds && {
175+
href: `/price-feeds/${encodeURIComponent(feed.symbol)}`,
176+
})}
177+
>
178+
<div className={styles.feedCardContents}>
179+
<PriceFeedTag
180+
symbol={feed.product.display_symbol}
181+
description={feed.product.description}
182+
icon={<PriceFeedIcon symbol={feed.product.display_symbol} />}
183+
/>
184+
{showPrices && (
185+
<div className={styles.prices}>
186+
<LivePrice feedKey={feed.product.price_account} />
187+
<ChangePercent
188+
className={styles.changePercent}
189+
feedKey={feed.product.price_account}
190+
/>
191+
</div>
192+
)}
193+
</div>
194+
</Card>
195+
))}
196+
</Stats>
194197
</div>
195198
</Card>
196199
);

apps/insights/src/components/Root/footer.module.scss

+10-1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@
77
// XL
88
padding: theme.spacing(8) 0;
99

10+
@include theme.mobile {
11+
padding-bottom: theme.spacing(20);
12+
}
13+
1014
// bg-beige-100 sm:border-t sm:border-stone-300
1115

1216
.topContent {
@@ -18,10 +22,15 @@
1822
align-items: center;
1923
justify-content: space-between;
2024

25+
@media screen and (max-width: theme.breakpoint("sm")) {
26+
flex-flow: column nowrap;
27+
align-items: flex-start;
28+
}
29+
2130
@include theme.max-width;
2231

2332
// XL
24-
margin-bottom: theme.spacing(12);
33+
margin-bottom: theme.spacing(6);
2534

2635
// py-6
2736

apps/insights/src/components/Root/footer.tsx

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { ArrowSquareOut } from "@phosphor-icons/react/dist/ssr/ArrowSquareOut";
12
import {
23
type Props as ButtonProps,
34
Button,
@@ -21,10 +22,10 @@ export const Footer = () => (
2122
<div className={styles.divider} />
2223
<div className={styles.help}>
2324
<SupportDrawer>
24-
<Link>Help</Link>
25+
<Link>Support</Link>
2526
</SupportDrawer>
2627
<Link href="https://docs.pyth.network" target="_blank">
27-
Documentation
28+
Documentation <ArrowSquareOut />
2829
</Link>
2930
</div>
3031
</div>

apps/insights/src/components/Root/header.module.scss

+47-23
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,11 @@
44
position: sticky;
55
top: 0;
66
width: 100%;
7-
background-color: theme.color("background", "nav-blur");
8-
backdrop-filter: blur(32px);
7+
background-color: theme.color("background", "primary");
8+
border-bottom: 1px solid theme.color("background", "secondary");
9+
10+
// TODO: This causes that navigation is not fixed
11+
// backdrop-filter: blur(32px);
912

1013
.content {
1114
height: 100%;
@@ -16,18 +19,23 @@
1619

1720
.leftMenu {
1821
flex: none;
19-
gap: theme.spacing(6);
22+
gap: theme.spacing(4);
23+
position: relative;
2024

2125
@include theme.row;
2226

2327
.logoLink {
2428
padding: theme.spacing(3);
25-
margin: -#{theme.spacing(3)};
2629
color: theme.color("foreground");
2730

31+
@include theme.desktop {
32+
position: absolute;
33+
left: -#{theme.spacing(16)};
34+
}
35+
2836
.logoWrapper {
29-
width: theme.spacing(9);
30-
height: theme.spacing(9);
37+
width: theme.spacing(8);
38+
height: theme.spacing(8);
3139
position: relative;
3240

3341
.logo {
@@ -52,33 +60,49 @@
5260

5361
.rightMenu {
5462
flex: none;
63+
position: relative;
5564
gap: theme.spacing(2);
5665

5766
@include theme.row;
5867

59-
margin-right: -#{theme.button-padding("sm", false)};
60-
6168
.themeSwitch {
62-
margin-left: theme.spacing(1);
63-
}
64-
}
69+
position: relative;
6570

66-
@media screen and (min-width: theme.$max-width + (2 * (theme.spacing(9) + theme.spacing(8) + theme.spacing(7)))) {
67-
.leftMenu {
68-
margin-left: -#{theme.spacing(9) + theme.spacing(7)};
69-
70-
.logoLink {
71-
margin-right: -#{theme.spacing(2)};
71+
@include theme.mobile {
72+
display: none;
7273
}
73-
}
7474

75-
.rightMenu {
76-
margin-right: -#{theme.spacing(9) + theme.spacing(7)};
77-
78-
.themeSwitch {
79-
margin-left: theme.spacing(5);
75+
@include theme.desktop {
76+
display: block;
77+
position: absolute;
78+
right: -#{theme.spacing(16)};
8079
}
8180
}
8281
}
82+
83+
// Reason: you can absolute position relatively to a container and disable this behavior on mobile
84+
// @media screen and (min-width: #{theme.$max-width + (2 * (theme.spacing(9) + theme.spacing(8) + theme.spacing(7)))}) {
85+
// .leftMenu {
86+
// margin-left: -#{theme.spacing(9) + theme.spacing(7)};
87+
88+
// .logoLink {
89+
// margin-right: -#{theme.spacing(2)};
90+
// }
91+
// }
92+
93+
// .rightMenu {
94+
// margin-right: -#{theme.spacing(9) + theme.spacing(7)};
95+
96+
// .themeSwitch {
97+
// margin-left: theme.spacing(5);
98+
// }
99+
// }
100+
// }
101+
}
102+
}
103+
104+
.hideOnMobile {
105+
@include theme.mobile {
106+
display: none;
83107
}
84108
}

0 commit comments

Comments
 (0)