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

[김미소] Week13 #425

Merged
merged 3 commits into from
May 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
8 changes: 8 additions & 0 deletions .babelrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"presets": [
"next/babel"
],
"plugins": [
"babel-plugin-styled-components"
]
}
62 changes: 62 additions & 0 deletions components/common/Footer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import Link from "next/link";
import SocialLinkButton from "./SocialLinkButton";
import {
FootInner,
FootNav,
FootSign,
FootSocial,
FootWrap,
} from "./footerStyle";
export interface IImageSnsArr {
id: string;
src: string;
link: string;
}
Comment on lines +10 to +14
Copy link
Collaborator

Choose a reason for hiding this comment

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

다음 타입은 배열이 아닌 것으로 보입니다 !

다음과 같이 Arr을 없애보는건 어떨까요?

Suggested change
export interface IImageSnsArr {
id: string;
src: string;
link: string;
}
export interface IImageSns {
id: string;
src: string;
link: string;
}

Copy link
Collaborator

Choose a reason for hiding this comment

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

또한, Footer 컴포넌트에서 IImageSns 타입을 반환하고 있습니다.
FooterIImageSns를 사용하고만 있는데 export까지 해주면 Footer.tsx의 역할이 많아질 것으로 우려됩니다 !
ImageSns 컴포넌트를 따로 만들어서 Props를 정의하여 export 하거나, 앱 내에 자주 사용될 것으로 보인다면 타입 파일을 따로 만드시는게 어떨까요?

const imageSnsArr: IImageSnsArr[] = [
{
id: "Facebook",
src: "/assets/icon/icons_face.svg",
link: "https://www.facebook.com/?locale=ko_KR",
},
{
id: "Twitter",
src: "/assets/icon/icons_twt.svg",
link: "https://twitter.com/?lang=ko",
},
{
id: "YouTube",
src: "/assets/icon/icons_you.svg",
link: "https://www.youtube.com/",
},
{
id: "Instagram",
src: "/assets/icon/icons_ins.svg",
link: "https://www.instagram.com/",
},
];
Comment on lines +15 to +36
Copy link
Collaborator

Choose a reason for hiding this comment

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

또한 타입 추론으로도 가능합니다.

만약, IImageSnsArr 타입이 재사용성이 낮다면 타입 추론을 활용해보시는 게 어떨까 싶어요 !


function Footer() {
return (
<FootWrap className="foot__main">
<FootInner className="foot__inner">
<FootSign className="foot__sign">
<Link href="https://www.codeit.kr/" target="_blank">
©codeit - 2023
</Link>
</FootSign>

<FootNav className="d__flex foot__nav">
<Link href="/privacy">Privacy Policy</Link>
<Link href="/faq">FAQ</Link>
</FootNav>

<FootSocial className="d__flex foot__btn__sns">
{imageSnsArr.map((sns) => (
<SocialLinkButton key={sns.id} {...sns} />
))}
</FootSocial>
</FootInner>
</FootWrap>
);
}
export default Footer;
72 changes: 72 additions & 0 deletions components/common/Header.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import { useEffect, useState } from "react";
import axios from "@/lib/axios";
import { Email, HeaderControl, HeaderInner, HeaderLogo, HeaderUserInfo, HeaderWrap } from "./headerStyle";
import { useRouter } from "next/router";
import { Profile } from "@/styles/commonStyle";
import LinkButton from "./atoms/LinkButton";
import Link from "next/link";
import Image from "next/image";

const logo = '/assets/logo/logo.svg';

export interface IHeaderUser {
id:number,
email:string,
name?:string,
image_source?:string,
created_at?:string,
auth_id:string
}

export interface IHeaderUserLoginInfoApi {
userInfo?: {
data: IHeaderUser[];
};
}

export async function getStaticProps() {
const res = await axios.get(``);
const userInfo = res.data;

return {
props:{
userInfo,
}
}
}

function Header({userInfo}:IHeaderUserLoginInfoApi) {
const {pathname} = useRouter();
Comment on lines +38 to +39
Copy link
Collaborator

Choose a reason for hiding this comment

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

프리티어를 사용해보시는거 어떨까요 ?

Suggested change
function Header({userInfo}:IHeaderUserLoginInfoApi) {
const {pathname} = useRouter();
function Header({ userInfo }: IHeaderUserLoginInfoApi) {
const { pathname } = useRouter();

사소한 줄바꿈, 띄어쓰기 등 코드를 작성하시다보면 자연스럽게 불규칙해지는 경우가 많아요.
이를 돕기 위해서 개발 커뮤니티에서는 개발 경험 향상을 위한 여러가지 도구들이 있는데요.

보편적으로 많이 사용되는 툴은 prettier입니다 !

Prettier: https://prettier.io/

prettier는 vscode plugin에서 install하고 실행할 수 있습니다 ! 🤗

macos 경우 option + shift + f
windows의 경우 alt + shift + f

const [fixed, setFixed] = useState(true);

useEffect(() => {
if (pathname === '/folder') {
setFixed(false);
}
}, [pathname]);

return (
<HeaderWrap className="head__wrap" $position={fixed}>
<HeaderInner>
<HeaderLogo className="head__logo">
<Link href="/">
<img src={logo} alt="linkbrary" />
</Link>
</HeaderLogo>
<HeaderControl className="head__login__box">
{userInfo ? (
<HeaderUserInfo>
<Profile></Profile>
<Email>{userInfo?.data[0].email}</Email>
</HeaderUserInfo>
) : (
<LinkButton $link={'/signin'} $linkClass={'link--gradient link--login large'}>
로그인
</LinkButton>
)}
</HeaderControl>
</HeaderInner>
</HeaderWrap>
);
}
export default Header;
9 changes: 9 additions & 0 deletions components/common/SocialLinkButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { IImageSnsArr } from "./Footer";

export default function SocialLinkButton({ id, src, link }: IImageSnsArr) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

여기서 Props타입을 정의해줘도 되겠군요 !

Suggested change
export default function SocialLinkButton({ id, src, link }: IImageSnsArr) {
export default function SocialLinkButton({ id, src, link }: { id: string, src: string, link: string }) {

해당 파일에서만 사용 되는 것으로 보여요. 그렇다면 Footer에서 타입 추론으로 객체를 정의해두고 해당 컴포넌트에 props를 내려줘도 될 것 같아요.

return (
<a href={link} target="_blank">
<img src={src} alt={id + "이동 버튼"} />
Copy link
Collaborator

Choose a reason for hiding this comment

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

alt는 대체 텍스트예요:

Suggested change
<img src={src} alt={id + "이동 버튼"} />
<img src={src} alt={id + " 아이콘"} />

alt는 스크린 리더 사용자에 대한 보조 텍스트가 될 수 있으므로 "어떠한 이미지 인지"를 작성해주는 것이 좋아요 !

alt의 목적

  • 인터넷 연결이 끊겼을 때 대체되는 이미지
  • 스크린 리더 사용자를 위한 대체 텍스트
  • 이미지를 볼 수 없는 환경에서 이미지를 대체하기 위한 텍스트
    등 목적을 알게 된다면 alt를 어떻게 사용하시면 될지 알 수 있을 것 같아요.

다음은 하버드 에듀케이션에서 제안하는 alt 규칙입니다:

tl;dr

  • Write Good Alt Text
  • Add alt text all non-decorative images.
  • Keep it short and descriptive, like a tweet.
  • Don’t include “image of” or “photo of”.
  • Leave alt text blank if the image is purely decorative
  • It's not necessary to add text in the Title field.

원문 보기

</a>
);
}
32 changes: 32 additions & 0 deletions components/common/atoms/Button.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { ButtonHTMLAttributes } from 'react';
import { ButtonModule } from './buttonStyle';
interface IButtonModule {
children: React.ReactNode;
$btnClass: string;
$BeforButtonIcon?: string;
$id?: string;
$afterButtonIcon?: string;
$type?: ButtonHTMLAttributes<HTMLButtonElement>['type'];
onclick?: () => void;
}

export default function Button({
children,
$btnClass,
$type = 'button',
$BeforButtonIcon = '',
$afterButtonIcon = '',
onclick,
}: IButtonModule) {
return (
<ButtonModule
className={$btnClass}
type={$type}
$BeforButtonIcon={$BeforButtonIcon}
$afterButtonIcon={$afterButtonIcon}
onClick={onclick}
>
{children}
</ButtonModule>
);
}
33 changes: 33 additions & 0 deletions components/common/atoms/CheckBox.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { IModal } from '../../modal/interface';
import { CheckBoxWrap } from './checkBoxStyle';

interface ICheckBoxData {
$data: IModal['$modalData'];
}

function CheckBox({ $data }: ICheckBoxData) {
if ($data?.data) {
return (
<CheckBoxWrap className="chk--list-type1">
{$data &&
$data.data.map((list: any) => (
<div className="inner" key={list.id}>
<input type="checkbox" id={list.id} />
<label htmlFor={list.id}>
<strong>{list.name}</strong>
<span>{list.link.count}개 링크</span>
</label>
</div>
))}
</CheckBoxWrap>
);
} else {
return (
<div>
<input type="text" />
<label htmlFor=""></label>
</div>
);
}
}
export default CheckBox;
71 changes: 71 additions & 0 deletions components/common/atoms/Input.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import { ChangeEvent, ReactNode, useEffect, useRef, useState } from 'react';
import { InputModule } from './inputStyle';
import Button from './Button';
import { SearchResults } from '@/pages/folder/folderStyle';
import { Relative } from '@/styles/commonStyle';

interface IButtonModule {
$type?: string;
$inputClass?: string;
$btnShow?: boolean;
$placeholder?: string;
$beforeBgIcon?: string;
$btnClass?: string;
children?: ReactNode;
$clickEvent?: string;
onchange?: (value: string) => void;
}

function Input({
$btnShow = false,
$type = 'text',
$inputClass,
$placeholder,
$beforeBgIcon = '',
$btnClass = '',
children,
$clickEvent,
onchange,
}: IButtonModule) {
const [value, setValue] = useState('');
const refInput = useRef(null);
const handleChangInput = (e: ChangeEvent<HTMLInputElement>) => {
const { value } = e.target;
setValue(value);

if (onchange) {
// value값 전달
onchange(value);
}
};

const handleButtonEvent = (text: string) => {
if (!$clickEvent) return;
if ($clickEvent === 'reset') {
setValue('');
}
};

return (
<>
<Relative>
<InputModule
type={$type}
className={$inputClass}
placeholder={$placeholder}
value={value}
onChange={handleChangInput}
$beforeBgIcon={$beforeBgIcon}
ref={refInput}
/>
{$btnShow && (
<Button $btnClass={$btnClass} onclick={() => handleButtonEvent(value)}>
{children}
</Button>
)}
Comment on lines +61 to +65
Copy link
Collaborator

Choose a reason for hiding this comment

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

input인데 버튼도 함께 있군요.

둘을 떼어놓거나 input의 레이아웃을 변경하기는 어려워보입니다. atoms 관점으로 본다면 최소한의 단위로 사용되기는 어려움이 있어보이는데 미소님의 생각이 궁금합니다 !

</Relative>
{value && <SearchResults><span>{value} </span>으로 검색한 결과입니다.</SearchResults>}
</>
);
}
export default Input;
20 changes: 20 additions & 0 deletions components/common/atoms/LinkButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { LinkModule } from "./LinkButtonStyle";
interface IButtonModule {
children: React.ReactNode;
$link: string;
$linkClass: string;
$target?: string;
}

export default function LinkButton({
children,
$link,
$linkClass,
$target="_self"
}: IButtonModule) {
return (
<LinkModule href={$link} className={$linkClass} target="$target">
{children}
</LinkModule>
);
}
49 changes: 49 additions & 0 deletions components/common/atoms/LinkButtonStyle.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import styled from "styled-components";
import { theme } from "@/styles/theme";
import Link from "next/link";
import { font24 } from "@/styles/commonStyle";


export const LinkModule = styled(Link)`
display: block;
text-align: center;
&.link {
&--gradient {
color: #fff;
font-weight: 600;
text-align:center;
background:${theme.bgColor.gradient};
border-radius: 8px;
}
&--login {
width: 128px;
font-size: 18px;
@media screen and (max-width: ${theme.screenSize.moLarge}) {
width: 80px;
}
}
&--title {
&-text {
${font24}
}
}
}
&.full {
width: 100% !important;
}
&.large {
font-size: 18px;
line-height: 53px;
font-weight: 600;
@media screen and (max-width: ${theme.screenSize.moLarge}) {
font-size: 14px;
line-height: 37px;
}
}
&.mideum {
width: 80px;
font-size: 14px;
line-height: 37px;
font-weight: 600;
}
`
Loading
Loading