Skip to content

Commit ab085da

Browse files
committed
FEAT 토스트 UI 추가, 북마크 버튼 제거 (#develop)
1 parent 1a23f4c commit ab085da

File tree

25 files changed

+288
-34
lines changed

25 files changed

+288
-34
lines changed

pnpm-lock.yaml

Lines changed: 19 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

services/ahhachul.com/package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@
5050
"axios": "^1.7.9",
5151
"js-cookie": "^3.0.5",
5252
"lexical": "^0.23.1",
53+
"lucide-react": "^0.460.0",
5354
"motion": "^11.18.0",
5455
"react": "^19.0.0",
5556
"react-dom": "^19.0.0",
@@ -62,6 +63,7 @@
6263
"react-zoom-pan-pinch": "3.6.0",
6364
"rxjs": "^7.8.1",
6465
"swiper": "^11.1.15",
66+
"uuid": "^11.1.0",
6567
"vaul": "^1.1.2",
6668
"zustand": "^5.0.2"
6769
},

services/ahhachul.com/src/App.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ import React from 'react';
22

33
import { StackFlow } from '@/stackflow';
44

5+
import { UiComponent } from './components';
6+
57
if (import.meta.env.MODE === 'mock') {
68
const { worker } = await import('@/mocks');
79
worker.start();
@@ -11,6 +13,7 @@ function App() {
1113
return (
1214
<React.Suspense fallback={null}>
1315
<StackFlow.Routes />
16+
<UiComponent.ToastContainerComponent />
1417
</React.Suspense>
1518
);
1619
}

services/ahhachul.com/src/components/common/comment/emptyCommentList/EmptyCommentList.styled.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,10 @@ export const Desc = styled.div`
1515
display: flex;
1616
flex-direction: column;
1717
align-items: center;
18-
gap: 6px;
18+
gap: 2px;
1919
2020
& > p {
21-
${theme.fonts.titleMedium};
21+
${theme.fonts.bodyMedium};
2222
color: ${theme.colors.gray[80]};
2323
}
2424
`}

services/ahhachul.com/src/components/common/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,4 +26,5 @@ export * from './imageCarouselModal';
2626
export * from './skeleton';
2727
export * from './iosBottomPadding';
2828

29+
export * from './toast';
2930
export * from './maintain';

services/ahhachul.com/src/components/common/subwayLinePicker/SubwayLinePicker.component.tsx

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,16 +34,21 @@ const SubwayLinePicker: React.FC<SubwayLinePickerProps> = ({
3434
};
3535

3636
return (
37-
<Drawer.Root open={isOpen} shouldScaleBackground onOpenChange={toggleOpen}>
37+
<Drawer.Root
38+
open={isOpen}
39+
shouldScaleBackground
40+
repositionInputs={false}
41+
onOpenChange={toggleOpen}
42+
>
3843
<Drawer.Trigger asChild>
3944
<S.SelectButton isActive={!!selectedLine} aria-invalid={!!errorMsg}>
4045
<span>{selectedLine ? subwayLineOptions[selectedLine] : buttonLabel}</span>
4146
<ChevronIcon />
4247
</S.SelectButton>
4348
</Drawer.Trigger>
4449
<Drawer.Portal>
45-
<S.DrawerOverlay />
46-
<S.DrawerContainer>
50+
<Drawer.Overlay css={S.overlay} />
51+
<Drawer.Content css={S.drawerContainer}>
4752
<S.ContentWrapper>
4853
<S.DrawerHeader>
4954
<S.CancelButton onClick={toggleOpen}>취소</S.CancelButton>
@@ -59,7 +64,7 @@ const SubwayLinePicker: React.FC<SubwayLinePickerProps> = ({
5964
/>
6065
</S.SubwayListContainer>
6166
</S.ContentWrapper>
62-
</S.DrawerContainer>
67+
</Drawer.Content>
6368
</Drawer.Portal>
6469
</Drawer.Root>
6570
);

services/ahhachul.com/src/components/common/subwayLinePicker/SubwayLinePicker.styled.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ export const SelectButton = styled.button<{ isActive: boolean }>`
2121
}
2222
`;
2323

24-
export const DrawerOverlay = styled(Drawer.Overlay)`
24+
export const overlay = css`
2525
position: fixed;
2626
top: 0;
2727
right: 0;
@@ -30,13 +30,13 @@ export const DrawerOverlay = styled(Drawer.Overlay)`
3030
background-color: rgba(0, 0, 0, 0.4);
3131
`;
3232

33-
export const DrawerContainer = styled(Drawer.Content)`
33+
export const drawerContainer = css`
3434
z-index: 999999999;
3535
display: flex;
3636
flex-direction: column;
3737
border-top-left-radius: 10px;
3838
border-top-right-radius: 10px;
39-
height: max-content;
39+
max-height: 96%;
4040
position: fixed;
4141
bottom: 0;
4242
left: 0;
Lines changed: 143 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,143 @@
1-
export {};
1+
import type React from 'react';
2+
import { useEffect } from 'react';
3+
4+
import { css } from '@emotion/react';
5+
import styled from '@emotion/styled';
6+
import { AlertCircle, CheckCircle, Info, X, AlertTriangle } from 'lucide-react';
7+
8+
import { useToastStore, type ToastType } from '@/stores/toast';
9+
10+
interface ToastProps {
11+
id: string;
12+
message: string;
13+
type: ToastType;
14+
onClose: () => void;
15+
}
16+
17+
const toastIcons = {
18+
success: CheckCircle,
19+
warning: AlertTriangle,
20+
info: Info,
21+
error: AlertCircle,
22+
};
23+
24+
const getToastStyle = (type: ToastType) => {
25+
switch (type) {
26+
case 'success':
27+
return css`
28+
background-color: #22c55e;
29+
color: white;
30+
`;
31+
case 'warning':
32+
case 'error':
33+
return css`
34+
background-color: #ef4444;
35+
color: white;
36+
`;
37+
case 'info':
38+
return css`
39+
background-color: #3b82f6;
40+
color: white;
41+
`;
42+
default:
43+
return css`
44+
background-color: #ef4444;
45+
color: white;
46+
`;
47+
}
48+
};
49+
50+
const ToastContainer = styled.div`
51+
position: fixed;
52+
bottom: 3.3rem;
53+
right: 1rem;
54+
left: 1rem;
55+
width: calc(100% - 2rem);
56+
margin: 0 auto;
57+
z-index: 50;
58+
display: flex;
59+
flex-direction: column;
60+
align-items: flex-end;
61+
`;
62+
63+
const ToastWrapper = styled.div<{ type: ToastType }>`
64+
display: flex;
65+
align-items: center;
66+
justify-content: space-between;
67+
width: 100%;
68+
max-width: 28rem;
69+
padding: 1rem;
70+
margin-bottom: 0.5rem;
71+
border-radius: 0.375rem;
72+
box-shadow:
73+
0 4px 6px -1px rgba(0, 0, 0, 0.1),
74+
0 2px 4px -1px rgba(0, 0, 0, 0.06);
75+
${({ type }) => getToastStyle(type)}
76+
`;
77+
78+
const ToastContent = styled.div`
79+
display: flex;
80+
align-items: center;
81+
`;
82+
83+
const ToastMessage = styled.span`
84+
font-weight: 500;
85+
margin-left: 0.5rem;
86+
`;
87+
88+
const CloseButton = styled.button`
89+
display: inline-flex;
90+
align-items: center;
91+
justify-content: center;
92+
width: 1.5rem;
93+
height: 1.5rem;
94+
border-radius: 0.25rem;
95+
color: white;
96+
&:hover {
97+
background-color: rgba(255, 255, 255, 0.2);
98+
}
99+
`;
100+
101+
const Toast: React.FC<ToastProps> = ({ message, type, onClose }) => {
102+
const Icon = toastIcons[type];
103+
104+
useEffect(() => {
105+
const timer = setTimeout(() => {
106+
onClose();
107+
}, 3000);
108+
109+
return () => clearTimeout(timer);
110+
}, [onClose]);
111+
112+
return (
113+
<ToastWrapper type={type} role="alert">
114+
<ToastContent>
115+
<Icon size={20} />
116+
<ToastMessage>{message}</ToastMessage>
117+
</ToastContent>
118+
<CloseButton onClick={onClose} aria-label="Close">
119+
<X size={16} />
120+
</CloseButton>
121+
</ToastWrapper>
122+
);
123+
};
124+
125+
const ToastContainerComponent: React.FC = () => {
126+
const { toasts, removeToast } = useToastStore();
127+
128+
return (
129+
<ToastContainer>
130+
{toasts.map(toast => (
131+
<Toast
132+
key={toast.id}
133+
id={toast.id}
134+
message={toast.message}
135+
type={toast.type}
136+
onClose={() => removeToast(toast.id)}
137+
/>
138+
))}
139+
</ToastContainer>
140+
);
141+
};
142+
143+
export default ToastContainerComponent;

services/ahhachul.com/src/components/common/toast/Toast.styled.ts

Lines changed: 0 additions & 1 deletion
This file was deleted.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export { default as ToastContainerComponent } from './Toast.component';

0 commit comments

Comments
 (0)