Skip to content

Commit 19cc8eb

Browse files
authored
Merge pull request #12 from acmucsd/website-responsiveness
feat(website): add mobile support
2 parents ed8955a + af1aaa4 commit 19cc8eb

27 files changed

+425
-73
lines changed
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
$navbar-drawer-width: 80vw;
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import c from "clsx"
2+
3+
import s from "./styles.module.scss"
4+
5+
import { Dispatch, ReactNode, SetStateAction, useState } from "react"
6+
7+
interface MobileDrawerProps {
8+
isOpen: boolean
9+
setIsOpen: Dispatch<SetStateAction<boolean>>
10+
secondaryMenu?: ReactNode
11+
children: ReactNode
12+
}
13+
14+
const MobileDrawer = ({ isOpen, setIsOpen, secondaryMenu, children }: MobileDrawerProps) => {
15+
const [menu, setMenu] = useState<'primary' | 'secondary'>(secondaryMenu ? 'secondary' : 'primary')
16+
17+
return (
18+
<>
19+
<div
20+
className={c(s.backdrop, isOpen && s.backdropVisible)}
21+
role="presentation"
22+
onClick={() => { setIsOpen(false); }}
23+
/>
24+
<div className={c(s.drawer, isOpen && s.show)}>
25+
<div className={c(s.panes, menu === 'secondary' && s.showSecondaryPane)}>
26+
<div className={s.pane}>
27+
<button
28+
className={s.switchPaneButton}
29+
onClick={() => { setMenu('secondary') }}
30+
>
31+
Go to secondary menu →
32+
</button>
33+
{children}
34+
</div>
35+
<div className={s.pane}>
36+
<button
37+
className={s.switchPaneButton}
38+
onClick={() => { setMenu('primary') }}
39+
>
40+
← Back to primary menu
41+
</button>
42+
{secondaryMenu}
43+
</div>
44+
</div>
45+
</div>
46+
</>
47+
)
48+
}
49+
50+
export default MobileDrawer
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
@use "./vars";
2+
3+
.backdrop {
4+
position: fixed;
5+
inset: 0;
6+
visibility: hidden;
7+
opacity: 0;
8+
background-color: hsl(0 0% 0% / 0.1);
9+
10+
&.backdropVisible {
11+
visibility: visible;
12+
opacity: 1;
13+
}
14+
}
15+
16+
.drawer {
17+
position: fixed;
18+
top: 0;
19+
bottom: 0;
20+
left: 0;
21+
width: vars.$navbar-drawer-width;
22+
23+
transform: translate3d(-100%, 0, 0);
24+
visibility: hidden;
25+
opacity: 0;
26+
27+
background-color: #fff; // TODO
28+
box-shadow: 0px 8px 8px hsl(0 0 0 / 0.3); // TODO
29+
30+
overflow-x: hidden;
31+
32+
transition: opacity 400ms ease,
33+
visibility 400ms ease,
34+
transform 400ms ease;
35+
36+
&.show {
37+
transform: translateZ(0);
38+
visibility: visible;
39+
opacity: 1;
40+
}
41+
42+
.panes {
43+
display: flex;
44+
height: 100%;
45+
46+
transition: transform 400ms ease;
47+
48+
&.showSecondaryPane {
49+
transform: translate3d(#{-1 * vars.$navbar-drawer-width}, 0, 0);
50+
}
51+
52+
.pane {
53+
flex-shrink: 0;
54+
padding: 1rem 0.5rem 0.5rem;
55+
width: vars.$navbar-drawer-width;
56+
overflow-x: hidden;
57+
58+
.switchPaneButton {
59+
width: 100%;
60+
padding: 0.5rem 1.5rem;
61+
background-color: hsl(0 0% 0% / 0.05);
62+
margin-bottom: 0.5rem;
63+
}
64+
}
65+
}
66+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// AUTOGENERATED FILE -- DO NOT EDIT DIRECTLY
2+
declare namespace StylesModuleScssNamespace {
3+
export interface IStylesModuleScss {
4+
backdrop: string;
5+
backdropVisible: string;
6+
drawer: string;
7+
pane: string;
8+
panes: string;
9+
show: string;
10+
showSecondaryPane: string;
11+
switchPaneButton: string;
12+
}
13+
}
14+
15+
declare const StylesModuleScssModule: StylesModuleScssNamespace.IStylesModuleScss;
16+
17+
export = StylesModuleScssModule;
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
@use "@/styles/utils";
2+
@use "./vars" as *;
3+
4+
:export {
5+
iconSize: utils.strip-units($icon-size);
6+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// AUTOGENERATED FILE -- DO NOT EDIT DIRECTLY
2+
declare namespace ExportsModuleScssNamespace {
3+
export interface IExportsModuleScss {
4+
iconSize: string;
5+
}
6+
}
7+
8+
declare const ExportsModuleScssModule: ExportsModuleScssNamespace.IExportsModuleScss;
9+
10+
export = ExportsModuleScssModule;
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
$icon-size: 32px;
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import c from "clsx";
2+
import type { MouseEventHandler } from "react";
3+
4+
import { iconSize as iconSizeString } from "./_exports.module.scss";
5+
import s from "./styles.module.scss"
6+
7+
8+
interface MobileMenuButtonProps {
9+
isOpen?: boolean
10+
onClick: MouseEventHandler<HTMLButtonElement>
11+
className?: string
12+
}
13+
14+
const MobileMenuButton = ({ isOpen, onClick, className }: MobileMenuButtonProps) => {
15+
return (
16+
<button
17+
type="button"
18+
title={isOpen ? 'Close menu' : 'Open menu'}
19+
className={c(s.button, className)}
20+
onClick={onClick}
21+
>
22+
<span className={s.icon} aria-hidden="true">
23+
<svg
24+
className={c(s.hamburgerIcon, isOpen ? s.closed : s.open)}
25+
width={iconSizeString}
26+
height={iconSizeString}
27+
viewBox="0 0 32 32"
28+
>
29+
<path d="M4 24V22H28V24ZM4 17V15H28V17ZM4 10V8H28V10Z" />
30+
</svg>
31+
</span>
32+
<span className={s.icon} aria-hidden="true">
33+
<svg
34+
className={c(s.closeIcon, isOpen ? s.open : s.closed)}
35+
width={iconSizeString}
36+
height={iconSizeString}
37+
viewBox="0 0 32 32"
38+
>
39+
<path d="M8.3 25.1 6.9 23.7 14.6 16 6.9 8.3 8.3 6.9 16 14.6 23.7 6.9 25.1 8.3 17.4 16 25.1 23.7 23.7 25.1 16 17.4Z"/>
40+
</svg>
41+
</span>
42+
</button>
43+
)
44+
}
45+
46+
export default MobileMenuButton
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
@use "./vars";
2+
3+
.button {
4+
width: vars.$icon-size;
5+
height: vars.$icon-size;
6+
cursor: pointer;
7+
position: relative;
8+
9+
.icon {
10+
position: absolute;
11+
top: 0;
12+
left: 0;
13+
14+
.hamburgerIcon, .closeIcon {
15+
position: relative;
16+
transition: all 0.15s ease;
17+
width: vars.$icon-size;
18+
height: vars.$icon-size;
19+
}
20+
21+
.closeIcon {
22+
transform-origin: center center;
23+
}
24+
25+
.open {
26+
transform: scale(1);
27+
opacity: 1;
28+
}
29+
30+
.closed {
31+
transform: scale(0);
32+
opacity: 0;
33+
}
34+
}
35+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// AUTOGENERATED FILE -- DO NOT EDIT DIRECTLY
2+
declare namespace StylesModuleScssNamespace {
3+
export interface IStylesModuleScss {
4+
button: string;
5+
closeIcon: string;
6+
closed: string;
7+
hamburgerIcon: string;
8+
icon: string;
9+
open: string;
10+
}
11+
}
12+
13+
declare const StylesModuleScssModule: StylesModuleScssNamespace.IStylesModuleScss;
14+
15+
export = StylesModuleScssModule;

0 commit comments

Comments
 (0)