Skip to content

Commit

Permalink
Merge pull request #14 from raipen/feat/main-page
Browse files Browse the repository at this point in the history
Feat: main page
  • Loading branch information
raipen authored Mar 17, 2024
2 parents 29eb35d + d131d00 commit 474cad0
Show file tree
Hide file tree
Showing 13 changed files with 296 additions and 66 deletions.
4 changes: 2 additions & 2 deletions src/front/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { LoginContext, useInitLoginContext } from '@context/LoginContext';
import LoginedRoute from './LoginedRoute';
import Header from '@components/Header';
import Footer from '@components/Footer';
import Main from '@pages/Main';
import Home from '@pages/Home';
import Login from '@pages/Login';
import Signup from '@pages/Signup';
import MyWordbook from '@pages/MyWordbook';
Expand All @@ -17,7 +17,7 @@ function App() {
<LoginContext.Provider value={value}>
<Header />
<Routes>
<Route path="/" element={<Main />} />
<Route path="/" element={<Home />} />
<Route path="/login" element={<LoginedRoute element={<Login />} isLoginPage={false} />} />
<Route path="/signup" element={<LoginedRoute element={<Signup />} isLoginPage={false} />} />
<Route path="/mywordbook" element={<LoginedRoute element={<MyWordbook />} />} />
Expand Down
Binary file added src/front/assets/createWordbook.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/front/assets/edit.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/front/assets/study.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/front/assets/test.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 1 addition & 4 deletions src/front/components/AddWordbook.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,7 @@ function AddWordbookList({setNewWordbook}: {setNewWordbook: React.Dispatch<React
<AddWordbookContainer as="form">
<WordbookInfo>
<WordbookName>
<span className="material-icons-sharp">
menu_book
</span>
<Input placeholder="단어장 이름(ex. 토익 day1)" ref={inputRef} style={{marginBottom: '10px'}}/>
<Input placeholder="단어장 이름(ex. 토익 day1)" ref={inputRef} style={{marginBottom: '10px', width: '100%'}} />
</WordbookName>
<WordbookDetailInfo createdAt={new Date(new Date().getTime() - new Date().getTimezoneOffset() * 60000).toISOString()} vocaCount={0} />
</WordbookInfo>
Expand Down
16 changes: 10 additions & 6 deletions src/front/components/Footer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,22 @@ import { styled } from 'styled-components';

const FooterContainer = styled.footer`
background-color: #f8f9fa;
padding: 20px;
margin-top: auto;
text-align: center;
width: 100%;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 80px;
`;

function Footer() {
return (
<FooterContainer>
© 2024. <a href="https://github.com/raipen" target="_blank" style={{color:"#8e8bf9",fontWeight:"600"}}>Raipen</a> all rights reserved.
<br/>
<i>contact: [email protected]</i>
<div>
© 2024. <a href="https://github.com/raipen" target="_blank" style={{color:"#8e8bf9",fontWeight:"600"}}>Raipen</a> all rights reserved.
<br/>
<i>contact: [email protected]</i>
</div>
</FooterContainer>
);
}
Expand Down
2 changes: 1 addition & 1 deletion src/front/components/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ function Header() {
const { isLogined, loading, logout} = useContext(LoginContext);
return (
<HeaderContainer>
<Link to="/">
<Link to="/" reloadDocument>
<img src={Logo} alt="로고" />
</Link>
<WordMenu>
Expand Down
83 changes: 81 additions & 2 deletions src/front/components/index.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {styled, css} from 'styled-components';
import {styled, css, keyframes } from 'styled-components';

const FlexRowCenter = css`
display: flex;
Expand Down Expand Up @@ -100,6 +100,7 @@ export const HeaderButton = ReverseButtonWithHoverAnimation;
export const ButtonContainingIcon = styled.button<{ $margin?: string }>`
${ButtonCss};
${MainColorBackground};
word-break: keep-all;
padding: 5px 20px;
${props => props.$margin && `margin: ${props.$margin};`}
gap: 10px;
Expand All @@ -123,11 +124,33 @@ export const MainContainer = styled.main<{ $background?: string, $flexdirection?
width: 100%;
display: flex;
flex-direction: ${props => props.$flexdirection || 'column'};
background-color: ${props => props.$background || 'white'};
background: ${props => props.$background || 'none'};
gap: 20px;
flex-wrap: wrap;
`;

const showUp = keyframes`
0% {
transform: translateY(100%);
opacity: 0;
}
100% {
transform: translateY(0);
opacity: 1;
}
`;

export const HomeContainer = styled(MainContainer)`
flex-grow: 1;
overflow: hidden;
flex-wrap: nowrap;
position: relative;
height: calc(100vh - 70px);
&>*{
animation: ${showUp} 0.8s ease-in-out;
}
`;

export const LoginContainer = styled.form`
padding: 20px 30px;
margin: 0 auto;
Expand Down Expand Up @@ -166,6 +189,7 @@ export const WordbookListContainer = styled.div`
margin-left: auto;
@media (max-width: 600px) {
width: 100%;
padding: 0;
}
`;

Expand Down Expand Up @@ -392,3 +416,58 @@ export const InputWithLabelContainer = styled.div`
&>input {
}
`;

const PageLink = styled.div`
width: fit-content;
gap: 5px;
padding: 5px 10px;
${clickable};
border-radius: 5px;
&:hover {
color: var(--main-color);
background-color: RGBA(0,0,0,0.1);
}
&>span {
text-decoration: underline;
text-underline-offset: 2px;
}
&>.material-icons-sharp {
font-size: 1rem;
text-decoration: none;
margin-right: 5px;
}
`;

export const NewPageLink = ({text}:{text: string|undefined}) => {
return (
<PageLink>
<div className="material-icons-sharp">open_in_new</div>
<span>{text}</span>
</PageLink>
);
}

const BounceAnimation = keyframes`
0%, 100% {
transform: translate(-50%, 0);
}
50% {
transform: translate(-50%, 10px);
}
`;

export const ScrollBottom = styled.div`
${clickable};
position: absolute;
bottom: 10px;
left: 50%;
font-size: 3rem;
width: fit-content;
animation: ${BounceAnimation} 1s infinite;
`;

export const ImageContainer = styled.img`
border: 3px solid var(--main-color);
border-radius: 10px;
`;

73 changes: 73 additions & 0 deletions src/front/hooks/useMainPage.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import { useEffect, useState, useCallback, useMemo } from 'react';

function useMainPage<T>(pageList: Array<T>) {
const [page, setPage] = useState(0);
const [isScrolling, setIsScrolling] = useState(false);

const pageUp = useCallback(() => {
if (page < pageList.length - 1) setPage(page + 1);
}, [page]);

const pageDown = useCallback(() => {
if (page > 0) setPage(page - 1);
}, [page]);

const pageControl = useCallback((type: 'up' | 'down') => {
if (isScrolling) return;
setIsScrolling(true);
if (type === 'up') pageUp();
else pageDown();
setTimeout(() => {
setIsScrolling(false);
}, 1000);
}, [isScrolling, pageUp, pageDown]);

const wheelEvent = useCallback((e: WheelEvent) => {
if(page === pageList.length - 1 && e.deltaY > 0 && !isScrolling) return;
e.preventDefault();
if (e.deltaY > 0) return pageControl('up');
pageControl('down');
}, [pageControl]);

const touchEvent = useCallback(() => {
let startY = 0;
const touchStart = (e: TouchEvent) => {
startY = e.touches[0].clientY;
}
const touchEnd = (e: TouchEvent) => {
const endY = e.changedTouches[0].clientY;
if(startY === 0) return;
if (startY - endY > 50) return pageControl('up');
if (startY - endY < -50) return pageControl('down');
}
return { touchStart, touchEnd };
}, [pageControl]);

const touchMove = useCallback((e: TouchEvent) => {
if(page === pageList.length - 1 && !isScrolling) return;
if(page === 0 && !isScrolling) return;
e.preventDefault();
}, [isScrolling, page]);

useEffect(() => {
window.addEventListener('wheel', wheelEvent, { passive: false });
const { touchStart, touchEnd } = touchEvent();
window.addEventListener('touchstart', touchStart);
window.addEventListener('touchend', touchEnd);
window.addEventListener('touchmove', touchMove, { passive: false });
return () => {
window.removeEventListener('wheel', wheelEvent);
window.removeEventListener('touchstart', touchStart);
window.removeEventListener('touchend', touchEnd);
window.removeEventListener('touchmove', touchMove);
};
}, [wheelEvent, touchEvent]);

useEffect(()=> {
scrollTo(0,0);
}, [page]);

return useMemo(()=>({page,info:pageList[page], pageUp}), [page, pageList, pageUp]);
}

export default useMainPage;
54 changes: 54 additions & 0 deletions src/front/pages/Home.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { HomeContainer,NewPageLink, ScrollBottom,ImageContainer, ButtonContainingIcon } from '@components';
import useMainPage from '@hooks/useMainPage';
import { pageList, ContentsType } from '@utils/homeList';
import { Link } from 'react-router-dom';

function Home() {
const {page,info,pageUp} = useMainPage(pageList);

const a = (
<>
<h2>{info.title}</h2>
{info.contents.map((content, index) => {
switch(content.type) {
case ContentsType.LINK:
return (
<Link to={content.src!} key={index} target="_blank" style={{width:"fit-content"}}>
<NewPageLink text={content.text}/>
</Link>
);
case ContentsType.TEXT:
return <p key={index} style={{whiteSpace:"pre-line"}}>{content.text}</p>;
case ContentsType.IMAGE:
return <ImageContainer key={index} src={content.src} alt="main" style={{maxWidth: "600px"}}/>;
case ContentsType.BUTTON:
return (
<Link to={content.link!} key={index} style={{width:"100%", maxWidth:"350px"}}>
<ButtonContainingIcon style={{width:"100%", padding:"10px", fontSize:"1.5rem"}}>
{content.text}
</ButtonContainingIcon>
</Link>
);
}
})}
{page!==pageList.length -1 && <ScrollBottom onClick={pageUp} className="material-icons-sharp">
keyboard_double_arrow_down
</ScrollBottom>}
</>
)

if(page%2 === 0) return (
<HomeContainer $background={info.background}>
<input type="hidden" value="home"/>
{a}
</HomeContainer>
);

return (
<HomeContainer $background={info.background}>
{a}
</HomeContainer>
);
}

export default Home;
51 changes: 0 additions & 51 deletions src/front/pages/Main.tsx

This file was deleted.

Loading

0 comments on commit 474cad0

Please sign in to comment.