Skip to content

Commit f32aa43

Browse files
Card (#978)
* Basic Card (#967) * Basic Card * Use Content instead of CardBody * Make sure Content children only span their natural height * Vertical icon and image cards (#968) * Support image in Cards * Add image and icon examples * Use CSS selectors instead of context for slotted components * Add illustration examples * Clickable card (#970) * Add clickable option * Add examples of clickable cards with bg color * Add comment * Adjust comments * Remove footer * Replace href prop with CardLink component * Fix hover on heading * Fix stories * Remove comment * Fix z-index * Finish CardLink * Fix heading styles * Remove some group/card usage * Fix hover styles and stories * Fix image zoom hover effect * Fix hover on CardLink with no href * Fixup stories * Fix CTA cards * Fix CTA stories * Remove media context * Simplify CardLinkProps * Change border prop to variant * Fix story name * Add CVA default variant * Add changeset
1 parent 00e0eea commit f32aa43

File tree

6 files changed

+562
-2
lines changed

6 files changed

+562
-2
lines changed

.changeset/twenty-maps-yawn.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@obosbbl/grunnmuren-react': minor
3+
---
4+
5+
New `<Card>` component that can serve as either a clickable link or a decorative container. Supporting text content along with images, illustrations and icons.
+367
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,367 @@
1+
import type { Meta } from '@storybook/react';
2+
import { Card, CardLink } from './Card';
3+
import { Heading, Content, Media, Footer } from '../content';
4+
import { cx } from 'cva';
5+
import {
6+
ArrowRight,
7+
Bed,
8+
Documents,
9+
House,
10+
PiggyBank,
11+
} from '@obosbbl/grunnmuren-icons-react';
12+
import { Badge } from '../badge';
13+
import { Button } from '../button';
14+
15+
const meta: Meta<typeof Card> = {
16+
title: 'Card',
17+
component: Card,
18+
render: () => (
19+
<Card>
20+
<Content>
21+
<Heading level={3}>Min bolig</Heading>
22+
<p>
23+
Her finner du alt om din nye bolig og hva som venter deg fremover. Du
24+
finner dine dokumenter, salgsoppgave og mye mer.
25+
</p>
26+
</Content>
27+
</Card>
28+
),
29+
};
30+
31+
export default meta;
32+
33+
const Cards = ({ children }: { children: React.ReactNode }) => (
34+
<div className="grid gap-4">{children}</div>
35+
);
36+
37+
export const WithBackground = () => {
38+
const bgColors = [
39+
'bg-mint-lightest',
40+
'bg-sky-light',
41+
'bg-blue-dark',
42+
'bg-green-dark',
43+
] as const;
44+
return (
45+
<Cards>
46+
{bgColors.map((bgColor) => (
47+
<Card
48+
className={cx(bgColor, bgColor.includes('dark') && 'text-white')}
49+
key={bgColor}
50+
>
51+
<Content>
52+
<Heading level={3}>Bakgrunn {bgColor}</Heading>
53+
<p>Dette kortet har {bgColor} som bakgrunnsfarge</p>
54+
</Content>
55+
</Card>
56+
))}
57+
</Cards>
58+
);
59+
};
60+
61+
export const WithImage = () => (
62+
<Card>
63+
<Media>
64+
<img
65+
alt=""
66+
src="https://res.cloudinary.com/obosit-prd-ch-clry/image/upload/obos-logo-socialmeta.jpg"
67+
/>
68+
</Media>
69+
<Content>
70+
<Heading level={3}>Kort med bilde</Heading>
71+
<p>
72+
Dette kortet har et bilde og er uten border. Derfor er alle hjørner på
73+
bildet avrundet.
74+
</p>
75+
</Content>
76+
</Card>
77+
);
78+
79+
export const OutlinedWithImageAnd = () => (
80+
<Card variant="outlined">
81+
<Media>
82+
<img
83+
alt=""
84+
src="https://res.cloudinary.com/obosit-prd-ch-clry/image/upload/obos-logo-socialmeta.jpg"
85+
/>
86+
</Media>
87+
<Content>
88+
<Heading level={3}>Kort med bilde og border</Heading>
89+
<p>
90+
Dette kortet har et bilde og border. Derfor er kun hjørnene i toppen
91+
avrundet.
92+
</p>
93+
</Content>
94+
</Card>
95+
);
96+
97+
export const WithIconTop = () => (
98+
<Card variant="outlined">
99+
<PiggyBank />
100+
<Content>
101+
<Heading level={3}>Kort med ikon i topp</Heading>
102+
<p>Dette kortet har svart border og et ikon i toppen</p>
103+
</Content>
104+
</Card>
105+
);
106+
107+
export const WithIconBottom = () => (
108+
<Card variant="outlined">
109+
<Content>
110+
<Heading level={3}>Kort med ikon i bunn</Heading>
111+
<p>Dette kortet har svart border og et ikon i bunn</p>
112+
</Content>
113+
<PiggyBank />
114+
</Card>
115+
);
116+
117+
const Illustration = () => (
118+
<svg
119+
aria-hidden="true"
120+
width="112"
121+
height="112"
122+
viewBox="0 0 112 112"
123+
fill="none"
124+
xmlns="http://www.w3.org/2000/svg"
125+
>
126+
<path
127+
d="M29.8947 51.7441V25.0321H35.6627C37.6875 25.0321 39.6294 25.8364 41.0612 27.2682C42.493 28.7 43.2973 30.6419 43.2973 32.6667V44.1188C43.2973 46.1436 42.493 48.0855 41.0612 49.5173C39.6294 50.9491 37.6875 51.7534 35.6627 51.7534H29.8947V51.7441Z"
128+
fill="#002169"
129+
/>
130+
<path
131+
d="M59.8827 27.4306C58.0224 25.8375 55.6539 24.9619 53.2047 24.9619C50.7555 24.9619 48.387 25.8375 46.5267 27.4306L17.304 52.4906V96.8053H89.1147V52.4906L59.8827 27.4306Z"
132+
fill="#0047BA"
133+
/>
134+
<path d="M76.468 68.3198H60.8066V96.8052H76.468V68.3198Z" fill="white" />
135+
<path
136+
d="M60.8066 96.8053H76.468V97.664C76.4606 98.9934 75.9273 100.266 74.9847 101.203C74.042 102.141 72.7667 102.667 71.4373 102.667H65.8373C64.5031 102.667 63.2235 102.137 62.2801 101.193C61.3367 100.25 60.8066 98.9702 60.8066 97.636V96.7773V96.8053Z"
137+
fill="#BEDFEC"
138+
/>
139+
<path
140+
d="M45.444 78.3161C43.387 78.3161 41.4142 77.4989 39.9597 76.0444C38.5052 74.5898 37.688 72.6171 37.688 70.5601C37.688 72.6171 36.8709 74.5898 35.4163 76.0444C33.9618 77.4989 31.989 78.3161 29.932 78.3161V83.7294H45.444V78.3161Z"
141+
fill="white"
142+
/>
143+
<path
144+
d="M37.688 70.56C37.688 71.5785 37.8886 72.587 38.2784 73.528C38.6682 74.469 39.2395 75.3241 39.9597 76.0443C40.6799 76.7645 41.5349 77.3358 42.4759 77.7256C43.4169 78.1153 44.4255 78.316 45.444 78.316V68.2173H29.932V78.316C31.989 78.316 33.9618 77.4988 35.4163 76.0443C36.8709 74.5897 37.688 72.617 37.688 70.56Z"
145+
fill="#002169"
146+
/>
147+
<path
148+
d="M100.203 94.0522C100.197 92.6146 99.7328 91.2164 98.8787 90.0602C98.0245 88.9039 96.8243 88.0498 95.452 87.6215V85.6988C95.4569 84.8639 95.2966 84.0363 94.9802 83.2636C94.6638 82.4909 94.1976 81.7885 93.6085 81.1968C93.0195 80.6051 92.3191 80.1358 91.5478 79.816C90.7766 79.4963 89.9496 79.3323 89.1147 79.3335C88.2829 79.3323 87.459 79.495 86.6902 79.8125C85.9214 80.13 85.2227 80.5959 84.6341 81.1836C84.0455 81.7714 83.5785 82.4694 83.2599 83.2377C82.9413 84.0061 82.7773 84.8297 82.7773 85.6615V87.5842C81.4061 88.0128 80.2071 88.8673 79.3545 90.0237C78.5019 91.1801 78.04 92.5781 78.036 94.0148V96.7495H100.203V94.0522Z"
149+
fill="#002169"
150+
/>
151+
<path
152+
d="M91.868 30.8373C97.7958 30.8373 102.601 26.0318 102.601 20.1039C102.601 14.1761 97.7958 9.37061 91.868 9.37061C85.9401 9.37061 81.1346 14.1761 81.1346 20.1039C81.1346 26.0318 85.9401 30.8373 91.868 30.8373Z"
153+
fill="#BEDFEC"
154+
/>
155+
</svg>
156+
);
157+
158+
export const CardWithInlineTopIllustration = () => (
159+
<Card variant="outlined" className="w-72">
160+
<Illustration />
161+
<Content>
162+
<Heading level={3}>Utemiljø og grøntanlegg</Heading>
163+
<p>
164+
Et godt utemiljø er viktig for trivselen. Vi har en egen utenhusavdeling
165+
med flinke folk som kan hjelpe med realisering av nye prosjekter.
166+
</p>
167+
</Content>
168+
</Card>
169+
);
170+
171+
export const CardWithCoveringIllustration = () => (
172+
<Card variant="outlined" className="w-72">
173+
<Media>
174+
<Illustration />
175+
</Media>
176+
<Content>
177+
<div className="grid gap-1">
178+
<Heading level={3}>Rødbergvn 88C</Heading>
179+
<small className="description">Bjerke - Oslo</small>
180+
</div>
181+
<small className="description -order-1">
182+
Forhåndsvarsling - Saksnr. F0347565
183+
</small>
184+
<p className="font-semibold">100 m² | Prisantydning 9 600 000 kr</p>
185+
<p className="flex gap-x-1">
186+
<House /> Rekkehus/småhus
187+
</p>
188+
<p className="flex gap-x-1">
189+
<Bed /> 3 soverom
190+
</p>
191+
<p className="flex gap-x-1">
192+
<PiggyBank /> Totalpris 9 989 838
193+
</p>
194+
<Badge size="small" color="mint">
195+
Visning 13. oktober
196+
</Badge>
197+
</Content>
198+
</Card>
199+
);
200+
201+
export const ClickableWithIcon = () => (
202+
<Card variant="outlined">
203+
<Content>
204+
<Heading level={3}>
205+
<CardLink href="#card">Klikkbar med ikon</CardLink>
206+
</Heading>
207+
<p>Dette kortet er klikkbart og har svart border med et ikon</p>
208+
</Content>
209+
<ArrowRight className="transition-transform group-hover/card:motion-safe:translate-x-1" />
210+
</Card>
211+
);
212+
213+
export const ClickableWithImage = () => (
214+
<Card>
215+
<Media>
216+
<img
217+
alt=""
218+
src="https://res.cloudinary.com/obosit-prd-ch-clry/image/upload/obos-logo-socialmeta.jpg"
219+
/>
220+
</Media>
221+
<Content>
222+
<Heading level={3}>
223+
<CardLink href="#card">Klikkbar med bilde</CardLink>
224+
</Heading>
225+
<p>
226+
Dette kortet er klikkbart. Det har et bilde og er uten border. Derfor er
227+
alle hjørner på bildet avrundet.
228+
</p>
229+
</Content>
230+
</Card>
231+
);
232+
233+
export const ClickableWithBackground = () => (
234+
<Card className="bg-blue-dark text-white">
235+
<Content>
236+
<Heading level={3}>
237+
<CardLink href="#card">Klikkbar med bakgrunnsfarge</CardLink>
238+
</Heading>
239+
<p>Dette kortet er klikkbart og har en bakgrunnsfarge</p>
240+
</Content>
241+
<ArrowRight className="transition-transform group-hover/card:motion-safe:translate-x-1" />
242+
</Card>
243+
);
244+
245+
export const ClickableWithImageAndCTA = () => (
246+
<Card>
247+
<Media>
248+
<img
249+
alt=""
250+
src="https://res.cloudinary.com/obosit-prd-ch-clry/image/upload/obos-logo-socialmeta.jpg"
251+
/>
252+
</Media>
253+
<Content>
254+
<Heading level={3}>Med bilde og CTA</Heading>
255+
<p>Dette kortet har bilde og er klikkbart mot en CTA-lenke</p>
256+
<CardLink className="group/cta">
257+
<Button href="#cta" variant="tertiary">
258+
Les mer
259+
<ArrowRight className="transition-transform group-hover/cta:motion-safe:translate-x-1" />
260+
</Button>
261+
</CardLink>
262+
</Content>
263+
</Card>
264+
);
265+
266+
export const ClickableWithBackgroundAndCTA = () => (
267+
<Card className="bg-blue-dark text-white">
268+
<Content>
269+
<Heading level={3}>Bakgrunnsfarge og CTA</Heading>
270+
<p>Dette kortet har bakgrunnsfarge og er klikkbart mot en CTA-lenke.</p>
271+
<CardLink className="group/cta mt-1">
272+
<Button href="#cta" variant="tertiary">
273+
Les mer
274+
<ArrowRight className="transition-transform group-hover/cta:motion-safe:translate-x-1" />
275+
</Button>
276+
</CardLink>
277+
</Content>
278+
</Card>
279+
);
280+
281+
export const ClickableWithOtherClickableElements = () => (
282+
<Card variant="outlined" className="w-72">
283+
<Media>
284+
<img
285+
alt=""
286+
src="https://res.cloudinary.com/obosit-prd-ch-clry/image/upload/f_auto,c_limit,w_2048,q_auto/v1582122753/Boligprosjekter/Oslo/Ulven/Ulven-N%C3%A6romr%C3%A5de-Oslo-OBOS-Construction-city.jpg"
287+
/>
288+
</Media>
289+
<Content>
290+
<div className="grid gap-1">
291+
<Heading level={3}>
292+
<CardLink href="#card">Rødbergvn 88C</CardLink>
293+
</Heading>
294+
<small className="description">Bjerke - Oslo</small>
295+
</div>
296+
<small className="description -order-1">
297+
Forhåndsvarsling - Saksnr. F0347565
298+
</small>
299+
<p className="font-semibold">100 m² | Prisantydning 9 600 000 kr</p>
300+
<p className="flex gap-x-1">
301+
<House /> Rekkehus/småhus
302+
</p>
303+
<p className="flex gap-x-1">
304+
<Bed /> 3 soverom
305+
</p>
306+
<p className="flex gap-x-1">
307+
<PiggyBank /> Totalpris 9 989 838
308+
</p>
309+
<Badge size="small" color="mint">
310+
Visning 13. oktober
311+
</Badge>
312+
<Footer className="relative grid gap-y-2">
313+
<hr className="border-t border-t-current" />
314+
<Button href="#other-link" variant="tertiary">
315+
Se prospekt
316+
<Documents />
317+
</Button>
318+
</Footer>
319+
</Content>
320+
</Card>
321+
);
322+
323+
export const ClickableWithOtherClickableElementsAndBackgroundColor = () => (
324+
<Card variant="outlined" className="w-72 bg-blue-dark text-mint">
325+
<Media>
326+
<img
327+
alt=""
328+
src="https://res.cloudinary.com/obosit-prd-ch-clry/image/upload/f_auto,c_limit,w_2048,q_auto/v1582122753/Boligprosjekter/Oslo/Ulven/Ulven-N%C3%A6romr%C3%A5de-Oslo-OBOS-Construction-city.jpg"
329+
/>
330+
</Media>
331+
<Content>
332+
<div className="grid gap-1">
333+
<Heading level={3}>
334+
<CardLink href="#card">Rødbergvn 88C</CardLink>
335+
</Heading>
336+
<small className="description">Bjerke - Oslo</small>
337+
</div>
338+
<small className="description -order-1">
339+
Forhåndsvarsling - Saksnr. F0347565
340+
</small>
341+
<p className="font-semibold">100 m² | Prisantydning 9 600 000 kr</p>
342+
<p className="flex gap-x-1">
343+
<House /> Rekkehus/småhus
344+
</p>
345+
<p className="flex gap-x-1">
346+
<Bed /> 3 soverom
347+
</p>
348+
<p className="flex gap-x-1">
349+
<PiggyBank /> Totalpris 9 989 838
350+
</p>
351+
<Badge size="small" color="mint" className="text-black">
352+
Visning 13. oktober
353+
</Badge>
354+
<Footer className="relative grid gap-y-2">
355+
<hr className="border-t border-t-current" />
356+
<Button
357+
href="#other-link"
358+
variant="tertiary"
359+
className="focus-visible:outline-current"
360+
>
361+
Se prospekt
362+
<Documents />
363+
</Button>
364+
</Footer>
365+
</Content>
366+
</Card>
367+
);

0 commit comments

Comments
 (0)