diff --git a/.stylelintrc.json b/.stylelintrc.json index e67f227e..e7750f1a 100644 --- a/.stylelintrc.json +++ b/.stylelintrc.json @@ -22,6 +22,7 @@ "noEmptyLineBetween": true, "properties": [ "display", + "gap", "justify-content", "align-items", "flex-direction", @@ -30,6 +31,12 @@ "flex-grow", "flex-shrink", "flex-basis", + "grid-template-columns", + "grid-area", + "grid-template-rows", + "grid-column", + "grid-template-areas", + "grid-gap", "position", "top", "right", @@ -77,6 +84,8 @@ "border-style", "background", "background-color", + "background-position", + "background-size", "color", "font-style", "font-weight", diff --git a/README.md b/README.md index ee635805..25cd5492 100644 --- a/README.md +++ b/README.md @@ -1 +1,151 @@ -아루밍 비니 쩡우 도리 큐비들 사랑해~❤️ +
+

💌 Lecue 💌

+ +로고 대문 이미지 +
+ +
+ +## 💡서비스 소개 +다 함께 마음을 전해요. 최애를 위한 우리들의 롤링페이퍼, 레큐 + +- 최애만을 위한 레큐북을 만들고 링크로 전달해요. +- 각자의 마음을 담아 레큐노트를 작성해요. +- 다 함께 레큐북을 꾸며요. + +
+ +## ✨ OUR TEAM + +| 프로필사진 | 프로필사진 | 프로필사진 | 프로필사진 | +| :-------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------: | +|
[짱리드]아름
|
은빈
|
정우
|
도윤
| +| [@Arooming](https://github.com/Arooming) | [@eunbeann](https://github.com/eunbeann) | [@jungwoo3490](https://github.com/jungwoo3490) | [@binllionaire](https://github.com/binllionaire) | + + +
+ +

🛠 기술스택

+ +
+ +| 역할 | 종류 | +| -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Library | ![React](https://img.shields.io/badge/React-61DAFB?style=for-the-badge&logo=React&logoColor=black) | +| Programming Language | ![TypeScript](https://img.shields.io/badge/TypeScript-3178C6?style=for-the-badge&logo=TypeScript&logoColor=white) | +| Styling | ![Emotion](https://img.shields.io/badge/Emotion-000000?style=for-the-badge&logo=emotion&logoColor=white) | +| Data Fetching | ![React Query](https://img.shields.io/badge/react--query-FF4154?style=for-the-badge&logo=react-query&logoColor=white) | +| State Management | ![State Management](https://img.shields.io/badge/recoil-007af4?style=for-the-badge&logo=Recoil&logoColor=white) | +| Formatting | ![ESLint](https://img.shields.io/badge/ESLint-4B3263?style=for-the-badge&logo=eslint&logoColor=white) ![Prettier](https://img.shields.io/badge/prettier-1A2C34?style=for-the-badge&logo=prettier&logoColor=F7BA3E) ![StyleLint](https://img.shields.io/badge/stylelint-E0EFEF?style=for-the-badge&logo=stylelint&logoColor=000) | +| Package Manager | ![Yarn](https://img.shields.io/badge/Yarn-2C8EBB?style=for-the-badge&logo=yarn&logoColor=white) | +| Version Control | ![Git](https://img.shields.io/badge/git-%23F05033.svg?style=for-the-badge&logo=git&logoColor=white) ![GitHub](https://img.shields.io/badge/github-%23121011.svg?style=for-the-badge&logo=github&logoColor=white) | +| Deployment | ![Vercel](https://img.shields.io/badge/Vercel-000000?style=for-the-badge&logo=vercel&logoColor=white) | + +
+ +
+ +

💡 주요 라이브러리

+ +``` + "@emotion/react": "^11.11.3", + "@emotion/styled": "^11.11.0", + "axios": "^1.6.5", + "postcss": "^8.4.33", + "react-query": "^3.39.3", + "react-router-dom": "^6.21.1", + "vite-plugin-svgr": "^4.2.0" +``` + +
+ +

📄 컨벤션 및 브랜치 전략

+

🔽💌 큐비들 공간 💌🔽

+ + +
+ +## 💻 Commit 컨벤션 + +- 기본적인것 (feat, fix, chore, ..) 위주로만 지키기! + +| 제목 | 내용 | +| ----------- | -------------------------------------------------------------------------------- | +| init | 브랜치 첫 커밋 | +| feat | 새로운 기능을 추가할 경우 | +| style | 기능에 영향을 주지 않는 커밋, 코드 순서, css 등의 포맷에 관한 커밋 | +| fix | 버그를 고친 경우 | +| refactor | 코드 리팩토링에 대한 커밋 | +| docs | 문서를 수정한 경우, 파일 삭제, 파일명 수정 등 | +| chore | 빌드 테스트 업데이트, 패키지 매니저를 설정하는 경우, 주석 추가, 자잘한 문서 수정 | + +
+ +## 🎋 브랜치 전략 +- **`feature/페이지명`** + - feature/SelectPage (파스칼) +- **`페이지명/#이슈번호-기능설명`** + - SelectPage/#3-select-custom (-로 연결) + +- 페이지명/이슈번호-기능설명 브랜치 ⇒ feature/페이지명으로 머지 +- feature/페이지명 완료 되면 ⇒ develop으로 머지 +- 중간 중간 develop ⇒ main 머지 + +
+ +## 💒 브랜치 운영 +- **main**: 우리가 개발 최종시에 Merge를 하는 곳 ❗️ +- **develop** : 개발할때 Merge +- **hotfix** : QA 시 수정사항 반영 +- **feature**: 기능을 개발하면서 각자가 사용할 브랜치 +- **test**: 개인 연습 브랜치 + +
+ +

📁 폴더 구조

+ +- 지역성의 원칙을 고려한 폴더구조 +- 한글 네이밍 가능 + +``` +├── public 🗂 썸네일 이미지, 로고 이미지 저장 +├── .eslintrc.cjs ✨ 린트 설정 +├── .prettierrc.cjs ✨ 프리티어 설정 +├── package.json 📦 설치된 패키지를 관리하는 파일 +└── src + ├── App.tsx ✡️ 앱의 라우팅과 글로벌 스타일 지정 + │ + ├── main.tsx + │ + ├── Router.tsx ✡️ 라우터 설정 + │ + ├── assets + │ ├── icon 🖼 이미지 파일들 저장 + │ ├── └── svgs 🌁 svg 파일들 저장 + │ + ├── components 🗂 공통 컴포넌트들 저장 + │ └── Modal.tsx + │ + ├── Login 🗂 각 기능 별 폴더 생성 + │ ├── pages 🗂 라우팅 시 보여질 페이지 컴포넌트 저장 + │ │ └── LoginPage.tsx + │ ├── components 🗂 해당 기능을 구현하는데 필요한 컴포넌트 저장 + │ │ ├── LoginFooter.tsx + │ │ ├── LoginCallback.tsx + │ │ └── LoginHome.tsx + │ │ + │ └── constants 🗂 상수 파일 저장 + │ + ├── styles 🗂 전역 스타일 관련 파일들 저장 + │ ├── GlobalStyle.ts + │ └── theme.ts + │ + ├── utils 🗂 util 함수 관련 파일들 저장 + │ + ├── libs 🗂 라이브러리리 관련 파일 저장 + │ ├── hooks 🗂 커스텀 훅 저장 + │ ├── api.ts + │ +``` + +
diff --git a/index.html b/index.html index 2f69458c..61d50fb4 100644 --- a/index.html +++ b/index.html @@ -7,6 +7,7 @@
+
diff --git a/package.json b/package.json index f51ae401..e4f3c5d9 100644 --- a/package.json +++ b/package.json @@ -14,6 +14,7 @@ "@emotion/styled": "^11.11.0", "axios": "^1.6.5", "eslint-plugin-react": "^7.33.2", + "lottie-react": "^2.4.0", "postcss": "^8.4.33", "postcss-styled-syntax": "^0.6.3", "prettier": "^3.1.1", diff --git a/src/Detail/components/.gitkeep b/src/Detail/components/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/src/Detail/components/BigLecueNote/BigLecueNote.style.ts b/src/Detail/components/BigLecueNote/BigLecueNote.style.ts new file mode 100644 index 00000000..9f24aaba --- /dev/null +++ b/src/Detail/components/BigLecueNote/BigLecueNote.style.ts @@ -0,0 +1,77 @@ +import styled from '@emotion/styled'; + +export const BigLecueNoteWrapper = styled.div<{ + noteBackgroundColor: number; + noteBackgroundImage: string; + noteTextColor: number; +}>` + width: 100%; + height: 34.2rem; + padding: 2rem 1.1rem 1.7rem 1.9rem; + + border-radius: 0.6rem; + background: ${({ theme, noteBackgroundColor, noteBackgroundImage }) => { + if (noteBackgroundColor === -1) { + return `url(${noteBackgroundImage})`; + } else { + switch (noteBackgroundColor) { + case 1: + return theme.colors.sub_pink; + case 2: + return theme.colors.sub_blue; + case 3: + return theme.colors.sub_green; + case 4: + return theme.colors.sub_purple; + case 5: + return theme.colors.sub_yellow; + case 6: + return theme.colors.sub_ivory; + default: + return 'transparent'; + } + } + }}; + background-size: cover; + color: ${({ theme, noteTextColor }) => { + switch (noteTextColor) { + case 0: + return theme.colors.white; + case 1: + return theme.colors.BG; + } + }}; +`; + +export const BigLecueNoteNickname = styled.p` + ${({ theme }) => theme.fonts.Head1_B_20}; +`; + +export const BigLecueNoteContentWrapper = styled.div` + display: flex; + justify-content: center; + align-items: center; + overflow: scroll; + + width: 100%; + height: 22.4rem; + padding-right: 0.8rem; + margin-top: 1.5rem; +`; + +export const BigLecueNoteContent = styled.div` + width: 100%; + max-height: 100%; + + ${({ theme }) => theme.fonts.Body1_R_16}; +`; + +export const BigLecueNoteDate = styled.p` + width: 100%; + padding-right: 0.8rem; + margin-top: 2.1rem; + + ${({ theme }) => theme.fonts.E_Body2_R_14}; + + text-align: end; +`; diff --git a/src/Detail/components/BigLecueNote/index.tsx b/src/Detail/components/BigLecueNote/index.tsx new file mode 100644 index 00000000..7bb04427 --- /dev/null +++ b/src/Detail/components/BigLecueNote/index.tsx @@ -0,0 +1,35 @@ +import * as S from './BigLecueNote.style'; + +interface BigLecueNoteProps { + content: string; + noteDate: string; + noteNickname: string; + noteTextColor: number; + noteBackgroundColor: number; + noteBackgroundImage: string; +} + +function BigLecueNote({ + content, + noteDate, + noteNickname, + noteTextColor, + noteBackgroundColor, + noteBackgroundImage, +}: BigLecueNoteProps) { + return ( + + {noteNickname} + + {content} + + {noteDate} + + ); +} + +export default BigLecueNote; diff --git a/src/Detail/components/BookInfoBox/BookInfoBox.style.ts b/src/Detail/components/BookInfoBox/BookInfoBox.style.ts new file mode 100644 index 00000000..77c89392 --- /dev/null +++ b/src/Detail/components/BookInfoBox/BookInfoBox.style.ts @@ -0,0 +1,93 @@ +import styled from '@emotion/styled'; + +export const BookInfoBoxWrapper = styled.div<{ backgroundColor: number }>` + display: flex; + + width: 100%; + height: 18.3em; + + background-color: ${({ theme, backgroundColor }) => { + switch (backgroundColor) { + case 0: + return theme.colors.BG; + case 1: + return theme.colors.white; + } + }}; +`; + +export const ProfileImageWrapper = styled.div` + display: flex; + align-items: center; + + margin-left: 1.6rem; +`; + +export const ProfileImg = styled.img` + width: 12.6rem; + height: 12.6rem; + + border-radius: 8.2rem; + + object-fit: cover; +`; + +export const BookInfoWrapper = styled.div` + padding: 2.2rem 1.7rem; +`; + +export const BookInfoHeader = styled.div` + display: flex; + align-items: center; + column-gap: 0.9rem; +`; + +export const BookInfoHeaderItemWrapper = styled.div` + display: flex; + align-items: center; + column-gap: 0.3rem; +`; + +export const BookInfoHeaderItem = styled.p<{ backgroundColor: number }>` + height: 1.8rem; + padding-top: 0.4rem; + + color: ${({ theme, backgroundColor }) => { + switch (backgroundColor) { + case 0: + return theme.colors.white30; + case 1: + return theme.colors.MG; + } + }}; + ${({ theme }) => theme.fonts.E_Caption_R_12}; +`; + +export const BookInfoTitle = styled.p<{ backgroundColor: number }>` + margin-top: 0.7rem; + + color: ${({ theme, backgroundColor }) => { + switch (backgroundColor) { + case 0: + return theme.colors.white; + case 1: + return theme.colors.BG; + } + }}; + ${({ theme }) => theme.fonts.Head2_SB_18}; +`; + +export const BookInfoContent = styled.p<{ backgroundColor: number }>` + height: 8.5rem; + margin-top: 1rem; + + color: ${({ theme, backgroundColor }) => { + switch (backgroundColor) { + case 0: + return theme.colors.white80; + case 1: + return theme.colors.BG; + } + }}; + ${({ theme }) => theme.fonts.Body3_R_14}; +`; diff --git a/src/Detail/components/BookInfoBox/index.tsx b/src/Detail/components/BookInfoBox/index.tsx new file mode 100644 index 00000000..4fcaea64 --- /dev/null +++ b/src/Detail/components/BookInfoBox/index.tsx @@ -0,0 +1,52 @@ +import { IcCrown, IcDate } from '../../../assets'; +import * as S from './BookInfoBox.style'; + +interface BookInfoBoxProps { + profileImg: string; + date: string; + nickname: string; + title: string; + content: string; + backgroundColor: number; +} + +function BookInfoBox({ + profileImg, + date, + nickname, + title, + content, + backgroundColor, +}: BookInfoBoxProps) { + return ( + + + + + + + + + + {date} + + + + + + {nickname} + + + + + {title} + + + {content} + + + + ); +} + +export default BookInfoBox; diff --git a/src/Detail/components/LecueNoteLIstHeader/LecueNoteListHeader.style.ts b/src/Detail/components/LecueNoteLIstHeader/LecueNoteListHeader.style.ts new file mode 100644 index 00000000..1c4dc714 --- /dev/null +++ b/src/Detail/components/LecueNoteLIstHeader/LecueNoteListHeader.style.ts @@ -0,0 +1,50 @@ +import styled from '@emotion/styled'; + +export const LecueNoteListHeaderWrapper = styled.div<{ + backgroundColor: number; +}>` + display: flex; + position: sticky; + top: 9.8rem; + z-index: 2; + + padding: 1.2rem 1.65rem 0; + + background-color: transparent; + column-gap: 1rem; +`; + +export const LecueNoteCountBox = styled.div<{ backgroundColor: number }>` + display: flex; + justify-content: center; + align-items: center; + + padding: 1.05rem 1.8rem; + + border-radius: 7rem; + background-color: ${({ theme, backgroundColor }) => { + switch (backgroundColor) { + case 0: + return theme.colors.BG; + case 1: + return theme.colors.white; + } + }}; + color: ${({ theme, backgroundColor }) => { + switch (backgroundColor) { + case 0: + return theme.colors.white; + case 1: + return theme.colors.BG; + } + }}; + ${({ theme }) => theme.fonts.E_Body2_R_14}; +`; + +export const LecueNoteRenderModeButton = styled.button` + position: relative; + z-index: 2; + + width: 3.8rem; + height: 3.8rem; +`; diff --git a/src/Detail/components/LecueNoteLIstHeader/index.tsx b/src/Detail/components/LecueNoteLIstHeader/index.tsx new file mode 100644 index 00000000..132031d2 --- /dev/null +++ b/src/Detail/components/LecueNoteLIstHeader/index.tsx @@ -0,0 +1,29 @@ +import { BtnFloatingList, BtnFloatingPostit } from '../../../assets'; +import * as S from './LecueNoteListHeader.style'; + +interface LecueNoteListHeaderProps { + noteNum: number; + backgroundColor: number; + isZigZagView: boolean; + buttonOnClick: () => void; +} + +function LecueNoteListHeader({ + noteNum, + backgroundColor, + isZigZagView, + buttonOnClick, +}: LecueNoteListHeaderProps) { + return ( + + {`${noteNum}개`} + + {isZigZagView ? : } + + + ); +} + +export default LecueNoteListHeader; diff --git a/src/Detail/components/LecueNoteListContainer/LecueNoteListContainer.style.ts b/src/Detail/components/LecueNoteListContainer/LecueNoteListContainer.style.ts new file mode 100644 index 00000000..553b1ebb --- /dev/null +++ b/src/Detail/components/LecueNoteListContainer/LecueNoteListContainer.style.ts @@ -0,0 +1,24 @@ +import styled from '@emotion/styled'; + +export const LecueNoteListContainerWrapper = styled.div<{ + backgroundColor: number; +}>` + padding: 0 1.65rem; + + background-color: ${({ theme, backgroundColor }) => { + switch (backgroundColor) { + case 0: + return theme.colors.white; + case 1: + return theme.colors.BG; + } + }}; + flex: 1; +`; + +export const LecueNoteListViewWrapper = styled.div` + display: flex; + justify-content: center; + + width: 100%; +`; diff --git a/src/Detail/components/LecueNoteListContainer/index.tsx b/src/Detail/components/LecueNoteListContainer/index.tsx new file mode 100644 index 00000000..a06b4ccf --- /dev/null +++ b/src/Detail/components/LecueNoteListContainer/index.tsx @@ -0,0 +1,50 @@ +import { useState } from 'react'; + +import LecueNoteListHeader from '../LecueNoteLIstHeader'; +import LinearView from '../LinearView'; +import ZigZagView from '../ZigZagView'; +import * as S from './LecueNoteListContainer.style'; + +interface Note { + noteId: number; + renderType: number; + content: string; + noteDate: string; + noteNickname: string; + noteTextColor: number; + noteBackgroundColor: number; + noteBackgroundImage: string; +} + +interface LecueNoteListContainerProps { + noteNum: number; + backgroundColor: number; + noteList: Note[]; +} + +function LecueNoteListContainer({ + noteNum, + backgroundColor, + noteList, +}: LecueNoteListContainerProps) { + const [isZigZagView, setIsZigZagView] = useState(true); + return ( + + setIsZigZagView(!isZigZagView)} + /> + + {isZigZagView ? ( + + ) : ( + + )} + + + ); +} + +export default LecueNoteListContainer; diff --git a/src/Detail/components/LecueNoteModal/LecueNoteModal.style.ts b/src/Detail/components/LecueNoteModal/LecueNoteModal.style.ts new file mode 100644 index 00000000..feb29c2f --- /dev/null +++ b/src/Detail/components/LecueNoteModal/LecueNoteModal.style.ts @@ -0,0 +1,105 @@ +import styled from '@emotion/styled'; + +export const BlurryContainer = styled.div` + display: flex; + justify-content: center; + align-items: center; + position: fixed; + top: 0; + left: 0; + z-index: 9999; + + width: 100vw; + height: 100vh; + + background-color: ${({ theme }) => theme.colors.Modal}; +`; + +export const LecueNoteModalWrapper = styled.div<{ + noteBackgroundColor: number; + noteBackgroundImage: string; + noteTextColor: number; +}>` + position: relative; + + width: 31.1rem; + height: 35.8rem; + padding: 2rem 1.5rem; + + border-radius: 0.4rem; + background: ${({ theme, noteBackgroundColor, noteBackgroundImage }) => { + if (noteBackgroundColor === -1) { + return `url(${noteBackgroundImage})`; + } else { + switch (noteBackgroundColor) { + case 1: + return theme.colors.sub_pink; + case 2: + return theme.colors.sub_blue; + case 3: + return theme.colors.sub_green; + case 4: + return theme.colors.sub_purple; + case 5: + return theme.colors.sub_yellow; + case 6: + return theme.colors.sub_ivory; + default: + return 'transparent'; + } + } + }}; + background-size: cover; + color: ${({ theme, noteTextColor }) => { + switch (noteTextColor) { + case 0: + return theme.colors.white; + case 1: + return theme.colors.BG; + } + }}; +`; + +export const CloseButton = styled.button` + position: absolute; + top: 0.6rem; + right: 0.6rem; + + width: 3.2rem; + height: 3.2rem; +`; + +export const LecueNoteModalNickname = styled.p` + ${({ theme }) => theme.fonts.Head2_SB_18}; +`; + +export const LecueNoteModalContentWrapper = styled.div` + display: flex; + justify-content: center; + align-items: center; + overflow: scroll; + + width: 100%; + height: 23.4rem; + padding: 1.3rem 0.6rem; + margin-top: 3rem; +`; + +export const LecueNoteModalContent = styled.p` + width: 100%; + max-height: 100%; + + ${({ theme }) => theme.fonts.Title2_M_16}; +`; + +export const LecueNoteModalDate = styled.p` + width: 100%; + max-height: 100%; + + padding-right: 0.6rem; + margin-top: 1.3rem; + + ${({ theme }) => theme.fonts.E_Body2_R_14}; + + text-align: end; +`; diff --git a/src/Detail/components/LecueNoteModal/index.tsx b/src/Detail/components/LecueNoteModal/index.tsx new file mode 100644 index 00000000..c0ece624 --- /dev/null +++ b/src/Detail/components/LecueNoteModal/index.tsx @@ -0,0 +1,50 @@ +import { createPortal } from 'react-dom'; + +import { IcX } from '../../../assets'; +import * as S from './LecueNoteModal.style'; +const modalContainer = document.getElementById( + 'lecuenote-modal', +) as HTMLElement; + +interface Note { + noteId: number; + renderType: number; + content: string; + noteDate: string; + noteNickname: string; + noteTextColor: number; + noteBackgroundColor: number; + noteBackgroundImage: string; +} + +interface LecueNoteModalProps { + selectedNote: Note | null; +} + +function LecueNoteModal({ selectedNote }: LecueNoteModalProps) { + return createPortal( + + + + + + + {selectedNote?.noteNickname} + + + + {selectedNote?.content} + + + {selectedNote?.noteDate} + + , + modalContainer, + ); +} + +export default LecueNoteModal; diff --git a/src/Detail/components/LinearView/LinearView.style.ts b/src/Detail/components/LinearView/LinearView.style.ts new file mode 100644 index 00000000..236977bb --- /dev/null +++ b/src/Detail/components/LinearView/LinearView.style.ts @@ -0,0 +1,11 @@ +import styled from '@emotion/styled'; + +export const LinearViewWrapper = styled.div` + display: flex; + align-items: center; + flex-direction: column; + + width: 100%; + padding: 1.8rem 0 2.5rem; + row-gap: 1.8rem; +`; diff --git a/src/Detail/components/LinearView/index.tsx b/src/Detail/components/LinearView/index.tsx new file mode 100644 index 00000000..e5d1c02a --- /dev/null +++ b/src/Detail/components/LinearView/index.tsx @@ -0,0 +1,29 @@ +import BigLecueNote from '../BigLecueNote'; +import * as S from './LinearView.style'; + +interface Note { + noteId: number; + renderType: number; + content: string; + noteDate: string; + noteNickname: string; + noteTextColor: number; + noteBackgroundColor: number; + noteBackgroundImage: string; +} + +interface LinearViewProps { + noteList: Note[]; +} + +function LinearView({ noteList }: LinearViewProps) { + return ( + + {noteList.map((note) => ( + + ))} + + ); +} + +export default LinearView; diff --git a/src/Detail/components/SlideBanner/SlideBanner.style.ts b/src/Detail/components/SlideBanner/SlideBanner.style.ts new file mode 100644 index 00000000..724f6553 --- /dev/null +++ b/src/Detail/components/SlideBanner/SlideBanner.style.ts @@ -0,0 +1,51 @@ +import { keyframes } from '@emotion/react'; +import styled from '@emotion/styled'; + +export const infiniteSlide = keyframes` + 0% { + transform: translateX(0); + } + + 100% { + transform: translateX(-50%); + } +`; + +export const SliderBannerWrapper = styled.div` + position: fixed; + overflow: hidden; + z-index: 1; + + width: 100%; + height: 4.4rem; + + border-bottom: 0.1rem solid ${({ theme }) => theme.colors.BG}; + background-color: ${({ theme }) => theme.colors.key}; +`; + +export const AnimationBox = styled.div<{ + width: number; + animationDuration: number; +}>` + display: flex; + + width: ${(props) => props.width}rem; + max-width: none; + + height: 100%; + + animation: ${infiniteSlide}; + animation-duration: ${(props) => props.animationDuration}s; + animation-timing-function: linear; + animation-iteration-count: infinite; +`; + +export const SlideBannerItemList = styled.div<{ width: number }>` + display: flex; + align-items: center; + + width: ${(props) => props.width}rem; + max-width: none; + + height: 100%; +`; diff --git a/src/Detail/components/SlideBanner/index.tsx b/src/Detail/components/SlideBanner/index.tsx new file mode 100644 index 00000000..289e3bee --- /dev/null +++ b/src/Detail/components/SlideBanner/index.tsx @@ -0,0 +1,54 @@ +import { useEffect, useRef, useState } from 'react'; + +import SlideBannerItem from '../SlideBannerItem'; +import * as S from './SlideBanner.style'; + +interface SlideBannerProps { + name: string; +} + +function SlideBanner({ name }: SlideBannerProps) { + const itemBoxRef = useRef(null); + const [itemListWidth, setItemListWidth] = useState(0); + const [animationListWidth, setAnimationListWidth] = useState(0); + const [animationDuration, setAnimationDuration] = useState(10); + + const renderSlideBannerItems = () => { + return Array.from({ length: 10 }, (_, index) => ( + + )); + }; + + useEffect(() => { + if (itemBoxRef.current) { + const itemBoxWidth = itemBoxRef.current.offsetWidth; + + const itemListWidth = itemBoxWidth + 6; + + setItemListWidth(itemListWidth); + setAnimationListWidth(itemListWidth * 2); + + const nameLength = name.length; + const newAnimationDuration = Math.max(1, nameLength * 7); + setAnimationDuration(newAnimationDuration); + } + }, [name]); + + return ( + + + + {renderSlideBannerItems()} + + + {renderSlideBannerItems()} + + + + ); +} + +export default SlideBanner; diff --git a/src/Detail/components/SlideBannerItem/SlideBannerItem.style.ts b/src/Detail/components/SlideBannerItem/SlideBannerItem.style.ts new file mode 100644 index 00000000..971b0261 --- /dev/null +++ b/src/Detail/components/SlideBannerItem/SlideBannerItem.style.ts @@ -0,0 +1,15 @@ +import styled from '@emotion/styled'; + +export const SliderBannerItemWrapper = styled.div` + display: flex; + flex-shrink: 0; + + width: auto; + margin-right: 0.6rem; +`; + +export const Name = styled.p` + margin: 0.3rem 0.6rem 0; + + ${({ theme }) => theme.fonts.Orange}; +`; diff --git a/src/Detail/components/SlideBannerItem/index.tsx b/src/Detail/components/SlideBannerItem/index.tsx new file mode 100644 index 00000000..db6dae47 --- /dev/null +++ b/src/Detail/components/SlideBannerItem/index.tsx @@ -0,0 +1,23 @@ +import React, { forwardRef } from 'react'; + +import { ImgLe, ImgStarOrangeLine } from '../../../assets'; +import * as S from './SlideBannerItem.style'; + +interface SlideBannerItemProps { + name: string; +} + +const SlideBannerItem = forwardRef(function SlideBannerItem( + { name }: SlideBannerItemProps, + ref: React.Ref, +) { + return ( + }> + + {`( ${name} )`} + + + ); +}); + +export default SlideBannerItem; diff --git a/src/Detail/components/SmallLecueNote/SmallLecueNote.style.ts b/src/Detail/components/SmallLecueNote/SmallLecueNote.style.ts new file mode 100644 index 00000000..f4fdc5c1 --- /dev/null +++ b/src/Detail/components/SmallLecueNote/SmallLecueNote.style.ts @@ -0,0 +1,116 @@ +import styled from '@emotion/styled'; + +export const SmallLecueNoteWrapper = styled.div<{ + renderType: number; + noteTextColor: number; + noteBackgroundColor: number; + noteBackgroundImage: string; +}>` + width: 15.2rem; + height: 16.6rem; + padding: 1.4rem 1rem 0.9rem; + margin: ${({ renderType }) => { + switch (renderType) { + case 1: + return '3.5rem 0 0 0.803rem'; + case 2: + return '0.6rem 0 0 0.86rem'; + case 3: + return '3.2rem 0 0 0.86rem'; + case 4: + return '0.81rem 0 0 0.803rem'; + case 5: + return '3rem 0 0 0.991rem'; + case 6: + return '1rem 0 0 0.926rem'; + } + }}; + + border-radius: 0.4rem; + background: ${({ theme, noteBackgroundColor, noteBackgroundImage }) => { + if (noteBackgroundColor === -1 && noteBackgroundImage) { + return `url(${noteBackgroundImage})`; + } else { + switch (noteBackgroundColor) { + case 1: + return theme.colors.sub_pink; + case 2: + return theme.colors.sub_blue; + case 3: + return theme.colors.sub_green; + case 4: + return theme.colors.sub_purple; + case 5: + return theme.colors.sub_yellow; + case 6: + return theme.colors.sub_ivory; + default: + return 'transparent'; + } + } + }}; + background-size: cover; + color: ${({ theme, noteTextColor }) => { + switch (noteTextColor) { + case 0: + return theme.colors.white; + case 1: + return theme.colors.BG; + } + }}; + + transform: ${({ renderType }) => { + switch (renderType) { + case 1: + return 'rotate(4deg)'; + case 2: + return 'rotate(-4deg)'; + case 3: + return 'rotate(-4deg)'; + case 4: + return 'rotate(4deg)'; + case 5: + return 'rotate(6deg)'; + case 6: + return 'rotate(-6deg)'; + } + }}; +`; + +export const SmallLecueNoteNickName = styled.p` + ${({ theme }) => theme.fonts.Title1_SB_16}; +`; + +export const SmallLecueNoteContentWrapper = styled.div` + display: flex; + justify-content: center; + align-items: center; + + height: 10rem; + margin-top: 0.6rem; + + ${({ theme }) => theme.fonts.Body2_M_14}; +`; + +export const SmallLecueNoteContent = styled.p` + display: -webkit-box; + -webkit-box-orient: vertical; + + overflow: hidden; + text-overflow: ellipsis; + -webkit-line-clamp: 5; + + max-height: 100%; + + ${({ theme }) => theme.fonts.Body2_M_14}; +`; + +export const SmallLecueNoteDate = styled.p` + width: 100%; + margin-top: 0.8rem; + + color: ${({ theme }) => theme.colors.DG50}; + ${({ theme }) => theme.fonts.E_Caption_R_12}; + + text-align: right; +`; diff --git a/src/Detail/components/SmallLecueNote/index.tsx b/src/Detail/components/SmallLecueNote/index.tsx new file mode 100644 index 00000000..11519b80 --- /dev/null +++ b/src/Detail/components/SmallLecueNote/index.tsx @@ -0,0 +1,69 @@ +import { useState } from 'react'; + +import LecueNoteModal from '../LecueNoteModal'; +import * as S from './SmallLecueNote.style'; + +interface Note { + noteId: number; + renderType: number; + content: string; + noteDate: string; + noteNickname: string; + noteTextColor: number; + noteBackgroundColor: number; + noteBackgroundImage: string; +} + +interface SmallLecueNoteProps { + renderType: number; + content: string; + noteDate: string; + noteNickname: string; + noteTextColor: number; + noteBackgroundColor: number; + noteBackgroundImage: string; + noteId: number; + noteList: Note[]; +} + +function SmallLecueNote({ + renderType, + content, + noteDate, + noteNickname, + noteTextColor, + noteBackgroundColor, + noteBackgroundImage, + noteId, + noteList, +}: SmallLecueNoteProps) { + const [modalShow, setModalShow] = useState(false); + + const getClickedNote = () => noteList.find((note) => note.noteId === noteId); + + const handleClickSmallLecueNote = () => { + const clickedNote = getClickedNote(); + if (clickedNote) { + setModalShow((prevModalShow) => !prevModalShow); + } + }; + + return ( + + {noteNickname} + + {content} + + {noteDate} + {modalShow && } + + ); +} + +export default SmallLecueNote; diff --git a/src/Detail/components/ZigZagView/ZigZagView.style.ts b/src/Detail/components/ZigZagView/ZigZagView.style.ts new file mode 100644 index 00000000..07f3f26d --- /dev/null +++ b/src/Detail/components/ZigZagView/ZigZagView.style.ts @@ -0,0 +1,14 @@ +import styled from '@emotion/styled'; + +export const ZigZagViewWrapper = styled.div` + display: grid; + grid-template-columns: repeat(2, 1fr); + + width: 34.2rem; + padding: 0.4rem 0 2rem; +`; + +export const LecueNoteContainer = styled.div` + width: 100%; + height: 20.6rem; +`; diff --git a/src/Detail/components/ZigZagView/index.tsx b/src/Detail/components/ZigZagView/index.tsx new file mode 100644 index 00000000..61cb8158 --- /dev/null +++ b/src/Detail/components/ZigZagView/index.tsx @@ -0,0 +1,30 @@ +import SmallLecueNote from '../SmallLecueNote'; +import * as S from './ZigZagView.style'; + +interface Note { + noteId: number; + renderType: number; + content: string; + noteDate: string; + noteNickname: string; + noteBackgroundColor: number; + noteBackgroundImage: string; +} + +interface ZigZagViewProps { + noteList: Note[]; +} + +function ZigZagView({ noteList }: ZigZagViewProps) { + return ( + + {noteList.map((note) => ( + + + + ))} + + ); +} + +export default ZigZagView; diff --git a/src/Detail/constants/.gitkeep b/src/Detail/constants/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/src/Detail/hooks/.gitkeep b/src/Detail/hooks/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/src/Detail/page/DetailPage/DetailPage.style.ts b/src/Detail/page/DetailPage/DetailPage.style.ts new file mode 100644 index 00000000..a1f6c1ac --- /dev/null +++ b/src/Detail/page/DetailPage/DetailPage.style.ts @@ -0,0 +1,36 @@ +import styled from '@emotion/styled'; + +export const DetailPageWrapper = styled.div` + display: flex; + align-items: center; + flex-direction: column; + + width: 100vw; + height: 100dvh; +`; + +export const DetailPageBodyWrapper = styled.div` + margin-top: 5.4rem; +`; + +export const LecueBookContainer = styled.div` + margin-top: 4.4rem; +`; + +export const StickerButton = styled.button` + position: fixed; + right: 2.057rem; + bottom: 9.8rem; + + width: 6.8rem; + height: 6.8rem; +`; + +export const WriteButton = styled.button` + position: fixed; + right: 2.057rem; + bottom: 2rem; + + width: 6.8rem; + height: 6.8rem; +`; diff --git a/src/Detail/page/DetailPage/index.tsx b/src/Detail/page/DetailPage/index.tsx new file mode 100644 index 00000000..5232b4e4 --- /dev/null +++ b/src/Detail/page/DetailPage/index.tsx @@ -0,0 +1,141 @@ +import { + BtnFloatingSticker, + BtnFloatingStickerOrange, + BtnFloatingWrite, + BtnFloatingWriteOrange, +} from '../../../assets'; +import Header from '../../../components/common/Header'; +import BookInfoBox from '../../components/BookInfoBox'; +import LecueNoteListContainer from '../../components/LecueNoteListContainer'; +import SlideBanner from '../../components/SlideBanner'; +import * as S from './DetailPage.style'; + +// test + +const testProp = { + name: 'LeoJ', + profileImg: + 'https://s3-alpha-sig.figma.com/img/db13/905b/40596e7ff9d7e2c5d23d2b59eaed1a7f?Expires=1705276800&Key-Pair-Id=APKAQ4GOSFWCVNEHN3O4&Signature=YdVtmax5JokofS88zzvQYV8dhDYNr5gALJf1s0eyCl9siaRilm9ZtXOtCSOe~UsH~~K5jEkb81jG3ccCA9FJ25BvUgR9K388K7h90OcCHmn-Wo4enHTIV85J2U2yIiOqh8IDoKNxG9H2hHxKVBU8GzdNitXCkUHtAaxTZRN4taiMZkVFyrFCEw-04VBKywXmAAOd3EaWJ0rJgKqecBpOKnB6DT6HgHlX3wxWhHsQI1KKqueJmXLhT4n-AxWCVALVJDdoT3VvB9-AsecG5C6og89535kPkOmVxUhwhQunmAmWYev0bPDhaSQpVDUwyVDUHgVUmuENYB4Y017o5RjiFA__', + date: '2024.01.25', + nickname: '큐야', + title: '첫 예능 라디오스타 축하해!', + content: + '우리만의 스타 레오제이 !! 3년만에 첫 예능이자 라디오스타 출연 넘 축하해~!! 앞으로 계속 이렇게 우리 옆에 있어줘! 항상 응원할게! 어그래그래어엉', + noteNum: 123123243, + backgroundColor: 1, + noteList: [ + { + noteId: 1, + renderType: 1, + content: + '야야야양야야야양야양 다음에 웨비고? 다음에 웨비고? 다음에 웨비고? 다음에 웨비고? 다음에 웨비고? 다음에 웨비고? 다음에야야야양야야야양야양 다음에 웨비고? 다음에 웨비고? 다음에 웨비고? 다음에 웨비고? 다음에 웨비고? 다음에 웨비고? 다음에야야야양야야야양야양 다음에 웨비고? 다음에 웨비고? 다음에 웨비고? 다음에 웨비고? 다음에 웨비고? 다음에 웨비고? 다음에야야야양야야야양야양 다음에 웨비고? 다음에 웨비고? 다음에 웨비고? 다음에 웨비고? 다음에 웨비고? 다음에 웨비고? 다음에야야야양야야야양야양 다음에 웨비고? 다음에 웨비고? 다음에 웨비고? 다음에 웨비고? 다음에 웨비고? 다음에 웨비고? 다음에야야야양야야야양야양 다음에 웨비고? 다음에 웨비고? 다음에 웨비고? 다음에 웨비고? 다음에 웨비고? 다음에 웨비고? 다음에야야야양야야야양야양 다음에 웨비고? 다음에 웨비고? 다음에 웨비고? 다음에 웨비고? 다음에 웨비고? 다음에 웨비고? 다음에야야야양야야야양야양 다음에 웨비고? 다음에 웨비고? 다음에 웨비고? 다음에 웨비고? 다음에 웨비고? 다음에 웨비고? 다음에야야야양야야야양야양 다음에 웨비고? 다음에 웨비고? 다음에 웨비고? 다음에 웨비고? 다음에 웨비고? 다음에 웨비고? 다음에야야야양야야야양야양 다음에 웨비고? 다음에 웨비고? 다음에 웨비고? 다음에 웨비고? 다음에 웨비고? 다음에 웨비고? 다음에', + noteDate: '2024. 01. 09', + noteNickname: '웹팟이미래다크크', + noteTextColor: 0, + noteBackgroundColor: -1, + noteBackgroundImage: + 'https://lequu-server-bucket.s3.ap-northeast-2.amazonaws.com/notes/background_image/469456ec-5894-4014-8b90-332d453217ba.jpg', + }, + { + noteId: 2, + renderType: 2, + content: '야야야양야야야양야양 다음에 웨비고?', + noteDate: '2024. 01. 09', + noteNickname: '웹팟이미래다크크', + noteTextColor: 1, + noteBackgroundColor: -1, + noteBackgroundImage: + 'https://lequu-server-bucket.s3.ap-northeast-2.amazonaws.com/notes/background_image/912ac7e2-672a-4f26-b115-b90cda4d7cc3.jpg', + }, + { + noteId: 3, + renderType: 3, + content: + '야야야양야야야양야양 다음에 웨비고? 다음에 웨비고? 다음에 웨비고? 다음에 웨비고? 다음에 웨비고? 다음에 웨비고? 다음에', + noteDate: '2024. 01. 09', + noteNickname: '웹팟이미래다크크', + noteTextColor: 0, + noteBackgroundColor: -1, + noteBackgroundImage: + 'https://lequu-server-bucket.s3.ap-northeast-2.amazonaws.com/notes/background_image/676c2ca3-f868-423f-8000-a0bcb67dc797.jpg', + }, + { + noteId: 4, + renderType: 4, + content: + '야야야양야야야양야양 다음에 웨비고? 다음에 웨비고? 다음에 웨비고? 다음에 웨비고? 다음에 웨비고? 다음에 웨비고? 다음에', + noteDate: '2024. 01. 09', + noteNickname: '웹팟이미래다크크', + noteTextColor: 1, + noteBackgroundColor: 4, + noteBackgroundImage: '', + }, + { + noteId: 5, + renderType: 5, + content: + '야야야양야야야양야양 다음에 웨비고? 다음에 웨비고? 다음에 웨비고? 다음에 웨비고? 다음에 웨비고? 다음에 웨비고? 다음에', + noteDate: '2024. 01. 09', + noteNickname: '웹팟이미래다크크', + noteTextColor: 0, + noteBackgroundColor: -1, + noteBackgroundImage: + 'https://lequu-server-bucket.s3.ap-northeast-2.amazonaws.com/notes/background_image/676c2ca3-f868-423f-8000-a0bcb67dc797.jpg', + }, + { + noteId: 6, + renderType: 6, + content: + '야야야양야야야양야양 다음에 웨비고? 다음에 웨비고? 다음에 웨비고? 다음에 웨비고? 다음에 웨비고? 다음에 웨비고? 다음에', + noteDate: '2024. 01. 09', + noteNickname: '웹팟이미래다크크', + noteTextColor: 1, + noteBackgroundColor: -1, + noteBackgroundImage: + 'https://lequu-server-bucket.s3.ap-northeast-2.amazonaws.com/notes/background_image/469456ec-5894-4014-8b90-332d453217ba.jpg', + }, + ], +}; + +function DetailPage() { + const handleClickStickerButton = () => { + // 스티커 페이지 이동 + }; + + const handleClickWriteButton = () => { + // 레큐노트 작성 페이지 이동 + }; + + return ( + +
+ + + + + + + + + {testProp.backgroundColor === 0 ? ( + + ) : ( + + )} + + + {testProp.backgroundColor === 0 ? ( + + ) : ( + + )} + + + ); +} + +export default DetailPage; diff --git a/src/HealthTest.tsx b/src/HealthTest.tsx new file mode 100644 index 00000000..1d2bb4d3 --- /dev/null +++ b/src/HealthTest.tsx @@ -0,0 +1,23 @@ +import { useEffect, useState } from 'react'; + +import { api } from './libs/api'; + +interface TestType { + status: string; +} + +function HealthTest() { + const [data, setData] = useState(); + const getHealthCheck = async () => { + const data = await api.get('/actuator/health'); + setData(data.data); + }; + + useEffect(() => { + getHealthCheck(); + }, []); + + return
status : {data?.status}
; +} + +export default HealthTest; diff --git a/src/Home/page/HomePage.tsx b/src/Home/page/HomePage.tsx index 991219a8..d37c9029 100644 --- a/src/Home/page/HomePage.tsx +++ b/src/Home/page/HomePage.tsx @@ -1,8 +1,9 @@ +import Header from '../../components/common/Header'; + function HomePage() { return (
-

HomePage

-

HomeHome

+
); } diff --git a/src/LecueNote/components/CreateNote/CreateNote.style.ts b/src/LecueNote/components/CreateNote/CreateNote.style.ts new file mode 100644 index 00000000..9fcb1774 --- /dev/null +++ b/src/LecueNote/components/CreateNote/CreateNote.style.ts @@ -0,0 +1,11 @@ +import styled from '@emotion/styled'; + +export const Wrapper = styled.section` + display: flex; + flex-direction: column; + + width: 100%; + margin: 7.8rem 0 3.3rem; + + gap: 3.2rem; +`; diff --git a/src/LecueNote/components/CreateNote/index.tsx b/src/LecueNote/components/CreateNote/index.tsx new file mode 100644 index 00000000..783b7711 --- /dev/null +++ b/src/LecueNote/components/CreateNote/index.tsx @@ -0,0 +1,46 @@ +import { useState } from 'react'; +import { + BG_COLOR_CHART, + CATEGORY, + TEXT_COLOR_CHART, +} from '../../constants/colorChart'; +import SelectColor from '../SelectColor'; +import WriteNote from '../WriteNote'; +import * as S from './CreateNote.style'; + +function CreateNote() { + const [clickedCategory, setclickedCategory] = useState(CATEGORY[0]); + const [clickedTextColor, setClickedTextColor] = useState(TEXT_COLOR_CHART[0]); + const [clickedBgColor, setclickedBgColor] = useState(BG_COLOR_CHART[0]); + + const handleClickCategory = ( + e: React.MouseEvent, + ) => { + setclickedCategory(e.currentTarget.innerHTML); + }; + + const handleClickedColorBtn = ( + e: React.MouseEvent, + ) => { + if (clickedCategory === '텍스트색') { + setClickedTextColor(e.currentTarget.id); + } else { + setclickedBgColor(e.currentTarget.id); + } + }; + + return ( + + + + + ); +} + +export default CreateNote; diff --git a/src/LecueNote/components/Footer/Footer.style.ts b/src/LecueNote/components/Footer/Footer.style.ts new file mode 100644 index 00000000..8c2bec6b --- /dev/null +++ b/src/LecueNote/components/Footer/Footer.style.ts @@ -0,0 +1,10 @@ +import styled from '@emotion/styled'; + +export const Wrapper = styled.footer` + display: flex; + justify-content: center; + align-items: end; + + width: 100%; + margin-bottom: 2rem; +`; diff --git a/src/LecueNote/components/Footer/index.tsx b/src/LecueNote/components/Footer/index.tsx new file mode 100644 index 00000000..38a8f217 --- /dev/null +++ b/src/LecueNote/components/Footer/index.tsx @@ -0,0 +1,14 @@ +import Button from '../../../components/common/Button'; +import * as S from './Footer.style'; + +function Footer() { + return ( + + + + ); +} + +export default Footer; diff --git a/src/LecueNote/components/SelectColor/SelectColor.style.ts b/src/LecueNote/components/SelectColor/SelectColor.style.ts new file mode 100644 index 00000000..e07545f1 --- /dev/null +++ b/src/LecueNote/components/SelectColor/SelectColor.style.ts @@ -0,0 +1,29 @@ +import { css } from '@emotion/react'; +import styled from '@emotion/styled'; + +export const Wrapper = styled.article` + display: flex; + flex-direction: column; + + gap: 1.8rem; +`; + +export const CategoryWrapper = styled.div` + display: flex; + + gap: 1.4rem; +`; + +export const Category = styled.button<{ variant: boolean }>` + ${({ theme, variant }) => + variant + ? css` + ${theme.fonts.Title1_SB_16} + color: ${theme.colors.BG} + ` + : css` + ${theme.fonts.Title2_M_16} + color: ${theme.colors.MG} + `} + background-color: none; +`; diff --git a/src/LecueNote/components/SelectColor/index.tsx b/src/LecueNote/components/SelectColor/index.tsx new file mode 100644 index 00000000..a88032f9 --- /dev/null +++ b/src/LecueNote/components/SelectColor/index.tsx @@ -0,0 +1,51 @@ +import { + BG_COLOR_CHART, + CATEGORY, + TEXT_COLOR_CHART, +} from '../../constants/colorChart'; +import { SelectColorProps } from '../../type/lecueNoteType'; +import ShowColorChart from '../ShowColorChart'; +import * as S from './SelectColor.style'; + +function SelectColor({ + clickedCategory, + clickedTextColor, + clickedBgColor, + handleCategoryFn, + handleColorFn, +}: SelectColorProps) { + return ( + + + {CATEGORY.map((it) => { + return ( + + {it} + + ); + })} + + + {clickedCategory === '텍스트색' ? ( + + ) : ( + + )} + + ); +} + +export default SelectColor; diff --git a/src/LecueNote/components/ShowColorChart/ShowColorChart.style.ts b/src/LecueNote/components/ShowColorChart/ShowColorChart.style.ts new file mode 100644 index 00000000..b432ee29 --- /dev/null +++ b/src/LecueNote/components/ShowColorChart/ShowColorChart.style.ts @@ -0,0 +1,50 @@ +import { css } from '@emotion/react'; +import styled from '@emotion/styled'; + +export const Wrapper = styled.div` + display: flex; + justify-content: flex-start; + align-items: center; + + padding: 0.5rem 0.1rem 0.7rem 0.3rem; + + overflow-x: scroll; + + gap: 1.4rem; +`; + +export const ColorWrapper = styled.div` + display: flex; + justify-content: center; + align-items: center; + flex-shrink: 0; + + width: 3.8rem; + height: 3.8rem; +`; + +export const Color = styled.button<{ $colorCode: string; variant: boolean }>` + border-radius: 3rem; + ${({ $colorCode, theme }) => + $colorCode === '#FFF' && + css` + outline: 0.1rem solid ${theme.colors.WG}; + `}; + background-color: ${({ $colorCode }) => $colorCode}; + + ${({ variant, theme }) => + variant + ? css` + width: 3.8rem; + height: 3.8rem; + + border: 0.4rem solid ${theme.colors.white}; + outline: 0.1rem solid ${theme.colors.WG}; + ` + : css` + width: 3rem; + height: 3rem; + + border: none; + `}; +`; diff --git a/src/LecueNote/components/ShowColorChart/index.tsx b/src/LecueNote/components/ShowColorChart/index.tsx new file mode 100644 index 00000000..3a853cc1 --- /dev/null +++ b/src/LecueNote/components/ShowColorChart/index.tsx @@ -0,0 +1,22 @@ +import { ShowColorChartProps } from '../../type/lecueNoteType'; +import * as S from './ShowColorChart.style'; + +function ShowColorChart({ colorChart, state, handleFn }: ShowColorChartProps) { + return ( + + {colorChart.map((colorCode) => ( + + + + ))} + + ); +} + +export default ShowColorChart; diff --git a/src/LecueNote/components/WriteNote/WriteNote.style.ts b/src/LecueNote/components/WriteNote/WriteNote.style.ts new file mode 100644 index 00000000..63835995 --- /dev/null +++ b/src/LecueNote/components/WriteNote/WriteNote.style.ts @@ -0,0 +1,22 @@ +import styled from '@emotion/styled'; + +export const Wrapper = styled.div` + display: flex; + flex-direction: column; + + gap: 0.4rem; +`; + +export const LecueNote = styled.article<{ $bgColor: string }>` + width: 100%; + height: calc(100dvh - 33rem); + + border-radius: 0.6rem; + background-color: ${({ $bgColor }) => $bgColor}; +`; + +export const Notice = styled.p` + color: ${({ theme }) => theme.colors.key}; + + ${({ theme }) => theme.fonts.Caption1_R_12}; +`; diff --git a/src/LecueNote/components/WriteNote/index.tsx b/src/LecueNote/components/WriteNote/index.tsx new file mode 100644 index 00000000..89196c1e --- /dev/null +++ b/src/LecueNote/components/WriteNote/index.tsx @@ -0,0 +1,13 @@ +import { WriteNoteProps } from '../../type/lecueNoteType'; +import * as S from './WriteNote.style'; + +function WriteNote({ clickedBgColor }: WriteNoteProps) { + return ( + + + *욕설/비속어는 자동 필터링됩니다. + + ); +} + +export default WriteNote; diff --git a/src/LecueNote/constants/colorChart.ts b/src/LecueNote/constants/colorChart.ts new file mode 100644 index 00000000..ea772d97 --- /dev/null +++ b/src/LecueNote/constants/colorChart.ts @@ -0,0 +1,18 @@ +export const CATEGORY = ['텍스트색', '배경색']; + +export const TEXT_COLOR_CHART = ['#191919', '#FFF']; + +export const BG_COLOR_CHART = [ + '#EFB6B6', + '#E5E2CE', + '#F8E99A', + '#85CEAF', + '#B3CBE8', + '#929DD9', + '#FE394C', + '#9852F9', + '#FFD600', + '#98ED4D', + '#FF71B3', + '#CCC', +]; diff --git a/src/LecueNote/page/LeceuNotePage/LecueNotePage.style.ts b/src/LecueNote/page/LeceuNotePage/LecueNotePage.style.ts new file mode 100644 index 00000000..ca2763b5 --- /dev/null +++ b/src/LecueNote/page/LeceuNotePage/LecueNotePage.style.ts @@ -0,0 +1,14 @@ +import styled from '@emotion/styled'; + +export const Wrapper = styled.div` + display: flex; + align-items: center; + flex-direction: column; + position: relative; + overflow: hidden; + + width: 100vw; + height: 100dvh; + + padding: 0 1.7rem; +`; diff --git a/src/LecueNote/page/LeceuNotePage/index.tsx b/src/LecueNote/page/LeceuNotePage/index.tsx new file mode 100644 index 00000000..ed6e4301 --- /dev/null +++ b/src/LecueNote/page/LeceuNotePage/index.tsx @@ -0,0 +1,16 @@ +import Header from '../../../components/common/Header'; +import CreateNote from '../../components/CreateNote'; +import Footer from '../../components/Footer'; +import * as S from './LecueNotePage.style'; + +function LecueNotePage() { + return ( + +
+ +