@edu-tosel/design 1.0.154 → 1.0.156

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.
Files changed (41) hide show
  1. package/asset/SVG.d.ts +11 -9
  2. package/asset/SVG.js +2 -0
  3. package/asset/SVG.tsx +4 -2
  4. package/asset/svg/Eye.d.ts +12 -0
  5. package/asset/svg/Eye.js +13 -0
  6. package/asset/svg/Eye.tsx +48 -0
  7. package/asset/svg/Icon.d.ts +7 -6
  8. package/asset/svg/Icon.js +10 -10
  9. package/asset/svg/Icon.tsx +17 -16
  10. package/card/design/Card.design.js +4 -2
  11. package/card/design/RollCard.design.js +1 -1
  12. package/card/template/InfoCard/Finance.js +1 -1
  13. package/card/template/InfoCard/Student.d.ts +2 -2
  14. package/card/template/InfoCard/Student.js +6 -11
  15. package/card/template/NavCard.js +1 -1
  16. package/card/template/ProgressCard/Large.js +1 -1
  17. package/interface/Property.d.ts +1 -1
  18. package/layout/design/Row.design/index.js +1 -0
  19. package/layout/index.d.ts +1 -0
  20. package/layout/index.js +1 -0
  21. package/layout/template/Archive/Header.js +66 -41
  22. package/layout/template/BbsLayout.js +3 -1
  23. package/layout/template/Event/One.js +39 -1
  24. package/layout/template/MonthlyProgressReport/Report.d.ts +36 -0
  25. package/layout/template/MonthlyProgressReport/Report.js +80 -0
  26. package/layout/template/MonthlyProgressReport/index.d.ts +5 -0
  27. package/layout/template/MonthlyProgressReport/index.js +5 -0
  28. package/layout/template/home/layout/Header.js +72 -15
  29. package/layout/template/home/layout/Navigation.d.ts +4 -2
  30. package/layout/template/home/layout/Navigation.js +56 -20
  31. package/package.json +2 -1
  32. package/tailwind.config.ts +20 -0
  33. package/util/compareDates.d.ts +4 -0
  34. package/util/compareDates.js +32 -0
  35. package/util/convertDateToString.d.ts +1 -0
  36. package/util/convertDateToString.js +6 -0
  37. package/util/index.d.ts +2 -0
  38. package/util/index.js +2 -0
  39. package/version.txt +1 -1
  40. package/widget/template/Input/Form.js +10 -2
  41. package/widget/template/Select/Select.js +30 -17
@@ -1,10 +1,48 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { cn, isHTMLString } from "../../../util";
3
3
  import { StatusText } from "./StatusText";
4
+ import { useState, useEffect } from "react";
4
5
  export default function One({ event }) {
6
+ const [currentTime, setCurrentTime] = useState(new Date());
7
+ useEffect(() => {
8
+ const timer = setInterval(() => setCurrentTime(new Date()), 1000);
9
+ return () => clearInterval(timer);
10
+ }, []);
5
11
  const button = () => ({
6
12
  sizes: "w-full h-12 flex items-center justify-center rounded-md text-white cursor-pointer font-bold gap-3 text-sm xs:text-md",
7
13
  backgrounds: "bg-gradient-to-l from-[#760023] to-[#105652]",
8
14
  });
9
- return (_jsxs("div", { className: "flex flex-col mmd:flex-row", children: [_jsx("div", { className: "min-w-[320px] h-auto p-5 mmd:sticky mmd:top-20 mmd:self-start", children: _jsxs("div", { className: "w-full h-auto rounded-xl sm:flex mmd:flex-col", children: [_jsx("div", { className: "w-full mmd:h-50 overflow-hidden", children: _jsx("img", { src: event.thumbnail, alt: "", className: "rounded-xl h-full object-cover w-full" }) }), _jsxs("div", { className: "w-full h-auto pt-5 sm:p-5 mmd:p-0 mmd:pt-5 gap-3 flex flex-col", children: [_jsx("div", { className: "flex items-center", children: _jsx(StatusText, { event: event }) }), _jsx("div", { className: "text-sm font-bold text-gray-dark flex items-center mb-2", children: event.title }), event.button && (_jsx("div", { onClick: event.button.onClick, className: cn(button()), children: event.button?.title }))] })] }, event.id) }), _jsxs("div", { className: "flex-grow p-5", children: [_jsx("div", { children: isHTMLString(event.content) ? (_jsx("div", { dangerouslySetInnerHTML: { __html: event.content }, className: "w-full rounded-xl object-cover overflow-hidden" })) : (_jsx("div", { children: event.content })) }), _jsx("button", { onClick: () => history.back(), className: "p-5 bg-green-dark/5 text-green-dark rounded-xl flex items-center justify-center hover:bg-green-dark/20 transition-all", children: "\uBAA9\uB85D\uC73C\uB85C \uB3CC\uC544\uAC00\uAE30" })] })] }));
15
+ // 현재는 startedAt과 expiredAt 모두 시각은 09:00:00 으로 설정되어 있습니다.
16
+ const startedAt = event.startedAt ? new Date(event.startedAt) : null;
17
+ const expiredAt = event.expiredAt ? new Date(event.expiredAt) : null;
18
+ let buttonContent = null;
19
+ if (startedAt && expiredAt) {
20
+ const timeDiff = startedAt.getTime() - currentTime.getTime();
21
+ const daysRemaining = Math.floor(timeDiff / (1000 * 60 * 60 * 24));
22
+ const hoursRemaining = Math.floor((timeDiff / (1000 * 60 * 60)) % 24);
23
+ const minutesRemaining = Math.floor((timeDiff / (1000 * 60)) % 60);
24
+ const secondsRemaining = Math.floor((timeDiff / 1000) % 60);
25
+ if (startedAt < currentTime && currentTime < expiredAt) {
26
+ buttonContent = (_jsx("div", { onClick: event.button?.onClick, className: cn(button()), children: event.button?.title }));
27
+ }
28
+ else if (currentTime < startedAt) {
29
+ const countdownText = daysRemaining > 0
30
+ ? `오픈까지 D-${daysRemaining}`
31
+ : `오픈까지 ${hoursRemaining
32
+ .toString()
33
+ .padStart(2, "0")}:${minutesRemaining
34
+ .toString()
35
+ .padStart(2, "0")}:${secondsRemaining
36
+ .toString()
37
+ .padStart(2, "0")} 남음`;
38
+ buttonContent = (_jsx("div", { className: "w-full h-12 flex items-center justify-center rounded-md bg-gray-light text-green-dark font-bold gap-3 text-sm xs:text-md", children: countdownText }));
39
+ }
40
+ else if (expiredAt < currentTime) {
41
+ buttonContent = (_jsx("div", { className: "w-full h-12 flex items-center justify-center rounded-md bg-gray-light text-gray-medium font-bold gap-3 text-sm xs:text-md", children: "\uC774\uBCA4\uD2B8\uAC00 \uB9C8\uAC10\uB418\uC5C8\uC5B4\uC694" }));
42
+ }
43
+ }
44
+ else {
45
+ buttonContent = _jsx("div", { className: cn(button()), children: event.button?.title });
46
+ }
47
+ return (_jsxs("div", { className: "flex flex-col mmd:flex-row", children: [_jsx("div", { className: "min-w-[320px] h-auto p-5 mmd:sticky mmd:top-20 mmd:self-start", children: _jsxs("div", { className: "w-full h-auto rounded-xl sm:flex mmd:flex-col", children: [_jsx("div", { className: "w-full mmd:h-50 overflow-hidden", children: _jsx("img", { src: event.thumbnail, alt: "", className: "rounded-xl h-full object-cover w-full" }) }), _jsxs("div", { className: "w-full h-auto pt-5 sm:p-5 mmd:p-0 mmd:pt-5 gap-3 flex flex-col", children: [_jsx("div", { className: "flex items-center", children: _jsx(StatusText, { event: event }) }), _jsx("div", { className: "text-sm font-bold text-gray-dark flex items-center mb-2", children: event.title }), buttonContent] })] }, event.id) }), _jsxs("div", { className: "flex-grow p-5", children: [_jsx("div", { children: isHTMLString(event.content) ? (_jsx("div", { dangerouslySetInnerHTML: { __html: event.content }, className: "w-full rounded-xl object-cover overflow-hidden max-w-[810px]" })) : (_jsx("div", { children: event.content })) }), _jsx("button", { onClick: () => history.back(), className: "mt-8 p-5 bg-green-dark/5 text-green-dark rounded-xl flex items-center justify-center hover:bg-green-dark/20 transition-all", children: "\uBAA9\uB85D\uC73C\uB85C \uB3CC\uC544\uAC00\uAE30" })] })] }));
10
48
  }
@@ -0,0 +1,36 @@
1
+ export interface Result {
2
+ createdTimeStamp: number;
3
+ updatedTimeStamp: number;
4
+ academyId: number;
5
+ etc: null;
6
+ report: {
7
+ section1Part1: number;
8
+ section1Part2: number;
9
+ section1Part3: number;
10
+ section1Part4: null;
11
+ section2Part1: number;
12
+ section2Part2: number;
13
+ section2Part3: number;
14
+ section2Part4: null;
15
+ };
16
+ id: number;
17
+ setId: number;
18
+ level: string;
19
+ answers: number[];
20
+ userId: number;
21
+ }
22
+ interface ProgressReportProps {
23
+ studentInfo: {
24
+ name: string;
25
+ birthday: string;
26
+ belong?: string;
27
+ academy?: string;
28
+ };
29
+ results: Result[];
30
+ recentResult: Result & {
31
+ examName: string;
32
+ };
33
+ comment: string | string[];
34
+ }
35
+ export default function ProgressReport({ studentInfo, recentResult, comment, }: ProgressReportProps): import("react/jsx-runtime").JSX.Element;
36
+ export {};
@@ -0,0 +1,80 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { InfoCard } from "../../../card";
3
+ import CardDesign from "../../../card/design/Card.design";
4
+ import { LineBreaks } from "../../../text";
5
+ import { cn } from "../../../util";
6
+ import { ResponsiveContainer, XAxis, YAxis, LineChart, Line, Legend, } from "recharts";
7
+ import moment from "moment-timezone";
8
+ export default function ProgressReport({ studentInfo, recentResult, comment, }) {
9
+ const container = {
10
+ displays: "flex justify-between ",
11
+ sizes: "w-[297mm] h-[210mm]",
12
+ boundaries: "border-2 px-10 pt-7 pb-9 border-gray-medium",
13
+ fonts: "font-pretendard-var",
14
+ };
15
+ const leftBody = {
16
+ displays: "flex flex-col gap-y-7.5",
17
+ };
18
+ const rightBody = {
19
+ displays: "flex flex-col",
20
+ };
21
+ const calculate = (result, type) => {
22
+ const section1 = Object.values(result.report)
23
+ .slice(0, 4)
24
+ .filter((v) => v !== null)
25
+ .reduce((acc, cur) => Number(acc) + Number(cur), 0);
26
+ const section2 = Object.values(result.report)
27
+ .slice(4, 8)
28
+ .filter((v) => v !== null)
29
+ .reduce((acc, cur) => Number(acc) + Number(cur), 0);
30
+ const total = (section1 ?? 0) + (section2 ?? 0);
31
+ if (type === "section1")
32
+ return section1;
33
+ if (type === "section2")
34
+ return section2;
35
+ return total;
36
+ };
37
+ const circle = {
38
+ displays: "flex items-center justify-center",
39
+ sizes: "aspect-square ",
40
+ styles: "rounded-full border-gray-dark border-8",
41
+ fonts: "text-5xl font-bold text-blue-navy",
42
+ };
43
+ return (_jsxs("div", { className: cn(container), children: [_jsxs("div", { className: cn(leftBody), children: [_jsxs("div", { className: "flex flex-col text-blue-navy pl-4 border-l-4 border-blue-navy", children: [_jsx("div", { className: "flex items-center", children: _jsx("img", { src: "/images/logos/lab-spiral.png", alt: "lab" }) }), _jsx("div", { className: "text-2xl leading-tight font-bold", children: "MONTHLY PROGRESS REPORT" })] }), _jsxs("div", { className: "flex flex-col justify-between h-full", children: [_jsx(InfoCard.Student, { titles: {
44
+ title: studentInfo.name,
45
+ subtitle: studentInfo.birthday,
46
+ }, image: "/images/mock/haerin.jpeg", data: {
47
+ belong: studentInfo.belong,
48
+ academy: studentInfo.academy,
49
+ }, option: {
50
+ boundary: "border-2 border-blue-navy",
51
+ } }), _jsx("div", { className: "h-96", children: _jsxs(CardDesign, { option: {
52
+ height: "full",
53
+ boundary: "border-2 border-blue-navy pt-5 px-6 pb-6",
54
+ }, children: [_jsxs("div", { className: "flex flex-col justify-center border-b-3 border-blue-navy pb-2.5", children: [_jsx("div", { className: " text-lg font-bold", children: "\uCD5C\uADFC \uC2DC\uD5D8" }), _jsx("div", { children: recentResult.examName })] }), _jsxs("div", { className: "flex flex-col gap-y-7.5 absolute bottom-0 w-full px-3.5", children: [_jsxs("div", { className: "flex gap-x-12 justify-between w-full", children: [_jsxs("div", { className: "flex-1 ", children: [_jsx("div", { className: "text-center mb-3.5 text-lg", children: "SECTION I" }), _jsx("div", { className: cn(circle), children: calculate(recentResult, "section1") })] }), _jsxs("div", { className: "flex-1", children: [_jsx("div", { className: "text-center mb-3.5 text-lg", children: "SECTION II" }), _jsx("div", { className: cn(circle), children: calculate(recentResult, "section2") })] })] }), _jsxs("div", { className: "flex gap-x-2 justify-end items-end font-bold text-blue-navy", children: [_jsx("div", { className: "text-xl", children: "total" }), _jsx("div", { className: "text-5xl leading-none ", children: calculate(recentResult) })] })] })] }) })] })] }), _jsxs("div", { className: cn(rightBody), children: [_jsx("div", { className: "h-12 flex justify-end text-blue-navy font-bold", children: _jsx("div", { children: moment(new Date()).format("YYYY-MM-DD HH:mm:ss") }) }), _jsxs("div", { className: "flex flex-col justify-between h-full", children: [_jsx("div", { className: "h-88", children: _jsx(CardDesign, { option: {
55
+ width: "xl",
56
+ height: "full",
57
+ boundary: "border-2 border-blue-navy",
58
+ }, children: _jsx(ResponsiveContainer, { width: "95%", height: "95%", className: "absolute left-0 bottom-0", children: _jsxs(LineChart, { data: [
59
+ {
60
+ date: "2024-03-01",
61
+ score: 34,
62
+ },
63
+ {
64
+ date: "2024-03-02",
65
+ score: 45,
66
+ },
67
+ // {
68
+ // date: "2024-03-03",
69
+ // score: 47,
70
+ // },
71
+ // {
72
+ // date: "2024-03-04",
73
+ // score: 53,
74
+ // },
75
+ ], children: [_jsx(XAxis, { dataKey: "date" }), _jsx(YAxis, { dataKey: "score", scale: "log", domain: ["auto", "auto"] }), _jsx(Line, { type: "monotone", name: "Monthly Test", dataKey: "score", stroke: "#173A8B", fill: "#173A8B" }), _jsx(Legend, {})] }) }) }) }), _jsx("div", { className: "h-72", children: _jsxs(CardDesign, { option: {
76
+ width: "xl",
77
+ height: "full",
78
+ boundary: "border-2 border-blue-navy p-5",
79
+ }, children: [_jsx("div", { className: "text-gray-dark font-bold text-lg", children: "\uC6D0\uC7A5\uB2D8\uC758 \uCF54\uBA58\uD2B8" }), _jsx("div", { className: "h-52 overflow-y-scroll scrollbar-hidden text-sm mt-2.5", children: _jsx(LineBreaks, { texts: comment }) })] }) })] })] })] }));
80
+ }
@@ -0,0 +1,5 @@
1
+ import Report from "./Report";
2
+ declare const MonthlyProgressReport: {
3
+ Report: typeof Report;
4
+ };
5
+ export default MonthlyProgressReport;
@@ -0,0 +1,5 @@
1
+ import Report from "./Report";
2
+ const MonthlyProgressReport = {
3
+ Report,
4
+ };
5
+ export default MonthlyProgressReport;
@@ -1,31 +1,88 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useState, useEffect } from "react";
2
3
  import { cn, gradient } from "../../../../util";
3
4
  import { Label } from "../../../../widget";
5
+ import { useResponsive } from "../../../../hook";
4
6
  export default function Header({ logo, rightButton, contents, }) {
7
+ const [isExpanded, setIsExpanded] = useState(false);
8
+ const toggleHeight = () => {
9
+ setIsExpanded(!isExpanded);
10
+ };
11
+ const handleClickOutside = (event) => {
12
+ const menuElement = document.getElementById("buttonArea");
13
+ if (menuElement && !menuElement.contains(event.target)) {
14
+ setIsExpanded(false);
15
+ }
16
+ };
17
+ //버튼, 혹은 외부를 클릭시 메뉴 닫음
18
+ useEffect(() => {
19
+ if (isExpanded) {
20
+ document.addEventListener("click", handleClickOutside);
21
+ }
22
+ else {
23
+ document.removeEventListener("click", handleClickOutside);
24
+ }
25
+ return () => {
26
+ document.removeEventListener("click", handleClickOutside);
27
+ };
28
+ }, [isExpanded]);
29
+ const isMD = useResponsive("md");
30
+ //메뉴바 배경
5
31
  const container = {
6
- positions: "fixed top-0 left-0 z-40",
7
- displays: "flex justify-center items-center",
32
+ positions: "fixed top-0 left-0 z-40 md:h-15",
33
+ displays: "flex justify-center items-start overflow-hidden",
8
34
  sizes: "w-full",
9
35
  styles: "bg-white box-shadow",
10
36
  textstyles: "antialiased",
37
+ animation: !isMD && isExpanded ? "animate-grow" : "animate-shrink"
11
38
  };
12
39
  const body = {
13
- displays: "flex items-center justify-center md:justify-between",
14
- className: "w-full max-w-[1200px] h-15",
15
- boundaries: "md:px-12 py-2.5",
40
+ displays: "flex md:flex-row flex-col md:items-center items-start justify-between",
41
+ className: "w-full max-w-[1200px]",
42
+ boundaries: "p-0 sm:px-12",
43
+ };
44
+ const buttonBoxWrapper = {
45
+ displays: "inline-flex items-center flex-nowrap",
46
+ scrollStyles: "overflow-y-scroll scrollbar-hidden",
47
+ spacings: "pr-10 gap-2.5 h-15 md:pr-0",
16
48
  };
17
49
  const buttonBox = {
18
- fonts: "text-[9px] xs:text-[10px] sm:text-[11px] md:text-[16px] leading-tight",
50
+ fonts: "text-base leading-tight",
19
51
  texts: "text-gray-dark hover:text-black",
20
52
  backgrounds: "hover:bg-[#F0F0F0]/50",
21
53
  animations: "duration-300",
22
- sizes: "h-10 rounded-md",
23
- boundaries: "px-0.5 md:px-2.5",
24
- };
25
- return (_jsx("div", { className: cn(container), children: _jsxs("div", { className: cn(body), children: [_jsx("div", { className: "hidden md:block", onClick: logo.onClick, children: logo.node }), _jsxs("div", { className: "flex items-center gap-x-7.5 md:gap-x-12", children: [_jsx("div", { className: "flex items-center gap-2.5", children: contents.map((button, index) => (_jsx("button", { onClick: button.onClick, className: cn(buttonBox), children: button.title }, index))) }), rightButton && (_jsx(Label.Button, { title: rightButton.title, onClick: rightButton?.onClick, option: {
26
- width: "2xs",
27
- height: "4xs",
28
- background: gradient.bg.greenToRed,
29
- text: "text-white",
30
- } }))] })] }) }));
54
+ sizes: "h-10 rounded-md w-fit flex-none",
55
+ spacings: "px-2.5",
56
+ scrollMargin: "translate-x-5 md:translate-x-0 "
57
+ };
58
+ const leftWrapper = {
59
+ displays: "flex flex-row gap-6 items-center flex-none",
60
+ sizes: "w-full md:w-fit justify-between md:justify-start pl-5 pr-2 sm:px-0",
61
+ };
62
+ const rightWrapper = {
63
+ displays: "flex flex-row justify-center md:justify-start",
64
+ spacings: "items-center gap-x-6 ml:gap-x-12 ",
65
+ sizes: "w-full md:w-fit",
66
+ boundaries: "border-gray-light border-t-2",
67
+ };
68
+ const essenstialsWrapper = {
69
+ displays: "flex flex-row items-center h-15",
70
+ spacings: "gap-2 md:gap-6",
71
+ sizes: "h-15",
72
+ responsiveAction: "block md:hidden",
73
+ };
74
+ const menuButton = {
75
+ displays: "flex justify-center items-center p-2",
76
+ };
77
+ 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: {
78
+ width: "2xs",
79
+ height: "xs",
80
+ background: gradient.bg.greenToRed,
81
+ 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: {
83
+ width: "2xs",
84
+ height: "xs",
85
+ background: gradient.bg.greenToRed,
86
+ text: "text-white",
87
+ } })) })] })] }) }));
31
88
  }
@@ -5,9 +5,11 @@ interface Browser {
5
5
  interface Calendar {
6
6
  schedules: {
7
7
  onClick?: OnClick;
8
- category: string;
9
8
  title: string;
10
- description?: string | [string] | [string, string];
9
+ applyDay: Date;
10
+ testStart: Date;
11
+ testEnd?: Date;
12
+ gradeOpen: Date;
11
13
  }[];
12
14
  }
13
15
  interface Notice {
@@ -2,26 +2,23 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
2
2
  import { useEffect, useState } from "react";
3
3
  import { animated, useTransition } from "react-spring";
4
4
  import SVG from "../../../../asset/SVG";
5
- import { cn } from "../../../../util";
5
+ import { cn, compareDates, convertDateToString } from "../../../../util";
6
6
  import { useActionStore } from "../../../../store";
7
7
  import { LineBreaks } from "../../../../text";
8
+ import { useResponsive } from "../../../../hook";
8
9
  export default function Navigation({ browser, calendar, notice, event, }) {
9
10
  const { flag } = useActionStore();
10
11
  const [isOpen, setIsOpen] = useState(false);
11
12
  const [isHidden, setIsHidden] = useState(false);
12
13
  const [type, setType] = useState();
13
14
  const container = {
14
- displays: "flex flex-col justify-center gap-y-5 items-center",
15
- sizes: !isOpen ? "h-80 rounded-r-xl" : "h-screen",
16
- widths: !isHidden ? "w-[56px] duration-100" : "w-0 duration-500",
17
- backgrounds: "bg-gradient-to-b from-green-dark to-crimson-burgundy",
15
+ displays: "flex flex-row md:flex-col justify-center gap-x-8 sm:gap-x-12 gap-y-5 items-center",
16
+ sizes: !isOpen ? "h-16 md:h-80 md:rounded-r-xl" : "h-16 md:h-screen",
17
+ widths: !isHidden
18
+ ? "w-screen md:w-[56px] duration-100"
19
+ : "w-0 duration-100",
20
+ backgrounds: "bg-gradient-to-r md:bg-gradient-to-b from-green-dark to-crimson-burgundy",
18
21
  };
19
- const overlayPopTransition = useTransition(!isHidden && isOpen, {
20
- from: { width: "0%" },
21
- enter: { width: "30%" },
22
- leave: { width: "0%" },
23
- config: { duration: 100 },
24
- });
25
22
  const overlayCoverTransition = useTransition(isHidden, {
26
23
  from: { width: "0%" },
27
24
  enter: { width: "100%" },
@@ -47,27 +44,66 @@ export default function Navigation({ browser, calendar, notice, event, }) {
47
44
  };
48
45
  const itemContainer = {
49
46
  positions: "fixed top-0 left-0 z-40 ",
50
- sizes: "h-screen ",
51
- boundaries: "pl-[56px]",
52
- styles: "overflow-hidden bg-white ",
47
+ sizes: "h-screen w-[400px]",
48
+ boundaries: "md:pl-[56px]",
49
+ styles: "overflow-hidden bg-black/20 backdrop-blur-sm",
50
+ shadows: "shadow-main",
53
51
  };
54
52
  const itemBody = {
55
- boundaries: "px-7.5 pt-[34px]",
53
+ positions: "absolute bottom-16 md:static md:bottom-auto ",
54
+ sizes: "w-full md:w-[556px] h-80 md:h-screen",
55
+ boundaries: "p-5",
56
+ styles: "bg-white overflow-hidden",
57
+ };
58
+ const iconWrapper = {
59
+ displays: "flex justify-center items-center",
60
+ sizes: "w-8 h-8 rounded-md",
61
+ animations: "hover:bg-white/20",
56
62
  };
63
+ const isMobile = useResponsive("md");
64
+ const overlayPopTransition = useTransition(!isHidden && isOpen, {
65
+ from: { width: "0%" },
66
+ enter: { width: "100%" },
67
+ leave: { width: "0%" },
68
+ config: { duration: isMobile ? 100 : 0 },
69
+ });
57
70
  return (_jsxs(_Fragment, { children: [overlayCoverTransition((styles, item) => item && (_jsxs(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: [_jsx("img", { src: "/images/logos/tosel.png", alt: "tosel", width: 368.56, height: 80.07 }), _jsx("div", { children: "dashboard loading..." })] }))), overlayPopTransition((styles, item) => type &&
58
- item && (_jsx(animated.div, { style: styles, className: cn(itemContainer), children: _jsxs("div", { className: cn(itemBody), children: [_jsx("div", { className: "text-[26px] font-bold text-gradient-green-to-red ", children: navigationTypeString[type] }), _jsx(NavigationItem, { type: type, calendar: calendar, notice: notice, event: event })] }) }))), _jsx("div", { className: "fixed top-1/2 -translate-y-1/2 flex justify-center items-center z-45", children: _jsxs("div", { onClick: (e) => e.stopPropagation(), className: cn(container), children: [_jsx(SVG.Icon.Calendar, { onClick: () => handleOpen("calendar") }), _jsx(SVG.Icon.Notification, { onClick: () => handleOpen("notification") }), _jsx(SVG.Icon.Search, { onClick: () => handleOpen("search") }), _jsx(SVG.Icon.Browser, { onClick: () => handleOpen("browser") }), _jsx(SVG.Icon.Event, { onClick: () => handleOpen("event") })] }) })] }));
71
+ item && (_jsx(animated.div, { style: styles, className: cn(itemContainer), children: _jsxs("div", { className: cn(itemBody), children: [_jsx("div", { className: "text-[20px] font-bold text-green-dark ", children: navigationTypeString[type] }), _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("div", { className: cn(iconWrapper), onClick: () => handleOpen("calendar"), children: _jsx(SVG.Icon.Calendar, { size: isMobile ? "md" : "lg" }) }), _jsx("div", { className: cn(iconWrapper), onClick: () => handleOpen("notification"), children: _jsx(SVG.Icon.Notification, { size: isMobile ? "md" : "lg" }) }), _jsx("div", { className: cn(iconWrapper), onClick: () => handleOpen("search"), children: _jsx(SVG.Icon.Search, { size: isMobile ? "md" : "lg" }) }), _jsx("div", { className: cn(iconWrapper), onClick: () => handleOpen("browser"), children: _jsx(SVG.Icon.Browser, { size: isMobile ? "md" : "lg" }) }), _jsx("div", { className: cn(iconWrapper), onClick: () => handleOpen("event"), children: _jsx(SVG.Icon.Event, { size: isMobile ? "md" : "lg" }) })] }) })] }));
59
72
  }
60
73
  const navigationTypeString = {
61
- calendar: "시험 일정",
74
+ calendar: "시험 접수 일정",
62
75
  notification: "공지사항",
63
76
  event: "이벤트",
64
77
  };
65
78
  function NavigationItem({ type, calendar, notice, event, }) {
79
+ const cardWrapper = {
80
+ displays: "flex flex-col gap-y-5",
81
+ };
82
+ const cardBox = {
83
+ displays: "",
84
+ sizes: "",
85
+ };
86
+ const dateWrapper = {
87
+ displays: "flex flex-row gap-3",
88
+ };
89
+ const dateText = {
90
+ textStyles: "font-bold font-pretendar-var font-sm font-gray-dark",
91
+ spacings: "leading-normal",
92
+ };
93
+ const container = {
94
+ styles: "relative mt-[34px] scrollbar-hidden flex flex-row md:flex-col gap-y-[15px] md:h-screen overflow-x-scroll md:overflow-y-scroll",
95
+ };
96
+ const item = {
97
+ displays: "flex-shrink-0 flex flex-col md:justify-between ",
98
+ };
66
99
  if (type === "calendar")
67
- return (_jsx("div", { className: "mt-[34px] flex flex-col gap-y-[15px]", children: calendar.schedules.map(({ category, title, description, onClick }) => (_jsxs("div", { onClick: onClick, className: "flex flex-col justify-between w-full h-[184px] box-shadow rounded-[10px] p-7.5", children: [_jsxs("div", { children: [_jsx("div", { className: "text-[15px] text-gray-medium", children: category }), _jsx("div", { className: "text-[20px] font-bold text-gray-dark", children: title })] }), _jsx(LineBreaks, { texts: description, className: "text-gray-dark text-[18px]" })] }))) }));
100
+ return (_jsx("div", { className: cn(container), children: calendar.schedules.map(({ applyDay, onClick }) => {
101
+ const { isBefore } = compareDates(applyDay);
102
+ return (_jsx("div", { onClick: onClick, className: cn(item, "w-[400px] md:w-full h-[184px] shadow-main rounded-[10px] p-7.5"), children: _jsxs("div", { children: [_jsx("div", { className: "text-[16px] font-bold text-gray-dark", children: convertDateToString(applyDay) }), _jsx("div", { children: isBefore && _jsx("p", { children: "\uC811\uC218\uC911" }) })] }) }));
103
+ }) }));
68
104
  if (type === "notification")
69
- return (_jsx("div", { className: "mt-[34px] flex flex-col gap-y-[15px]", children: notice.announcements.map(({ title, date, description, onClick }) => (_jsxs("div", { onClick: onClick, className: "flex flex-col justify-between w-full h-[140px] box-shadow rounded-[10px] p-7.5", children: [_jsxs("div", { children: [_jsx("div", { className: "text-[15px] text-gray-medium", children: date }), _jsx("div", { className: "text-[20px] font-bold text-gray-dark", children: title })] }), _jsx(LineBreaks, { texts: description, className: "text-gray-dark text-[18px]" })] }))) }));
105
+ return (_jsx("div", { className: cn(container), children: notice.announcements.map(({ title, date, description, onClick }) => (_jsxs("div", { onClick: onClick, className: cn(item, "h-[140px] box-shadow rounded-[10px] p-7.5"), children: [_jsxs("div", { children: [_jsx("div", { className: "text-[15px] text-gray-medium", children: date }), _jsx("div", { className: "text-[20px] font-bold text-gray-dark", children: title })] }), _jsx(LineBreaks, { texts: description, className: "text-gray-dark text-[18px]" })] }))) }));
70
106
  if (type === "event")
71
- return (_jsx("div", { className: "mt-[34px] flex flex-col gap-y-[15px]", children: event.events.map(({ title, category, thumbnail, onClick }) => (_jsxs("div", { onClick: onClick, className: "flex flex-col justify-between w-full box-shadow rounded-[10px] p-7.5", children: [_jsxs("div", { className: "h-[92px] border-b-2", children: [_jsx("div", { className: "text-[15px] text-gray-medium", children: category }), _jsx("div", { className: "text-[20px] font-bold text-gray-dark", children: title })] }), _jsx("div", { className: "image-container pt-[15px]", children: _jsx("img", { src: thumbnail, alt: title, className: "w-full" }) })] }))) }));
107
+ return (_jsx("div", { className: cn(container), children: event.events.map(({ title, thumbnail, onClick }) => (_jsx("div", { onClick: onClick, className: cn(item, "w-full box-shadow rounded-[10px] p-7.5"), children: _jsx("div", { className: "image-container pt-[15px]", children: _jsx("img", { src: thumbnail, alt: title, className: "w-full" }) }) }))) }));
72
108
  return null;
73
109
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@edu-tosel/design",
3
- "version": "1.0.154",
3
+ "version": "1.0.156",
4
4
  "description": "UI components for International TOSEL Committee",
5
5
  "keywords": [
6
6
  "jsx",
@@ -20,6 +20,7 @@
20
20
  "date-fns-tz": "^2.0.1",
21
21
  "dayjs": "^1.11.12",
22
22
  "gsap": "^3.12.5",
23
+ "moment-timezone": "^0.5.45",
23
24
  "react": "^18.2.0",
24
25
  "react-beautiful-dnd": "^13.1.1",
25
26
  "react-datepicker": "^6.4.0",
@@ -32,10 +32,20 @@ export default {
32
32
  },
33
33
  boxShadow: {
34
34
  main: "0 2px 10px 0px rgba(0, 0, 0, 0.14)",
35
+ "main-small": "0 0px 5px 0px rgba(0, 0, 0, 0.1)",
35
36
  "main-hover": "0 10px 12px 0px rgba(0, 0, 0, 0.3)",
36
37
  green: "0 0px 10px 0px rgba(16, 86, 82, 0.38)",
37
38
  },
38
39
  keyframes: {
40
+ grow: {
41
+ "0%": { height: "60px" },
42
+ "100%": { height: "120px" },
43
+ },
44
+ shrink: {
45
+ "0%": { height: "120px" },
46
+ "100%": { height: "60px" },
47
+ },
48
+
39
49
  slideBackground: {
40
50
  "0%, 100%": { backgroundPosition: "left center" },
41
51
  "50%": { backgroundPosition: "right center" },
@@ -57,6 +67,12 @@ export default {
57
67
  to: { width: "0%" },
58
68
  },
59
69
  },
70
+
71
+ animation: {
72
+ grow: "grow 0.2s ease-in-out forwards",
73
+ shrink: "shrink 0.2s ease-in-out forwards",
74
+ },
75
+
60
76
  colors: {
61
77
  "white-off": "#F5F5F5",
62
78
  "red-burgundy": "#933652",
@@ -272,6 +288,10 @@ export default {
272
288
  151.75: "37.9375rem",
273
289
  152: "38rem",
274
290
  153: "38.25rem",
291
+ 154: "38.5rem",
292
+ 155: "38.75rem",
293
+ 156: "39rem",
294
+ 157: "39.25rem",
275
295
  158: "39.5rem",
276
296
  159: "39.75rem",
277
297
  160: "40rem",
@@ -0,0 +1,4 @@
1
+ export default function compareDates(targetDate: Date): {
2
+ isBefore: boolean;
3
+ dDay: string | null;
4
+ };
@@ -0,0 +1,32 @@
1
+ export default function compareDates(targetDate) {
2
+ const currentDate = new Date();
3
+ const KSTOffset = 9 * 60 * 60 * 1000;
4
+ const KSTDate = new Date(currentDate.getTime() + KSTOffset);
5
+ const targetDateKST = new Date(targetDate.getTime() + KSTOffset);
6
+ const isBefore = KSTDate < targetDateKST;
7
+ const timeDiff = targetDateKST.getTime() - KSTDate.getTime();
8
+ if (isBefore) {
9
+ if (timeDiff < 24 * 60 * 60 * 1000) {
10
+ const hours = Math.floor(timeDiff / (1000 * 60 * 60));
11
+ const minutes = Math.floor((timeDiff % (1000 * 60 * 60)) / (1000 * 60));
12
+ const seconds = Math.floor((timeDiff % (1000 * 60)) / 1000);
13
+ return {
14
+ isBefore,
15
+ dDay: `${hours}시 ${minutes}분 ${seconds}초`,
16
+ };
17
+ }
18
+ else {
19
+ const days = Math.floor(timeDiff / (1000 * 60 * 60 * 24));
20
+ return {
21
+ isBefore,
22
+ dDay: `D-${days}`,
23
+ };
24
+ }
25
+ }
26
+ else {
27
+ return {
28
+ isBefore,
29
+ dDay: null,
30
+ };
31
+ }
32
+ }
@@ -0,0 +1 @@
1
+ export default function formatDateToString(date: Date): string;
@@ -0,0 +1,6 @@
1
+ export default function formatDateToString(date) {
2
+ const year = date.getFullYear();
3
+ const month = (date.getMonth() + 1).toString().padStart(2, "0"); // 월은 0부터 시작하므로 +1
4
+ const day = date.getDate().toString().padStart(2, "0"); // 날짜를 두 자리로 맞춤
5
+ return `${year}-${month}-${day}`;
6
+ }
package/util/index.d.ts CHANGED
@@ -5,6 +5,8 @@ export { default as isDebug } from "./isDebug";
5
5
  export { default as sortByOrder } from "./sortByOrder";
6
6
  export { default as checkPathMatch } from "./checkPathMatch";
7
7
  export { default as createSetter } from "./createSetter";
8
+ export { default as compareDates } from "./compareDates";
9
+ export { default as convertDateToString } from "./convertDateToString";
8
10
  export * from "./colors";
9
11
  export * from "./pattern";
10
12
  export * from "./shape";
package/util/index.js CHANGED
@@ -5,6 +5,8 @@ export { default as isDebug } from "./isDebug";
5
5
  export { default as sortByOrder } from "./sortByOrder";
6
6
  export { default as checkPathMatch } from "./checkPathMatch";
7
7
  export { default as createSetter } from "./createSetter";
8
+ export { default as compareDates } from "./compareDates";
9
+ export { default as convertDateToString } from "./convertDateToString";
8
10
  export * from "./colors";
9
11
  export * from "./pattern";
10
12
  export * from "./shape";
package/version.txt CHANGED
@@ -1 +1 @@
1
- 1.0.154
1
+ 1.0.156
@@ -1,11 +1,13 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { useRef, useState } from "react";
2
+ import { useEffect, useRef, useState } from "react";
3
3
  import { cn, gradient } from "../../../util";
4
4
  import Label from "../Label";
5
5
  import Obstacle from "../Obstacle";
6
+ import SVG from "../../../asset/SVG";
6
7
  export default function InputForm({ title, state, placeholder, isValid, type, onKeyDown, button, maxLength, disabled, }) {
7
8
  const [value, setValue] = state;
8
9
  const [onFocus, setOnFocus] = useState(false);
10
+ const [isEyeOpen, setIsEyeOpen] = useState(false);
9
11
  const ref = useRef(null);
10
12
  const container = {
11
13
  positions: "relative",
@@ -44,6 +46,11 @@ export default function InputForm({ title, state, placeholder, isValid, type, on
44
46
  !(isValid === false) &&
45
47
  "shadow-[0px_0px_10px_0px_rgba(16,86,82,0.38)]",
46
48
  };
49
+ useEffect(() => {
50
+ if (type === "password") {
51
+ ref.current?.setAttribute("type", isEyeOpen ? "text" : "password");
52
+ }
53
+ }, [isEyeOpen]);
47
54
  return (_jsxs("div", { children: [title && _jsx("div", { className: "text-gray-dark", children: title }), _jsxs("div", { className: cn(container), children: [_jsx("div", { onClick: () => ref.current?.focus(), className: cn(placeholderBox), children: placeholderString }), _jsx("input", { ref: ref, className: cn(inputBox), value: value, onKeyDown: onKeyDown && ((e) => onKeyDown(e, value ?? "")), onFocus: () => setOnFocus(true), onBlur: () => setOnFocus(false), onChange: (e) => {
48
55
  if (maxLength && e.target.value.length > maxLength)
49
56
  return;
@@ -55,5 +62,6 @@ export default function InputForm({ title, state, placeholder, isValid, type, on
55
62
  background: button.option?.background ?? gradient.bg.greenToRed,
56
63
  text: button.option?.text ?? "text-white",
57
64
  ...button.option,
58
- } })), _jsx(Obstacle, { disabled: disabled })] })] }));
65
+ } })), type === "password" &&
66
+ (isEyeOpen ? (_jsx(SVG.Eye.Open, { onClick: () => setIsEyeOpen(false), className: "absolute top-3.5 right-3.75" })) : (_jsx(SVG.Eye.Close, { onClick: () => setIsEyeOpen(true), className: "absolute top-3.5 right-3.75" }))), _jsx(Obstacle, { disabled: disabled })] })] }));
59
67
  }