2024. 4. 23. 11:32ㆍReact
20240423 화
반응형 웹
import React, { useEffect, useState } from "react";
import { useNavigate, useParams } from "react-router-dom";
import Badge from '@mui/material/Badge';
import Box from '@mui/material/Box';
import Button from '@mui/material/Button';
import Divider from '@mui/material/Divider';
import Drawer from '@mui/material/Drawer';
import Grid from '@mui/material/Grid';
import IconButton from '@mui/material/IconButton';
import InputBase from '@mui/material/InputBase';
import Link from '@mui/material/Link';
import List from '@mui/material/List';
import ListItem from '@mui/material/ListItem';
import MenuIcon from '@mui/icons-material/Menu';
import Paper from '@mui/material/Paper';
import SearchIcon from '@mui/icons-material/Search';
import Stack from '@mui/material/Stack';
import Typography from '@mui/material/Typography';
import YouTubeIcon from '@mui/icons-material/YouTube';
import VideocamIcon from '@mui/icons-material/Videocam';
import { useAuthContext } from "../context/AuthContext";
import LoginModal from "./LoginModal";
import useWatchVideo from '../hooks/useWatchVideo';
export default function SearchHeader() {
const { keyword } = useParams();
const navigate = useNavigate();
const [text, setText] = useState('');
const [isMenuOpen, setIsMenuOpen] = useState(false);
const handleSubmit = e => {
e.preventDefault();
navigate(`/videos/${text}`);
}
useEffect(() => {
setText(keyword || '');
}, [keyword]);
const { user, logout } = useAuthContext();
const { getCount: { data: count }} = useWatchVideo(user);
return (
<header>
<Stack direction={'row'} alignItems='center'>
<Grid container>
<Grid item xs={2} md={2} lg={3}>
<Link href='/' style={{textDecoration: 'none', color: 'black'}}>
<Stack direction={'row'} spacing={1} alignItems='center'>
<YouTubeIcon color='error' fontSize="large" />
<Typography variant="h4"
sx={{fontWeight: 'bold', display: {xs: 'none', md: 'none', lg: 'flex'}}}>
Youtube
</Typography>
</Stack>
</Link>
</Grid>
<Grid item xs={7} md={6} lg={4}>
<Paper
component="form" onSubmit={handleSubmit}
sx={{ p:'2px 4px', display:'flex', alignItems:'center', width:'100%' }}
>
<InputBase
sx={{ ml: 1, flex: 1 }}
placeholder="검색..."
value={text}
onChange={e => setText(e.target.value)}
/>
<Divider sx={{ height: 28, m: 0.5 }} orientation="vertical" />
<IconButton type="button" sx={{ p: 1 }} aria-label="search" onClick={handleSubmit}>
<SearchIcon />
</IconButton>
</Paper>
</Grid>
<Grid item xs={3} md={4} lg={5}>
<Stack direction='row' spacing={2} justifyContent='right' alignItems='center'
sx={{display: {xs: 'none', md: 'none', lg: 'flex'}}}>
{user && user.isAdmin &&
<Link href='/videos/admin' underline="hover" color='primary'>
<Typography variant="h6">관리자 메뉴</Typography>
</Link>}
{user &&
<Link href='/videos/record' underline="hover" color='primary'>
<Stack direction={'row'} alignItems='center' sx={{mr: 1}}>
<Typography variant="h6">시청기록</Typography>
<Badge badgeContent={count} color="primary">
<VideocamIcon color="action" />
</Badge>
</Stack>
</Link>}
{user && user.photoURL && (
<img src={user.photoURL} alt={user.displayName} height='32' style={{borderRadius:100}} />
)}
{user && <Typography variant="h6">{user.displayName}</Typography>}
{user && (
<Button variant="outlined" onClick={logout}>
로그아웃
</Button>
)}
{!user && <LoginModal />}
</Stack>
<Stack direction='row' spacing={2} justifyContent='right' alignItems='center'
sx={{display: {xs: 'flex', md: 'flex', lg: 'none'}}}>
{(count > 0) &&
<Link href='/videos/record' color='primary'>
<Badge badgeContent={count} color="primary">
<VideocamIcon color="action" />
</Badge>
</Link>}
<IconButton sx={{ p: 1 }} aria-label="menu" color="inherit"
onClick={() => setIsMenuOpen(true)}>
<MenuIcon />
</IconButton>
<Drawer open={isMenuOpen} onClose={() => setIsMenuOpen(false)} anchor="right"
sx={{ "& .MuiDrawer-paper": { height: "20%" } }}>
<Box sx={{ width: 250 }} role="presentation" onClick={() => setIsMenuOpen(false)}>
<List>
{user &&
<ListItem key={'key01'} disablePadding sx={{ px: 2, py: 0.5 }}>
<Link href='/videos/record' color='primary'>
<Typography variant="h6">시청기록</Typography>
</Link>
</ListItem>}
{user && user.isAdmin &&
<ListItem key={'key02'} disablePadding sx={{ px: 2, py: 0.5 }}>
<Link href='/videos/admin' color='primary'>
<Typography variant="h6">관리자 메뉴</Typography>
</Link>
</ListItem>}
<ListItem key={'key03'} disablePadding sx={{ px: 2, py: 0.5 }}>
{user && (
<Button variant="outlined" onClick={logout}>
로그아웃
</Button>
)}
{!user && <LoginModal />}
</ListItem>
</List>
</Box>
</Drawer>
</Stack>
</Grid>
</Grid>
</Stack>
<Divider sx={{my: 1}} />
</header>
)
}
설명 예시 :
로그인 후 youtube 구현 페이지 예시
# one source multi use - 개발 한 것을 스마트폰 태블릿 노트북 데스크탑 에서도 볼 수 있는 것을 지칭하는 말
1) triger point
*1.xs 스마트폰 기준 반응형 normal framework에서 우선순위가 가장 높음 -정확한 픽셀은 검색 후 이용 : 웹브라우저 형태로 볼 수 있게 구현
2.sm 화면 구성요소가 적어짐 (유투브 동영상 갯수)
3.md 로고가 축소
*4.lg
5.xl
hamburger menu > drawer 사용
관리자메뉴 : 아코디언 - xs로 줄어도 상관 없음
2) SearchHeader.jsx
구현 방법 : Grid 가장 밖 : container
container
Grid
xs={2} 7 3 : 12
md={2} 6 4 : 12
lg={3} 4 5 : 12
large 일 때 youtube 글자가 보임
xs일 때는 안보임 - 마크만 보임
sx mui tag css style tag display 속성에 <{sx={{display: {xs: 'none', md: 'none', lg: 'flex'}}}>
3) 줄어들었을 때 웹에 햄버거 메뉴만 보이게 하는 방법
Stack
sx
<{sx={{display: {xs: 'flex', md: 'flex', lg: 'none'}}}>
<(count > 0) &&
menu onClick isMenuOpen: true 면 open 됨 colose: false
anchor="right" 왼쪽이면 튕겨져나감
height 전체에서 20%
관리자 페이지에 사용자별 리스트 보이게 하기
<List>
4) 단위
픽셀 기본 폰트 16px css 기준
반응형에서는 px을 사용하면 좋지 않다
한 글자의 크기 = 1em 이라고 함
fixed font 2d coding font 같음
variable font 가병폰트 제일 큰 글자 대문자 M 길이가 가장 김 프린터 용어 M이 기준이 됨
rem
부모의 텍스트 px
부모 사이지에서 맞는 형태의 자식 글자 사이즈
rem 이라는 단어를 고민해보기
반응형 단위
vw : 내가 표시할 수 있는 width의 100분의 1
vh : 내가 표시할 수 있는 높이의 100분의 1
이미지 일 경우
처음 시작할 때 : 100px > 내 화면에 차지하는 상대하는 비율로 표시하기 10% 20% 등
이미지 : 200px 일 때, 깨질 경우 화질이 떨어지지 않게 maxwidth: 200px 로 잡아서 그 이상은 커지지 않게 하기
'React' 카테고리의 다른 글
20240423 맘대로 해봐라! 3차 프로젝트 FlowNary SNS 6일차 (0) | 2024.04.23 |
---|---|
20240419 맘대로 해봐라! 3차 프로젝트 FlowNary SNS 5일차 (0) | 2024.04.23 |
20240418 맘대로 해봐라! 3차 프로젝트 FlowNary SNS 4일차 (0) | 2024.04.19 |
20240418 맘대로 해봐라! 3차 프로젝트 FlowNary SNS 3일차 (0) | 2024.04.18 |
20240417 맘대로 해봐라! 3차 프로젝트 FlowNary SNS 2일차 (0) | 2024.04.17 |