-
Notifications
You must be signed in to change notification settings - Fork 44
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
The head ref may contain hidden characters: "part3-\uAE40\uBBF8\uC18C-week13"
[김미소] Week13 #425
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
{ | ||
"presets": [ | ||
"next/babel" | ||
], | ||
"plugins": [ | ||
"babel-plugin-styled-components" | ||
] | ||
} |
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; | ||
} | ||
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
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 또한 타입 추론으로도 가능합니다.만약, |
||
|
||
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; |
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
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 프리티어를 사용해보시는거 어떨까요 ?
Suggested change
사소한 줄바꿈, 띄어쓰기 등 코드를 작성하시다보면 자연스럽게 불규칙해지는 경우가 많아요. 보편적으로 많이 사용되는 툴은
|
||||||||||
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; |
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) { | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 여기서
|
export default function SocialLinkButton({ id, src, link }: IImageSnsArr) { | |
export default function SocialLinkButton({ id, src, link }: { id: string, src: string, link: string }) { |
해당 파일에서만 사용 되는 것으로 보여요. 그렇다면 Footer
에서 타입 추론으로 객체를 정의해두고 해당 컴포넌트에 props
를 내려줘도 될 것 같아요.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
alt
는 대체 텍스트예요:
<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.
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> | ||
); | ||
} |
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; |
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
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
</Relative> | ||
{value && <SearchResults><span>{value} </span>으로 검색한 결과입니다.</SearchResults>} | ||
</> | ||
); | ||
} | ||
export default Input; |
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> | ||
); | ||
} |
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; | ||
} | ||
` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
다음 타입은 배열이 아닌 것으로 보입니다 !
다음과 같이
Arr
을 없애보는건 어떨까요?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
또한,
Footer
컴포넌트에서IImageSns
타입을 반환하고 있습니다.Footer
가IImageSns
를 사용하고만 있는데export
까지 해주면Footer.tsx
의 역할이 많아질 것으로 우려됩니다 !ImageSns
컴포넌트를 따로 만들어서Props
를 정의하여export
하거나, 앱 내에 자주 사용될 것으로 보인다면 타입 파일을 따로 만드시는게 어떨까요?