Skip to content

Commit

Permalink
feat(novui): Map panda values to mantine theme (#5692)
Browse files Browse the repository at this point in the history
* feat: Map Mantine config

* fix: Use gradient default

* feat: Add WIP button

* feat: Include mantine styles & use example
  • Loading branch information
Joel Anton authored Jun 11, 2024
1 parent 8b7d73d commit 92377f7
Show file tree
Hide file tree
Showing 10 changed files with 179 additions and 5 deletions.
2 changes: 2 additions & 0 deletions apps/web/src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import { initializeApp } from './initializeApp';
import reportWebVitals from './reportWebVitals';
import { LAUNCH_DARKLY_CLIENT_SIDE_ID } from '@novu/shared-web';

// TODO: would like to figure out a better solution, but this unblocks for now
import '@novu/novui/components.css';
import '@novu/novui/styles.css';

(async () => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import { Button } from '@novu/novui';
import { PageContainer } from '../../layout';
import { WorkflowsTable } from './table';

export const WorkflowsListPage = () => {
return (
<PageContainer title="Workflows">
<Button onClick={() => alert('hello!')}>Hello!</Button>
<WorkflowsTable />
</PageContainer>
);
Expand Down
4 changes: 1 addition & 3 deletions libs/novui/.storybook/preview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,7 @@ import { css } from '../styled-system/css';
import { MantineThemeProvider } from '@mantine/core';
import { NovuiProvider } from '../src/components';

import '@mantine/core/styles.css';
// Bring in the Panda-generated stylesheets
import '../src/index.css';
import '../styles.css';

export const parameters: Parameters = {
layout: 'fullscreen',
Expand Down
3 changes: 2 additions & 1 deletion libs/novui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,8 @@
"require": "./styled-system/jsx/index.js",
"import": "./styled-system/jsx/index.js"
},
"./styles.css": "./styled-system/styles.css"
"./styles.css": "./styled-system/styles.css",
"./components.css": "./node_modules/@mantine/core/styles.css"
},
"scripts": {
"prepare:lib": "pnpm prepare:panda && pnpm prepare:audit",
Expand Down
4 changes: 3 additions & 1 deletion libs/novui/src/components/NovuiProvider.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import { MantineProvider } from '@mantine/core';
import { FC, PropsWithChildren } from 'react';
import { IconProvider } from '../icons/IconProvider';
import { MANTINE_THEME } from './mantine-theme.config';

type INovuiProviderProps = PropsWithChildren;

/** Used to export a v7 Mantine provider */
export const NovuiProvider: FC<INovuiProviderProps> = ({ children }) => {
return (
<MantineProvider>
<MantineProvider theme={MANTINE_THEME}>
<IconProvider>{children}</IconProvider>
</MantineProvider>
);
Expand Down
55 changes: 55 additions & 0 deletions libs/novui/src/components/button/Button.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import React from 'react';
import { StoryFn, Meta } from '@storybook/react';
import { Button } from './Button';
import { Flex } from '../../../styled-system/jsx';
import { Icon10K, IconInfo } from '../../icons';

export default {
title: 'Components/Button',
component: Button,
argTypes: {},
} as Meta<typeof Button>;

const Template: StoryFn<typeof Button> = ({ ...args }) => <Button {...args}>Click Me</Button>;

export const Default = Template.bind({});
Default.args = {};

export const Loading = Template.bind({});
Loading.args = {
loading: true,
};

export const icon = () => (
<Flex>
<Button size="lg" Icon={Icon10K}>
Large
</Button>
<Button Icon={IconInfo}>Medium</Button>
</Flex>
);

export const filled = () => (
<Flex>
<Button size="lg">Large</Button>
<Button>Medium</Button>
</Flex>
);

export const outline = () => (
<Flex>
<Button size="lg" variant="outline">
Large
</Button>
<Button variant="outline">Medium</Button>
</Flex>
);

export const disabled = () => (
<Flex>
<Button disabled>Filled</Button>
<Button variant="outline" disabled>
Outline
</Button>
</Flex>
);
25 changes: 25 additions & 0 deletions libs/novui/src/components/button/Button.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { FC } from 'react';
import { CorePropsWithChildren } from '../../types';
import { Button as ExternalButton, ButtonProps } from '@mantine/core';
import { IconType } from '../../icons';
import { css } from '../../../styled-system/css';

export interface IButtonProps
extends CorePropsWithChildren,
React.ButtonHTMLAttributes<HTMLButtonElement>,
Pick<ButtonProps, 'size' | 'variant'> {
Icon?: IconType;
}

export const Button: FC<IButtonProps> = ({ children, Icon, size = 'md', variant = 'filled', ...buttonProps }) => {
return (
<ExternalButton
size={size}
leftSection={Icon ? <Icon title="button-icon" size="16" className={css({ color: 'legacy.white' })} /> : undefined}
variant={variant}
{...buttonProps}
>
{children}
</ExternalButton>
);
};
1 change: 1 addition & 0 deletions libs/novui/src/components/button/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './Button';
1 change: 1 addition & 0 deletions libs/novui/src/components/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export * from './NovuiProvider';
export * from './table';
export * from './Test';
export * from './button';
87 changes: 87 additions & 0 deletions libs/novui/src/components/mantine-theme.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import { MantineColorsTuple, MantineThemeOverride } from '@mantine/core';
import { COLOR_PALETTE_TOKENS } from '../tokens/colors.tokens';
import { token, Token } from '../../styled-system/tokens';

/**
* Generates a Mantine color tuple for the given Panda color "family"
*/
const generateMantineColorTokens = (colorFamily: keyof typeof COLOR_PALETTE_TOKENS): MantineColorsTuple => {
return Object.keys(COLOR_PALETTE_TOKENS[colorFamily]).map((paletteNumber) =>
token(`colors.${colorFamily}.${paletteNumber}.dark` as Token)
) as unknown as MantineColorsTuple;
};

/** Maps Panda token values to a mantine theme config */
export const MANTINE_THEME: MantineThemeOverride = {
// colors
white: token('colors.legacy.white'),
black: token('colors.legacy.black'),
primaryColor: 'gradient',
primaryShade: 6,
colors: {
gray: generateMantineColorTokens('mauve'),
yellow: generateMantineColorTokens('amber'),
blue: generateMantineColorTokens('blue'),
green: generateMantineColorTokens('green'),
red: generateMantineColorTokens('red'),
// must have a tuple of 10 strings, but replace the value at primaryShade with our gradient
gradient: ['', '', '', '', '', '', token('gradients.horizontal'), '', '', ''],
},

// typography
fontFamily: token('fonts.system'),
fontFamilyMonospace: token('fonts.mono'),
lineHeights: {
sm: token('lineHeights.100'),
md: token('lineHeights.125'),
lg: token('lineHeights.150'),
// missing 175
xl: token('lineHeights.200'),
},
headings: {
fontFamily: token('fonts.system'),
fontWeight: token('fontWeights.strong'),
sizes: {
// page title
h1: {
fontSize: token('fontSizes.150'),
lineHeight: token('lineHeights.200'),
},
// section title
h2: {
fontSize: token('fontSizes.125'),
lineHeight: token('lineHeights.175'),
},
// subsection title
h3: {
fontSize: token('fontSizes.100'),
lineHeight: token('lineHeights.150'),
},
},
},

// TODO: these are guesses for how they match up
spacing: {
xs: token('spacing.25'),
sm: token('spacing.50'),
md: token('spacing.100'),
lg: token('spacing.150'),
xl: token('spacing.200'),
xxl: token('spacing.250'),
xxxl: token('spacing.300'),
},
radius: {
xs: token('radii.xs'),
sm: token('radii.s'),
md: token('radii.m'),
lg: token('radii.l'),
},
defaultRadius: 'md',
shadows: {
// TODO: this makes no sense except for md
sm: token('shadows.light'),
md: token('shadows.medium'),
lg: token('shadows.dark'),
xl: token('shadows.color'),
},
};

0 comments on commit 92377f7

Please sign in to comment.