diff --git a/src/app/routes/paths.ts b/src/app/routes/paths.ts index ca1af694..ddf01cfc 100644 --- a/src/app/routes/paths.ts +++ b/src/app/routes/paths.ts @@ -19,4 +19,5 @@ export const ROUTES = { POLICY_PRIVACY: "/policy/privacy", // 개인정보처리방침 MYPAGE: "/mypage", + BOOKMARK: "/bookmark", }; diff --git a/src/app/routes/protected-routes.tsx b/src/app/routes/protected-routes.tsx index 235897f8..9ed95368 100644 --- a/src/app/routes/protected-routes.tsx +++ b/src/app/routes/protected-routes.tsx @@ -44,6 +44,12 @@ const MyPage = lazy(() => })) ); +const BookmarkPage = lazy(() => + import("@/pages/bookmark/bookmark-page").then((module) => ({ + default: module.BookmarkPage, + })) +); + export const protectedRoutes = [ { path: ROUTES.ONBOARDING, element: }, { path: ROUTES.EXPERIENCE_MATCHING, element: }, @@ -68,4 +74,5 @@ export const protectedRoutes = [ }, { path: ROUTES.MYPAGE, element: }, + { path: ROUTES.BOOKMARK, element: }, ]; diff --git a/src/features/bookmark/.gitkeep b/src/features/bookmark/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/src/features/bookmark/config/bookmark-page.constants.ts b/src/features/bookmark/config/bookmark-page.constants.ts new file mode 100644 index 00000000..09bb7a09 --- /dev/null +++ b/src/features/bookmark/config/bookmark-page.constants.ts @@ -0,0 +1,101 @@ +export interface BookmarkRow { + id: number; + companyName: string; + scrapedAt: string; + isConnected: boolean; +} + +export const BOOKMARK_PAGE_SIZE = 4; + +export const BOOKMARK_MOCK_ROWS: BookmarkRow[] = [ + { + id: 1, + companyName: "쿠팡", + scrapedAt: "2025-11-21", + isConnected: true, + }, + { + id: 2, + companyName: "SK네트웍스서비스", + scrapedAt: "2025-11-20", + isConnected: false, + }, + { + id: 3, + companyName: "레진엔터테인먼트", + scrapedAt: "2025-11-19", + isConnected: false, + }, + { + id: 4, + companyName: "컴퓨존", + scrapedAt: "2025-11-19", + isConnected: false, + }, + { + id: 5, + companyName: "CJ ENM", + scrapedAt: "2025-11-18", + isConnected: true, + }, + { + id: 6, + companyName: "삼성전자", + scrapedAt: "2025-11-16", + isConnected: false, + }, + { + id: 7, + companyName: "네이버", + scrapedAt: "2025-11-15", + isConnected: true, + }, + { + id: 8, + companyName: "카카오", + scrapedAt: "2025-11-14", + isConnected: false, + }, + { + id: 9, + companyName: "우아한형제들", + scrapedAt: "2025-11-12", + isConnected: true, + }, + { + id: 10, + companyName: "토스", + scrapedAt: "2025-11-11", + isConnected: true, + }, + { + id: 11, + companyName: "라인플러스", + scrapedAt: "2025-11-10", + isConnected: false, + }, + { + id: 12, + companyName: "당근", + scrapedAt: "2025-11-09", + isConnected: true, + }, + { + id: 13, + companyName: "현대자동차", + scrapedAt: "2025-11-08", + isConnected: true, + }, + { + id: 14, + companyName: "LG전자", + scrapedAt: "2025-11-07", + isConnected: false, + }, + { + id: 15, + companyName: "포스코", + scrapedAt: "2025-11-05", + isConnected: true, + }, +]; diff --git a/src/features/bookmark/index.ts b/src/features/bookmark/index.ts new file mode 100644 index 00000000..5025f047 --- /dev/null +++ b/src/features/bookmark/index.ts @@ -0,0 +1,9 @@ +export { + BOOKMARK_MOCK_ROWS, + BOOKMARK_PAGE_SIZE, +} from "./config/bookmark-page.constants"; +export type { BookmarkRow } from "./config/bookmark-page.constants"; + +export { BookmarkCheckbox } from "./ui/bookmark-checkbox"; +export { BookmarkEmptyState } from "./ui/bookmark-empty-state"; +export { BookmarkTable } from "./ui/bookmark-table"; diff --git a/src/features/bookmark/ui/bookmark-checkbox.css.ts b/src/features/bookmark/ui/bookmark-checkbox.css.ts new file mode 100644 index 00000000..b188066d --- /dev/null +++ b/src/features/bookmark/ui/bookmark-checkbox.css.ts @@ -0,0 +1,43 @@ +import { style } from "@vanilla-extract/css"; + +import { themeVars } from "@/app/styles"; + +export const checkbox = style({ + position: "relative", + display: "inline-flex", + alignItems: "center", + justifyContent: "center", + width: "2.4rem", + height: "2.4rem", + cursor: "pointer", + verticalAlign: "middle", +}); + +export const input = style({ + position: "absolute", + inset: 0, + margin: 0, + opacity: 0, + cursor: "pointer", +}); + +export const icon = style({ + width: "2.4rem", + height: "2.4rem", + display: "inline-flex", + alignItems: "center", + justifyContent: "center", + pointerEvents: "none", + selectors: { + [`${input}:focus-visible + &`]: { + outline: `0.2rem solid ${themeVars.color.blue400}`, + outlineOffset: "0.2rem", + }, + }, +}); + +export const iconSvg = style({ + width: "2.4rem", + height: "2.4rem", + flexShrink: 0, +}); diff --git a/src/features/bookmark/ui/bookmark-checkbox.tsx b/src/features/bookmark/ui/bookmark-checkbox.tsx new file mode 100644 index 00000000..99b421b0 --- /dev/null +++ b/src/features/bookmark/ui/bookmark-checkbox.tsx @@ -0,0 +1,39 @@ +import { + CheckboxSmallDisabled, + CheckboxSmallPressed, +} from "@/shared/assets/icons"; + +import * as styles from "./bookmark-checkbox.css"; + +interface BookmarkCheckboxProps { + checked: boolean; + onCheckedChange: (checked: boolean) => void; + ariaLabel: string; +} + +const BookmarkCheckbox = ({ + checked, + onCheckedChange, + ariaLabel, +}: BookmarkCheckboxProps) => { + return ( + + ); +}; + +export { BookmarkCheckbox }; diff --git a/src/features/bookmark/ui/bookmark-empty-state.css.ts b/src/features/bookmark/ui/bookmark-empty-state.css.ts new file mode 100644 index 00000000..52da56c3 --- /dev/null +++ b/src/features/bookmark/ui/bookmark-empty-state.css.ts @@ -0,0 +1,33 @@ +import { style } from "@vanilla-extract/css"; + +import { themeVars } from "@/app/styles"; + +export const emptyContent = style({ + display: "flex", + flexDirection: "column", + alignItems: "center", + justifyContent: "center", + textAlign: "center", +}); + +export const emptyImageWrap = style({ + width: "36rem", +}); + +export const emptyImage = style({ + width: "100%", + height: "auto", + display: "block", +}); + +export const emptyTitle = style({ + marginTop: "1rem", + color: themeVars.color.gray800, + ...themeVars.fontStyles.title_b_28, +}); + +export const emptyDescription = style({ + marginTop: "0.8rem", + color: themeVars.color.gray500, + ...themeVars.fontStyles.hline_m_18, +}); diff --git a/src/features/bookmark/ui/bookmark-empty-state.tsx b/src/features/bookmark/ui/bookmark-empty-state.tsx new file mode 100644 index 00000000..d092d340 --- /dev/null +++ b/src/features/bookmark/ui/bookmark-empty-state.tsx @@ -0,0 +1,41 @@ +import { ERROR, SEARCH_IMG } from "@/shared/assets/images"; + +import * as styles from "./bookmark-empty-state.css"; + +type BookmarkEmptyStateType = "bookmark" | "search"; + +interface BookmarkEmptyStateProps { + type: BookmarkEmptyStateType; +} + +const EMPTY_STATE_CONTENT = { + bookmark: { + image: ERROR, + title: "북마크한 기업이 없습니다", + description: "관심 있는 기업을 탐색하고 북마크해 보세요.", + }, + search: { + image: SEARCH_IMG, + title: "검색 결과가 없습니다", + description: "다른 키워드로 다시 검색해 보세요.", + }, +} as const; + +const BookmarkEmptyState = ({ type }: BookmarkEmptyStateProps) => { + const { image, title, description } = EMPTY_STATE_CONTENT[type]; + const titleId = `${type}-empty-state-title`; + + return ( +
+
+ +
+

+ {title} +

+

{description}

+
+ ); +}; + +export { BookmarkEmptyState }; diff --git a/src/features/bookmark/ui/bookmark-table.css.ts b/src/features/bookmark/ui/bookmark-table.css.ts new file mode 100644 index 00000000..b47eb3cc --- /dev/null +++ b/src/features/bookmark/ui/bookmark-table.css.ts @@ -0,0 +1,106 @@ +import { style } from "@vanilla-extract/css"; +import { recipe } from "@vanilla-extract/recipes"; + +import { themeVars } from "@/app/styles"; + +const tableTopBorder = `1px solid ${themeVars.color.gray400}`; +const rowBorder = `1px solid ${themeVars.color.gray200}`; + +export const table = style({ + alignSelf: "flex-start", + width: "100%", + borderCollapse: "collapse", + borderTop: tableTopBorder, + tableLayout: "fixed", +}); + +export const checkboxColumn = style({ + width: "11.2rem", +}); + +export const companyColumn = style({ + width: "54.8rem", +}); + +export const dateColumn = style({ + width: "20rem", +}); + +export const statusColumn = style({ + width: "20rem", +}); + +export const headerCell = style({ + height: "4rem", + backgroundColor: themeVars.color.gray100, + color: themeVars.color.gray800, + borderBottom: rowBorder, + ...themeVars.fontStyles.body_b_16, +}); + +export const bodyCell = style({ + height: "11rem", + color: themeVars.color.gray800, + borderBottom: rowBorder, + ...themeVars.fontStyles.hline_m_18, +}); + +export const checkboxCell = style({ + textAlign: "center", + verticalAlign: "middle", +}); + +export const leftCell = style({ + textAlign: "left", + paddingLeft: "0.8rem", + verticalAlign: "middle", +}); + +export const centerCell = style({ + textAlign: "center", + verticalAlign: "middle", +}); + +export const companyButton = style({ + padding: 0, + border: 0, + background: "transparent", + color: themeVars.color.gray800, + cursor: "pointer", + ...themeVars.fontStyles.hding_m_20, + selectors: { + "&:hover": { + textDecoration: "underline", + }, + }, +}); + +export const connectionStatus = recipe({ + base: { + ...themeVars.fontStyles.hline_m_18, + }, + variants: { + connected: { + true: { + color: themeVars.color.gray800, + }, + false: { + color: themeVars.color.gray300, + }, + }, + }, + defaultVariants: { + connected: false, + }, +}); + +export const srOnly = style({ + position: "absolute", + width: "0.1rem", + height: "0.1rem", + padding: 0, + margin: "-0.1rem", + overflow: "hidden", + clip: "rect(0, 0, 0, 0)", + border: 0, +}); diff --git a/src/features/bookmark/ui/bookmark-table.tsx b/src/features/bookmark/ui/bookmark-table.tsx new file mode 100644 index 00000000..88d5aa00 --- /dev/null +++ b/src/features/bookmark/ui/bookmark-table.tsx @@ -0,0 +1,88 @@ +import { BookmarkCheckbox } from "./bookmark-checkbox"; +import * as styles from "./bookmark-table.css"; + +import type { BookmarkRow } from "../config/bookmark-page.constants"; + +interface BookmarkTableProps { + rows: BookmarkRow[]; + selectedIds: Set; + isAllSelected: boolean; + onToggleAll: (checked: boolean) => void; + onToggleRow: (rowId: number, checked: boolean) => void; + onClickCompany: (companyId: number) => void; +} + +const BookmarkTable = ({ + rows, + selectedIds, + isAllSelected, + onToggleAll, + onToggleRow, + onClickCompany, +}: BookmarkTableProps) => { + return ( + + + + + + + + + + + + + + + + + + {rows.map((row) => ( + + + + + + + ))} + +
기업 북마크 목록
+ + 기업명 + 스크랩일 + + 경험 연결 여부 +
+ onToggleRow(row.id, checked)} + ariaLabel={`${row.companyName} 선택`} + /> + + + + {row.scrapedAt} + + + 연결 + +
+ ); +}; + +export { BookmarkTable }; diff --git a/src/features/experience-detail/ui/experience-form/experience-form.tsx b/src/features/experience-detail/ui/experience-form/experience-form.tsx index fc50ef92..68f3550e 100644 --- a/src/features/experience-detail/ui/experience-form/experience-form.tsx +++ b/src/features/experience-detail/ui/experience-form/experience-form.tsx @@ -38,7 +38,12 @@ const ExperienceForm = () => { isDefault={isDraftDefault} onToggle={onToggleDefault} rightSlot={ - } diff --git a/src/pages/bookmark/bookmark-page.css.ts b/src/pages/bookmark/bookmark-page.css.ts new file mode 100644 index 00000000..9aa5ea6d --- /dev/null +++ b/src/pages/bookmark/bookmark-page.css.ts @@ -0,0 +1,123 @@ +import { globalStyle, style } from "@vanilla-extract/css"; + +import { themeVars } from "@/app/styles"; + +export const page = style({ + width: "100%", + maxWidth: "106rem", + margin: "0 auto", + paddingTop: `calc(${themeVars.height.header} + 8rem)`, + paddingBottom: "8rem", +}); + +export const topRow = style({ + display: "flex", + alignItems: "center", + justifyContent: "space-between", + gap: "2rem", +}); + +export const headerSection = style({ + display: "flex", + alignItems: "center", + gap: "1.6rem", +}); + +export const titleIcon = style({ + width: "6.4rem", + height: "6.4rem", + flexShrink: 0, +}); + +export const titleWrap = style({ + display: "flex", + flexDirection: "column", + gap: "0.4rem", +}); + +export const title = style({ + color: themeVars.color.black, + ...themeVars.fontStyles.title_b_24, +}); + +export const subtitle = style({ + color: themeVars.color.gray500, + ...themeVars.fontStyles.body_m_16, +}); + +export const actionSection = style({ + display: "flex", + alignItems: "center", + gap: "1.2rem", +}); + +export const searchWrap = style({ + display: "flex", + alignItems: "center", +}); + +export const deleteButtonWrap = style({ + display: "inline-flex", +}); + +export const deleteButtonWrapActive = style({}); + +export const trashIcon = style({ + width: "2.4rem", + height: "2.4rem", + flexShrink: 0, + color: "currentColor", +}); + +export const modalTrashIcon = style({ + color: themeVars.color.blue500, +}); + +globalStyle(`${deleteButtonWrap} > button`, { + width: "4.8rem", + minWidth: "4.8rem", + height: "4.8rem", + padding: 0, + borderRadius: "12px", + border: `1.5px solid ${themeVars.color.blue600}`, + backgroundColor: themeVars.color.blue600, + color: themeVars.color.white, +}); + +globalStyle(`${deleteButtonWrap} > button:hover:not(:disabled)`, { + borderColor: themeVars.color.blue600, + backgroundColor: themeVars.color.blue600, + color: themeVars.color.white, +}); + +globalStyle(`${deleteButtonWrap} > button:active:not(:disabled)`, { + borderColor: themeVars.color.gray300, + backgroundColor: themeVars.color.white, + color: themeVars.color.gray300, +}); + +globalStyle(`${deleteButtonWrapActive} > button:not(:disabled)`, { + borderColor: themeVars.color.gray300, + backgroundColor: themeVars.color.white, + color: themeVars.color.gray300, +}); + +globalStyle(`${deleteButtonWrap} > button:disabled`, { + borderColor: themeVars.color.blue600, + backgroundColor: themeVars.color.blue600, + color: themeVars.color.white, +}); + +export const tableSection = style({ + marginTop: "5rem", + display: "flex", + alignItems: "center", + justifyContent: "center", + height: "48.5rem", +}); + +export const paginationSection = style({ + marginTop: "4.8rem", + display: "flex", + justifyContent: "center", +}); diff --git a/src/pages/bookmark/bookmark-page.tsx b/src/pages/bookmark/bookmark-page.tsx new file mode 100644 index 00000000..90b33980 --- /dev/null +++ b/src/pages/bookmark/bookmark-page.tsx @@ -0,0 +1,252 @@ +import { useEffect, useMemo, useState } from "react"; +import { useNavigate, useSearchParams } from "react-router-dom"; + +import { ROUTES } from "@/app/routes/paths"; +import { + BOOKMARK_MOCK_ROWS, + BOOKMARK_PAGE_SIZE, + BookmarkEmptyState, + BookmarkTable, +} from "@/features/bookmark"; +import { IconBookmarkBefore, IconTrash } from "@/shared/assets/icons"; +import { modalStore } from "@/shared/model/store"; +import { Button, ModalBasic, Pagination, Search } from "@/shared/ui"; + +import * as styles from "./bookmark-page.css"; + +const BOOKMARK_QUERY_KEY = "keyword"; +const BOOKMARK_PAGE_QUERY_KEY = "page"; +const BOOKMARK_DELETE_MODAL_ID = "bookmark-delete-modal"; + +const BookmarkPage = () => { + const navigate = useNavigate(); + const [searchParams, setSearchParams] = useSearchParams(); + + const [rows, setRows] = useState(BOOKMARK_MOCK_ROWS); + const [selectedIds, setSelectedIds] = useState>(new Set()); + const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false); + + const keyword = searchParams.get(BOOKMARK_QUERY_KEY)?.trim() ?? ""; + const currentPageParam = Number(searchParams.get(BOOKMARK_PAGE_QUERY_KEY)); + const currentPage = + Number.isInteger(currentPageParam) && currentPageParam > 0 + ? currentPageParam + : 1; + const [searchInput, setSearchInput] = useState(keyword); + + useEffect(() => { + setSearchInput(keyword); + }, [keyword]); + + useEffect(() => { + const unsubscribe = modalStore.subscribe((modals) => { + setIsDeleteModalOpen( + modals.some((modal) => modal.id === BOOKMARK_DELETE_MODAL_ID) + ); + }); + + return unsubscribe; + }, []); + + const filteredRows = useMemo(() => { + if (!keyword) return rows; + + const normalizedKeyword = keyword.toLowerCase(); + return rows.filter((row) => + row.companyName.toLowerCase().includes(normalizedKeyword) + ); + }, [keyword, rows]); + + const totalPage = Math.ceil(filteredRows.length / BOOKMARK_PAGE_SIZE); + const paginationTotalPage = Math.max(totalPage, 1); + const resolvedCurrentPage = Math.min(currentPage, paginationTotalPage); + + const currentPageRows = useMemo(() => { + const startIndex = (resolvedCurrentPage - 1) * BOOKMARK_PAGE_SIZE; + return filteredRows.slice(startIndex, startIndex + BOOKMARK_PAGE_SIZE); + }, [filteredRows, resolvedCurrentPage]); + + const visibleIds = useMemo( + () => currentPageRows.map((row) => row.id), + [currentPageRows] + ); + + const isAllSelected = + visibleIds.length > 0 && visibleIds.every((id) => selectedIds.has(id)); + + const isDeleteDisabled = selectedIds.size === 0; + const isBookmarkEmpty = rows.length === 0; + const isSearchResultEmpty = rows.length > 0 && filteredRows.length === 0; + const showPagination = !isBookmarkEmpty && !isSearchResultEmpty; + + const updateSearchParams = (nextKeyword: string, nextPage: number) => { + const nextSearchParams = new URLSearchParams(searchParams); + + if (nextKeyword) { + nextSearchParams.set(BOOKMARK_QUERY_KEY, nextKeyword); + } else { + nextSearchParams.delete(BOOKMARK_QUERY_KEY); + } + + if (nextPage > 1) { + nextSearchParams.set(BOOKMARK_PAGE_QUERY_KEY, String(nextPage)); + } else { + nextSearchParams.delete(BOOKMARK_PAGE_QUERY_KEY); + } + + setSearchParams(nextSearchParams); + }; + + const handleSearch = (value: string) => { + const trimmedValue = value.trim(); + + if (value.length > 0 && trimmedValue.length === 0) { + setSearchInput(keyword); + return; + } + + updateSearchParams(trimmedValue, 1); + setSelectedIds(new Set()); + }; + + const handlePageChange = (page: number) => { + setSelectedIds(new Set()); + updateSearchParams(keyword, page); + }; + + const handleToggleAll = (checked: boolean) => { + if (checked) { + setSelectedIds((prev) => { + const next = new Set(prev); + visibleIds.forEach((id) => next.add(id)); + return next; + }); + return; + } + + setSelectedIds((prev) => { + const next = new Set(prev); + visibleIds.forEach((id) => next.delete(id)); + return next; + }); + }; + + const handleToggleRow = (rowId: number, checked: boolean) => { + setSelectedIds((prev) => { + const next = new Set(prev); + + if (checked) { + next.add(rowId); + } else { + next.delete(rowId); + } + + return next; + }); + }; + + const handleDeleteSelected = () => { + setRows((prev) => prev.filter((row) => !selectedIds.has(row.id))); + setSelectedIds(new Set()); + modalStore.close(BOOKMARK_DELETE_MODAL_ID); + }; + + const handleOpenDeleteModal = () => { + if (isDeleteDisabled) return; + + modalStore.open( + + } + title="선택한 북마크를 삭제할까요?" + subTitle="삭제하면 다시 복구할 수 없어요" + closeText="취소하기" + confirmText="삭제하기" + onClose={() => modalStore.close(BOOKMARK_DELETE_MODAL_ID)} + onConfirm={handleDeleteSelected} + />, + undefined, + undefined, + BOOKMARK_DELETE_MODAL_ID + ); + }; + + const handleClickCompany = (companyId: number) => { + navigate(ROUTES.COMPANY(String(companyId))); + }; + + return ( +
+
+
+
+ +
+
+ +
+ +
+ +
+
+
+ +
+ {isBookmarkEmpty ? ( + + ) : isSearchResultEmpty ? ( + + ) : ( + + )} +
+ + {showPagination && ( +
+ +
+ )} +
+ ); +}; + +export { BookmarkPage }; diff --git a/src/pages/my-page/my-page.tsx b/src/pages/my-page/my-page.tsx index c30e91ef..7690ac76 100644 --- a/src/pages/my-page/my-page.tsx +++ b/src/pages/my-page/my-page.tsx @@ -1,5 +1,6 @@ -import { Navigate } from "react-router-dom"; +import { Navigate, useNavigate } from "react-router-dom"; +import { ROUTES } from "@/app/routes/paths"; import { useAuthStore } from "@/app/store"; import { useGetProfile, useLogout } from "@/features/my-page"; import { queryClient } from "@/shared/api"; @@ -9,10 +10,15 @@ import * as styles from "./my-page.css"; import { MyPageCards } from "./ui/my-page-cards"; const MyPage = () => { + const navigate = useNavigate(); const { actions, isLoggedIn } = useAuthStore(); const { data } = useGetProfile({ enabled: isLoggedIn }); const { mutate: logout, isPending } = useLogout(); + const handleBookmarkClick = () => { + navigate(ROUTES.BOOKMARK); + }; + if (!isLoggedIn) { return ; } @@ -41,7 +47,7 @@ const MyPage = () => { - + ); }; diff --git a/src/pages/my-page/ui/my-page-cards.css.ts b/src/pages/my-page/ui/my-page-cards.css.ts index 8f847fdf..3a7d94e8 100644 --- a/src/pages/my-page/ui/my-page-cards.css.ts +++ b/src/pages/my-page/ui/my-page-cards.css.ts @@ -46,6 +46,10 @@ export const mediumIconPadding = style({ padding: "2.2rem 2.8rem 3.1rem", }); +export const clickableCard = style({ + cursor: "pointer", +}); + export const largeRow = style({ display: "flex", alignItems: "center", diff --git a/src/pages/my-page/ui/my-page-cards.tsx b/src/pages/my-page/ui/my-page-cards.tsx index f39a972c..d8726273 100644 --- a/src/pages/my-page/ui/my-page-cards.tsx +++ b/src/pages/my-page/ui/my-page-cards.tsx @@ -17,6 +17,10 @@ type CardProps = HTMLAttributes & { as?: "section" | "div"; }; +type MyPageCardsProps = GetMeResponseDto & { + onBookmarkClick: () => void; +}; + const Card = ({ type, as: Component = "div", @@ -45,7 +49,8 @@ const MyPageCards = ({ educationLevel, firstIndustry, fistJob, -}: GetMeResponseDto) => { + onBookmarkClick, +}: MyPageCardsProps) => { return (
@@ -80,7 +85,16 @@ const MyPageCards = ({ { + if (event.key === "Enter" || event.key === " ") { + event.preventDefault(); + onBookmarkClick(); + } + }} + role="button" + tabIndex={0} aria-label="기업 북마크" >
diff --git a/src/shared/assets/icons/checkbox_small_default.svg b/src/shared/assets/icons/checkbox_small_default.svg new file mode 100644 index 00000000..6ae287e7 --- /dev/null +++ b/src/shared/assets/icons/checkbox_small_default.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/shared/assets/icons/checkbox_small_disabled.svg b/src/shared/assets/icons/checkbox_small_disabled.svg new file mode 100644 index 00000000..9ac7ee73 --- /dev/null +++ b/src/shared/assets/icons/checkbox_small_disabled.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/shared/assets/icons/checkbox_small_pressed.svg b/src/shared/assets/icons/checkbox_small_pressed.svg new file mode 100644 index 00000000..aa049a53 --- /dev/null +++ b/src/shared/assets/icons/checkbox_small_pressed.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/shared/assets/icons/icon_bookmark.svg b/src/shared/assets/icons/icon_bookmark.svg new file mode 100644 index 00000000..526758a7 --- /dev/null +++ b/src/shared/assets/icons/icon_bookmark.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/shared/assets/icons/icon_bookmark_before.svg b/src/shared/assets/icons/icon_bookmark_before.svg new file mode 100644 index 00000000..d502ce6d --- /dev/null +++ b/src/shared/assets/icons/icon_bookmark_before.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/src/shared/assets/icons/icon_trash.svg b/src/shared/assets/icons/icon_trash.svg new file mode 100644 index 00000000..c58da8e6 --- /dev/null +++ b/src/shared/assets/icons/icon_trash.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/src/shared/assets/icons/icon_trash_on.svg b/src/shared/assets/icons/icon_trash_on.svg deleted file mode 100644 index 74bec63d..00000000 --- a/src/shared/assets/icons/icon_trash_on.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/src/shared/assets/icons/index.ts b/src/shared/assets/icons/index.ts index 02e4b8d4..2be20e37 100644 --- a/src/shared/assets/icons/index.ts +++ b/src/shared/assets/icons/index.ts @@ -24,6 +24,9 @@ export { default as IconLinkDefault } from "./icon_link_default.svg?react"; export { default as IconInformation } from "./icon_information.svg?react"; export { default as IconQuestion } from "./icon_question.svg?react"; export { default as IconCalendar } from "./icon_date.svg?react"; +export { default as IconBookmarkBefore } from "./icon_bookmark_before.svg?react"; +export { default as CheckboxSmallDisabled } from "./checkbox_small_disabled.svg?react"; +export { default as CheckboxSmallPressed } from "./checkbox_small_pressed.svg?react"; export { default as DateLeftArrow } from "./date_arrow_left.svg?react"; export { default as DateRightArrow } from "./date_arrow_right.svg?react"; @@ -56,4 +59,4 @@ export { default as IconCheckOn } from "./icon_check_on.svg?react"; export { default as IconPen } from "./icon_pen.svg?react"; export { default as IconWarn } from "./icon_warning.svg?react"; -export { default as IconTrash } from "./icon_trash_on.svg?react"; +export { default as IconTrash } from "./icon_trash.svg?react"; diff --git a/src/shared/assets/images/index.ts b/src/shared/assets/images/index.ts index 05aad05b..d3449a5a 100644 --- a/src/shared/assets/images/index.ts +++ b/src/shared/assets/images/index.ts @@ -32,5 +32,6 @@ export { default as LOADING } from "./loading-spinner.png"; export { default as ICONAI } from "./icon_ai.png"; export { default as ERROR } from "./error_img.png"; +export { default as SEARCH_IMG } from "./search_img.png"; export { default as PROFILE } from "./icon_profile.png"; diff --git a/src/shared/assets/images/search_img.png b/src/shared/assets/images/search_img.png new file mode 100644 index 00000000..06532923 Binary files /dev/null and b/src/shared/assets/images/search_img.png differ