Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add dev-test draft #22

Draft
wants to merge 34 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 17 commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
3644102
feat: set global style
Jun99uu Feb 5, 2023
cf38722
feat: add _document file
Jun99uu Feb 5, 2023
4e43b67
feat: add Page-Wrapper for mobile viewport
Jun99uu Feb 5, 2023
544c64c
feat: set DevTest empty Page
Jun99uu Feb 5, 2023
ff07208
feat: add community-StartButton Component
Jun99uu Feb 5, 2023
64f6196
feat: add community-Button Component
Jun99uu Feb 5, 2023
5092f7c
feat: add community-Title Box Component
Jun99uu Feb 5, 2023
8e79f75
feat: add community-Visitor Component
Jun99uu Feb 5, 2023
7b4f980
feat: add design token for community spec
Jun99uu Feb 5, 2023
a4a5534
fix: apply design token
Jun99uu Feb 5, 2023
9029cd1
fix: fix Page Wrapper
Jun99uu Feb 5, 2023
dc97fcc
feat: add absolute path
Jun99uu Feb 5, 2023
b7aa0f8
fix: fix mobile web vh-bug
Jun99uu Feb 5, 2023
db62045
feat: add devtest inner content changing
Jun99uu Feb 5, 2023
1c65c1e
fix: fix font in TitleBox
Jun99uu Feb 5, 2023
6d18e79
fix: fix Font in Button
Jun99uu Feb 5, 2023
6b6cbd8
feat: add questions content page
Jun99uu Feb 5, 2023
9f79c93
fix : change community directory name
Jun99uu Feb 12, 2023
20369b1
fix : fix component dependency and props
Jun99uu Feb 12, 2023
d299b47
fix : take out DevTestPage
Jun99uu Feb 12, 2023
4557271
fix : styling by vanilla-extract
Jun99uu Feb 12, 2023
1fb23c0
feat : add dev-test questions
Jun99uu Feb 13, 2023
0cb2a72
fix : fix Image and fontSize
Jun99uu Feb 14, 2023
b166518
feat : add progress bar
Jun99uu Feb 14, 2023
9aa6685
feat : add feat caculating test-result
Jun99uu Feb 19, 2023
a0bf7ea
fix : fix init value in Progressbar
Jun99uu Feb 19, 2023
d2e4f8a
feat : add result resources(svg)
Jun99uu Feb 19, 2023
1563edb
feat : print dev-test result
Jun99uu Feb 19, 2023
80dab9c
Merge branch 'main' of https://github.com/gdsc-ssu/web into feat/20_d…
Jun99uu Feb 19, 2023
f382802
fix : fix Result type
Jun99uu Feb 20, 2023
4d08f40
feat : add result dom to image function
Jun99uu Feb 28, 2023
89e41d1
feat : add loading spinner
Jun99uu Feb 28, 2023
a38b00e
feat : add useInterval hooks
Jun99uu Feb 28, 2023
7cec2fe
feat : add loading spinner in result page (3s)
Jun99uu Feb 28, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/components/comuunity/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import DevTestPage from './playground/DevTest';

export { DevTestPage };
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🍎 폴더 이름 community인데 comuunity로 오타났어요!

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

헉 수정하겠습니다! 감사해요!!!

76 changes: 76 additions & 0 deletions src/components/comuunity/playground/DevTest/PlayPage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import { questions } from '@/resources/devTestQustions';
import { Dispatch, SetStateAction, useState } from 'react';
import { Button, TitleBox } from '../common';
import { COLORS } from '../common/token';

interface Props {
setStage: Dispatch<SetStateAction<number>>;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🥝 setter 자체를 넘겨주면 외부 로직에 너무 의존성이 높아질 것 같은데, 단순히 '이 스텝이 끝날 때 실행된다'는 의미로 onFinish 또는 onEnd 느낌으로 네이밍을 한 뒤에, 타입을 () => void로 단순히 정의하면 어떨까요? 그리고 외부에서는 이런 식으로 쓰면 될 것 같아요.

const goToNextStep = () => {
  setState(prev => prev + 1);
};

return (
  <PlayPage onEnd={goToNextStep} />
);

이런 느낌으로 하면 더 유연하게 짤 수 있지 않을까요?

그리고 이렇게 한다면 모든 step에 쓰이는 컴포넌트들이 동일한 interface를 가지도록 할 수 있을 것 같아요. 예를 들어서

// src/components/community/playground/DevTest/types.ts
export interface StepProps {
  onEnd?: () => void;
}
// src/components/community/playground/DevTest/PlayPage.tsx
import type { StepProps } from './types';

interface Props extends StepProps {}

이렇게 짜도 좋을 것 같아요!

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

오홍...!! 뭔가 함수 넘겨주기보다 setter 넘겨주는게 편하다고 생각해서 아무 생각없이 이렇게 해왔는데 인터페이스도 통일할 수 있고 의존성 문제도 해결할 수 있겠네요...
수정하겠습니당!!

}

const PlayPage = (props: Props) => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

혹시 props를 spread하지 않는 이유가 따로 있을까요?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ㅋㅋㅋㅋㅋ앗 props가 하나라 귀..찮아서 안했던건데 들켰네효...ㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋ
수정하겠습니당!

const [idx, setIdx] = useState(0);
const [answers, setAnswers] = useState<Array<number>>(
Array(questions.length).fill(0),
);

return (
<div className="devtest__play-page">
<div className="devtest__play-page--question">
<TitleBox title={`Q${idx + 1}`} subtitle={questions[idx].question} />
</div>
<div className="devtest__play-page--select">
{questions[idx].select.map((s, aIdx) => (
<Button
backgroundColor={
answers[idx] === aIdx
? COLORS.grayscale.Black
: COLORS.grayscale.white
}
color={
answers[idx] === aIdx
? COLORS.grayscale.white
: COLORS.grayscale.Black
}
title={s}
onClickHandler={() =>
setAnswers((prev) => prev.map((p, pi) => (idx === pi ? aIdx : p)))
}
key={s}
/>
))}
</div>
<Button
backgroundColor="white"
color={COLORS.SSU.DeepBlue}
title="다음 질문으로!"
onClickHandler={
() =>
idx !== questions.length - 1 //마지막 질문이 아니라면
? setIdx((prev) => prev + 1) //다음 질문으로
: props.setStage((prev) => prev + 1) //마지막 질문이라면 -> 다음 스테이지로
}
/>
<style jsx>{`
.devtest__play-page {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 50px;
}
.devtest__play-page--question,
.devtest__play-page--select {
width: 100%;
display: flex;
flex-direction: column;
align-items: center;
gap: 15px;
}
`}</style>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🍌 저희는 이번 프로젝트에서 스타일링 라이브러리로 vanilla-extract를 사용하기로 했는데, 혹시 styled-jsx를 쓰신 이유가 따로 없다면 vanilla-extract로 바꿔보면 어떨까요?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

넵!! 변경하겠습니당

</div>
);
};

export default PlayPage;
76 changes: 76 additions & 0 deletions src/components/comuunity/playground/DevTest/StartPage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import { StartButton, TitleBox, VisitorBox } from '../common';
import {
COLORS,
TEXT_STYLE_BODY_PC,
TEXT_STYLE_BODY_MOBILE,
} from '../common/token';
import { devTestLogo } from '@/resources/communityRes';
import { Dispatch, SetStateAction } from 'react';

interface Props {
setStage: Dispatch<SetStateAction<number>>;
}

/**
* 시작하기 버튼이 있는 테스트 시작 페이지
*/
const StartPage = (props: Props) => {
return (
<div className="devtest__first-page">
<TitleBox
title="개발자 성향테스트"
subtitle="과연 나는 어떤 개발자일까? "
/>
<VisitorBox today={10} sum={100} />
<StartButton
color={COLORS.SSU.DeepBlue}
title="시작하기"
onClickHandler={() => props.setStage((prev) => prev + 1)}
/>
<span>GDSC Soongsil Univ.</span>
<img src={devTestLogo} alt="devtest-logo" />
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🍌 앗 리뷰하다가 깜빡했는데, 그냥 img 말고 next/image<Image>를 쓰면 좋을 것 같아요! 이건 제가 세팅만 해놓고 테스트를 못해서 궁금해서 여쭈어 보는 건데, 혹시 이 부분에서 eslint warning 떴나요?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

아 헐 Image 까먹고있었어요...ㅋㅋㅋㅋㅋㅋ 수정하겠씁니다!
아뇨 별도의 문제는 없었습니다!!

<style jsx>{`
.devtest__first-page {
width: 100%;
height: 100%;
position: relative;
display: flex;
flex-direction: column;
align-items: center;
justify-content: flex-start;
gap: 30px;
padding-top: 80px;
}
span {
color: white;
font-size: ${TEXT_STYLE_BODY_PC.body2B.fontSize};
font-weight: ${TEXT_STYLE_BODY_PC.body2B.fontWeight};
}
img {
width: 65%;
height: auto;
position: absolute;
bottom: 0px;
left: 50%;
transform: translateX(-50%);
}

@media screen and (max-width: 500px) {
span {
color: white;
font-size: ${TEXT_STYLE_BODY_MOBILE.body2B.fontSize};
font-weight: ${TEXT_STYLE_BODY_MOBILE.body2B.fontWeight};
}
}

@media screen and (min-height: 800px) {
.devtest__first-page {
padding-top: 120px;
}
}
`}</style>
</div>
);
};

export default StartPage;
35 changes: 35 additions & 0 deletions src/components/comuunity/playground/DevTest/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import Wrapper from '../Wrapper';
import StartPage from './StartPage';
import PlayPage from './PlayPage';
import { useState } from 'react';

/**
* 개발자 성향테스트 페이지 최상위 Wrapper
*/
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🍌 PlayPageStartPage의 경우도 마찬가지이지만 특히 index.tsx의 경우 재사용 여지가 없이 devtest 페이지에서만 쓰이기 위한 것으로 보이는데요(실제로 devtest.tsx에 가보면 이 컴포넌트를 import해서 넣는 정도밖에 하고 있지 않구요!), 그러면 components 폴더에 굳이 있을 필요 없이 이 부분의 코드가 devtest.tsx에서 구현되면 되지 않을까요?
components에 있는 것들은 조금 더 재사용성에 초점을 두면 좋을 것 같아요!

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

앗 넵!! 저도 이 부분 작성하면서 잘못된것 같다고 생각하고있었는데... 감사해요! 수정하겠습니다!!

const DevTestPage = () => {
const [stage, setStage] = useState(0);

return (
<div className="devtest__page">
<Wrapper topColor="#00A4CA" bottomColor="#58C4C4">
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이 컬러들은 혹시 이 페이지에서만 사용되는 컬러인가요?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

허걱 아뇨... 토큰에서 가져오는걸로 바꿀게요!

{stage === 0 ? (
<StartPage setStage={setStage} />
) : (
<PlayPage setStage={setStage} />
)}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🥝 stage가 앞으로도 0 또는 1만 있을 거라는 보장이 없으니 조금 더 확장성 있게 설계하면 어떨까요?

const STAGES = [
  StartPage,
  PlayPage,
] as const;

const DevTestPage = () => {
  // ...
  const CurrentPage = STAGES[stage];

  return (
    <div className="devtest__page">
      <Wrapper topColor="#00A4CA" bottomColor="#58C4C4">
        <CurrentPage setStage={setStage} />
          {/* ... */}
  );
};

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

오홍... 훨씬 직관적이네요! 감사합니다~!

</Wrapper>
<style jsx>{`
.devtest__page {
padding: 0;
margin: 0;
background-color: black;
display: flex;
justify-content: center;
align-items: center;
}
`}</style>
</div>
);
};

export default DevTestPage;
46 changes: 46 additions & 0 deletions src/components/comuunity/playground/Wrapper.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
interface Props {
children: React.ReactNode;
topColor: string;
bottomColor: string;
}

/**
* 모바일 중심형 페이지 Wrapper Component
* @param topColor 왼쪽 상단 색상 헥사코드(eg. #00A4CA)
* @param bottomColor 우측 하단 색상 헥사코드
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🍌 이렇게 하면 아마 주석이 제대로 적용이 안 될 텐데, 아래처럼 하면 prop에 마우스를 올렸을 때 주석이 같이 보일 것 같아요!

interface Props {
  children: React.ReactNode;
  /** 왼쪽 상단 색상 헥사코드(eg. #00A4CA) */
  topColor: string;
  /** 우측 하단 색상 헥사코드 */
  bottomColor: string;
}

🥝 topColorbottomColor는 유효한 색상 문자열이기만 하면 동작할 텐데(ex: rgba(0, 0, 0, 0.1)), 주석에 헥사코드라는 제약을 지워도 되지 않을까요?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

아아 넵!! 수정하겠습니다!!

*/
const Wrapper = (props: Props) => {
return (
<div className="container">
{props.children}
<style jsx>{`
.container {
width: 31.2vw;
min-height: 100vh;
height: 100vh;
background: linear-gradient(
135deg,
${props.topColor},
${props.bottomColor}
);
overflow-x: hidden;
}

@media screen and (min-width: 500px) {
.container {
min-width: 500px;
}
}

@media screen and (max-width: 500px) {
.container {
width: 100vw;
height: calc(var(--var, 1vh) * 100);
}
}
`}</style>
</div>
);
};

export default Wrapper;
54 changes: 54 additions & 0 deletions src/components/comuunity/playground/common/Button/Button.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { TEXT_STYLE_BUTTON_PC, TEXT_STYLE_BUTTON_MOBILE } from '../token';

interface Props {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🍌 어차피 내부에서 <button>을 직접적으로 사용하니, <button>이 받을 수 있는 모든 prop을 허용해도 되지 않을까요?

interface Props extends React.ComponentProps<'button'> {
  backgroundColor: string;
  color: string;
  title: string;
}

const Button = ({ backgroundColor, color, title, ...buttonProps }: Props) => {
  return (
    <button {...buttonProps}>
      {/* ... */}
  );
};

이렇게 하면 onClickHandler도 생략할 수 있어요!

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

아 헐... 너무 좋은 것 같아요.... 대박
감사합니다!

backgroundColor: string;
color: string;
title: string;
onClickHandler: () => void;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🍌 onClickHandler라는 표현은 이상한 것 같아요! 그냥 onClick로 하는 게 맞지 않을까요? 예를 들어 <button>을 사용할 때는 <button onClick=... 이런 식으로 사용할 텐데, Button을 사용할 때는 <Button onClickHandler=... 이런 식으로 사용한다는 건 일관성이 없기도 하고 의미가 뭔지 헷갈릴 것 같아요.
그리고 보통 handler는 이 컴포넌트를 소비하는 곳에서 만든 함수 자체를 handler라고 하고, react에서 on prefix를 붙이는 네이밍은 보통 '어떤 일이 일어나면 너가 넘겨준 이 함수를 실행시켜줄게' 느낌으로 사용하기 때문에 handler라고 표현하면 어색할 것 같아요. 예를 들면 보통은 이런 식으로 네이밍합니다!

const handleClick = () => {
  console.log("clicked!");
};

return (
  <button onClick={handleClick} />
);

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

아..!!!! 왜인지 모르겠지만 저는 오히려 onClick이랑 구분해야한다고 생각을 하고있었네요...
전체적으로 네이밍 수정이 필요하겠어요ㅠㅠ 감사합니다!!

}
/**
* 테스트 중 사용될 일반 버튼
* @param backgroundColor 배경색
* @param color 글자색
* @param title 버튼 텍스트
* @param onClickHandler 클릭 이벤트핸들러
*/
const Button = (props: Props) => {
return (
<button onClick={props.onClickHandler}>
{props.title}
<style jsx>{`
button {
border: none;
background-color: ${props.backgroundColor};
width: 90%;
min-width: 270px;
min-height: 50px;
border-radius: 500px;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
box-shadow: rgba(0, 0, 0, 0.05) 0px 10px 50px;

font-size: ${TEXT_STYLE_BUTTON_PC.button4B.fontSize}px;
font-weight: ${TEXT_STYLE_BUTTON_PC.button4B.fontWeight};
font-family: 'SUIT Variable', sans-serif;
white-space: pre-line;
word-break: keep-all;
text-align: center;
color: ${props.color};
}

@media screen and (max-width: 500px) {
button {
font-size: ${TEXT_STYLE_BUTTON_MOBILE.button4B.fontSize}px;
font-weight: ${TEXT_STYLE_BUTTON_MOBILE.button4B.fontWeight};
}
}
`}</style>
</button>
);
};

export default Button;
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { TEXT_STYLE_BUTTON_PC, TEXT_STYLE_BUTTON_MOBILE } from '../token';

interface Props {
color: string; //글자색
title: string; //버튼 텍스트
onClickHandler: () => void;
}

/**
* 플레이그라운드에서 사용하는 시작버튼
* @param color 글자색
* @param title 버튼 텍스트
* @param onClickHandler 클릭 이벤트핸들러
*/
const StartButton = (props: Props) => {
return (
<button onClick={props.onClickHandler}>
{props.title}
<style jsx>{`
button {
border: none;
background-color: white;
width: 65%;
min-width: 220px;
height: 55px;
border-radius: 20px;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
box-shadow: rgba(0, 0, 0, 0.05) 0px 10px 50px;

font-size: ${TEXT_STYLE_BUTTON_PC.button1B.fontSize}px;
font-weight: 800;
font-family: 'SUIT Variable', sans-serif;
white-space: pre-line;
word-break: keep-all;
text-align: center;
color: ${props.color};
}

@media screen and (max-width: 500px) {
button {
font-size: ${TEXT_STYLE_BUTTON_MOBILE.button1B.fontSize}px;
font-weight: 800;
}
}
`}</style>
</button>
);
};

export default StartButton;
Loading