Merged in feat/LOY-400-create-spend-points-modal (pull request #3131)
Feat/LOY-400 create spend points modal * feat(LOY-400): Added custom button to my pages overview and skeleton file to custom modal for my points. * feat(LOY-400): Added custom button to my pages overview and components for custom modal for my points. * feat(LOY-400): Changed some style and infogridcardover * feat(LOY-400):Removed custom card components and changed in infoCard: Added imagePosition top, added optional height prop. In Card: Changed Text-wrap styling, added min-width styling to buttons, added optional Icon prop, added optional height prop * feat(LOY-400):Added linkList, LinkListItem component and messageBanner component. Added granola illustration. * feat(LOY-400): Removed background in several illustrations. Added component for illustration. Fixed LinkedList and styling for UsePointsButton. * feat(LOY-400): Added modal to PointsToSpendCard and fixed UsePointsButton. * fix(LOY-400):added some styling * feat(LOY-400): Linked Modal to contentstack and fetch the data in cards with UsePointsModal for now * feat(LOY-400): changed link to aria-component, cleaned up a bit * feat(LOY-400): Changed height for larger modals in mobile, fixed zod schema for no illustration input, cleaned up * fix(LOY-400): fixed graphql after rebase * fix(LOY-400): mini fix * fix(LOY-400): fixed pr-comments * fix(LOY-400): fixed some PR-comments * fix(LOY-400): fixed a PR-comment * feat(LOY-400): added size prop to ilustration in LinkListItem to be able to use illustrations in IllustrationByIconName * fix(LOY-400): fixed pr-comments * Merged in feat/LOY-402-pre-ticked-book-reward-night-in-booking-flow (pull request #3210) Feat/LOY-402 pre ticked book reward night in booking flow * feat(LOY-402): Changed UsePointsModal structure to handle button actions in card. * feat(LOY-402): added functionality for book now button * feat(LOY-400): pr comment fix * feat(LOY-402): transformed the contentstack data * fix(LOY-402): fixed pr comments Approved-by: Chuma Mcphoy (We Ahead) Approved-by: Anton Gunnarsson Approved-by: Matilda Landström * Merged in feat/LOY-404-add-tracking-for-spend-points-modal (pull request #3229) Feat/LOY-404 add tracking for spend points modal * feat(LOY-402): Changed UsePointsModal structure to handle button actions in card. * feat(LOY-402): added functionality for book now button * feat(LOY-400): pr comment fix * feat(LOY-402): transformed the contentstack data * feat(LOY-404): added tracking * fix(LOY-404): fix for session storage removal of bookNowFromPointsModal * feat(LOY-404): added consts * fix(LOY-404): moved foxusWidget const * fix(LOY-404): moved BOOKING_WIDGET_STATE const * fix(LOY-404):fix Approved-by: Matilda Landström * fix(LOY-400): some fixes * feat(LOY-400): created linkList storybook Approved-by: Chuma Mcphoy (We Ahead) Approved-by: Matilda Landström
This commit is contained in:
@@ -0,0 +1,56 @@
|
||||
import type { Meta, StoryObj } from '@storybook/nextjs-vite'
|
||||
import { LinkList } from './index'
|
||||
import { IconName } from '../Icons/iconName'
|
||||
import type { LinkListItemProps } from './LinkListItem'
|
||||
|
||||
const meta: Meta<typeof LinkList> = {
|
||||
title: 'Components/LinkList',
|
||||
component: LinkList,
|
||||
argTypes: {},
|
||||
}
|
||||
|
||||
export default meta
|
||||
|
||||
type Story = StoryObj<typeof LinkList>
|
||||
|
||||
const illustrationItems = [
|
||||
{
|
||||
text: 'First Link Item',
|
||||
isExternal: false,
|
||||
illustration: {
|
||||
illustration: 'Granola' as IconName,
|
||||
size: 'medium',
|
||||
},
|
||||
} as LinkListItemProps,
|
||||
{
|
||||
text: 'Second Link Item',
|
||||
isExternal: true,
|
||||
illustration: {
|
||||
illustration: 'Coin' as IconName,
|
||||
size: 'small',
|
||||
},
|
||||
} as LinkListItemProps,
|
||||
]
|
||||
|
||||
const textItems = [
|
||||
{
|
||||
text: 'First Link Item',
|
||||
isExternal: false,
|
||||
} as LinkListItemProps,
|
||||
{
|
||||
text: 'Second Link Item',
|
||||
isExternal: true,
|
||||
} as LinkListItemProps,
|
||||
]
|
||||
|
||||
export const IllustrationLinkList: Story = {
|
||||
args: {
|
||||
linkListItems: illustrationItems,
|
||||
},
|
||||
}
|
||||
|
||||
export const TextOnlyLinkList: Story = {
|
||||
args: {
|
||||
linkListItems: textItems,
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
import { IconProps, LogoAndIllustrationProps } from '../../../Icons'
|
||||
import { IconName } from '../../../Icons/iconName'
|
||||
import { IllustrationByIconName } from '../../../Icons/IllustrationByIconName'
|
||||
import { FC } from 'react'
|
||||
|
||||
export interface IllustrationIconProps extends LogoAndIllustrationProps {
|
||||
illustration: IconName
|
||||
size?: 'small' | 'medium' | 'large'
|
||||
}
|
||||
|
||||
function mapIllustrationToIcon(illustration: IconName): FC<IconProps> | null {
|
||||
if (!IllustrationByIconName(illustration)) return null
|
||||
return IllustrationByIconName(illustration)
|
||||
}
|
||||
|
||||
const sizeMap = {
|
||||
small: { width: 60, height: 60 },
|
||||
medium: { width: 80, height: 80 },
|
||||
large: { width: 120, height: 120 },
|
||||
} as const
|
||||
|
||||
export function IllustrationIcon({
|
||||
illustration,
|
||||
size = 'large',
|
||||
...props
|
||||
}: IllustrationIconProps) {
|
||||
const IllustrationComponent = mapIllustrationToIcon(illustration)
|
||||
if (!IllustrationComponent) return null
|
||||
return (
|
||||
<IllustrationComponent
|
||||
{...props}
|
||||
height={sizeMap[size].height}
|
||||
width={sizeMap[size].width}
|
||||
/>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
import type { Meta, StoryObj } from '@storybook/nextjs-vite'
|
||||
import { LinkListItem } from './index'
|
||||
import { IconName } from '../../Icons/iconName'
|
||||
|
||||
const meta: Meta<typeof LinkListItem> = {
|
||||
title: 'Components/LinkListItem',
|
||||
component: LinkListItem,
|
||||
argTypes: {
|
||||
isExternal: {
|
||||
control: { type: 'boolean' },
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
export default meta
|
||||
|
||||
type Story = StoryObj<typeof LinkListItem>
|
||||
|
||||
export const Default: Story = {
|
||||
args: {
|
||||
text: 'Link Item',
|
||||
},
|
||||
}
|
||||
|
||||
export const IllustrationItem: Story = {
|
||||
args: {
|
||||
text: 'Link Item',
|
||||
isExternal: false,
|
||||
illustration: {
|
||||
illustration: 'Granola' as IconName,
|
||||
size: 'medium',
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
export const TextOnlyItem: Story = {
|
||||
args: {
|
||||
text: 'Link Item',
|
||||
isExternal: true,
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
import { MaterialIcon } from '../../Icons/MaterialIcon'
|
||||
import { Typography } from '../../Typography'
|
||||
|
||||
import styles from './linkListItem.module.css'
|
||||
import {
|
||||
IllustrationIcon,
|
||||
IllustrationIconProps,
|
||||
} from '../LinkListItem/IllustrationIcon'
|
||||
|
||||
import { cx } from 'class-variance-authority'
|
||||
import { Link } from 'react-aria-components'
|
||||
|
||||
export interface LinkListItemProps {
|
||||
text: string
|
||||
isExternal?: boolean
|
||||
href: string
|
||||
className?: string
|
||||
illustration?: IllustrationIconProps
|
||||
onClick?: () => void
|
||||
}
|
||||
|
||||
export function LinkListItem({
|
||||
text,
|
||||
isExternal,
|
||||
href,
|
||||
illustration,
|
||||
onClick,
|
||||
}: LinkListItemProps) {
|
||||
return (
|
||||
<Link
|
||||
href={href}
|
||||
target={'_blank'}
|
||||
onClick={onClick}
|
||||
className={cx(styles.content, {
|
||||
[styles.graphic]: illustration,
|
||||
[styles.noGraphic]: !illustration,
|
||||
})}
|
||||
>
|
||||
{illustration && (
|
||||
<div className={styles.illustrationWrapper}>
|
||||
<IllustrationIcon
|
||||
illustration={illustration.illustration}
|
||||
size={illustration.size}
|
||||
className={styles.illustration}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
<Typography variant="Body/Paragraph/mdBold">
|
||||
<p>{text}</p>
|
||||
</Typography>
|
||||
<MaterialIcon
|
||||
color="Icon/Interactive/Default"
|
||||
icon={isExternal ? 'open_in_new' : 'arrow_forward'}
|
||||
/>
|
||||
</Link>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
.list {
|
||||
list-style-type: none;
|
||||
}
|
||||
|
||||
.linkListItem {
|
||||
border: 1px solid var(--Base-Border-Subtle);
|
||||
background-color: var(--Surface-Primary-Default);
|
||||
}
|
||||
|
||||
.linkListItem + .linkListItem {
|
||||
border-top: none;
|
||||
}
|
||||
|
||||
.linkListItem:first-child {
|
||||
border-radius: var(--Corner-radius-md) var(--Corner-radius-md) 0 0;
|
||||
}
|
||||
|
||||
.linkListItem:last-child {
|
||||
border-radius: 0 0 var(--Corner-radius-md) var(--Corner-radius-md);
|
||||
}
|
||||
|
||||
.linkListItem:hover {
|
||||
background-color: var(--Surface-Primary-Hover);
|
||||
}
|
||||
|
||||
.content {
|
||||
display: grid;
|
||||
align-items: center;
|
||||
padding: var(--Space-x2);
|
||||
gap: var(--Space-x2);
|
||||
text-decoration: none;
|
||||
color: var(--Text-Interactive-Default);
|
||||
}
|
||||
|
||||
.graphic {
|
||||
grid-template-columns: 80px 1fr auto;
|
||||
}
|
||||
|
||||
.noGraphic {
|
||||
grid-template-columns: 1fr auto;
|
||||
}
|
||||
|
||||
.illustrationWrapper {
|
||||
position: relative;
|
||||
border-radius: var(--Corner-radius-sm);
|
||||
background-color: var(--Surface-Primary-Hover-Accent);
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
}
|
||||
|
||||
.illustration {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
}
|
||||
23
packages/design-system/lib/components/LinkList/index.tsx
Normal file
23
packages/design-system/lib/components/LinkList/index.tsx
Normal file
@@ -0,0 +1,23 @@
|
||||
import { LinkListItem, type LinkListItemProps } from './LinkListItem'
|
||||
import styles from './LinkListItem/linkListItem.module.css'
|
||||
export interface LinkListProps {
|
||||
linkListItems: LinkListItemProps[]
|
||||
}
|
||||
|
||||
export function LinkList({ linkListItems }: LinkListProps) {
|
||||
return (
|
||||
<ul className={styles.list}>
|
||||
{linkListItems.map((item, index) => (
|
||||
<li className={styles.linkListItem} key={index}>
|
||||
<LinkListItem
|
||||
text={item.text}
|
||||
isExternal={item.isExternal}
|
||||
href={item.href}
|
||||
illustration={item.illustration}
|
||||
onClick={item.onClick}
|
||||
/>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user