Skip to content
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
"dependencies": {
"@emotion/react": "11.10.0",
"@emotion/styled": "11.10.0",
"@mui/icons-material": "5.11.11",
"@mui/material": "5.10.7",
"i18next": "21.9.2",
"next": "12.3.1",
Expand Down
87 changes: 87 additions & 0 deletions src/components/modals/ModalHeaderMenu/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import { Box, Modal, Slide, ButtonBase, Typography, IconButton } from '@mui/material'
import CloseIcon from '@mui/icons-material/Close'
import Link from 'next/link'
import { useRouter } from 'next/router'
import { Logo } from 'src/components/atoms'
import { Colors } from 'src/styles/color'
import { HeaderMenuItem } from 'src/components/organisms/Header'

export interface ModalHeaderMenuProps {
open: boolean
onClose: () => void
menuList: HeaderMenuItem[]
}

export const ModalHeaderMenu = ({ open, onClose, menuList }: ModalHeaderMenuProps) => {
const router = useRouter()

return (
<Modal open={open} onClose={onClose} sx={{ display: 'flex', zIndex: 9999, bottom: 'auto' }}>
<Slide in={open} direction="down">
<Box
width={1}
pt="12px"
pb="24px"
px="16px"
color={Colors.text.white}
sx={{ background: Colors.background.brand_color }}
display="flex"
flexDirection="column"
>
<Box display="flex" alignItems="center" justifyContent="space-between" width={1} mb="16px">
<Box>
<Logo
sx={{
width: '140px',
height: '24px',
color: Colors.text.white
}}
/>
</Box>
<IconButton color="inherit" onClick={onClose}>
<CloseIcon fontSize="large" />
</IconButton>
</Box>
<Box
display="flex"
flex={1}
gap="16px"
flexDirection="column"
alignItems="center"
justifyContent="space-between"
>
{menuList.map((list, i) => {
return (
<Link key={i} href={list.href || router.asPath}>
<a>
<Box
sx={{
cursor: 'pointer',
boxSizing: 'border-box',
color: Colors.text.white,
textDecoration: 'none',
borderBottom: router.pathname === list.href ? '3px solid' : ''
}}
>
{list.onClick ? (
<ButtonBase onClick={list.onClick}>
<Typography variant="body1" color="inherit" sx={{ textAlign: 'left' }}>
{list.label}
</Typography>
</ButtonBase>
) : (
<Typography variant="body1" color="inherit" sx={{ textAlign: 'left' }}>
{list.label}
</Typography>
)}
</Box>
</a>
</Link>
)
})}
</Box>
</Box>
</Slide>
</Modal>
)
}
49 changes: 49 additions & 0 deletions src/components/molecules/HeaderMenu/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import React from 'react'
import { Typography, Box } from '@mui/material'
import Link from 'next/link'
import { useRouter } from 'next/router'
import { HeaderItemColor, HeaderMenuItem, HeaderItemBehaviorStyles } from 'src/components/organisms/Header'

export interface HeaderMenuProps {
menuList: HeaderMenuItem[]
itemColor: HeaderItemColor
itemBehaviorStyles: HeaderItemBehaviorStyles
}

export const HeaderMenu = ({ menuList, itemColor, itemBehaviorStyles }: HeaderMenuProps) => {
const router = useRouter()

return (
<Box sx={{ display: 'flex', gap: '8px', margin: '0 24px 0 auto' }}>
{menuList.map((list, i) => {
return list.href ? (
<Link href={list.href} key={i}>
<a>
<Typography
sx={{
borderBottom: router.pathname === list.href ? '3px solid' : '',
color: itemColor.default,
p: '4px 8px',
...itemBehaviorStyles
}}
>
{list.label}
</Typography>
</a>
</Link>
) : (
<Typography
onClick={list.onClick}
sx={{
color: itemColor.default,
p: '4px 8px',
...itemBehaviorStyles
}}
>
{list.label}
</Typography>
)
})}
</Box>
)
}
101 changes: 60 additions & 41 deletions src/components/organisms/Header/index.tsx
Original file line number Diff line number Diff line change
@@ -1,48 +1,70 @@
import React from 'react'
import i18n from 'src/i18n/configs'
import { AppBar, Toolbar, Typography, Box } from '@mui/material'
import React, { useState, useMemo } from 'react'
import MenuRoundedIcon from '@mui/icons-material/MenuRounded'
import { AppBar, Toolbar, Box, IconButton } from '@mui/material'
import { Colors } from 'src/styles/color'
import { useTranslation } from 'react-i18next'
import { Logo } from 'src/components/atoms'
import { useScrollY, useSize } from 'src/modules/hooks'
import { HeaderMenu } from 'src/components/molecules/HeaderMenu'
import { ModalHeaderMenu } from 'src/components/modals/ModalHeaderMenu'
import { handleChangeLanguage } from 'src/i18n/util'
import { useTranslation } from 'react-i18next'

const handleChangeLanguage = () => {
switch (i18n.language) {
case 'ja':
i18n.changeLanguage('en')
return
case 'en':
i18n.changeLanguage('ja')
return
}
}

interface HeaderItemColors {
export interface HeaderItemColor {
default: string
hover: string
activeBg: string
}

// TODO: 各ページへのリンクを実装, スマートフォンモード実装
export type HeaderMenuItem = {
href?: string
label: string
onClick?: () => void
}

export type HeaderItemBehaviorStyles = {
'&:hover': {
cursor: string
color: string
}
'&:active': {
color: string
backgroundColor: string
}
}

export const Header = () => {
const isScrolled = useScrollY() > 0
const headerItemColors: HeaderItemColors = isScrolled
? { default: Colors.text.white, hover: Colors.text.white_hover, activeBg: Colors.header.active.white }
: { default: Colors.text.primary, hover: Colors.text.primary_hover, activeBg: Colors.header.active.default }
const [modalMenuOpen, setModalMenuOpen] = useState(false)
const { t } = useTranslation()
const isScrolled = useScrollY() > 0
const { isPCOrOver } = useSize()
const isLogoDisplayed = isPCOrOver || isScrolled
const headerItemBehaviorStyles = {
const headerItemColor: HeaderItemColor = isScrolled
? { default: Colors.text.white, hover: Colors.text.white_hover, activeBg: Colors.header.active.white }
: { default: Colors.text.primary, hover: Colors.text.primary_hover, activeBg: Colors.header.active.default }
const headerItemBehaviorStyles: HeaderItemBehaviorStyles = {
'&:hover': {
cursor: 'pointer',
color: headerItemColors.hover
color: headerItemColor.hover
},
'&:active': {
color: headerItemColors.hover,
backgroundColor: headerItemColors.activeBg
color: headerItemColor.hover,
backgroundColor: headerItemColor.activeBg
}
}

const menuList: HeaderMenuItem[] = useMemo(() => {
return [
{ href: '/', label: 'Home' },
{ href: '/sessions', label: 'Sessions' },
{ href: '/timetable', label: 'Timetable' },
{ href: '/floor_guide', label: 'Floor Guide' },
{
label: t('change_language'),
onClick: handleChangeLanguage
}
]
}, [t])

return (
<AppBar position="fixed" sx={{ backgroundColor: '#fff0', height: '100px', boxShadow: 0 }}>
{/* グラデーション背景 */}
Expand All @@ -62,30 +84,27 @@ export const Header = () => {
<Box>
<Logo
sx={{
width: '233px',
height: '40px',
color: headerItemColors.default,
width: isPCOrOver ? '233px' : '140px',
height: isPCOrOver ? '40px' : '24px',
color: headerItemColor.default,
marginLeft: '12px',
borderRadius: '8px',
...headerItemBehaviorStyles
}}
/>
</Box>
)}
<Box sx={{ margin: '0 24px 0 auto' }}>
<Typography
onClick={handleChangeLanguage}
sx={{
color: headerItemColors.default,
p: '4px 8px',
borderRadius: '8px',
...headerItemBehaviorStyles
}}
>
{t('change_language')}
</Typography>
</Box>
{isPCOrOver ? (
<HeaderMenu itemColor={headerItemColor} menuList={menuList} itemBehaviorStyles={headerItemBehaviorStyles} />
) : (
<Box flex={1} display="flex" justifyContent="flex-end">
<IconButton onClick={() => setModalMenuOpen(true)}>
<MenuRoundedIcon sx={{ fontSize: 24, color: headerItemColor.default }} />
</IconButton>
</Box>
)}
</Toolbar>
<ModalHeaderMenu open={modalMenuOpen} onClose={() => setModalMenuOpen(false)} menuList={menuList} />
</AppBar>
)
}
9 changes: 1 addition & 8 deletions src/components/pages/PageTop/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,7 @@ import type { NextPage } from 'next'
import { Layout } from 'src/components/commons'
import { useTranslation } from 'react-i18next'
import { useSessionize } from 'src/modules/sessionize/hooks'
import {
MainVisual,
TopDescription,
SponsorsSection,
CommunityBoothSection,
SpeakersSection
} from 'src/components/organisms'
import { MainVisual, TopDescription, SponsorsSection, CommunityBoothSection } from 'src/components/organisms'

export const PageTop: NextPage = () => {
const { t } = useTranslation()
Expand All @@ -21,7 +15,6 @@ export const PageTop: NextPage = () => {
<Layout>
<MainVisual />
<TopDescription />
<SpeakersSection />
<SponsorsSection />
<CommunityBoothSection />
</Layout>
Expand Down
12 changes: 12 additions & 0 deletions src/i18n/util.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import i18n from 'src/i18n/configs'

export const handleChangeLanguage = () => {
switch (i18n.language) {
case 'ja':
i18n.changeLanguage('en')
return
case 'en':
i18n.changeLanguage('ja')
return
}
}
11 changes: 11 additions & 0 deletions src/pages/floor_guide.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { PageTop } from 'src/components/pages'

type InitialProps = {}
type Props = {} & InitialProps

const Index = (_: Props) => {
/* TODO: 各ページの実装 */
return <PageTop />
}

export default Index
11 changes: 11 additions & 0 deletions src/pages/sessions.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { PageTop } from 'src/components/pages'

type InitialProps = {}
type Props = {} & InitialProps

const Index = (_: Props) => {
/* TODO: 各ページの実装 */
return <PageTop />
}

export default Index
11 changes: 11 additions & 0 deletions src/pages/timetable.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { PageTop } from 'src/components/pages'

type InitialProps = {}
type Props = {} & InitialProps

const Index = (_: Props) => {
/* TODO: 各ページの実装 */
return <PageTop />
}

export default Index
Loading