Skip to content

Commit fd3d303

Browse files
authored
Merge pull request #72 from wafflestudio/haram
시간표 토글 버튼 라벨 추가, 레이아웃 수정, 로딩 화면 개선
2 parents 17b5afb + 395d203 commit fd3d303

5 files changed

Lines changed: 106 additions & 43 deletions

File tree

src/pages/timetable/TimeTableToolbar.tsx

Lines changed: 54 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ interface TimeTableToolbarProps {
1313
onSemesterChange: (semester: Semester) => void;
1414
isToggleOn: boolean;
1515
onToggleChange: (isToggleOn: boolean) => void;
16+
isLoading?: boolean;
1617
years?: number[];
1718
}
1819

@@ -25,6 +26,7 @@ const TimeTableToolbar = ({
2526
onSemesterChange,
2627
isToggleOn,
2728
onToggleChange,
29+
isLoading = false,
2830
years,
2931
}: TimeTableToolbarProps) => {
3032
const { user } = useAuth();
@@ -36,47 +38,60 @@ const TimeTableToolbar = ({
3638
<div className={styles.timetableToolbarContainer}>
3739
<div className={styles.headerRow}>
3840
<div className={styles.selectGroup}>
39-
<span className={styles.selectWrap}>
40-
<select
41-
className={styles.select}
42-
value={year}
43-
onChange={(e) => onYearChange(Number(e.target.value))}
44-
aria-label="년도 선택"
45-
>
46-
{yearOptions.map((y) => (
47-
<option key={y} value={y}>
48-
{y}학년도
49-
</option>
50-
))}
51-
</select>
52-
</span>
41+
<div className={styles.semesterSelectGroup}>
42+
<span className={styles.selectWrap}>
43+
<select
44+
className={styles.select}
45+
value={year}
46+
disabled={isLoading}
47+
onChange={(e) => {
48+
onYearChange(Number(e.target.value));
49+
e.currentTarget.blur();
50+
}}
51+
aria-label="년도 선택"
52+
>
53+
{yearOptions.map((y) => (
54+
<option key={y} value={y}>
55+
{y}학년도
56+
</option>
57+
))}
58+
</select>
59+
</span>
5360

54-
<span className={styles.selectWrap}>
55-
<select
56-
className={styles.select}
57-
value={semester}
58-
onChange={(e) => onSemesterChange(e.target.value as Semester)}
59-
aria-label="학기 선택"
60-
>
61-
{SEMESTER_LABEL.map((s) => (
62-
<option key={s.id} value={s.id}>
63-
{s.label}
64-
</option>
65-
))}
66-
</select>
67-
</span>
61+
<span className={styles.selectWrap}>
62+
<select
63+
className={styles.select}
64+
value={semester}
65+
disabled={isLoading}
66+
onChange={(e) => {
67+
onSemesterChange(e.target.value as Semester);
68+
e.currentTarget.blur();
69+
}}
70+
aria-label="학기 선택"
71+
>
72+
{SEMESTER_LABEL.map((s) => (
73+
<option key={s.id} value={s.id}>
74+
{s.label}
75+
</option>
76+
))}
77+
</select>
78+
</span>
79+
</div>
6880
<p className={styles.dateTitle}>{timetableName}</p>
69-
<button
70-
type="button"
71-
className={`${styles.timetableToggle} ${
72-
isToggleOn ? styles.timetableToggleOn : ""
73-
}`}
74-
aria-label="시간표 토글"
75-
aria-pressed={isToggleOn}
76-
onClick={() => onToggleChange(!isToggleOn)}
77-
>
78-
<span className={styles.timetableToggleThumb} />
79-
</button>
81+
<div className={styles.timetableToggleGroup}>
82+
<span className={styles.timetableToggleLabel}>행사 함께 보기</span>
83+
<button
84+
type="button"
85+
className={`${styles.timetableToggle} ${
86+
isToggleOn ? styles.timetableToggleOn : ""
87+
}`}
88+
aria-label="행사 함께 보기"
89+
aria-pressed={isToggleOn}
90+
onClick={() => onToggleChange(!isToggleOn)}
91+
>
92+
<span className={styles.timetableToggleThumb} />
93+
</button>
94+
</div>
8095
</div>
8196

8297
<div className={styles.profileRow}>

src/pages/timetable/TimetableGrid.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ export type TimetableProps = {
3333
onAddBlock?: (id: number, item: Course) => void;
3434
onRemoveBlock?: (timetableId: number, enrollId: number) => Promise<void>;
3535
isSimplified?: boolean;
36+
isLoading?: boolean;
3637
weekEvents?: CalendarEvent[];
3738
onSelectEvent?: (event: Event) => void;
3839
dayLabels?: Record<Day, string>;
@@ -47,6 +48,7 @@ export function TimetableGrid({
4748
toBlocks,
4849
onRemoveBlock,
4950
isSimplified = false,
51+
isLoading = false,
5052
weekEvents = [],
5153
onSelectEvent,
5254
dayLabels = DAY_LABELS_KO,
@@ -118,7 +120,9 @@ export function TimetableGrid({
118120
}, [weekEvents, config]);
119121

120122
return (
121-
<div className={styles.gridWrap}>
123+
<div
124+
className={`${styles.gridWrap} ${isLoading ? styles.gridWrapLoading : ""}`}
125+
>
122126
<div className={styles.headerRow}>
123127
<div className={styles.timeGutterHeader} />
124128
{Days.map((d) => (

src/pages/timetable/TimetablePage.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -158,8 +158,6 @@ export default function TimetablePage() {
158158
);
159159
}, [weekViewData]);
160160

161-
if (isLoading) return <div>로딩 중...</div>;
162-
163161
return (
164162
<div
165163
className={`${styles.page} ${
@@ -194,6 +192,7 @@ export default function TimetablePage() {
194192
onYearChange={setYear}
195193
isToggleOn={isTimetableSimplified}
196194
onToggleChange={setIsTimetableSimplified}
195+
isLoading={isLoading}
197196
years={years}
198197
/>
199198

@@ -214,6 +213,7 @@ export default function TimetablePage() {
214213
toBlocks={flattenCoursesToBlocks}
215214
onRemoveBlock={deleteCourse}
216215
isSimplified={isTimetableSimplified}
216+
isLoading={isLoading}
217217
weekEvents={isTimetableSimplified ? weekCalendarEvents : []}
218218
/>
219219
)}

src/styles/Timetable.module.css

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,12 @@
232232

233233
.gridWrap {
234234
min-width: 860px;
235+
transition: opacity 0.18s ease;
236+
}
237+
238+
.gridWrapLoading {
239+
opacity: 0.48;
240+
pointer-events: none;
235241
}
236242

237243
.headerRow {

src/styles/Toolbar.module.css

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -224,10 +224,33 @@
224224
.selectGroup {
225225
display: flex;
226226
align-items: center;
227-
gap: 14px;
227+
gap: 25px;
228228
min-width: 0;
229229
}
230230

231+
.semesterSelectGroup {
232+
display: inline-flex;
233+
align-items: center;
234+
gap: 8px;
235+
flex: 0 0 auto;
236+
}
237+
238+
.timetableToggleGroup {
239+
display: inline-flex;
240+
flex-direction: column;
241+
align-items: flex-start;
242+
gap: 4px;
243+
flex: 0 0 auto;
244+
}
245+
246+
.timetableToggleLabel {
247+
font-size: 12px;
248+
font-weight: 500;
249+
line-height: 1;
250+
color: #6b7280;
251+
white-space: nowrap;
252+
}
253+
231254
.timetableToggle {
232255
position: relative;
233256
flex: 0 0 auto;
@@ -288,6 +311,12 @@
288311
background: #fafafa;
289312
}
290313

314+
.select:disabled {
315+
color: #8a8a8a;
316+
cursor: wait;
317+
background: #f7f7f7;
318+
}
319+
291320
.select:focus {
292321
border-color: #d0d0d0;
293322
box-shadow: 0 0 0 4px rgba(0, 0, 0, 0.04);
@@ -322,6 +351,9 @@
322351
flex: 1;
323352
gap: 8px;
324353
}
354+
.timetableToolbarContainer .semesterSelectGroup {
355+
display: none;
356+
}
325357
.timetableToolbarContainer .selectWrap {
326358
display: none;
327359
}
@@ -335,6 +367,12 @@
335367
text-overflow: ellipsis;
336368
white-space: nowrap;
337369
}
370+
.timetableToolbarContainer .timetableToggleGroup {
371+
align-items: flex-start;
372+
}
373+
.timetableToolbarContainer .timetableToggleLabel {
374+
display: none;
375+
}
338376
.timetableToolbarContainer .timetableToggle {
339377
width: 38px;
340378
height: 22px;

0 commit comments

Comments
 (0)