diff --git a/apps/loan/src/components/PageLlamaMarkets/cells/LineGraphCell.tsx b/apps/loan/src/components/PageLlamaMarkets/cells/LineGraphCell.tsx index fd6bab791..be7bd6ee6 100644 --- a/apps/loan/src/components/PageLlamaMarkets/cells/LineGraphCell.tsx +++ b/apps/loan/src/components/PageLlamaMarkets/cells/LineGraphCell.tsx @@ -22,7 +22,7 @@ function getColor(design: DesignSystem, data: LendingSnapshot[], type: GraphType if (!data.length) return undefined const first = data[0][`${type}_apy`] const last = data[data.length - 1][`${type}_apy`] - return design.Text.TextColors[last === first ? 'Info' : last < first ? 'Error' : 'Success'] + return design.Layer.Feedback[last === first ? 'Info' : last < first ? 'Error' : 'Success'] } /** Center the y-axis around the first value */ diff --git a/packages/curve-ui-kit/src/features/switch-chain/ui/ChainList.tsx b/packages/curve-ui-kit/src/features/switch-chain/ui/ChainList.tsx index 32b11e07d..fb18e240b 100644 --- a/packages/curve-ui-kit/src/features/switch-chain/ui/ChainList.tsx +++ b/packages/curve-ui-kit/src/features/switch-chain/ui/ChainList.tsx @@ -12,6 +12,7 @@ import Box from '@mui/material/Box' import Alert from '@mui/material/Alert' import { CheckedIcon } from '@ui-kit/shared/icons/CheckedIcon' import { MenuSectionHeader } from '@ui-kit/shared/ui/MenuSectionHeader' +import AlertTitle from '@mui/material/AlertTitle' enum ChainType { test = 'test', @@ -86,7 +87,7 @@ export function ChainList({ )) ) : ( - {t`No networks found`} + {t`No networks found`} )} diff --git a/packages/curve-ui-kit/src/features/switch-chain/ui/ChainSwitcher.tsx b/packages/curve-ui-kit/src/features/switch-chain/ui/ChainSwitcher.tsx index 9d3f09364..f4fec38a7 100644 --- a/packages/curve-ui-kit/src/features/switch-chain/ui/ChainSwitcher.tsx +++ b/packages/curve-ui-kit/src/features/switch-chain/ui/ChainSwitcher.tsx @@ -14,6 +14,7 @@ import Snackbar from '@mui/material/Snackbar' import Alert from '@mui/material/Alert' import { Duration } from '@ui-kit/themes/design/0_primitives' import Container from '@mui/material/Container' +import AlertTitle from '@mui/material/AlertTitle' export type ChainOption = { chainId: TChainId @@ -63,7 +64,7 @@ export const ChainSwitcher = ({ > - {t`This application is only available on the Ethereum Mainnet`} + {t`This application is only available on the Ethereum Mainnet`} diff --git a/packages/curve-ui-kit/src/shared/icons/CheckIcon.tsx b/packages/curve-ui-kit/src/shared/icons/CheckIcon.tsx new file mode 100644 index 000000000..b7e7d804e --- /dev/null +++ b/packages/curve-ui-kit/src/shared/icons/CheckIcon.tsx @@ -0,0 +1,11 @@ +import { createSvgIcon } from '@mui/material/utils' + +export const CheckIcon = createSvgIcon( + + + , + 'Check', +) diff --git a/packages/curve-ui-kit/src/shared/icons/ExclamationTriangleIcon.tsx b/packages/curve-ui-kit/src/shared/icons/ExclamationTriangleIcon.tsx new file mode 100644 index 000000000..d9395ee21 --- /dev/null +++ b/packages/curve-ui-kit/src/shared/icons/ExclamationTriangleIcon.tsx @@ -0,0 +1,21 @@ +import { createSvgIcon } from '@mui/material/utils' + +export const ExclamationTriangleIcon = createSvgIcon( + + + + + , + 'ExclamationTriangle', +) diff --git a/packages/curve-ui-kit/src/shared/icons/InfoCircledIcon.tsx b/packages/curve-ui-kit/src/shared/icons/InfoCircledIcon.tsx new file mode 100644 index 000000000..b80949170 --- /dev/null +++ b/packages/curve-ui-kit/src/shared/icons/InfoCircledIcon.tsx @@ -0,0 +1,21 @@ +import { createSvgIcon } from '@mui/material/utils' + +export const InfoCircledIcon = createSvgIcon( + + + + + , + 'InfoCircled', +) diff --git a/packages/curve-ui-kit/src/shared/ui/Metric.tsx b/packages/curve-ui-kit/src/shared/ui/Metric.tsx index dc925af56..6c9e1fb45 100644 --- a/packages/curve-ui-kit/src/shared/ui/Metric.tsx +++ b/packages/curve-ui-kit/src/shared/ui/Metric.tsx @@ -12,6 +12,7 @@ import { SizesAndSpaces } from '@ui-kit/themes/design/1_sizes_spaces' import { TypographyVariantKey, TYPOGRAPHY_VARIANTS } from '@ui-kit/themes/typography' import { abbreviateNumber, scaleSuffix } from '@ui-kit/utils' import { Duration } from '../../themes/design/0_primitives' +import AlertTitle from '@mui/material/AlertTitle' const { Spacing } = SizesAndSpaces @@ -229,7 +230,8 @@ export const Metric = ({ setOpenCopyAlert(false)} autoHideDuration={Duration.Snackbar}> - {copyText}: {value} + {copyText} + {value} diff --git a/packages/curve-ui-kit/src/themes/basic-theme/basic.ts b/packages/curve-ui-kit/src/themes/basic-theme/basic.ts index 5b7c5bfc6..f855af5f9 100644 --- a/packages/curve-ui-kit/src/themes/basic-theme/basic.ts +++ b/packages/curve-ui-kit/src/themes/basic-theme/basic.ts @@ -27,17 +27,24 @@ export const basicMuiTheme = createMuiTheme({ * '@media (min-width: 1200px)': { width: 100, height: '300px' } * } */ -export const handleBreakpoints = (values: Record) => +export const handleBreakpoints = (values: Record): CSSObject => Object.fromEntries( - basicMuiTheme.breakpoints.keys.map((breakpoint) => [ - basicMuiTheme.breakpoints.up(breakpoint), - Object.fromEntries( - Object.entries(values).map(([key, value]) => [ - key, - typeof value === 'string' || typeof value === 'number' ? value : value[breakpoint], - ]), - ), - ]), + basicMuiTheme.breakpoints.keys.map((breakpoint) => { + const selector = basicMuiTheme.breakpoints.up(breakpoint) + return [ + selector, + { + // in case the selector is already present, merge the values + ...((values[selector] as CSSObject) ?? {}), + ...Object.fromEntries( + Object.entries(values).map(([key, value]) => [ + key, + typeof value === 'string' || typeof value === 'number' || value == null ? value : value[breakpoint], + ]), + ), + }, + ] + }), ) export type Responsive = Record diff --git a/packages/curve-ui-kit/src/themes/components.ts b/packages/curve-ui-kit/src/themes/components.ts index d05e26256..41ec5f486 100644 --- a/packages/curve-ui-kit/src/themes/components.ts +++ b/packages/curve-ui-kit/src/themes/components.ts @@ -7,15 +7,17 @@ import { SizesAndSpaces } from './design/1_sizes_spaces' import { defineMuiSwitch } from './mui-switch' import { basicMuiTheme } from './basic-theme' import { alpha } from '@mui/system' -import type { TypographyOptions } from '@mui/material/styles/createTypography' import { defineMuiMenuItem } from '@ui-kit/themes/mui-menu-item' +import { defineMuiAlert, defineMuiAlertTitle } from '@ui-kit/themes/mui-alert' +import type { TypographyOptions } from '@mui/material/styles/createTypography' import { TransitionFunction } from '@ui-kit/themes/design/0_primitives' -import { linearProgressClasses } from '@mui/material/LinearProgress' export const DEFAULT_BAR_SIZE = SizesAndSpaces.ButtonSize.sm export const MOBILE_SIDEBAR_WIDTH = { width: '100%', minWidth: 320 } as const export const createComponents = (design: DesignSystem, typography: TypographyOptions): ThemeOptions['components'] => ({ + MuiAlert: defineMuiAlert(design, typography), + MuiAlertTitle: defineMuiAlertTitle(design, typography), MuiButton: defineMuiButton(design), MuiButtonBase: { defaultProps: { diff --git a/packages/curve-ui-kit/src/themes/design/1_surfaces_text.ts b/packages/curve-ui-kit/src/themes/design/1_surfaces_text.ts index 1bef98b5d..906bff59f 100644 --- a/packages/curve-ui-kit/src/themes/design/1_surfaces_text.ts +++ b/packages/curve-ui-kit/src/themes/design/1_surfaces_text.ts @@ -1,4 +1,4 @@ -import { Grays, Blues, Violet } from './0_primitives' +import { Grays, Blues, Violet, Reds, Greens } from './0_primitives' export const SurfacesAndText = { plain: { @@ -9,6 +9,12 @@ export const SurfacesAndText = { tertiary: Grays[500], Disabled: Grays[400], highlight: Blues[500], + Feedback: { + Success: Greens[500], + Warning: Reds[400], + Error: Reds[500], + Inverted: Grays[50], + }, }, Layer: { '1': { @@ -28,6 +34,12 @@ export const SurfacesAndText = { Selected: Grays[100], Hover: Grays[150], }, + Feedback: { + Info: Blues[500], + Success: Greens[600], + Warning: Reds[300], + Error: Reds[500], + }, }, Tables: { Header: { Fill: Grays[200] }, @@ -40,6 +52,12 @@ export const SurfacesAndText = { tertiary: Grays[400], Disabled: Grays[500], highlight: Blues[500], + Feedback: { + Success: Greens[600], + Warning: Reds[300], + Error: Reds[500], + Inverted: Grays[950], + }, }, Layer: { '1': { @@ -59,6 +77,12 @@ export const SurfacesAndText = { Selected: Grays[750], Hover: Grays[800], }, + Feedback: { + Info: Blues[50], + Success: Greens[300], + Warning: Reds[400], + Error: Reds[500], + }, }, Tables: { Header: { Fill: Grays[800] }, @@ -71,6 +95,12 @@ export const SurfacesAndText = { tertiary: Grays[500], Disabled: Grays[400], highlight: Violet[600], + Feedback: { + Success: Greens[600], + Warning: Reds[400], + Error: Reds[500], + Inverted: Grays[50], + }, }, Tables: { Header: { Fill: Violet[50] }, @@ -93,6 +123,12 @@ export const SurfacesAndText = { Selected: Violet[50], Hover: Violet[200], }, + Feedback: { + Info: Violet[700], + Success: Greens[600], + Warning: Reds[300], + Error: Reds[500], + }, }, }, }, @@ -104,6 +140,12 @@ export const SurfacesAndText = { tertiary: Grays[400], Disabled: Grays[500], highlight: Blues[500], + Feedback: { + Success: Greens[300], + Warning: Reds[300], + Error: Reds[500], + Inverted: Grays[950], + }, }, Layer: { '1': { @@ -123,6 +165,12 @@ export const SurfacesAndText = { Selected: Grays[850], Hover: Grays[900], }, + Feedback: { + Info: Blues[800], + Success: Greens[300], + Warning: Reds[400], + Error: Reds[500], + }, }, Tables: { Header: { Fill: Grays[800] }, @@ -135,6 +183,12 @@ export const SurfacesAndText = { tertiary: Grays[600], Disabled: Grays[400], highlight: Blues[500], + Feedback: { + Success: Greens[500], + Warning: Reds[400], + Error: Reds[500], + Inverted: Grays[50], + }, }, Layer: { '1': { @@ -154,6 +208,12 @@ export const SurfacesAndText = { Selected: Blues[100], Hover: Blues[50], }, + Feedback: { + Info: Blues[500], + Success: Greens[600], + Warning: Reds[300], + Error: Reds[500], + }, }, Tables: { Header: { Fill: Grays[200] }, @@ -166,6 +226,12 @@ export const SurfacesAndText = { tertiary: Grays[400], Disabled: Grays[500], highlight: Violet[400], + Feedback: { + Success: Greens[500], + Warning: Reds[300], + Error: Reds[500], + Inverted: Grays[950], + }, }, Tables: { Header: { Fill: Violet[800] }, @@ -188,6 +254,12 @@ export const SurfacesAndText = { Selected: Violet[800], Hover: Violet[900], }, + Feedback: { + Info: Grays[850], + Success: Greens[300], + Warning: Reds[400], + Error: Reds[500], + }, }, }, }, diff --git a/packages/curve-ui-kit/src/themes/design/2_theme.ts b/packages/curve-ui-kit/src/themes/design/2_theme.ts index 002873c71..35a5ccb6f 100644 --- a/packages/curve-ui-kit/src/themes/design/2_theme.ts +++ b/packages/curve-ui-kit/src/themes/design/2_theme.ts @@ -28,6 +28,7 @@ export const createLightDesign = (Light: typeof plain.Light | typeof inverted.Li Outline: Light.Layer.Highlight, }, TypeAction: Light.Layer.TypeAction, + Feedback: Light.Layer.Feedback, } as const const Text = { @@ -37,10 +38,7 @@ export const createLightDesign = (Light: typeof plain.Light | typeof inverted.Li Tertiary: Light.Text.tertiary, Highlight: Light.Text.highlight, Disabled: Light.Text.Disabled, - Success: Greens[500], - Warning: Reds[400], - Error: Reds[500], - Info: Layer.Highlight.Outline, + Feedback: Light.Text.Feedback, }, FontFamily: { Heading: 'Mona Sans', @@ -375,6 +373,7 @@ export const createDarkDesign = (Dark: typeof plain.Dark | typeof inverted.Dark) Hover: Dark.Layer.TypeAction.Hover, Selected: Dark.Layer.TypeAction.Selected, }, + Feedback: Dark.Layer.Feedback, } as const const Text = { @@ -384,10 +383,7 @@ export const createDarkDesign = (Dark: typeof plain.Dark | typeof inverted.Dark) Tertiary: Dark.Text.tertiary, Highlight: Dark.Text.highlight, Disabled: Dark.Text.Disabled, - Success: Greens[400], - Info: Layer.Highlight.Outline, - Warning: Reds[300], - Error: Reds[500], + Feedback: Dark.Text.Feedback, }, FontFamily: { Heading: 'Mona Sans', @@ -663,6 +659,7 @@ export const createChadDesign = (Chad: typeof plain.Chad | typeof inverted.Chad) Outline: Chad.Layer.Highlight, }, TypeAction: Chad.Layer.TypeAction, + Feedback: Chad.Layer.Feedback, } as const const Text = { @@ -672,10 +669,7 @@ export const createChadDesign = (Chad: typeof plain.Chad | typeof inverted.Chad) Tertiary: Chad.Text.tertiary, Highlight: Chad.Text.highlight, Disabled: Chad.Text.Disabled, - Success: Greens[500], - Info: Layer.Highlight.Outline, - Warning: Reds[400], - Error: Reds[500], + Feedback: Chad.Text.Feedback, }, FontFamily: { Heading: 'Minecraft', diff --git a/packages/curve-ui-kit/src/themes/mui-alert.tsx b/packages/curve-ui-kit/src/themes/mui-alert.tsx new file mode 100644 index 000000000..1b8114712 --- /dev/null +++ b/packages/curve-ui-kit/src/themes/mui-alert.tsx @@ -0,0 +1,68 @@ +import { Components } from '@mui/material/styles' +import { DesignSystem } from './design' +import { CheckIcon } from '@ui-kit/shared/icons/CheckIcon' +import { InfoCircledIcon } from '@ui-kit/shared/icons/InfoCircledIcon' +import { ExclamationTriangleIcon } from '@ui-kit/shared/icons/ExclamationTriangleIcon' +import type { TypographyOptions } from '@mui/material/styles/createTypography' +import { SizesAndSpaces } from '@ui-kit/themes/design/1_sizes_spaces' +import { handleBreakpoints } from '@ui-kit/themes/basic-theme' + +const { Spacing, IconSize } = SizesAndSpaces + +export const defineMuiAlert = ( + { Layer: { 1: Layer1, Feedback }, Text: { TextColors } }: DesignSystem, + { bodyXsRegular }: TypographyOptions, +): Components['MuiAlert'] => ({ + defaultProps: { + iconMapping: { + success: , + info: , + warning: , + error: , + }, + }, + styleOverrides: { + root: handleBreakpoints({ + ...bodyXsRegular, + paddingInlineStart: Spacing.md, + paddingInlineEnd: Spacing.sm, + paddingBlockStart: Spacing.sm, + paddingBlockEnd: Spacing.xs, + }), + outlined: { + backgroundColor: Layer1.Fill, + color: TextColors.Secondary, + '&.MuiAlert-colorInfo .MuiAlertTitle-root': { color: Feedback.Info }, + '&.MuiAlert-colorSuccess .MuiAlertTitle-root': { color: Feedback.Success }, + '&.MuiAlert-colorWarning .MuiAlertTitle-root': { color: Feedback.Warning }, + '&.MuiAlert-colorError .MuiAlertTitle-root': { color: Feedback.Error }, + }, + filled: { + color: TextColors.Feedback.Inverted, + '&.MuiAlert-colorInfo': { backgroundColor: Feedback.Info }, + '&.MuiAlert-colorSuccess': { backgroundColor: Feedback.Success }, + '&.MuiAlert-colorWarning': { backgroundColor: Feedback.Warning, color: TextColors.Primary }, + '&.MuiAlert-colorError': { backgroundColor: Feedback.Error }, + }, + icon: { + ...handleBreakpoints({ marginRight: Spacing.xs }), + '& svg': handleBreakpoints({ + width: IconSize.sm, + height: IconSize.sm, + }), + }, + }, +}) + +export const defineMuiAlertTitle = ( + {}: DesignSystem, + { bodySBold }: TypographyOptions, +): Components['MuiAlertTitle'] => ({ + styleOverrides: { + root: handleBreakpoints({ + ...bodySBold, + height: IconSize.sm, + marginBlockEnd: '4px', + }), + }, +}) diff --git a/packages/curve-ui-kit/src/themes/palette/palette.ts b/packages/curve-ui-kit/src/themes/palette/palette.ts index 5f550ab49..ccab6d075 100644 --- a/packages/curve-ui-kit/src/themes/palette/palette.ts +++ b/packages/curve-ui-kit/src/themes/palette/palette.ts @@ -3,21 +3,21 @@ import { PaletteOptions } from '@mui/material' export const createPalette = ( mode: 'light' | 'dark', - { Layer, Color, Feedback, Text }: DesignSystem, + { Layer, Color, Feedback, Text: { TextColors } }: DesignSystem, ): PaletteOptions => ({ mode, primary: { main: Color.Primary[500] }, secondary: { main: Color.Secondary[500] }, - error: { main: Feedback.Error, contrastText: Text.TextColors.Error }, - info: { main: Feedback.Info, contrastText: Text.TextColors.Info }, - warning: { main: Feedback.Warning, contrastText: Text.TextColors.Warning }, - success: { main: Feedback.Success, contrastText: Text.TextColors.Success }, + error: { main: Layer.Feedback.Error, contrastText: TextColors.Feedback.Error }, + info: { main: Layer.Feedback.Info, contrastText: TextColors.Primary }, + warning: { main: Layer.Feedback.Warning, contrastText: TextColors.Feedback.Warning }, + success: { main: Layer.Feedback.Success, contrastText: TextColors.Feedback.Success }, text: { - primary: Text.TextColors.Primary, - secondary: Text.TextColors.Secondary, - tertiary: Text.TextColors.Tertiary, - disabled: Text.TextColors.Disabled, - highlight: Text.TextColors.Highlight, + primary: TextColors.Primary, + secondary: TextColors.Secondary, + tertiary: TextColors.Tertiary, + disabled: TextColors.Disabled, + highlight: TextColors.Highlight, }, action: { // note: action, disabled, focus themes are left default for now diff --git a/packages/curve-ui-kit/src/themes/stories/Alert.stories.ts b/packages/curve-ui-kit/src/themes/stories/Alert.stories.ts deleted file mode 100644 index 8c5ae2122..000000000 --- a/packages/curve-ui-kit/src/themes/stories/Alert.stories.ts +++ /dev/null @@ -1,74 +0,0 @@ -import Alert from '@mui/material/Alert' -import type { Meta, StoryObj } from '@storybook/react' - -const meta: Meta = { - title: 'UI Kit/Primitives/Alert', - component: Alert, - argTypes: { - variant: { - control: 'select', - options: ['standard', 'filled', 'outlined', undefined], - description: 'The variant of the component', - }, - severity: { - control: 'select', - options: ['success', 'info', 'warning', 'error', undefined], - description: 'The severity of the component', - }, - children: { - control: 'text', - description: 'The label of the component', - }, - }, - args: { - variant: 'filled', - }, -} - -type Story = StoryObj - -export const Success: Story = { - args: { - severity: 'success', - children: 'A success text message is displayed. A little llama is happy.', - }, -} - -export const SuccessOutlined: Story = { - args: { - severity: 'success', - variant: 'outlined', - children: 'An outlined success text message is displayed. A little llama is happy.', - }, -} - -export const Info: Story = { - args: { - severity: 'info', - children: 'An info text message is displayed. A little llama is curious.', - }, -} - -export const InfoOutlined: Story = { - args: { - severity: 'info', - variant: 'outlined', - children: 'An outlined info text message is displayed. A little llama is curious.', - }, -} - -export const Warning: Story = { - args: { - severity: 'warning', - children: 'A warning text message is displayed. A little llama is cautious.', - }, -} - -export const Error: Story = { - args: { - severity: 'error', - children: 'An error text message is displayed. A little llama is very sad.', - }, -} - -export default meta diff --git a/packages/curve-ui-kit/src/themes/stories/Alert.stories.tsx b/packages/curve-ui-kit/src/themes/stories/Alert.stories.tsx new file mode 100644 index 000000000..6ce8a06a6 --- /dev/null +++ b/packages/curve-ui-kit/src/themes/stories/Alert.stories.tsx @@ -0,0 +1,42 @@ +import AlertTitle from '@mui/material/AlertTitle' +import type { Meta, StoryObj } from '@storybook/react' +import Alert, { AlertProps } from '@mui/material/Alert' +import Stack from '@mui/material/Stack' + +const AlertStory = (props: AlertProps) => ( + + + SuccessA success text message is displayed. A little llama is happy 😊 + + + InfoA info text message is displayed. A little llama is curious 🤔 + + + WarningA warning text message is displayed. A little llama is cautious 🦙. + + + Error + An error text message is displayed. A little llama is very sad 😔 + + +) + +const meta: Meta = { + title: 'UI Kit/Primitives/Alert', + component: AlertStory, + argTypes: { + variant: { + control: 'select', + options: ['standard', 'filled', 'outlined', undefined], + description: 'The variant of the component', + }, + }, +} + +type Story = StoryObj + +export const Filled: Story = { args: { variant: 'filled' } } +export const Outlined: Story = { args: { variant: 'outlined' } } +export const Standard: Story = { args: { variant: 'standard' } } + +export default meta diff --git a/tests/cypress/e2e/loan/llamalend-markets.cy.ts b/tests/cypress/e2e/loan/llamalend-markets.cy.ts index f8c2b62e8..bbb9641bd 100644 --- a/tests/cypress/e2e/loan/llamalend-markets.cy.ts +++ b/tests/cypress/e2e/loan/llamalend-markets.cy.ts @@ -34,7 +34,7 @@ describe('LlamaLend Markets', () => { }) it('should show graphs', () => { - const [green, red] = [isDarkMode ? 'rgb(39, 184, 108)' : 'rgb(31, 162, 94)', 'rgb(237, 36, 47)'] + const [green, red] = [isDarkMode ? 'rgb(50, 206, 121)' : 'rgb(22, 125, 74)', 'rgb(237, 36, 47)'] cy.get('[data-testid="line-graph-cell-lend"] path').first().should('have.css', 'stroke', green) cy.get('[data-testid="line-graph-cell-borrow"] path').first().should('have.css', 'stroke', red) @@ -112,7 +112,7 @@ describe('LlamaLend Markets', () => { { toggle: 'borrowChart', element: 'line-graph-borrow' }, { toggle: 'lendChart', element: 'line-graph-lend' }, ) - cy.get(`[data-testid="${element}"]`).scrollIntoView() + cy.get(`[data-testid="${element}"]`).first().scrollIntoView() cy.get(`[data-testid="${element}"]`).should('be.visible') cy.get(`[data-testid="btn-visibility-settings"]`).click() cy.get(`[data-testid="visibility-toggle-${toggle}"]`).click()