@uniai-fe/uds-templates 0.4.20 → 0.4.22

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@uniai-fe/uds-templates",
3
- "version": "0.4.20",
3
+ "version": "0.4.22",
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.95.2",
73
+ "@tanstack/react-query": "^5.96.0",
74
74
  "@types/node": "^24.10.2",
75
75
  "@types/react": "^19.2.14",
76
76
  "@types/react-dom": "^19.2.3",
@@ -24,22 +24,17 @@ export default function AuthLoginContainer({
24
24
  onFindPasswordLinkClick,
25
25
  }: AuthLoginProps) {
26
26
  return (
27
- <>
28
- <AuthContainer
29
- className={clsx("auth-login-container", className)}
30
- header={header}
31
- footer={footer}
32
- >
33
- <AuthLoginFormField {...fieldOptions} />
34
- {linkOptions && (
35
- <AuthLoginLinkButtons
36
- hrefFindId={linkOptions.find.id}
37
- hrefFindPassword={linkOptions.find.password}
38
- hrefSignup={linkOptions.signup}
39
- onFindPasswordClick={onFindPasswordLinkClick}
40
- />
41
- )}
42
- </AuthContainer>
43
- </>
27
+ <AuthContainer
28
+ className={clsx("auth-login-container", className)}
29
+ header={header}
30
+ footer={footer}
31
+ >
32
+ <AuthLoginFormField {...fieldOptions} />
33
+ {/* 링크 옵션이 부분적으로만 넘어와도 내부에서 존재하는 항목만 렌더링한다. */}
34
+ <AuthLoginLinkButtons
35
+ linkOptions={linkOptions}
36
+ onFindPasswordClick={onFindPasswordLinkClick}
37
+ />
38
+ </AuthContainer>
44
39
  );
45
40
  }
@@ -1,55 +1,76 @@
1
1
  import Link from "next/link";
2
2
  import { Button, Divider } from "@uniai-fe/uds-primitives";
3
+ import type { AuthLoginLinkOptions } from "../types";
3
4
 
5
+ /**
6
+ * 로그인 링크 버튼 묶음; 전달된 링크만 선택적으로 렌더링한다.
7
+ * @component
8
+ * @param {{ linkOptions?: AuthLoginLinkOptions; onFindPasswordClick?: () => void; }} props
9
+ * @param {AuthLoginLinkOptions} [props.linkOptions] 로그인 링크 옵션
10
+ * @param {() => void} [props.onFindPasswordClick] 비밀번호 찾기 커스텀 클릭 핸들러
11
+ */
4
12
  export default function AuthLoginLinkButtons({
5
- hrefFindId,
6
- hrefFindPassword,
7
- hrefSignup,
13
+ linkOptions,
8
14
  onFindPasswordClick,
9
15
  }: {
10
- hrefFindId: string;
11
- hrefFindPassword: string;
12
- hrefSignup: string;
16
+ linkOptions?: AuthLoginLinkOptions;
13
17
  onFindPasswordClick?: () => void;
14
18
  }) {
19
+ const hrefFindId = linkOptions?.find?.id;
20
+ const hrefFindPassword = linkOptions?.find?.password;
21
+ const hrefSignup = linkOptions?.signup;
22
+
23
+ if (!hrefFindId && !hrefFindPassword && !hrefSignup) {
24
+ return null;
25
+ }
26
+
15
27
  return (
16
28
  <div className="auth-login-util-container">
17
- <div className="auth-login-find-account">
18
- <Link
19
- href={hrefFindId}
20
- className="auth-login-find-account-button auth-find-id-button"
21
- >
22
- <span>아이디 찾기</span>
23
- </Link>
24
- <Divider />
25
- {onFindPasswordClick ? (
26
- <button
27
- type="button"
28
- className="auth-login-find-account-button auth-find-password-button"
29
- onClick={onFindPasswordClick}
30
- >
31
- <span>비밀번호 찾기</span>
32
- </button>
33
- ) : (
34
- <Link
35
- href={hrefFindPassword}
36
- className="auth-login-find-account-button auth-find-password-button"
29
+ {(hrefFindId || hrefFindPassword) && (
30
+ <div className="auth-login-find-account">
31
+ {hrefFindId && (
32
+ <Link
33
+ href={hrefFindId}
34
+ className="auth-login-find-account-button auth-find-id-button"
35
+ >
36
+ <span>아이디 찾기</span>
37
+ </Link>
38
+ )}
39
+ {hrefFindId && hrefFindPassword && <Divider />}
40
+ {/* 비밀번호 찾기 링크가 있을 때만 버튼/링크를 선택적으로 노출한다. */}
41
+ {hrefFindPassword &&
42
+ (onFindPasswordClick ? (
43
+ <button
44
+ type="button"
45
+ className="auth-login-find-account-button auth-find-password-button"
46
+ onClick={onFindPasswordClick}
47
+ >
48
+ <span>비밀번호 찾기</span>
49
+ </button>
50
+ ) : (
51
+ <Link
52
+ href={hrefFindPassword}
53
+ className="auth-login-find-account-button auth-find-password-button"
54
+ >
55
+ <span>비밀번호 찾기</span>
56
+ </Link>
57
+ ))}
58
+ </div>
59
+ )}
60
+ {hrefSignup && (
61
+ <div className="auth-login-signup">
62
+ {/* 회원가입 링크가 있을 때만 signup CTA를 유지한다. */}
63
+ <Button.Rounded
64
+ as={Link}
65
+ href={hrefSignup}
66
+ className="auth-login-signup-button"
67
+ priority="tertiary"
68
+ size="small"
37
69
  >
38
- <span>비밀번호 찾기</span>
39
- </Link>
40
- )}
41
- </div>
42
- <div className="auth-login-signup">
43
- <Button.Rounded
44
- as={Link}
45
- href={hrefSignup}
46
- className="auth-login-signup-button"
47
- priority="tertiary"
48
- size="small"
49
- >
50
- 회원가입
51
- </Button.Rounded>
52
- </div>
70
+ 회원가입
71
+ </Button.Rounded>
72
+ </div>
73
+ )}
53
74
  </div>
54
75
  );
55
76
  }
@@ -244,31 +244,31 @@ export interface AuthLoginFieldOptions {
244
244
 
245
245
  /**
246
246
  * 로그인 화면 링크 옵션; 찾기/회원가입 링크를 묶는다.
247
- * @property {{ id: string; password: string }} find 계정찾기 링크
248
- * @property {string} find.id 아이디 찾기 링크
249
- * @property {string} find.password 비밀번호 찾기 링크
250
- * @property {string} signup 회원가입 링크
247
+ * @property {{ id?: string; password?: string }} [find] 계정찾기 링크
248
+ * @property {string} [find.id] 아이디 찾기 링크
249
+ * @property {string} [find.password] 비밀번호 찾기 링크
250
+ * @property {string} [signup] 회원가입 링크
251
251
  */
252
252
  export interface AuthLoginLinkOptions {
253
253
  /**
254
254
  * 아이디/비밀번호 찾기 링크
255
- * @property {string} id 아이디 찾기 링크
256
- * @property {string} password 비밀번호 찾기 링크
255
+ * @property {string} [id] 아이디 찾기 링크
256
+ * @property {string} [password] 비밀번호 찾기 링크
257
257
  */
258
- find: {
258
+ find?: {
259
259
  /**
260
260
  * 아이디 찾기 링크
261
261
  */
262
- id: string;
262
+ id?: string;
263
263
  /**
264
264
  * 비밀번호 찾기 링크
265
265
  */
266
- password: string;
266
+ password?: string;
267
267
  };
268
268
  /**
269
269
  * 회원가입 링크
270
270
  */
271
- signup: string;
271
+ signup?: string;
272
272
  }
273
273
 
274
274
  /**
@@ -279,7 +279,7 @@ export interface AuthLoginLinkOptions {
279
279
  * @property {ReactNode} [footer] 하단 콘텐츠
280
280
  * @property {AuthLoginFieldOptions} [fieldOptions] 입력 필드 옵션
281
281
  * @property {AuthLoginLinkOptions} [linkOptions] 계정관련 링크 옵션
282
- * @property {() => void} onFindPasswordLinkClick 비밀번호 찾기 링크버튼 클릭 콜백 이벤트
282
+ * @property {() => void} [onFindPasswordLinkClick] 비밀번호 찾기 링크버튼 클릭 콜백 이벤트
283
283
  */
284
284
  export interface AuthLoginProps extends Omit<AuthContainerProps, "children"> {
285
285
  /**
@@ -11,6 +11,7 @@ export default function CCTVVideoOverlayHeader({
11
11
  activeTitle,
12
12
  title,
13
13
  isLive,
14
+ isShared,
14
15
  }: CctvVideoOverlayHeaderProps) {
15
16
  const showUpper = activeLiveState || activeCloseButton;
16
17
  const showLower = activeTitle;
@@ -23,7 +24,15 @@ export default function CCTVVideoOverlayHeader({
23
24
  >
24
25
  {showUpper && (
25
26
  <div className="cctv-video-overlay-header-upper">
26
- {activeLiveState && <CCTVVideoLiveState isLive={isLive} />}
27
+ {activeLiveState && (
28
+ <CCTVVideoLiveState
29
+ isLive={isLive}
30
+ isShared={isShared}
31
+ {...(activeCloseButton
32
+ ? { badgeOptions: { size: "medium" } }
33
+ : {})}
34
+ />
35
+ )}
27
36
  {activeCloseButton && <CCTVVideoCloseButton />}
28
37
  </div>
29
38
  )}
@@ -1,21 +1,27 @@
1
1
  "use client";
2
2
 
3
3
  import clsx from "clsx";
4
- import { Badge } from "@uniai-fe/uds-primitives";
4
+ import { Badge, type BadgeProps } from "@uniai-fe/uds-primitives";
5
5
 
6
6
  export default function CCTVVideoLiveState({
7
7
  isLive = false,
8
+ isShared = false,
9
+ badgeOptions,
8
10
  }: {
9
11
  isLive?: boolean;
12
+ isShared?: boolean;
13
+ badgeOptions?: Partial<Omit<BadgeProps, "className" | "children">>;
10
14
  }) {
15
+ const { size, intent, ...options } = badgeOptions ?? {};
11
16
  return (
12
17
  <Badge
13
- size="xsmall"
14
- intent="tertiary"
18
+ size={size ?? "xsmall"}
19
+ intent={intent ?? "tertiary"}
15
20
  className={clsx("cctv-video-live-state", { on: isLive == true })}
21
+ {...options}
16
22
  >
17
23
  <figure className="cctv-video-live-state-dot"></figure>
18
- <span>Live</span>
24
+ <span>{isShared ? "외부공유중" : "Live"}</span>
19
25
  </Badge>
20
26
  );
21
27
  }
@@ -29,6 +29,7 @@ export interface API_Req_GetCompanyListParams extends Omit<
29
29
  * @property {boolean} cam_online 카메라 설치상태
30
30
  * @property {string} [cam_rtc] 카메라 스트리밍 WebRTC 경로
31
31
  * @property {string} [cam_rtcp] 카메라 RTCP 경로
32
+ * @property {boolean} [cam_shared] 카메라 외부공유 여부
32
33
  */
33
34
  export interface API_Res_CctvCompanyCameraList {
34
35
  // API 응답은 데이터-only 구조이므로 UI 전용 콜백은 포함하지 않는다.
@@ -54,6 +55,10 @@ export interface API_Res_CctvCompanyCameraList {
54
55
  * RTCP 경로
55
56
  */
56
57
  cam_rtcp?: string;
58
+ /**
59
+ * 외부공유 상태
60
+ */
61
+ cam_shared?: boolean;
57
62
  }
58
63
 
59
64
  /**
@@ -9,6 +9,7 @@ import type { CctvCompanyCameraData } from "./list";
9
9
  * @property {React.ReactNode} [title] 제목 콘텐츠
10
10
  * @property {boolean} [activeTime] 시간 표시 영역 활성화 여부
11
11
  * @property {boolean} [isLive] Live 뱃지를 on/off 상태로 표시할지 여부
12
+ * @property {boolean} [isShared] 외부공유 여부
12
13
  */
13
14
  export interface CctvVideoOverlayHeaderProps {
14
15
  className?: string;
@@ -32,6 +33,10 @@ export interface CctvVideoOverlayHeaderProps {
32
33
  * 시간 표시 영역 활성화 여부
33
34
  */
34
35
  isLive?: boolean;
36
+ /**
37
+ * 해당 카메라의 외부공유 여부 상태
38
+ */
39
+ isShared?: boolean;
35
40
  }
36
41
 
37
42
  /**