@uniai-fe/uds-templates 0.5.0 → 0.5.1
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/README.md +12 -0
- package/dist/styles.css +49 -0
- package/package.json +4 -4
- package/src/edge-case/EdgeCase.tsx +16 -0
- package/src/edge-case/components/Empty.tsx +42 -0
- package/src/edge-case/components/Loading.tsx +42 -0
- package/src/edge-case/components/NotFound.tsx +74 -0
- package/src/edge-case/components/index.tsx +3 -0
- package/src/edge-case/img/404.svg +3 -0
- package/src/edge-case/index.scss +1 -0
- package/src/edge-case/index.tsx +11 -0
- package/src/edge-case/styles/edge-case.scss +56 -0
- package/src/edge-case/styles/index.scss +1 -0
- package/src/edge-case/types/index.ts +94 -0
- package/src/index.scss +1 -0
- package/src/index.tsx +1 -0
package/README.md
CHANGED
|
@@ -98,6 +98,14 @@ Next.js 서비스에서 primitives와 동일한 방식으로 **Raw TypeScript**
|
|
|
98
98
|
- `MobileFrameProps`
|
|
99
99
|
- `PageFrameDesktopNavProps`
|
|
100
100
|
- `SitemapDataType`
|
|
101
|
+
- `/edge-case`
|
|
102
|
+
- `EdgeCase`
|
|
103
|
+
- `EdgeCase.Empty`
|
|
104
|
+
- `EdgeCase.Loading`
|
|
105
|
+
- `EdgeCase.NotFound`
|
|
106
|
+
- `EdgeCaseEmptyProps`
|
|
107
|
+
- `EdgeCaseLoadingProps`
|
|
108
|
+
- `EdgeCaseNotFoundProps`
|
|
101
109
|
|
|
102
110
|
## 현재 제공 템플릿/모듈
|
|
103
111
|
|
|
@@ -126,6 +134,9 @@ Next.js 서비스에서 primitives와 동일한 방식으로 **Raw TypeScript**
|
|
|
126
134
|
- finder/viewer/video/pagination 조합과 rtc/company-list API helper를 제공한다.
|
|
127
135
|
- `/page-frame/**`
|
|
128
136
|
- mobile/desktop private route frame, nav/header/popup 조합을 제공한다.
|
|
137
|
+
- `/edge-case/**`
|
|
138
|
+
- empty/loading/not-found 화면 상태 템플릿을 제공한다.
|
|
139
|
+
- primitives `Alternate.Layout.*`를 조합하며, 실제 routing/history 판정은 서비스 앱이 소유한다.
|
|
129
140
|
|
|
130
141
|
각 템플릿의 상세한 범위와 의사결정은 `CONTEXT-*.md` 문서에서 관리합니다.
|
|
131
142
|
|
|
@@ -225,6 +236,7 @@ export default function LoginPage() {
|
|
|
225
236
|
|
|
226
237
|
- Modal CSS 변수 네임스페이스를 `--modal-*`, `--modal-alert-*`, `--modal-dialog-*` 세 축으로 통일했다. 기존 `--dialog-*` 이름을 사용하지 말고, Auth 템플릿이 Alert을 호출할 때에는 반드시 `Modal.Alert` 팩토리를 통해 렌더링한다.
|
|
227
238
|
- Auth(회원가입/아이디 찾기/비밀번호 찾기) 템플릿은 이메일 인증 타이머 5분, alert 문구, readonly 이메일 필드, 완료 단계 헤더 제거 등 최신 플로우를 반영했다. 모듈에서 `window.alert`/`window.confirm`을 호출하지 않고, 서비스 앱이 Modal helper를 주입하는 구조를 README와 `CONTEXT-AUTH*.md`에 명시했다.
|
|
239
|
+
- Edge Case 템플릿은 `EdgeCase.Empty`, `EdgeCase.Loading`, `EdgeCase.NotFound` namespace로 공개한다. `NotFound`는 `onPrev` 또는 `fallbackHref="/"`를 연결하지만 `router.back()`이나 service-origin 판정은 실행하지 않는다.
|
|
228
240
|
|
|
229
241
|
### 토큰 스코프 & ThemeProvider
|
|
230
242
|
|
package/dist/styles.css
CHANGED
|
@@ -1923,3 +1923,52 @@
|
|
|
1923
1923
|
.page-frame-inquiry-button {
|
|
1924
1924
|
margin-top: auto;
|
|
1925
1925
|
}
|
|
1926
|
+
|
|
1927
|
+
.edge-case {
|
|
1928
|
+
width: 100%;
|
|
1929
|
+
}
|
|
1930
|
+
|
|
1931
|
+
.edge-case:where([data-edge-case=not-found]) {
|
|
1932
|
+
--alternate-layout-gap: var(--spacing-gap-3);
|
|
1933
|
+
--alternate-layout-figure-size: 128px;
|
|
1934
|
+
--alternate-layout-title-color: var(--color-label-standard);
|
|
1935
|
+
--alternate-layout-title-font-size: var(--font-heading-xsmall-size);
|
|
1936
|
+
--alternate-layout-title-line-height: var(--font-heading-xsmall-line-height);
|
|
1937
|
+
--alternate-layout-title-letter-spacing: var(
|
|
1938
|
+
--font-heading-xsmall-letter-spacing
|
|
1939
|
+
);
|
|
1940
|
+
--alternate-layout-title-font-weight: var(--font-heading-xsmall-weight);
|
|
1941
|
+
--alternate-layout-contents-font-size: var(--font-body-xsmall-size);
|
|
1942
|
+
--alternate-layout-contents-line-height: var(--font-body-xsmall-line-height);
|
|
1943
|
+
--alternate-layout-contents-letter-spacing: var(
|
|
1944
|
+
--font-body-xsmall-letter-spacing
|
|
1945
|
+
);
|
|
1946
|
+
--alternate-layout-contents-font-weight: var(--font-body-xsmall-weight);
|
|
1947
|
+
--button-default-font-label-medium-size: var(--font-label-small-size);
|
|
1948
|
+
--button-default-font-label-medium-line-height: var(
|
|
1949
|
+
--font-label-small-line-height
|
|
1950
|
+
);
|
|
1951
|
+
--button-default-font-label-medium-letter-spacing: var(
|
|
1952
|
+
--font-label-small-letter-spacing
|
|
1953
|
+
);
|
|
1954
|
+
--button-default-font-label-medium-weight: var(--font-label-small-weight);
|
|
1955
|
+
--button-default-font-weight: var(--font-label-small-weight);
|
|
1956
|
+
min-height: 0;
|
|
1957
|
+
padding: calc(var(--spacing-padding-11) + var(--spacing-padding-7)) var(--spacing-padding-8);
|
|
1958
|
+
border: 1px solid var(--color-border-assistive);
|
|
1959
|
+
border-radius: var(--theme-radius-large-1);
|
|
1960
|
+
background: var(--color-common-100);
|
|
1961
|
+
justify-content: flex-start;
|
|
1962
|
+
}
|
|
1963
|
+
.edge-case:where([data-edge-case=not-found]) :where(.alternate-layout-figure) {
|
|
1964
|
+
margin-bottom: var(--spacing-gap-3);
|
|
1965
|
+
}
|
|
1966
|
+
.edge-case:where([data-edge-case=not-found]) :where(.alternate-layout-contents) {
|
|
1967
|
+
white-space: nowrap;
|
|
1968
|
+
}
|
|
1969
|
+
.edge-case:where([data-edge-case=not-found]) :where(.alternate-layout-contents) :where(p + p) {
|
|
1970
|
+
margin-top: var(--spacing-gap-3);
|
|
1971
|
+
}
|
|
1972
|
+
.edge-case:where([data-edge-case=not-found]) :where(.alternate-layout-button) {
|
|
1973
|
+
margin-top: var(--spacing-gap-3);
|
|
1974
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@uniai-fe/uds-templates",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.1",
|
|
4
4
|
"description": "UNIAI Design System; UI Templates Package",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"private": false,
|
|
@@ -70,7 +70,7 @@
|
|
|
70
70
|
},
|
|
71
71
|
"devDependencies": {
|
|
72
72
|
"@svgr/webpack": "^8.1.0",
|
|
73
|
-
"@tanstack/react-query": "^5.
|
|
73
|
+
"@tanstack/react-query": "^5.99.0",
|
|
74
74
|
"@types/node": "^24.10.2",
|
|
75
75
|
"@types/react": "^19.2.14",
|
|
76
76
|
"@types/react-dom": "^19.2.3",
|
|
@@ -88,9 +88,9 @@
|
|
|
88
88
|
"eslint": "^9.39.2",
|
|
89
89
|
"jotai": "^2.19.1",
|
|
90
90
|
"next": "^15.5.11",
|
|
91
|
-
"prettier": "^3.8.
|
|
91
|
+
"prettier": "^3.8.3",
|
|
92
92
|
"react-hook-form": "^7.72.1",
|
|
93
93
|
"sass": "^1.99.0",
|
|
94
|
-
"typescript": "
|
|
94
|
+
"typescript": "5.9.3"
|
|
95
95
|
}
|
|
96
96
|
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { EdgeCaseEmpty, EdgeCaseLoading, EdgeCaseNotFound } from "./components";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Edge Case; empty/loading/not-found 화면 상태 namespace
|
|
5
|
+
* @desc
|
|
6
|
+
* - `EdgeCase.Empty`: 빈 상태 화면 조합이다.
|
|
7
|
+
* - `EdgeCase.Loading`: 로딩 상태 화면 조합이다.
|
|
8
|
+
* - `EdgeCase.NotFound`: not-found 상태 화면 조합이다.
|
|
9
|
+
*/
|
|
10
|
+
const EdgeCase = {
|
|
11
|
+
Empty: EdgeCaseEmpty,
|
|
12
|
+
Loading: EdgeCaseLoading,
|
|
13
|
+
NotFound: EdgeCaseNotFound,
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export default EdgeCase;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { clsx } from "clsx";
|
|
4
|
+
import { Alternate } from "@uniai-fe/uds-primitives";
|
|
5
|
+
import type { EdgeCaseEmptyProps } from "../types";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Edge Case Empty; 빈 상태 화면 템플릿
|
|
9
|
+
* @component
|
|
10
|
+
* @param {EdgeCaseEmptyProps} props
|
|
11
|
+
* @param {string} [props.className] 최상위 edge-case container className override다.
|
|
12
|
+
* @param {React.ReactNode} [props.figure] 빈 상태를 보조하는 visual 콘텐츠다.
|
|
13
|
+
* @param {React.ReactNode} props.title 빈 상태 제목 콘텐츠다.
|
|
14
|
+
* @param {React.ReactNode} [props.description] 빈 상태 설명 콘텐츠다.
|
|
15
|
+
* @param {React.ReactNode} [props.children] 하단에 주입할 custom action 또는 보조 콘텐츠다.
|
|
16
|
+
* @example
|
|
17
|
+
* <EdgeCase.Empty title="조회 결과가 없습니다." description="다른 조건으로 다시 검색해 주세요." />
|
|
18
|
+
*/
|
|
19
|
+
export default function EdgeCaseEmpty({
|
|
20
|
+
className,
|
|
21
|
+
figure,
|
|
22
|
+
title,
|
|
23
|
+
description,
|
|
24
|
+
children,
|
|
25
|
+
}: EdgeCaseEmptyProps) {
|
|
26
|
+
return (
|
|
27
|
+
<Alternate.Layout.Container
|
|
28
|
+
className={clsx("edge-case", className)}
|
|
29
|
+
data-edge-case="empty"
|
|
30
|
+
>
|
|
31
|
+
{figure ? (
|
|
32
|
+
<Alternate.Layout.Figure>{figure}</Alternate.Layout.Figure>
|
|
33
|
+
) : null}
|
|
34
|
+
<Alternate.Layout.Title>{title}</Alternate.Layout.Title>
|
|
35
|
+
{description ? (
|
|
36
|
+
<Alternate.Layout.Contents>{description}</Alternate.Layout.Contents>
|
|
37
|
+
) : null}
|
|
38
|
+
{/* 변경: templates는 action 정책을 확정하지 않고 소비 측 주입 지점만 연다. */}
|
|
39
|
+
{children}
|
|
40
|
+
</Alternate.Layout.Container>
|
|
41
|
+
);
|
|
42
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { clsx } from "clsx";
|
|
4
|
+
import { Alternate } from "@uniai-fe/uds-primitives";
|
|
5
|
+
import type { EdgeCaseLoadingProps } from "../types";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Edge Case Loading; 로딩 상태 화면 템플릿
|
|
9
|
+
* @component
|
|
10
|
+
* @param {EdgeCaseLoadingProps} props
|
|
11
|
+
* @param {string} [props.className] 최상위 edge-case container className override다.
|
|
12
|
+
* @param {React.ReactNode} [props.figure] 로딩 상태 visual 콘텐츠다.
|
|
13
|
+
* @param {React.ReactNode} [props.title] 로딩 상태 제목 콘텐츠다.
|
|
14
|
+
* @param {React.ReactNode} [props.description] 로딩 상태 설명 콘텐츠다.
|
|
15
|
+
* @param {React.ReactNode} [props.children] 하단에 주입할 custom action 또는 보조 콘텐츠다.
|
|
16
|
+
* @example
|
|
17
|
+
* <EdgeCase.Loading title="불러오는 중입니다." />
|
|
18
|
+
*/
|
|
19
|
+
export default function EdgeCaseLoading({
|
|
20
|
+
className,
|
|
21
|
+
figure,
|
|
22
|
+
title,
|
|
23
|
+
description,
|
|
24
|
+
children,
|
|
25
|
+
}: EdgeCaseLoadingProps) {
|
|
26
|
+
return (
|
|
27
|
+
<Alternate.Layout.Container
|
|
28
|
+
className={clsx("edge-case", className)}
|
|
29
|
+
data-edge-case="loading"
|
|
30
|
+
>
|
|
31
|
+
<Alternate.Layout.Figure>
|
|
32
|
+
{figure ?? <Alternate.LoadingIcon size="large" direction="vertical" />}
|
|
33
|
+
</Alternate.Layout.Figure>
|
|
34
|
+
{title ? <Alternate.Layout.Title>{title}</Alternate.Layout.Title> : null}
|
|
35
|
+
{description ? (
|
|
36
|
+
<Alternate.Layout.Contents>{description}</Alternate.Layout.Contents>
|
|
37
|
+
) : null}
|
|
38
|
+
{/* 변경: 로딩 취소/재시도 같은 정책은 서비스 앱이 children으로 주입한다. */}
|
|
39
|
+
{children}
|
|
40
|
+
</Alternate.Layout.Container>
|
|
41
|
+
);
|
|
42
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { clsx } from "clsx";
|
|
4
|
+
import { Alternate } from "@uniai-fe/uds-primitives";
|
|
5
|
+
import NotFoundIcon from "../img/404.svg";
|
|
6
|
+
import type { EdgeCaseNotFoundProps } from "../types";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Edge Case Not Found; not-found 상태 화면 템플릿
|
|
10
|
+
* @component
|
|
11
|
+
* @param {EdgeCaseNotFoundProps} props
|
|
12
|
+
* @param {string} [props.className] 최상위 edge-case container className override다.
|
|
13
|
+
* @param {string} [props.inquiryHref] 문의 text action을 link로 렌더링할 href다.
|
|
14
|
+
* @param {() => void} [props.onInquiry] 문의 text action을 button으로 렌더링할 콜백이다.
|
|
15
|
+
* @param {string} [props.fallbackHref] onPrev가 없을 때 사용할 fallback href다.
|
|
16
|
+
* @param {() => void} [props.onPrev] 이전 페이지 이동을 소비 앱에서 실행하는 콜백이다.
|
|
17
|
+
* @example
|
|
18
|
+
* <EdgeCase.NotFound onPrev={() => router.back()} />
|
|
19
|
+
*/
|
|
20
|
+
export default function EdgeCaseNotFound({
|
|
21
|
+
className,
|
|
22
|
+
inquiryHref,
|
|
23
|
+
onInquiry,
|
|
24
|
+
fallbackHref = "/",
|
|
25
|
+
onPrev,
|
|
26
|
+
}: EdgeCaseNotFoundProps) {
|
|
27
|
+
return (
|
|
28
|
+
<Alternate.Layout.Container
|
|
29
|
+
className={clsx("edge-case", className)}
|
|
30
|
+
data-edge-case="not-found"
|
|
31
|
+
>
|
|
32
|
+
<Alternate.Layout.Figure>
|
|
33
|
+
<NotFoundIcon
|
|
34
|
+
width={128}
|
|
35
|
+
height={128}
|
|
36
|
+
viewBox="0 0 128 128"
|
|
37
|
+
aria-hidden="true"
|
|
38
|
+
/>
|
|
39
|
+
</Alternate.Layout.Figure>
|
|
40
|
+
<Alternate.Layout.Title as="h1">
|
|
41
|
+
이 페이지를 찾을 수 없습니다.
|
|
42
|
+
</Alternate.Layout.Title>
|
|
43
|
+
<Alternate.Layout.Contents>
|
|
44
|
+
<p>
|
|
45
|
+
페이지가 이동되었거나 삭제되었을 수 있습니다.
|
|
46
|
+
<br />
|
|
47
|
+
페이지 주소를 다시 확인해 주세요.
|
|
48
|
+
</p>
|
|
49
|
+
{/* 변경: NotFound 본문 줄바꿈은 폭 제한이 아니라 Figma fixed copy의 br로 고정한다. */}
|
|
50
|
+
{onInquiry || inquiryHref ? (
|
|
51
|
+
<p>
|
|
52
|
+
관련된 문의사항은{" "}
|
|
53
|
+
<Alternate.Layout.TextButton href={inquiryHref} onClick={onInquiry}>
|
|
54
|
+
문의하기
|
|
55
|
+
</Alternate.Layout.TextButton>
|
|
56
|
+
를 통해
|
|
57
|
+
<br />
|
|
58
|
+
접수해 주시길 바랍니다.
|
|
59
|
+
</p>
|
|
60
|
+
) : null}
|
|
61
|
+
</Alternate.Layout.Contents>
|
|
62
|
+
{/* 변경: router/history 판정은 내부에서 실행하지 않고 onPrev 또는 fallback href만 연결한다. */}
|
|
63
|
+
{onPrev ? (
|
|
64
|
+
<Alternate.Layout.Button onClick={onPrev}>
|
|
65
|
+
이전 페이지로
|
|
66
|
+
</Alternate.Layout.Button>
|
|
67
|
+
) : (
|
|
68
|
+
<Alternate.Layout.Button as="a" href={fallbackHref}>
|
|
69
|
+
이전 페이지로
|
|
70
|
+
</Alternate.Layout.Button>
|
|
71
|
+
)}
|
|
72
|
+
</Alternate.Layout.Container>
|
|
73
|
+
);
|
|
74
|
+
}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
<svg width="128" height="128" viewBox="0 0 128 128" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
2
|
+
<path fill-rule="evenodd" clip-rule="evenodd" d="M60.6598 32.877C62.1862 30.3743 65.8137 30.3743 67.3401 32.877L103.419 92.0324C105.013 94.6459 103.137 97.9999 100.08 98H27.9197C24.8631 97.9996 22.9866 94.6458 24.5805 92.0324L60.6598 32.877ZM64.5227 81.3305C63.1717 81.3306 62.0762 82.4281 62.0762 83.7819C62.0762 85.1357 63.1716 86.2331 64.5227 86.2333C65.8736 86.2329 66.9693 85.1355 66.9693 83.7819C66.9692 82.4283 65.8735 81.3309 64.5227 81.3305ZM64.5227 49.5599C63.2257 49.5601 62.1737 50.6141 62.1736 51.9137V75.4471C62.1736 76.7467 63.2257 77.8007 64.5227 77.8008C65.8195 77.8004 66.8718 76.7466 66.8718 75.4471V51.9137C66.8717 50.6143 65.8195 49.5603 64.5227 49.5599Z" fill="#F43625"/>
|
|
3
|
+
</svg>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
@use "./styles/index.scss" as edgeCaseStyles;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import "./index.scss";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Edge Case; 화면 단위 예외 상태 템플릿 엔트리
|
|
5
|
+
* @desc
|
|
6
|
+
* - `EdgeCase.Empty`: 빈 상태 화면 조합이다.
|
|
7
|
+
* - `EdgeCase.Loading`: 로딩 상태 화면 조합이다.
|
|
8
|
+
* - `EdgeCase.NotFound`: not-found 상태 화면 조합이다.
|
|
9
|
+
*/
|
|
10
|
+
export { default as EdgeCase } from "./EdgeCase";
|
|
11
|
+
export type * from "./types";
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
.edge-case {
|
|
2
|
+
width: 100%;
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
.edge-case:where([data-edge-case="not-found"]) {
|
|
6
|
+
--alternate-layout-gap: var(--spacing-gap-3);
|
|
7
|
+
--alternate-layout-figure-size: 128px;
|
|
8
|
+
--alternate-layout-title-color: var(--color-label-standard);
|
|
9
|
+
--alternate-layout-title-font-size: var(--font-heading-xsmall-size);
|
|
10
|
+
--alternate-layout-title-line-height: var(--font-heading-xsmall-line-height);
|
|
11
|
+
--alternate-layout-title-letter-spacing: var(
|
|
12
|
+
--font-heading-xsmall-letter-spacing
|
|
13
|
+
);
|
|
14
|
+
--alternate-layout-title-font-weight: var(--font-heading-xsmall-weight);
|
|
15
|
+
--alternate-layout-contents-font-size: var(--font-body-xsmall-size);
|
|
16
|
+
--alternate-layout-contents-line-height: var(--font-body-xsmall-line-height);
|
|
17
|
+
--alternate-layout-contents-letter-spacing: var(
|
|
18
|
+
--font-body-xsmall-letter-spacing
|
|
19
|
+
);
|
|
20
|
+
--alternate-layout-contents-font-weight: var(--font-body-xsmall-weight);
|
|
21
|
+
--button-default-font-label-medium-size: var(--font-label-small-size);
|
|
22
|
+
--button-default-font-label-medium-line-height: var(
|
|
23
|
+
--font-label-small-line-height
|
|
24
|
+
);
|
|
25
|
+
--button-default-font-label-medium-letter-spacing: var(
|
|
26
|
+
--font-label-small-letter-spacing
|
|
27
|
+
);
|
|
28
|
+
--button-default-font-label-medium-weight: var(--font-label-small-weight);
|
|
29
|
+
--button-default-font-weight: var(--font-label-small-weight);
|
|
30
|
+
|
|
31
|
+
min-height: 0;
|
|
32
|
+
padding: calc(var(--spacing-padding-11) + var(--spacing-padding-7))
|
|
33
|
+
var(--spacing-padding-8);
|
|
34
|
+
border: 1px solid var(--color-border-assistive);
|
|
35
|
+
border-radius: var(--theme-radius-large-1);
|
|
36
|
+
background: var(--color-common-100);
|
|
37
|
+
justify-content: flex-start;
|
|
38
|
+
|
|
39
|
+
:where(.alternate-layout-figure) {
|
|
40
|
+
// 변경: not-found preset은 Alternate.Layout gap을 유지하되 Figma root gap 12px만 figure/button 쪽 margin으로 보정한다.
|
|
41
|
+
margin-bottom: var(--spacing-gap-3);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
:where(.alternate-layout-contents) {
|
|
45
|
+
white-space: nowrap;
|
|
46
|
+
|
|
47
|
+
:where(p + p) {
|
|
48
|
+
// 변경: inquiry variant의 문의 문단은 Figma Text frame의 두 번째 content group gap 6px을 따른다.
|
|
49
|
+
margin-top: var(--spacing-gap-3);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
:where(.alternate-layout-button) {
|
|
54
|
+
margin-top: var(--spacing-gap-3);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
@use "./edge-case.scss";
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import type { ReactNode } from "react";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Edge Case Empty Props; 빈 상태 화면 템플릿 props
|
|
5
|
+
* @property {string} [className] 최상위 edge-case container className override다.
|
|
6
|
+
* @property {ReactNode} [figure] 빈 상태를 보조하는 visual 콘텐츠다.
|
|
7
|
+
* @property {ReactNode} title 빈 상태 제목 콘텐츠다.
|
|
8
|
+
* @property {ReactNode} [description] 빈 상태 설명 콘텐츠다.
|
|
9
|
+
* @property {ReactNode} [children] 하단에 주입할 custom action 또는 보조 콘텐츠다.
|
|
10
|
+
*/
|
|
11
|
+
export interface EdgeCaseEmptyProps {
|
|
12
|
+
/**
|
|
13
|
+
* 최상위 edge-case container className override다.
|
|
14
|
+
*/
|
|
15
|
+
className?: string;
|
|
16
|
+
/**
|
|
17
|
+
* 빈 상태를 보조하는 visual 콘텐츠다.
|
|
18
|
+
*/
|
|
19
|
+
figure?: ReactNode;
|
|
20
|
+
/**
|
|
21
|
+
* 빈 상태 제목 콘텐츠다.
|
|
22
|
+
*/
|
|
23
|
+
title: ReactNode;
|
|
24
|
+
/**
|
|
25
|
+
* 빈 상태 설명 콘텐츠다.
|
|
26
|
+
*/
|
|
27
|
+
description?: ReactNode;
|
|
28
|
+
/**
|
|
29
|
+
* 하단에 주입할 custom action 또는 보조 콘텐츠다.
|
|
30
|
+
*/
|
|
31
|
+
children?: ReactNode;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Edge Case Loading Props; 로딩 상태 화면 템플릿 props
|
|
36
|
+
* @property {string} [className] 최상위 edge-case container className override다.
|
|
37
|
+
* @property {ReactNode} [figure] 로딩 상태 visual 콘텐츠다. 없으면 Alternate.LoadingIcon을 사용한다.
|
|
38
|
+
* @property {ReactNode} [title] 로딩 상태 제목 콘텐츠다.
|
|
39
|
+
* @property {ReactNode} [description] 로딩 상태 설명 콘텐츠다.
|
|
40
|
+
* @property {ReactNode} [children] 하단에 주입할 custom action 또는 보조 콘텐츠다.
|
|
41
|
+
*/
|
|
42
|
+
export interface EdgeCaseLoadingProps {
|
|
43
|
+
/**
|
|
44
|
+
* 최상위 edge-case container className override다.
|
|
45
|
+
*/
|
|
46
|
+
className?: string;
|
|
47
|
+
/**
|
|
48
|
+
* 로딩 상태 visual 콘텐츠다. 없으면 Alternate.LoadingIcon을 사용한다.
|
|
49
|
+
*/
|
|
50
|
+
figure?: ReactNode;
|
|
51
|
+
/**
|
|
52
|
+
* 로딩 상태 제목 콘텐츠다.
|
|
53
|
+
*/
|
|
54
|
+
title?: ReactNode;
|
|
55
|
+
/**
|
|
56
|
+
* 로딩 상태 설명 콘텐츠다.
|
|
57
|
+
*/
|
|
58
|
+
description?: ReactNode;
|
|
59
|
+
/**
|
|
60
|
+
* 하단에 주입할 custom action 또는 보조 콘텐츠다.
|
|
61
|
+
*/
|
|
62
|
+
children?: ReactNode;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Edge Case Not Found Props; not-found 상태 화면 템플릿 props
|
|
67
|
+
* @property {string} [className] 최상위 edge-case container className override다.
|
|
68
|
+
* @property {string} [inquiryHref] 문의 text action을 link로 렌더링할 href다.
|
|
69
|
+
* @property {() => void} [onInquiry] 문의 text action을 button으로 렌더링할 콜백이다.
|
|
70
|
+
* @property {string} [fallbackHref] onPrev가 없을 때 사용할 fallback href다.
|
|
71
|
+
* @property {() => void} [onPrev] 이전 페이지 이동을 소비 앱에서 실행하는 콜백이다.
|
|
72
|
+
*/
|
|
73
|
+
export interface EdgeCaseNotFoundProps {
|
|
74
|
+
/**
|
|
75
|
+
* 최상위 edge-case container className override다.
|
|
76
|
+
*/
|
|
77
|
+
className?: string;
|
|
78
|
+
/**
|
|
79
|
+
* 문의 text action을 link로 렌더링할 href다.
|
|
80
|
+
*/
|
|
81
|
+
inquiryHref?: string;
|
|
82
|
+
/**
|
|
83
|
+
* 문의 text action을 button으로 렌더링할 콜백이다.
|
|
84
|
+
*/
|
|
85
|
+
onInquiry?: () => void;
|
|
86
|
+
/**
|
|
87
|
+
* onPrev가 없을 때 사용할 fallback href다.
|
|
88
|
+
*/
|
|
89
|
+
fallbackHref?: string;
|
|
90
|
+
/**
|
|
91
|
+
* 이전 페이지 이동을 소비 앱에서 실행하는 콜백이다.
|
|
92
|
+
*/
|
|
93
|
+
onPrev?: () => void;
|
|
94
|
+
}
|
package/src/index.scss
CHANGED