@edu-tosel/design 1.0.173 → 1.0.174

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.
@@ -1,6 +1,7 @@
1
- import { State } from "../../../interface";
2
- export default function Header({ state, seriesState, levelState, }: {
1
+ import { Button as _Button, State } from "../../../interface";
2
+ export default function Header({ state, seriesState, levelState, contents, }: {
3
3
  state: State<string>;
4
4
  seriesState: State<string | undefined>;
5
5
  levelState: State<string | undefined>;
6
+ contents: _Button[];
6
7
  }): import("react/jsx-runtime").JSX.Element;
@@ -2,7 +2,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { cn } from "../../../util";
3
3
  import { Input, Select } from "../../../widget";
4
4
  import { useResponsive } from "../../../hook";
5
- export default function Header({ state, seriesState, levelState, }) {
5
+ export default function Header({ state, seriesState, levelState, contents, }) {
6
6
  const container = {
7
7
  displays: "flex justify-between items-start flex-wrap flex-none gap-y-5 gap-x-5",
8
8
  sizes: "w-full h-fit",
@@ -51,28 +51,7 @@ export default function Header({ state, seriesState, levelState, }) {
51
51
  title: "High Junior",
52
52
  value: "HJ",
53
53
  },
54
- ], state: levelState, placeholder: "\uB808\uBCA8" }) })] }), _jsx(ContentBox, { contents: [
55
- {
56
- title: "교재 음원",
57
- onClick: () => { },
58
- disabled: false,
59
- },
60
- {
61
- title: "정오표",
62
- onClick: () => { },
63
- disabled: true,
64
- },
65
- {
66
- title: "홍보자료",
67
- onClick: () => { },
68
- disabled: true,
69
- },
70
- {
71
- title: "기타 자료",
72
- onClick: () => { },
73
- disabled: true,
74
- },
75
- ] })] }));
54
+ ], state: levelState, placeholder: "\uB808\uBCA8" }) })] }), _jsx(ContentBox, { contents: contents })] }));
76
55
  }
77
56
  function ContentBox({ contents }) {
78
57
  const container = {
@@ -1 +1,2 @@
1
1
  export default function SectionA(): import("react/jsx-runtime").JSX.Element;
2
+ export declare function ScrollBookComponent(): import("react/jsx-runtime").JSX.Element;
@@ -3,32 +3,54 @@ import { useEffect, useRef } from "react";
3
3
  import gsap from "gsap";
4
4
  import ScrollTrigger from "gsap/ScrollTrigger";
5
5
  import { cn } from "../../../util";
6
+ import { useResponsive } from "../../../hook";
6
7
  gsap.registerPlugin(ScrollTrigger);
8
+ let divIndex = 0;
7
9
  export default function SectionA() {
8
10
  const stickyRef = useRef(null);
9
- const bookRef = useRef(null); // bookWrapper를 위한 ref 추가
10
- const mainTitleRef = useRef(null); // mainTitle을 위한 ref 추가
11
+ const bookRef = useRef(null);
12
+ const mainTitleRef = useRef(null);
11
13
  const subTitleRef = useRef(null);
14
+ const bgRef = useRef(null);
15
+ const buttonRef = useRef(null);
16
+ const bookScrollRef = useRef(null);
17
+ const refs = useRef([]);
18
+ const isMD = useResponsive("md");
19
+ const cardHeight = isMD ? 560 : 400;
20
+ console.log(isMD);
21
+ console.log(cardHeight);
22
+ const handleScroll = (direction) => {
23
+ if (bookScrollRef.current) {
24
+ const scrollAmount = cardHeight;
25
+ const currentScrollTop = bookScrollRef.current.scrollTop;
26
+ console.log(`direction: ${direction}`);
27
+ const newScrollTop = direction === "up"
28
+ ? Math.max(currentScrollTop - scrollAmount, 0)
29
+ : currentScrollTop + scrollAmount;
30
+ bookScrollRef.current.scrollTo({
31
+ top: newScrollTop,
32
+ behavior: "smooth",
33
+ });
34
+ }
35
+ };
12
36
  useEffect(() => {
13
37
  const ctx = gsap.context(() => {
14
38
  const vh = window.innerHeight * 0.01;
15
39
  const scrollWrapper = stickyRef.current;
16
- const bookWrapper = bookRef.current; // bookWrapper 참조
17
- const endpoint = `${50 * vh}px`;
40
+ const bookWrapper = bookRef.current;
41
+ const sectionEndPoint = `${50 * vh}px`;
42
+ const bookScrollEndPoint = `${1000 * vh}px`;
18
43
  if (scrollWrapper && bookWrapper) {
19
- // 첫 번째 ScrollTrigger: stickyRef를 고정하고 mainTitle의 투명도를 조정 및 크기 조절
44
+ // 첫 번째 ScrollTrigger: stickyRef를 고정하고 mainTitle의 투명도와 크기 조정
20
45
  const scrollTrigger = ScrollTrigger.create({
21
46
  trigger: scrollWrapper,
22
47
  start: "top top",
23
- end: `bottom ${endpoint}`,
48
+ end: `bottom ${sectionEndPoint}`,
24
49
  pin: true,
25
50
  markers: false,
26
- onLeave: () => {
27
- console.log("Scroll completed, navigate to the next component");
28
- },
29
- scrub: true, // 스크롤에 따라 애니메이션 동기화
51
+ scrub: true,
30
52
  });
31
- // mainTitle의 투명도와 크기를 스크롤 위치에 따라 조절하는 애니메이션 추가
53
+ // mainTitle의 투명도와 크기를 스크롤 위치에 따라 조절하는 애니메이션
32
54
  if (mainTitleRef.current) {
33
55
  gsap.to(mainTitleRef.current, {
34
56
  opacity: 0,
@@ -36,37 +58,73 @@ export default function SectionA() {
36
58
  scrollTrigger: {
37
59
  trigger: scrollWrapper,
38
60
  start: `top-=10 top`,
39
- end: `bottom ${endpoint}`,
40
- markers: true,
41
- scrub: true, // 스크롤에 따라 애니메이션 동기화
61
+ end: `bottom ${sectionEndPoint}`,
62
+ markers: false,
63
+ scrub: true,
42
64
  },
43
65
  });
44
66
  }
45
- if (subTitleRef.current) {
46
- gsap.to(subTitleRef.current, {
67
+ if (bgRef.current) {
68
+ gsap.to(bgRef.current, {
47
69
  opacity: 0,
48
70
  scrollTrigger: {
49
71
  trigger: scrollWrapper,
50
- start: `top top`,
51
- end: `bottom ${endpoint}`,
52
- markers: true,
53
- scrub: true, // 스크롤에 따라 애니메이션 동기화
72
+ start: `top-=10 top`,
73
+ end: `bottom ${sectionEndPoint}`,
74
+ markers: false,
75
+ scrub: true,
76
+ },
77
+ });
78
+ }
79
+ if (buttonRef.current) {
80
+ const tween = gsap.to(buttonRef.current, {
81
+ bottom: "60px",
82
+ duration: 0.3,
83
+ ease: "power2.inOut",
84
+ scrollTrigger: {
85
+ trigger: "",
86
+ start: `top+=1 top-=1`,
87
+ end: `bottom bottom`,
88
+ markers: false,
89
+ toggleActions: "play play play reverse",
54
90
  },
55
91
  });
92
+ // 스크롤에 따라 책 이미지 전환
93
+ refs.current.forEach((ref) => {
94
+ if (ref) {
95
+ gsap.to(ref, {
96
+ scrollTrigger: {
97
+ trigger: ref,
98
+ start: "top top",
99
+ end: "bottom top",
100
+ snap: {
101
+ snapTo: 1,
102
+ duration: 0.5,
103
+ ease: "power3.inOut",
104
+ },
105
+ onEnter: () => {
106
+ divIndex++;
107
+ handleScroll("down");
108
+ console.log(`onEnter: ${divIndex}`);
109
+ },
110
+ onLeaveBack: () => {
111
+ divIndex--;
112
+ handleScroll("up");
113
+ console.log(`onLeaveBack: ${divIndex}`);
114
+ },
115
+ },
116
+ });
117
+ }
118
+ });
56
119
  }
57
120
  // 두 번째 ScrollTrigger: bookWrapper가 뷰포트 상단에 도달하면 sticky하게 붙기
58
121
  const bookTrigger = ScrollTrigger.create({
59
122
  trigger: bookWrapper,
60
- start: "top top", // bookWrapper의 top이 뷰포트의 top에 도달했을 때
123
+ start: "top top",
124
+ end: `${bookScrollEndPoint} top`,
61
125
  pin: true,
62
- pinSpacing: false, // 추가된 pinSpacing을 false로 설정하여 고정된 상태에서 공간을 차지하지 않음
63
- markers: false,
64
- onEnter: () => {
65
- console.log("bookWrapper is pinned!");
66
- },
67
- onLeaveBack: () => {
68
- console.log("bookWrapper is unpinned!");
69
- },
126
+ pinSpacing: false,
127
+ markers: true,
70
128
  });
71
129
  return () => {
72
130
  scrollTrigger.kill();
@@ -74,29 +132,182 @@ export default function SectionA() {
74
132
  };
75
133
  }
76
134
  });
77
- return () => ctx.revert();
78
- }, []); // 빈 배열로 dependency 설정
135
+ return () => ctx.kill();
136
+ }, [handleScroll]);
79
137
  const container = {
80
- sizes: "w-full h-fit",
138
+ sizes: "w-full h-fit relative",
81
139
  displays: "flex flex-col justify-start items-center",
82
140
  textstyles: "antialiased",
83
141
  backgrounds: "bg-white bg-cover bg-center",
84
142
  };
143
+ const absoluteWrapperBottom = {
144
+ sizes: "w-full h-[200vh]",
145
+ displays: "absolute flex flex-col",
146
+ positions: "top-0 left-0 z-0",
147
+ };
148
+ const absoluteWrapperTop = {
149
+ sizes: "w-full h-[100vh]",
150
+ displays: "flex flex-col justify-center items-center fixed",
151
+ positions: "top-0 left-0 z-100",
152
+ };
153
+ const buttonStyling = {
154
+ sizes: "w-fit h-fit rounded-2xl",
155
+ spacings: "p-4 absolute mt-40",
156
+ display: "flex flex-row gap-2",
157
+ textStyling: "font-bold text-green-dark",
158
+ backgrounds: "shadow-main bg-white",
159
+ animation: "duration-300 hover:bg-green-dark hover:text-white",
160
+ };
85
161
  const TitleWrapper = {
86
- spacings: "pt-[30vh] z-0",
162
+ spacings: "pt-[20vh] z-5",
87
163
  sizes: "w-full h-[100vh]",
88
164
  display: "flex flex-col justify-start items-center",
89
- test: "border-2 border-red-500",
90
165
  };
91
166
  const miniTitle = {
92
- textstyles: "text-center font-medium text-lg text-green-dark",
167
+ textstyles: "text-center font-bold text-xl text-white",
93
168
  };
94
169
  const mainTitle = {
95
- textstyles: "text-center font-bold text-9xl text-black",
170
+ display: "flex flex-row gap-4 md:gap-10 mt-[5vh]",
171
+ textstyles: "text-center font-medium text-5xl md:text-8xl ml:text-10xl text-white leading-none",
96
172
  };
97
173
  const bookWrapper = {
98
174
  displays: "flex flex-col justify-center items-center -translate-y-[40vh]",
99
- sizes: "p-10 w-full h-screen",
175
+ sizes: "p-10 w-full h-screen ",
176
+ };
177
+ const bookExplainWrapper = {
178
+ displays: "flex flex-col md:flex-row justify-center items-center",
179
+ sizes: "h-screen w-full",
180
+ };
181
+ const bookTitle = {
182
+ displays: "flex flex-col justify-end items-center",
183
+ sizes: "h-full w-full pb-5",
184
+ textStyling: "font-bold text-2xl",
185
+ };
186
+ return (_jsxs("div", { className: cn(container), children: [_jsx("div", { className: cn(absoluteWrapperBottom, "bg-gradient-to-tr from-crimson-burgundy to-green-dark"), ref: bgRef }), _jsx("div", { className: cn(absoluteWrapperTop), children: _jsxs("div", { className: cn(buttonStyling), ref: buttonRef, onClick: () => {
187
+ window.location.href = "https://smartstore.naver.com/tosel";
188
+ }, children: [_jsx("div", { children: _jsx("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", fill: "currentColor", className: "size-6", children: _jsx("path", { d: "M2.25 2.25a.75.75 0 0 0 0 1.5h1.386c.17 0 .318.114.362.278l2.558 9.592a3.752 3.752 0 0 0-2.806 3.63c0 .414.336.75.75.75h15.75a.75.75 0 0 0 0-1.5H5.378A2.25 2.25 0 0 1 7.5 15h11.218a.75.75 0 0 0 .674-.421 60.358 60.358 0 0 0 2.96-7.228.75.75 0 0 0-.525-.965A60.864 60.864 0 0 0 5.68 4.509l-.232-.867A1.875 1.875 0 0 0 3.636 2.25H2.25ZM3.75 20.25a1.5 1.5 0 1 1 3 0 1.5 1.5 0 0 1-3 0ZM16.5 20.25a1.5 1.5 0 1 1 3 0 1.5 1.5 0 0 1-3 0Z" }) }) }), "\uAD50\uC7AC\uBAB0 \uBC14\uB85C\uAC00\uAE30"] }) }), _jsxs("div", { className: cn(TitleWrapper), ref: stickyRef, children: [_jsx("div", { className: cn(miniTitle), ref: subTitleRef, children: "\uB2F9\uC2E0\uC774 \uBBFF\uC744 \uC218 \uC788\uB294 \uC601\uC5B4\uAD50\uC7AC" }), _jsxs("div", { className: cn(mainTitle), ref: mainTitleRef, children: [_jsx("div", { className: "flex justify-center items-center w-40 md:w-80 ml:w-120", children: _jsx("img", { src: "https://resource.tosel.co.kr/images/img-logo-tosel-darkmode.svg", alt: "", className: "max-w-full h-auto" }) }), _jsx("div", { className: "h-full w-0.5 bg-white" }), _jsx("div", { children: " books " })] })] }), _jsx("div", { className: cn(bookWrapper), ref: bookRef, children: _jsx("div", { className: cn("w-72 h-100 md:w-100 md:h-140 bg-white z-10 rounded-2xl shadow-main overflow-y-scroll scrollbar-hidden snap-y snap-mandatory"), ref: bookScrollRef, children: _jsx(ScrollBookComponent, {}) }) }), bookData.map((item, index) => {
189
+ // item.levelLow 값을 LevelKey로 변환하기 전에 유효성 검사
190
+ const lowLevelStyle = getLevelStyle(item.levelLow); // 안전하게 캐스팅
191
+ const highLevelStyle = getLevelStyle(item.levelHigh); // 이 부분도 마찬가지로
192
+ return (_jsxs("div", { className: cn(bookExplainWrapper), ref: (el) => {
193
+ if (el) {
194
+ refs.current[index] = el;
195
+ }
196
+ }, children: [_jsxs("div", { className: cn(bookTitle), children: [_jsx("div", { children: item.title }), _jsx("div", { className: "text-base text-gray-medium", children: item.type })] }), _jsx("div", { className: "h-100 w-full shrink-0" }), _jsxs("div", { className: "h-full w-full pt-5 flex flex-col justify-start items-center", children: [_jsxs("div", { className: "w-fit h-fit flex flex-row gap-2", children: [_jsx("div", { className: `w-fit h-fit px-2 py-1 text-sm rounded-md font-bold ${lowLevelStyle.textColor} ${lowLevelStyle.bgColor}`, children: lowLevelStyle.name }), "~", _jsx("div", { className: `w-fit h-fit px-2 py-1 text-sm rounded-md font-bold ${highLevelStyle.textColor} ${highLevelStyle.bgColor}`, children: highLevelStyle.name })] }), isMD && (_jsx("div", { className: "text-center font-medium text-sm", children: item.description }))] })] }, item.id));
197
+ })] }));
198
+ }
199
+ const bookData = [
200
+ {
201
+ id: 1,
202
+ type: "학습 시리즈",
203
+ title: "Speaking Series",
204
+ imgSrc: "https://resource.tosel.co.kr/images/SP-COVER-PS.png",
205
+ description: "어쩌",
206
+ levelLow: "PS",
207
+ levelHigh: "HJ",
208
+ link: "",
209
+ },
210
+ {
211
+ id: 2,
212
+ type: "학습 시리즈",
213
+ title: "Story Series",
214
+ imgSrc: "https://resource.tosel.co.kr/images/SP-COVER-PS.png",
215
+ description: "어쩌",
216
+ levelLow: "PS",
217
+ levelHigh: "JR",
218
+ link: "",
219
+ },
220
+ {
221
+ id: 3,
222
+ type: "학습 시리즈",
223
+ title: "Listening Series",
224
+ imgSrc: "https://resource.tosel.co.kr/images/SP-COVER-PS.png",
225
+ description: "어쩌",
226
+ levelLow: "PS",
227
+ levelHigh: "HJ",
228
+ link: "",
229
+ },
230
+ {
231
+ id: 4,
232
+ type: "학습 시리즈",
233
+ title: "Reading Series",
234
+ imgSrc: "https://resource.tosel.co.kr/images/SP-COVER-PS.png",
235
+ description: "어쩌",
236
+ levelLow: "PS",
237
+ levelHigh: "HJ",
238
+ link: "",
239
+ },
240
+ {
241
+ id: 5,
242
+ type: "학습 시리즈",
243
+ title: "Grammar Series",
244
+ imgSrc: "https://resource.tosel.co.kr/images/SP-COVER-PS.png",
245
+ description: "어쩌",
246
+ levelLow: "PS",
247
+ levelHigh: "HJ",
248
+ link: "",
249
+ },
250
+ {
251
+ id: 6,
252
+ type: "학습 시리즈",
253
+ title: "VOCA Series",
254
+ imgSrc: "https://resource.tosel.co.kr/images/SP-COVER-PS.png",
255
+ description: "어쩌",
256
+ levelLow: "PS",
257
+ levelHigh: "HJ",
258
+ link: "",
259
+ },
260
+ ];
261
+ const levelStyles = {
262
+ CO: {
263
+ name: "cocoon",
264
+ textColor: "text-cocoon-green",
265
+ bgColor: "bg-cocoon-green/10",
266
+ },
267
+ PS: {
268
+ name: "Pre-Starter",
269
+ textColor: "text-ps-pink",
270
+ bgColor: "bg-ps-pink-light",
271
+ },
272
+ ST: {
273
+ name: "Starter",
274
+ textColor: "text-st-orange",
275
+ bgColor: "bg-st-orange-light",
276
+ },
277
+ BA: {
278
+ name: "Basic",
279
+ textColor: "text-ba-yellow",
280
+ bgColor: "bg-ba-yellow-light",
281
+ },
282
+ JR: {
283
+ name: "Junior",
284
+ textColor: "text-jr-blue",
285
+ bgColor: "bg-jr-blue-light",
286
+ },
287
+ HJ: {
288
+ name: "High Junior",
289
+ textColor: "text-hj-blue",
290
+ bgColor: "bg-hj-blue-light",
291
+ },
292
+ AD: {
293
+ name: "Advanced",
294
+ textColor: "text-gray-dark",
295
+ bgColor: "bg-gray-light",
296
+ },
297
+ };
298
+ const getLevelStyle = (level) => {
299
+ return levelStyles[level];
300
+ };
301
+ export function ScrollBookComponent() {
302
+ const container = {
303
+ sizes: "w-full h-fit relative",
304
+ displyas: "flex flex-col",
305
+ backgrounds: "bg-white",
306
+ };
307
+ const imageWrapper = {
308
+ sizes: "w-72 h-100 md:w-100 md:h-140",
309
+ imgStyling: "bg-contain bg-no-repeat bg-center",
310
+ scrollActions: "snap-start",
100
311
  };
101
- return (_jsxs("div", { className: cn(container), children: [_jsxs("div", { className: cn(TitleWrapper), ref: stickyRef, children: [_jsx("div", { className: cn(miniTitle), ref: subTitleRef, children: "\uBBFF\uC744 \uC218 \uC788\uB294 \uC601\uC5B4\uAD50\uC7AC" }), _jsx("div", { className: cn(mainTitle), ref: mainTitleRef, children: "TOSEL Books" }), " "] }), _jsx("div", { className: cn(bookWrapper), ref: bookRef, children: _jsx("div", { className: "w-100 h-140 bg-red-500 mt-[calc(10vh)] z-10 rounded-2xl shadow-main " }) })] }));
312
+ return (_jsx("div", { className: cn(container), children: bookData.map((item) => (_jsx("div", { className: cn(imageWrapper, `bg-[url('${item.imgSrc}')]`) }, item.id))) }));
102
313
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@edu-tosel/design",
3
- "version": "1.0.173",
3
+ "version": "1.0.174",
4
4
  "description": "UI components for International TOSEL Committee",
5
5
  "keywords": [
6
6
  "jsx",
package/version.txt CHANGED
@@ -1 +1 @@
1
- 1.0.173
1
+ 1.0.174