diff --git a/src/page/main/main-page.tsx b/src/page/main/main-page.tsx index fadf3cc..4c4e1a8 100644 --- a/src/page/main/main-page.tsx +++ b/src/page/main/main-page.tsx @@ -1,4 +1,25 @@ +import BottomSheet from '@widgets/main/bottom-sheet/bottom-sheet'; +import { RadioContent } from '@widgets/main/bottom-sheet/contents/radio/radio-content'; +import { useState } from 'react'; + +export type SortType = 'latest' | 'near'; + const MainPage = () => { - return
Mainpage
; + const [isOpen, setIsOpen] = useState(true); + const [sortType, setSortType] = useState('latest'); + + return ( +
+ setIsOpen(false)}> + + + + + + + + +
+ ); }; export default MainPage; diff --git a/src/shared/assets/icon/Radio.svg b/src/shared/assets/icon/Radio.svg new file mode 100644 index 0000000..4d2f10c --- /dev/null +++ b/src/shared/assets/icon/Radio.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/shared/hooks/.gitkeep b/src/shared/hooks/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/src/shared/hooks/use-bottom-sheet-context.ts b/src/shared/hooks/use-bottom-sheet-context.ts new file mode 100644 index 0000000..6d645be --- /dev/null +++ b/src/shared/hooks/use-bottom-sheet-context.ts @@ -0,0 +1,15 @@ +import { createContext, useContext } from 'react'; + +interface BottomSheetContextValue { + onClose: () => void; +} + +const BottomSheetContext = createContext(null); + +export function useBottomSheetContext() { + const ctx = useContext(BottomSheetContext); + if (!ctx) throw new Error('BottomSheet 내부에서만 사용 가능'); + return ctx; +} + +export { BottomSheetContext }; diff --git a/src/shared/components/button.tsx b/src/shared/ui/button.tsx similarity index 100% rename from src/shared/components/button.tsx rename to src/shared/ui/button.tsx diff --git a/src/shared/components/floatingActionButton.tsx b/src/shared/ui/floatingActionButton.tsx similarity index 100% rename from src/shared/components/floatingActionButton.tsx rename to src/shared/ui/floatingActionButton.tsx diff --git a/src/shared/components/input.tsx b/src/shared/ui/input.tsx similarity index 100% rename from src/shared/components/input.tsx rename to src/shared/ui/input.tsx diff --git a/src/shared/components/topNavigation.tsx b/src/shared/ui/topNavigation.tsx similarity index 100% rename from src/shared/components/topNavigation.tsx rename to src/shared/ui/topNavigation.tsx diff --git a/src/widgets/.gitkeep b/src/widgets/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/src/widgets/main/bottom-sheet/bottom-sheet.tsx b/src/widgets/main/bottom-sheet/bottom-sheet.tsx new file mode 100644 index 0000000..13bacfc --- /dev/null +++ b/src/widgets/main/bottom-sheet/bottom-sheet.tsx @@ -0,0 +1,93 @@ +import { + BottomSheetContext, + useBottomSheetContext, +} from '@shared/hooks/use-bottom-sheet-context'; +import type { ReactNode } from 'react'; +import { cva } from 'class-variance-authority'; +import { cn } from '@shared/utils/cn'; + +interface BottomSheetProps { + isOpen: boolean; + onClose: () => void; + children: ReactNode; +} + +function Overlay() { + const { onClose } = useBottomSheetContext(); + + return ( +
+ ); +} + +function Root({ isOpen, onClose, children }: BottomSheetProps) { + if (!isOpen) return null; + + return ( + +
{children}
+
+ ); +} + +const containerVariants = cva( + 'fixed bottom-0 left-0 right-0 bg-white rounded-t-[24px] z-50', + { + variants: { + size: { + sm: 'h-[19.8rem]', + md: 'h-[40rem]', + }, + }, + }, +); + +function Container({ + size, + children, +}: { + size?: 'sm' | 'md'; + children: ReactNode; +}) { + return
{children}
; +} + +function Header({ + title, + rightAction, +}: { + title: string; + rightAction?: React.ReactNode; +}) { + return ( +
+
+
+
+
+

{title}

+ + {rightAction && ( + + )} +
+
+ ); +} +function Content({ children }: { children: ReactNode }) { + return
{children}
; +} +const BottomSheet = { + Root, + Overlay, + Container, + Header, + Content, +}; + +export default BottomSheet; diff --git a/src/widgets/main/bottom-sheet/contents/map/location-search.tsx b/src/widgets/main/bottom-sheet/contents/map/location-search.tsx new file mode 100644 index 0000000..67f6b3e --- /dev/null +++ b/src/widgets/main/bottom-sheet/contents/map/location-search.tsx @@ -0,0 +1,24 @@ +import { FloatingActionButton } from '@shared/ui/floatingActionButton'; +import Input from '@shared/ui/input'; +import LocationIcon from '@shared/assets/icon/material-symbols_my-location-outline-rounded.svg?react'; + +interface LocationSearchProps { + value: string; + onChange: (value: string) => void; +} + +export function LocationSearch({ value, onChange }: LocationSearchProps) { + return ( +
+ onChange(e.target.value)} + placeholder="동을 입력해주세요. 예) 역삼동" + /> + } + /> +
+ ); +} diff --git a/src/widgets/main/bottom-sheet/contents/radio/radio-button.tsx b/src/widgets/main/bottom-sheet/contents/radio/radio-button.tsx new file mode 100644 index 0000000..0edd750 --- /dev/null +++ b/src/widgets/main/bottom-sheet/contents/radio/radio-button.tsx @@ -0,0 +1,23 @@ +import RadioIcon from '@shared/assets/icon/Radio.svg?react'; + +interface RadioButtonProps { + label: string; + checked: boolean; + onClick: () => void; +} + +export function RadioButton({ label, checked, onClick }: RadioButtonProps) { + return ( + + ); +} diff --git a/src/widgets/main/bottom-sheet/contents/radio/radio-content.tsx b/src/widgets/main/bottom-sheet/contents/radio/radio-content.tsx new file mode 100644 index 0000000..e0b47a4 --- /dev/null +++ b/src/widgets/main/bottom-sheet/contents/radio/radio-content.tsx @@ -0,0 +1,26 @@ +import { RadioButton } from '@widgets/main/bottom-sheet/contents/radio/radio-button'; + +type SortType = 'latest' | 'near'; + +interface RadioContentProps { + value: SortType; + onChange: (value: SortType) => void; +} + +export function RadioContent({ value, onChange }: RadioContentProps) { + return ( +
+ onChange('latest')} + /> + + onChange('near')} + /> +
+ ); +} diff --git a/src/page/main/component/card/card-info.tsx b/src/widgets/main/card/card-info.tsx similarity index 100% rename from src/page/main/component/card/card-info.tsx rename to src/widgets/main/card/card-info.tsx diff --git a/src/page/main/component/card/card-title.tsx b/src/widgets/main/card/card-title.tsx similarity index 100% rename from src/page/main/component/card/card-title.tsx rename to src/widgets/main/card/card-title.tsx diff --git a/src/page/main/component/card/card.tsx b/src/widgets/main/card/card.tsx similarity index 82% rename from src/page/main/component/card/card.tsx rename to src/widgets/main/card/card.tsx index 3132260..4a6869a 100644 --- a/src/page/main/component/card/card.tsx +++ b/src/widgets/main/card/card.tsx @@ -1,5 +1,5 @@ -import { CardInfo } from '@page/main/component/card/card-info'; -import { CardTitle } from '@page/main/component/card/card-title'; +import { CardInfo } from '@widgets/main/card/card-info'; +import { CardTitle } from '@widgets/main/card/card-title'; interface CardProps { image?: string; diff --git a/vite.config.ts b/vite.config.ts index 62cf985..95df126 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -13,6 +13,7 @@ export default defineConfig({ icon: true, // viewBox 유지 + size 제어 쉬움 replaceAttrValues: { black: 'currentColor', + '#B0B0B0': 'currentColor', }, }, }),