Skip to content

Commit 03b79a7

Browse files
committed
feat: add collection card
1 parent 8f7198d commit 03b79a7

5 files changed

Lines changed: 211 additions & 0 deletions

File tree

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
import { CubeIcon } from '@phosphor-icons/react'
2+
3+
import {
4+
CollectionCard,
5+
CollectionCardButton,
6+
CollectionCardDescription,
7+
CollectionCardHeader,
8+
CollectionCardIcon,
9+
CollectionCardTitle,
10+
Typography,
11+
} from '@genseki/react/v2'
12+
13+
export function CollectionCardSection() {
14+
return (
15+
<div className="grid grid-cols-2 gap-4">
16+
<CollectionCard>
17+
<CollectionCardIcon icon={CubeIcon} />
18+
<CollectionCardHeader>
19+
<CollectionCardTitle>
20+
<Typography type="h4" weight="semibold">
21+
Collection 1
22+
</Typography>
23+
</CollectionCardTitle>
24+
</CollectionCardHeader>
25+
<CollectionCardDescription>
26+
<Typography type="body" weight="normal" className="line-clamp-3">
27+
Lorem ipsum dolor s
28+
</Typography>
29+
</CollectionCardDescription>
30+
<CollectionCardButton onClick={() => {}}>
31+
<Typography type="body" weight="normal">
32+
View collection
33+
</Typography>
34+
</CollectionCardButton>
35+
</CollectionCard>
36+
37+
<CollectionCard>
38+
<CollectionCardIcon icon={CubeIcon} />
39+
<CollectionCardHeader>
40+
<CollectionCardTitle>
41+
<Typography type="h4" weight="semibold">
42+
Collection 1
43+
</Typography>
44+
</CollectionCardTitle>
45+
</CollectionCardHeader>
46+
<CollectionCardDescription>
47+
<Typography type="body" weight="normal" className="line-clamp-3">
48+
Lorem ipsum dolor sit amet consectetur adipisicing elit. Quisquam, quos. Lorem ipsum
49+
dolor sit amet consectetur adipisicing elit. Quisquam, quos. Lorem ipsum dolor sit amet
50+
consectetur adipisicing elit. Quisquam, quos. Lorem ipsum dolor sit amet consectetur
51+
adipisicing elit. Quisquam, quos. Lorem ipsum dolor sit amet consectetur adipisicing
52+
elit. Quisquam, quos.
53+
</Typography>
54+
</CollectionCardDescription>
55+
<CollectionCardButton onClick={() => {}}>
56+
<Typography type="body" weight="normal">
57+
View collection
58+
</Typography>
59+
</CollectionCardButton>
60+
</CollectionCard>
61+
</div>
62+
)
63+
}

examples/ui-playground/src/app/playground/shadcn/page-sidebar.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ const navigationItems = [
3939
{ href: '#textarea', label: 'Textarea' },
4040
{ href: '#toast', label: 'Toast' },
4141
{ href: '#rich-text-editor', label: 'Rich Text Editor' },
42+
{ href: '#collection-card', label: 'Collection Card' },
4243
{ href: '/playground/shadcn/sidebar', label: 'Sidebar' },
4344
]
4445

examples/ui-playground/src/app/playground/shadcn/page.tsx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { Typography } from '@genseki/react/v2'
66
import { ButtonSection } from './button-section'
77
import { CheckboxSection } from './checkbox-section'
88
import { CollapsibleSection } from './collapsible-section'
9+
import { CollectionCardSection } from './collection-card-section'
910
import { ColorPickerSection } from './color-picker-section'
1011
import { ComboboxSection } from './combobox-section'
1112
import { DatePickerSection } from './date-picker-section'
@@ -133,6 +134,10 @@ export default function ComboboxPage() {
133134
Rich Text Editor
134135
</Typography>
135136
<RichTextSection />
137+
<Typography type="h2" weight="bold" id="collection-card">
138+
Collection Card
139+
</Typography>
140+
<CollectionCardSection />
136141
</div>
137142
<React.Suspense fallback={null}>
138143
<PageSidebar />
Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
'use client'
2+
3+
import * as React from 'react'
4+
5+
import { IconChevronLgRight } from '@intentui/icons'
6+
import { CubeIcon, FolderIcon } from '@phosphor-icons/react'
7+
8+
import { BadgeOrange } from '../../../src/react/icons/badge-orange'
9+
import { DotsCard } from '../../../src/react/icons/dots-card'
10+
import { cn } from '../../../src/react/utils/cn'
11+
12+
function CollectionCard({ className, ...props }: React.ComponentProps<'div'>) {
13+
return (
14+
<div
15+
data-slot="collection-card"
16+
className={cn(
17+
'bg-white rounded-2xl shadow-sm p-2 w-full border border-bluegray-300 relative flex flex-col',
18+
className
19+
)}
20+
{...props}
21+
/>
22+
)
23+
}
24+
25+
function CollectionCardIcon({
26+
icon: Icon = CubeIcon,
27+
badgeClassName,
28+
iconClassName,
29+
}: {
30+
icon?: React.ComponentType<React.ComponentProps<typeof CubeIcon>>
31+
badgeClassName?: string
32+
iconClassName?: string
33+
}) {
34+
return (
35+
<>
36+
<BadgeOrange
37+
data-slot="collection-card-badge"
38+
className={cn('size-24 absolute top-0 left-6 -translate-y-1/2 z-[1]', badgeClassName)}
39+
/>
40+
<Icon
41+
data-slot="collection-card-icon"
42+
className={cn(
43+
'text-text-brand size-10 absolute top-0 left-8 -translate-y-1/2 z-[2] translate-x-1/2',
44+
iconClassName
45+
)}
46+
/>
47+
</>
48+
)
49+
}
50+
51+
function CollectionCardHeader({ className, ...props }: React.ComponentProps<'div'>) {
52+
return (
53+
<div
54+
data-slot="collection-card-header"
55+
className={cn(
56+
'flex justify-between items-center px-8 pb-4 pt-14 border-b border-bluegray-300 relative overflow-hidden',
57+
className
58+
)}
59+
{...props}
60+
>
61+
<div className="absolute top-0 left-0">
62+
<DotsCard />
63+
</div>
64+
{props.children}
65+
</div>
66+
)
67+
}
68+
69+
function CollectionCardTitle({ className, ...props }: React.ComponentProps<'p'>) {
70+
return (
71+
<div
72+
data-slot="collection-card-title"
73+
className={cn('text-bluegray-800', className)}
74+
{...props}
75+
/>
76+
)
77+
}
78+
79+
function CollectionCardItemCount({
80+
className,
81+
itemNumber,
82+
...props
83+
}: React.ComponentProps<'div'> & {
84+
itemNumber: number
85+
}) {
86+
return (
87+
<div
88+
data-slot="collection-card-item-count"
89+
className={cn('flex items-center gap-2', className)}
90+
{...props}
91+
>
92+
<FolderIcon className="text-text-secondary" />
93+
<span className="text-sm text-text-secondary">{itemNumber} items</span>
94+
</div>
95+
)
96+
}
97+
98+
function CollectionCardDescription({ className, ...props }: React.ComponentProps<'div'>) {
99+
return (
100+
<div
101+
data-slot="collection-card-description"
102+
className={cn('px-8 pb-8 pt-6 flex-grow text-text-secondary', className)}
103+
{...props}
104+
>
105+
{props.children}
106+
</div>
107+
)
108+
}
109+
110+
function CollectionCardButton({
111+
className,
112+
children,
113+
title = 'View',
114+
...props
115+
}: React.ComponentProps<'button'> & {
116+
title?: string
117+
}) {
118+
return (
119+
<button
120+
data-slot="collection-card-button"
121+
className={cn(
122+
'w-full py-6 px-8 bg-gradient-to-b from-pumpkin-50 to-pumpkin-100 rounded-lg text-text-secondary font-medium flex items-center justify-end hover:from-pumpkin-100 hover:to-pumpkin-300 transition cursor-pointer gap-3',
123+
className
124+
)}
125+
{...props}
126+
>
127+
<span>{children ?? title}</span>
128+
<IconChevronLgRight fontSize={24} className="size-10 text-text-secondary" />
129+
</button>
130+
)
131+
}
132+
133+
export {
134+
CollectionCard,
135+
CollectionCardButton,
136+
CollectionCardDescription,
137+
CollectionCardHeader,
138+
CollectionCardIcon,
139+
CollectionCardItemCount,
140+
CollectionCardTitle,
141+
}

packages/react/v2/components/primitives/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ export * from './button-group'
44
export * from './calendar'
55
export * from './checkbox'
66
export * from './collapsible'
7+
export * from './collection-card'
78
export * from './color-picker'
89
export * from './combobox'
910
export * from './command'

0 commit comments

Comments
 (0)