@edu-tosel/design 1.0.351 → 1.0.354
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/interface/EducationalVideo.d.ts +20 -0
- package/interface/EducationalVideo.js +3 -0
- package/interface/Interview.d.ts +42 -0
- package/interface/Interview.js +9 -0
- package/interface/News.d.ts +24 -0
- package/interface/News.js +17 -0
- package/layout/template/home/Education.d.ts +4 -0
- package/layout/template/home/Education.js +143 -0
- package/layout/template/home/Interviews.d.ts +6 -0
- package/layout/template/home/Interviews.js +35 -0
- package/layout/template/home/News.d.ts +4 -0
- package/layout/template/home/News.js +106 -0
- package/layout/template/home/index.d.ts +6 -0
- package/layout/template/home/index.js +7 -1
- package/layout/template/home/layout/Header.d.ts +1 -1
- package/layout/template/home/layout/index.d.ts +3 -2
- package/package.json +1 -1
- package/version.txt +1 -1
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export declare const educationalVideoKeys: readonly ["id", "index", "category", "title", "subTitle", "content", "youtubeId", "referenceUrl", "thumbnailUrl", "isValid", "createdAt", "updatedAt"];
|
|
2
|
+
export interface EducationalVideo {
|
|
3
|
+
id: number;
|
|
4
|
+
index: number;
|
|
5
|
+
category: string;
|
|
6
|
+
title: string;
|
|
7
|
+
subTitle: string;
|
|
8
|
+
content: string;
|
|
9
|
+
youtubeId: string;
|
|
10
|
+
referenceUrl: string;
|
|
11
|
+
thumbnailUrl: string;
|
|
12
|
+
isValid: boolean;
|
|
13
|
+
createdAt: Date;
|
|
14
|
+
updatedAt: Date;
|
|
15
|
+
}
|
|
16
|
+
export type EducationalVideoAutoSetKeys = "id" | "createdAt" | "updatedAt";
|
|
17
|
+
export interface EducationalVideoCreate extends Omit<EducationalVideo, EducationalVideoAutoSetKeys> {
|
|
18
|
+
}
|
|
19
|
+
export interface EducationalVideoUpdate extends Partial<EducationalVideoCreate> {
|
|
20
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
export declare const interviewKeys: readonly ["id", "index", "category", "title", "subTitle", "content", "profile", "isValid", "createdAt", "updatedAt"];
|
|
2
|
+
export declare const interviewCategories: readonly ["LAB", "REG", "SPO", "VCO"];
|
|
3
|
+
export type InterviewCategoryType = (typeof interviewCategories)[number];
|
|
4
|
+
export interface InterviewText {
|
|
5
|
+
title: string;
|
|
6
|
+
label: string;
|
|
7
|
+
content: string;
|
|
8
|
+
align?: 'left' | 'center' | 'right' | null;
|
|
9
|
+
}
|
|
10
|
+
export interface InterviewContent {
|
|
11
|
+
content?: InterviewText[] | null;
|
|
12
|
+
videoId?: string | null;
|
|
13
|
+
imageUrl?: string | null;
|
|
14
|
+
align?: 'left' | 'center' | 'right' | null;
|
|
15
|
+
type: "A" | "B" | "C" | "D";
|
|
16
|
+
}
|
|
17
|
+
export interface InterviewProfile {
|
|
18
|
+
name: string;
|
|
19
|
+
description: string;
|
|
20
|
+
profileUrl?: string | null;
|
|
21
|
+
tag?: string | null;
|
|
22
|
+
tagBackgroundColor?: string | null;
|
|
23
|
+
textColor?: string | null;
|
|
24
|
+
content?: string | null;
|
|
25
|
+
}
|
|
26
|
+
export interface Interview {
|
|
27
|
+
id: number;
|
|
28
|
+
index: number;
|
|
29
|
+
category: InterviewCategoryType;
|
|
30
|
+
title: string;
|
|
31
|
+
subTitle: string;
|
|
32
|
+
content?: InterviewContent[] | null;
|
|
33
|
+
profile?: InterviewProfile | null;
|
|
34
|
+
isValid: boolean;
|
|
35
|
+
createdAt: Date;
|
|
36
|
+
updatedAt: Date;
|
|
37
|
+
}
|
|
38
|
+
export type InterviewAutoSetKeys = "id" | "createdAt" | "updatedAt";
|
|
39
|
+
export interface InterviewCreate extends Omit<Interview, InterviewAutoSetKeys> {
|
|
40
|
+
}
|
|
41
|
+
export interface InterviewUpdate extends Partial<InterviewCreate> {
|
|
42
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export const interviewKeys = [
|
|
2
|
+
'id', 'index', 'category', 'title', 'subTitle', 'content', 'profile', 'isValid', 'createdAt', 'updatedAt'
|
|
3
|
+
];
|
|
4
|
+
export const interviewCategories = [
|
|
5
|
+
"LAB", // Lab
|
|
6
|
+
"REG", // 정기시험
|
|
7
|
+
"SPO", // Speaking Olympiad
|
|
8
|
+
"VCO", // Voca Olympiad
|
|
9
|
+
];
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export declare const newsKeys: readonly ["id", "index", "category", "title", "subTitle", "content", "imgUrl", "author", "isValid", "isPinned", "createdAt", "updatedAt"];
|
|
2
|
+
export declare const newsCategories: readonly ["test", "lab", "education", "tosel", "event"];
|
|
3
|
+
export type NewsCategoryType = (typeof newsCategories)[number];
|
|
4
|
+
export declare const newsAuthors: readonly ["tosel", "tosel-lab", "professor", "administrator", "esg"];
|
|
5
|
+
export type NewsAuthorType = (typeof newsAuthors)[number];
|
|
6
|
+
export interface News {
|
|
7
|
+
id: number;
|
|
8
|
+
index: number;
|
|
9
|
+
category: NewsCategoryType;
|
|
10
|
+
title: string;
|
|
11
|
+
subTitle: string;
|
|
12
|
+
content: string;
|
|
13
|
+
imgUrl: string;
|
|
14
|
+
author: NewsAuthorType;
|
|
15
|
+
isValid: boolean;
|
|
16
|
+
isPinned: boolean;
|
|
17
|
+
createdAt: Date;
|
|
18
|
+
updatedAt: Date;
|
|
19
|
+
}
|
|
20
|
+
export type NewsAutoSetKeys = "id" | "createdAt" | "updatedAt";
|
|
21
|
+
export interface NewsCreate extends Omit<News, NewsAutoSetKeys> {
|
|
22
|
+
}
|
|
23
|
+
export interface NewsUpdate extends Partial<NewsCreate> {
|
|
24
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export const newsKeys = [
|
|
2
|
+
'id', 'index', 'category', 'title', 'subTitle', 'content', 'imgUrl', 'author', 'isValid', 'isPinned', 'createdAt', 'updatedAt'
|
|
3
|
+
];
|
|
4
|
+
export const newsCategories = [
|
|
5
|
+
"test", // 시험
|
|
6
|
+
"lab", // Lab
|
|
7
|
+
"education", // 공교육
|
|
8
|
+
"tosel", // TOSEL
|
|
9
|
+
"event", // 이벤트
|
|
10
|
+
];
|
|
11
|
+
export const newsAuthors = [
|
|
12
|
+
"tosel",
|
|
13
|
+
"tosel-lab",
|
|
14
|
+
"professor",
|
|
15
|
+
"administrator",
|
|
16
|
+
"esg"
|
|
17
|
+
];
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useMemo, useRef, useState, useEffect } from "react";
|
|
3
|
+
import { cn } from "../../../util";
|
|
4
|
+
export default function Education({ educationalVideos }) {
|
|
5
|
+
const scrollContainerRef = useRef(null);
|
|
6
|
+
const cardWidth = 320; // card width
|
|
7
|
+
const [activeVideoIndex, setActiveVideoIndex] = useState(0); // 초기값: 첫 번째 비디오
|
|
8
|
+
const recentVideos = useMemo(() => {
|
|
9
|
+
return [...educationalVideos]
|
|
10
|
+
.sort((a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime())
|
|
11
|
+
.slice(0, 4);
|
|
12
|
+
}, [educationalVideos]);
|
|
13
|
+
// 스크롤 위치 상태 관리
|
|
14
|
+
const [canScrollLeft, setCanScrollLeft] = useState(false);
|
|
15
|
+
const [canScrollRight, setCanScrollRight] = useState(true);
|
|
16
|
+
// 스크롤 위치 확인 함수
|
|
17
|
+
const checkScrollPosition = () => {
|
|
18
|
+
if (scrollContainerRef.current) {
|
|
19
|
+
const { scrollLeft, scrollWidth, clientWidth } = scrollContainerRef.current;
|
|
20
|
+
// 왼쪽 끝 확인 (약간의 여유값 포함)
|
|
21
|
+
setCanScrollLeft(scrollLeft > 5);
|
|
22
|
+
// 오른쪽 끝 확인 (약간의 여유값 포함)
|
|
23
|
+
setCanScrollRight(scrollLeft < scrollWidth - clientWidth - 5);
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
// 초기 로드시와 recentVideos 변경시 스크롤 위치 확인
|
|
27
|
+
useEffect(() => {
|
|
28
|
+
const timer = setTimeout(() => {
|
|
29
|
+
checkScrollPosition();
|
|
30
|
+
}, 100); // DOM 렌더링 후 확인
|
|
31
|
+
return () => clearTimeout(timer);
|
|
32
|
+
}, [recentVideos]);
|
|
33
|
+
// 스크롤 이벤트 리스너 등록
|
|
34
|
+
useEffect(() => {
|
|
35
|
+
const scrollContainer = scrollContainerRef.current;
|
|
36
|
+
if (scrollContainer) {
|
|
37
|
+
scrollContainer.addEventListener("scroll", checkScrollPosition);
|
|
38
|
+
return () => {
|
|
39
|
+
scrollContainer.removeEventListener("scroll", checkScrollPosition);
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
}, []);
|
|
43
|
+
const handleScroll = (direction) => {
|
|
44
|
+
if (scrollContainerRef.current) {
|
|
45
|
+
const scrollAmount = cardWidth;
|
|
46
|
+
const currentScrollLeft = scrollContainerRef.current.scrollLeft;
|
|
47
|
+
const newScrollLeft = direction === "left"
|
|
48
|
+
? Math.max(currentScrollLeft - scrollAmount, 0)
|
|
49
|
+
: currentScrollLeft + scrollAmount;
|
|
50
|
+
scrollContainerRef.current.scrollTo({
|
|
51
|
+
left: newScrollLeft,
|
|
52
|
+
behavior: "smooth",
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
const container = {
|
|
57
|
+
positions: "relative z-10 group",
|
|
58
|
+
displays: "flex flex-col",
|
|
59
|
+
textStyles: "break-keep antialiased",
|
|
60
|
+
};
|
|
61
|
+
const cardPositioning = {
|
|
62
|
+
displays: "flex flex-nowrap",
|
|
63
|
+
sizes: "w-screen",
|
|
64
|
+
};
|
|
65
|
+
const cardWrapper = {
|
|
66
|
+
sizes: "w-full overflow-x-auto scroll-smooth scrollbar-hidden scroll-px-[20px]",
|
|
67
|
+
display: "flex flex-nowrap vertical-top",
|
|
68
|
+
spacings: "px-5 pt-4 md:pt-6 pb-12",
|
|
69
|
+
snap: "snap-x snap-mandatory scroll-ms-0",
|
|
70
|
+
};
|
|
71
|
+
const cardDeck = {
|
|
72
|
+
displays: "inline-flex",
|
|
73
|
+
spacings: "gap-5 xl:mr-[calc(100vw-1200px)]",
|
|
74
|
+
};
|
|
75
|
+
const buttonPositioning = {
|
|
76
|
+
displays: "flex flex-row",
|
|
77
|
+
sizes: "w-full h-full",
|
|
78
|
+
spacings: "xl:pr-[calc(50vw-600px)] md:pr-[62px] pl-2 pr-4 gap-5",
|
|
79
|
+
positions: "justify-end items-center duration-300",
|
|
80
|
+
hovering: "group pointer-events-none",
|
|
81
|
+
};
|
|
82
|
+
const hoverButton = {
|
|
83
|
+
sizes: "rounded-full w-9 h-9",
|
|
84
|
+
animation: "duration-300",
|
|
85
|
+
test: "bg-gray-medium/50 hover:bg-gray-medium pointer-events-auto backdrop-blur-sm",
|
|
86
|
+
};
|
|
87
|
+
const disabledButton = {
|
|
88
|
+
sizes: "rounded-full w-9 h-9",
|
|
89
|
+
animation: "duration-300",
|
|
90
|
+
test: "bg-gray-medium/20 pointer-events-none backdrop-blur-sm opacity-30",
|
|
91
|
+
};
|
|
92
|
+
return (_jsx("div", { className: cn(container), children: _jsx("div", { className: cn(cardPositioning), children: _jsx("div", { className: cn(cardWrapper, "comp-customer-videos__cards o-content-container u-hide-on-tablet u-hide-on-mobile"), ref: scrollContainerRef, children: _jsx("div", { className: cn(cardDeck), children: recentVideos.map((video, index) => (_jsx(VideoCard, { video: video, isActive: index === activeVideoIndex, onHover: () => setActiveVideoIndex(index) }, video.id))) }) }) }) }));
|
|
93
|
+
}
|
|
94
|
+
function VideoCard({ video, isActive, onHover }) {
|
|
95
|
+
const ghostCard = {
|
|
96
|
+
displays: "flex",
|
|
97
|
+
spacings: "ms-0 ps-0",
|
|
98
|
+
scroll: "snap-start",
|
|
99
|
+
};
|
|
100
|
+
const card = {
|
|
101
|
+
graphics: "shadow-main",
|
|
102
|
+
sizes: isActive ? "w-96 md:w-[500px] h-72" : "w-56 md:w-72 h-72",
|
|
103
|
+
backgrounds: "bg-white",
|
|
104
|
+
hover: "hover:shadow-main-hover",
|
|
105
|
+
position: "xl:translate-x-[calc(50vw-665px)] md:translate-x-[56px]",
|
|
106
|
+
transition: "duration-500 ease-in-out",
|
|
107
|
+
displays: "relative display-block overflow-hidden",
|
|
108
|
+
fonts: "font-pretendard-var",
|
|
109
|
+
radius: "rounded-lg md:rounded-xl",
|
|
110
|
+
};
|
|
111
|
+
const videoContainer = {
|
|
112
|
+
sizes: "w-full h-full",
|
|
113
|
+
displays: "flex items-center justify-center",
|
|
114
|
+
backgrounds: "bg-black",
|
|
115
|
+
overflow: "overflow-hidden",
|
|
116
|
+
positions: "relative",
|
|
117
|
+
};
|
|
118
|
+
const titleBox = {
|
|
119
|
+
container: {
|
|
120
|
+
positions: "absolute inset-0 flex flex-col justify-center items-start z-10 gap-2",
|
|
121
|
+
sizes: "w-full h-full",
|
|
122
|
+
paddings: "p-4 md:p-6",
|
|
123
|
+
backgrounds: "bg-gradient-to-t from-black/70 via-black/30 to-transparent",
|
|
124
|
+
},
|
|
125
|
+
title: {
|
|
126
|
+
fonts: "text-xl md:text-2xl lg:text-3xl font-bold",
|
|
127
|
+
colors: "text-white",
|
|
128
|
+
},
|
|
129
|
+
subtitle: {
|
|
130
|
+
fonts: "text-sm md:text-base font-medium",
|
|
131
|
+
colors: "text-white/90",
|
|
132
|
+
transitions: "transition-all duration-300",
|
|
133
|
+
},
|
|
134
|
+
};
|
|
135
|
+
// 썸네일 URL: video.thumbnailUrl이 있으면 사용, 없으면 YouTube 썸네일 사용
|
|
136
|
+
const thumbnailUrl = video.thumbnailUrl || `https://img.youtube.com/vi/${video.youtubeId}/maxresdefault.jpg`;
|
|
137
|
+
return (_jsx("div", { className: cn(ghostCard), children: _jsx("div", { className: cn(card), onMouseEnter: onHover, children: _jsxs("div", { className: cn(videoContainer), children: [_jsx("div", { className: cn("w-full h-full transition-transform duration-500 ease-in-out relative", isActive ? "scale-110" : "scale-100"), children: _jsx("img", { src: thumbnailUrl, alt: video.title, className: "w-full h-full object-cover", onError: (e) => {
|
|
138
|
+
// thumbnailUrl이 제공되지 않은 경우에만 YouTube 썸네일로 대체
|
|
139
|
+
if (!video.thumbnailUrl) {
|
|
140
|
+
e.currentTarget.src = `https://img.youtube.com/vi/${video.youtubeId}/hqdefault.jpg`;
|
|
141
|
+
}
|
|
142
|
+
} }) }), _jsxs("div", { className: cn(titleBox.container), children: [_jsx("div", { className: cn(titleBox.title), children: video.title }), video.subTitle && (_jsx("div", { className: cn(titleBox.subtitle, isActive ? "opacity-100 max-h-20" : "opacity-0 max-h-0 overflow-hidden"), children: video.subTitle }))] })] }) }) }));
|
|
143
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useMemo } from "react";
|
|
3
|
+
import { cn } from "../../../util";
|
|
4
|
+
export default function Interviews({ interviews, onClick }) {
|
|
5
|
+
const sortedInterviews = useMemo(() => {
|
|
6
|
+
return [...interviews]
|
|
7
|
+
.sort((a, b) => {
|
|
8
|
+
// 먼저 index로 정렬
|
|
9
|
+
if (a.index !== b.index) {
|
|
10
|
+
return a.index - b.index;
|
|
11
|
+
}
|
|
12
|
+
// index가 같으면 createdAt으로 최신순 정렬
|
|
13
|
+
return new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime();
|
|
14
|
+
})
|
|
15
|
+
.slice(0, 3); // 최대 3개만 선택
|
|
16
|
+
}, [interviews]);
|
|
17
|
+
return (_jsx("div", { className: "w-full bg-[#0a0e27] py-16 px-5 md:px-8", children: _jsxs("div", { className: "max-w-7xl mx-auto", children: [_jsxs("div", { className: "flex flex-col md:flex-row justify-between items-start md:items-center mb-12", children: [_jsxs("div", { className: "flex flex-col gap-2 mb-4 md:mb-0", children: [_jsx("div", { className: "text-[#5b9bd5] text-sm md:text-base font-semibold", children: "SUCCESS STORIES" }), _jsx("h2", { className: "text-3xl md:text-4xl lg:text-5xl font-bold text-white", children: "TOSEL\uACFC \uD568\uAED8 \uC131\uC7A5\uD55C \uD559\uC0DD\uB4E4" })] }), _jsx("button", { onClick: (e) => onClick(e), className: "text-white underline text-sm md:text-base hover:text-[#5b9bd5] transition-colors", children: "\uB354 \uB9CE\uC740 \uC0AC\uB840 \uBCF4\uAE30" })] }), _jsx("div", { className: "grid grid-cols-1 md:grid-cols-3 gap-6 md:gap-8", children: sortedInterviews.map((interview, index) => {
|
|
18
|
+
if (!interview.profile)
|
|
19
|
+
return null;
|
|
20
|
+
const { profile } = interview;
|
|
21
|
+
const avatarColors = [
|
|
22
|
+
"bg-purple-500",
|
|
23
|
+
"bg-green-500",
|
|
24
|
+
"bg-gray-500"
|
|
25
|
+
];
|
|
26
|
+
const tagColors = [
|
|
27
|
+
{ bg: "bg-blue-600", text: "text-white" },
|
|
28
|
+
{ bg: "bg-green-600", text: "text-white" },
|
|
29
|
+
{ bg: "bg-purple-600", text: "text-white" }
|
|
30
|
+
];
|
|
31
|
+
const avatarColor = avatarColors[index % avatarColors.length];
|
|
32
|
+
const tagColor = tagColors[index % tagColors.length];
|
|
33
|
+
return (_jsxs("div", { className: "bg-[#1a1f3a] rounded-xl p-6 md:p-8 shadow-lg hover:shadow-xl transition-shadow duration-300 flex flex-col", children: [_jsxs("div", { className: "flex items-start gap-4 mb-4", children: [_jsx("div", { className: cn("w-12 h-12 md:w-14 md:h-14 rounded-full flex-shrink-0 flex items-center justify-center", avatarColor), children: profile.profileUrl ? (_jsx("img", { src: profile.profileUrl, alt: profile.name, className: "w-full h-full rounded-full object-cover" })) : (_jsx("div", { className: "text-white text-lg md:text-xl font-bold", children: profile.name.charAt(0) })) }), _jsxs("div", { className: "flex-1 min-w-0", children: [_jsx("div", { className: "text-white font-semibold text-base md:text-lg mb-1", children: profile.name }), _jsx("div", { className: "text-gray-400 text-sm md:text-base", children: profile.description })] })] }), profile.tag && (_jsx("div", { className: cn("inline-block px-3 py-1 rounded text-xs md:text-sm font-medium mb-4 w-fit", profile.tagBackgroundColor || tagColor.bg, profile.textColor || tagColor.text), children: profile.tag })), profile.content && (_jsxs("div", { className: "text-white text-sm md:text-base leading-relaxed mb-6 flex-1", children: ["\"", profile.content, "\""] }))] }, interview.id));
|
|
34
|
+
}) })] }) }));
|
|
35
|
+
}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { cn } from "../../../util";
|
|
3
|
+
import { useMemo } from "react";
|
|
4
|
+
// 날짜 포맷팅 함수
|
|
5
|
+
const formatDate = (date) => {
|
|
6
|
+
const year = date.getFullYear();
|
|
7
|
+
const month = String(date.getMonth() + 1).padStart(2, "0");
|
|
8
|
+
const day = String(date.getDate()).padStart(2, "0");
|
|
9
|
+
return `${year}.${month}.${day}`;
|
|
10
|
+
};
|
|
11
|
+
export default function News({ newsList }) {
|
|
12
|
+
// createdAt 기준으로 최신 4개 선택
|
|
13
|
+
const selectedNews = useMemo(() => {
|
|
14
|
+
const sorted = [...newsList]
|
|
15
|
+
.sort((a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime())
|
|
16
|
+
.slice(0, 4);
|
|
17
|
+
const main = sorted[0]; // 가장 최신 1개
|
|
18
|
+
const sub = sorted.slice(1, 4); // 나머지 3개
|
|
19
|
+
return { main, sub };
|
|
20
|
+
}, [newsList]);
|
|
21
|
+
if (!selectedNews.main) {
|
|
22
|
+
return _jsx("div", {});
|
|
23
|
+
}
|
|
24
|
+
const container = {
|
|
25
|
+
displays: "flex flex-col lg:flex-row lg:items-start",
|
|
26
|
+
spacings: "gap-6 lg:gap-8",
|
|
27
|
+
sizes: "w-full",
|
|
28
|
+
boundaries: "px-4 md:px-6 lg:px-8",
|
|
29
|
+
};
|
|
30
|
+
const leftCont = {
|
|
31
|
+
displays: "flex flex-col justify-start items-center lg:items-end",
|
|
32
|
+
sizes: "w-full lg:w-[51.5%]",
|
|
33
|
+
};
|
|
34
|
+
const mainArticle = {
|
|
35
|
+
displays: "flex flex-col lg:self-end",
|
|
36
|
+
sizes: "w-full max-w-full lg:max-w-2xl",
|
|
37
|
+
};
|
|
38
|
+
const imgArea = {
|
|
39
|
+
positions: "relative",
|
|
40
|
+
displays: "flex items-center justify-center group",
|
|
41
|
+
sizes: "w-full max-w-full lg:max-w-2xl h-64 md:h-72 lg:h-76 rounded-2xl overflow-hidden",
|
|
42
|
+
spacings: "mb-0 p-4 md:p-6 lg:p-8",
|
|
43
|
+
cursor: "cursor-pointer",
|
|
44
|
+
margins: "lg:ml-auto",
|
|
45
|
+
hover: "hover:scale-105",
|
|
46
|
+
transitions: "transition-transform duration-300",
|
|
47
|
+
};
|
|
48
|
+
const imgElm = {
|
|
49
|
+
positions: "absolute inset-0",
|
|
50
|
+
sizes: "w-full h-full",
|
|
51
|
+
backgrounds: "bg-cover bg-center",
|
|
52
|
+
filters: "brightness-50",
|
|
53
|
+
transitions: "transition-all duration-300",
|
|
54
|
+
};
|
|
55
|
+
const textElm = {
|
|
56
|
+
positions: "relative z-10",
|
|
57
|
+
displays: "flex flex-col",
|
|
58
|
+
spacings: "gap-4",
|
|
59
|
+
textStyles: "text-white",
|
|
60
|
+
};
|
|
61
|
+
const newsTitle = {
|
|
62
|
+
textStyles: "text-xl md:text-2xl lg:text-3xl font-bold leading-tight text-white",
|
|
63
|
+
};
|
|
64
|
+
const newsDesc = {
|
|
65
|
+
textStyles: "text-sm md:text-base lg:text-lg text-white/90 line-clamp-3",
|
|
66
|
+
};
|
|
67
|
+
const rightCont = {
|
|
68
|
+
displays: "flex flex-col justify-start",
|
|
69
|
+
sizes: "w-full lg:w-2/5 lg:max-w-lg",
|
|
70
|
+
};
|
|
71
|
+
const rightItem = {
|
|
72
|
+
displays: "flex flex-col",
|
|
73
|
+
sizes: "w-full min-h-[100px]",
|
|
74
|
+
spacings: "py-5 md:py-3 border-b border-gray-200 last:border-0",
|
|
75
|
+
};
|
|
76
|
+
const rightItemLink = {
|
|
77
|
+
displays: "flex items-start justify-between flex-col sm:flex-row",
|
|
78
|
+
spacings: "gap-3 sm:gap-4 md:gap-8",
|
|
79
|
+
cursor: "cursor-pointer",
|
|
80
|
+
hover: "hover:opacity-80",
|
|
81
|
+
transitions: "transition-opacity",
|
|
82
|
+
sizes: "w-full",
|
|
83
|
+
};
|
|
84
|
+
const textArea = {
|
|
85
|
+
displays: "flex flex-col",
|
|
86
|
+
sizes: "flex-1",
|
|
87
|
+
spacings: "gap-2",
|
|
88
|
+
};
|
|
89
|
+
const rightTitle = {
|
|
90
|
+
textStyles: "text-base md:text-lg font-bold text-gray-900 mb-2",
|
|
91
|
+
};
|
|
92
|
+
const rightDesc = {
|
|
93
|
+
textStyles: "text-sm md:text-base text-gray-600 line-clamp-2",
|
|
94
|
+
};
|
|
95
|
+
const rightDateArea = {
|
|
96
|
+
displays: "flex items-center",
|
|
97
|
+
sizes: "flex-shrink-0",
|
|
98
|
+
};
|
|
99
|
+
const rightDateText = {
|
|
100
|
+
textStyles: "text-xs md:text-sm text-gray-600 whitespace-nowrap",
|
|
101
|
+
};
|
|
102
|
+
return (_jsxs("div", { className: cn(container), children: [_jsx("div", { className: cn(leftCont), children: _jsx("article", { className: cn(mainArticle), children: _jsx("a", { href: "#", className: "block", children: _jsxs("div", { className: cn(imgArea), children: [_jsx("div", { className: cn(imgElm), style: { backgroundImage: `url(${selectedNews.main.imgUrl})` } }), _jsxs("div", { className: cn(textElm), children: [_jsx("h3", { className: cn(newsTitle), children: selectedNews.main.title }), selectedNews.main.subTitle && (_jsx("div", { className: cn(newsDesc), children: selectedNews.main.subTitle }))] })] }) }) }) }), _jsx("div", { className: cn(rightCont), children: selectedNews.sub.map((news) => {
|
|
103
|
+
const newsDate = new Date(news.createdAt);
|
|
104
|
+
return (_jsx("div", { className: cn(rightItem), children: _jsxs("a", { href: "#", className: cn(rightItemLink), children: [_jsxs("div", { className: cn(textArea), children: [_jsx("h5", { className: cn(rightTitle), children: news.title }), news.subTitle && (_jsx("p", { className: cn(rightDesc), children: news.subTitle }))] }), _jsx("div", { className: cn(rightDateArea), children: _jsx("span", { className: cn(rightDateText), children: formatDate(newsDate) }) })] }) }, news.id));
|
|
105
|
+
}) })] }));
|
|
106
|
+
}
|
|
@@ -7,6 +7,9 @@ import Service from "./Service";
|
|
|
7
7
|
import Shortcut from "./Shortcut";
|
|
8
8
|
import Float from "./Float";
|
|
9
9
|
import Session from "./Session";
|
|
10
|
+
import News from "./News";
|
|
11
|
+
import Education from "./Education";
|
|
12
|
+
import Interviews from "./Interviews";
|
|
10
13
|
declare const Home: {
|
|
11
14
|
Layout: typeof Layout;
|
|
12
15
|
Navigation: typeof Navigation;
|
|
@@ -17,5 +20,8 @@ declare const Home: {
|
|
|
17
20
|
NewsPaper: typeof NewsPaper;
|
|
18
21
|
Float: typeof Float;
|
|
19
22
|
Session: typeof Session;
|
|
23
|
+
News: typeof News;
|
|
24
|
+
Education: typeof Education;
|
|
25
|
+
Interviews: typeof Interviews;
|
|
20
26
|
};
|
|
21
27
|
export default Home;
|
|
@@ -7,6 +7,9 @@ import Service from "./Service";
|
|
|
7
7
|
import Shortcut from "./Shortcut";
|
|
8
8
|
import Float from "./Float";
|
|
9
9
|
import Session from "./Session";
|
|
10
|
+
import News from "./News";
|
|
11
|
+
import Education from "./Education";
|
|
12
|
+
import Interviews from "./Interviews";
|
|
10
13
|
const Home = {
|
|
11
14
|
Layout,
|
|
12
15
|
Navigation,
|
|
@@ -16,6 +19,9 @@ const Home = {
|
|
|
16
19
|
Service,
|
|
17
20
|
NewsPaper,
|
|
18
21
|
Float,
|
|
19
|
-
Session
|
|
22
|
+
Session,
|
|
23
|
+
News,
|
|
24
|
+
Education,
|
|
25
|
+
Interviews
|
|
20
26
|
};
|
|
21
27
|
export default Home;
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ExtendedButton } from "./Header";
|
|
2
|
+
import { OnClick } from "../../../../interface";
|
|
2
3
|
import { ReactNode } from "react";
|
|
3
4
|
export default function Layout({ contents, children, logo, rightButton, option, }: {
|
|
4
|
-
contents:
|
|
5
|
+
contents: ExtendedButton[];
|
|
5
6
|
children: React.ReactNode;
|
|
6
7
|
logo: {
|
|
7
8
|
node: ReactNode;
|
package/package.json
CHANGED
package/version.txt
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
1.0.
|
|
1
|
+
1.0.354
|