@nuskin/foundation-ui-components 1.8.1 → 1.9.1

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.
Files changed (46) hide show
  1. package/package.json +1 -1
  2. package/src/common/accordion/NsAccordionHeader.tsx +2 -7
  3. package/src/common/accordion/NsCollapse.tsx +35 -42
  4. package/src/common/alert/NsAlert.tsx +7 -5
  5. package/src/common/auth-dropdown/NsAuthDropdown.styled.ts +1 -5
  6. package/src/common/autocomplete/helper/AutoCompleteButton.tsx +1 -1
  7. package/src/common/autocomplete/helper/renderGroupName.tsx +1 -1
  8. package/src/common/autocomplete/mock/MockUI.tsx +1 -1
  9. package/src/common/banner/NsBanner.stories.tsx +1 -1
  10. package/src/common/button/NsButton.styled.tsx +40 -45
  11. package/src/common/card/NsAwardCard.tsx +71 -0
  12. package/src/common/card/NsBgCard.tsx +2 -1
  13. package/src/common/card/NsLargeCard.tsx +14 -9
  14. package/src/common/card/NsMediumCard.tsx +21 -6
  15. package/src/common/card/NsPost.tsx +4 -7
  16. package/src/common/card/index.ts +1 -0
  17. package/src/common/card/stories/NsAwardCard.stories.tsx +26 -0
  18. package/src/common/card/stories/NsLargeCard.stories.tsx +5 -4
  19. package/src/common/card/stories/NsMediumCard.stories.tsx +7 -3
  20. package/src/common/card/stories/NsPost.stories.tsx +2 -2
  21. package/src/common/carousal/NsCarousal.tsx +6 -5
  22. package/src/common/carousal/NsScrollingCarousal.tsx +4 -8
  23. package/src/common/checkbox/NsCheckbox.tsx +1 -1
  24. package/src/common/column-control/NsColumnControl.tsx +6 -3
  25. package/src/common/column-control/styled/StyledFlex.tsx +5 -4
  26. package/src/common/column-control/styled/StyledGrid.tsx +2 -1
  27. package/src/common/icon/NsIcon.stories.tsx +42 -0
  28. package/src/common/icon/NsIcon.styled.tsx +5 -3
  29. package/src/common/icon/NsIcon.tsx +9 -1
  30. package/src/common/icon/types.d.ts +37 -0
  31. package/src/common/input/InputWrapper.tsx +3 -10
  32. package/src/common/link/NsLink.stories.tsx +2 -2
  33. package/src/common/link/NsLink.styled.tsx +2 -12
  34. package/src/common/link/NsLink.tsx +4 -7
  35. package/src/common/modal/helper-component/NsModalContentBox.tsx +1 -1
  36. package/src/common/modal/stories/mock.tsx +1 -1
  37. package/src/common/nav-product-card/NsNavProductCard.tsx +1 -1
  38. package/src/common/progress/NsProgress.tsx +1 -1
  39. package/src/common/radiogroup/NsRadioGroup.styled.tsx +6 -7
  40. package/src/common/text-strip/NsTextStrip.tsx +1 -1
  41. package/src/common/typography/HtmlTagVariantMap.tsx +24 -0
  42. package/src/common/typography/NsTypography.stories.tsx +1 -0
  43. package/src/common/typography/NsTypography.tsx +7 -2
  44. package/src/common/typography/Typography.styled.tsx +12 -10
  45. package/src/common/typography/types.d.ts +15 -8
  46. package/src/common/util.ts +3 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nuskin/foundation-ui-components",
3
- "version": "1.8.1",
3
+ "version": "1.9.1",
4
4
  "description": "It is a foundation library written in react, that provides common components to all UI pages",
5
5
  "main": "src/common/index.ts",
6
6
  "repository": {
@@ -2,15 +2,10 @@ import { NsTypography, NsIcon, NsAccordionHeaderProps, AccordionVariant, NsIconP
2
2
  import { styled } from '@nuskin/foundation-theme';
3
3
  import { isValidIconName } from '../icon/NsIconVariants';
4
4
  import { getAccordionColor } from './colorMap';
5
- const options = {
6
- shouldForwardProp: (propKey: string) => !['variant', 'invert'].includes(propKey),
7
- };
5
+
8
6
  type StyledType = { variant: AccordionVariantType; invert: boolean };
9
7
 
10
- const StyledHeader = styled(
11
- 'header',
12
- options
13
- )<StyledType>(({ theme, variant, invert }) => {
8
+ const StyledHeader = styled('header')<StyledType>(({ theme, variant, invert }) => {
14
9
  const { headBg, headText } = getAccordionColor({ theme, variant, invert, keys: ['headBg', 'headText'] });
15
10
  let borderBottom = 'none';
16
11
  if (variant === AccordionVariant.Compact) {
@@ -1,59 +1,52 @@
1
1
  import { styled } from '@nuskin/foundation-theme';
2
+ import { isValidElement, ReactElement, useMemo } from 'react';
3
+
2
4
  import {
5
+ AccordionContentTypeObject,
6
+ AccordionItem,
3
7
  AccordionVariant,
4
8
  AccordionVariantType,
5
- NsCollapseProps,
6
- AccordionItem,
7
9
  NsAccordion,
8
- AccordionContentTypeObject,
10
+ NsCollapseProps,
9
11
  } from '../';
10
12
  import { getAccordionColor } from './colorMap';
11
- import { ReactElement, isValidElement, useMemo } from 'react';
12
13
 
13
14
  const getLevelOffset = (level: number) => {
14
15
  return level > 1 ? (level - 1) * 16 : 0;
15
16
  };
17
+ type CollapsePropsType = { variant: AccordionVariantType; level: number; invert: boolean; isChild: boolean };
16
18
 
17
- const options = {
18
- shouldForwardProp: (key: string) => !['variant', 'level'].includes(key),
19
- };
19
+ export const StyledCollapse = styled('section')<CollapsePropsType>(({ theme, variant, level, invert, isChild }) => {
20
+ const { contentBg, contentText } = getAccordionColor({
21
+ theme,
22
+ invert,
23
+ variant,
24
+ keys: ['contentBg', 'contentText'],
25
+ });
20
26
 
21
- export const StyledCollapse = styled(
22
- 'section',
23
- options
24
- )<{ variant: AccordionVariantType; level: number; invert: boolean; isChild: boolean }>(
25
- ({ theme, variant, level, invert, isChild }) => {
26
- const { contentBg, contentText } = getAccordionColor({
27
- theme,
28
- invert,
29
- variant,
30
- keys: ['contentBg', 'contentText'],
31
- });
32
-
33
- let borderBottom = 'none';
34
- if (variant === AccordionVariant.Compact) {
35
- borderBottom = isChild ? 'none' : '1px solid rgb(0,0,0,0.125)';
36
- }
37
- return {
38
- backgroundColor: contentBg,
39
- color: contentText,
40
- opacity: 0,
41
- padding: '0 16px',
42
- height: 0,
43
- overflow: 'hidden',
44
- transition: '0.3s',
45
- '&.expanded': {
46
- padding: `9px 0 9px ${getLevelOffset(level)}px`,
47
- height: 'auto',
48
- opacity: 1,
49
- borderBottom,
50
- },
51
- '.nsa-content-padded': {
52
- padding: '0 16px 16px',
53
- },
54
- };
27
+ let borderBottom = 'none';
28
+ if (variant === AccordionVariant.Compact) {
29
+ borderBottom = isChild ? 'none' : '1px solid rgb(0,0,0,0.125)';
55
30
  }
56
- );
31
+ return {
32
+ backgroundColor: contentBg,
33
+ color: contentText,
34
+ opacity: 0,
35
+ padding: '0 16px',
36
+ height: 0,
37
+ overflow: 'hidden',
38
+ transition: '0.3s',
39
+ '&.expanded': {
40
+ padding: `9px 0 9px ${getLevelOffset(level)}px`,
41
+ height: 'auto',
42
+ opacity: 1,
43
+ borderBottom,
44
+ },
45
+ '.nsa-content-padded': {
46
+ padding: '0 16px 16px',
47
+ },
48
+ };
49
+ });
57
50
 
58
51
  /**
59
52
  * NsCollapse component adds css animation while showing children items if prop `isOpen` is true,
@@ -1,14 +1,16 @@
1
1
  import React, { useEffect, useState } from 'react';
2
+
2
3
  import {
3
- AlertContainer,
4
4
  Alert,
5
- AlertIcon,
6
- AlertHead,
5
+ AlertBody,
7
6
  AlertCloseButton,
7
+ AlertContainer,
8
8
  AlertContent,
9
9
  AlertFoot,
10
- AlertBody,
10
+ AlertHead,
11
+ AlertIcon,
11
12
  } from './NsAlert.styled';
13
+
12
14
  import type { NsAlertProps, ContextType, AlertType } from './types.d';
13
15
  import { NsIcon } from '../icon';
14
16
  import Header, { colorMap, iconMap } from './Header';
@@ -59,7 +61,7 @@ export default function NsAlert({
59
61
  </AlertHead>
60
62
  {hasDismissListener && (
61
63
  <AlertCloseButton data-testid="alert-close-button" onClick={onDismiss}>
62
- <NsIcon name="close" size="small" />
64
+ <NsIcon name="close" size="small" cursor="pointer" />
63
65
  </AlertCloseButton>
64
66
  )}
65
67
  <AlertContent type={alertType as AlertType}>
@@ -1,6 +1,5 @@
1
1
  import { styled, ColorUtils } from '@nuskin/foundation-theme';
2
2
  import { DarkModeEnabledOption } from '../common.types';
3
- import { skipDarkModeEnabled } from '../util';
4
3
 
5
4
  //[TODO-Arun] - Use from custom color variables
6
5
  // const MAGENTA_COLOR = '#bb29bb';
@@ -49,10 +48,7 @@ export const Triangle = styled.div`
49
48
  box-shadow: 0 0 5px 0 ${color('neutral', '20')};
50
49
  }
51
50
  `;
52
- const options = {
53
- shouldForwardProp: skipDarkModeEnabled,
54
- };
55
- export const AuthHead = styled('div', options)<DarkModeEnabledOption>`
51
+ export const AuthHead = styled('div')<DarkModeEnabledOption>`
56
52
  cursor: pointer;
57
53
  padding: 5px 10px;
58
54
  display: flex;
@@ -15,7 +15,7 @@ export const AutoCompleteButton = (props: AutoCompleteButtonProps) => {
15
15
  return (
16
16
  <li className="text-right p-3">
17
17
  <NsButton onClick={onClick} data-testid={testId}>
18
- <NsTypography variant="p-xs" weight="bold">
18
+ <NsTypography variant="body-xs" weight="bold">
19
19
  {text}
20
20
  </NsTypography>
21
21
  </NsButton>
@@ -5,7 +5,7 @@ import { NsTypography, OptionsProps } from '../..';
5
5
  export const renderGroupName = ({ key, group, children }: AutocompleteRenderGroupParams) => (
6
6
  <li key={key}>
7
7
  {group ? (
8
- <NsTypography variant="p-m" weight="bold" className="p-3">
8
+ <NsTypography variant="body-m" weight="bold" className="p-3">
9
9
  {group}
10
10
  </NsTypography>
11
11
  ) : null}
@@ -8,7 +8,7 @@ const OptionUiComponent = ({ option }: ListUiProps) => {
8
8
  return (
9
9
  <ListStyled>
10
10
  <div className="item-description" role="link" tabIndex={0}>
11
- <NsTypography aria-label="Nu Skin Tumbler" variant="p-m" colorOverride="#63666A">
11
+ <NsTypography aria-label="Nu Skin Tumbler" variant="body-m" colorOverride="#63666A">
12
12
  <img src={option.image} alt="No-image" />
13
13
  {option?.value}
14
14
  </NsTypography>
@@ -32,7 +32,7 @@ export default {
32
32
  <NsTypography className="w-80" variant="h1" colorOverride="#000000">
33
33
  Limited time offers on LumiSpa iO cleansers and bundles!
34
34
  </NsTypography>
35
- <NsTypography variant="p-m" className="my-5" colorOverride="#000000">
35
+ <NsTypography variant="body-m" className="my-5" colorOverride="#000000">
36
36
  Learn more about what I do and how I can help you
37
37
  </NsTypography>
38
38
  <NsButton variant="contained">Contact me</NsButton>
@@ -5,7 +5,6 @@ import { ButtonConfig } from '@nuskin/foundation-theme/src/common/themes/types/b
5
5
 
6
6
  import { NsButtonProps } from './types.d';
7
7
  import { generateContainedStyle, generateIconOnlyStyles, generateOutlinedStyle, generateTextStyles } from './helper';
8
- import { skipDarkModeEnabled } from '../util';
9
8
 
10
9
  const { buttonColor, paletteColor } = ColorUtils;
11
10
 
@@ -13,49 +12,45 @@ const getButtonConfig = (theme: FoundationTheme.Theme, attribute: keyof ButtonCo
13
12
  const { config } = theme || {};
14
13
  return config?.components?.button?.[attribute] || '';
15
14
  };
16
- const options = {
17
- shouldForwardProp: skipDarkModeEnabled,
18
- };
19
15
 
20
- export const StyledButton = styled(
21
- MUIButton,
22
- options
23
- )<NsButtonProps>(({ theme, color, size, darkModeEnabled, variant, iconOnly }) => {
24
- const borderRadius = getButtonConfig(theme, 'borderRadius') || 0;
25
- const focusBorderColor = getButtonConfig(theme, 'focusColor');
26
- // TODO: remove as any from the theme and color
27
- const sizeStyle = (theme as any)?.components?.button?.['size']?.[size ?? '']?.padding ?? {};
28
- const btnColor = color as any;
29
-
30
- let buttonStyles = {};
31
- const hovered = buttonColor(btnColor, 'hovered')({ theme });
32
- const pressed = buttonColor(btnColor, 'pressed')({ theme });
33
- const focused = buttonColor(btnColor, 'focused')({ theme });
34
- const textColor = paletteColor(btnColor, 'contrastText')({ theme, darkModeEnabled });
35
- const backgroundColor = paletteColor(btnColor)({ theme, darkModeEnabled });
36
-
37
- if (variant === 'contained') {
38
- buttonStyles = generateContainedStyle({ backgroundColor, textColor, hovered, pressed, focused });
39
- } else if (variant === 'outlined') {
40
- const activeColor = paletteColor(btnColor)({ theme });
41
- buttonStyles = generateOutlinedStyle({ borderColor: backgroundColor, hovered, pressed, activeColor });
42
- } else if (variant === 'text') {
43
- buttonStyles = generateTextStyles({ underlineColor: backgroundColor, hovered, pressed });
44
- } else if (iconOnly) {
45
- buttonStyles = generateIconOnlyStyles();
16
+ export const StyledButton = styled(MUIButton)<NsButtonProps>(
17
+ ({ theme, color, size, darkModeEnabled, variant, iconOnly }) => {
18
+ const borderRadius = getButtonConfig(theme, 'borderRadius') || 0;
19
+ const focusBorderColor = getButtonConfig(theme, 'focusColor');
20
+ // TODO: remove as any from the theme and color
21
+ const sizeStyle = (theme as any)?.components?.button?.['size']?.[size ?? '']?.padding ?? {};
22
+ const btnColor = color as any;
23
+
24
+ let buttonStyles = {};
25
+ const hovered = buttonColor(btnColor, 'hovered')({ theme });
26
+ const pressed = buttonColor(btnColor, 'pressed')({ theme });
27
+ const focused = buttonColor(btnColor, 'focused')({ theme });
28
+ const textColor = paletteColor(btnColor, 'contrastText')({ theme, darkModeEnabled });
29
+ const backgroundColor = paletteColor(btnColor)({ theme, darkModeEnabled });
30
+
31
+ if (variant === 'contained') {
32
+ buttonStyles = generateContainedStyle({ backgroundColor, textColor, hovered, pressed, focused });
33
+ } else if (variant === 'outlined') {
34
+ const activeColor = paletteColor(btnColor)({ theme });
35
+ buttonStyles = generateOutlinedStyle({ borderColor: backgroundColor, hovered, pressed, activeColor });
36
+ } else if (variant === 'text') {
37
+ buttonStyles = generateTextStyles({ underlineColor: backgroundColor, hovered, pressed });
38
+ } else if (iconOnly) {
39
+ buttonStyles = generateIconOnlyStyles();
40
+ }
41
+
42
+ return {
43
+ gap: '10px',
44
+ borderRadius,
45
+ '&:focus': {
46
+ border: `1px solid ${focusBorderColor} !important`,
47
+ },
48
+ '&:disabled': {
49
+ backgroundColor: buttonColor(btnColor, 'disabled'),
50
+ color: buttonColor(btnColor, 'disabledText'),
51
+ },
52
+ ...buttonStyles,
53
+ ...sizeStyle,
54
+ };
46
55
  }
47
-
48
- return {
49
- gap: '10px',
50
- borderRadius,
51
- '&:focus': {
52
- border: `1px solid ${focusBorderColor} !important`,
53
- },
54
- '&:disabled': {
55
- backgroundColor: buttonColor(btnColor, 'disabled'),
56
- color: buttonColor(btnColor, 'disabledText'),
57
- },
58
- ...buttonStyles,
59
- ...sizeStyle,
60
- };
61
- });
56
+ );
@@ -0,0 +1,71 @@
1
+ import Box from '@mui/material/Box';
2
+ import { styled } from '@nuskin/foundation-theme';
3
+ import { NsImage } from '..';
4
+
5
+ type NsAwardCardProps = {
6
+ title: string;
7
+ awardName: string;
8
+ mediaOutlet: string;
9
+ backgroundImageUrl: string;
10
+ backgroundImageAlt: string;
11
+ };
12
+
13
+ const CardContainer = styled(Box)(() => {
14
+ return {
15
+ display: 'flex',
16
+ flexDirection: 'column',
17
+ position: 'relative',
18
+ backgroundColor: '#fff',
19
+ alignItems: 'center',
20
+ '.image': {
21
+ width: '150px',
22
+ height: 'auto',
23
+ objectFit: 'cover',
24
+ backgroundColor: 'red',
25
+ },
26
+ '.content': {
27
+ display: 'flex',
28
+ flexDirection: 'column',
29
+ alignItems: 'center',
30
+ },
31
+ '.title': {
32
+ fontSize: '16px',
33
+ fontWeight: 'bold',
34
+ marginTop: '30px',
35
+ },
36
+ '.awardName': {
37
+ fontSize: '16px',
38
+ fontWeight: '400',
39
+ marginTop: '20px',
40
+ },
41
+ '.mediaOutlet': {
42
+ fontSize: '11px',
43
+ fontWeight: '400',
44
+ marginTop: '20px',
45
+ },
46
+ '.action-link': {
47
+ marginTop: '10px',
48
+ fontSize: '14px',
49
+ alignSelf: 'start',
50
+ },
51
+ };
52
+ });
53
+
54
+ export default function NsAwardCard({
55
+ title,
56
+ awardName,
57
+ mediaOutlet,
58
+ backgroundImageUrl,
59
+ backgroundImageAlt,
60
+ }: NsAwardCardProps) {
61
+ return (
62
+ <CardContainer role="award-card" component="div" data-testid="award-card">
63
+ <NsImage alt={backgroundImageAlt} src={backgroundImageUrl} className="image" />
64
+ <div className="content">
65
+ <article className="title">{title}</article>
66
+ <article className="awardName">{awardName}</article>
67
+ <article className="mediaOutlet">{mediaOutlet}</article>
68
+ </div>
69
+ </CardContainer>
70
+ );
71
+ }
@@ -1,11 +1,12 @@
1
1
  import Card from '@mui/material/Card';
2
2
  import { styled } from '@nuskin/foundation-theme';
3
+ import { shouldNotForwardPropsWithKeys } from '../util';
3
4
 
4
5
  type NsBgCardProps = {
5
6
  backgroundImageUrl: string;
6
7
  };
7
8
  const options = {
8
- shouldForwardProp: (propKey: string) => propKey !== 'backgroundImageUrl',
9
+ shouldForwardProp: shouldNotForwardPropsWithKeys<NsBgCardProps>(['backgroundImageUrl']),
9
10
  };
10
11
  const Component = ({ backgroundImageUrl }: NsBgCardProps) => {
11
12
  const width = 256;
@@ -4,9 +4,10 @@ import { NsButton, NsIcon, NsImage, NsLink, NsIconNameType } from '..';
4
4
 
5
5
  type NsLargeCardProps = {
6
6
  title: string;
7
- subtitle: string;
7
+ subtitle?: string;
8
8
  intro: string;
9
- icon: NsIconNameType;
9
+ icon?: NsIconNameType;
10
+ buttonVariant: 'text' | 'outlined' | 'contained';
10
11
  backgroundImageUrl: string;
11
12
  backgroundImageAlt: string;
12
13
  cardLink: { href: string; title: string };
@@ -14,16 +15,16 @@ type NsLargeCardProps = {
14
15
  };
15
16
 
16
17
  const CardContainer = styled((props: any) => <Box {...props} />)(({ isHorizontal }) => {
17
- let width = 'fit-content',
18
+ let width = '375px',
18
19
  paddingLeft = '0px',
19
20
  justifyContent,
20
- fontSizeSub = '11px',
21
+ fontSizeSub = '16px',
21
22
  fontSizeTitle = '26px';
22
23
 
23
24
  if (isHorizontal) {
24
- width = '400px';
25
+ width = 'unset';
25
26
  paddingLeft = '30px';
26
- justifyContent = 'space-around';
27
+ justifyContent = 'center';
27
28
  fontSizeSub = '16px';
28
29
  fontSizeTitle = '36px';
29
30
  }
@@ -33,15 +34,15 @@ const CardContainer = styled((props: any) => <Box {...props} />)(({ isHorizontal
33
34
  display: 'flex',
34
35
  flexDirection: direction,
35
36
  position: 'relative',
37
+ width,
36
38
  '.image': {
37
39
  width: '375px',
38
- height: '392px',
40
+ height: 'auto',
39
41
  objectFit: 'cover',
40
42
  },
41
43
  '.content': {
42
44
  display: 'flex',
43
45
  flexDirection: 'column',
44
- width,
45
46
  paddingLeft,
46
47
  justifyContent,
47
48
  },
@@ -59,6 +60,7 @@ const CardContainer = styled((props: any) => <Box {...props} />)(({ isHorizontal
59
60
  display: 'flex',
60
61
  flexDirection: 'column' as 'column',
61
62
  width: 'fit-content',
63
+
62
64
  borderBottom: '1px solid black',
63
65
  ':hover': {
64
66
  opacity: '0.8',
@@ -68,6 +70,7 @@ const CardContainer = styled((props: any) => <Box {...props} />)(({ isHorizontal
68
70
  marginTop: '10px',
69
71
  display: 'flex',
70
72
  fontWeight: 600,
73
+ width: 'fit-content',
71
74
  ':hover': {
72
75
  textDecoration: 'none',
73
76
  },
@@ -84,6 +87,7 @@ export default function NsLargeCard({
84
87
  backgroundImageUrl,
85
88
  backgroundImageAlt,
86
89
  cardLink,
90
+ buttonVariant,
87
91
  intro,
88
92
  icon,
89
93
  isHorizontal,
@@ -105,11 +109,12 @@ export default function NsLargeCard({
105
109
  ) : (
106
110
  <NsButton
107
111
  className="action-link"
108
- variant="outlined"
112
+ variant={buttonVariant}
109
113
  color="primary"
110
114
  href={cardLink.href}
111
115
  fullWidth={false}
112
116
  darkModeEnabled={false}
117
+ endIcon={buttonVariant !== 'contained' ? <NsIcon className="icon" name={icon} /> : null}
113
118
  >
114
119
  {cardLink.title}
115
120
  </NsButton>
@@ -1,12 +1,15 @@
1
1
  import Box from '@mui/material/Box';
2
2
  import { styled } from '@nuskin/foundation-theme';
3
- import { NsButton, NsImage } from '..';
3
+ import { NsButton, NsIcon, NsIconNameType, NsImage, NsTypography } from '..';
4
4
 
5
5
  type NsMediumCardProps = {
6
6
  title: string;
7
+ titleFontWeight?: 'bold' | 'normal' | 'light';
7
8
  subtitle: string;
9
+ icon?: NsIconNameType;
8
10
  backgroundImageUrl: string;
9
11
  backgroundImageAlt: string;
12
+ buttonVariant: 'text' | 'outlined' | 'contained';
10
13
  cardLink: { href: string; title: string };
11
14
  };
12
15
 
@@ -22,16 +25,16 @@ const CardContainer = styled(Box)(() => {
22
25
  },
23
26
  '.content': {
24
27
  display: 'flex',
28
+ width: '300px',
25
29
  flexDirection: 'column',
26
30
  },
27
31
  '.subtitle': {
28
- fontSize: '11px',
32
+ fontSize: '16px',
29
33
  fontWeight: '400',
30
34
  marginTop: '10px',
31
35
  },
32
36
  '.title': {
33
- fontSize: '16px',
34
- fontWeight: '400',
37
+ fontSize: '20px',
35
38
  marginTop: '10px',
36
39
  },
37
40
  '.action-link': {
@@ -44,18 +47,30 @@ const CardContainer = styled(Box)(() => {
44
47
 
45
48
  export default function NsMediumCard({
46
49
  title,
50
+ titleFontWeight,
47
51
  subtitle,
48
52
  backgroundImageUrl,
49
53
  backgroundImageAlt,
50
54
  cardLink,
55
+ icon,
56
+ buttonVariant,
51
57
  }: NsMediumCardProps) {
52
58
  return (
53
59
  <CardContainer role="medium-card" component="div" data-testid="medium-card">
54
60
  <NsImage alt={backgroundImageAlt} src={backgroundImageUrl} className="image" />
55
61
  <div className="content">
56
- <article className="title">{title}</article>
62
+ <NsTypography variant="h5" color="primary" className="title" weight={titleFontWeight}>
63
+ {title}
64
+ </NsTypography>
57
65
  <article className="subtitle">{subtitle}</article>
58
- <NsButton className="action-link" variant="outlined" color="primary" href={cardLink.href}>
66
+ <NsButton
67
+ className="action-link"
68
+ variant={buttonVariant}
69
+ color="primary"
70
+ href={cardLink.href}
71
+ fullWidth={false}
72
+ endIcon={buttonVariant !== 'contained' ? <NsIcon className="icon" name={icon} /> : null}
73
+ >
59
74
  {cardLink.title}
60
75
  </NsButton>
61
76
  </div>
@@ -19,17 +19,14 @@ const CardContainer = styled(Box)(() => {
19
19
  position: 'relative',
20
20
  overflow: 'hidden',
21
21
  height: 'auto',
22
- width: '165px',
22
+ width: '200px',
23
23
  backgroundColor: '#fff',
24
- '.image': {
25
- width: '100%',
26
- height: '180px',
27
- display: 'block',
28
- },
29
24
  '.content': {
30
- padding: '20px',
25
+ padding: '10px',
31
26
  display: 'flex',
32
27
  flexDirection: 'column',
28
+ minHeight: '150px',
29
+ justifyContent: 'space-between',
33
30
  },
34
31
  '.body-title': {
35
32
  fontSize: '18px',
@@ -11,3 +11,4 @@ export { default as NsSmallFullCard } from './NsSmallFullCard';
11
11
  export { default as NsXLargeCard } from './NsXLargeCard';
12
12
  export { default as NsLargeCard } from './NsLargeCard';
13
13
  export { default as NsMediumCard } from './NsMediumCard';
14
+ export { default as NsAwardCard } from './NsAwardCard';
@@ -0,0 +1,26 @@
1
+ import type { StoryObj, Meta } from '@storybook/react';
2
+ import { withCenterDecorator } from '@/stories/decorators/withCenterDecorator';
3
+ import { NsAwardCard } from '../';
4
+
5
+ type ComponentType = typeof NsAwardCard;
6
+ type Story = StoryObj<ComponentType>;
7
+ type MetaStory = Meta<ComponentType>;
8
+
9
+ export default {
10
+ component: NsAwardCard,
11
+ title: 'Components/Containers/Card/NsAwardCard',
12
+ argTypes: {},
13
+ decorators: [withCenterDecorator],
14
+ } as MetaStory;
15
+
16
+ const host = 'https://media.nuskin.com';
17
+
18
+ export const Default: Story = {
19
+ args: {
20
+ title: 'AgeLoc LumiSpa iO',
21
+ awardName: '2023 Bronze Winner',
22
+ mediaOutlet: 'Edison Awards',
23
+ backgroundImageUrl: `${host}/m/2ec571a87dc9680c/Small-Edison-Bronze-Logo-Homepage.jpg`,
24
+ backgroundImageAlt: 'Edison Bronze Logo',
25
+ },
26
+ };
@@ -18,15 +18,16 @@ const host = 'https://media.nuskin.com';
18
18
  export const Default: Story = {
19
19
  args: {
20
20
  isHorizontal: false,
21
- title: 'Title',
21
+ title: 'Personal Care',
22
22
  subtitle: 'Subtitle',
23
- intro: 'Introduction sentence',
23
+ intro: 'Nu Skin® product lines combine nature and science for skincare benefits you can see and feel.',
24
24
  icon: 'cart',
25
25
  cardLink: {
26
26
  href: 'https://www.forceforgood.org/',
27
- title: 'Button Text',
27
+ title: 'REVEAL YOUR BEST SKIN',
28
28
  },
29
- backgroundImageUrl: `${host}/m/36f2a073f3de08a2/Small-category-facial_cleansers.jpg`,
29
+ buttonVariant: 'outlined',
30
+ backgroundImageUrl: `${host}/m/95f9cf4143e3882/Small-About_Us-Personal-Care-Products-Image.jpg`,
30
31
  backgroundImageAlt: 'Facial Moisturizers',
31
32
  },
32
33
  };
@@ -17,12 +17,16 @@ const host = 'https://media.nuskin.com';
17
17
 
18
18
  export const Default: Story = {
19
19
  args: {
20
- title: 'Introducing LumiSpa',
21
- subtitle: 'Lorem ipsum dolor',
20
+ title: 'Sustainability',
21
+ titleFontWeight: 'bold',
22
+ subtitle:
23
+ 'We’re committed to keeping our global communities clean, safe, and protected for the future. We’re proud to embrace sustainable practices today for a resource-rich tomorrow.',
22
24
  cardLink: {
23
25
  href: 'https://www.forceforgood.org/',
24
- title: 'Button Text',
26
+ title: 'SEE WHAT WE’RE DOING',
25
27
  },
28
+ icon: 'arrowRight',
29
+ buttonVariant: 'outlined',
26
30
  backgroundImageUrl: `${host}/m/3353b9c05cb83860/Small-category-facial_moisturizers.jpg`,
27
31
  backgroundImageAlt: 'Lumi Spa',
28
32
  },