Skip to content

Commit 95ce0e0

Browse files
authored
feat: header with link (#172)
1 parent c01d2b6 commit 95ce0e0

File tree

11 files changed

+290
-62
lines changed

11 files changed

+290
-62
lines changed

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
"dependencies": {
1616
"@emotion/react": "11.10.0",
1717
"@emotion/styled": "11.10.0",
18+
"@mui/icons-material": "5.11.11",
1819
"@mui/material": "5.10.7",
1920
"i18next": "21.9.2",
2021
"next": "12.3.1",
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
import { Box, Modal, Slide, ButtonBase, Typography, IconButton } from '@mui/material'
2+
import CloseIcon from '@mui/icons-material/Close'
3+
import Link from 'next/link'
4+
import { useRouter } from 'next/router'
5+
import { Logo } from 'src/components/atoms'
6+
import { Colors } from 'src/styles/color'
7+
import { HeaderMenuItem } from 'src/components/organisms/Header'
8+
9+
export interface ModalHeaderMenuProps {
10+
open: boolean
11+
onClose: () => void
12+
menuList: HeaderMenuItem[]
13+
}
14+
15+
export const ModalHeaderMenu = ({ open, onClose, menuList }: ModalHeaderMenuProps) => {
16+
const router = useRouter()
17+
18+
return (
19+
<Modal open={open} onClose={onClose} sx={{ display: 'flex', zIndex: 9999, bottom: 'auto' }}>
20+
<Slide in={open} direction="down">
21+
<Box
22+
width={1}
23+
pt="12px"
24+
pb="24px"
25+
px="16px"
26+
color={Colors.text.white}
27+
sx={{ background: Colors.background.brand_color }}
28+
display="flex"
29+
flexDirection="column"
30+
>
31+
<Box display="flex" alignItems="center" justifyContent="space-between" width={1} mb="16px">
32+
<Box>
33+
<Logo
34+
sx={{
35+
width: '140px',
36+
height: '24px',
37+
color: Colors.text.white
38+
}}
39+
/>
40+
</Box>
41+
<IconButton color="inherit" onClick={onClose}>
42+
<CloseIcon fontSize="large" />
43+
</IconButton>
44+
</Box>
45+
<Box
46+
display="flex"
47+
flex={1}
48+
gap="16px"
49+
flexDirection="column"
50+
alignItems="center"
51+
justifyContent="space-between"
52+
>
53+
{menuList.map((list, i) => {
54+
return (
55+
<Link key={i} href={list.href || router.asPath}>
56+
<a>
57+
<Box
58+
sx={{
59+
cursor: 'pointer',
60+
boxSizing: 'border-box',
61+
color: Colors.text.white,
62+
textDecoration: 'none',
63+
borderBottom: router.pathname === list.href ? '3px solid' : ''
64+
}}
65+
>
66+
{list.onClick ? (
67+
<ButtonBase onClick={list.onClick}>
68+
<Typography variant="body1" color="inherit" sx={{ textAlign: 'left' }}>
69+
{list.label}
70+
</Typography>
71+
</ButtonBase>
72+
) : (
73+
<Typography variant="body1" color="inherit" sx={{ textAlign: 'left' }}>
74+
{list.label}
75+
</Typography>
76+
)}
77+
</Box>
78+
</a>
79+
</Link>
80+
)
81+
})}
82+
</Box>
83+
</Box>
84+
</Slide>
85+
</Modal>
86+
)
87+
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import React from 'react'
2+
import { Typography, Box } from '@mui/material'
3+
import Link from 'next/link'
4+
import { useRouter } from 'next/router'
5+
import { HeaderItemColor, HeaderMenuItem, HeaderItemBehaviorStyles } from 'src/components/organisms/Header'
6+
7+
export interface HeaderMenuProps {
8+
menuList: HeaderMenuItem[]
9+
itemColor: HeaderItemColor
10+
itemBehaviorStyles: HeaderItemBehaviorStyles
11+
}
12+
13+
export const HeaderMenu = ({ menuList, itemColor, itemBehaviorStyles }: HeaderMenuProps) => {
14+
const router = useRouter()
15+
16+
return (
17+
<Box sx={{ display: 'flex', gap: '8px', margin: '0 24px 0 auto' }}>
18+
{menuList.map((list, i) => {
19+
return list.href ? (
20+
<Link href={list.href} key={i}>
21+
<a>
22+
<Typography
23+
sx={{
24+
borderBottom: router.pathname === list.href ? '3px solid' : '',
25+
color: itemColor.default,
26+
p: '4px 8px',
27+
...itemBehaviorStyles
28+
}}
29+
>
30+
{list.label}
31+
</Typography>
32+
</a>
33+
</Link>
34+
) : (
35+
<Typography
36+
onClick={list.onClick}
37+
sx={{
38+
color: itemColor.default,
39+
p: '4px 8px',
40+
...itemBehaviorStyles
41+
}}
42+
>
43+
{list.label}
44+
</Typography>
45+
)
46+
})}
47+
</Box>
48+
)
49+
}
Lines changed: 60 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,48 +1,70 @@
1-
import React from 'react'
2-
import i18n from 'src/i18n/configs'
3-
import { AppBar, Toolbar, Typography, Box } from '@mui/material'
1+
import React, { useState, useMemo } from 'react'
2+
import MenuRoundedIcon from '@mui/icons-material/MenuRounded'
3+
import { AppBar, Toolbar, Box, IconButton } from '@mui/material'
44
import { Colors } from 'src/styles/color'
5-
import { useTranslation } from 'react-i18next'
65
import { Logo } from 'src/components/atoms'
76
import { useScrollY, useSize } from 'src/modules/hooks'
7+
import { HeaderMenu } from 'src/components/molecules/HeaderMenu'
8+
import { ModalHeaderMenu } from 'src/components/modals/ModalHeaderMenu'
9+
import { handleChangeLanguage } from 'src/i18n/util'
10+
import { useTranslation } from 'react-i18next'
811

9-
const handleChangeLanguage = () => {
10-
switch (i18n.language) {
11-
case 'ja':
12-
i18n.changeLanguage('en')
13-
return
14-
case 'en':
15-
i18n.changeLanguage('ja')
16-
return
17-
}
18-
}
19-
20-
interface HeaderItemColors {
12+
export interface HeaderItemColor {
2113
default: string
2214
hover: string
2315
activeBg: string
2416
}
2517

26-
// TODO: 各ページへのリンクを実装, スマートフォンモード実装
18+
export type HeaderMenuItem = {
19+
href?: string
20+
label: string
21+
onClick?: () => void
22+
}
23+
24+
export type HeaderItemBehaviorStyles = {
25+
'&:hover': {
26+
cursor: string
27+
color: string
28+
}
29+
'&:active': {
30+
color: string
31+
backgroundColor: string
32+
}
33+
}
34+
2735
export const Header = () => {
28-
const isScrolled = useScrollY() > 0
29-
const headerItemColors: HeaderItemColors = isScrolled
30-
? { default: Colors.text.white, hover: Colors.text.white_hover, activeBg: Colors.header.active.white }
31-
: { default: Colors.text.primary, hover: Colors.text.primary_hover, activeBg: Colors.header.active.default }
36+
const [modalMenuOpen, setModalMenuOpen] = useState(false)
3237
const { t } = useTranslation()
38+
const isScrolled = useScrollY() > 0
3339
const { isPCOrOver } = useSize()
3440
const isLogoDisplayed = isPCOrOver || isScrolled
35-
const headerItemBehaviorStyles = {
41+
const headerItemColor: HeaderItemColor = isScrolled
42+
? { default: Colors.text.white, hover: Colors.text.white_hover, activeBg: Colors.header.active.white }
43+
: { default: Colors.text.primary, hover: Colors.text.primary_hover, activeBg: Colors.header.active.default }
44+
const headerItemBehaviorStyles: HeaderItemBehaviorStyles = {
3645
'&:hover': {
3746
cursor: 'pointer',
38-
color: headerItemColors.hover
47+
color: headerItemColor.hover
3948
},
4049
'&:active': {
41-
color: headerItemColors.hover,
42-
backgroundColor: headerItemColors.activeBg
50+
color: headerItemColor.hover,
51+
backgroundColor: headerItemColor.activeBg
4352
}
4453
}
4554

55+
const menuList: HeaderMenuItem[] = useMemo(() => {
56+
return [
57+
{ href: '/', label: 'Home' },
58+
{ href: '/sessions', label: 'Sessions' },
59+
{ href: '/timetable', label: 'Timetable' },
60+
{ href: '/floor_guide', label: 'Floor Guide' },
61+
{
62+
label: t('change_language'),
63+
onClick: handleChangeLanguage
64+
}
65+
]
66+
}, [t])
67+
4668
return (
4769
<AppBar position="fixed" sx={{ backgroundColor: '#fff0', height: '100px', boxShadow: 0 }}>
4870
{/* グラデーション背景 */}
@@ -62,30 +84,27 @@ export const Header = () => {
6284
<Box>
6385
<Logo
6486
sx={{
65-
width: '233px',
66-
height: '40px',
67-
color: headerItemColors.default,
87+
width: isPCOrOver ? '233px' : '140px',
88+
height: isPCOrOver ? '40px' : '24px',
89+
color: headerItemColor.default,
6890
marginLeft: '12px',
6991
borderRadius: '8px',
7092
...headerItemBehaviorStyles
7193
}}
7294
/>
7395
</Box>
7496
)}
75-
<Box sx={{ margin: '0 24px 0 auto' }}>
76-
<Typography
77-
onClick={handleChangeLanguage}
78-
sx={{
79-
color: headerItemColors.default,
80-
p: '4px 8px',
81-
borderRadius: '8px',
82-
...headerItemBehaviorStyles
83-
}}
84-
>
85-
{t('change_language')}
86-
</Typography>
87-
</Box>
97+
{isPCOrOver ? (
98+
<HeaderMenu itemColor={headerItemColor} menuList={menuList} itemBehaviorStyles={headerItemBehaviorStyles} />
99+
) : (
100+
<Box flex={1} display="flex" justifyContent="flex-end">
101+
<IconButton onClick={() => setModalMenuOpen(true)}>
102+
<MenuRoundedIcon sx={{ fontSize: 24, color: headerItemColor.default }} />
103+
</IconButton>
104+
</Box>
105+
)}
88106
</Toolbar>
107+
<ModalHeaderMenu open={modalMenuOpen} onClose={() => setModalMenuOpen(false)} menuList={menuList} />
89108
</AppBar>
90109
)
91110
}

src/components/pages/PageTop/index.tsx

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,7 @@ import type { NextPage } from 'next'
22
import { Layout } from 'src/components/commons'
33
import { useTranslation } from 'react-i18next'
44
import { useSessionize } from 'src/modules/sessionize/hooks'
5-
import {
6-
MainVisual,
7-
TopDescription,
8-
SponsorsSection,
9-
CommunityBoothSection,
10-
SpeakersSection
11-
} from 'src/components/organisms'
5+
import { MainVisual, TopDescription, SponsorsSection, CommunityBoothSection } from 'src/components/organisms'
126

137
export const PageTop: NextPage = () => {
148
const { t } = useTranslation()
@@ -21,7 +15,6 @@ export const PageTop: NextPage = () => {
2115
<Layout>
2216
<MainVisual />
2317
<TopDescription />
24-
<SpeakersSection />
2518
<SponsorsSection />
2619
<CommunityBoothSection />
2720
</Layout>

src/i18n/util.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import i18n from 'src/i18n/configs'
2+
3+
export const handleChangeLanguage = () => {
4+
switch (i18n.language) {
5+
case 'ja':
6+
i18n.changeLanguage('en')
7+
return
8+
case 'en':
9+
i18n.changeLanguage('ja')
10+
return
11+
}
12+
}

src/pages/floor_guide.tsx

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { PageTop } from 'src/components/pages'
2+
3+
type InitialProps = {}
4+
type Props = {} & InitialProps
5+
6+
const Index = (_: Props) => {
7+
/* TODO: 各ページの実装 */
8+
return <PageTop />
9+
}
10+
11+
export default Index

src/pages/sessions.tsx

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { PageTop } from 'src/components/pages'
2+
3+
type InitialProps = {}
4+
type Props = {} & InitialProps
5+
6+
const Index = (_: Props) => {
7+
/* TODO: 各ページの実装 */
8+
return <PageTop />
9+
}
10+
11+
export default Index

src/pages/timetable.tsx

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { PageTop } from 'src/components/pages'
2+
3+
type InitialProps = {}
4+
type Props = {} & InitialProps
5+
6+
const Index = (_: Props) => {
7+
/* TODO: 各ページの実装 */
8+
return <PageTop />
9+
}
10+
11+
export default Index

0 commit comments

Comments
 (0)