diff --git a/.gitignore b/.gitignore index 67554aa08f162d30056f0091db37e431f3275070..1d65852cfdfa8419b4f13542526859ad2f2b7043 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ # Ignore node_modules directory node_modules/ +package.json diff --git a/react-whenMeet/Dockerfile b/react-whenMeet/Dockerfile index 33b3773160ad0f4535bda962033684f78e775832..b6fab58f44c620a47f39c9f9b132fd34f68c8a5b 100644 --- a/react-whenMeet/Dockerfile +++ b/react-whenMeet/Dockerfile @@ -3,5 +3,5 @@ WORKDIR /app COPY package.json ./ RUN npm install COPY . . -EXPOSE 80 +EXPOSE 3001 CMD ["npm", "start"] \ No newline at end of file diff --git a/react-whenMeet/package.json b/react-whenMeet/package.json index dafb6ea7b18bff19ba9b489f9521e02e3c51cfff..600f87f5fb7656835882ba780874569b60d46f25 100644 --- a/react-whenMeet/package.json +++ b/react-whenMeet/package.json @@ -19,7 +19,7 @@ "web-vitals": "^2.1.4" }, "scripts": { - "start": "react-scripts start", + "start": "export PORT=3001 && react-scripts start", "build": "react-scripts build", "test": "react-scripts test", "eject": "react-scripts eject" diff --git a/react-whenMeet/src/components/CalendarWeek.jsx b/react-whenMeet/src/components/CalendarWeek.jsx index 6340e2bd8c112e7ae04d67e822ada015d9d5889c..604d8f0e3dec2f47abf7c1374a7e547d8039d0d0 100644 --- a/react-whenMeet/src/components/CalendarWeek.jsx +++ b/react-whenMeet/src/components/CalendarWeek.jsx @@ -115,7 +115,7 @@ const CalendarWeek = ({ const weekDates = weeks[currentWeekIndex] || []; return ( - <div className="wrap"> + <div className="calendarWeekContainer wrap"> <div className="button-container"> <button onClick={handlePrevWeek} disabled={currentWeekIndex === 0}> Prev Week diff --git a/react-whenMeet/src/components/HomeParticipateForm.js b/react-whenMeet/src/components/HomeParticipateForm.js index f505918466bab127f94642ea4c127e03d6c2373e..c3470bf160e993e84feed0c3bb7f7bc83202a709 100644 --- a/react-whenMeet/src/components/HomeParticipateForm.js +++ b/react-whenMeet/src/components/HomeParticipateForm.js @@ -3,6 +3,7 @@ import Input from "./Input"; import Button from "./Button"; import { useNavigate, useParams } from "react-router-dom"; import axios from "axios"; +import "../styles/HomeParticipateForm.css" function HomeParticipateForm() { const [name, setName] = useState(""); @@ -186,6 +187,7 @@ function HomeParticipateForm() { <form> <div> <h1>투표에 참여하기</h1> + <h2> 아이디가 없다면 아래 양식에 맞춰 작성 후 참여하기를 누르세요</h2> <Input type="text" value={name} @@ -204,7 +206,7 @@ function HomeParticipateForm() { onChange={handleEmail} placeholder="이메일(선택)" /> - <Button type="submit" text="참여" onClick={handleSubmit} /> + <Button type="submit" text="참여하기" onClick={handleSubmit} /> </div> </form> ); diff --git a/react-whenMeet/src/components/Input.js b/react-whenMeet/src/components/Input.js index 1023ac9b83af4081874a17ce6f026c9e92488ec0..1f7edd3e6603a30f392fd3ff6ef7a2d236ecdc68 100644 --- a/react-whenMeet/src/components/Input.js +++ b/react-whenMeet/src/components/Input.js @@ -1,8 +1,9 @@ import PropTypes from "prop-types"; -function Input({ type, value, onChange, placeholder }) { +function Input({ type, value, onChange, placeholder, classname }) { return ( <input + className={classname} type={type} placeholder={placeholder} onChange={onChange} diff --git a/react-whenMeet/src/components/LinkPageForm.js b/react-whenMeet/src/components/LinkPageForm.js index 822980941956ea469d4394f1a26a2caee8ccbd64..652676b5c08d0e5b6d7c7a8f834e322cb6b8c5d0 100644 --- a/react-whenMeet/src/components/LinkPageForm.js +++ b/react-whenMeet/src/components/LinkPageForm.js @@ -28,8 +28,9 @@ function LinkPageForm() { return ( <form onSubmit={handleSubmit}> + <h1>투표 링크가 생성되었습니다</h1> + <hr/> <div> - <p>hey</p> <Input value={`https://when-meet.link/HomeParticipate/${id}`} /> diff --git a/react-whenMeet/src/components/MakeHeader.jsx b/react-whenMeet/src/components/MakeHeader.jsx index b9b6dae74955518f2428a262f9ef49695dce7ebd..152a32babf96199aa9a857ea79cf8a1eef363b4c 100644 --- a/react-whenMeet/src/components/MakeHeader.jsx +++ b/react-whenMeet/src/components/MakeHeader.jsx @@ -6,7 +6,7 @@ export default function MakeHeader({ }) { return ( <div className="header"> - <h2> + <h2 className="calendarh2"> <button type="button" onClick={prevMonth}> prev </button> diff --git a/react-whenMeet/src/components/MeetingInfoForm.js b/react-whenMeet/src/components/MeetingInfoForm.js index 1f50093385e725604c6a340690684efe21ad016c..8b98be7e1d6725f49413cb184e4e39fc89761246 100644 --- a/react-whenMeet/src/components/MeetingInfoForm.js +++ b/react-whenMeet/src/components/MeetingInfoForm.js @@ -90,38 +90,49 @@ function MeetingInfoForm() { }; return ( <form onSubmit={handleSubmit}> - <div> - <div className="purpose-selector"> - <h1>약속 일정 만들기</h1> - <label> - 목적: - <select value={meetingPurpose} onChange={handleOnChange}> - <option value="선택">선택</option> - <option value="스터디">스터디</option> - <option value="회의">회의</option> - <option value="놀기">놀기</option> - <option value="식사">식사</option> - <option value="기타">기타</option> - </select> - </label> + <div className="center-container"> + <h1>약속 일정 만들기</h1> + <div className="purpose"> + <h2 className="not-enter">약속 목적 </h2> + <select className="purpose-selector" value={meetingPurpose} onChange={handleOnChange}> + <option value="선택">선택</option> + <option value="스터디">스터디</option> + <option value="회의">회의</option> + <option value="놀기">놀기</option> + <option value="식사">식사</option> + <option value="기타">기타</option> + </select> </div> <div className="calendar-month"> <Calendar usingDate={usingDate} setUsingDate={setUsingDate} /> </div> - <div className="timeStartEnd"> - 투표 가능 시간 - <TimeInput onTimeChange={handleStartTimeChange} /> - ~ - <TimeInput onTimeChange={handleEndTimeChange} /> + <div className="form-input"> + <h2>추가 설정</h2> + <div className="num-of-people"> + <h2>투표 인원수</h2> + <Input + classname="voteNumber" + type="number" + value={number} + onChange={handleNumber} + placeholder="인원수" + /> + </div> + <div className="timeStartEnd"> + <h2>투표 가능 시간</h2> + <TimeInput onTimeChange={handleStartTimeChange} /> + ~ + <TimeInput onTimeChange={handleEndTimeChange} /> + </div> + <div className="end-time"> + <h2 className="not-enter">투표 종료 시간</h2> + <Input + classname= "vote-end" + type="datetime-local" + value={endVote} + onChange={handleVoteEnd} /> + </div> </div> - <Input - type="number" - value={number} - onChange={handleNumber} - placeholder="예상 투표 인원(선택)" - /> - <a>예상 투표 종료 시간(선택)</a> - <Input type="datetime-local" value={endVote} onChange={handleVoteEnd} /> <Button type="submit" text="시작하기" /> </div> </form> diff --git a/react-whenMeet/src/components/ResultMakeForm.js b/react-whenMeet/src/components/ResultMakeForm.js index b44a2534d85026977de580b1096124cc5fd2a3a1..d0fdb575946efd63c16796793c9a3660cfae897f 100644 --- a/react-whenMeet/src/components/ResultMakeForm.js +++ b/react-whenMeet/src/components/ResultMakeForm.js @@ -13,7 +13,70 @@ function ResultMakeForm() { const [hoveredInfo, setHoveredInfo] = useState(null); const [isLoading, setIsLoading] = useState(true); const [isModalOpen, setIsModalOpen] = useState(false); + const [mostAvailableDates, setMostAvailableDates] = useState([]); + const [topAvailableDates, setTopAvailableDates] = useState([]); + useEffect(() => { + if (meetingData && meetingData.participants) { + calculateTopAvailableDates(); + } + }, [meetingData]); + + const calculateTopAvailableDates = () => { + let dateAvailability = {}; + + meetingData.participants.forEach((participant) => { + participant.availableSchedules.forEach((schedule) => { + if (!dateAvailability[schedule.availableDate]) { + dateAvailability[schedule.availableDate] = {}; + } + schedule.availableTimes.forEach((time) => { + if (!dateAvailability[schedule.availableDate][time]) { + dateAvailability[schedule.availableDate][time] = 0; + } + dateAvailability[schedule.availableDate][time]++; + }); + }); + }); + + let dateCounts = Object.entries(dateAvailability).map(([date, times]) => { + let maxCount = Math.max(...Object.values(times)); + let count = Object.values(times).filter((val) => val === maxCount).length; + return { date, count, maxCount }; + }); + + dateCounts.sort((a, b) => b.maxCount - a.maxCount || b.count - a.count); + + setTopAvailableDates(dateCounts.slice(0, 5)); + }; + + useEffect(() => { + if (meetingData && meetingData.participants) { + calculateMostAvailableDates(); + } + }, [meetingData]); + + const calculateMostAvailableDates = () => { + let dateAvailabilityCount = {}; + + meetingData.participants.forEach((participant) => { + participant.availableSchedules.forEach((schedule) => { + if (!dateAvailabilityCount[schedule.availableDate]) { + dateAvailabilityCount[schedule.availableDate] = new Set(); + } + schedule.availableTimes.forEach((time) => { + dateAvailabilityCount[schedule.availableDate].add(time); + }); + }); + }); + + const sortedDates = Object.entries(dateAvailabilityCount) + .map(([date, times]) => ({ date, count: times.size })) + .sort((a, b) => b.count - a.count) + .slice(0, 5); + + setMostAvailableDates(sortedDates); + }; useEffect(() => { const fetchMeetingData = async () => { setIsLoading(true); @@ -141,15 +204,15 @@ function ResultMakeForm() { <h1 className="title-box">{meetingData?.title}</h1> {meetingData.maxParticipants && ( <div> - 현재 완료한 인원수 {meetingData?.currentParticipants} /{" "} + 현재 완료한 인원수 : {meetingData?.currentParticipants} /{" "} {meetingData?.maxParticipants} </div> )} {!meetingData.maxParticipants && ( - <div>현재 완료한 인원수 {meetingData?.currentParticipants}</div> + <div>현재 완료한 인원수 : {meetingData?.currentParticipants}</div> )} - <div>종료까지 남은 시간 {timeLeft}</div> + <div>종료까지 남은 시간 : {timeLeft}</div> <button onClick={handleEdit}>수정하기</button> <button onClick={closeMeeting}>투표 종료하기</button> </div> @@ -174,33 +237,42 @@ function ResultMakeForm() { onRequestClose={handleModalClose} onSubmit={handlePasswordSubmit} /> - <span className="mostTime"> - <div style={{ textAlign: "center" }}> - 가장 많은 사람들이 가능한 일정 - </div> - <ol>//일정 5개 나열</ol> - </span> - <span className="possible"> - {!hoveredInfo && ( - <div> - <strong>가능한 사람들이 표시됩니다.</strong> - <p>마우스를 달력 위에 올려보세요!</p> - </div> - )} - - {hoveredInfo && ( - <div style={{ textAlign: "center" }}> - <strong> - {hoveredInfo.date} {hoveredInfo.time}에 가능한 사람: - </strong> - <ul> - {hoveredInfo.participants.map((name) => ( - <li key={name}>{name}</li> - ))} - </ul> - </div> - )} - </span> + <div className="flex-bottom-container"> + <span className="mostTime"> + <strong style={{ textAlign: "center" }}> + 가장 많은 사람들이 가능한 일정 + </strong> + <ol> + {topAvailableDates.map((dateInfo, index) => ( + <li key={index}> + {dateInfo.date} ({dateInfo.maxCount}명이 가능한 시간대:{" "} + {dateInfo.count}개 ) + </li> + ))} + </ol> + </span> + <span className="possible"> + {!hoveredInfo && ( + <div> + <strong>가능한 사람들이 표시됩니다.</strong> + <p>마우스를 달력 위에 올려보세요!</p> + </div> + )} + + {hoveredInfo && ( + <div style={{ textAlign: "center" }}> + <strong> + {hoveredInfo.date} {hoveredInfo.time}에 가능한 사람: + </strong> + <ul> + {hoveredInfo.participants.map((name) => ( + <li key={name}>{name}</li> + ))} + </ul> + </div> + )} + </span> + </div> </> ); } diff --git a/react-whenMeet/src/components/TimeInput.js b/react-whenMeet/src/components/TimeInput.js index a126852e47bf878a7c0ff8d9c6366dbdae5a5713..224c6ed1f8cae12cfbb6940fb4bee69632b115fe 100644 --- a/react-whenMeet/src/components/TimeInput.js +++ b/react-whenMeet/src/components/TimeInput.js @@ -11,7 +11,7 @@ function TimeInput({ onTimeChange }) { return ( <div> <label> - <select value={time} onChange={handleTimeChange}> + <select className="time-selector" value={time} onChange={handleTimeChange}> {Array.from({ length: 48 }, (_, i) => { const paddedHour = Math.floor(i / 2).toString().padStart(2, "0"); const paddedMinute = (i % 2 === 0 ? "00" : "30"); diff --git a/react-whenMeet/src/styles/Calendar.css b/react-whenMeet/src/styles/Calendar.css index 6379f3ceffb36b0bc03950fdf93ccdda9ec9b046..91209263af6daf9a821ad56e9b69f9a3c4e31fdf 100644 --- a/react-whenMeet/src/styles/Calendar.css +++ b/react-whenMeet/src/styles/Calendar.css @@ -1,3 +1,17 @@ +.calendar-month .calendar { + display: flex; + flex-direction: column; + align-items: center; + border: 1px solid #ccc; +} + +table { + table-layout: fixed; +} +.calendarTable { + width: 100%; +} + .header { display: flex; flex-direction: column; @@ -18,8 +32,3 @@ margin: 0; /* 기본 마진을 제거합니다. */ font-size: 16px; /* 원하는 크기로 조절합니다. */ } - -table { - /* width: 100%; */ - border: 1px solid #444444; -} diff --git a/react-whenMeet/src/styles/CalendarWeek.css b/react-whenMeet/src/styles/CalendarWeek.css index 406b79c7d99199e75d9ab92cea02500cf7b8c6e8..f7007bdbcfa474096910e62ba38122a2b6949fdd 100644 --- a/react-whenMeet/src/styles/CalendarWeek.css +++ b/react-whenMeet/src/styles/CalendarWeek.css @@ -1,51 +1,66 @@ -.calendar-container { +.calendarWeekContainer .calendar-container { margin-top: 20px; width: 100%; background-color: #5fbdff; } -.button-container { + +.calendarWeekContainer .button-container { display: flex; justify-content: space-between; } -.button-container button:first-child { - margin-right: 20px; + +.calendarWeekContainer .button-container button:first-child { + margin-right: 10%; + margin-left: 10%; } -.button-container button:last-child { - margin-left: 20px; + +.calendarWeekContainer .button-container button:last-child { + margin-right: 10%; + margin-left: 10%; } -.wrap { + +.calendarWeekContainer .wrap { width: 80%; } -table { + +.calendarWeekContainer table { width: 100%; border-collapse: collapse; text-align: center; margin-bottom: 4%; } -th, -td { +.calendarWeekContainer th, +.calendarWeekContainer td { border: 1px solid #ddd; padding: 10px; } -th { +.calendarWeekContainer th { background-color: #f4f4f4; } -td { +.calendarWeekContainer td { background-color: #f4f4f4; cursor: pointer; transition: background-color 0.3s ease, transform 0.3s ease, - box-shadow 0.3s ease; /* 부드러운 애니메이션 효과 */ + box-shadow 0.3s ease; } -td:hover { + +.calendarWeekContainer td:hover { background-color: aqua; - transform: scale(1.05); /* 셀을 약간 확대 */ - box-shadow: 0 0 10px rgba(0, 0, 0, 0.2); /* 셀에 그림자 추가 */ - border: 1px solid #5fbdff; /* 셀 주위에 테두리 추가 */ + transform: scale(1.05); + box-shadow: 0 0 10px rgba(0, 0, 0, 0.2); + border: 1px solid #5fbdff; +} + +.calendarWeekContainer .selected { + background-color: #e0ffe0; } -.selected { - background-color: #e0ffe0; /* 선택된 셀의 배경색 */ +@media screen and (max-width: 768px) { + .calendarWeekContainer .wrap { + display: flex; + width: 100%; + } } diff --git a/react-whenMeet/src/styles/Global.css b/react-whenMeet/src/styles/Global.css index 8d01e25f6172b104a8a65b6cb0551530b525bdb8..be95dc3aa0a3096f08c3bce3b8318f958d489d6a 100644 --- a/react-whenMeet/src/styles/Global.css +++ b/react-whenMeet/src/styles/Global.css @@ -1,3 +1,21 @@ * { font-family: 'Noto Sans KR', sans-serif; -} \ No newline at end of file +} + +/* Media queries for responsiveness */ +@media (max-width: 768px) { + form { + width: 80%; + } +} + +@media (max-width: 576px) { + form { + width: 90%; + } +} +@media (max-width: 376px) { + form { + width: 77%; + } + } \ No newline at end of file diff --git a/react-whenMeet/src/styles/HomeMake.css b/react-whenMeet/src/styles/HomeMake.css index 248e257e3e2c01c41e7133bf26bc3b85cb502f59..91c9efc5159871c91872320fc5c18672f8f17761 100644 --- a/react-whenMeet/src/styles/HomeMake.css +++ b/react-whenMeet/src/styles/HomeMake.css @@ -1,5 +1,3 @@ -/* HomeMake.css */ - body { background-color:white; margin: 0; @@ -9,7 +7,7 @@ body { form { width: 50%; padding: 20px; - margin: auto; + margin:auto; text-align: center; } @@ -31,6 +29,7 @@ h1 { display: flex; flex-direction: column; /* 세로 방향으로 정렬 */ align-items: center; + height: 100vh; } input { @@ -80,3 +79,9 @@ button:hover { width: 90%; } } + +@media (max-width: 376px) { + form { + width: 100%; + } +} diff --git a/react-whenMeet/src/styles/HomeParticipateForm.css b/react-whenMeet/src/styles/HomeParticipateForm.css new file mode 100644 index 0000000000000000000000000000000000000000..3bb970982a5e5caaa32984d524b92dcdb0fdaa72 --- /dev/null +++ b/react-whenMeet/src/styles/HomeParticipateForm.css @@ -0,0 +1,4 @@ +h2 { + font-size: 12px; + font-weight: lighter; +} \ No newline at end of file diff --git a/react-whenMeet/src/styles/MeetingInfo.css b/react-whenMeet/src/styles/MeetingInfo.css index 1a33c0d032132bbc61084ed646009d278b7cf445..9a3123f4495ee9f71770bb06718f19809074cf6a 100644 --- a/react-whenMeet/src/styles/MeetingInfo.css +++ b/react-whenMeet/src/styles/MeetingInfo.css @@ -29,17 +29,56 @@ h1 { margin-bottom: 10px; color: #333333; font-size: 24px; - font-family: "Lato"; } h2 { + font-size: 16px; + padding: 5px; +} + +.not-enter { + white-space: nowrap; +} + +select { + width: 20%; + padding: 5px; + font-size: 16px; + border: 1px solid #ccc; + border-radius: 5px; + outline: none; + cursor: pointer; +} +.purpose-selector { + width: 50%; + padding: 5px; + font-size: 16px; + border: 1px solid #ccc; + border-radius: 5px; + outline: none; + cursor: pointer; +} + +.time-selector { + width: 100%; + font-size: 16px; + border: 1px solid #ccc; + border-radius: 5px; + outline: none; + cursor: pointer; +} +.calendarh2 { + display: flex; + white-space: nowrap; + margin: 0; +} +.num-of-people { display: flex; align-items: center; justify-content: space-between; white-space: nowrap; margin: 0; } - .timeStartEnd { display: flex; align-items: center; @@ -47,7 +86,13 @@ h2 { white-space: nowrap; margin: 0; } - +.end-time { + display: flex; + align-items: center; + justify-content: space-between; + white-space: nowrap; + margin: 0; +} input { width: 100%; padding: 10px; @@ -57,6 +102,19 @@ input { border-radius: 4px; } +.voteNumber { + width: 60%; + box-sizing: border-box; + border: 1px solid #ccc; + border-radius: 4px; +} +.vote-end { + width: 60%; + box-sizing: border-box; + border: 1px solid #ccc; + border-radius: 4px; +} + button { width: 100%; padding: 10px; @@ -87,15 +145,17 @@ button:hover { margin: auto; } .header button:first-child { - margin-right: 20px; + margin-right: 6em; } .header button:last-child { - margin-left: 20px; + margin-left: 6em; } -.purpose-selector { - margin: 20px; +.purpose { + display: flex; + align-items: center; } + .calendarTable { display: flex; justify-content: center; diff --git a/react-whenMeet/src/styles/ResultEnd.css b/react-whenMeet/src/styles/ResultEnd.css index 9b944aef28649883f68f10ddd03efbb25fd3afd8..02692e2138f8850c3fd15639fdfe48288ac0e20c 100644 --- a/react-whenMeet/src/styles/ResultEnd.css +++ b/react-whenMeet/src/styles/ResultEnd.css @@ -9,11 +9,11 @@ } .form-container label { display: flex; - align-items: center; /* 라디오 버튼과 텍스트를 세로 중앙에 맞춤 */ - margin: 20px 0; /* 라벨 간에 여백을 추가 */ + align-items: center; + margin: 20px 0; } .form-container input[type="radio"] { - margin-right: 10px; /* 라디오 버튼과 텍스트 사이의 공간 조정 */ + margin-right: 10px; width: 20%; } @@ -24,11 +24,9 @@ .possible { position: fixed; - right: 0; /* 화면의 오른쪽 끝에 고정 */ - top: 60%; /* 화면의 상단으로부터 50%의 위치에 고정 */ - transform: translateY( - -50% - ); /* 상단 50% 위치에서 자기 자신의 높이의 절반을 위로 이동 */ + right: 0; + top: 60%; + transform: translateY(-50%); width: 20%; border: 1px solid black; padding: 20px; @@ -45,3 +43,15 @@ flex-direction: column; align-items: center; } +@media screen and (max-width: 768px) { + .possible { + position: static; + width: 40%; + margin: 200px 20px; + } + + .flex-row { + flex-direction: column; + width: 100%; + } +} diff --git a/react-whenMeet/src/styles/ResultMake.css b/react-whenMeet/src/styles/ResultMake.css index e678d31596e9b64343b57eade4f32b55fe151783..482917bc63f5ac5ec045244ab796af8d9b21736f 100644 --- a/react-whenMeet/src/styles/ResultMake.css +++ b/react-whenMeet/src/styles/ResultMake.css @@ -18,15 +18,60 @@ box-shadow: 0px 1px 5px rgba(95, 189, 255, 0.5); /* 구분선에 그림자 효과 추가 */ padding-top: 20px; margin-top: 30px; + width: 50%; + overflow-x: auto; +} + +.mostTime, +.possible { + border: 1px solid #ddd; + padding: 20px; + margin: 10px; /* 각 요소 주변의 공간을 더욱 명확히 */ + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); /* 세련된 그림자 효과 */ + border-radius: 8px; /* 모서리를 둥글게 */ + background-color: #ffffff; /* 배경색 설정 */ + box-sizing: border-box; /* 패딩과 보더를 너비에 포함 */ } .mostTime { position: fixed; right: 0; top: 30%; - transform: translateY(-50%); + transform: translateY(-60%); + width: 20%; + border: 1px solid black; + padding: 20px; + margin-right: 2%; +} +.possible { + position: fixed; + right: 0; + top: 60%; + transform: translateY(-40%); width: 20%; border: 1px solid black; padding: 20px; margin-right: 2%; } + +@media screen and (max-width: 768px) { + .flex-bottom-container { + display: flex; + justify-content: space-between; + width: 100%; + + bottom: 0; + left: 0; + } + + .mostTime, + .possible { + position: static; + width: 40%; + margin: 200px 20px; + } + .flex-row { + flex-direction: column; + width: 100%; + } +}