@obosbbl/grunnmuren-react 3.4.2 → 3.4.3

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,562 @@
1
+ import { jsx, jsxs } from 'react/jsx-runtime';
2
+ import { ArrowRight } from '@obosbbl/grunnmuren-icons-react';
3
+ import { cva, cx } from 'cva';
4
+ import { useContextProps, Provider, Link, GroupContext } from 'react-aria-components';
5
+ import { createContext } from 'react';
6
+
7
+ const HeadingContext = /*#__PURE__*/ createContext({});
8
+ const headingVariants = cva({
9
+ variants: {
10
+ /** The visual text size of the heading */ size: {
11
+ xl: 'heading-xl',
12
+ l: 'heading-l',
13
+ m: 'heading-m',
14
+ s: 'heading-s',
15
+ xs: 'heading-xs'
16
+ }
17
+ }
18
+ });
19
+ const Heading = ({ ref = null, ...props })=>{
20
+ [props, ref] = useContextProps(props, ref, HeadingContext);
21
+ const { children, level, size, className, _innerWrapper: innerWrapper, _outerWrapper: outerWrapper, ...restProps } = props;
22
+ const _className = headingVariants({
23
+ size
24
+ });
25
+ const Element = `h${level}`;
26
+ const content = /*#__PURE__*/ jsx(Element, {
27
+ ...restProps,
28
+ className: cx(className, _className),
29
+ "data-slot": "heading",
30
+ children: innerWrapper ? innerWrapper(children) : children
31
+ });
32
+ return outerWrapper ? outerWrapper(content) : content;
33
+ };
34
+ const ContentContext = /*#__PURE__*/ createContext({});
35
+ const Content = ({ ref = null, ...props })=>{
36
+ [props, ref] = useContextProps(props, ref, ContentContext);
37
+ const { _outerWrapper: outerWrapper, ...restProps } = props;
38
+ const content = /*#__PURE__*/ jsx("div", {
39
+ ...restProps,
40
+ "data-slot": "content"
41
+ });
42
+ return outerWrapper ? outerWrapper(content) : content;
43
+ };
44
+ const mediaVariant = cva({
45
+ variants: {
46
+ /**
47
+ * Control how the content should be placed with the object-fit property
48
+ * You might for example want to use `fit="contain"` portrait images that should not be cropped
49
+ * @default cover
50
+ * */ fit: {
51
+ cover: '*:object-cover',
52
+ contain: '*:object-contain'
53
+ }
54
+ }
55
+ });
56
+ const MediaContext = /*#__PURE__*/ createContext({});
57
+ const Media = ({ ref = null, ...props })=>{
58
+ [props, ref] = useContextProps(props, ref, MediaContext);
59
+ const { className, fit, ...restProps } = props;
60
+ const _className = mediaVariant({
61
+ fit
62
+ });
63
+ return /*#__PURE__*/ jsx("div", {
64
+ ref: ref,
65
+ className: cx(className, _className),
66
+ // This can be used (internally) in other components
67
+ // to apply custom styles to the media element depending on the fit
68
+ "data-fit": fit,
69
+ ...restProps,
70
+ "data-slot": "media"
71
+ });
72
+ };
73
+
74
+ const cardVariants = cva({
75
+ base: [
76
+ 'group/card',
77
+ 'rounded-[inherit]',
78
+ 'border p-3',
79
+ 'flex flex-col gap-y-4',
80
+ 'relative',
81
+ // **** Content ****
82
+ '[&_[data-slot="content"]]:flex [&_[data-slot="content"]]:flex-col [&_[data-slot="content"]]:gap-y-4',
83
+ // **** Media ****
84
+ '[&_[data-slot="media"]_*]:pointer-events-none',
85
+ '[&_[data-slot="media"]]:overflow-hidden',
86
+ '[&_[data-slot="media"]]:relative',
87
+ // Position media at the edges of the card (because of these negative margins the media-element must be a wrapper around the actual image or other media content)
88
+ '[&_[data-slot="media"]]:mx-[calc(theme(space.3)*-1-theme(borderWidth.DEFAULT))] [&_[data-slot="media"]]:mt-[calc(theme(space.3)*-1-theme(borderWidth.DEFAULT))]',
89
+ // Sets the aspect ratio of the media content (width: 100% is necessary to make aspect ratio work on images in FF)
90
+ '[&_[data-slot="media"]>*:not([data-slot="badge"])]:aspect-3/2 [&_[data-slot="media"]>img]:w-full [&_[data-slot="media"]>img]:object-cover',
91
+ // Prepare zoom animation for hover effects. The hover effect can also be enabled by classes on the parent component, so it is always prepared here.
92
+ '[&_[data-slot="media"]>*]:duration-300 [&_[data-slot="media"]>*]:ease-in-out [&_[data-slot="media"]>*]:motion-safe:transition-transform',
93
+ // **** Card link ****
94
+ // **** Hover ****
95
+ // Enables the zoom hover effect on media (note that we can't use group-hover/card here, because there might be other clickable elements in the card aside from the heading)
96
+ '[&:has([data-slot="card-link"]_a:hover)_[data-slot="media"]>img]:scale-110',
97
+ '[&:has([data-slot="heading"]_[data-slot="card-link"]:hover)_[data-slot="media"]>img]:scale-110',
98
+ // **** Fail-safe for interactive elements ****
99
+ // Make interactive elements clickable by themselves, while the rest of the card is clickable as a whole
100
+ // The card is made clickable by a pseudo-element on the heading that covers the entire card
101
+ '[&:not(:has([data-slot="card-link"]_a))_a:not([data-slot="card-link"])]:relative [&_button]:relative [&_input]:relative',
102
+ // Our Button component has position: relative by default, so we need to override that if it is used in a CardLink (to make the entire card clickable)
103
+ '[&_[data-slot="card-link"]_a]:static',
104
+ // Place other interactive on top of the pseudo-element that makes the entire card clickable
105
+ // by setting a higher z-index than the pseudo-element (which implicitly z-index 0)
106
+ '[&_a:not([data-slot="card-link"])]:z-[1] [&_button]:z-[1] [&_input]:z-[1]',
107
+ // **** Badge ****
108
+ '[&_[data-slot="media"]_[data-slot="badge"]]:absolute [&_[data-slot="media"]_[data-slot="badge"]]:top-0',
109
+ // Increasing z-index Preserves badge position when media content is hovered (the transform scale effect might otherwise move the badge behind the other media content)
110
+ '[&_[data-slot="media"]_[data-slot="badge"]]:z-[1]',
111
+ // Left aligned - override default corner radius of the badge
112
+ '[&_[data-slot="media"]_[data-slot="badge"]:first-child]:rounded-tl-2xl',
113
+ '[&_[data-slot="media"]_[data-slot="badge"]:first-child]:rounded-br-2xl',
114
+ '[&_[data-slot="media"]_[data-slot="badge"]:first-child]:rounded-tr-none',
115
+ '[&_[data-slot="media"]_[data-slot="badge"]:first-child]:rounded-bl-none',
116
+ // Right aligned - override default corner radius of the badge
117
+ '[&_[data-slot="media"]_[data-slot="badge"]:last-child]:rounded-tl-none',
118
+ '[&_[data-slot="media"]_[data-slot="badge"]:last-child]:rounded-br-none',
119
+ '[&_[data-slot="media"]_[data-slot="badge"]:last-child]:rounded-tr-2xl',
120
+ '[&_[data-slot="media"]_[data-slot="badge"]:last-child]:rounded-bl-2xl',
121
+ // ... and position the badge at the right edge of the media content
122
+ '[&_[data-slot="media"]_[data-slot="badge"]:last-child]:right-0'
123
+ ],
124
+ variants: {
125
+ /**
126
+ * The variant of the card
127
+ * @default subtle
128
+ */ variant: {
129
+ subtle: [
130
+ 'border-transparent',
131
+ // **** Media styles ****
132
+ '[&_[data-slot="media"]]:rounded-2xl'
133
+ ],
134
+ outlined: 'border border-black'
135
+ },
136
+ /**
137
+ * The layout of the card
138
+ * @default vertical
139
+ */ layout: {
140
+ vertical: [
141
+ 'flex-col',
142
+ // **** Media ****
143
+ '[&_[data-slot="media"]]:rounded-t-2xl'
144
+ ],
145
+ horizontal: [
146
+ // Use more gap for horizontal cards that have media
147
+ // Since this does not affect the layout before the flex direction is set (at breakpoint @2xl for Card with Media), we can set it here
148
+ 'has-data-[slot=media]:layout-gap-x not-has-data-[slot=media]:gap-x-4',
149
+ // **** With Media ****
150
+ '[&:has(>[data-slot="media"]:last-child)]:flex-col-reverse',
151
+ 'has-data-[slot=media]:@2xl:!flex-row',
152
+ '*:data-[slot=media]:@2xl:h-fit',
153
+ 'has-data-[slot=media]:*:@2xl:basis-1/2',
154
+ // Position media at the edges of the card
155
+ '*:data-[slot=media]:@2xl:mb-[calc(theme(space.3)*-1-theme(borderWidth.DEFAULT))]',
156
+ '*:data-[slot=media]:first:@2xl:mr-0',
157
+ '*:data-[slot=media]:last:@2xl:ml-0',
158
+ // Make sure the card link is clickable when the media is on the right side
159
+ // This is necessary because the media content is positioned after the card link in the DOM
160
+ '[&:has(>[data-slot="media"]:last-child)_[data-slot="card-link"]]:z-[1]',
161
+ // **** Without Media ****
162
+ 'not-has-data-[slot=media]:@md:flex-row',
163
+ // Make the layout responsive: when the Content reaches a minimum width of 12rem, the layout switches to vertical. Also makes sure Content takes up the remaining space available.
164
+ 'not-has-data-[slot=media]:**:data-[slot=content]:grow',
165
+ // Make sure svg's etc. are not shrinkable
166
+ '[&>:not([data-slot="content"],[data-slot="media"])]:shrink-0'
167
+ ]
168
+ }
169
+ },
170
+ defaultVariants: {
171
+ variant: 'subtle',
172
+ layout: 'vertical'
173
+ },
174
+ compoundVariants: [
175
+ {
176
+ variant: 'outlined',
177
+ layout: 'horizontal',
178
+ className: [
179
+ // **** Media ****
180
+ // Some rounded corners are removed when the card is outlined
181
+ '[&_[data-slot="media"]]:rounded-t-2xl',
182
+ '*:data-[slot=media]:first:@2xl:rounded-tr-none *:data-[slot=media]:first:@2xl:rounded-bl-2xl',
183
+ '*:data-[slot=media]:last:@2xl:rounded-tl-none *:data-[slot=media]:last:@2xl:rounded-br-2xl',
184
+ // **** Badge ****
185
+ // Override default corner radius of the badge to match the media border radius
186
+ '[&_[data-slot="media"]:first-child_[data-slot="badge"]:last-child]:@2xl:rounded-tr-none',
187
+ '[&_[data-slot="media"]:last-child_[data-slot="badge"]:first-child]:@2xl:rounded-tl-none'
188
+ ]
189
+ }
190
+ ]
191
+ });
192
+ const Card = ({ children, className, variant, layout, ...restProps })=>{
193
+ const cardClassName = cardVariants({
194
+ variant,
195
+ layout
196
+ });
197
+ return(// The border-radius is set on the outer container to make it act as an invisible wrapper, only used for container queries
198
+ // Since passing the className prop to this container is necessary to make custom styles behave as expected, we need to apply the border-radius here incase the consumer passes a custom background color
199
+ /*#__PURE__*/ jsx("div", {
200
+ ...restProps,
201
+ className: cx(className, '@container rounded-2xl'),
202
+ children: /*#__PURE__*/ jsx("div", {
203
+ className: cardClassName,
204
+ children: /*#__PURE__*/ jsx(Provider, {
205
+ values: [
206
+ [
207
+ HeadingContext,
208
+ {
209
+ size: 's',
210
+ className: cx([
211
+ 'inline',
212
+ 'w-fit',
213
+ 'text-pretty',
214
+ 'hyphens-auto',
215
+ '[word-break:break-word]',
216
+ // **** Card link in Heading ****
217
+ // Border (bottom/top) is set to transparent to make sure the bottom underline is not visible when the card is hovered
218
+ // Border top is set to even out the border bottom used for the underline
219
+ '*:data-[slot="card-link"]:no-underline',
220
+ '*:data-[slot="card-link"]:border-y-2',
221
+ '*:data-[slot="card-link"]:border-y-transparent',
222
+ '*:data-[slot="card-link"]:transition-colors',
223
+ '*:data-[slot="card-link"]:hover:border-b-current',
224
+ // Mimic heading styles for the card link if placed in the heading slot. This is necessary to make the custom underline align with the link text
225
+ '*:data-[slot="card-link"]:font-inherit',
226
+ '*:data-[slot="card-link"]:text-pretty',
227
+ '*:data-[slot="card-link"]:hyphens-auto',
228
+ '*:data-[slot="card-link"]:[word-break:break-word]'
229
+ ])
230
+ }
231
+ ]
232
+ ],
233
+ children: children
234
+ })
235
+ })
236
+ }));
237
+ };
238
+ const cardLinkVariants = cva({
239
+ base: 'w-fit max-w-full',
240
+ variants: {
241
+ withHref: {
242
+ true: [
243
+ // **** Clickarea ****
244
+ 'cursor-pointer',
245
+ 'after:absolute',
246
+ 'after:inset-[calc(theme(borderWidth.DEFAULT)*-1)]',
247
+ 'after:rounded-[calc(theme(borderRadius.2xl)-theme(borderWidth.DEFAULT))]',
248
+ // **** Focus ****
249
+ 'focus-visible:outline-none',
250
+ 'data-focus-visible:after:outline-focus',
251
+ 'data-focus-visible:after:outline-offset-2',
252
+ // **** Hover ****
253
+ // Links are underlined by default, and the underline is removed on hover.
254
+ // So we make sure that also happens when the user hovers the clickable area.
255
+ 'hover:no-underline'
256
+ ],
257
+ false: [
258
+ // **** Clickarea ****
259
+ '[&_a]:after:cursor-pointer',
260
+ '[&_a]:after:absolute',
261
+ '[&_a]:after:inset-[calc(theme(borderWidth.DEFAULT)*-1)]',
262
+ '[&_a]:after:rounded-[calc(theme(borderRadius.2xl)-theme(borderWidth.DEFAULT))]',
263
+ // **** Focus ****
264
+ '[&_a[data-focus-visible]]:outline-none',
265
+ '[&_a[data-focus-visible]]:after:outline-focus',
266
+ '[&_a[data-focus-visible]]:after:outline-offset-2',
267
+ // **** Hover ****
268
+ // Links are underlined by default, and the underline is removed on hover.
269
+ // So we make sure that also happens when the user hovers the card.
270
+ // The group-hover ensures that the hover effect also applies when this component is used as a wrapper around a link.
271
+ '[&_a]:group-hover/card:no-underline'
272
+ ]
273
+ }
274
+ }
275
+ });
276
+ /**
277
+ * A component that creates a clickable area on a card.
278
+ * It can be used either as a wrapper around a link or as a standalone link.
279
+ */ const CardLink = ({ className: _className, href, ...restProps })=>{
280
+ const className = cardLinkVariants({
281
+ className: _className,
282
+ withHref: !!href
283
+ });
284
+ return href ? /*#__PURE__*/ jsx(Link, {
285
+ "data-slot": "card-link",
286
+ ...restProps,
287
+ href: href,
288
+ className: className
289
+ }) : // We can't utilize that the `Link` component from react-aria-components renders as a span if it doesn't have an href,
290
+ // because it still renders with role="link" and tabindex="0" which makes it focusable.
291
+ // So we need to render a div instead.
292
+ /*#__PURE__*/ jsx("div", {
293
+ ...restProps,
294
+ "data-slot": "card-link",
295
+ className: className
296
+ });
297
+ };
298
+
299
+ const HeroContext = /*#__PURE__*/ createContext(null);
300
+ // Common variant for "standard" and "full-bleed" Hero variants
301
+ const oneColumnLayout = [
302
+ // Vertical spacing in the <Content>
303
+ 'lg:*:data-[slot="content"]:gap-y-4',
304
+ // Main text content takes up 9 columns on medium screens and above
305
+ 'lg:*:data-[slot="content"]:col-span-9',
306
+ // Make sure other elements than <Content> and <Media> (i.e CTA) does not span the full width on small screens
307
+ '*:not-data-[slot="content"]:not-data-[slot="media"]:w-fit',
308
+ // Other elements than <Content> and <Media> (e.g. CTA, SVG logo or Badge) take up 3 columns on medium screens and above, and are right aligned
309
+ 'lg:*:not-data-[slot="content"]:not-data-[slot="media"]:not-data-[slot="carousel"]:col-span-3 lg:*:not-data-[slot="content"]:not-data-[slot="media"]:justify-self-end',
310
+ // <Media> and <Carousel> content takes up the full width on medium screens and above
311
+ 'lg:*:data-[slot="media"]:col-span-full *:data-[slot="media"]:*:w-full',
312
+ 'lg:*:data-[slot="carousel"]:col-span-full',
313
+ // Aligns <Content> and any element beside it (e.g. <Media>, <Badge>, <CTA> etc.) to the bottom of the <Content> container
314
+ 'lg:items-end'
315
+ ];
316
+ const nonFullBleedAspectRatiosForSmallScreens = '*:data-[slot="media"]:*:aspect-[1/1] sm:*:data-[slot="media"]:*:aspect-4/3 md:*:data-[slot="media"]:*:aspect-3/2';
317
+ const variants = cva({
318
+ base: [
319
+ 'container px-0',
320
+ // Grid variant to position the Hero's content
321
+ 'grid lg:grid-cols-12 lg:gap-x-12 xl:gap-x-16',
322
+ 'gap-y-10 lg:gap-y-12',
323
+ // Enable vertical gap within <Content>
324
+ '*:data-[slot="content"]:grid',
325
+ // Vertical spacing in the <Content>
326
+ '*:data-[slot="content"]:gap-y-3',
327
+ // Make sure <Media> content fills any available vertical and horizontal space
328
+ '*:data-[slot="media"]:*:object-cover',
329
+ '*:data-[slot="carousel"]:overflow-hidden *:data-[slot="carousel"]:rounded-3xl',
330
+ // Make the carousel items full width, so we scroll one at a time
331
+ '**:data-[slot="carousel-item"]:basis-full'
332
+ ],
333
+ variants: {
334
+ /**
335
+ * Defines the variant of the Hero
336
+ * @default standard
337
+ * */ variant: {
338
+ standard: [
339
+ oneColumnLayout,
340
+ nonFullBleedAspectRatiosForSmallScreens,
341
+ 'lg:*:data-[slot="media"]:*:aspect-2/1'
342
+ ],
343
+ 'full-bleed': [
344
+ oneColumnLayout,
345
+ // Position the media and carousel content to fill the entire viewport width
346
+ '*:data-[slot="media"]:*:absolute *:data-[slot="media"]:*:left-0',
347
+ // Special case for Carousel, where the Media is nested inside a CarouselItem
348
+ '*:data-[slot="carousel"]:**:data-[slot="media"]:w-full',
349
+ // Match the heights of the <Media> or <Carousel> wrapper for the Media content (e.g. image, VideoLoop, video etc.)
350
+ // This is necessary due to the absolute positioning of the media and carousel containers in this variant
351
+ // biome-ignore lint/nursery/useSortedClasses: biome is unable to sort the custom classes for 3xl and 4xl breakpoints
352
+ '**:data-[slot="media"]:h-80 sm:**:data-[slot="media"]:h-[25rem] md:**:data-[slot="media"]:h-[30rem] lg:**:data-[slot="media"]:h-[35rem] xl:**:data-[slot="media"]:h-[40rem] 2xl:**:data-[slot="media"]:h-[42rem] 3xl:**:data-[slot="media"]:h-[48rem] 4xl:**:data-[slot="media"]:h-[53rem]',
353
+ '**:data-[slot="media"]:*:h-[inherit]',
354
+ // biome-ignore lint/nursery/useSortedClasses: biome is unable to sort the custom classes for 3xl and 4xl breakpoints
355
+ '*:data-[slot="carousel"]:h-80 sm:*:data-[slot="carousel"]:h-[25rem] md:*:data-[slot="carousel"]:h-[30rem] lg:*:data-[slot="carousel"]:h-[35rem] xl:*:data-[slot="carousel"]:h-[40rem] 2xl:*:data-[slot="carousel"]:h-[42rem] 3xl:*:data-[slot="carousel"]:h-[48rem] 4xl:*:data-[slot="carousel"]:h-[53rem]',
356
+ '*:data-[slot="carousel"]:w-full!',
357
+ // Override aspect ratio of the media and carousel-item slots (since we can not use aspect for full-bleed layout)
358
+ '**:data-[slot="carousel-item"]:data-[slot="media"]:*:aspect-none',
359
+ // break out the carousel out of the container
360
+ '**:data-[slot="carousel-items-container"]:absolute **:data-[slot="carousel-items-container"]:right-0 **:data-[slot="carousel-items-container"]:left-0 **:data-[slot="carousel-items-container"]:h-[inherit]',
361
+ // Positions the carousel controls inside the carousel
362
+ '**:data-[slot="carousel-controls"]:z-10 **:data-[slot="carousel-controls"]:mb-4 *:data-[slot="carousel"]:flex *:data-[slot="carousel"]:items-end *:data-[slot="carousel"]:justify-end'
363
+ ],
364
+ 'two-column': [
365
+ 'lg:items-center lg:*:col-span-6',
366
+ // Vertical spacing in the <Content>
367
+ 'lg:*:data-[slot="content"]:gap-y-7',
368
+ nonFullBleedAspectRatiosForSmallScreens,
369
+ // Set media aspect ratio to 1:1 (square)
370
+ 'lg:*:data-[slot="media"]:*:aspect-square'
371
+ ]
372
+ }
373
+ },
374
+ compoundVariants: [
375
+ {
376
+ variant: [
377
+ 'standard',
378
+ 'two-column'
379
+ ],
380
+ className: [
381
+ '*:data-[slot="media"]:*:rounded-3xl',
382
+ '**:data-[slot="carousel-controls"]:absolute *:data-[slot="carousel"]:relative **:data-[slot="carousel-controls"]:right-4 **:data-[slot="carousel-controls"]:bottom-4 **:data-[slot="carousel-container"]:rounded-3xl'
383
+ ]
384
+ }
385
+ ],
386
+ defaultVariants: {
387
+ variant: 'standard'
388
+ }
389
+ });
390
+ const Hero = ({ variant, className, children, ...rest })=>{
391
+ const variantsClassName = variants({
392
+ variant,
393
+ className
394
+ });
395
+ return /*#__PURE__*/ jsx(Provider, {
396
+ values: [
397
+ [
398
+ HeroContext,
399
+ {
400
+ variant
401
+ }
402
+ ],
403
+ [
404
+ HeadingContext,
405
+ {
406
+ // Sets the default heading size for the Hero based on the variant
407
+ size: variant === 'two-column' ? 'xl' : 'l',
408
+ className: // word-break:break-word to allow long words to break (this is necessary to make hyphens work in grid containers in Safari)
409
+ 'hyphens-auto text-pretty [word-break:break-word]'
410
+ }
411
+ ],
412
+ [
413
+ GroupContext,
414
+ {
415
+ // Prevents the group from being announced as a group by screen readers
416
+ // The Group component is used to group the Hero's CTA buttons together visually, and has no semantic meaning
417
+ role: 'presentation',
418
+ className: 'flex flex-wrap gap-3 *:w-fit'
419
+ }
420
+ ]
421
+ ],
422
+ children: /*#__PURE__*/ jsx("div", {
423
+ className: cx(variantsClassName, className),
424
+ ...rest,
425
+ children: children
426
+ })
427
+ });
428
+ };
429
+
430
+ const meta = {
431
+ title: 'Layout'
432
+ };
433
+ const GridContainer = ()=>/*#__PURE__*/ jsx("main", {
434
+ className: "layout-grid-container",
435
+ children: /*#__PURE__*/ jsxs(Hero, {
436
+ children: [
437
+ /*#__PURE__*/ jsxs(Content, {
438
+ children: [
439
+ /*#__PURE__*/ jsx(Heading, {
440
+ level: 1,
441
+ size: "xl",
442
+ children: "Jobb i OBOS"
443
+ }),
444
+ /*#__PURE__*/ jsx("p", {
445
+ className: "lead",
446
+ children: "Bli med å oppfylle boligdrømmer! Vi søker engasjerte og dyktige personer som vil ta OBOS videre. Søk på våre ledige stillinger!"
447
+ })
448
+ ]
449
+ }),
450
+ /*#__PURE__*/ jsx(Media, {
451
+ children: /*#__PURE__*/ jsx("img", {
452
+ src: "https://cdn.sanity.io/media-libraries/mln4u7f3Hc8r/images/410001cfde5211194e0072bf39abd3214befb1c2-1920x1080.jpg?auto=format",
453
+ alt: ""
454
+ })
455
+ })
456
+ ]
457
+ })
458
+ });
459
+ const GridContainerWithSubGrids = ()=>/*#__PURE__*/ jsxs("main", {
460
+ className: "layout-grid-container layout-gap-y",
461
+ children: [
462
+ /*#__PURE__*/ jsx("h1", {
463
+ className: "heading-xl sm:col-end-9",
464
+ children: "Dette er OBOS"
465
+ }),
466
+ /*#__PURE__*/ jsxs("ul", {
467
+ className: "md:layout-subgrid-12 *:md:col-span-2 *:lg:col-span-3",
468
+ children: [
469
+ /*#__PURE__*/ jsxs(Card, {
470
+ role: "listitem",
471
+ children: [
472
+ /*#__PURE__*/ jsxs(Content, {
473
+ children: [
474
+ /*#__PURE__*/ jsx(Heading, {
475
+ level: 2,
476
+ children: /*#__PURE__*/ jsx(CardLink, {
477
+ href: "/bolig",
478
+ children: "Bolig"
479
+ })
480
+ }),
481
+ /*#__PURE__*/ jsx("p", {
482
+ children: "Oppfyll boligdrømmen med OBOS!"
483
+ })
484
+ ]
485
+ }),
486
+ /*#__PURE__*/ jsx(ArrowRight, {
487
+ className: "transition-transform group-hover/card:motion-safe:translate-x-1"
488
+ })
489
+ ]
490
+ }),
491
+ /*#__PURE__*/ jsxs(Card, {
492
+ role: "listitem",
493
+ children: [
494
+ /*#__PURE__*/ jsxs(Content, {
495
+ children: [
496
+ /*#__PURE__*/ jsx(Heading, {
497
+ level: 2,
498
+ children: /*#__PURE__*/ jsx(CardLink, {
499
+ href: "/medlem",
500
+ children: "Medlem"
501
+ })
502
+ }),
503
+ /*#__PURE__*/ jsx("p", {
504
+ children: "Bli medlem i OBOS og få tilgang til eksklusive fordeler!"
505
+ })
506
+ ]
507
+ }),
508
+ /*#__PURE__*/ jsx(ArrowRight, {
509
+ className: "transition-transform group-hover/card:motion-safe:translate-x-1"
510
+ })
511
+ ]
512
+ }),
513
+ /*#__PURE__*/ jsxs(Card, {
514
+ role: "listitem",
515
+ children: [
516
+ /*#__PURE__*/ jsxs(Content, {
517
+ children: [
518
+ /*#__PURE__*/ jsx(Heading, {
519
+ level: 2,
520
+ children: /*#__PURE__*/ jsx(CardLink, {
521
+ href: "/bli-bankkunde",
522
+ children: "Bank"
523
+ })
524
+ }),
525
+ /*#__PURE__*/ jsx("p", {
526
+ children: "OBOS Bank tilbyr konkurransedyktige rente på boliglån og sparekonto!"
527
+ })
528
+ ]
529
+ }),
530
+ /*#__PURE__*/ jsx(ArrowRight, {
531
+ className: "transition-transform group-hover/card:motion-safe:translate-x-1"
532
+ })
533
+ ]
534
+ }),
535
+ /*#__PURE__*/ jsxs(Card, {
536
+ role: "listitem",
537
+ children: [
538
+ /*#__PURE__*/ jsxs(Content, {
539
+ children: [
540
+ /*#__PURE__*/ jsx(Heading, {
541
+ level: 2,
542
+ children: /*#__PURE__*/ jsx(CardLink, {
543
+ href: "/medlem-i-obos",
544
+ children: "Forkjøp"
545
+ })
546
+ }),
547
+ /*#__PURE__*/ jsx("p", {
548
+ children: "Som medlem i OBOS har du forkjøpsrett på tusenvis av boliger hvert år!"
549
+ })
550
+ ]
551
+ }),
552
+ /*#__PURE__*/ jsx(ArrowRight, {
553
+ className: "transition-transform group-hover/card:motion-safe:translate-x-1"
554
+ })
555
+ ]
556
+ })
557
+ ]
558
+ })
559
+ ]
560
+ });
561
+
562
+ export { GridContainer, GridContainerWithSubGrids, meta as default };