Skip to content

Commit 0c056c0

Browse files
authored
Merge pull request #1229 from kleros/feat(web)/new-scrollbar-and-placeholder
feat(web): style scrollbar a bit and add placeholder if not scrollabl…
2 parents 88cb3ca + 11839a6 commit 0c056c0

File tree

15 files changed

+195
-104
lines changed

15 files changed

+195
-104
lines changed

web/package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,8 @@
8282
"graphql": "^16.7.1",
8383
"graphql-request": "~6.1.0",
8484
"moment": "^2.29.4",
85+
"overlayscrollbars": "^2.3.0",
86+
"overlayscrollbars-react": "^0.5.2",
8587
"react": "^18.2.0",
8688
"react-chartjs-2": "^4.3.1",
8789
"react-dom": "^18.2.0",

web/src/components/Overlay.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,5 @@ export const Overlay = styled.div`
77
width: 100vw;
88
height: 100vh;
99
background-color: ${({ theme }) => theme.blackLowOpacity};
10-
z-index: 1;
10+
z-index: 0;
1111
`;
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import { createContext, MutableRefObject } from "react";
2+
3+
export const OverlayScrollContext = createContext<MutableRefObject<HTMLElement | null> | null>(null);
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import { useContext, useEffect, useCallback } from "react";
2+
import { OverlayScrollContext } from "context/OverlayScrollContext";
3+
4+
export const useLockOverlayScroll = (shouldLock: boolean) => {
5+
const osInstanceRef = useContext(OverlayScrollContext);
6+
7+
const lockScroll = useCallback(() => {
8+
const osInstance = osInstanceRef?.current?.osInstance();
9+
if (osInstance) {
10+
osInstance.options({ overflow: { x: "hidden", y: "hidden" } });
11+
}
12+
}, [osInstanceRef]);
13+
14+
const unlockScroll = useCallback(() => {
15+
const osInstance = osInstanceRef?.current?.osInstance();
16+
if (osInstance) {
17+
osInstance.options({ overflow: { x: "scroll", y: "scroll" } });
18+
}
19+
}, [osInstanceRef]);
20+
21+
useEffect(() => {
22+
if (shouldLock) {
23+
lockScroll();
24+
} else {
25+
unlockScroll();
26+
}
27+
}, [shouldLock, lockScroll, unlockScroll]);
28+
};

web/src/layout/Header/navbar/DappList.tsx

Lines changed: 15 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ import Linguo from "svgs/icons/linguo.svg";
1010
import POH from "svgs/icons/poh-image.png";
1111
import Tokens from "svgs/icons/tokens.svg";
1212
import Product from "./Product";
13-
import { Overlay } from "components/Overlay";
1413

1514
const Header = styled.h1`
1615
display: flex;
@@ -28,7 +27,7 @@ const Container = styled.div`
2827
top: 5%;
2928
left: 50%;
3029
transform: translate(-50%);
31-
z-index: 10;
30+
z-index: 1;
3231
flex-direction: column;
3332
align-items: center;
3433
@@ -58,10 +57,6 @@ const ItemsDiv = styled.div`
5857
grid-template-columns: repeat(auto-fit, minmax(100px, 1fr));
5958
`;
6059

61-
interface IDappList {
62-
toggleSolution: () => void;
63-
}
64-
6560
const ITEMS = [
6661
{
6762
text: "Court v1",
@@ -105,24 +100,25 @@ const ITEMS = [
105100
},
106101
];
107102

108-
const DappList: React.FC<IDappList> = ({ toggleSolution }) => {
103+
interface IDappList {
104+
toggleIsDappListOpen: () => void;
105+
}
106+
107+
const DappList: React.FC<IDappList> = ({ toggleIsDappListOpen }) => {
109108
const containerRef = useRef(null);
110109
useFocusOutside(containerRef, () => {
111-
toggleSolution();
110+
toggleIsDappListOpen();
112111
});
113112

114113
return (
115-
<>
116-
<Overlay />
117-
<Container ref={containerRef}>
118-
<Header>Kleros Solutions</Header>
119-
<ItemsDiv>
120-
{ITEMS.map((item) => {
121-
return <Product {...item} key={item.text} />;
122-
})}
123-
</ItemsDiv>
124-
</Container>
125-
</>
114+
<Container ref={containerRef}>
115+
<Header>Kleros Solutions</Header>
116+
<ItemsDiv>
117+
{ITEMS.map((item) => {
118+
return <Product {...item} key={item.text} />;
119+
})}
120+
</ItemsDiv>
121+
</Container>
126122
);
127123
};
128124
export default DappList;

web/src/layout/Header/navbar/Menu/Help.tsx

Lines changed: 12 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import Bug from "svgs/icons/bug.svg";
77
import ETH from "svgs/icons/eth.svg";
88
import Faq from "svgs/menu-icons/help.svg";
99
import Telegram from "svgs/socialmedia/telegram.svg";
10-
import { Overlay } from "components/Overlay";
1110

1211
const Container = styled.div`
1312
display: flex;
@@ -16,7 +15,7 @@ const Container = styled.div`
1615
top: 5%;
1716
left: 50%;
1817
transform: translate(-50%);
19-
z-index: 10;
18+
z-index: 1;
2019
padding: 27px 10px;
2120
gap: 23px;
2221
border: 1px solid ${({ theme }) => theme.stroke};
@@ -83,27 +82,24 @@ const ITEMS = [
8382
];
8483

8584
interface IHelp {
86-
toggle: () => void;
85+
toggleIsHelpOpen: () => void;
8786
}
8887

89-
const Help: React.FC<IHelp> = ({ toggle }) => {
88+
const Help: React.FC<IHelp> = ({ toggleIsHelpOpen }) => {
9089
const containerRef = useRef(null);
9190
useFocusOutside(containerRef, () => {
92-
toggle();
91+
toggleIsHelpOpen();
9392
});
9493

9594
return (
96-
<>
97-
<Overlay />
98-
<Container ref={containerRef}>
99-
{ITEMS.map((item) => (
100-
<ListItem href={item.url} key={item.text} target="_blank">
101-
<Icon as={item.Icon} />
102-
<small>{item.text}</small>
103-
</ListItem>
104-
))}
105-
</Container>
106-
</>
95+
<Container ref={containerRef}>
96+
{ITEMS.map((item) => (
97+
<ListItem href={item.url} key={item.text} target="_blank">
98+
<Icon as={item.Icon} />
99+
<small>{item.text}</small>
100+
</ListItem>
101+
))}
102+
</Container>
107103
);
108104
};
109105
export default Help;

web/src/layout/Header/navbar/Menu/Settings/index.tsx

Lines changed: 17 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
1-
import React, { Dispatch, SetStateAction, useRef, useState } from "react";
1+
import React, { useRef, useState } from "react";
22
import styled from "styled-components";
33
import { Tabs } from "@kleros/ui-components-library";
44
import General from "./General";
55
import SendMeNotifications from "./SendMeNotifications";
66
import { useFocusOutside } from "hooks/useFocusOutside";
7-
import { Overlay } from "components/Overlay";
87

98
const Container = styled.div`
109
display: flex;
1110
position: absolute;
11+
max-height: 80vh;
12+
overflow-y: auto;
1213
z-index: 1;
1314
background-color: ${({ theme }) => theme.whiteBackground};
1415
flex-direction: column;
@@ -45,29 +46,26 @@ const TABS = [
4546
];
4647

4748
interface ISettings {
48-
setIsSettingsOpen: Dispatch<SetStateAction<boolean>>;
49+
toggleIsSettingsOpen: () => void;
4950
}
5051

51-
const Settings: React.FC<ISettings> = ({ setIsSettingsOpen }) => {
52+
const Settings: React.FC<ISettings> = ({ toggleIsSettingsOpen }) => {
5253
const [currentTab, setCurrentTab] = useState<number>(0);
5354
const containerRef = useRef(null);
54-
useFocusOutside(containerRef, () => setIsSettingsOpen(false));
55+
useFocusOutside(containerRef, () => toggleIsSettingsOpen());
5556

5657
return (
57-
<>
58-
<Overlay />
59-
<Container ref={containerRef}>
60-
<StyledSettingsText>Settings</StyledSettingsText>
61-
<StyledTabs
62-
currentValue={currentTab}
63-
items={TABS}
64-
callback={(n: number) => {
65-
setCurrentTab(n);
66-
}}
67-
/>
68-
{currentTab === 0 ? <General /> : <SendMeNotifications />}
69-
</Container>
70-
</>
58+
<Container ref={containerRef}>
59+
<StyledSettingsText>Settings</StyledSettingsText>
60+
<StyledTabs
61+
currentValue={currentTab}
62+
items={TABS}
63+
callback={(n: number) => {
64+
setCurrentTab(n);
65+
}}
66+
/>
67+
{currentTab === 0 ? <General /> : <SendMeNotifications />}
68+
</Container>
7169
);
7270
};
7371

web/src/layout/Header/navbar/Menu/index.tsx

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,11 @@
1-
import React, { useState } from "react";
1+
import React from "react";
22
import styled from "styled-components";
3-
import { useToggle } from "react-use";
43
import LightButton from "components/LightButton";
5-
import Help from "./Help";
64
import DarkModeIcon from "svgs/menu-icons/dark-mode.svg";
75
import HelpIcon from "svgs/menu-icons/help.svg";
86
import LightModeIcon from "svgs/menu-icons/light-mode.svg";
97
import NotificationsIcon from "svgs/menu-icons/notifications.svg";
108
import SettingsIcon from "svgs/menu-icons/settings.svg";
11-
import Settings from "./Settings";
129
import { useToggleTheme } from "hooks/useToggleThemeContext";
1310

1411
const Container = styled.div``;
@@ -19,18 +16,21 @@ const ButtonContainer = styled.div`
1916
align-items: center;
2017
`;
2118

22-
const Menu: React.FC = () => {
19+
interface IMenu {
20+
toggleIsSettingsOpen: () => void;
21+
toggleIsHelpOpen: () => void;
22+
}
23+
24+
const Menu: React.FC<IMenu> = ({ toggleIsHelpOpen, toggleIsSettingsOpen }) => {
2325
const [theme, toggleTheme] = useToggleTheme();
24-
const [isHelpOpen, toggleIsHelpOpen] = useToggle(true);
25-
const [isSettingsOpen, setIsSettingsOpen] = useState(false);
2626

2727
const isLightTheme = theme === "light";
2828
const buttons = [
2929
{ text: "Notifications", Icon: NotificationsIcon },
3030
{
3131
text: "Settings",
3232
Icon: SettingsIcon,
33-
onClick: () => setIsSettingsOpen(true),
33+
onClick: () => toggleIsSettingsOpen(),
3434
},
3535
{
3636
text: "Help",
@@ -53,8 +53,6 @@ const Menu: React.FC = () => {
5353
<LightButton {...{ text, onClick, Icon }} />
5454
</ButtonContainer>
5555
))}
56-
{isHelpOpen && <Help toggle={toggleIsHelpOpen} />}
57-
{isSettingsOpen && <Settings setIsSettingsOpen={setIsSettingsOpen} />}
5856
</Container>
5957
);
6058
};

web/src/layout/Header/navbar/index.tsx

Lines changed: 50 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,63 +1,87 @@
11
import React from "react";
22
import styled from "styled-components";
3-
import { useLockBodyScroll, useToggle } from "react-use";
4-
import ConnectWallet from "components/ConnectWallet";
5-
import LightButton from "components/LightButton";
6-
import KlerosSolutionsIcon from "svgs/menu-icons/kleros-solutions.svg";
3+
import { useToggle } from "react-use";
74
import { useOpenContext } from "../index";
85
import DappList from "./DappList";
96
import Explore from "./Explore";
7+
import ConnectWallet from "components/ConnectWallet";
8+
import LightButton from "components/LightButton";
9+
import { Overlay } from "components/Overlay";
10+
import KlerosSolutionsIcon from "svgs/menu-icons/kleros-solutions.svg";
1011
import Menu from "./Menu";
1112
import Debug from "./Debug";
13+
import Help from "./Menu/Help";
14+
import Settings from "./Menu/Settings";
15+
import { useLockOverlayScroll } from "hooks/useLockOverlayScroll";
1216

1317
const Container = styled.div<{ isOpen: boolean }>`
1418
position: absolute;
1519
top: 64px;
1620
left: 0;
1721
right: 0;
22+
max-height: calc(100vh - 64px);
23+
overflow-y: auto;
1824
z-index: 1;
1925
background-color: ${({ theme }) => theme.whiteBackground};
2026
border: 1px solid ${({ theme }) => theme.stroke};
2127
box-shadow: 0px 2px 3px ${({ theme }) => theme.defaultShadow};
22-
2328
transform-origin: top;
2429
transform: scaleY(${({ isOpen }) => (isOpen ? "1" : "0")});
2530
visibility: ${({ isOpen }) => (isOpen ? "visible" : "hidden")};
2631
transition-property: transform, visibility;
2732
transition-duration: ${({ theme }) => theme.transitionSpeed};
2833
transition-timing-function: ease;
29-
3034
padding: 24px;
3135
3236
hr {
3337
margin: 24px 0;
3438
}
3539
`;
3640

41+
const PopupContainer = styled.div`
42+
position: fixed;
43+
top: 0;
44+
left: 0;
45+
width: 100%;
46+
height: 100%;
47+
z-index: 20;
48+
`;
49+
3750
const NavBar: React.FC = () => {
38-
const [isSolutionsOpen, toggleSolution] = useToggle(false);
51+
const [isDappListOpen, toggleIsDappListOpen] = useToggle(false);
52+
const [isHelpOpen, toggleIsHelpOpen] = useToggle(false);
53+
const [isSettingsOpen, toggleIsSettingsOpen] = useToggle(false);
3954
const { isOpen } = useOpenContext();
40-
useLockBodyScroll(isOpen);
55+
useLockOverlayScroll(isOpen);
4156

4257
return (
43-
<Container {...{ isOpen }}>
44-
<LightButton
45-
text="Kleros Solutions"
46-
onClick={() => {
47-
toggleSolution();
48-
}}
49-
Icon={KlerosSolutionsIcon}
50-
/>
51-
{isSolutionsOpen && <DappList toggleSolution={toggleSolution} />}
52-
<hr />
53-
<Explore />
54-
<hr />
55-
<ConnectWallet />
56-
<hr />
57-
<Menu />
58-
<br />
59-
<Debug />
60-
</Container>
58+
<>
59+
<Container {...{ isOpen }}>
60+
<LightButton
61+
text="Kleros Solutions"
62+
onClick={() => {
63+
toggleIsDappListOpen();
64+
}}
65+
Icon={KlerosSolutionsIcon}
66+
/>
67+
<hr />
68+
<Explore />
69+
<hr />
70+
<ConnectWallet />
71+
<hr />
72+
<Menu {...{ toggleIsHelpOpen, toggleIsSettingsOpen }} />
73+
<br />
74+
<Debug />
75+
</Container>
76+
{(isDappListOpen || isHelpOpen || isSettingsOpen) && (
77+
<PopupContainer>
78+
<Overlay />
79+
{isDappListOpen && <DappList {...{ toggleIsDappListOpen }} />}
80+
{isHelpOpen && <Help {...{ toggleIsHelpOpen }} />}
81+
{isSettingsOpen && <Settings {...{ toggleIsSettingsOpen }} />}
82+
</PopupContainer>
83+
)}
84+
</>
6185
);
6286
};
6387

0 commit comments

Comments
 (0)