@x-plat/design-system 0.5.0 → 0.5.2

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.
@@ -0,0 +1,95 @@
1
+ # 파일/미디어: FileUpload / ImageSelector / Video
2
+
3
+ ## FileUpload
4
+
5
+ 파일 업로드 영역을 표시한다. 드래그 앤 드롭과 클릭 업로드를 모두 지원한다.
6
+
7
+ ```tsx
8
+ import { FileUpload } from "@xplat/design-system";
9
+ ```
10
+
11
+ | Prop | 타입 | 기본값 | 설명 |
12
+ |------|------|--------|------|
13
+ | accept | `string` | — | 허용 파일 타입 (예: `"image/*,.pdf"`) |
14
+ | multiple | `boolean` | `false` | 다중 파일 허용 |
15
+ | maxSize | `number` | — | 최대 파일 크기 (bytes). 초과 파일은 자동 필터 |
16
+ | onChange | `(files: File[]) => void` | — | 파일 선택 콜백 |
17
+ | label | `string` | `"파일을 드래그하거나 클릭하여 업로드"` | 안내 텍스트 |
18
+ | description | `string` | — | 부가 설명 |
19
+
20
+ ```tsx
21
+ <FileUpload
22
+ accept="image/*"
23
+ multiple
24
+ maxSize={5 * 1024 * 1024}
25
+ onChange={(files) => console.log(files)}
26
+ description="최대 5MB, 이미지만 허용"
27
+ />
28
+ ```
29
+
30
+ ---
31
+
32
+ ## ImageSelector
33
+
34
+ 단일 이미지를 선택/미리보기하는 컨트롤이다. controlled 방식으로 동작한다.
35
+
36
+ ```tsx
37
+ import { ImageSelector } from "@xplat/design-system";
38
+ ```
39
+
40
+ | Prop | 타입 | 기본값 | 설명 |
41
+ |------|------|--------|------|
42
+ | value | `File` | — | 선택된 이미지 파일 |
43
+ | label | `string` | `"이미지 추가하기"` | 빈 상태 안내 텍스트 |
44
+ | onChange | `(value: File \| undefined) => void` | — | 변경 콜백 (삭제 시 `undefined`) |
45
+
46
+ ```tsx
47
+ const [image, setImage] = useState<File | undefined>();
48
+
49
+ <ImageSelector value={image} onChange={setImage} />
50
+ ```
51
+
52
+ ---
53
+
54
+ ## Video
55
+
56
+ 비디오 플레이어를 표시한다. `controls={false}`이면 커스텀 재생/일시정지 오버레이를 표시한다. `ref`를 지원한다.
57
+
58
+ ```tsx
59
+ import { Video } from "@xplat/design-system";
60
+ ```
61
+
62
+ | Prop | 타입 | 기본값 | 설명 |
63
+ |------|------|--------|------|
64
+ | src `*` | `string` | — | 비디오 URL |
65
+ | poster | `string` | — | 썸네일 이미지 URL |
66
+ | controls | `boolean` | `true` | 네이티브 컨트롤 표시. `false`면 커스텀 오버레이 |
67
+ | autoPlay | `boolean` | — | 자동 재생 |
68
+ | muted | `boolean` | — | 음소거 |
69
+ | loop | `boolean` | — | 반복 재생 |
70
+ | playsInline | `boolean` | `true` | 인라인 재생 (모바일) |
71
+
72
+ `HTMLVideoElement`의 나머지 속성도 전달 가능하다.
73
+
74
+ ```tsx
75
+ const videoRef = useRef<HTMLVideoElement>(null);
76
+
77
+ <Video
78
+ ref={videoRef}
79
+ src="/intro.mp4"
80
+ poster="/thumb.jpg"
81
+ controls={false}
82
+ muted
83
+ loop
84
+ />
85
+ ```
86
+
87
+ ---
88
+
89
+ ## 의사결정
90
+
91
+ | 상황 | 사용할 것 |
92
+ |------|----------|
93
+ | 파일 업로드 (범용) | FileUpload |
94
+ | 이미지 1장 선택 + 미리보기 | ImageSelector |
95
+ | 비디오 재생 | Video |
@@ -0,0 +1,60 @@
1
+ # 폼 컨트롤: CheckBox / Radio / Switch
2
+
3
+ ## CheckBox
4
+
5
+ ```tsx
6
+ <CheckBox label="동의합니다" checked={checked} onChange={setChecked} />
7
+ <CheckBox label="에러 상태" type="error" checked={false} />
8
+ ```
9
+
10
+ | Prop | 설명 |
11
+ |------|------|
12
+ | label | 라벨 텍스트 |
13
+ | checked | 체크 상태 |
14
+ | type | `"brand" \| "success" \| "error" \| "warning" \| "info"` |
15
+
16
+ ---
17
+
18
+ ## Radio
19
+
20
+ **RadioGroup 안에 Radio를 조합한다.**
21
+
22
+ ```tsx
23
+ <RadioGroup name="fruit" value={value} onChange={(e) => setValue(e.target.value)}>
24
+ <Radio value="apple" label="사과" />
25
+ <Radio value="banana" label="바나나" />
26
+ </RadioGroup>
27
+ ```
28
+
29
+ | Prop (RadioGroup) | 설명 |
30
+ |-------------------|------|
31
+ | name | 그룹 이름 |
32
+ | value | 선택된 값 |
33
+ | onChange | 변경 콜백 |
34
+
35
+ ---
36
+
37
+ ## Switch
38
+
39
+ **controlled 패턴**을 사용한다.
40
+
41
+ ```tsx
42
+ <Switch value={isOn} onChange={setIsOn} />
43
+ <Switch value={isOn} onChange={setIsOn} type="brand" />
44
+ ```
45
+
46
+ | Prop | 설명 |
47
+ |------|------|
48
+ | value | 토글 상태 |
49
+ | onChange | 변경 콜백 |
50
+ | type | 스타일 타입 |
51
+
52
+ ---
53
+
54
+ ## 의사결정
55
+
56
+ | 상황 | 사용할 것 |
57
+ |------|----------|
58
+ | 다중 선택 | CheckBox |
59
+ | 단일 선택 (여러 옵션 중 하나) | Radio |
60
+ | 켜기/끄기 토글 | Switch |
@@ -0,0 +1,38 @@
1
+ # HtmlTypeWriter
2
+
3
+ HTML 문자열을 한 글자씩 타이핑하는 효과를 표시한다. HTML 태그 구조를 유지하면서 텍스트만 순차적으로 렌더한다.
4
+
5
+ ```tsx
6
+ import { HtmlTypeWriter } from "@xplat/design-system";
7
+ ```
8
+
9
+ ## Props
10
+
11
+ | Prop | 타입 | 기본값 | 설명 |
12
+ |------|------|--------|------|
13
+ | html `*` | `string` | — | 타이핑할 HTML 문자열 |
14
+ | duration | `number` | `20` | 글자당 타이핑 간격 (ms) |
15
+ | onDone | `() => void` | — | 타이핑 완료 콜백 |
16
+ | onChange | `() => void` | — | 타이핑 진행 중 매 글자마다 호출 |
17
+
18
+ ---
19
+
20
+ ## 사용 예시
21
+
22
+ ```tsx
23
+ <HtmlTypeWriter
24
+ html="<p>안녕하세요. <strong>타이핑</strong> 효과입니다.</p>"
25
+ duration={30}
26
+ onDone={() => console.log("타이핑 완료")}
27
+ />
28
+ ```
29
+
30
+ ### 동적 HTML 변경
31
+
32
+ `html` prop이 변경되면 타이핑을 처음부터 다시 시작한다.
33
+
34
+ ```tsx
35
+ const [content, setContent] = useState("<p>첫 번째 메시지</p>");
36
+
37
+ <HtmlTypeWriter html={content} onDone={() => setContent("<p>두 번째 메시지</p>")} />
38
+ ```
@@ -0,0 +1,55 @@
1
+ # Input / PasswordInput / TextArea
2
+
3
+ ## Input
4
+
5
+ ```tsx
6
+ <Input placeholder="이름" />
7
+ <Input type="email" placeholder="이메일" />
8
+ <Input
9
+ type="tel"
10
+ validations={[{ status: "error", message: "필수 항목입니다" }]}
11
+ />
12
+ <Input suffix={<SearchIcon />} />
13
+ ```
14
+
15
+ | Prop | 타입 | 기본값 | 설명 |
16
+ |------|------|--------|------|
17
+ | type | `"text" \| "number" \| "email" \| "tel"` | `"text"` | 입력 타입 |
18
+ | size | `"sm" \| "md" \| "lg"` | `"md"` | 크기 |
19
+ | validations | `{ status, message }[]` | - | 유효성 검사 |
20
+ | suffix | `ReactNode` | - | 우측 아이콘 |
21
+
22
+ `ref` 전달을 지원한다 (`HTMLInputElement`).
23
+
24
+ ---
25
+
26
+ ## PasswordInput
27
+
28
+ 비밀번호 입력 전용이다. 눈 아이콘으로 비밀번호 표시/숨김을 토글한다.
29
+
30
+ ```tsx
31
+ <PasswordInput placeholder="비밀번호" />
32
+ ```
33
+
34
+ ---
35
+
36
+ ## TextArea
37
+
38
+ 자동 높이 조정을 지원한다. `ref` 전달을 지원한다 (`HTMLTextAreaElement`).
39
+
40
+ ```tsx
41
+ <TextArea placeholder="내용을 입력하세요" />
42
+ ```
43
+
44
+ ---
45
+
46
+ ## 상태
47
+
48
+ | 상태 | 설명 |
49
+ |------|------|
50
+ | default | 기본 |
51
+ | hover | 마우스 오버 |
52
+ | focused | 포커스 |
53
+ | typing | 입력 중 |
54
+ | filled | 입력 완료 |
55
+ | disabled | 비활성화 |
@@ -0,0 +1,80 @@
1
+ # 내비게이션: Tab / CardTab / Breadcrumb / Pagination / Steps
2
+
3
+ ## Tab
4
+
5
+ 인덱스 기반 탭이다. 탭 영역만 제공한다.
6
+
7
+ ```tsx
8
+ <Tab activeIndex={activeIndex} onChange={setActiveIndex} type="default">
9
+ <Tab.Item>탭1</Tab.Item>
10
+ <Tab.Item>탭2</Tab.Item>
11
+ </Tab>
12
+ ```
13
+
14
+ | Prop | 설명 |
15
+ |------|------|
16
+ | activeIndex | 활성 탭 인덱스 (controlled) |
17
+ | type | `"default" \| "toggle"` |
18
+
19
+ ---
20
+
21
+ ## CardTab
22
+
23
+ 값 기반 탭이다. **CardTab.Panel만 children으로 허용한다.**
24
+
25
+ ```tsx
26
+ <CardTab tabs={[{ value: "tab1", title: "탭1" }, { value: "tab2", title: "탭2" }]}>
27
+ <CardTab.Panel value="tab1">탭1 내용</CardTab.Panel>
28
+ <CardTab.Panel value="tab2">탭2 내용</CardTab.Panel>
29
+ </CardTab>
30
+ ```
31
+
32
+ ---
33
+
34
+ ## Breadcrumb
35
+
36
+ 경로를 표시한다.
37
+
38
+ ```tsx
39
+ <Breadcrumb items={[
40
+ { label: "홈", href: "/" },
41
+ { label: "설정", href: "/settings" },
42
+ { label: "프로필" },
43
+ ]} />
44
+ ```
45
+
46
+ ---
47
+
48
+ ## Pagination
49
+
50
+ 페이지네이션을 표시한다.
51
+
52
+ ```tsx
53
+ <Pagination current={page} total={100} onChange={setPage} />
54
+ ```
55
+
56
+ ---
57
+
58
+ ## Steps
59
+
60
+ 단계 진행을 표시한다.
61
+
62
+ ```tsx
63
+ <Steps
64
+ items={[
65
+ { title: "정보 입력" },
66
+ { title: "확인" },
67
+ { title: "완료" },
68
+ ]}
69
+ current={1}
70
+ />
71
+ ```
72
+
73
+ ---
74
+
75
+ ## 의사결정
76
+
77
+ | 상황 | 사용할 것 |
78
+ |------|----------|
79
+ | 탭 영역만 (콘텐츠는 직접 관리) | Tab |
80
+ | 탭 + 패널 콘텐츠 | CardTab |
@@ -0,0 +1,72 @@
1
+ # 오버레이: Modal / Drawer / PopOver / Tooltip
2
+
3
+ 모두 **controlled 패턴**을 사용한다 (`isOpen`, `onClose`).
4
+
5
+ ---
6
+
7
+ ## Modal
8
+
9
+ 중앙 다이얼로그를 표시한다.
10
+
11
+ ```tsx
12
+ <Modal isOpen={isOpen} onClose={() => setIsOpen(false)}>
13
+ <h2>제목</h2>
14
+ <p>내용</p>
15
+ </Modal>
16
+ ```
17
+
18
+ ---
19
+
20
+ ## Drawer
21
+
22
+ 사이드 패널을 표시한다.
23
+
24
+ ```tsx
25
+ <Drawer isOpen={isOpen} onClose={handleClose} placement="right" width={400}>
26
+ <p>사이드 패널</p>
27
+ </Drawer>
28
+ ```
29
+
30
+ | Prop | 설명 |
31
+ |------|------|
32
+ | placement | `"left" \| "right"` |
33
+ | width | 패널 너비 |
34
+
35
+ ---
36
+
37
+ ## PopOver
38
+
39
+ 트리거 요소 기반 팝오버를 표시한다.
40
+
41
+ ```tsx
42
+ <PopOver
43
+ isOpen={isOpen}
44
+ onClose={() => setIsOpen(false)}
45
+ trigger={<Button>열기</Button>}
46
+ >
47
+ <p>팝오버 내용</p>
48
+ </PopOver>
49
+ ```
50
+
51
+ ---
52
+
53
+ ## Tooltip
54
+
55
+ 부가 정보를 표시한다. **description이 필수이다.** children이 트리거이다.
56
+
57
+ ```tsx
58
+ <Tooltip description="도움말 텍스트">
59
+ <Button>호버하세요</Button>
60
+ </Tooltip>
61
+ ```
62
+
63
+ ---
64
+
65
+ ## 의사결정
66
+
67
+ | 상황 | 사용할 것 |
68
+ |------|----------|
69
+ | 전체 화면 차단 (확인/취소) | Modal |
70
+ | 사이드 패널 (상세 정보/폼) | Drawer |
71
+ | 트리거 기반 부가 정보 | PopOver |
72
+ | 간단한 설명 텍스트 | Tooltip |
@@ -0,0 +1,44 @@
1
+ # Select
2
+
3
+ **Select.Item만 children으로 허용한다.**
4
+
5
+ ```tsx
6
+ <Select placeholder="선택하세요" onChange={(value, label) => console.log(value)}>
7
+ <Select.Item value="apple">사과</Select.Item>
8
+ <Select.Item value="banana">바나나</Select.Item>
9
+ </Select>
10
+ ```
11
+
12
+ ## onChange
13
+
14
+ `onChange(value: string, label: string)` 형태로 선택된 값과 라벨을 전달한다.
15
+
16
+ ## Controlled / Uncontrolled
17
+
18
+ ```tsx
19
+ // controlled
20
+ <Select value={selected} onChange={(v) => setSelected(v)}>
21
+ <Select.Item value="a">A</Select.Item>
22
+ </Select>
23
+
24
+ // uncontrolled
25
+ <Select defaultValue="a">
26
+ <Select.Item value="a">A</Select.Item>
27
+ </Select>
28
+ ```
29
+
30
+ ## 상태
31
+
32
+ | 상태 | 설명 |
33
+ |------|------|
34
+ | error | 에러 표시 |
35
+ | disabled | 비활성화 |
36
+
37
+ ---
38
+
39
+ ## 유사 컴포넌트 구분
40
+
41
+ | 목적 | 사용할 것 |
42
+ |------|----------|
43
+ | 값 선택 (onChange) | Select |
44
+ | 액션 메뉴 (onClick per item) | Dropdown |
@@ -0,0 +1,84 @@
1
+ # Swiper
2
+
3
+ 슬라이더/캐러셀을 표시한다. 드래그, 자동 재생, 루프를 지원하며 controlled/uncontrolled 모두 가능하다.
4
+
5
+ ```tsx
6
+ import { Swiper } from "@xplat/design-system";
7
+ import type { SwiperHandle } from "@xplat/design-system";
8
+ ```
9
+
10
+ ## Props
11
+
12
+ | Prop | 타입 | 기본값 | 설명 |
13
+ |------|------|--------|------|
14
+ | renderItems | `ReactNode[]` | `[]` | 슬라이드 아이템 배열 |
15
+ | viewItemCount | `number` | `1` | 한 번에 보이는 아이템 수 |
16
+ | maxItems | `number` | — | 최대 아이템 수 (초과 시 잘림) |
17
+ | spaceBetween | `number` | `16` | 슬라이드 간격 (px) |
18
+ | speed | `number` | `300` | 전환 속도 (ms) |
19
+ | slideBy | `number` | `1` | 한 번에 이동할 슬라이드 수 |
20
+ | auto | `boolean` | `false` | 자동 슬라이딩 |
21
+ | autoplayDelay | `number` | `3000` | 오토플레이 간격 (ms) |
22
+ | loop | `boolean` | `false` | 무한 루프 |
23
+ | showProgress | `boolean` | `false` | 진행바 표시 |
24
+ | index | `number` | — | 현재 인덱스 (controlled) |
25
+ | onChange | `(index: number) => void` | — | 슬라이드 변경 콜백 |
26
+ | swiperRef | `RefObject<SwiperHandle>` | — | 명령형 제어 ref |
27
+
28
+ ### SwiperHandle
29
+
30
+ | 메서드 | 설명 |
31
+ |--------|------|
32
+ | `slidePrev()` | 이전 슬라이드로 이동 |
33
+ | `slideNext()` | 다음 슬라이드로 이동 |
34
+ | `slideTo(index)` | 특정 인덱스로 이동 |
35
+
36
+ ---
37
+
38
+ ## 사용 예시
39
+
40
+ ### 기본
41
+
42
+ ```tsx
43
+ <Swiper
44
+ renderItems={[
45
+ <img src="/img1.jpg" />,
46
+ <img src="/img2.jpg" />,
47
+ <img src="/img3.jpg" />,
48
+ ]}
49
+ />
50
+ ```
51
+
52
+ ### 자동 재생 + 루프 + 진행바
53
+
54
+ ```tsx
55
+ <Swiper
56
+ renderItems={slides}
57
+ auto
58
+ loop
59
+ showProgress
60
+ autoplayDelay={5000}
61
+ />
62
+ ```
63
+
64
+ ### 명령형 제어
65
+
66
+ ```tsx
67
+ const ref = useRef<SwiperHandle>(null);
68
+
69
+ <Swiper swiperRef={ref} renderItems={slides} />
70
+
71
+ <button onClick={() => ref.current?.slidePrev()}>이전</button>
72
+ <button onClick={() => ref.current?.slideNext()}>다음</button>
73
+ ```
74
+
75
+ ### 다중 아이템 뷰
76
+
77
+ ```tsx
78
+ <Swiper
79
+ renderItems={cards}
80
+ viewItemCount={3}
81
+ spaceBetween={24}
82
+ slideBy={3}
83
+ />
84
+ ```
@@ -0,0 +1,62 @@
1
+ # Table
2
+
3
+ **반드시 `Table > TableHead/TableBody > TableRow > TableCell` 구조를 따른다.**
4
+
5
+ ```tsx
6
+ <Table>
7
+ <TableHead>
8
+ <TableRow>
9
+ <TableCell>이름</TableCell>
10
+ <TableCell>나이</TableCell>
11
+ </TableRow>
12
+ </TableHead>
13
+ <TableBody>
14
+ <TableRow>
15
+ <TableCell>홍길동</TableCell>
16
+ <TableCell>30</TableCell>
17
+ </TableRow>
18
+ </TableBody>
19
+ </Table>
20
+ ```
21
+
22
+ ## Props
23
+
24
+ | Prop | 설명 |
25
+ |------|------|
26
+ | headerSticky | 헤더 고정 |
27
+ | isSticky | 특정 셀 고정 |
28
+
29
+ ## TableRow type
30
+
31
+ | type | 용도 |
32
+ |------|------|
33
+ | primary | 기본 행 |
34
+ | secondary | 보조 행 (배경색 구분) |
35
+
36
+ ---
37
+
38
+ ## 올바른 예시
39
+
40
+ ```tsx
41
+ <Table headerSticky>
42
+ <TableHead>
43
+ <TableRow>
44
+ <TableCell isSticky>이름</TableCell>
45
+ <TableCell>부서</TableCell>
46
+ <TableCell>직급</TableCell>
47
+ </TableRow>
48
+ </TableHead>
49
+ <TableBody>
50
+ <TableRow type="primary">
51
+ <TableCell isSticky>홍길동</TableCell>
52
+ <TableCell>개발팀</TableCell>
53
+ <TableCell>선임</TableCell>
54
+ </TableRow>
55
+ <TableRow type="secondary">
56
+ <TableCell isSticky>김철수</TableCell>
57
+ <TableCell>디자인팀</TableCell>
58
+ <TableCell>책임</TableCell>
59
+ </TableRow>
60
+ </TableBody>
61
+ </Table>
62
+ ```
@@ -0,0 +1,95 @@
1
+ # Grid 시스템
2
+
3
+ 페이지 레이아웃과 컴포넌트 내부 배치 모두 Grid를 사용한다.
4
+
5
+ ```tsx
6
+ import { FullGrid, FullScreen, GridItem } from "@x-plat/design-system/layout";
7
+ ```
8
+
9
+ ## 컴포넌트
10
+
11
+ | 컴포넌트 | 용도 |
12
+ |---------|------|
13
+ | FullGrid | 12컬럼 그리드 컨테이너 |
14
+ | FullScreen | 전체 화면 그리드 |
15
+ | GridItem | 그리드 아이템 |
16
+
17
+ ## gap
18
+
19
+ ```tsx
20
+ <FullGrid gap={16}>
21
+ <GridItem column={6}>왼쪽</GridItem>
22
+ <GridItem column={6}>오른쪽</GridItem>
23
+ </FullGrid>
24
+ ```
25
+
26
+ ---
27
+
28
+ ## 반응형 브레이크포인트
29
+
30
+ | 브레이크포인트 | 범위 | 최대 컬럼 |
31
+ |---------------|------|-----------|
32
+ | laptop (default) | 1024px ~ | 12 |
33
+ | tablet | 768px ~ 1024px | 8 |
34
+ | mobile | ~ 768px | 4 |
35
+
36
+ ## Column 상속 규칙
37
+
38
+ 하위 브레이크포인트를 지정하지 않으면 상위 값을 상속한다.
39
+
40
+ ```tsx
41
+ <GridItem column={{ default: 6, tablet: 4, mobile: 4 }}>
42
+ 내용
43
+ </GridItem>
44
+ ```
45
+
46
+ ---
47
+
48
+ ## 위젯 패턴
49
+
50
+ ### 대시보드
51
+
52
+ ```tsx
53
+ <FullGrid>
54
+ <GridItem column={{ default: 4, tablet: 4, mobile: 4 }}>
55
+ <Card>위젯 A</Card>
56
+ </GridItem>
57
+ <GridItem column={{ default: 4, tablet: 4, mobile: 4 }}>
58
+ <Card>위젯 B</Card>
59
+ </GridItem>
60
+ <GridItem column={{ default: 4, tablet: 8, mobile: 4 }}>
61
+ <Card>위젯 C</Card>
62
+ </GridItem>
63
+ </FullGrid>
64
+ ```
65
+
66
+ ### 폼
67
+
68
+ ```tsx
69
+ <FullGrid>
70
+ <GridItem column={{ default: 6, tablet: 4, mobile: 4 }}>
71
+ <Input placeholder="이름" />
72
+ </GridItem>
73
+ <GridItem column={{ default: 6, tablet: 4, mobile: 4 }}>
74
+ <Input placeholder="이메일" type="email" />
75
+ </GridItem>
76
+ <GridItem column={{ default: 12, tablet: 8, mobile: 4 }}>
77
+ <Button type="primary">저장</Button>
78
+ </GridItem>
79
+ </FullGrid>
80
+ ```
81
+
82
+ ### 중첩 Grid
83
+
84
+ ```tsx
85
+ <Card title="사용자 정보">
86
+ <FullGrid>
87
+ <GridItem column={{ default: 3, tablet: 2, mobile: 4 }}>
88
+ <Avatar name="홍길동" size="lg" />
89
+ </GridItem>
90
+ <GridItem column={{ default: 9, tablet: 6, mobile: 4 }}>
91
+ <Input placeholder="이름" />
92
+ </GridItem>
93
+ </FullGrid>
94
+ </Card>
95
+ ```