diff --git a/.gitignore b/.gitignore deleted file mode 100644 index b78818f..0000000 --- a/.gitignore +++ /dev/null @@ -1,41 +0,0 @@ -### react ### -.DS_* -*.log -logs -**/*.backup.* -**/*.back.* - -node_modules -bower_components - -*.sublime* - -psd -thumb -sketch - -# dependencies -/node_modules -/.pnp -.pnp.js - -# testing -/coverage - -# production -/build - -# misc -.DS_Store -.env.local -.env.development.local -.env.test.local -.env.production.local - -npm-debug.log* -yarn-debug.log* -yarn-error.log* - -.DS_Store -node_modules -.cache \ No newline at end of file diff --git a/back b/back deleted file mode 160000 index 9a425ba..0000000 --- a/back +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 9a425bafe21781ad35b47a8a9d09232c9db2a29f diff --git a/front/.gitignore b/front/.gitignore index b78818f..b2d9d47 100644 --- a/front/.gitignore +++ b/front/.gitignore @@ -1,4 +1,8 @@ ### react ### + +# macOS 시스템 파일 +.DS_Store + .DS_* *.log logs diff --git a/front/src/global/global.js b/front/src/global/global.js index 5b1845e..46547f0 100644 --- a/front/src/global/global.js +++ b/front/src/global/global.js @@ -11,63 +11,63 @@ const GlobalStyle = createGlobalStyle` font-family: 'Pretendard'; font-weight: 900; font-style: normal; - src: url(${process.env.PUBLIC_URL}/assets/fonts/pretendard/Pretendard-Black.woff2) format('woff2'); + src: url(${process.env.PUBLIC_URL}/assets/fonts/Pretendard-Black.woff2) format('woff2'); } @font-face { font-family: 'Pretendard'; font-weight: 800; font-style: normal; - src: url(${process.env.PUBLIC_URL}/assets/fonts/pretendard/Pretendard-ExtraBold.woff2) format('woff2'); + src: url(${process.env.PUBLIC_URL}/assets/fonts/Pretendard-ExtraBold.woff2) format('woff2'); } @font-face { font-family: 'Pretendard'; font-weight: 700; font-style: normal; - src: url(${process.env.PUBLIC_URL}/assets/fonts/pretendard/Pretendard-Bold.woff2) format('woff2'); + src: url(${process.env.PUBLIC_URL}/assets/fonts/Pretendard-Bold.woff2) format('woff2'); } @font-face { font-family: 'Pretendard'; font-weight: 600; font-style: normal; - src: url(${process.env.PUBLIC_URL}/assets/fonts/pretendard/Pretendard-SemiBold.woff2) format('woff2'); + src: url(${process.env.PUBLIC_URL}/assets/fonts/Pretendard-SemiBold.woff2) format('woff2'); } @font-face { font-family: 'Pretendard'; font-weight: 500; font-style: normal; - src: url(${process.env.PUBLIC_URL}/assets/fonts/pretendard/Pretendard-Medium.woff2) format('woff2'); + src: url(${process.env.PUBLIC_URL}/assets/fonts/Pretendard-Medium.woff2) format('woff2'); } @font-face { font-family: 'Pretendard'; font-weight: 400; font-style: normal; - src: url(${process.env.PUBLIC_URL}/assets/fonts/pretendard/Pretendard-Regular.woff2) format('woff2'); + src: url(${process.env.PUBLIC_URL}/assets/fonts/Pretendard-Regular.woff2) format('woff2'); } @font-face { font-family: 'Pretendard'; font-weight: 300; font-style: normal; - src: url(${process.env.PUBLIC_URL}/assets/fonts/pretendard/Pretendard-Light.woff2) format('woff2'); + src: url(${process.env.PUBLIC_URL}/assets/fonts/Pretendard-Light.woff2) format('woff2'); } @font-face { font-family: 'Pretendard'; font-weight: 200; font-style: normal; - src: url(${process.env.PUBLIC_URL}/assets/fonts/pretendard/Pretendard-ExtraLight.woff2) format('woff2'); + src: url(${process.env.PUBLIC_URL}/assets/fonts/Pretendard-ExtraLight.woff2) format('woff2'); } @font-face { font-family: 'Pretendard'; font-weight: 100; font-style: normal; - src: url(${process.env.PUBLIC_URL}/assets/fonts/pretendard/Pretendard-thin.woff2) format('woff2'); + src: url(${process.env.PUBLIC_URL}/assets/fonts/Pretendard-thin.woff2) format('woff2'); } /* 3) 초기 스타일 */ diff --git a/front/src/pages/archive/BookmarkTyped.jsx b/front/src/pages/archive/BookmarkTyped.jsx index 6151f11..d8b535c 100644 --- a/front/src/pages/archive/BookmarkTyped.jsx +++ b/front/src/pages/archive/BookmarkTyped.jsx @@ -36,8 +36,9 @@ const BookmarkTyped = () => { setSelectedCard(null); // 닫기 }; - const items = [ + const [items, setItems] = useState([ { + id: 1, date: "2025.06.28", title: "끝내주는 인생", content: @@ -49,7 +50,27 @@ const BookmarkTyped = () => { artist: "John Canada", coverUrl: "/assets/images/book-img.jpeg", }, - ]; + ]); + + // 편집 모드 + const [isEditMode, setIsEditMode] = useState(false); + const [selectedIds, setSelectedIds] = useState([]); + + const handleEditClick = () => { + setIsEditMode((prev) => !prev); + setSelectedIds([]); // 편집 모드 종료 시 초기화 + }; + + const handleCardSelect = (id) => { + if (!isEditMode) return; + setSelectedIds((prev) => (prev.includes(id) ? prev.filter((item) => item !== id) : [...prev, id])); + }; + + const handleDeleteSelected = () => { + const newItems = items.filter((item) => !selectedIds.includes(item.id)); + setItems(newItems); + setSelectedIds([]); + }; return ( <> @@ -84,13 +105,26 @@ const BookmarkTyped = () => { )} - 편집 + {isEditMode ? ( + + 삭제 + {selectedIds.length}개 선택됨 + + ) : ( + 편집 + )} {/* 북마크 카드 리스트 */} {items.map((item, idx) => ( - handleCardClick(item)} /> + (isEditMode ? handleCardSelect(item.id) : handleCardClick(item))} + selected={selectedIds.includes(item.id)} + isEditMode={isEditMode} + /> ))} {/* 팝업 */} diff --git a/front/src/pages/archive/HistoryCard.jsx b/front/src/pages/archive/HistoryCard.jsx index 784528e..3e0b653 100644 --- a/front/src/pages/archive/HistoryCard.jsx +++ b/front/src/pages/archive/HistoryCard.jsx @@ -3,7 +3,7 @@ import useClickOutside from "../../modules/hooks/useClickOutside"; import Card from "./history.card.style"; import Dropdown from "./dropdown.style"; -const HistoryCard = ({ data, onClick }) => { +const HistoryCard = ({ data, onClick, selected, isEditMode }) => { const { date, content, title, author, music, artist } = data; // 북마크, 좋아요 토글 버튼 @@ -16,7 +16,7 @@ const HistoryCard = ({ data, onClick }) => { useClickOutside(dropdownRef, () => setOpenDropdown(false)); return ( - + {date} e.stopPropagation()}> diff --git a/front/src/pages/archive/bookmark.section.style.js b/front/src/pages/archive/bookmark.section.style.js index 7f15b6a..cb23644 100644 --- a/front/src/pages/archive/bookmark.section.style.js +++ b/front/src/pages/archive/bookmark.section.style.js @@ -95,6 +95,7 @@ S.ScrollRightBtn = styled.button` S.Card = styled.div` width: 160px; flex-shrink: 0; + `; S.Image = styled.img` diff --git a/front/src/pages/archive/bookmark.typed.style.js b/front/src/pages/archive/bookmark.typed.style.js index 4769e2b..01ccdcf 100644 --- a/front/src/pages/archive/bookmark.typed.style.js +++ b/front/src/pages/archive/bookmark.typed.style.js @@ -103,6 +103,28 @@ S.CardColumn = styled.div` gap: 16px; `; +// 편집 모드 +S.EditRow = styled.div` + display: flex; + align-items: center; + gap: 8px; + margin-top: 10px; +`; + +S.DeleteButton = styled.button` + background: none; + border: none; + color: #f96f3d; + font-size: 14px; + cursor: pointer; + padding: 0; +`; + +S.SelectedText = styled.span` + font-size: 14px; + color: gray; +`; + // 디테일 팝업 // 전체 배경 어둡게 diff --git a/front/src/pages/archive/history.card.style.js b/front/src/pages/archive/history.card.style.js index bbf8008..e9b4ee8 100644 --- a/front/src/pages/archive/history.card.style.js +++ b/front/src/pages/archive/history.card.style.js @@ -5,9 +5,11 @@ const Card = {}; Card.Card = styled.div` background-color: #fff; padding: 24px 22px 24px 22px; - border: 1px solid #e0e0e0; + border: ${({ selected }) => (selected ? "1px solid #f96f3d" : "1px solid #e0e0e0")}; border-radius: 5px; font-family: pretendard; + transition: border 0.2s ease; + cursor: pointer; `; Card.Header = styled.div` diff --git a/front/src/pages/main/MainContainer.jsx b/front/src/pages/main/MainContainer.jsx index c6c3164..ef66fdc 100644 --- a/front/src/pages/main/MainContainer.jsx +++ b/front/src/pages/main/MainContainer.jsx @@ -180,7 +180,7 @@ const MainContainer = ({isUpdate, setIsUpdate}) => { - + {currentData && ( diff --git a/front/src/pages/main/main.form.style.js b/front/src/pages/main/main.form.style.js index 4c84d51..da392c2 100644 --- a/front/src/pages/main/main.form.style.js +++ b/front/src/pages/main/main.form.style.js @@ -1,6 +1,6 @@ -import React from 'react'; +import React from "react"; import styled, { css } from "styled-components"; -import { justifyContentCenter, justifyContentStart } from '../../global/common'; +import { justifyContentCenter, justifyContentStart } from "../../global/common"; const sharedStyle = ` font-size: 20px; @@ -12,8 +12,7 @@ const sharedStyle = ` white-space: pre-wrap; `; - -const M = { }; +const M = {}; M.Container = styled.div` width: 1200px; @@ -33,18 +32,18 @@ M.Content01 = styled.div` justify-content: space-between; align-items: start; display: inline-flex; -` +`; M.TitleWrap = styled.div` ${justifyContentStart} gap: 5px; - padding-bottom: 19px -` + padding-bottom: 19px; +`; M.TitleIconWrap = styled.div` gap: 18px; display: inline-flex; -` +`; M.IcBtn = styled.button` all: unset; @@ -57,7 +56,6 @@ M.IcBtn = styled.button` } `; - // ------------------------------------------ M.Content02 = styled.div` flex: 1; @@ -66,7 +64,7 @@ M.Content02 = styled.div` /* justify-content: space-between; */ gap: 21px; overflow: hidden; -` +`; // 타이핑 스피드 부분 ----------------------------- M.TypingSpeedWrap = styled.div` @@ -74,7 +72,7 @@ M.TypingSpeedWrap = styled.div` display: flex; flex-direction: column; gap: 6px; -` +`; // 게이지 전체 + 퍼센트 M.ProgressBarWrapper = styled.div` @@ -91,7 +89,7 @@ M.ProgressBarContainer = styled.div` justify-content: flex-start; align-items: center; margin-right: 14px; -`; +`; // 게이지 자체 M.ProgressBar = styled.div` @@ -105,7 +103,7 @@ M.ProgressBar = styled.div` M.ProgressTick = styled.div` width: 1.5px; height: 7px; - background: ${({ $active }) => ($active ? '#F96F3D' : '#282828')}; + background: ${({ $active }) => ($active ? "#F96F3D" : "#282828")}; opacity: ${({ $active }) => ($active ? 0.6 : 1)}; `; @@ -113,7 +111,7 @@ M.ProgressTick = styled.div` M.ProgressPoint = styled.div` width: 7px; height: 7px; - background: ${({ $active }) => ($active ? '#F96F3D' : '#BFBFBF')}; + background: ${({ $active }) => ($active ? "#F96F3D" : "#BFBFBF")}; `; // 퍼센트 전체 감싸는 래퍼 (가로 74px 고정) @@ -129,7 +127,7 @@ M.ProgressPercentWrap = styled.div` M.Bar = styled.div` width: 6px; height: 30px; - background-color: #BFBFBF; + background-color: #bfbfbf; `; // 회전된 삼각형 @@ -147,16 +145,12 @@ M.PercentText = styled.span` font-size: 16px; font-family: Pretendard; font-weight: 400; - color: #F96F3D; + color: #f96f3d; line-height: 24px; text-align: right; padding-left: 10px; `; - - - - // 본문 내용 부분 -------------------------------- M.ContentBox = styled.div` width: 100%; @@ -183,7 +177,7 @@ M.UnderContent = styled.div` flex-direction: column; display: flex; gap: 15px; -` +`; // 실시간 컬러변경 ------------------------------------------------- M.TypingTextDisplay = styled.div` @@ -196,7 +190,6 @@ M.TypingTextDisplay = styled.div` z-index: 1; `; - M.TypingOverlay = styled.div` position: absolute; top: 0; @@ -237,28 +230,26 @@ M.HiddenInput = styled.textarea` } `; - - // 음악, 출처, 버튼 ------------------------------------------------- M.Line = styled.div` align-self: stretch; height: 1px; - background: #BFBFBF; -` + background: #bfbfbf; +`; M.StyledUnder01 = styled.div` align-self: stretch; justify-content: space-between; align-items: center; display: inline-flex; -` +`; M.StyledUnder02 = styled.div` align-self: stretch; justify-content: space-between; align-items: flex-end; display: inline-flex; -` +`; M.SaveBtn = styled.div` width: 150px; @@ -275,26 +266,26 @@ M.SaveBtn = styled.div` line-height: 30px; &:hover { - background-color: #F96F3D; + background-color: #f96f3d; } &:active { - background-color: #663C2D; + background-color: #663c2d; } &:disabled { - background-color: #BFBFBF; + background-color: #bfbfbf; color: white; cursor: not-allowed; } -` +`; M.StyledMusic = styled.div` justify-content: flex-start; align-items: center; gap: 14px; display: inline-flex; -` +`; M.IconButton = styled.button` background: none; @@ -307,56 +298,56 @@ M.IconButton = styled.button` height: 24px; display: block; } -` +`; M.Album = styled.div` ${justifyContentStart} gap: 12px; -` +`; M.AlbumInfo = styled.div` ${justifyContentStart} gap: 8px; -` +`; M.AlbumImg = styled.img` width: 39px; height: 39px; border-radius: 1px; - border: 0.50px #787878 solid; + border: 0.5px #787878 solid; `; M.PlayListIconWrap = styled.div` ${justifyContentStart} gap: 30px; -` +`; M.PlayIconWrap = styled.div` ${justifyContentCenter} gap: 10px; -` +`; M.PlayIcon = styled.div` ${justifyContentCenter} gap: 10px; - img{ - width: 30px; - height: 30px; - position: relative; - } -` + img { + width: 30px; + height: 30px; + position: relative; + } +`; -M.PlayListWrap = styled.button` +M.PlayListWrap = styled.div` ${justifyContentCenter} background: none; gap: 6px; -` +`; M.ReplayBookIconWrap = styled.div` ${justifyContentStart} gap: 14px; -` +`; M.ReplayBtn = styled.button` width: 32px; @@ -364,34 +355,33 @@ M.ReplayBtn = styled.button` background: none; padding: 6px; border-radius: 50px; - outline: 1px #BFBFBF solid; + outline: 1px #bfbfbf solid; outline-offset: -1px; ${justifyContentCenter} gap: 10px; -` +`; M.BookmarkInfoWrap = styled.div` ${justifyContentCenter} gap: 10px; -` +`; M.BookInfoWrapper = styled.div` flex-direction: column; justify-content: flex-start; align-items: flex-start; display: inline-flex; -` +`; M.BookInfoWrap = styled.div` align-self: stretch; ${justifyContentStart} gap: 6px; -` +`; M.FadeWrapper = styled.div` - opacity: ${({ fade }) => (fade ? 1 : 0)}; + opacity: ${({ $fade }) => ($fade ? 1 : 0)}; transition: opacity 0.3s ease-in-out; -` - +`; -export default M; \ No newline at end of file +export default M; diff --git "a/front/\354\225\204\354\271\264\354\235\264\353\270\214.zip" "b/front/\354\225\204\354\271\264\354\235\264\353\270\214.zip" new file mode 100644 index 0000000..a00743a Binary files /dev/null and "b/front/\354\225\204\354\271\264\354\235\264\353\270\214.zip" differ