Skip to content

Commit

Permalink
Merge branch 'release/0.1.5'
Browse files Browse the repository at this point in the history
  • Loading branch information
pipisebastian committed Dec 2, 2024
2 parents 4ab761a + 9f3bb36 commit 167ebf6
Show file tree
Hide file tree
Showing 62 changed files with 1,955 additions and 410 deletions.
8 changes: 8 additions & 0 deletions @noctaCrdt/Interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,7 @@ export interface RemotePageUpdateOperation {
}
export interface WorkSpaceSerializedProps {
id: string;
name: string;
pageList: Page[];
authUser: Map<string, string>;
}
Expand All @@ -190,3 +191,10 @@ export interface RemoteBlockReorderOperation {
client: number;
pageId: string;
}
export interface WorkspaceListItem {
id: string;
name: string;
role: string;
memberCount: number;
activeUsers: number;
}
12 changes: 8 additions & 4 deletions @noctaCrdt/WorkSpace.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,25 +4,29 @@ import { EditorCRDT } from "./Crdt";

export class WorkSpace {
id: string;
name: string;
pageList: Page[];
authUser: Map<string, string>;

constructor(id: string, pageList: Page[]) {
this.id = id;
this.pageList = pageList;
this.authUser = new Map();
constructor(id?: string, name?: string, pageList?: Page[], authUser?: Map<string, string>) {
this.id = id ? id : crypto.randomUUID();
this.name = name ? name : "Untitled";
this.pageList = pageList ? pageList : [];
this.authUser = authUser ? authUser : new Map();
}

serialize(): WorkSpaceSerializedProps {
return {
id: this.id,
name: this.name,
pageList: this.pageList,
authUser: this.authUser,
};
}

deserialize(data: WorkSpaceSerializedProps): void {
this.id = data.id;
this.name = data.name;
this.pageList = data.pageList.map((pageData) => {
const page = new Page();
page.deserialize(pageData);
Expand Down
115 changes: 77 additions & 38 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,69 +1,85 @@
![Group 38 (1)](https://github.com/user-attachments/assets/a882c5c5-b205-43cc-9a16-2f5e87dbd6aa)

![image](https://github.com/user-attachments/assets/ce48d2e5-ca40-43e6-8d64-0f874312f065)


<div align="center">

![image](https://github.com/user-attachments/assets/e7f5453b-ecc8-4087-b0ae-0c72b422103f)

<br>

![image](https://github.com/user-attachments/assets/dba641b3-417d-4bb6-9c87-4cfc78d8324c)
<br>
<a href="https://hits.seeyoufarm.com"><img src="https://hits.seeyoufarm.com/api/count/incr/badge.svg?url=https%3A%2F%2Fgithub.com%2Fboostcampwm-2024%2Fweb33-Nocta&count_bg=%2379C83D&title_bg=%23555555&icon=&icon_color=%23E7E7E7&title=hits&edge_flat=false"/></a>


</div>

<p align="center">
<a href="https://nocta.site" title="๐ŸŒŒ ๋ฐคํ•˜๋Š˜์˜ ๋ณ„๋น›์ฒ˜๋Ÿผ, ์ž์œ ๋กœ์šด ์ธํ„ฐ๋ž™์…˜ ์‹ค์‹œ๊ฐ„ ์—๋””ํ„ฐ"><strong>๋ฐฐํฌ ์‚ฌ์ดํŠธ</strong></a>
</p>
<div align="center">

## ๐Ÿ“‘ ๋ฌธ์„œ ์ž‘์„ฑ์ด ๋” ํŽธํ•˜๊ณ  ์ฆ๊ฑฐ์›Œ์ง„๋‹ค

## `Nocta`
<a href="https://nocta.site" title="๐ŸŒŒ ๋ฐคํ•˜๋Š˜์˜ ๋ณ„๋น›์ฒ˜๋Ÿผ, ์ž์œ ๋กœ์šด ์ธํ„ฐ๋ž™์…˜ ์‹ค์‹œ๊ฐ„ ์—๋””ํ„ฐ"><strong>๋ฐฐํฌ ์‚ฌ์ดํŠธ</strong></a>

> ๐ŸŒŒ ๋ฐคํ•˜๋Š˜์˜ ๋ณ„๋น›์ฒ˜๋Ÿผ, ์ž์œ ๋กœ์šด ์ธํ„ฐ๋ž™์…˜ ์‹ค์‹œ๊ฐ„ ์—๋””ํ„ฐ
**๐Ÿค” ํ•˜๋‚˜์˜ ๋ฌธ์„œ๋ฅผ ์ž‘์„ฑํ•˜๋ฉด์„œ ๋‹ค๋ฅธ ๋ฌธ์„œ๋„ ํ•จ๊ป˜ ๋ณด๊ณ  ์‹ถ์—ˆ๋˜ ์  ์žˆ์œผ์‹ ๊ฐ€์š”?**

- ์‹ค์‹œ๊ฐ„ ๊ธฐ๋ก ํ˜‘์—… ์†Œํ”„ํŠธ์›จ์–ด์ž…๋‹ˆ๋‹ค.
๋ฌธ์„œ ์ž‘์„ฑํ•  ๋•Œ ์—ฌ๋Ÿฌ ์ฐฝ์„ ๋„์›Œ๋‘๊ณ  ๋ฒˆ๊ฑฐ๋กญ๊ฒŒ ์ž‘์—…ํ•˜์…จ๋˜ ๋ถˆํŽธํ•จ์ด ์žˆ์—ˆ์ฃ .

๊ธฐ์กด ์—๋””ํ„ฐ๋“ค์€ ํ•˜๋‚˜์˜ ์ฐฝ์— ๊ฐ‡ํ˜€์žˆ์–ด์„œ, ์ฐธ๊ณ ํ•  ๋‚ด์šฉ์ด ์žˆ์„ ๋•Œ๋งˆ๋‹ค ์ฐฝ์„ ์ด๋™ํ•ด์•ผ ํ–ˆ์–ด์š”.

## `Team Glassmo`
Nocta๋Š” ์—๋””ํ„ฐ์— ์ƒˆ๋กœ์šด ๋ฐ”๋žŒ์„ ๋ถˆ์–ด๋„ฃ์—ˆ์–ด์š”.

**ํƒญ ๋ธŒ๋ผ์šฐ์ง•์œผ๋กœ ์—ฌ๋Ÿฌ ๋ฌธ์„œ๋ฅผ ์ž์œ ๋กญ๊ฒŒ ๋„˜๋‚˜๋“ค ์ˆ˜ ์žˆ๊ณ , ์ธํ„ฐ๋ž™ํ‹ฐ๋ธŒํ•œ ์š”์†Œ๋“ค๋กœ ๋ฌธ์„œ ์ž‘์„ฑ์ด ๋” ํฅ๋ฏธ๋กญ๊ฒŒ ๋ณ€ํ™”๋ฉ๋‹ˆ๋‹ค.**

- ๊ธ€๋ž˜์Šค๋ชจํ”ผ์ฆ˜์˜ ์•ฝ์ž
Nocta์—์„œ ๋‹จ์ˆœํ•œ ๊ธฐ๋ก์„ ๋„˜์–ด, ์ƒˆ๋กœ์šด ๊ธ€์“ฐ๊ธฐ ๊ฒฝํ—˜์„ ์‹œ์ž‘ํ•˜์„ธ์š”.

## ๐Ÿ“… ํ”„๋กœ์ ํŠธ ๊ธฐ๊ฐ„
[๋…ธ์…˜](https://abrupt-feta-9a9.notion.site/web33-12a9ff1b21c38003b600f57baa654626?pvs=4)

> 2024.10.28 ~ 2024.12.06
[๊ธฐํš](https://abrupt-feta-9a9.notion.site/12a9ff1b21c380b4b3bafc3af92b2a25?pvs=4) | [๋””์ž์ธ](https://abrupt-feta-9a9.notion.site/12f9ff1b21c380459f74f7a2e4fb7a93?pvs=4)

## ๐ŸŒฑ ํŒ€์› ์†Œ๊ฐœ
[๊ฐœ๋ฐœ์œ„ํ‚ค](https://abrupt-feta-9a9.notion.site/12a9ff1b21c380f2a490deae65256639?pvs=4) | [DB์Šคํ‚ค๋งˆ](https://abrupt-feta-9a9.notion.site/DB-708e1cf3c1454b3c950bff67d0924dde?pvs=4) | [๋ฐฑ๋กœ๊ทธ](https://abrupt-feta-9a9.notion.site/12e9ff1b21c380ecb202f869f6ad040e?pvs=4)

| ๊น€ํ˜„ํ›ˆ | ๋ฏผ์—ฐ๊ทœ | ๋ฏผ์ •์šฐ | ์žฅ์„œ์œค |
| :-------------------------------------------------------------------: | :-------------------------------------------------------------------: | :--------------------------------------------------------------------: | :-----------------------------------------------------------------------: |
| <img src="https://github.com/hyonun321.png" width="100" height="100"> | <img src="https://github.com/Ludovico7.png" width="100" height="100"> | <img src="https://github.com/minjungw00.png" width="100" height="100"> | <img src="https://github.com/pipisebastian.png" width="100" height="100"> |
| FE+BE | FE | BE | FE |
| [@hyonun321](https://github.com/hyonun321) | [@Ludovico7](https://github.com/Ludovico7) | [@minjungw00](https://github.com/minjungw00) | [@pipisebastian](https://github.com/pipisebastian) |
[๊ทธ๋ผ์šด๋“œ๋ฃฐ](https://abrupt-feta-9a9.notion.site/12a9ff1b21c3807ca2b8e308178e5c2f?pvs=4) | [์Šคํฌ๋ŸผํšŒ์˜๋ก](https://abrupt-feta-9a9.notion.site/12a9ff1b21c38087848fcd2d37445005?pvs=4) | [์Šคํ”„๋ฆฐํŠธํšŒ์˜๋ก](https://abrupt-feta-9a9.notion.site/12a9ff1b21c380ac876cdd60332f5826?pvs=4) | [ํšŒ๊ณ ๋ก](https://abrupt-feta-9a9.notion.site/12a9ff1b21c380959d92e485fcc94f8a?pvs=4)

<a href="https://hits.seeyoufarm.com"><img src="https://hits.seeyoufarm.com/api/count/incr/badge.svg?url=https%3A%2F%2Fgithub.com%2Fboostcampwm-2024%2Fweb33-Nocta&count_bg=%2379C83D&title_bg=%23555555&icon=&icon_color=%23E7E7E7&title=hits&edge_flat=false"/></a>

</div>

## ํ”„๋กœ์ ํŠธ ๊ธฐ๋Šฅ ์†Œ๊ฐœ


### 1. ํŽ˜์ด์ง€ ์ƒ์„ฑ, ๋“œ๋ž˜๊ทธ ์•ค ๋“œ๋ž

์‚ฌ์ด๋“œ๋ฐ”์˜ ํŽ˜์ด์ง€ ์ถ”๊ฐ€ ๋ฒ„ํŠผ์„ ํ†ตํ•ด ํŽ˜์ด์ง€๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
## ๐Ÿšฉ ๋ชฉ์ฐจ

![111111](https://github.com/user-attachments/assets/7bbbd091-a906-49b1-8043-13240bdf2f5b)
- [Nocta๋งŒ์˜ ์ฐจ๋ณ„์ ](#-nocta๋งŒ์˜-์ฐจ๋ณ„์ )
- [๊ธฐ์ˆ ์Šคํƒ](#-๊ธฐ์ˆ -์Šคํƒ)
- [์‹œ์Šคํ…œ ์•„ํ‚คํ…์ฒ˜ ๋‹ค์ด์–ด๊ทธ๋žจ](#์‹œ์Šคํ…œ-์•„ํ‚คํ…์ฒ˜-๋‹ค์ด์–ด๊ทธ๋žจ)
- [ํ”„๋กœ์ ํŠธ ์‹œ์ž‘ ๊ฐ€์ด๋“œ](#-ํ”„๋กœ์ ํŠธ-์‹œ์ž‘-๊ฐ€์ด๋“œ)
- [ํ”„๋กœ์ ํŠธ ๊ธฐ๊ฐ„](#-ํ”„๋กœ์ ํŠธ-๊ธฐ๊ฐ„)
- [ํŒ€์› ์†Œ๊ฐœ](#-ํŒ€์›-์†Œ๊ฐœ)

### 2. ํƒญ ๋ธŒ๋ผ์šฐ์ง•: ์ตœ์†Œํ™” ์ตœ๋Œ€ํ™” ๋ฆฌ์‚ฌ์ด์ฆˆ
## โœจ Nocta๋งŒ์˜ ์ฐจ๋ณ„์ 

### 1. ํƒญ ๋ธŒ๋ผ์šฐ์ง•: ์ตœ์†Œํ™” ์ตœ๋Œ€ํ™” ๋ฆฌ์‚ฌ์ด์ฆˆ

๊ฐ๊ฐ์˜ ๋ฌธ์„œ๋ฅผ ํƒญ๋ธŒ๋ผ์šฐ์ง• ๋ฐฉ์‹์œผ๋กœ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํฌ๊ธฐ๋ฅผ ์กฐ์ ˆํ•˜๊ฑฐ๋‚˜ ๋“œ๋ž˜๊ทธ ์•ค ๋“œ๋ž์„ ํ†ตํ•ด ์›ํ•˜๋Š” ์œ„์น˜์— ์œ„์น˜์‹œํ‚ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

![22222](https://github.com/user-attachments/assets/7355a84a-7ff5-44c5-a3d0-24840a468818)
![tab](https://github.com/user-attachments/assets/e504e103-6b3b-4ea7-8f3e-38c9152e04b5)


### 2. ์ธํ„ฐ๋ž™ํ‹ฐ๋ธŒ ํ…์ŠคํŠธ

ํ…์ŠคํŠธ ๋ธ”๋Ÿญ์— ์ธํ„ฐ๋ž™ํ‹ฐ๋ธŒํ•œ ์†์„ฑ์„ ๋ถ€์—ฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํ•˜์ด๋ผ์ดํŠธ, ๊ทธ๋ผ๋ฐ์ด์…˜ ๋“ฑ์˜ ์†์„ฑ์ด ์กด์žฌํ•ฉ๋‹ˆ๋‹ค.

![Animation2](https://github.com/user-attachments/assets/16cd6a7f-05f5-4807-aafe-456e0dab1310)

## ๐ŸŒ™ Noca์˜ ํŠน์ง•

### ์‹ค์‹œ๊ฐ„ ๋งˆํฌ๋‹ค์šด ํŽธ์ง‘

### 3. ์‹ค์‹œ๊ฐ„ ๋งˆํฌ๋‹ค์šด ํŽธ์ง‘
**์™ธ๋ถ€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์—†์ด ์ง์ ‘ ๊ตฌํ˜„ํ•œ ๋งˆํฌ๋‹ค์šด ์•Œ๊ณ ๋ฆฌ์ฆ˜** ์„ ํ†ตํ•ด ๋งˆํฌ๋‹ค์šด ๋ฌธ๋ฒ•์„ ์ž…๋ ฅํ•˜๋ฉด ์‹ค์‹œ๊ฐ„์œผ๋กœ ๋งˆํฌ๋‹ค์šด ๋ฌธ๋ฒ•์œผ๋กœ ๋ณ€ํ™˜ํ•ฉ๋‹ˆ๋‹ค. ๋ฆฌ์น˜ ํ…์ŠคํŠธ ๊ธฐ๋ฐ˜์˜ ํŽธ์ง‘๊ธฐ๋กœ ๋‹ค์–‘ํ•œ ๋งˆํฌ๋‹ค์šด ๋ฌธ๋ฒ•๊ณผ ์Šคํƒ€์ผ, ํ…์ŠคํŠธ ์ƒ‰์ƒ์„ ์ ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋งˆํฌ๋‹ค์šด ๋ฌธ๋ฒ•์„ ์ž…๋ ฅํ•˜๋ฉด ์‹ค์‹œ๊ฐ„์œผ๋กœ ๋งˆํฌ๋‹ค์šด ๋ฌธ๋ฒ•์œผ๋กœ ๋ณ€ํ™˜ํ•ฉ๋‹ˆ๋‹ค.
![rich](https://github.com/user-attachments/assets/62550129-3408-4dfb-848d-565f9e2918cf)

![33333](https://github.com/user-attachments/assets/ffcf7fa5-9436-4e6b-b38f-6fbf9e813cb5)
### ์‹ค์‹œ๊ฐ„ ๋™์‹œํŽธ์ง‘

### 4.์‹ค์‹œ๊ฐ„ ๋™์‹œํŽธ์ง‘(๊ตฌํ˜„์ค‘)
**์™ธ๋ถ€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์—†์ด ์ง์ ‘ ๊ตฌํ˜„ํ•œ CRDT ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ํ†ตํ•ด** ํ•˜๋‚˜์˜ ๋ฌธ์„œ๋ฅผ ์—ฌ๋Ÿฌ ์‚ฌ์šฉ์ž๊ฐ€ ๋™์‹œ์— ํŽธ์ง‘์ด ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค. ์‹ค์‹œ๊ฐ„ ๋ณ€๊ฒฝ์‚ฌํ•ญ์„ ๋ชจ๋“  ์‚ฌ์šฉ์ž์—๊ฒŒ ๋ฐ˜์˜ํ•ฉ๋‹ˆ๋‹ค.

ํ•˜๋‚˜์˜ ๋ฌธ์„œ๋ฅผ ์—ฌ๋Ÿฌ ์‚ฌ์šฉ์ž๊ฐ€ ๋™์‹œ์— ํŽธ์ง‘์ด ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค. CRDT ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ํ†ตํ•ด ์‹ค์‹œ๊ฐ„ ๋ณ€๊ฒฝ์‚ฌํ•ญ์„ ๋ชจ๋“  ์‚ฌ์šฉ์ž์—๊ฒŒ ๋ฐ˜์˜ํ•ฉ๋‹ˆ๋‹ค.
![ezgif com-video-to-gif-converter](https://github.com/user-attachments/assets/445f80f3-d291-4e83-8a58-da4dc669e42a)


## ๐Ÿ”ง ๊ธฐ์ˆ  ์Šคํƒ
Expand All @@ -74,7 +90,7 @@

**Frontend**

<div align="left"> <img src="https://img.shields.io/badge/React-61DAFB?style=flat-square&logo=React&logoColor=black"/> <img src="https://img.shields.io/badge/React_Query-FF4154?style=flat-square&logo=ReactQuery&logoColor=white"/> <img src="https://img.shields.io/badge/React_Router-CA4245?style=flat-square&logo=ReactRouter&logoColor=white"/> <img src="https://img.shields.io/badge/Zustand-764ABC?style=flat-square&logo=Zustand&logoColor=white"/> <img src="https://img.shields.io/badge/Panda_CSS-06B6D4?style=flat-square&logo=PandaCSS&logoColor=white"/> <img src="https://img.shields.io/badge/Vite-646CFF?style=flat-square&logo=Vite&logoColor=white"/> <img src="https://img.shields.io/badge/Storybook-FF4785?style=flat-square&logo=Storybook&logoColor=white"/> </div>
<div align="left"> <img src="https://img.shields.io/badge/React-61DAFB?style=flat-square&logo=React&logoColor=black"/> <img src="https://img.shields.io/badge/React_Query-FF4154?style=flat-square&logo=ReactQuery&logoColor=white"/> <img src="https://img.shields.io/badge/Zustand-764ABC?style=flat-square&logo=Zustand&logoColor=white"/> <img src="https://img.shields.io/badge/Panda_CSS-06B6D4?style=flat-square&logo=PandaCSS&logoColor=white"/> <img src="https://img.shields.io/badge/Vite-646CFF?style=flat-square&logo=Vite&logoColor=white"/> </div>

**Backend**

Expand All @@ -88,8 +104,33 @@

![image](https://github.com/user-attachments/assets/ab96462b-5f38-4dd9-9c72-984829fa873d)


## ๐Ÿ“… ํ”„๋กœ์ ํŠธ ๊ธฐ๊ฐ„

> 2024.10.28 ~ 2024.12.06 (6์ฃผ)
<br>

## ๐ŸŒฑ ํŒ€์› ์†Œ๊ฐœ

<div align="center">

| J078 | J098 | J099 | J213 |
| :-------------------------------------------------------------------: | :-------------------------------------------------------------------: | :--------------------------------------------------------------------: | :-----------------------------------------------------------------------: |
| <img src="https://github.com/hyonun321.png" width="100" height="100"> | <img src="https://github.com/Ludovico7.png" width="100" height="100"> | <img src="https://github.com/minjungw00.png" width="100" height="100"> | <img src="https://github.com/pipisebastian.png" width="100" height="100"> |
| FE+BE | FE+BE | BE+Infra | FE |
| [๊น€ํ˜„ํ›ˆ](https://github.com/hyonun321) | [๋ฏผ์—ฐ๊ทœ](https://github.com/Ludovico7) | [๋ฏผ์ •์šฐ](https://github.com/minjungw00) | [์žฅ์„œ์œค](https://github.com/pipisebastian) |

</div>

<br>



## ๐Ÿš€ ํ”„๋กœ์ ํŠธ ์‹œ์ž‘ ๊ฐ€์ด๋“œ

> ํ™˜๊ฒฝ๋ณ€์ˆ˜๋Š” /client, /server ํด๋”์— ์žˆ๋Š” .env.sample ํŒŒ์ผ์„ ์ฐธ๊ณ ํ•ด์ฃผ์‹œ๊ธฐ ๋ฐ”๋ž๋‹ˆ๋‹ค. * ์ถ”๊ฐ€์˜ˆ์ •
```bash
# ์ €์žฅ์†Œ ๋ณต์ œ
git clone https://github.com/boostcampwm-2024/web33-boostproject.git
Expand All @@ -109,8 +150,6 @@ pnpm run dev
docker-compose up -d --build
```

## ๐Ÿ”— ํ”„๋กœ์ ํŠธ ๋งํฌ

| ๋…ธ์…˜ | ๋””์ž์ธ |
| :----------------------------------------------------------------------------------------- | :-------- |
| [Notion](https://abrupt-feta-9a9.notion.site/web33-12a9ff1b21c38003b600f57baa654626?pvs=4) | [Figma]() |


10 changes: 7 additions & 3 deletions client/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,20 @@ import { useSocketStore } from "./stores/useSocketStore";
const App = () => {
// TODO ๋ผ์šฐํ„ฐ, react query ์„ค์ •
const { isErrorModalOpen, errorMessage } = useErrorStore();
const { id } = useUserInfo();
const { userId } = useUserInfo();

useEffect(() => {
const socketStore = useSocketStore.getState();
socketStore.init(id);
const savedWorkspace = sessionStorage.getItem("currentWorkspace");
const workspaceId = savedWorkspace ? JSON.parse(savedWorkspace).id : null;
socketStore.init(userId, workspaceId);

return () => {
setTimeout(() => {
socketStore.cleanup();
}, 0);
};
}, [id]);
}, [userId]);

return (
<>
Expand Down
9 changes: 7 additions & 2 deletions client/src/components/bottomNavigator/BottomNavigator.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,16 @@ import { bottomNavigatorContainer } from "./BottomNavigator.style";
interface BottomNavigatorProps {
pages: Page[];
handlePageSelect: ({ pageId, isSidebar }: { pageId: string; isSidebar?: boolean }) => void;
BottomNavigatorOnBoardingProps?: Record<string, string>;
}

export const BottomNavigator = ({ pages, handlePageSelect }: BottomNavigatorProps) => {
export const BottomNavigator = ({
pages,
handlePageSelect,
BottomNavigatorOnBoardingProps,
}: BottomNavigatorProps) => {
return (
<div className={bottomNavigatorContainer}>
<div className={bottomNavigatorContainer} {...BottomNavigatorOnBoardingProps}>
{pages.map((page) => (
<motion.div
key={page.id}
Expand Down
2 changes: 1 addition & 1 deletion client/src/components/button/IconButton.style.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { cva } from "@styled-system/css";
export const iconButtonContainer = cva({
base: {
display: "flex",

flexShrink: 1,
justifyContent: "center",
alignItems: "center",
borderRadius: "xs",
Expand Down
6 changes: 5 additions & 1 deletion client/src/components/button/IconButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,11 @@ export const IconButton = ({ icon, size, onClick }: IconButtonProps) => {
const { icon: IconComponent, color: defaultColor }: IconConfig = iconComponents[icon];

return (
<button className={iconButtonContainer({ size })} onClick={onClick}>
<button
className={iconButtonContainer({ size })}
data-onboarding="page-add-button"
onClick={onClick}
>
<IconComponent color={defaultColor} size="24px" />
</button>
);
Expand Down
2 changes: 1 addition & 1 deletion client/src/components/button/textButton.style.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ const textButton = cva({
base: {
borderRadius: "md",
width: "50%",
height: "40px",
paddingY: "4px",
cursor: "pointer",
},
variants: {
Expand Down
6 changes: 5 additions & 1 deletion client/src/components/button/textButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,11 @@ interface TextButtonProps {

export const TextButton = ({ variant = "primary", children, onClick }: TextButtonProps) => {
return (
<button className={textButtonContainer({ variant })} onClick={onClick}>
<button
className={textButtonContainer({ variant })}
onClick={onClick}
data-onboarding="login-button"
>
{children}
</button>
);
Expand Down
39 changes: 39 additions & 0 deletions client/src/components/modal/InviteModal.style.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// InviteModal.style.ts
import { css } from "@styled-system/css";

export const modalContentContainer = css({
display: "flex",
gap: "16px",
flexDirection: "column",
width: "400px",
padding: "16px",
});

export const titleText = css({
color: "gray.800",
fontSize: "xl",
fontWeight: "bold",
});

export const descriptionText = css({
color: "gray.600",
fontSize: "sm",
});

export const emailInput = css({
outline: "none",
border: "1px solid",
borderColor: "gray.200",
borderRadius: "md",
// ๊ธฐ๋ณธ input ์Šคํƒ€์ผ ์ถ”๊ฐ€
width: "100%",
padding: "8px 12px",
fontSize: "sm",
_placeholder: {
color: "gray.400",
},
_focus: {
borderColor: "blue.500",
boxShadow: "0 0 0 1px blue.500",
},
});
42 changes: 42 additions & 0 deletions client/src/components/modal/InviteModal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// InviteModal.tsx
import { useState } from "react";
import { modalContentContainer, titleText, descriptionText, emailInput } from "./InviteModal.style";
import { Modal } from "./modal";

interface InviteModalProps {
isOpen: boolean;
onClose: () => void;
onInvite: (email: string) => void;
}

export const InviteModal = ({ isOpen, onClose, onInvite }: InviteModalProps) => {
const [email, setEmail] = useState("");

const handleInvite = () => {
onInvite(email);
setEmail("");
onClose();
};

return (
<Modal
isOpen={isOpen}
primaryButtonLabel="์ดˆ๋Œ€ํ•˜๊ธฐ"
primaryButtonOnClick={handleInvite}
secondaryButtonLabel="์ทจ์†Œ"
secondaryButtonOnClick={onClose}
>
<div className={modalContentContainer}>
<h2 className={titleText}>์›Œํฌ์ŠคํŽ˜์ด์Šค ์ดˆ๋Œ€</h2>
<p className={descriptionText}>์ดˆ๋Œ€ํ•  ์‚ฌ์šฉ์ž์˜ ์ด๋ฉ”์ผ์„ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”</p>
<input
className={emailInput}
onChange={(e) => setEmail(e.target.value)}
placeholder="์ด๋ฉ”์ผ ์ฃผ์†Œ ์ž…๋ ฅ"
type="email"
value={email}
/>
</div>
</Modal>
);
};
Loading

0 comments on commit 167ebf6

Please sign in to comment.