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',
},
},
}),