@uniai-fe/uds-templates 0.1.15 → 0.1.17
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/dist/styles.css +139 -10
- package/package.json +18 -11
- package/src/auth/common/complete/Template.tsx +3 -0
- package/src/auth/common/complete/types.ts +4 -1
- package/src/auth/common/find/markup/CodeStep.tsx +2 -1
- package/src/auth/common/find/markup/InfoStep.tsx +2 -1
- package/src/auth/common/find/styles/result.scss +1 -1
- package/src/auth/find-password/markup/StepResetPassword.tsx +2 -1
- package/src/auth/index.tsx +8 -1
- package/src/auth/login/markup/FormField.tsx +2 -1
- package/src/auth/signup/markup/AccountForm.tsx +2 -1
- package/src/auth/signup/markup/Complete.tsx +2 -1
- package/src/auth/signup/markup/UserInfoForm.tsx +2 -1
- package/src/auth/signup/markup/VerificationForm.tsx +4 -2
- package/src/index.scss +1 -0
- package/src/index.tsx +1 -0
- package/src/modal/core/components/FooterButtons.tsx +4 -1
- package/src/modal/templates/Dialog.tsx +4 -2
- package/src/modal/types/footer.ts +4 -2
- package/src/page-frame/container/index.scss +14 -8
- package/src/page-frame/desktop/components/header/Container.tsx +22 -0
- package/src/page-frame/desktop/components/header/Section.tsx +20 -0
- package/src/page-frame/desktop/components/header/index.tsx +19 -0
- package/src/page-frame/desktop/components/header/util/Button.tsx +23 -0
- package/src/page-frame/desktop/components/header/util/Container.tsx +18 -0
- package/src/page-frame/desktop/components/header/util/Item.tsx +13 -0
- package/src/page-frame/desktop/components/header/util/Logout.tsx +26 -0
- package/src/page-frame/desktop/components/header/util/setting/Button.tsx +39 -0
- package/src/page-frame/desktop/components/index.tsx +15 -0
- package/src/page-frame/desktop/components/nav/Button.tsx +24 -0
- package/src/page-frame/desktop/components/nav/Container.tsx +70 -0
- package/src/page-frame/desktop/components/nav/Logo.tsx +46 -0
- package/src/page-frame/desktop/components/nav/index.tsx +5 -0
- package/src/page-frame/desktop/components/page/Container.tsx +13 -0
- package/src/page-frame/desktop/components/page/ServiceFrame.tsx +15 -0
- package/src/page-frame/desktop/components/page/ServiceMain.tsx +13 -0
- package/src/page-frame/desktop/components/page/ServiceMainWrapper.tsx +24 -0
- package/src/page-frame/desktop/components/page/index.tsx +14 -0
- package/src/page-frame/desktop/components/popup/Container.tsx +18 -0
- package/src/page-frame/desktop/components/popup/frame/Body.tsx +14 -0
- package/src/page-frame/desktop/components/popup/frame/Container.tsx +16 -0
- package/src/page-frame/desktop/components/popup/frame/Header.tsx +26 -0
- package/src/page-frame/desktop/components/popup/frame/index.tsx +11 -0
- package/src/page-frame/desktop/components/popup/index.tsx +9 -0
- package/src/page-frame/desktop/index.scss +5 -0
- package/src/page-frame/desktop/index.tsx +5 -0
- package/src/page-frame/desktop/styles/page/common.scss +40 -0
- package/src/page-frame/desktop/styles/page/header.scss +49 -0
- package/src/page-frame/desktop/styles/page/nav.scss +128 -0
- package/src/page-frame/desktop/styles/popup/popup.scss +45 -0
- package/src/page-frame/desktop/styles/variables.scss +28 -0
- package/src/page-frame/desktop/types/nav.ts +77 -0
- package/src/page-frame/index.tsx +2 -0
- package/src/page-frame/mobile/index.scss +1 -1
- package/src/page-frame/types/index.ts +69 -0
- package/src/weather/apis/index.ts +4 -0
- package/src/weather/apis/korea/client.ts +93 -0
- package/src/weather/apis/korea/server.ts +253 -0
- package/src/weather/apis/open-weather-map/client.ts +69 -0
- package/src/weather/apis/open-weather-map/server.ts +134 -0
- package/src/weather/components/icon/Address.tsx +13 -0
- package/src/weather/components/icon/Weather.tsx +32 -0
- package/src/weather/components/index.tsx +7 -0
- package/src/weather/components/page-header/Address.tsx +21 -0
- package/src/weather/components/page-header/Alert.tsx +42 -0
- package/src/weather/components/page-header/Container.tsx +14 -0
- package/src/weather/components/page-header/Forecast.tsx +26 -0
- package/src/weather/components/page-header/NextDays.tsx +32 -0
- package/src/weather/components/page-header/Today.tsx +135 -0
- package/src/weather/context/mock.tsx +45 -0
- package/src/weather/data/alert-regions-meta.json +1286 -0
- package/src/weather/data/response.ts +36 -0
- package/src/weather/data/weather-regions-meta.json +9833 -0
- package/src/weather/hooks/index.ts +4 -0
- package/src/weather/hooks/useOpenWeatherMap.ts +42 -0
- package/src/weather/hooks/useWeatherKorea.ts +78 -0
- package/src/weather/hooks/useWeatherKoreaAlert.ts +36 -0
- package/src/weather/index.tsx +11 -0
- package/src/weather/jotai/coordinate.ts +16 -0
- package/src/weather/jotai/farm-idx.ts +5 -0
- package/src/weather/jotai/index.ts +2 -0
- package/src/weather/styles/weather.scss +151 -0
- package/src/weather/types/api.ts +215 -0
- package/src/weather/types/base.ts +50 -0
- package/src/weather/types/index.ts +4 -0
- package/src/weather/types/korea.ts +228 -0
- package/src/weather/types/open-weather-map.ts +164 -0
- package/src/weather/utils/alert.ts +30 -0
- package/src/weather/utils/date-time.ts +65 -0
- package/src/weather/utils/index.ts +4 -0
- package/src/weather/utils/location.ts +161 -0
- package/src/weather/utils/validate.ts +9 -0
- package/src/weather/utils/weather.ts +304 -0
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import Image from "next/image";
|
|
4
|
+
import Link from "next/link";
|
|
5
|
+
import assetsUrl from "../../../../../../asset-url";
|
|
6
|
+
import PageHeaderUtilityItem from "./Item";
|
|
7
|
+
import PageHeaderUtilityButton from "./Button";
|
|
8
|
+
|
|
9
|
+
export default function PageHeaderLogoutButton({
|
|
10
|
+
path = "/logout",
|
|
11
|
+
}: {
|
|
12
|
+
path?: string;
|
|
13
|
+
}) {
|
|
14
|
+
return (
|
|
15
|
+
<PageHeaderUtilityItem>
|
|
16
|
+
<PageHeaderUtilityButton href={path} as={Link}>
|
|
17
|
+
<Image
|
|
18
|
+
src={`${assetsUrl}/img/page-header/logout-v2.svg`}
|
|
19
|
+
alt="로그아웃"
|
|
20
|
+
width={24}
|
|
21
|
+
height={24}
|
|
22
|
+
/>
|
|
23
|
+
</PageHeaderUtilityButton>
|
|
24
|
+
</PageHeaderUtilityItem>
|
|
25
|
+
);
|
|
26
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import Image from "next/image";
|
|
2
|
+
import assetUrl from "../../../../../../../asset-url";
|
|
3
|
+
import PageHeaderUtilityItem from "../Item";
|
|
4
|
+
import PageHeaderUtilityButton from "../Button";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* 페이지 header; 환경설정 버튼 컴포넌트
|
|
8
|
+
* - 페이지 프레임 구성요소 > pageHeader
|
|
9
|
+
* @component
|
|
10
|
+
* @description
|
|
11
|
+
* - 테마 설정
|
|
12
|
+
* - 날씨 알림 설정
|
|
13
|
+
* - 시세 알림 설정
|
|
14
|
+
* - 이상감지 알림 설정
|
|
15
|
+
* - SNS 메시지 알림 설정
|
|
16
|
+
* - 비밀번호 재설정
|
|
17
|
+
*/
|
|
18
|
+
export default function PageHeaderSettingButton({
|
|
19
|
+
className,
|
|
20
|
+
onOpen,
|
|
21
|
+
}: {
|
|
22
|
+
className?: string;
|
|
23
|
+
onOpen: () => void;
|
|
24
|
+
}) {
|
|
25
|
+
return (
|
|
26
|
+
<PageHeaderUtilityItem>
|
|
27
|
+
<PageHeaderUtilityButton className={className} onClick={onOpen}>
|
|
28
|
+
<figure>
|
|
29
|
+
<Image
|
|
30
|
+
src={`${assetUrl}/img/page-header/setting-v2.svg`}
|
|
31
|
+
alt="설정"
|
|
32
|
+
width={24}
|
|
33
|
+
height={24}
|
|
34
|
+
/>
|
|
35
|
+
</figure>
|
|
36
|
+
</PageHeaderUtilityButton>
|
|
37
|
+
</PageHeaderUtilityItem>
|
|
38
|
+
);
|
|
39
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import clsx from "clsx";
|
|
4
|
+
import Link from "next/link";
|
|
5
|
+
import type { PageFrameDesktopNavItemProps } from "../../types/nav";
|
|
6
|
+
|
|
7
|
+
export default function PageNavButton({
|
|
8
|
+
path,
|
|
9
|
+
icon,
|
|
10
|
+
menuName,
|
|
11
|
+
isHideName,
|
|
12
|
+
}: PageFrameDesktopNavItemProps) {
|
|
13
|
+
return (
|
|
14
|
+
<Link
|
|
15
|
+
href={path}
|
|
16
|
+
className={clsx("page-frame-nav-category", { "icon-only": isHideName })}
|
|
17
|
+
>
|
|
18
|
+
{icon && <span className="page-frame-nav-category-icon">{icon}</span>}
|
|
19
|
+
{!isHideName && (
|
|
20
|
+
<span className="page-frame-nav-category-label">{menuName}</span>
|
|
21
|
+
)}
|
|
22
|
+
</Link>
|
|
23
|
+
);
|
|
24
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import clsx from "clsx";
|
|
4
|
+
import Link from "next/link";
|
|
5
|
+
import { usePathname } from "next/navigation";
|
|
6
|
+
import { useCallback } from "react";
|
|
7
|
+
|
|
8
|
+
import PageNavButton from "./Button";
|
|
9
|
+
import PageNavLogo from "./Logo";
|
|
10
|
+
|
|
11
|
+
import type { SitemapDataType } from "../../../types";
|
|
12
|
+
import type { PageFrameDesktopNavProps } from "../../types/nav";
|
|
13
|
+
|
|
14
|
+
export default function PageNavContainer({
|
|
15
|
+
logo,
|
|
16
|
+
sitemap,
|
|
17
|
+
currentPath,
|
|
18
|
+
}: PageFrameDesktopNavProps) {
|
|
19
|
+
const pathnameValue = usePathname();
|
|
20
|
+
// currentPath를 명시하면 Next 라우터가 없는 환경에서도 선택 상태를 제어할 수 있다.
|
|
21
|
+
const resolvedPath = currentPath ?? pathnameValue ?? "";
|
|
22
|
+
const isSelected = useCallback(
|
|
23
|
+
(path: string): boolean => resolvedPath.startsWith(path),
|
|
24
|
+
[resolvedPath],
|
|
25
|
+
);
|
|
26
|
+
|
|
27
|
+
const formatRoutes = useCallback(
|
|
28
|
+
(routes?: SitemapDataType[]) =>
|
|
29
|
+
Array.isArray(routes)
|
|
30
|
+
? routes.map(route => ({
|
|
31
|
+
...route,
|
|
32
|
+
routeKey: `nav/${route.routeKey}`,
|
|
33
|
+
}))
|
|
34
|
+
: [],
|
|
35
|
+
[],
|
|
36
|
+
);
|
|
37
|
+
|
|
38
|
+
return (
|
|
39
|
+
<nav className="page-frame-nav">
|
|
40
|
+
{logo && <PageNavLogo {...logo} />}
|
|
41
|
+
<ul className="page-frame-nav-list">
|
|
42
|
+
{formatRoutes(sitemap).map(
|
|
43
|
+
({ routeKey, icon, name, path, depth, navDepthDisabled }) => (
|
|
44
|
+
<li
|
|
45
|
+
key={routeKey}
|
|
46
|
+
className={clsx("page-frame-nav-item", {
|
|
47
|
+
"is-selected": isSelected(path),
|
|
48
|
+
})}
|
|
49
|
+
>
|
|
50
|
+
<PageNavButton icon={icon} menuName={name} path={path} />
|
|
51
|
+
{!navDepthDisabled && depth.length > 0 && (
|
|
52
|
+
<div className="page-frame-nav-depth">
|
|
53
|
+
{formatRoutes(depth).map(({ routeKey, path, name }) => (
|
|
54
|
+
<Link
|
|
55
|
+
key={routeKey}
|
|
56
|
+
href={path}
|
|
57
|
+
className="page-frame-nav-depth-item"
|
|
58
|
+
>
|
|
59
|
+
<span>{name}</span>
|
|
60
|
+
</Link>
|
|
61
|
+
))}
|
|
62
|
+
</div>
|
|
63
|
+
)}
|
|
64
|
+
</li>
|
|
65
|
+
),
|
|
66
|
+
)}
|
|
67
|
+
</ul>
|
|
68
|
+
</nav>
|
|
69
|
+
);
|
|
70
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import Image from "next/image";
|
|
4
|
+
import Link from "next/link";
|
|
5
|
+
import type { PageFrameDesktopNavLogoProps } from "../../types/nav";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* PageFrame; Desktop Nav Logo 컴포넌트
|
|
9
|
+
* @component
|
|
10
|
+
* @param {PageFrameDesktopNavLogoProps} props - 컴포넌트 props
|
|
11
|
+
* @param {string} [props.href="/"] - 로고 클릭 시 이동할 링크 주소
|
|
12
|
+
* @param {string} props.src - 로고 이미지 src 속성 값
|
|
13
|
+
* @param {string} props.alt - 로고 이미지 alt 속성 값
|
|
14
|
+
* @param {number} props.width - 로고 이미지 width 속성 값
|
|
15
|
+
* @param {number} props.height - 로고 이미지 height 속성 값
|
|
16
|
+
* @param {boolean} [props.priority=false] - 로고 이미지 priority 속성 값
|
|
17
|
+
* @param {ReactNode} [props.children] - 커스텀 로고 콘텐츠
|
|
18
|
+
*/
|
|
19
|
+
export default function PageNavLogo({
|
|
20
|
+
src,
|
|
21
|
+
alt,
|
|
22
|
+
width,
|
|
23
|
+
height,
|
|
24
|
+
priority,
|
|
25
|
+
href,
|
|
26
|
+
children,
|
|
27
|
+
}: PageFrameDesktopNavLogoProps) {
|
|
28
|
+
return (
|
|
29
|
+
<div className="page-frame-nav-logo">
|
|
30
|
+
<Link href={href || "/"} aria-label={alt}>
|
|
31
|
+
{children ?? (
|
|
32
|
+
<figure>
|
|
33
|
+
<Image
|
|
34
|
+
src={src}
|
|
35
|
+
alt={alt}
|
|
36
|
+
width={width}
|
|
37
|
+
height={height}
|
|
38
|
+
priority={priority}
|
|
39
|
+
aria-hidden="true"
|
|
40
|
+
/>
|
|
41
|
+
</figure>
|
|
42
|
+
)}
|
|
43
|
+
</Link>
|
|
44
|
+
</div>
|
|
45
|
+
);
|
|
46
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import clsx from "clsx";
|
|
4
|
+
import type { ComponentBaseProps } from "../../../types";
|
|
5
|
+
|
|
6
|
+
export default function PageContainer({
|
|
7
|
+
className,
|
|
8
|
+
children,
|
|
9
|
+
}: ComponentBaseProps) {
|
|
10
|
+
return (
|
|
11
|
+
<main className={clsx("page-frame-container", className)}>{children}</main>
|
|
12
|
+
);
|
|
13
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import clsx from "clsx";
|
|
4
|
+
import type { ComponentBaseProps } from "../../../types";
|
|
5
|
+
|
|
6
|
+
export default function PageServiceFrame({
|
|
7
|
+
className,
|
|
8
|
+
children,
|
|
9
|
+
}: ComponentBaseProps) {
|
|
10
|
+
return (
|
|
11
|
+
<div className={clsx("page-frame-service-frame", className)}>
|
|
12
|
+
{children}
|
|
13
|
+
</div>
|
|
14
|
+
);
|
|
15
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import clsx from "clsx";
|
|
4
|
+
import type { ComponentBaseProps } from "../../../types";
|
|
5
|
+
|
|
6
|
+
export default function PageServiceMain({
|
|
7
|
+
className,
|
|
8
|
+
children,
|
|
9
|
+
}: ComponentBaseProps) {
|
|
10
|
+
return (
|
|
11
|
+
<div className={clsx("page-frame-service-main", className)}>{children}</div>
|
|
12
|
+
);
|
|
13
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import clsx from "clsx";
|
|
4
|
+
|
|
5
|
+
import type { ComponentBaseProps } from "../../../types";
|
|
6
|
+
|
|
7
|
+
export default function PageServiceMainWrapper({
|
|
8
|
+
className,
|
|
9
|
+
noPadding,
|
|
10
|
+
children,
|
|
11
|
+
}: ComponentBaseProps &
|
|
12
|
+
Partial<{
|
|
13
|
+
noPadding: boolean;
|
|
14
|
+
}>) {
|
|
15
|
+
return (
|
|
16
|
+
<div
|
|
17
|
+
className={clsx("page-frame-service-main-wrapper", className, {
|
|
18
|
+
"no-padding": noPadding,
|
|
19
|
+
})}
|
|
20
|
+
>
|
|
21
|
+
{children}
|
|
22
|
+
</div>
|
|
23
|
+
);
|
|
24
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import PageContainer from "./Container";
|
|
2
|
+
import PageServiceFrame from "./ServiceFrame";
|
|
3
|
+
import PageServiceMain from "./ServiceMain";
|
|
4
|
+
import PageServiceMainWrapper from "./ServiceMainWrapper";
|
|
5
|
+
|
|
6
|
+
const Page = {
|
|
7
|
+
Container: PageContainer,
|
|
8
|
+
Service: {
|
|
9
|
+
Frame: PageServiceFrame,
|
|
10
|
+
Main: PageServiceMain,
|
|
11
|
+
MainWrapper: PageServiceMainWrapper,
|
|
12
|
+
},
|
|
13
|
+
};
|
|
14
|
+
export default Page;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import clsx from "clsx";
|
|
4
|
+
import type { ReactNode } from "react";
|
|
5
|
+
|
|
6
|
+
export default function PopupContainer({
|
|
7
|
+
className,
|
|
8
|
+
children,
|
|
9
|
+
}: {
|
|
10
|
+
className?: string;
|
|
11
|
+
children: ReactNode;
|
|
12
|
+
}) {
|
|
13
|
+
return (
|
|
14
|
+
<main id="pagePopup" className={clsx("popup-container", className)}>
|
|
15
|
+
{children}
|
|
16
|
+
</main>
|
|
17
|
+
);
|
|
18
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import clsx from "clsx";
|
|
4
|
+
import type { ReactNode } from "react";
|
|
5
|
+
|
|
6
|
+
export default function PopupFrameBody({
|
|
7
|
+
className,
|
|
8
|
+
children,
|
|
9
|
+
}: {
|
|
10
|
+
className?: string;
|
|
11
|
+
children: ReactNode;
|
|
12
|
+
}) {
|
|
13
|
+
return <div className={clsx("popup-frame-body", className)}>{children}</div>;
|
|
14
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import clsx from "clsx";
|
|
4
|
+
import type { ReactNode } from "react";
|
|
5
|
+
|
|
6
|
+
export default function PopupFrameContainer({
|
|
7
|
+
className,
|
|
8
|
+
children,
|
|
9
|
+
}: {
|
|
10
|
+
className?: string;
|
|
11
|
+
children: ReactNode;
|
|
12
|
+
}) {
|
|
13
|
+
return (
|
|
14
|
+
<div className={clsx("popup-frame-container", className)}>{children}</div>
|
|
15
|
+
);
|
|
16
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import clsx from "clsx";
|
|
4
|
+
import type { ReactNode } from "react";
|
|
5
|
+
|
|
6
|
+
export default function PopupFrameHeader({
|
|
7
|
+
className,
|
|
8
|
+
title,
|
|
9
|
+
util,
|
|
10
|
+
children,
|
|
11
|
+
}: {
|
|
12
|
+
className?: string;
|
|
13
|
+
title: ReactNode;
|
|
14
|
+
util?: ReactNode;
|
|
15
|
+
children?: ReactNode;
|
|
16
|
+
}) {
|
|
17
|
+
return (
|
|
18
|
+
<header className={clsx("popup-frame-header", className)}>
|
|
19
|
+
<div className="popup-frame-header-title-container">
|
|
20
|
+
<h2 className="popup-frame-header-title">{title}</h2>
|
|
21
|
+
{util && <div className="popup-frame-header-util">{util}</div>}
|
|
22
|
+
</div>
|
|
23
|
+
{children}
|
|
24
|
+
</header>
|
|
25
|
+
);
|
|
26
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import PopupFrameContainer from "./Container";
|
|
2
|
+
import PopupFrameHeader from "./Header";
|
|
3
|
+
import PopupFrameBody from "./Body";
|
|
4
|
+
|
|
5
|
+
const PopupPageFrame = {
|
|
6
|
+
Container: PopupFrameContainer,
|
|
7
|
+
Header: PopupFrameHeader,
|
|
8
|
+
Body: PopupFrameBody,
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export default PopupPageFrame;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
// 페이지 프레임: 레이아웃 뼈대를 담당한다.
|
|
2
|
+
.page-frame-container {
|
|
3
|
+
width: 100%;
|
|
4
|
+
min-height: 100vh;
|
|
5
|
+
background-color: var(--uds-page-frame-background);
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
// 서비스 본문과 내비게이션을 병렬 배치한다.
|
|
9
|
+
.page-frame-service-frame {
|
|
10
|
+
width: 100%;
|
|
11
|
+
min-height: 100vh;
|
|
12
|
+
display: flex;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
// 내비게이션을 제외한 콘텐츠 영역.
|
|
16
|
+
.page-frame-service-main {
|
|
17
|
+
width: calc(100% - var(--uds-page-nav-width));
|
|
18
|
+
min-height: 100vh;
|
|
19
|
+
display: flex;
|
|
20
|
+
flex-direction: column;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// 본문 스크롤 영역: 헤더 높이를 제외하고 padding을 CSS 변수로 제어한다.
|
|
24
|
+
.page-frame-service-main-wrapper {
|
|
25
|
+
width: 100%;
|
|
26
|
+
height: calc(100% - var(--uds-page-header-height));
|
|
27
|
+
padding: var(--uds-page-body-padding-vertical)
|
|
28
|
+
var(--uds-page-body-padding-horizontal);
|
|
29
|
+
background-color: var(--uds-page-body-background);
|
|
30
|
+
overflow-y: auto;
|
|
31
|
+
|
|
32
|
+
position: relative;
|
|
33
|
+
z-index: 0;
|
|
34
|
+
|
|
35
|
+
// noPadding 상태일 때 padding/background를 제거한다.
|
|
36
|
+
&.no-padding {
|
|
37
|
+
--uds-page-body-background: var(--color-bg-standard-neutral);
|
|
38
|
+
padding: 0px;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
// 페이지 헤더: 상단 고정 막대.
|
|
2
|
+
.page-frame-header {
|
|
3
|
+
width: 100%;
|
|
4
|
+
height: var(--uds-page-header-height);
|
|
5
|
+
padding: var(--uds-page-header-padding-vertical)
|
|
6
|
+
var(--uds-page-header-padding-horizontal);
|
|
7
|
+
background: var(--uds-page-header-background);
|
|
8
|
+
border-bottom: 1px solid var(--uds-page-header-border);
|
|
9
|
+
display: flex;
|
|
10
|
+
align-items: center;
|
|
11
|
+
justify-content: space-between;
|
|
12
|
+
gap: var(--uds-page-header-item-gap);
|
|
13
|
+
position: relative;
|
|
14
|
+
z-index: 500;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// 섹션 래퍼: 좌측 브랜드, 중간 정보, 우측 유틸 등 원하는 대로 조합한다.
|
|
18
|
+
.page-frame-header-section {
|
|
19
|
+
display: flex;
|
|
20
|
+
align-items: center;
|
|
21
|
+
gap: var(--uds-page-header-item-gap);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// 헤더 우측 유틸리티 컨테이너.
|
|
25
|
+
.page-header-util-container {
|
|
26
|
+
display: flex;
|
|
27
|
+
align-items: center;
|
|
28
|
+
margin-left: auto;
|
|
29
|
+
gap: var(--uds-page-nav-item-gap, 0);
|
|
30
|
+
padding: 0;
|
|
31
|
+
margin-block: 0;
|
|
32
|
+
list-style: none;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// margin을 CSS 변수로 조정해 Item 별 여백을 만든다.
|
|
36
|
+
.page-header-util-item {
|
|
37
|
+
display: flex;
|
|
38
|
+
align-items: center;
|
|
39
|
+
list-style: none;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// 공통 버튼: 높이/패딩을 토큰으로 통일한다.
|
|
43
|
+
.page-header-util-button {
|
|
44
|
+
padding: 0px;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
.page-header-util-logout {
|
|
48
|
+
font-size: 0;
|
|
49
|
+
}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
.page-frame-nav {
|
|
2
|
+
width: var(--uds-page-nav-width);
|
|
3
|
+
border-right: 1px solid var(--uds-page-nav-border);
|
|
4
|
+
background-color: var(--uds-page-nav-background);
|
|
5
|
+
|
|
6
|
+
position: relative;
|
|
7
|
+
z-index: 500;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
.page-frame-nav-logo {
|
|
11
|
+
width: 100%;
|
|
12
|
+
height: var(--uds-page-nav-logo-height);
|
|
13
|
+
display: flex;
|
|
14
|
+
align-items: center;
|
|
15
|
+
justify-content: center;
|
|
16
|
+
|
|
17
|
+
a {
|
|
18
|
+
display: flex;
|
|
19
|
+
align-items: center;
|
|
20
|
+
justify-content: center;
|
|
21
|
+
font-size: 0;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
.page-frame-nav-list {
|
|
26
|
+
width: 100%;
|
|
27
|
+
padding: var(--uds-page-nav-list-padding-vertical)
|
|
28
|
+
var(--uds-page-nav-list-padding-horizontal);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
.page-frame-nav-item {
|
|
32
|
+
width: 100%;
|
|
33
|
+
margin-bottom: var(--uds-page-nav-item-gap);
|
|
34
|
+
position: relative;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
.page-frame-nav-category {
|
|
38
|
+
width: 100%;
|
|
39
|
+
height: var(--uds-page-nav-item-height);
|
|
40
|
+
text-decoration: none;
|
|
41
|
+
color: var(--uds-page-nav-item-color-default);
|
|
42
|
+
transition:
|
|
43
|
+
color 0.2s,
|
|
44
|
+
fill 0.2s;
|
|
45
|
+
|
|
46
|
+
display: flex;
|
|
47
|
+
align-items: center;
|
|
48
|
+
justify-content: center;
|
|
49
|
+
flex-direction: column;
|
|
50
|
+
gap: 0.2rem;
|
|
51
|
+
|
|
52
|
+
&.icon-only {
|
|
53
|
+
width: auto;
|
|
54
|
+
padding: 0.4rem;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
.page-frame-nav-category-icon {
|
|
59
|
+
width: var(--uds-page-nav-icon-size);
|
|
60
|
+
height: var(--uds-page-nav-icon-size);
|
|
61
|
+
display: flex;
|
|
62
|
+
align-items: center;
|
|
63
|
+
justify-content: center;
|
|
64
|
+
|
|
65
|
+
svg,
|
|
66
|
+
img {
|
|
67
|
+
width: 100%;
|
|
68
|
+
height: 100%;
|
|
69
|
+
object-fit: contain;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
svg path {
|
|
73
|
+
fill: var(--uds-page-nav-item-color-default);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
.page-frame-nav-category-label {
|
|
78
|
+
font-size: 1.2rem;
|
|
79
|
+
line-height: 1.4rem;
|
|
80
|
+
color: inherit;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
.page-frame-nav-item.is-selected .page-frame-nav-category,
|
|
84
|
+
.page-frame-nav-item:hover .page-frame-nav-category {
|
|
85
|
+
color: var(--uds-page-nav-item-color-active);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
.page-frame-nav-item.is-selected .page-frame-nav-category-icon svg path,
|
|
89
|
+
.page-frame-nav-item:hover .page-frame-nav-category-icon svg path {
|
|
90
|
+
fill: var(--uds-page-nav-item-color-active);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
.page-frame-nav-depth {
|
|
94
|
+
display: none;
|
|
95
|
+
width: fit-content;
|
|
96
|
+
min-height: 100%;
|
|
97
|
+
padding: 1.1rem 1.6rem;
|
|
98
|
+
background: var(--uds-page-nav-bg-active);
|
|
99
|
+
position: absolute;
|
|
100
|
+
top: 0;
|
|
101
|
+
left: calc(100% - 0.8rem);
|
|
102
|
+
z-index: 1000;
|
|
103
|
+
flex-direction: column;
|
|
104
|
+
justify-content: center;
|
|
105
|
+
border-radius: 1.2rem;
|
|
106
|
+
box-shadow: 0 0.6rem 1.2rem rgba(0, 0, 0, 0.15);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
.page-frame-nav-depth-item {
|
|
110
|
+
display: flex;
|
|
111
|
+
align-items: center;
|
|
112
|
+
width: 100%;
|
|
113
|
+
min-height: 2.4rem;
|
|
114
|
+
text-decoration: none;
|
|
115
|
+
|
|
116
|
+
span {
|
|
117
|
+
font-size: 1.2rem;
|
|
118
|
+
color: var(
|
|
119
|
+
--uds-page-nav-depth-color,
|
|
120
|
+
var(--uds-page-nav-item-color-active)
|
|
121
|
+
);
|
|
122
|
+
white-space: nowrap;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
.page-frame-nav-item:hover .page-frame-nav-depth {
|
|
127
|
+
display: flex;
|
|
128
|
+
}
|