@edu-tosel/design 1.0.303 → 1.0.304
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/globals.css +65 -5
- package/hook/useScrollbarVisibility.d.ts +1 -0
- package/hook/useScrollbarVisibility.js +66 -0
- package/layout/template/home/Float.js +3 -1
- package/layout/template/home/NewsPaper.js +43 -8
- package/layout/template/home/Service.js +43 -8
- package/layout/template/home/layout/Carousel.js +6 -6
- package/layout/template/home/layout/Header.js +9 -3
- package/layout/template/home/layout/Navigation.js +65 -2
- package/package.json +1 -1
- package/version.txt +1 -1
package/globals.css
CHANGED
|
@@ -2,6 +2,29 @@
|
|
|
2
2
|
@tailwind components;
|
|
3
3
|
@tailwind utilities;
|
|
4
4
|
|
|
5
|
+
/* 기본 HTML 리셋 및 스크롤 제어 */
|
|
6
|
+
html {
|
|
7
|
+
scroll-behavior: auto; /* smooth scroll 비활성화 */
|
|
8
|
+
-webkit-overflow-scrolling: auto; /* iOS momentum scrolling 비활성화 */
|
|
9
|
+
overflow-x: hidden;
|
|
10
|
+
scrollbar-width: thin;
|
|
11
|
+
scrollbar-color: rgba(128, 128, 128, 0.5) transparent;
|
|
12
|
+
-ms-overflow-style: none; /* IE and Edge */
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
body {
|
|
16
|
+
margin: 0;
|
|
17
|
+
padding: 0;
|
|
18
|
+
overflow-x: hidden;
|
|
19
|
+
-webkit-overflow-scrolling: auto; /* iOS momentum scrolling 비활성화 */
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
#root {
|
|
23
|
+
min-height: 100vh;
|
|
24
|
+
width: 100%;
|
|
25
|
+
overflow-x: hidden;
|
|
26
|
+
}
|
|
27
|
+
|
|
5
28
|
.image-container {
|
|
6
29
|
display: -webkit-box;
|
|
7
30
|
display: -ms-flexbox;
|
|
@@ -59,18 +82,44 @@ input[type="date"]::-webkit-calendar-picker-indicator {
|
|
|
59
82
|
-webkit-appearance: none;
|
|
60
83
|
}
|
|
61
84
|
|
|
85
|
+
/* 스크롤바 스타일링 - 스크롤 시에만 표시 */
|
|
62
86
|
::-webkit-scrollbar {
|
|
63
|
-
width:
|
|
64
|
-
|
|
87
|
+
width: 8px;
|
|
88
|
+
opacity: 0;
|
|
89
|
+
transition: opacity 0.3s ease;
|
|
65
90
|
}
|
|
66
91
|
|
|
67
92
|
::-webkit-scrollbar-track {
|
|
68
|
-
background
|
|
93
|
+
background: transparent;
|
|
69
94
|
}
|
|
95
|
+
|
|
70
96
|
::-webkit-scrollbar-thumb {
|
|
71
|
-
background-color:
|
|
72
|
-
opacity: 0.5;
|
|
97
|
+
background-color: rgba(128, 128, 128, 0.5);
|
|
73
98
|
border-radius: 10px;
|
|
99
|
+
border: 2px solid transparent;
|
|
100
|
+
background-clip: content-box;
|
|
101
|
+
transition: background-color 0.2s ease;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
::-webkit-scrollbar-thumb:hover {
|
|
105
|
+
background-color: rgba(128, 128, 128, 0.8);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/* 스크롤 중일 때 스크롤바 표시 */
|
|
109
|
+
.scrolling::-webkit-scrollbar {
|
|
110
|
+
opacity: 1;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/* body와 html에도 스크롤바 스타일 적용 */
|
|
114
|
+
body.scrolling::-webkit-scrollbar,
|
|
115
|
+
html.scrolling::-webkit-scrollbar {
|
|
116
|
+
opacity: 1;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/* Firefox용 스크롤바 (기본적으로 auto-hide) */
|
|
120
|
+
html {
|
|
121
|
+
scrollbar-width: thin;
|
|
122
|
+
scrollbar-color: rgba(128, 128, 128, 0.5) transparent;
|
|
74
123
|
}
|
|
75
124
|
|
|
76
125
|
.box-shadow {
|
|
@@ -268,6 +317,7 @@ input[type="date"]::-webkit-calendar-picker-indicator {
|
|
|
268
317
|
|
|
269
318
|
/* related to font rendering in safari engine */
|
|
270
319
|
* {
|
|
320
|
+
box-sizing: border-box;
|
|
271
321
|
font-synthesis: none !important;
|
|
272
322
|
-webkit-font-smoothing: antialiased;
|
|
273
323
|
-moz-osx-font-smoothing: grayscale;
|
|
@@ -279,3 +329,13 @@ input[type="date"]::-webkit-calendar-picker-indicator {
|
|
|
279
329
|
-webkit-mask-composite: destination-in;
|
|
280
330
|
mask-composite: intersect;
|
|
281
331
|
}
|
|
332
|
+
|
|
333
|
+
/* Navigation이 열렸을 때 스크롤바 완전히 숨김 */
|
|
334
|
+
.navigation-open::-webkit-scrollbar {
|
|
335
|
+
display: none !important;
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
.navigation-open {
|
|
339
|
+
scrollbar-width: none !important;
|
|
340
|
+
-ms-overflow-style: none !important;
|
|
341
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export default function useScrollbarVisibility(): void;
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { useEffect } from "react";
|
|
2
|
+
export default function useScrollbarVisibility() {
|
|
3
|
+
useEffect(() => {
|
|
4
|
+
let scrollTimer = null;
|
|
5
|
+
const handleScroll = () => {
|
|
6
|
+
// Navigation이 열렸을 때는 스크롤바 제어 비활성화
|
|
7
|
+
if (document.body.classList.contains("navigation-open")) {
|
|
8
|
+
return;
|
|
9
|
+
}
|
|
10
|
+
// 스크롤 중일 때 클래스 추가
|
|
11
|
+
document.documentElement.classList.add("scrolling");
|
|
12
|
+
document.body.classList.add("scrolling");
|
|
13
|
+
// 기존 타이머 클리어
|
|
14
|
+
if (scrollTimer) {
|
|
15
|
+
clearTimeout(scrollTimer);
|
|
16
|
+
}
|
|
17
|
+
// 1.5초 후 스크롤바 숨김
|
|
18
|
+
scrollTimer = setTimeout(() => {
|
|
19
|
+
document.documentElement.classList.remove("scrolling");
|
|
20
|
+
document.body.classList.remove("scrolling");
|
|
21
|
+
}, 1500);
|
|
22
|
+
};
|
|
23
|
+
// 스크롤 이벤트 리스너 추가
|
|
24
|
+
window.addEventListener("scroll", handleScroll, { passive: true });
|
|
25
|
+
// 마우스가 스크롤바 영역에 있을 때 표시
|
|
26
|
+
const handleMouseMove = (event) => {
|
|
27
|
+
// Navigation이 열렸을 때는 스크롤바 제어 비활성화
|
|
28
|
+
if (document.body.classList.contains("navigation-open")) {
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
const isNearScrollbar = window.innerWidth - event.clientX < 20;
|
|
32
|
+
if (isNearScrollbar) {
|
|
33
|
+
document.documentElement.classList.add("scrolling");
|
|
34
|
+
document.body.classList.add("scrolling");
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
const handleMouseLeave = () => {
|
|
38
|
+
// Navigation이 열렸을 때는 스크롤바 제어 비활성화
|
|
39
|
+
if (document.body.classList.contains("navigation-open")) {
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
// 마우스가 창을 벗어나면 스크롤바 숨김
|
|
43
|
+
if (scrollTimer) {
|
|
44
|
+
clearTimeout(scrollTimer);
|
|
45
|
+
}
|
|
46
|
+
scrollTimer = setTimeout(() => {
|
|
47
|
+
document.documentElement.classList.remove("scrolling");
|
|
48
|
+
document.body.classList.remove("scrolling");
|
|
49
|
+
}, 500);
|
|
50
|
+
};
|
|
51
|
+
window.addEventListener("mousemove", handleMouseMove, { passive: true });
|
|
52
|
+
window.addEventListener("mouseleave", handleMouseLeave);
|
|
53
|
+
// 클린업 함수
|
|
54
|
+
return () => {
|
|
55
|
+
if (scrollTimer) {
|
|
56
|
+
clearTimeout(scrollTimer);
|
|
57
|
+
}
|
|
58
|
+
window.removeEventListener("scroll", handleScroll);
|
|
59
|
+
window.removeEventListener("mousemove", handleMouseMove);
|
|
60
|
+
window.removeEventListener("mouseleave", handleMouseLeave);
|
|
61
|
+
// 클래스 제거
|
|
62
|
+
document.documentElement.classList.remove("scrolling");
|
|
63
|
+
document.body.classList.remove("scrolling");
|
|
64
|
+
};
|
|
65
|
+
}, []);
|
|
66
|
+
}
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useState } from "react";
|
|
2
3
|
import { cn } from "../../../util";
|
|
3
4
|
export default function Float({ contents }) {
|
|
5
|
+
const [hoveredButton, setHoveredButton] = useState(null);
|
|
4
6
|
const container = cn("fixed flex flex-col bottom-20 md:bottom-16 right-5 md:right-16 z-40 overflow-visible", "gap-5");
|
|
5
7
|
const buttonBox = (background) => cn("flex justify-center items-center", "p-1.5 md:p-3", "w-12 h-12 md:w-16 md:h-16", "rounded-full overflow-hidden shadow-main hover:scale-110 duration-300 hover:shadow-icon-hover", background ?? "bg-white");
|
|
6
|
-
return (_jsx("div", { className: container, children: contents.map(({ image, onClick, background, hoverContent }) => (_jsxs("div", { className: "relative
|
|
8
|
+
return (_jsx("div", { className: container, children: contents.map(({ image, onClick, background, hoverContent }, index) => (_jsxs("div", { className: "relative flex items-center", children: [hoverContent && (_jsx("div", { className: cn("absolute right-full mr-3 pointer-events-none", "bg-gray-dark text-white text-sm px-5 py-2 rounded shadow-md whitespace-nowrap", "transition-opacity duration-200", hoveredButton === index ? "opacity-100" : "opacity-0"), children: hoverContent })), _jsx("button", { onClick: onClick, className: buttonBox(background), onMouseEnter: () => setHoveredButton(index), onMouseLeave: () => setHoveredButton(null), children: _jsx("img", { src: image, alt: "image", className: "object-contain" }) })] }, image))) }));
|
|
7
9
|
}
|
|
@@ -1,11 +1,41 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { cn } from "../../../util";
|
|
3
|
-
import { useRef } from "react";
|
|
3
|
+
import { useRef, useState, useEffect } from "react";
|
|
4
4
|
import { Label } from "../../../widget";
|
|
5
5
|
export default function NewsPaper({ banners, browse, option, }) {
|
|
6
6
|
const { className } = option ?? {};
|
|
7
7
|
const scrollContainerRef = useRef(null);
|
|
8
8
|
const cardWidth = 480; //card width
|
|
9
|
+
// 스크롤 위치 상태 관리
|
|
10
|
+
const [canScrollLeft, setCanScrollLeft] = useState(false);
|
|
11
|
+
const [canScrollRight, setCanScrollRight] = useState(true);
|
|
12
|
+
// 스크롤 위치 확인 함수
|
|
13
|
+
const checkScrollPosition = () => {
|
|
14
|
+
if (scrollContainerRef.current) {
|
|
15
|
+
const { scrollLeft, scrollWidth, clientWidth } = scrollContainerRef.current;
|
|
16
|
+
// 왼쪽 끝 확인 (약간의 여유값 포함)
|
|
17
|
+
setCanScrollLeft(scrollLeft > 5);
|
|
18
|
+
// 오른쪽 끝 확인 (약간의 여유값 포함)
|
|
19
|
+
setCanScrollRight(scrollLeft < scrollWidth - clientWidth - 5);
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
// 초기 로드시와 banners 변경시 스크롤 위치 확인
|
|
23
|
+
useEffect(() => {
|
|
24
|
+
const timer = setTimeout(() => {
|
|
25
|
+
checkScrollPosition();
|
|
26
|
+
}, 100); // DOM 렌더링 후 확인
|
|
27
|
+
return () => clearTimeout(timer);
|
|
28
|
+
}, [banners]);
|
|
29
|
+
// 스크롤 이벤트 리스너 등록
|
|
30
|
+
useEffect(() => {
|
|
31
|
+
const scrollContainer = scrollContainerRef.current;
|
|
32
|
+
if (scrollContainer) {
|
|
33
|
+
scrollContainer.addEventListener("scroll", checkScrollPosition);
|
|
34
|
+
return () => {
|
|
35
|
+
scrollContainer.removeEventListener("scroll", checkScrollPosition);
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
}, []);
|
|
9
39
|
const handleScroll = (direction) => {
|
|
10
40
|
if (scrollContainerRef.current) {
|
|
11
41
|
const scrollAmount = cardWidth;
|
|
@@ -49,23 +79,28 @@ export default function NewsPaper({ banners, browse, option, }) {
|
|
|
49
79
|
spacings: "gap-5 xl:mr-[calc(100vw-1200px)]",
|
|
50
80
|
};
|
|
51
81
|
const buttonPositioning = {
|
|
52
|
-
displays: "
|
|
82
|
+
displays: "flex flex-row",
|
|
53
83
|
sizes: "w-full h-full",
|
|
54
|
-
spacings: "xl:
|
|
55
|
-
positions: "
|
|
84
|
+
spacings: "xl:pr-[calc(50vw-600px)] md:pr-[62px] pl-2 pr-4 gap-5",
|
|
85
|
+
positions: "justify-end items-center duration-300",
|
|
56
86
|
hovering: "group pointer-events-none",
|
|
57
87
|
};
|
|
58
88
|
const hoverButton = {
|
|
59
|
-
sizes: "rounded-full w-
|
|
60
|
-
animation: "duration-300
|
|
61
|
-
test: "bg-gray-medium/
|
|
89
|
+
sizes: "rounded-full w-9 h-9",
|
|
90
|
+
animation: "duration-300",
|
|
91
|
+
test: "bg-gray-medium/50 hover:bg-gray-medium pointer-events-auto backdrop-blur-sm",
|
|
92
|
+
};
|
|
93
|
+
const disabledButton = {
|
|
94
|
+
sizes: "rounded-full w-9 h-9",
|
|
95
|
+
animation: "duration-300",
|
|
96
|
+
test: "bg-gray-medium/20 pointer-events-none backdrop-blur-sm opacity-30",
|
|
62
97
|
};
|
|
63
98
|
return (_jsxs("div", { className: cn(container), children: [_jsx("div", { className: cn(deckTitlePositioning), children: _jsxs("div", { className: cn(deckTitle), children: [_jsx("div", { children: "\uC0C8\uB85C\uC6B4 \uC18C\uC2DD" }), _jsx(Label.Button, { title: "\uB354 \uBCF4\uAE30", onClick: browse, option: {
|
|
64
99
|
width: "xs",
|
|
65
100
|
height: "xs",
|
|
66
101
|
text: "text-white hover:text-green-dark font-bold",
|
|
67
102
|
background: "bg-green-dark hover:bg-green-light",
|
|
68
|
-
} })] }) }), _jsx("div", { className: cn(cardPositioning), children: _jsx("div", { className: cn(cardWrapper), ref: scrollContainerRef, children: _jsx("div", { className: cn(cardDeck), children: banners.map((banner) => (_jsx(Banner, { ...banner }, banner.image.src))) }) }) }), _jsxs("div", { className: cn(buttonPositioning), children: [_jsx("div", { className: cn(hoverButton), onClick: () => handleScroll("left"), children: _jsx("img", { src: "images/home/handle-left.svg", alt: "" }) }), _jsx("div", { className: cn(hoverButton), onClick: () => handleScroll("right"), children: _jsx("img", { src: "images/home/handle-right.svg", alt: "" }) })] })] }));
|
|
103
|
+
} })] }) }), _jsx("div", { className: cn(cardPositioning), children: _jsx("div", { className: cn(cardWrapper), ref: scrollContainerRef, children: _jsx("div", { className: cn(cardDeck), children: banners.map((banner) => (_jsx(Banner, { ...banner }, banner.image.src))) }) }) }), _jsxs("div", { className: cn(buttonPositioning), children: [_jsx("div", { className: cn(canScrollLeft ? hoverButton : disabledButton), onClick: canScrollLeft ? () => handleScroll("left") : undefined, children: _jsx("img", { src: "images/home/handle-left.svg", alt: "" }) }), _jsx("div", { className: cn(canScrollRight ? hoverButton : disabledButton), onClick: canScrollRight ? () => handleScroll("right") : undefined, children: _jsx("img", { src: "images/home/handle-right.svg", alt: "" }) })] })] }));
|
|
69
104
|
}
|
|
70
105
|
function Banner({ onClick, image, option }) {
|
|
71
106
|
const { background } = option ?? {};
|
|
@@ -1,9 +1,39 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { useRef } from "react";
|
|
2
|
+
import { useRef, useState, useEffect } from "react";
|
|
3
3
|
import { cn } from "../../../util";
|
|
4
4
|
export default function Service({ banners }) {
|
|
5
5
|
const scrollContainerRef = useRef(null);
|
|
6
6
|
const cardWidth = 400; // card width
|
|
7
|
+
// 스크롤 위치 상태 관리
|
|
8
|
+
const [canScrollLeft, setCanScrollLeft] = useState(false);
|
|
9
|
+
const [canScrollRight, setCanScrollRight] = useState(true);
|
|
10
|
+
// 스크롤 위치 확인 함수
|
|
11
|
+
const checkScrollPosition = () => {
|
|
12
|
+
if (scrollContainerRef.current) {
|
|
13
|
+
const { scrollLeft, scrollWidth, clientWidth } = scrollContainerRef.current;
|
|
14
|
+
// 왼쪽 끝 확인 (약간의 여유값 포함)
|
|
15
|
+
setCanScrollLeft(scrollLeft > 5);
|
|
16
|
+
// 오른쪽 끝 확인 (약간의 여유값 포함)
|
|
17
|
+
setCanScrollRight(scrollLeft < scrollWidth - clientWidth - 5);
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
// 초기 로드시와 banners 변경시 스크롤 위치 확인
|
|
21
|
+
useEffect(() => {
|
|
22
|
+
const timer = setTimeout(() => {
|
|
23
|
+
checkScrollPosition();
|
|
24
|
+
}, 100); // DOM 렌더링 후 확인
|
|
25
|
+
return () => clearTimeout(timer);
|
|
26
|
+
}, [banners]);
|
|
27
|
+
// 스크롤 이벤트 리스너 등록
|
|
28
|
+
useEffect(() => {
|
|
29
|
+
const scrollContainer = scrollContainerRef.current;
|
|
30
|
+
if (scrollContainer) {
|
|
31
|
+
scrollContainer.addEventListener("scroll", checkScrollPosition);
|
|
32
|
+
return () => {
|
|
33
|
+
scrollContainer.removeEventListener("scroll", checkScrollPosition);
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
}, []);
|
|
7
37
|
const handleScroll = (direction) => {
|
|
8
38
|
if (scrollContainerRef.current) {
|
|
9
39
|
const scrollAmount = cardWidth;
|
|
@@ -48,18 +78,23 @@ export default function Service({ banners }) {
|
|
|
48
78
|
spacings: "gap-5 xl:mr-[calc(100vw-1200px)]",
|
|
49
79
|
};
|
|
50
80
|
const buttonPositioning = {
|
|
51
|
-
displays: "
|
|
81
|
+
displays: "flex flex-row",
|
|
52
82
|
sizes: "w-full h-full",
|
|
53
|
-
spacings: "xl:
|
|
54
|
-
positions: "
|
|
83
|
+
spacings: "xl:pr-[calc(50vw-600px)] md:pr-[62px] pl-2 pr-4 gap-5",
|
|
84
|
+
positions: "justify-end items-center duration-300",
|
|
55
85
|
hovering: "group pointer-events-none",
|
|
56
86
|
};
|
|
57
87
|
const hoverButton = {
|
|
58
|
-
sizes: "rounded-full w-
|
|
59
|
-
animation: "duration-300
|
|
60
|
-
test: "bg-gray-medium/
|
|
88
|
+
sizes: "rounded-full w-9 h-9",
|
|
89
|
+
animation: "duration-300",
|
|
90
|
+
test: "bg-gray-medium/50 hover:bg-gray-medium pointer-events-auto backdrop-blur-sm",
|
|
91
|
+
};
|
|
92
|
+
const disabledButton = {
|
|
93
|
+
sizes: "rounded-full w-9 h-9",
|
|
94
|
+
animation: "duration-300",
|
|
95
|
+
test: "bg-gray-medium/20 pointer-events-none backdrop-blur-sm opacity-30",
|
|
61
96
|
};
|
|
62
|
-
return (_jsxs("div", { className: cn(container), children: [_jsx("div", { className: cn(deckTitlePositioning), children: _jsx("div", { className: cn(deckTitle), children: "\uD1A0\uC140\uC758 \uCC28\uBCC4\uD654\uB41C \uC11C\uBE44\uC2A4" }) }), _jsx("div", { className: cn(cardPositioning), children: _jsx("div", { className: cn(cardWrapper), ref: scrollContainerRef, children: _jsx("div", { className: cn(cardDeck), children: banners.map((banner) => (_jsx(Banner, { ...banner }, banner.titles.title))) }) }) }), _jsxs("div", { className: cn(buttonPositioning), children: [_jsx("div", { className: cn(hoverButton), onClick: () => handleScroll("left"), children: _jsx("img", { src: "images/home/handle-left.svg", alt: "" }) }), _jsx("div", { className: cn(hoverButton), onClick: () => handleScroll("right"), children: _jsx("img", { src: "images/home/handle-right.svg", alt: "" }) })] })] }));
|
|
97
|
+
return (_jsxs("div", { className: cn(container), children: [_jsx("div", { className: cn(deckTitlePositioning), children: _jsx("div", { className: cn(deckTitle), children: "\uD1A0\uC140\uC758 \uCC28\uBCC4\uD654\uB41C \uC11C\uBE44\uC2A4" }) }), _jsx("div", { className: cn(cardPositioning), children: _jsx("div", { className: cn(cardWrapper), ref: scrollContainerRef, children: _jsx("div", { className: cn(cardDeck), children: banners.map((banner) => (_jsx(Banner, { ...banner }, banner.titles.title))) }) }) }), _jsxs("div", { className: cn(buttonPositioning), children: [_jsx("div", { className: cn(canScrollLeft ? hoverButton : disabledButton), onClick: canScrollLeft ? () => handleScroll("left") : undefined, children: _jsx("img", { src: "images/home/handle-left.svg", alt: "" }) }), _jsx("div", { className: cn(canScrollRight ? hoverButton : disabledButton), onClick: canScrollRight ? () => handleScroll("right") : undefined, children: _jsx("img", { src: "images/home/handle-right.svg", alt: "" }) })] })] }));
|
|
63
98
|
}
|
|
64
99
|
function Banner({ titles, onClick, image, option }) {
|
|
65
100
|
const { background } = option ?? {};
|
|
@@ -64,9 +64,9 @@ export default function Carousel({ contents, option, }) {
|
|
|
64
64
|
animations: "duration-300",
|
|
65
65
|
};
|
|
66
66
|
const titleWrapper = {
|
|
67
|
-
displays: "flex flex-col xxs:flex-row xxs:items-center md:items-start md:flex-col",
|
|
68
|
-
sizes: "w-full h-fit xxs:w-fit md:w-72",
|
|
69
|
-
spacings: "mt-4 px-5 xxs:mt-8 xxs:gap-8 md:p-0 md:mt-0 md:gap-6 md:pl-7.5",
|
|
67
|
+
displays: "static md:relative flex flex-col xxs:flex-row xxs:items-center md:items-start md:flex-col",
|
|
68
|
+
sizes: "w-full h-fit xxs:h-full xxs:w-fit md:w-72",
|
|
69
|
+
spacings: "mt-4 px-5 xxs:mt-8 xxs:gap-8 md:p-0 md:mt-0 md:gap-6 md:pl-7.5 md:pt-20",
|
|
70
70
|
animations: "duration-500",
|
|
71
71
|
};
|
|
72
72
|
const titleSet = {
|
|
@@ -93,15 +93,15 @@ export default function Carousel({ contents, option, }) {
|
|
|
93
93
|
styles: "rounded-md",
|
|
94
94
|
};
|
|
95
95
|
const buttonBoxPosition = {
|
|
96
|
-
display: "absolute flex justify-center items-center md:
|
|
96
|
+
display: "absolute flex justify-center items-center md:justify-start",
|
|
97
97
|
sizes: "w-full h-fit left-0 bottom-0 z-10",
|
|
98
|
-
spacings: "ml-0 md:ml-
|
|
98
|
+
spacings: "ml-0 md:ml-[calc(70px)] xm:ml-7.5",
|
|
99
99
|
};
|
|
100
100
|
const buttonBox = {
|
|
101
101
|
displays: "relative justify-center items-center gap-1 flex z-10",
|
|
102
102
|
animations: "duration-500",
|
|
103
103
|
sizes: "w-34 h-10 md:h-6.25 md:w-26 bg-gray-dark rounded-full",
|
|
104
|
-
paddings: "px-1.5 mt-0 mb-5 md:
|
|
104
|
+
paddings: "px-1.5 mt-0 mb-5 md:mb-17 ",
|
|
105
105
|
};
|
|
106
106
|
const handlePosition = {
|
|
107
107
|
displays: "absolute flex justify-between items-center",
|
|
@@ -5,8 +5,10 @@ import { Label } from "../../../../widget";
|
|
|
5
5
|
import { useResponsive } from "../../../../hook";
|
|
6
6
|
export default function Header({ logo, rightButton, contents, }) {
|
|
7
7
|
const [isExpanded, setIsExpanded] = useState(false);
|
|
8
|
+
const [hasToggled, setHasToggled] = useState(false);
|
|
8
9
|
const toggleHeight = () => {
|
|
9
10
|
setIsExpanded(!isExpanded);
|
|
11
|
+
setHasToggled(true); // 한 번이라도 토글되었음을 표시
|
|
10
12
|
};
|
|
11
13
|
const handleClickOutside = (event) => {
|
|
12
14
|
const menuElement = document.getElementById("buttonArea");
|
|
@@ -34,7 +36,11 @@ export default function Header({ logo, rightButton, contents, }) {
|
|
|
34
36
|
sizes: "w-full",
|
|
35
37
|
styles: "bg-white box-shadow",
|
|
36
38
|
textstyles: "antialiased",
|
|
37
|
-
animation:
|
|
39
|
+
animation: hasToggled && !isMD
|
|
40
|
+
? isExpanded
|
|
41
|
+
? "animate-grow"
|
|
42
|
+
: "animate-shrink"
|
|
43
|
+
: "",
|
|
38
44
|
};
|
|
39
45
|
const body = {
|
|
40
46
|
displays: "flex md:flex-row flex-col md:items-center items-start justify-between",
|
|
@@ -53,7 +59,7 @@ export default function Header({ logo, rightButton, contents, }) {
|
|
|
53
59
|
animations: "duration-300",
|
|
54
60
|
sizes: "h-10 rounded-md w-fit flex-none",
|
|
55
61
|
spacings: "px-2.5",
|
|
56
|
-
scrollMargin: "translate-x-5 md:translate-x-0 "
|
|
62
|
+
scrollMargin: "translate-x-5 md:translate-x-0 ",
|
|
57
63
|
};
|
|
58
64
|
const leftWrapper = {
|
|
59
65
|
displays: "flex flex-row gap-6 items-center flex-none",
|
|
@@ -79,7 +85,7 @@ export default function Header({ logo, rightButton, contents, }) {
|
|
|
79
85
|
height: "xs",
|
|
80
86
|
background: gradient.bg.greenToRed,
|
|
81
87
|
text: "text-white",
|
|
82
|
-
} })), _jsx("button", { onClick: toggleHeight, className: cn(menuButton), children: _jsx("div", { className: "w-6 h-6", children: _jsxs("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", children: [!isExpanded && _jsx("path", { id: "menu", fill: "#B0B8C1", d: "M4.118 6.2h16a1.2 1.2 0 100-2.4h-16a1.2 1.2 0 100 2.4m16 4.6h-16a1.2 1.2 0 100 2.4h16a1.2 1.2 0 100-2.4m0 7h-16a1.2 1.2 0 100 2.4h16a1.2 1.2 0 100-2.4", "fill-rule": "evenodd" }), isExpanded && _jsx("path", { id: "close", fill: "#B0B8C1", "fill-rule": "evenodd", d: "M13.815 12l5.651-5.651a1.2 1.2 0 00-1.697-1.698l-5.651 5.652-5.652-5.652a1.201 1.201 0 00-1.697 1.698L10.421 12l-5.652 5.651a1.202 1.202 0 00.849 2.049c.307 0 .614-.117.848-.351l5.652-5.652 5.651 5.652a1.198 1.198 0 001.697 0 1.2 1.2 0 000-1.698L13.815 12z" })] }) }) })] })] }), _jsxs("div", { className: cn(rightWrapper), children: [_jsx("div", { className: cn(buttonBoxWrapper), children: contents.map((button, index) => (_jsx("button", { onClick: button.onClick, className: cn(buttonBox), children: button.title }, index))) }), _jsx("div", { className: "hidden md:block", children: rightButton && (_jsx(Label.Button, { title: rightButton.title, onClick: rightButton?.onClick, option: {
|
|
88
|
+
} })), _jsx("button", { onClick: toggleHeight, className: cn(menuButton), children: _jsx("div", { className: "w-6 h-6", children: _jsxs("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", children: [!isExpanded && (_jsx("path", { id: "menu", fill: "#B0B8C1", d: "M4.118 6.2h16a1.2 1.2 0 100-2.4h-16a1.2 1.2 0 100 2.4m16 4.6h-16a1.2 1.2 0 100 2.4h16a1.2 1.2 0 100-2.4m0 7h-16a1.2 1.2 0 100 2.4h16a1.2 1.2 0 100-2.4", "fill-rule": "evenodd" })), isExpanded && (_jsx("path", { id: "close", fill: "#B0B8C1", "fill-rule": "evenodd", d: "M13.815 12l5.651-5.651a1.2 1.2 0 00-1.697-1.698l-5.651 5.652-5.652-5.652a1.201 1.201 0 00-1.697 1.698L10.421 12l-5.652 5.651a1.202 1.202 0 00.849 2.049c.307 0 .614-.117.848-.351l5.652-5.652 5.651 5.652a1.198 1.198 0 001.697 0 1.2 1.2 0 000-1.698L13.815 12z" }))] }) }) })] })] }), _jsxs("div", { className: cn(rightWrapper), children: [_jsx("div", { className: cn(buttonBoxWrapper), children: contents.map((button, index) => (_jsx("button", { onClick: button.onClick, className: cn(buttonBox), children: button.title }, index))) }), _jsx("div", { className: "hidden md:block", children: rightButton && (_jsx(Label.Button, { title: rightButton.title, onClick: rightButton?.onClick, option: {
|
|
83
89
|
width: "2xs",
|
|
84
90
|
height: "xs",
|
|
85
91
|
background: gradient.bg.greenToRed,
|
|
@@ -25,18 +25,81 @@ export default function Navigation({ browser, calendar, notice, event, }) {
|
|
|
25
25
|
});
|
|
26
26
|
// Scroll Lock 처리
|
|
27
27
|
useEffect(() => {
|
|
28
|
-
const preventScroll = (e) =>
|
|
28
|
+
const preventScroll = (e) => {
|
|
29
|
+
// Navigation 내부 요소에서 발생한 이벤트는 허용
|
|
30
|
+
const target = e.target;
|
|
31
|
+
const navigationContainer = target?.closest("[data-navigation-content]");
|
|
32
|
+
if (navigationContainer) {
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
e.preventDefault();
|
|
36
|
+
};
|
|
37
|
+
const preventWheel = (e) => {
|
|
38
|
+
// Navigation 내부 요소에서 발생한 이벤트는 허용
|
|
39
|
+
const target = e.target;
|
|
40
|
+
const navigationContainer = target?.closest("[data-navigation-content]");
|
|
41
|
+
if (navigationContainer) {
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
e.preventDefault();
|
|
45
|
+
};
|
|
46
|
+
const preventKeyScroll = (e) => {
|
|
47
|
+
// Navigation 내부 요소에서 발생한 이벤트는 허용
|
|
48
|
+
const target = e.target;
|
|
49
|
+
const navigationContainer = target?.closest("[data-navigation-content]");
|
|
50
|
+
if (navigationContainer) {
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
// 스크롤 관련 키 차단
|
|
54
|
+
if ([
|
|
55
|
+
"ArrowUp",
|
|
56
|
+
"ArrowDown",
|
|
57
|
+
"PageUp",
|
|
58
|
+
"PageDown",
|
|
59
|
+
"Home",
|
|
60
|
+
"End",
|
|
61
|
+
" ",
|
|
62
|
+
].includes(e.key)) {
|
|
63
|
+
e.preventDefault();
|
|
64
|
+
}
|
|
65
|
+
};
|
|
29
66
|
if (isOpen) {
|
|
67
|
+
// 스크롤 완전 차단
|
|
30
68
|
document.body.style.overflow = "hidden";
|
|
69
|
+
document.documentElement.style.overflow = "hidden";
|
|
70
|
+
// 터치 스크롤 차단
|
|
31
71
|
document.addEventListener("touchmove", preventScroll, { passive: false });
|
|
72
|
+
// 마우스 휠 스크롤 차단
|
|
73
|
+
document.addEventListener("wheel", preventWheel, { passive: false });
|
|
74
|
+
// 키보드 스크롤 차단
|
|
75
|
+
document.addEventListener("keydown", preventKeyScroll, {
|
|
76
|
+
passive: false,
|
|
77
|
+
});
|
|
78
|
+
// 스크롤바 가시성 제어 비활성화
|
|
79
|
+
document.documentElement.classList.add("navigation-open");
|
|
80
|
+
document.body.classList.add("navigation-open");
|
|
32
81
|
}
|
|
33
82
|
else {
|
|
83
|
+
// 스크롤 복원
|
|
34
84
|
document.body.style.overflow = "";
|
|
85
|
+
document.documentElement.style.overflow = "";
|
|
86
|
+
// 이벤트 리스너 제거
|
|
35
87
|
document.removeEventListener("touchmove", preventScroll);
|
|
88
|
+
document.removeEventListener("wheel", preventWheel);
|
|
89
|
+
document.removeEventListener("keydown", preventKeyScroll);
|
|
90
|
+
// 스크롤바 가시성 제어 복원
|
|
91
|
+
document.documentElement.classList.remove("navigation-open");
|
|
92
|
+
document.body.classList.remove("navigation-open");
|
|
36
93
|
}
|
|
37
94
|
return () => {
|
|
95
|
+
// 클린업
|
|
38
96
|
document.body.style.overflow = "";
|
|
97
|
+
document.documentElement.style.overflow = "";
|
|
39
98
|
document.removeEventListener("touchmove", preventScroll);
|
|
99
|
+
document.removeEventListener("wheel", preventWheel);
|
|
100
|
+
document.removeEventListener("keydown", preventKeyScroll);
|
|
101
|
+
document.documentElement.classList.remove("navigation-open");
|
|
102
|
+
document.body.classList.remove("navigation-open");
|
|
40
103
|
};
|
|
41
104
|
}, [isOpen]);
|
|
42
105
|
useEffect(() => {
|
|
@@ -130,7 +193,7 @@ export default function Navigation({ browser, calendar, notice, event, }) {
|
|
|
130
193
|
textStyles: "text-lg font-bold text-green-dark",
|
|
131
194
|
};
|
|
132
195
|
return (_jsxs(_Fragment, { children: [overlayCoverTransition((styles, item) => item && (_jsx(animated.div, { style: styles, className: "bg-white h-screen fixed top-0 left-0 z-40 flex flex-col justify-center items-center overflow-hidden gap-y-14 ", children: _jsxs("div", { className: "flex flex-col justify-center items-center overflow-hidden gap-y-14 transition-none", children: [_jsx("img", { src: "/images/logos/tosel.png", alt: "tosel", width: 368.56, height: 80.07 }), _jsxs("div", { role: "status", children: [_jsxs("svg", { "aria-hidden": "true", className: "w-8 h-8 text-gray-200 animate-spin dark:text-gray-600 fill-green-dark", viewBox: "0 0 100 101", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: [_jsx("path", { d: "M100 50.5908C100 78.2051 77.6142 100.591 50 100.591C22.3858 100.591 0 78.2051 0 50.5908C0 22.9766 22.3858 0.59082 50 0.59082C77.6142 0.59082 100 22.9766 100 50.5908ZM9.08144 50.5908C9.08144 73.1895 27.4013 91.5094 50 91.5094C72.5987 91.5094 90.9186 73.1895 90.9186 50.5908C90.9186 27.9921 72.5987 9.67226 50 9.67226C27.4013 9.67226 9.08144 27.9921 9.08144 50.5908Z", fill: "currentColor" }), _jsx("path", { d: "M93.9676 39.0409C96.393 38.4038 97.8624 35.9116 97.0079 33.5539C95.2932 28.8227 92.871 24.3692 89.8167 20.348C85.8452 15.1192 80.8826 10.7238 75.2124 7.41289C69.5422 4.10194 63.2754 1.94025 56.7698 1.05124C51.7666 0.367541 46.6976 0.446843 41.7345 1.27873C39.2613 1.69328 37.813 4.19778 38.4501 6.62326C39.0873 9.04874 41.5694 10.4717 44.0505 10.1071C47.8511 9.54855 51.7191 9.52689 55.5402 10.0491C60.8642 10.7766 65.9928 12.5457 70.6331 15.2552C75.2735 17.9648 79.3347 21.5619 82.5849 25.841C84.9175 28.9121 86.7997 32.2913 88.1811 35.8758C89.083 38.2158 91.5421 39.6781 93.9676 39.0409Z", fill: "currentFill" })] }), _jsx("span", { className: "sr-only", children: "Loading..." })] }), _jsx("div", { children: "dashboard loading..." })] }) }))), overlayPopTransition((styles, item) => type &&
|
|
133
|
-
item && (_jsx(animated.div, { style: styles, className: cn(blurContainer), children: _jsxs("div", { className: cn(itemBody), onClick: (e) => e.stopPropagation(), children: [_jsxs("div", { className: cn(scrollTitleWrapper), children: [_jsx("div", { className: cn(scrollTitle), children: navigationTypeString[type] }), _jsx("div", { className: "" })] }), _jsx("div", { className: cn(itemsContainer), children: _jsx(NavigationItem, { type: type, calendar: calendar, notice: notice, event: event }) })] }) }))), _jsx("div", { className: "fixed bottom-0 md:top-1/2 md:-translate-y-1/2 flex justify-center items-center z-45", children: _jsxs("div", { onClick: (e) => e.stopPropagation(), className: cn(container), children: [_jsx("button", { className: cn(iconWrapper), onClick: () => handleOpen("calendar"), "data-tooltip": "\uC2DC\uD5D8\uC77C\uC815", onMouseEnter: handleMouseEnter, onMouseLeave: handleMouseLeave, onMouseMove: handleMouseMove, children: _jsx(SVG.Icon.Calendar, { size: isMobile ? "md" : "lg" }) }), _jsx("button", { className: cn(iconWrapper), onClick: () => handleOpen("notification"), "data-tooltip": "\uACF5\uC9C0\uC0AC\uD56D", onMouseEnter: handleMouseEnter, onMouseLeave: handleMouseLeave, onMouseMove: handleMouseMove, children: _jsx(SVG.Icon.Notification, { size: isMobile ? "md" : "lg" }) }), _jsx("button", { className: cn(iconWrapper), onClick: () => handleOpen("search"), "data-tooltip": "\uAC80\uC0C9\uD558\uAE30", onMouseEnter: handleMouseEnter, onMouseLeave: handleMouseLeave, onMouseMove: handleMouseMove, children: _jsx(SVG.Icon.Search, { size: isMobile ? "md" : "lg" }) }), _jsx("button", { className: cn(iconWrapper), onClick: () => handleOpen("browser"), "data-tooltip": "\uB300\uC2DC\uBCF4\uB4DC", onMouseEnter: handleMouseEnter, onMouseLeave: handleMouseLeave, onMouseMove: handleMouseMove, children: _jsx(SVG.Icon.Browser, { size: isMobile ? "md" : "lg" }) }), _jsx("button", { className: cn(iconWrapper), onClick: () => handleOpen("event"), "data-tooltip": "\uC0C8\uC18C\uC2DD", onMouseEnter: handleMouseEnter, onMouseLeave: handleMouseLeave, onMouseMove: handleMouseMove, children: _jsx(SVG.Icon.Newspaper, { size: isMobile ? "md" : "lg" }) }), tooltipText && (_jsx("div", { className: "absolute bg-gray-900 text-white text-sm px-3 py-1 rounded-lg transition-opacity duration-200 w-20 text-center", style: {
|
|
196
|
+
item && (_jsx(animated.div, { style: styles, className: cn(blurContainer), children: _jsxs("div", { className: cn(itemBody), onClick: (e) => e.stopPropagation(), "data-navigation-content": true, children: [_jsxs("div", { className: cn(scrollTitleWrapper), children: [_jsx("div", { className: cn(scrollTitle), children: navigationTypeString[type] }), _jsx("div", { className: "" })] }), _jsx("div", { className: cn(itemsContainer), children: _jsx(NavigationItem, { type: type, calendar: calendar, notice: notice, event: event }) })] }) }))), _jsx("div", { className: "fixed bottom-0 md:top-1/2 md:-translate-y-1/2 flex justify-center items-center z-45", children: _jsxs("div", { onClick: (e) => e.stopPropagation(), className: cn(container), children: [_jsx("button", { className: cn(iconWrapper), onClick: () => handleOpen("calendar"), "data-tooltip": "\uC2DC\uD5D8\uC77C\uC815", onMouseEnter: handleMouseEnter, onMouseLeave: handleMouseLeave, onMouseMove: handleMouseMove, children: _jsx(SVG.Icon.Calendar, { size: isMobile ? "md" : "lg" }) }), _jsx("button", { className: cn(iconWrapper), onClick: () => handleOpen("notification"), "data-tooltip": "\uACF5\uC9C0\uC0AC\uD56D", onMouseEnter: handleMouseEnter, onMouseLeave: handleMouseLeave, onMouseMove: handleMouseMove, children: _jsx(SVG.Icon.Notification, { size: isMobile ? "md" : "lg" }) }), _jsx("button", { className: cn(iconWrapper), onClick: () => handleOpen("search"), "data-tooltip": "\uAC80\uC0C9\uD558\uAE30", onMouseEnter: handleMouseEnter, onMouseLeave: handleMouseLeave, onMouseMove: handleMouseMove, children: _jsx(SVG.Icon.Search, { size: isMobile ? "md" : "lg" }) }), _jsx("button", { className: cn(iconWrapper), onClick: () => handleOpen("browser"), "data-tooltip": "\uB300\uC2DC\uBCF4\uB4DC", onMouseEnter: handleMouseEnter, onMouseLeave: handleMouseLeave, onMouseMove: handleMouseMove, children: _jsx(SVG.Icon.Browser, { size: isMobile ? "md" : "lg" }) }), _jsx("button", { className: cn(iconWrapper), onClick: () => handleOpen("event"), "data-tooltip": "\uC0C8\uC18C\uC2DD", onMouseEnter: handleMouseEnter, onMouseLeave: handleMouseLeave, onMouseMove: handleMouseMove, children: _jsx(SVG.Icon.Newspaper, { size: isMobile ? "md" : "lg" }) }), tooltipText && (_jsx("div", { className: "absolute bg-gray-900 text-white text-sm px-3 py-1 rounded-lg transition-opacity duration-200 w-20 text-center", style: {
|
|
134
197
|
left: `${position.x}px`,
|
|
135
198
|
top: `${position.y}px`,
|
|
136
199
|
pointerEvents: "none",
|
package/package.json
CHANGED
package/version.txt
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
1.0.
|
|
1
|
+
1.0.304
|