@edu-tosel/design 1.0.315 → 1.0.317

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.
@@ -12,9 +12,10 @@ export default function BbsLayout({ title, children, icon, links, }) {
12
12
  sizes: "w-full max-w-[1200px]",
13
13
  };
14
14
  const body = {
15
- displays: "flex items-center gap-y-5 md:flex-row justify-between md:items-end",
15
+ displays: "flex xs:flex-row flex-col items-center gap-y-5 md:flex-row justify-between md:items-end",
16
16
  sizes: "w-full md:h-[188px]",
17
17
  boundaries: "pt-8 md:pt-0 px-5 md:px-12 md:pb-10 ",
18
+ //debug: "border-2 border-red-500",
18
19
  };
19
20
  const childrenBody = {
20
21
  sizes: "w-full max-w-[1200px]",
@@ -24,7 +25,7 @@ export default function BbsLayout({ title, children, icon, links, }) {
24
25
  }
25
26
  export function BbsSelect({ links }) {
26
27
  const container = {
27
- displays: "flex",
28
+ displays: "flex gap-x-1.5",
28
29
  backgrounds: "bg-[#F0F0F0]",
29
30
  boundaries: "p-[6px]",
30
31
  styles: "rounded-full",
@@ -36,7 +37,8 @@ export function BbsSelect({ links }) {
36
37
  sizes: "w-[80px] md:w-[100px] h-[30px]",
37
38
  displays: "flex justify-center items-center",
38
39
  styles: "rounded-full",
39
- fonts: "text-[12px] leading-tight ",
40
+ fonts: "text-sm leading-tight font-pretendard-var font-medium",
41
+ animations: "hover:bg-white/50 duration-200",
40
42
  });
41
43
  return (_jsx("div", { className: cn(container), children: links.map(({ title, onClick, isPressed }) => (_jsx("button", { onClick: onClick, className: cn(button(isPressed)), children: title }))) }));
42
44
  }
@@ -19,7 +19,7 @@ export default function ShortcutBanner({ shortcuts, }) {
19
19
  const tagBox = {
20
20
  displays: "flex justify-center items-center",
21
21
  sizes: "w-full h-6.25 ",
22
- fonts: "text-xs font-pretendard-var font-medium text-gray-dark group-hover:text-green-dark",
22
+ fonts: "text-xs md:text-sm font-pretendard-var font-medium text-gray-dark group-hover:text-green-dark",
23
23
  animation: "duration-100",
24
24
  };
25
25
  const iconContainer = {
@@ -1,7 +1,9 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import urlAsset from "../../../../asset/url";
3
3
  import { cn } from "../../../../util";
4
+ import { useResponsive } from "../../../../hook";
4
5
  export default function Footer() {
6
+ const isXS = useResponsive("xs");
5
7
  const container = {
6
8
  displays: "flex justify-center items-center",
7
9
  sizes: "w-full h-fit",
@@ -28,6 +30,11 @@ export default function Footer() {
28
30
  const info = {
29
31
  textstyling: "leading-normal text-sm",
30
32
  };
33
+ const flexInfo = {
34
+ displays: "flex flex-row justify-start items-center flex-wrap",
35
+ sizes: "w-full max-w-150",
36
+ spacings: "gap-x-5",
37
+ };
31
38
  //social button styling
32
39
  const iconWrapper = {
33
40
  displays: "flex items-center gap-3 mt-8",
@@ -41,7 +48,7 @@ export default function Footer() {
41
48
  const socialIconControl = {
42
49
  siezes: "h-6",
43
50
  };
44
- return (_jsx("div", { className: cn(container), children: _jsxs("div", { className: cn(body), children: [_jsxs("div", { className: cn(logoWrapper), children: [_jsx("img", { className: cn(svgController), src: "/images/logos/logo-tosel-main.svg", alt: "" }), _jsx("img", { className: cn(svgController), src: "/images/logos/logo-itc-main.svg", alt: "" })] }), _jsxs("div", { className: "flex flex-wrap justify-between items-center border-b-1 border-gray-dark pb-4 mt-5 font-medium gap-y-1", children: [_jsx("div", { children: "Copyright TOSEL. \u24D2 All Rights Reserved." }), _jsx("div", { className: "flex gap-5", children: buttons.map((button, index) => (_jsxs("div", { onClick: button.onClick, className: "cursor-default", children: [button.title, " "] }, index))) })] }), _jsxs("div", { className: cn(infoSet), children: [_jsx("div", { className: cn(infoTitle), children: "\uACE0\uAC1D\uBB38\uC758" }), _jsxs("div", { className: cn(info), children: ["\u203B\uAC1C\uC778\uC815\uBCF4 \uBCF4\uD638 \uC815\uCC45\uC5D0 \uB530\uB77C, \uBAA8\uB4E0 \uACF5\uC2DD \uBB38\uC758\uB294 \uC774\uBA54\uC77C\uC744 \uD1B5\uD574\uC11C\uB9CC \uC811\uC218 \uAC00\uB2A5\uD569\uB2C8\uB2E4.", _jsx("br", {}), "\uB300\uD45C\uBC88\uD638 | 02-923-0505", _jsx("br", {}), "\uAC1C\uC778\uBB38\uC758 | tosel_cs@tosel.co.kr ", _jsx("br", {}), "\uB2E8\uCCB4\uBB38\uC758 | tosel_academy@tosel.co.kr"] })] }), _jsxs("div", { className: cn(infoSet), children: [_jsx("div", { className: cn(infoTitle), children: "\uAD6D\uC81C\uD1A0\uC140\uC704\uC6D0\uD68C" }), _jsxs("div", { className: cn(info), children: ["\uC0AC\uC5C5\uC790 \uB4F1\uB85D\uBC88\uD638 : 209-81-55585 | \uB300\uD45C : \uC624\uC2B9\uC5F0 ", _jsx("br", {}), "\uC6F9\uC11C\uBE44\uC2A4: \uC8FC\uC2DD\uD68C\uC0AC \uC5D0\uB4C0\uD1A0\uC140 | \uD1B5\uC2E0\uD310\uB9E4\uC5C5\uC2E0\uACE0\uBC88\uD638: \uC81C 2012-\uC11C\uC6B8\uC131\uBD81-0083\uD638", _jsx("br", {}), " \uC11C\uC6B8\uC2DC \uC131\uBD81\uAD6C \uC548\uC554\uB85C 145 \uACE0\uB824\uB300\uD559\uAD50 \uB77C\uC774\uC2DC\uC6C0 4\uCE35", _jsx("br", {}), " Lyceum Korea University, 145 Anam Ro, Seongbuk-Gu, Seoul, Korea 02841"] })] }), _jsxs("div", { className: cn(iconWrapper), children: [_jsx("a", { onClick: () => (location.href = "https://blog.naver.com/ebs1503"), children: _jsx("div", { className: cn(iconBox), children: _jsx("img", { className: cn(socialIconControl), src: "/images/logos/naver.svg", alt: "" }) }) }), _jsx("a", { onClick: () => (location.href = "https://www.instagram.com/tosel_official/"), children: _jsx("div", { className: cn(iconBox), children: _jsx("img", { className: cn(socialIconControl), src: "/images/logos/instagram.svg", alt: "" }) }) }), _jsx("a", { onClick: () => (location.href = "https://www.youtube.com/@tosel_official"), children: _jsx("div", { className: cn(iconBox), children: _jsx("img", { className: cn(socialIconControl), src: "/images/logos/youtube.svg", alt: "" }) }) })] })] }) }));
51
+ return (_jsx("div", { className: cn(container), children: _jsxs("div", { className: cn(body), children: [_jsxs("div", { className: cn(logoWrapper), children: [_jsx("img", { className: cn(svgController), src: "/images/logos/logo-tosel-main.svg", alt: "" }), _jsx("img", { className: cn(svgController), src: "/images/logos/logo-itc-main.svg", alt: "" })] }), _jsxs("div", { className: "flex flex-wrap justify-between items-center border-b-1 border-gray-medium/50 pb-4 mt-5 font-medium gap-y-1", children: [_jsx("div", { children: "Copyright TOSEL. \u24D2 All Rights Reserved." }), _jsx("div", { className: "flex gap-5", children: buttons.map((button, index) => (_jsxs("div", { onClick: button.onClick, className: "cursor-default", children: [button.title, " "] }, index))) })] }), _jsxs("div", { className: cn(infoSet), children: [_jsx("div", { className: cn(infoTitle), children: "\uACE0\uAC1D\uBB38\uC758" }), _jsxs("div", { className: cn(info), children: ["\u203B\uAC1C\uC778\uC815\uBCF4 \uBCF4\uD638 \uC815\uCC45\uC5D0 \uB530\uB77C, \uBAA8\uB4E0 \uACF5\uC2DD \uBB38\uC758\uB294 \uC774\uBA54\uC77C\uC744 \uD1B5\uD574\uC11C\uB9CC \uC811\uC218 \uAC00\uB2A5\uD569\uB2C8\uB2E4.", _jsx("br", {}), _jsxs("div", { className: cn(flexInfo, "py-2"), children: [_jsx("div", { children: "\uB300\uD45C\uBC88\uD638 | 02-923-0505" }), _jsx("div", { children: "TOSEL Lab \uC9C0\uC815\uAD50\uC721\uAE30\uAD00 | 02-953-0202 " }), isXS ? (_jsx("div", { children: "\uACE0\uB824\uB300\uD559\uAD50 \uBBF8\uB798\uAD50\uC721\uC6D0 \uD1A0\uC140 \uC804\uBB38\uAC00 \uACFC\uC815 | 02-953-0202 " })) : (_jsx("div", { children: "\uACE0\uB824\uB300 \uD1A0\uC140 \uC804\uBB38\uAC00 \uACFC\uC815 | 02-953-0202 " })), _jsx("div", { children: "\uAD50\uC7AC \uBB38\uC758 | 02-924-8137" })] }), "\uAC1C\uC778\uBB38\uC758 | tosel_cs@tosel.co.kr ", _jsx("br", {}), "\uB2E8\uCCB4\uBB38\uC758 | tosel_academy@tosel.co.kr"] })] }), _jsxs("div", { className: cn(infoSet), children: [_jsx("div", { className: cn(infoTitle), children: "\uAD6D\uC81C\uD1A0\uC140\uC704\uC6D0\uD68C" }), _jsxs("div", { className: cn(info, "flex flex-col gap-2"), children: [_jsxs("div", { children: ["\uBE44\uC601\uB9AC\uC5F0\uAD6C\uAE30\uAD00 \uACE0\uC720\uBC88\uD638 : 506-82-91193 ", _jsx("br", {}), "Web Service: Edu-tosel Co., Ltd. | \uD1B5\uC2E0\uD310\uB9E4\uC5C5\uC2E0\uACE0\uBC88\uD638: \uC81C 2012-\uC11C\uC6B8\uC131\uBD81-0083\uD638"] }), _jsxs("div", { children: ["\uC11C\uC6B8\uC2DC \uC131\uBD81\uAD6C \uC548\uC554\uB85C 145 \uACE0\uB824\uB300\uD559\uAD50 \uB77C\uC774\uC2DC\uC6C0 4\uCE35", _jsx("br", {}), " Lyceum Korea University, 145 Anam Ro, Seongbuk-Gu, Seoul, Korea 02841"] })] })] }), _jsxs("div", { className: cn(iconWrapper), children: [_jsx("a", { onClick: () => (location.href = "https://blog.naver.com/ebs1503"), children: _jsx("div", { className: cn(iconBox), children: _jsx("img", { className: cn(socialIconControl), src: "/images/logos/naver.svg", alt: "" }) }) }), _jsx("a", { onClick: () => (location.href = "https://www.instagram.com/tosel_official/"), children: _jsx("div", { className: cn(iconBox), children: _jsx("img", { className: cn(socialIconControl), src: "/images/logos/instagram.svg", alt: "" }) }) }), _jsx("a", { onClick: () => (location.href = "https://www.youtube.com/@tosel_official"), children: _jsx("div", { className: cn(iconBox), children: _jsx("img", { className: cn(socialIconControl), src: "/images/logos/youtube.svg", alt: "" }) }) })] })] }) }));
45
52
  }
46
53
  const buttons = [
47
54
  // {
@@ -1,14 +1,16 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { useState, useEffect } from "react";
2
+ import { useState, useEffect, useRef } from "react";
3
3
  import { cn, gradient } from "../../../../util";
4
4
  import { Label } from "../../../../widget";
5
5
  import { useResponsive } from "../../../../hook";
6
+ import { gsap } from "gsap";
6
7
  export default function Header({ logo, rightButton, contents, }) {
7
8
  const [isExpanded, setIsExpanded] = useState(false);
8
- const [hasToggled, setHasToggled] = useState(false);
9
+ const [isInitialized, setIsInitialized] = useState(false);
10
+ const headerRef = useRef(null);
11
+ const menuContentRef = useRef(null);
9
12
  const toggleHeight = () => {
10
13
  setIsExpanded(!isExpanded);
11
- setHasToggled(true); // 한 번이라도 토글되었음을 표시
12
14
  };
13
15
  const handleClickOutside = (event) => {
14
16
  const menuElement = document.getElementById("buttonArea");
@@ -29,18 +31,81 @@ export default function Header({ logo, rightButton, contents, }) {
29
31
  };
30
32
  }, [isExpanded]);
31
33
  const isMD = useResponsive("md");
34
+ // 초기 상태 설정 (애니메이션 없이)
35
+ useEffect(() => {
36
+ if (!headerRef.current || !menuContentRef.current)
37
+ return;
38
+ const header = headerRef.current;
39
+ const menuContent = menuContentRef.current;
40
+ // 초기 마운트시에는 애니메이션 없이 즉시 설정
41
+ if (isMD) {
42
+ // 데스크톱: 항상 표시되는 상태
43
+ gsap.set(header, { height: "60px" });
44
+ gsap.set(menuContent, { opacity: 1, visibility: "visible" });
45
+ }
46
+ else {
47
+ // 모바일: 접혀있는 상태로 시작
48
+ gsap.set(header, { height: "60px" });
49
+ gsap.set(menuContent, { opacity: 0, visibility: "hidden" });
50
+ }
51
+ setIsExpanded(false);
52
+ setIsInitialized(true);
53
+ }, [isMD]);
54
+ // GSAP 애니메이션 처리 (초기화 후에만 실행)
55
+ useEffect(() => {
56
+ if (!isInitialized || !headerRef.current || !menuContentRef.current)
57
+ return;
58
+ const header = headerRef.current;
59
+ const menuContent = menuContentRef.current;
60
+ if (isMD) {
61
+ // 데스크톱으로 전환시 즉시 표시
62
+ gsap.set(header, { height: "60px" });
63
+ gsap.set(menuContent, { opacity: 1, visibility: "visible" });
64
+ setIsExpanded(false);
65
+ }
66
+ else {
67
+ // 모바일에서만 애니메이션 적용
68
+ if (isExpanded) {
69
+ gsap.to(header, {
70
+ height: "auto",
71
+ duration: 0.3,
72
+ ease: "power2.inOut",
73
+ });
74
+ gsap.to(menuContent, {
75
+ opacity: 1,
76
+ visibility: "visible",
77
+ duration: 0.3,
78
+ ease: "power2.inOut",
79
+ });
80
+ }
81
+ else {
82
+ gsap.to(menuContent, {
83
+ opacity: 0,
84
+ visibility: "hidden",
85
+ duration: 0.2,
86
+ ease: "power2.inOut",
87
+ });
88
+ gsap.to(header, {
89
+ height: "60px",
90
+ duration: 0.3,
91
+ ease: "power2.inOut",
92
+ });
93
+ }
94
+ }
95
+ }, [isExpanded, isInitialized]);
96
+ // 화면 크기가 변경될 때 메뉴 상태 초기화
97
+ useEffect(() => {
98
+ if (isMD && isExpanded) {
99
+ setIsExpanded(false);
100
+ }
101
+ }, [isMD]);
32
102
  //메뉴바 배경
33
103
  const container = {
34
- positions: "fixed top-0 left-0 z-40 md:h-15",
104
+ positions: "fixed top-0 left-0 z-40",
35
105
  displays: "flex justify-center items-start overflow-hidden",
36
106
  sizes: "w-full",
37
- styles: "bg-white box-shadow",
107
+ styles: "bg-white box-shadow",
38
108
  textstyles: "antialiased",
39
- animation: hasToggled && !isMD
40
- ? isExpanded
41
- ? "animate-grow"
42
- : "animate-shrink"
43
- : "",
44
109
  };
45
110
  const body = {
46
111
  displays: "flex md:flex-row flex-col md:items-center items-start justify-between",
@@ -69,7 +134,10 @@ export default function Header({ logo, rightButton, contents, }) {
69
134
  displays: "flex flex-row justify-center md:justify-start",
70
135
  spacings: "items-center gap-x-6 ml:gap-x-12 ",
71
136
  sizes: "w-full md:w-fit",
72
- boundaries: "border-gray-light border-t-2",
137
+ boundaries: "border-gray-light md:border-t-0 border-t-2",
138
+ visibility: isMD
139
+ ? "opacity-100 visible"
140
+ : "opacity-0 invisible md:opacity-100 md:visible",
73
141
  };
74
142
  const essenstialsWrapper = {
75
143
  displays: "flex flex-row items-center h-15",
@@ -80,12 +148,12 @@ export default function Header({ logo, rightButton, contents, }) {
80
148
  const menuButton = {
81
149
  displays: "flex justify-center items-center p-2",
82
150
  };
83
- return (_jsx("div", { className: cn(container), children: _jsxs("div", { className: cn(body), children: [_jsxs("div", { className: cn(leftWrapper), children: [_jsx("div", { onClick: logo.onClick, children: logo.node }), _jsxs("div", { className: cn(essenstialsWrapper), id: "buttonArea", children: [rightButton && (_jsx(Label.Button, { title: rightButton.title, onClick: rightButton?.onClick, option: {
151
+ return (_jsx("div", { ref: headerRef, className: cn(container), children: _jsxs("div", { className: cn(body), children: [_jsxs("div", { className: cn(leftWrapper), children: [_jsx("div", { onClick: logo.onClick, children: logo.node }), _jsxs("div", { className: cn(essenstialsWrapper), id: "buttonArea", children: [rightButton && (_jsx(Label.Button, { title: rightButton.title, onClick: rightButton?.onClick, option: {
84
152
  width: "2xs",
85
153
  height: "xs",
86
154
  background: gradient.bg.greenToRed,
87
155
  text: "text-white",
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: {
156
+ } })), _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", { ref: menuContentRef, 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: {
89
157
  width: "xs",
90
158
  height: "xs",
91
159
  background: gradient.bg.greenToRed,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@edu-tosel/design",
3
- "version": "1.0.315",
3
+ "version": "1.0.317",
4
4
  "description": "UI components for International TOSEL Committee",
5
5
  "keywords": [
6
6
  "jsx",
@@ -14,6 +14,7 @@
14
14
  "type": "module",
15
15
  "scripts": {},
16
16
  "dependencies": {
17
+ "@edu-tosel/interface": "https://resource.tosel.co.kr/packages/interface/1.0.59",
17
18
  "@edu-tosel/utils": "^0.0.30",
18
19
  "@gsap/react": "^2.1.1",
19
20
  "date-fns": "^2.30.0",
package/version.txt CHANGED
@@ -1 +1 @@
1
- 1.0.315
1
+ 1.0.317