-
Notifications
You must be signed in to change notification settings - Fork 0
[Feat/#74] 인증 화면 개발 #76
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
Merged
Changes from all commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
c7826af
feat(web): 로그인 페이지 SNSLoginButton
seungdeok 80ea91c
feat(web): 로그인 페이지 TextField
seungdeok f6905fd
feat(web): 로그인 페이지 Button
seungdeok d7022e4
feat(web): 회원가입 페이지 TextField
seungdeok 862b540
feat(web): 로그인 페이지 TextField
seungdeok ebdcba2
fix(web): gap 추가
seungdeok File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,33 @@ | ||
| interface ButtonProps { | ||
| label: string; | ||
| style?: React.CSSProperties; | ||
| onClick?: () => void; | ||
| disabled?: boolean; | ||
| className?: string; | ||
| } | ||
|
|
||
| export function Button({ label, style, onClick, disabled, className }: ButtonProps) { | ||
| return ( | ||
| <button | ||
| type="button" | ||
| style={{ | ||
| backgroundColor: disabled ? "#B7B7B7" : "#3A8DFF", | ||
| color: "white", | ||
| borderRadius: "5px", | ||
| height: "50px", | ||
| display: "flex", | ||
| alignItems: "center", | ||
| justifyContent: "center", | ||
| cursor: disabled ? "not-allowed" : "pointer", | ||
| position: "relative", | ||
| width: "100%", | ||
| ...style, | ||
| }} | ||
| onClick={onClick} | ||
| disabled={disabled} | ||
| className={className} | ||
| > | ||
| <span style={{ fontSize: 16, fontWeight: 600, letterSpacing: "-0.32px" }}>{label}</span> | ||
| </button> | ||
| ); | ||
|
seungdeok marked this conversation as resolved.
|
||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,48 @@ | ||
| "use client"; | ||
|
|
||
| import Image from "next/image"; | ||
|
|
||
| export function SNSLoginButton({ provider }: { provider: "google" | "kakao" }) { | ||
| const variants = { | ||
| google: { | ||
| label: "구글 로그인", | ||
| bg: "#FFFFFF", | ||
| color: "#000000", | ||
| border: "1px solid #E3E8EF", | ||
| }, | ||
| kakao: { | ||
| label: "카카오 로그인", | ||
| bg: "#FEE500", | ||
| color: "#000000", | ||
| border: "1px solid #FEE500", | ||
| }, | ||
| }; | ||
|
|
||
| return ( | ||
| <button | ||
| type="button" | ||
| style={{ | ||
| background: variants[provider].bg, | ||
| color: variants[provider].color, | ||
| border: variants[provider].border, | ||
| borderRadius: "5px", | ||
| height: "45px", | ||
| display: "flex", | ||
| alignItems: "center", | ||
| justifyContent: "center", | ||
| cursor: "pointer", | ||
| position: "relative", | ||
| width: "100%", | ||
| }} | ||
| > | ||
| <Image | ||
| src={`/icons/${provider}.svg`} | ||
| alt={variants[provider].label} | ||
| width={26} | ||
| height={26} | ||
| style={{ position: "absolute", left: "25px" }} | ||
| /> | ||
|
seungdeok marked this conversation as resolved.
|
||
| <span style={{ fontSize: 16, fontWeight: 600, letterSpacing: "-0.32px" }}>{variants[provider].label}</span> | ||
| </button> | ||
|
seungdeok marked this conversation as resolved.
|
||
| ); | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,107 @@ | ||
| "use client"; | ||
|
|
||
| import { useId, useState } from "react"; | ||
|
|
||
| interface TextFieldProps { | ||
| type: "text" | "password"; | ||
| label: string; | ||
| validate?: (value: string) => boolean; | ||
| onChange?: (value: string) => void; | ||
| value?: string; | ||
| className?: string; | ||
| style?: React.CSSProperties; | ||
| required?: boolean; | ||
| disabled?: boolean; | ||
| readonly?: boolean; | ||
| placeholder?: string; | ||
| error?: string; | ||
| } | ||
|
|
||
| export function TextField({ | ||
| type, | ||
| label, | ||
| validate, | ||
| onChange, | ||
| value, | ||
| className, | ||
| style, | ||
| required, | ||
| disabled, | ||
| readonly, | ||
| placeholder, | ||
| error, | ||
| }: TextFieldProps) { | ||
| const id = useId(); | ||
| const [isFocused, setIsFocused] = useState(false); | ||
| const hasValidationError = validate ? !validate(value || "") : false; | ||
| const displayError = hasValidationError ? error : ""; | ||
|
seungdeok marked this conversation as resolved.
|
||
|
|
||
| const getBorderColor = () => { | ||
| if (hasValidationError) return "#E52929"; // 에러 상태 | ||
| if (isFocused) return "#3A8DFF"; // focus 상태 | ||
| return "#E3E8EF"; | ||
| }; | ||
|
|
||
| return ( | ||
| <div style={{ position: "relative" }}> | ||
| <label | ||
| style={{ | ||
| color: "#111", | ||
| fontSize: "12px", | ||
| fontStyle: "normal", | ||
| fontWeight: "600", | ||
| lineHeight: "140%", | ||
| letterSpacing: "-0.24px", | ||
| marginBottom: "2px", | ||
| }} | ||
| htmlFor={id} | ||
| > | ||
| {label} | ||
| </label> | ||
| <input | ||
| id={id} | ||
| type={type} | ||
| className={className} | ||
| onChange={onChange ? (e: React.ChangeEvent<HTMLInputElement>) => onChange(e.target.value) : undefined} | ||
| onFocus={() => setIsFocused(true)} | ||
| onBlur={() => setIsFocused(false)} | ||
| value={value} | ||
| required={required} | ||
| disabled={disabled} | ||
| readOnly={readonly} | ||
| placeholder={placeholder} | ||
| style={{ | ||
| width: "100%", | ||
| height: "43px", | ||
| borderBottom: `1px solid ${getBorderColor()}`, | ||
| display: "flex", | ||
| flexDirection: "row", | ||
| alignItems: "center", | ||
| color: "#111", | ||
| fontSize: "14px", | ||
| fontStyle: "normal", | ||
| fontWeight: "500", | ||
| lineHeight: "140%", | ||
| letterSpacing: "-0.28px", | ||
| outline: "none", | ||
| transition: "border-color 0.2s ease-in-out", | ||
| ...style, | ||
| }} | ||
|
seungdeok marked this conversation as resolved.
|
||
| /> | ||
| <span | ||
| style={{ | ||
| color: "#E52929", | ||
| position: "absolute", | ||
| bottom: "-24px", | ||
| left: "0", | ||
| fontSize: "12px", | ||
| fontWeight: "500", | ||
| lineHeight: "140%", | ||
| letterSpacing: "-0.24px", | ||
| }} | ||
| > | ||
| {displayError} | ||
| </span> | ||
|
Comment on lines
+91
to
+104
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. 에러 메시지 위치가 다른 요소와 겹칠 수 있습니다.
다음 중 하나를 고려하세요:
🤖 Prompt for AI Agents |
||
| </div> | ||
| ); | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,103 @@ | ||
| import type { Meta, StoryObj } from "@storybook/nextjs-vite"; | ||
| import React from "react"; | ||
| import { LoginPage } from "."; | ||
| import { Button } from "./components/Button"; | ||
| import { SNSLoginButton } from "./components/SNSLoginButton"; | ||
| import { TextField } from "./components/TextField"; | ||
|
|
||
| const meta = { | ||
| title: "v2/Views/Login", | ||
| component: LoginPage, | ||
| parameters: { | ||
| layout: "centered", | ||
| }, | ||
| tags: ["autodocs"], | ||
| argTypes: {}, | ||
| } satisfies Meta<typeof LoginPage>; | ||
|
|
||
| export default meta; | ||
| type Story = StoryObj<typeof meta>; | ||
|
|
||
| // 구글 로그인 | ||
| export const 구글_로그인: Story = { | ||
| args: {}, | ||
| render: () => ( | ||
| <div style={{ width: "360px" }}> | ||
| <SNSLoginButton provider="google" /> | ||
| </div> | ||
| ), | ||
| }; | ||
|
|
||
| // 카카오 로그인 | ||
| export const 카카오_로그인: Story = { | ||
| args: {}, | ||
| render: () => ( | ||
| <div style={{ width: "360px" }}> | ||
| <SNSLoginButton provider="kakao" /> | ||
| </div> | ||
| ), | ||
| }; | ||
|
|
||
| // 이메일 주소 입력 | ||
| export const 이메일_주소_입력: Story = { | ||
| args: {}, | ||
| render: () => { | ||
| const [email, setEmail] = React.useState(""); | ||
|
|
||
| return ( | ||
| <div style={{ width: "360px" }}> | ||
| <TextField | ||
| type="text" | ||
| label="이메일 주소" | ||
| placeholder="abcdef@naver.com" | ||
| value={email} | ||
| onChange={setEmail} | ||
| error="잘못된 이메일 주소입니다." | ||
| validate={value => { | ||
| // 빈 값이거나 유효한 이메일 형식인지 확인 | ||
| if (value.length === 0) return true; | ||
| const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; | ||
| return emailRegex.test(value); | ||
| }} | ||
| /> | ||
| </div> | ||
| ); | ||
| }, | ||
| }; | ||
|
|
||
| // 비밀번호 입력 | ||
| export const 비밀번호_입력: Story = { | ||
| args: {}, | ||
| render: () => { | ||
| const [password, setPassword] = React.useState(""); | ||
|
|
||
| return ( | ||
| <div style={{ width: "360px" }}> | ||
| <TextField | ||
| type="password" | ||
| label="비밀번호" | ||
| placeholder="8~16자리 영대•소문자, 숫자, 특수문자 조합" | ||
| value={password} | ||
| onChange={setPassword} | ||
| error="잘못된 비밀번호입니다." | ||
| validate={value => { | ||
| // 8~16자리 영대•소문자, 숫자, 특수문자 조합 | ||
| if (value.length === 0) return true; | ||
| return value.length >= 8 && value.length <= 16; | ||
| }} | ||
| /> | ||
| </div> | ||
| ); | ||
| }, | ||
| }; | ||
|
|
||
| // 로그인 버튼 | ||
| export const 로그인_버튼: Story = { | ||
| args: {}, | ||
| render: () => ( | ||
| <div style={{ width: "360px", display: "flex", flexDirection: "column", gap: "12px" }}> | ||
| <Button label="로그인" /> | ||
| <Button label="로그인" disabled /> | ||
| </div> | ||
| ), | ||
| }; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| "use client"; | ||
|
|
||
| export function RegisterPage() { | ||
| return ( | ||
| <div | ||
| style={{ | ||
| display: "flex", | ||
| flexDirection: "column", | ||
| justifyContent: "center", | ||
| alignItems: "center", | ||
| height: "100vh", | ||
| }} | ||
| > | ||
| <div>Register</div> | ||
| </div> | ||
| ); | ||
| } |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
border와 outline 속성을 추가하세요.
button 요소의 기본 border를 제거하지 않으면 브라우저마다 다른 스타일이 적용될 수 있습니다.
다음 diff를 적용하세요:
style={{ backgroundColor: disabled ? "#B7B7B7" : "#3A8DFF", color: "white", + border: "none", + outline: "none", borderRadius: "5px",📝 Committable suggestion
🤖 Prompt for AI Agents