Skip to content

Commit e104b8b

Browse files
authored
Merge pull request #103 from wafflestudio/hotfix/google-console
SEO 인덱싱 위해 구글 서치 콘솔 연결
2 parents 84863c2 + a9d45fd commit e104b8b

24 files changed

Lines changed: 559 additions & 156 deletions

index.html

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,17 @@
55
<link rel="icon" type="image/svg+xml" href="/assets/logo.png" />
66
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
77
<title>행샤</title>
8+
<meta
9+
name="description"
10+
content="서울대학교 교내 행사를 한눈에 모아보는 캘린더 서비스"
11+
/>
12+
<meta property="og:title" content="행샤" />
13+
<meta property="og:description" content="..." />
14+
<meta property="og:url" content="https://hangsha.wafflestudio.com" />
15+
<meta
16+
name="google-site-verification"
17+
content="vN4BTCAW-_S7Oc3eqEP1cQgi3rDjRQmh6ZHSawwF9Ys"
18+
/>
819
</head>
920
<body>
1021
<div id="root"></div>

src/App.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { DetailContextProvider } from "./contexts/DetailContext";
88
import AppRoutes from "./router/AppRoutes";
99
import { SearchProvider } from "./contexts/SearchContext";
1010
import { TimetableProvider } from "./contexts/TimetableContext";
11+
import { SidePanelResizeProvider } from "./widgets/SidePanelResize";
1112

1213
function App() {
1314
return (
@@ -19,7 +20,9 @@ function App() {
1920
<DayViewContextProvider>
2021
<DetailContextProvider>
2122
<TimetableProvider>
22-
<AppRoutes />
23+
<SidePanelResizeProvider>
24+
<AppRoutes />
25+
</SidePanelResizeProvider>
2326
</TimetableProvider>
2427
</DetailContextProvider>
2528
</DayViewContextProvider>

src/pages/CalendarView.tsx

Lines changed: 51 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,22 +4,27 @@ import { Views, type View } from "react-big-calendar";
44
import { useQueryClient } from "@tanstack/react-query";
55
import PullToRefresh from "react-simple-pull-to-refresh";
66
import styles from "@styles/CalendarView.module.css";
7-
import type {
8-
CalendarEvent,
9-
Event,
10-
} from "@types";
7+
import type { CalendarEvent, Event } from "@types";
118
import DetailView from "@/widgets/DetailView";
129
import MonthSideView from "@widgets/Month/MonthSideView/MonthSideView";
1310
import { MyCalendar } from "@widgets/MyCalendar";
1411
import { Sidebar } from "@widgets/Sidebar";
12+
import {
13+
SidePanelResizeHandle,
14+
useResizableSidePanel,
15+
} from "@/widgets/SidePanelResize";
1516

1617
import { useDetail } from "@contexts/DetailContext";
1718
import { useEvents } from "@contexts/EventContext";
1819
import { useFilter } from "@contexts/FilterContext";
1920
import { useUserData } from "@/contexts/UserDataContext";
2021
import BottomNav from "@/widgets/BottomNav";
2122
import { FilterSheet } from "@/widgets/FilterSheet/FilterSheet";
22-
import { useMonthEvents, useWeekEvents, useDayEvents } from "@/contexts/useCalendarEvents";
23+
import {
24+
useMonthEvents,
25+
useWeekEvents,
26+
useDayEvents,
27+
} from "@/contexts/useCalendarEvents";
2328

2429
const CalendarView = () => {
2530
// EventContext
@@ -56,12 +61,28 @@ const CalendarView = () => {
5661
eventTypeId: globalCategory?.map((g) => g.id),
5762
orgId: globalOrg?.map((g) => g.id),
5863
statusId: globalStatus?.map((g) => g.id),
59-
}), [globalCategory, globalOrg, globalStatus],
60-
)
61-
62-
const { data: monthViewData } = useMonthEvents(currentDate, filters, excludedKeywords, interestCategories);
63-
const { data: weekViewData} = useWeekEvents(currentDate, filters, excludedKeywords, interestCategories);
64-
const { data: dayViewEvents = [] } = useDayEvents(currentDate, filters, excludedKeywords, interestCategories);
64+
}),
65+
[globalCategory, globalOrg, globalStatus],
66+
);
67+
68+
const { data: monthViewData } = useMonthEvents(
69+
currentDate,
70+
filters,
71+
excludedKeywords,
72+
interestCategories,
73+
);
74+
const { data: weekViewData } = useWeekEvents(
75+
currentDate,
76+
filters,
77+
excludedKeywords,
78+
interestCategories,
79+
);
80+
const { data: dayViewEvents = [] } = useDayEvents(
81+
currentDate,
82+
filters,
83+
excludedKeywords,
84+
interestCategories,
85+
);
6586

6687
const queryClient = useQueryClient();
6788
const handleRefresh = async () => {
@@ -72,11 +93,11 @@ const CalendarView = () => {
7293
]);
7394
};
7495

75-
76-
77-
// Flatten byDate buckets in chronological key order : preserve each date bucket's internal sequence
96+
// Flatten byDate buckets in chronological key order : preserve each date bucket's internal sequence
7897
// 중복 시 첫 event만 keep : multi-day event sits at the position of its earliest bucket
79-
const flattenByDate = (byDate: Record<string, { events: Event[] }> | undefined) => {
98+
const flattenByDate = (
99+
byDate: Record<string, { events: Event[] }> | undefined,
100+
) => {
80101
const seen = new Map<number, Event>();
81102
const buckets = byDate ?? {};
82103
for (const dateKey of Object.keys(buckets).sort()) {
@@ -95,7 +116,6 @@ const CalendarView = () => {
95116
setCurrentDate(dayDate);
96117
}, [dayDate]);
97118

98-
99119
// click handler
100120
const onShowMoreClick = (date: Date, view: string) => {
101121
// showSideMonth on, showDetailView off
@@ -138,6 +158,9 @@ const CalendarView = () => {
138158
// clicking outside of sideview (that is not event or anything else) created
139159
const sidePanelRef = useRef<HTMLDivElement>(null);
140160

161+
// shared width for both MonthSideView and DetailView panels
162+
const { handleResizeStart, sidePanelStyle } = useResizableSidePanel();
163+
141164
// detect outside clicks
142165
useEffect(() => {
143166
function handleClickOutside(event: MouseEvent) {
@@ -186,7 +209,14 @@ const CalendarView = () => {
186209
)}
187210
</div>
188211
{showSideMonth && (
189-
<div className={styles.sidePanel} ref={sidePanelRef}>
212+
<div
213+
className={styles.sidePanel}
214+
ref={sidePanelRef}
215+
style={sidePanelStyle}
216+
>
217+
{!isMobile && (
218+
<SidePanelResizeHandle onMouseDown={handleResizeStart} />
219+
)}
190220
<MonthSideView day={clickedDate} onClose={handleCloseSideMonth} />
191221
</div>
192222
)}
@@ -195,7 +225,11 @@ const CalendarView = () => {
195225
<div
196226
className={`${styles.sidePanel} ${styles.detailPanel}`}
197227
ref={sidePanelRef}
228+
style={sidePanelStyle}
198229
>
230+
{!isMobile && (
231+
<SidePanelResizeHandle onMouseDown={handleResizeStart} />
232+
)}
199233
<DetailView eventId={clickedEventId} />
200234
</div>
201235
)}

src/pages/MyPage.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -132,14 +132,14 @@ const ProfileCard = ({ onClickInterest }: { onClickInterest: () => void }) => {
132132
<IoMdDoneAll
133133
onClick={handleChangesSave}
134134
className={styles.editBtn}
135-
size={20}
136-
color="ABABAB"
135+
size={25}
136+
color="#555555"
137137
/>
138138
) : (
139139
<RiPencilFill
140140
className={styles.editBtn}
141141
color="ABABAB"
142-
size={24}
142+
size={25}
143143
onClick={() => setIsEditmode(true)}
144144
/>
145145
)}

src/pages/bookmark/Bookmark.tsx

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { useEffect, useRef } from "react";
12
import { useUserData } from "@/contexts/UserDataContext";
23
import styles from "@styles/Bookmarks.module.css";
34
import { FaChevronLeft, FaChevronRight } from "react-icons/fa6";
@@ -6,6 +7,10 @@ import { useNavigate } from "react-router-dom";
67
import GalleryCard from "@/widgets/Day/Gallery/GalleryCard";
78
import { useDetail } from "@/contexts/DetailContext";
89
import DetailView from "@/widgets/DetailView";
10+
import {
11+
SidePanelResizeHandle,
12+
useResizableSidePanel,
13+
} from "@/widgets/SidePanelResize";
914

1015
export const BookmarkWidget = () => {
1116
const { bookmarkedEvents } = useUserData();
@@ -42,7 +47,25 @@ const BookmarksPage = () => {
4247
const { bookmarkedEvents } = useUserData();
4348
const navigate = useNavigate();
4449

45-
const { showDetail, clickedEventId } = useDetail();
50+
const { showDetail, setShowDetail, clickedEventId } = useDetail();
51+
const { isMobile, handleResizeStart, sidePanelStyle } =
52+
useResizableSidePanel();
53+
54+
const sidePanelRef = useRef<HTMLDivElement>(null);
55+
56+
useEffect(() => {
57+
function handleClickOutside(event: MouseEvent) {
58+
if (!sidePanelRef.current) return;
59+
const isInside = sidePanelRef.current.contains(event.target as Node);
60+
if (!isInside) {
61+
setShowDetail(false);
62+
}
63+
}
64+
document.addEventListener("mousedown", handleClickOutside);
65+
return () => {
66+
document.removeEventListener("mousedown", handleClickOutside);
67+
};
68+
}, [setShowDetail]);
4669

4770
return (
4871
<div className={styles.container}>
@@ -53,7 +76,9 @@ const BookmarksPage = () => {
5376
className={styles.backBtn}
5477
color="ABABAB"
5578
size={18}
56-
onClick={() => (window.history.length > 1 ? navigate(-1) : navigate("/my"))}
79+
onClick={() =>
80+
window.history.length > 1 ? navigate(-1) : navigate("/my")
81+
}
5782
/>
5883
<div className={styles.row}>
5984
<span>내 찜 목록</span>
@@ -72,7 +97,14 @@ const BookmarksPage = () => {
7297
)}
7398
</div>
7499
{showDetail && clickedEventId !== undefined && (
75-
<div className={styles.sidePanel}>
100+
<div
101+
className={styles.sidePanel}
102+
ref={sidePanelRef}
103+
style={sidePanelStyle}
104+
>
105+
{!isMobile && (
106+
<SidePanelResizeHandle onMouseDown={handleResizeStart} />
107+
)}
76108
<DetailView eventId={clickedEventId} />
77109
</div>
78110
)}

src/pages/memo/Memo.tsx

Lines changed: 53 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,16 @@ import { FaChevronLeft, FaChevronRight } from "react-icons/fa6";
77
import Navigationbar from "@/widgets/Navigationbar";
88
import { useNavigate } from "react-router-dom";
99
import MemoPageCard from "./MemoPageCard";
10-
import { useState } from "react";
10+
import { useEffect, useRef, useState } from "react";
1111
import Modal from "@/widgets/Modal";
1212
import Loading from "@/widgets/Loading";
1313
import BottomNav from "@/widgets/BottomNav";
14+
import { useDetail } from "@/contexts/DetailContext";
15+
import DetailView from "@/widgets/DetailView";
16+
import {
17+
SidePanelResizeHandle,
18+
useResizableSidePanel,
19+
} from "@/widgets/SidePanelResize";
1420

1521
const MemoWidgetCard = ({ memo }: { memo: Memo }) => {
1622
return (
@@ -67,23 +73,44 @@ const MemoPage = () => {
6773
const [deletingMemoId, setDeletingMemoId] = useState<number | null>(null);
6874
const { user } = useAuth();
6975
const navigate = useNavigate();
76+
const { showDetail, setShowDetail, clickedEventId } = useDetail();
77+
const { isMobile, handleResizeStart, sidePanelStyle } =
78+
useResizableSidePanel();
79+
80+
const sidePanelRef = useRef<HTMLDivElement>(null);
81+
82+
useEffect(() => {
83+
function handleClickOutside(event: MouseEvent) {
84+
if (!sidePanelRef.current) return;
85+
const isInside = sidePanelRef.current.contains(event.target as Node);
86+
if (!isInside) {
87+
setShowDetail(false);
88+
}
89+
}
90+
document.addEventListener("mousedown", handleClickOutside);
91+
return () => {
92+
document.removeEventListener("mousedown", handleClickOutside);
93+
};
94+
}, [setShowDetail]);
7095

7196
const handleDelete = async () => {
7297
if (deletingMemoId) await deleteMemo(deletingMemoId);
7398
setDeletingMemoId(null);
7499
};
75100
if (memoLoading) return <Loading />;
76101
if (!user) {
77-
return (<div className={styles.notFound}>
78-
<Navigationbar />
79-
<Modal
80-
content={"메모 이용을 위해서는\n로그인이 필요해요."}
81-
leftText="로그인 ·회원가입 페이지로 이동"
82-
onLeftClick={() => navigate("/")}
83-
onClose={null}
84-
/>
85-
<BottomNav />
86-
</div>);
102+
return (
103+
<div className={styles.notFound}>
104+
<Navigationbar />
105+
<Modal
106+
content={"메모 이용을 위해서는\n로그인이 필요해요."}
107+
leftText="로그인 ·회원가입 페이지로 이동"
108+
onLeftClick={() => navigate("/")}
109+
onClose={null}
110+
/>
111+
<BottomNav />
112+
</div>
113+
);
87114
}
88115

89116
return (
@@ -95,8 +122,9 @@ const MemoPage = () => {
95122
className={styles.backBtn}
96123
color="ABABAB"
97124
size={18}
98-
onClick={() => (window.history.length > 1 ? navigate(-1) : navigate("/my"))}
99-
125+
onClick={() =>
126+
window.history.length > 1 ? navigate(-1) : navigate("/my")
127+
}
100128
/>
101129
<div className={styles.row}>
102130
<span>내 메모 목록</span>
@@ -124,6 +152,18 @@ const MemoPage = () => {
124152
onClose={() => setDeletingMemoId(null)}
125153
/>
126154
)}
155+
{showDetail && clickedEventId !== undefined && (
156+
<div
157+
className={styles.sidePanel}
158+
ref={sidePanelRef}
159+
style={sidePanelStyle}
160+
>
161+
{!isMobile && (
162+
<SidePanelResizeHandle onMouseDown={handleResizeStart} />
163+
)}
164+
<DetailView eventId={clickedEventId} />
165+
</div>
166+
)}
127167
<BottomNav />
128168
</div>
129169
);

0 commit comments

Comments
 (0)