From dadf638631d9bcc3ccf8529ee35529568b6584ce Mon Sep 17 00:00:00 2001 From: Hazem Krimi Date: Tue, 18 Mar 2025 17:12:38 +0100 Subject: [PATCH] Stories scaffolding --- .gitignore | 1 - package.json | 7 +- src/components/Alert/index.stories.ts | 5 +- src/components/Avatar/index.stories.ts | 28 ++ src/components/Avatar/index.tsx | 2 +- src/components/BackendFeatureCard/index.tsx | 36 --- src/components/Box/index.stories.ts | 27 ++ src/components/Box/index.tsx | 31 +- src/components/Button/index.stories.ts | 28 ++ src/components/Button/index.tsx | 7 +- src/components/Button/styles.ts | 4 +- src/components/Card/index.stories.ts | 28 ++ .../{CategoryCard => Card}/index.tsx | 23 +- src/components/CheckBox/index.stories.ts | 29 ++ src/components/CheckBox/index.tsx | 6 +- src/components/Chip/index.stories.ts | 29 ++ src/components/Chip/index.tsx | 3 +- src/components/ContextMenu/index.stories.ts | 28 ++ src/components/ContextMenu/index.tsx | 8 +- src/components/FeatureCard/index.tsx | 72 ----- src/components/FrontendFeatureCard/index.tsx | 61 ---- src/components/IconButton/index.stories.ts | 28 ++ src/components/IconButton/index.tsx | 2 +- src/components/ImagePreview/index.stories.ts | 25 ++ src/components/ImagePreview/index.tsx | 2 +- src/components/Input/index.stories.ts | 26 ++ src/components/Input/index.tsx | 3 +- src/components/Link/index.stories.ts | 29 ++ src/components/Link/index.tsx | 8 +- src/components/Menu/index.stories.ts | 27 ++ src/components/Menu/index.tsx | 9 +- src/components/Modal/index.stories.ts | 31 ++ src/components/Modal/index.tsx | 7 +- src/components/Navbar/index.tsx | 172 ----------- src/components/Navbar/styles.ts | 47 --- src/components/Search/index.stories.ts | 28 ++ src/components/Search/index.tsx | 3 +- src/components/SectionSelector/index.tsx | 34 --- src/components/SectionSelector/styles.ts | 119 -------- src/components/Select/index.stories.ts | 33 ++ src/components/Select/index.tsx | 11 +- src/components/Sidebar/index.tsx | 286 ------------------ src/components/Sidebar/styles.ts | 25 -- src/components/SidebarItem/index.tsx | 25 -- src/components/SidebarItem/styles.ts | 53 ---- src/components/Spinner/index.stories.ts | 25 ++ src/components/SupportSidebar/index.tsx | 112 ------- src/components/SupportSidebar/styles.ts | 34 --- src/components/TemplateCard/index.tsx | 50 --- src/components/Text/index.stories.ts | 28 ++ src/components/Text/index.tsx | 2 +- src/components/TextArea/index.stories.ts | 28 ++ src/components/TextArea/index.tsx | 3 +- src/vite-env.d.ts | 1 + vite.config.ts | 6 + 55 files changed, 596 insertions(+), 1189 deletions(-) create mode 100644 src/components/Avatar/index.stories.ts delete mode 100644 src/components/BackendFeatureCard/index.tsx create mode 100644 src/components/Box/index.stories.ts create mode 100644 src/components/Button/index.stories.ts create mode 100644 src/components/Card/index.stories.ts rename src/components/{CategoryCard => Card}/index.tsx (75%) create mode 100644 src/components/CheckBox/index.stories.ts create mode 100644 src/components/Chip/index.stories.ts create mode 100644 src/components/ContextMenu/index.stories.ts delete mode 100644 src/components/FeatureCard/index.tsx delete mode 100644 src/components/FrontendFeatureCard/index.tsx create mode 100644 src/components/IconButton/index.stories.ts create mode 100644 src/components/ImagePreview/index.stories.ts create mode 100644 src/components/Input/index.stories.ts create mode 100644 src/components/Link/index.stories.ts create mode 100644 src/components/Menu/index.stories.ts create mode 100644 src/components/Modal/index.stories.ts delete mode 100644 src/components/Navbar/index.tsx delete mode 100644 src/components/Navbar/styles.ts create mode 100644 src/components/Search/index.stories.ts delete mode 100644 src/components/SectionSelector/index.tsx delete mode 100644 src/components/SectionSelector/styles.ts create mode 100644 src/components/Select/index.stories.ts delete mode 100644 src/components/Sidebar/index.tsx delete mode 100644 src/components/Sidebar/styles.ts delete mode 100644 src/components/SidebarItem/index.tsx delete mode 100644 src/components/SidebarItem/styles.ts create mode 100644 src/components/Spinner/index.stories.ts delete mode 100644 src/components/SupportSidebar/index.tsx delete mode 100644 src/components/SupportSidebar/styles.ts delete mode 100644 src/components/TemplateCard/index.tsx create mode 100644 src/components/Text/index.stories.ts create mode 100644 src/components/TextArea/index.stories.ts diff --git a/.gitignore b/.gitignore index f591aee..1023287 100644 --- a/.gitignore +++ b/.gitignore @@ -17,7 +17,6 @@ codegen-* # misc .DS_Store .env -.env.* npm-debug.log* yarn-debug.log* diff --git a/package.json b/package.json index 2956803..7dec51d 100644 --- a/package.json +++ b/package.json @@ -56,5 +56,10 @@ "typescript-eslint": "^8.26.1", "vite": "^6.2.2", "vite-plugin-svgr": "^4.3.0" - } + }, + "peerDependencies": { + "react": "^19.0.0", + "react-dom": "^19.0.0", + "styled-components": "^6.1.15" + } } diff --git a/src/components/Alert/index.stories.ts b/src/components/Alert/index.stories.ts index 75bb887..d5cc358 100644 --- a/src/components/Alert/index.stories.ts +++ b/src/components/Alert/index.stories.ts @@ -11,14 +11,15 @@ const meta = { tags: ['autodocs'], argTypes: { text: { control: 'text' }, - color: { control: 'color' }, + color: { options: ['client', 'productOwner', 'developer', 'admin'] }, }, } satisfies Meta; export default meta; + type Story = StoryObj; -export const Primary: Story = { +export const Example: Story = { args: { text: 'Alert', color: 'client' diff --git a/src/components/Avatar/index.stories.ts b/src/components/Avatar/index.stories.ts new file mode 100644 index 0000000..bb4c3fd --- /dev/null +++ b/src/components/Avatar/index.stories.ts @@ -0,0 +1,28 @@ +import type { Meta, StoryObj } from '@storybook/react'; + +import Avatar from '.'; + +const meta = { + title: 'Avatar', + component: Avatar, + parameters: { + layout: 'centered', + }, + tags: ['autodocs'], + argTypes: { + text: { control: 'text' }, + color: { options: ['client', 'productOwner', 'developer', 'admin'] }, + size: { options: ['big', 'small'] }, + }, +} satisfies Meta; + +export default meta; + +type Story = StoryObj; + +export const Example: Story = { + args: { + text: 'A', + color: 'admin' + }, +}; diff --git a/src/components/Avatar/index.tsx b/src/components/Avatar/index.tsx index cda51a0..5f912fa 100644 --- a/src/components/Avatar/index.tsx +++ b/src/components/Avatar/index.tsx @@ -10,7 +10,7 @@ type AvatarProps = { const Avatar = ({ color, size = 'small', text, className }: AvatarProps) => { return ( - {text} + {text[0]} ); }; diff --git a/src/components/BackendFeatureCard/index.tsx b/src/components/BackendFeatureCard/index.tsx deleted file mode 100644 index f23f512..0000000 --- a/src/components/BackendFeatureCard/index.tsx +++ /dev/null @@ -1,36 +0,0 @@ -import { Box, Text } from '..'; -import { Backend } from '../../assets'; -import { FeatureOutput } from '../../graphql/types'; - -type BackendFeatureCardProps = { - feature: FeatureOutput; -}; - -const BackendFeatureCard = ({ feature }: BackendFeatureCardProps) => { - return ( - - - - - {feature.name} - - - - - - - - ); -}; - -export default BackendFeatureCard; diff --git a/src/components/Box/index.stories.ts b/src/components/Box/index.stories.ts new file mode 100644 index 0000000..8f4d86f --- /dev/null +++ b/src/components/Box/index.stories.ts @@ -0,0 +1,27 @@ +import type { Meta, StoryObj } from '@storybook/react'; + +import Box from '.'; + +const meta = { + title: 'Box', + component: Box, + parameters: { + layout: 'centered', + }, + tags: ['autodocs'], + argTypes: { + color: { control: 'text' }, + children: { control: 'text' }, + }, +} satisfies Meta; + +export default meta; + +type Story = StoryObj; + +export const Example: Story = { + args: { + color: '#000000', + children: 'Hello, World!', + }, +}; diff --git a/src/components/Box/index.tsx b/src/components/Box/index.tsx index 0fd30d9..d6d041e 100644 --- a/src/components/Box/index.tsx +++ b/src/components/Box/index.tsx @@ -1,9 +1,10 @@ -import React from 'react'; +import React, { JSX } from 'react'; import { Wrapper } from './styles'; export type BoxProps = { className?: string; - children?: React.ReactNode | JSX.Element | string; + children?: React.ReactNode | JSX.Element | JSX.Element[] | string; + ref?: React.Ref; onClick?: () => void; cursor?: 'pointer' | 'default'; @@ -38,11 +39,11 @@ export type BoxProps = { alignItems?: 'center' | 'flex-start' | 'flex-end' | 'stretch'; justifyContent?: - | 'center' - | 'flex-start' - | 'flex-end' - | 'space-between' - | 'space-around'; + | 'center' + | 'flex-start' + | 'flex-end' + | 'space-between' + | 'space-around'; alignSelf?: 'center' | 'flex-start' | 'flex-end'; justifySelf?: 'center' | 'flex-start' | 'flex-end'; @@ -86,14 +87,12 @@ export type BoxProps = { textDecoration?: string; }; -const Box = React.forwardRef( - ({ children, ...props }, ref) => { - return ( - - {children} - - ); - } -); +function Box({ children, ref, ...props }: BoxProps) { + return ( + + {children} + + ); +}; export default Box; diff --git a/src/components/Button/index.stories.ts b/src/components/Button/index.stories.ts new file mode 100644 index 0000000..5af62ae --- /dev/null +++ b/src/components/Button/index.stories.ts @@ -0,0 +1,28 @@ +import type { Meta, StoryObj } from '@storybook/react'; + +import Button from '.'; + +const meta = { + title: 'Button', + component: Button, + parameters: { + layout: 'centered', + }, + tags: ['autodocs'], + argTypes: { + color: { options: ['client', 'productOwner', 'developer', 'admin', 'error'] }, + text: { control: 'text' }, + }, +} satisfies Meta; + +export default meta; + +type Story = StoryObj; + +export const Example: Story = { + args: { + color: 'admin', + text: 'Hello, World!', + variant: 'primary-action' + }, +}; diff --git a/src/components/Button/index.tsx b/src/components/Button/index.tsx index 8fadab5..f6b0bea 100644 --- a/src/components/Button/index.tsx +++ b/src/components/Button/index.tsx @@ -1,4 +1,5 @@ -import { Spinner } from '..'; +import Spinner from '../Spinner'; + import { Wrapper } from './styles'; type ButtonProps = { @@ -6,8 +7,8 @@ type ButtonProps = { size?: 'small' | 'big'; variant?: 'primary-action' | 'secondary-action' | 'outlined' | 'text'; type?: 'submit' | 'button' | 'reset'; - iconLeft?: React.FunctionComponentElement>; - iconRight?: React.FunctionComponentElement>; + iconLeft?: React.ReactNode; + iconRight?: React.ReactNode; fullWidth?: boolean; loading?: boolean; disabled?: boolean; diff --git a/src/components/Button/styles.ts b/src/components/Button/styles.ts index dc1e694..c6bb982 100644 --- a/src/components/Button/styles.ts +++ b/src/components/Button/styles.ts @@ -4,8 +4,8 @@ type WrapperProps = { color: 'client' | 'productOwner' | 'developer' | 'admin' | 'error'; size?: 'small' | 'big'; variant?: 'primary-action' | 'secondary-action' | 'outlined' | 'text'; - iconLeft?: React.FunctionComponentElement>; - iconRight?: React.FunctionComponentElement>; + iconLeft?: React.ReactNode; + iconRight?: React.ReactNode; load?: boolean; disabled?: boolean; fullWidth?: boolean; diff --git a/src/components/Card/index.stories.ts b/src/components/Card/index.stories.ts new file mode 100644 index 0000000..bf6196c --- /dev/null +++ b/src/components/Card/index.stories.ts @@ -0,0 +1,28 @@ +import type { Meta, StoryObj } from '@storybook/react'; + +import Card from '.'; + +const meta = { + title: 'Card', + component: Card, + parameters: { + layout: 'centered', + }, + tags: ['autodocs'], + argTypes: { + color: { options: ['client', 'productOwner', 'developer', 'admin', 'error'] }, + }, +} satisfies Meta; + +export default meta; + +type Story = StoryObj; + +export const Example: Story = { + args: { + color: 'developer', + title: 'Card title', + description: 'Card description', + selected: true + }, +}; diff --git a/src/components/CategoryCard/index.tsx b/src/components/Card/index.tsx similarity index 75% rename from src/components/CategoryCard/index.tsx rename to src/components/Card/index.tsx index 44d9eff..baaef73 100644 --- a/src/components/CategoryCard/index.tsx +++ b/src/components/Card/index.tsx @@ -1,22 +1,25 @@ -import { Box, Text } from '..'; -import { CategoryOutput } from '../../graphql/types'; +import Box from '../Box'; +import Text from '../Text'; + import { theme } from '../../themes'; -type CategoryCardProps = { - category: CategoryOutput; +type CardProps = { + title: string; + description: string; selectable?: boolean; selected?: boolean; toggleSelect?: () => void; color: 'client' | 'productOwner' | 'developer' | 'admin'; }; -const CategoryCard = ({ - category, +const Card = ({ + title, + description, selectable = false, selected = false, toggleSelect = () => {}, color, -}: CategoryCardProps) => { +}: CardProps) => { return ( - {category.name} + {title} - {category.description} + {description} ); }; -export default CategoryCard; +export default Card; diff --git a/src/components/CheckBox/index.stories.ts b/src/components/CheckBox/index.stories.ts new file mode 100644 index 0000000..d5f9448 --- /dev/null +++ b/src/components/CheckBox/index.stories.ts @@ -0,0 +1,29 @@ +import type { Meta, StoryObj } from '@storybook/react'; + +import CheckBox from '.'; + +const meta = { + title: 'CheckBox', + component: CheckBox, + parameters: { + layout: 'centered', + }, + tags: ['autodocs'], + argTypes: { + color: { options: ['client', 'productOwner', 'developer', 'admin'] }, + label: { control: 'text' }, + }, +} satisfies Meta; + +export default meta; + +type Story = StoryObj; + +export const Example: Story = { + args: { + color: 'admin', + label: 'Hello, World!', + checked: false, + onClick: () => window.alert('Clicked!'), + }, +}; diff --git a/src/components/CheckBox/index.tsx b/src/components/CheckBox/index.tsx index 776a67b..8a8aefe 100644 --- a/src/components/CheckBox/index.tsx +++ b/src/components/CheckBox/index.tsx @@ -1,19 +1,19 @@ import { Wrapper } from './styles'; -import { Text } from '..'; + +import Text from '../Text'; + import { Check } from '../../assets'; type CheckBoxProps = { className?: string; color?: 'client' | 'productOwner' | 'developer' | 'admin'; label: string; - name: string; checked: boolean; onClick: () => void; }; const CheckBox = ({ label, - name, checked, onClick, ...props diff --git a/src/components/Chip/index.stories.ts b/src/components/Chip/index.stories.ts new file mode 100644 index 0000000..549db46 --- /dev/null +++ b/src/components/Chip/index.stories.ts @@ -0,0 +1,29 @@ +import type { Meta, StoryObj } from '@storybook/react'; + +import Chip from '.'; + +const meta = { + title: 'Chip', + component: Chip, + parameters: { + layout: 'centered', + }, + tags: ['autodocs'], + argTypes: { + color: { options: ['client', 'productOwner', 'developer', 'admin'] }, + text: { control: 'text' }, + variant: { options: ['outlined', 'filled'] }, + }, +} satisfies Meta; + +export default meta; + +type Story = StoryObj; + +export const Example: Story = { + args: { + color: 'admin', + text: 'Hello, World!', + variant: 'filled' + }, +}; diff --git a/src/components/Chip/index.tsx b/src/components/Chip/index.tsx index fbbb20f..b016019 100644 --- a/src/components/Chip/index.tsx +++ b/src/components/Chip/index.tsx @@ -1,5 +1,6 @@ import { Wrapper } from './styles'; -import { Text } from '..'; + +import Text from '../Text'; type ChipProps = { variant?: 'outlined' | 'filled'; diff --git a/src/components/ContextMenu/index.stories.ts b/src/components/ContextMenu/index.stories.ts new file mode 100644 index 0000000..9eea57e --- /dev/null +++ b/src/components/ContextMenu/index.stories.ts @@ -0,0 +1,28 @@ +import type { Meta, StoryObj } from '@storybook/react'; + +import ContextMenu from '.'; + +const meta = { + title: 'ContextMenu', + component: ContextMenu, + parameters: { + layout: 'centered', + }, + tags: ['autodocs'], +} satisfies Meta; + +export default meta; + +type Story = StoryObj; + +export const Example: Story = { + args: { + items: [ + { + label: 'Hello, World!', + action: () => window.alert('Hello, World!') + } + ], + component: 'component', + }, +}; diff --git a/src/components/ContextMenu/index.tsx b/src/components/ContextMenu/index.tsx index 91296f7..40550e3 100644 --- a/src/components/ContextMenu/index.tsx +++ b/src/components/ContextMenu/index.tsx @@ -1,6 +1,8 @@ import { useEffect, useRef, useState } from 'react'; + import { Wrapper } from './styles'; -import { Text } from '..'; + +import Text from '../Text'; type ContextMenuProps = { className?: string; @@ -10,7 +12,7 @@ type ContextMenuProps = { const ContextMenu = ({ items, component, className }: ContextMenuProps) => { const [open, setOpen] = useState(false); - const parentComponentRef = useRef(); + const parentComponentRef = useRef(null); useEffect(() => { parentComponentRef.current = document.querySelector(`#${component}`) as HTMLDivElement; @@ -31,7 +33,7 @@ const ContextMenu = ({ items, component, className }: ContextMenuProps) => { parentComponentRef.current?.removeEventListener('mouseenter', openMenu); parentComponentRef.current?.removeEventListener('mouseleave', closeMenu); }; - }, []); + }, [component]); return ( void; - color?: 'client' | 'productOwner' | 'developer' | 'admin'; -}; - -const FeatureCard = ({ - feature, - selectable = false, - selected = false, - toggleSelect = () => {}, - color, -}: FeatureCardProps) => { - return ( - {}} - display='grid' - gridTemplateRows='auto' - alignItems='center' - rowGap='10px' - borderRadius='10px' - cursor={selectable ? 'pointer' : undefined} - > - - - - {feature.name} - - - - - {feature.featureType === 'frontend' || - (feature.featureType === 'fullstack' && )} - - - {feature.featureType === 'backend' || - (feature.featureType === 'fullstack' && )} - - - - - - {feature.description} - - - ${feature.price} - - - - ); -}; - -export default FeatureCard; diff --git a/src/components/FrontendFeatureCard/index.tsx b/src/components/FrontendFeatureCard/index.tsx deleted file mode 100644 index 3893a19..0000000 --- a/src/components/FrontendFeatureCard/index.tsx +++ /dev/null @@ -1,61 +0,0 @@ -import { Handle, Position } from 'reactflow'; -import { Box, Text } from '..'; -import { FeatureOutput } from '../../graphql/types'; - -type FrontendFeatureCardProps = { - data: FeatureOutput; - isConnectable?: boolean; - className?: string; -}; - -const FrontendFeatureCard = ({ - data, - isConnectable = false, - className, -}: FrontendFeatureCardProps) => { - return ( - <> - - - - - - {data.name} - - - - - {data.wireframes?.map((wireframe) => ( - {wireframe.name} - ))} - - - - - ); -}; - -export default FrontendFeatureCard; diff --git a/src/components/IconButton/index.stories.ts b/src/components/IconButton/index.stories.ts new file mode 100644 index 0000000..e18abab --- /dev/null +++ b/src/components/IconButton/index.stories.ts @@ -0,0 +1,28 @@ +import type { Meta, StoryObj } from '@storybook/react'; + +import IconButton from '.'; + +const meta = { + title: 'IconButton', + component: IconButton, + parameters: { + layout: 'centered', + }, + tags: ['autodocs'], + argTypes: { + color: { options: ['client', 'productOwner', 'developer', 'admin'] }, + size: { options: ['small', 'medium', 'big'] }, + }, +} satisfies Meta; + +export default meta; + +type Story = StoryObj; + +export const Example: Story = { + args: { + color: 'admin', + size: 'medium', + onClick: () => window.alert('Hello, World!') + }, +}; diff --git a/src/components/IconButton/index.tsx b/src/components/IconButton/index.tsx index 3ca7a2c..ccd9d31 100644 --- a/src/components/IconButton/index.tsx +++ b/src/components/IconButton/index.tsx @@ -3,7 +3,7 @@ import { Wrapper } from './styles'; type IconButtonProps = { color?: 'client' | 'productOwner' | 'developer' | 'admin'; size?: 'small' | 'medium' | 'big'; - icon?: React.FunctionComponentElement>; + icon?: React.ReactNode; onClick: () => void; }; diff --git a/src/components/ImagePreview/index.stories.ts b/src/components/ImagePreview/index.stories.ts new file mode 100644 index 0000000..968eb5e --- /dev/null +++ b/src/components/ImagePreview/index.stories.ts @@ -0,0 +1,25 @@ +import type { Meta, StoryObj } from '@storybook/react'; + +import ImagePreview from '.'; + +const meta = { + title: 'ImagePreview', + component: ImagePreview, + parameters: { + layout: 'centered', + }, + tags: ['autodocs'], + argTypes: { + color: { options: ['client', 'productOwner', 'developer', 'admin'] }, + }, +} satisfies Meta; + +export default meta; + +type Story = StoryObj; + +export const Example: Story = { + args: { + color: 'developer', + }, +}; diff --git a/src/components/ImagePreview/index.tsx b/src/components/ImagePreview/index.tsx index 9656dae..f3bcc04 100644 --- a/src/components/ImagePreview/index.tsx +++ b/src/components/ImagePreview/index.tsx @@ -16,7 +16,7 @@ type ImagePreviewProps = { error?: boolean; errorMessage?: string; name?: string; - image: { name: string; src: string } | undefined; + image?: { name: string; src: string } | undefined; deletable?: boolean; onChange?: (event: React.ChangeEvent) => void; onDelete?: () => void; diff --git a/src/components/Input/index.stories.ts b/src/components/Input/index.stories.ts new file mode 100644 index 0000000..02a76f6 --- /dev/null +++ b/src/components/Input/index.stories.ts @@ -0,0 +1,26 @@ +import type { Meta, StoryObj } from '@storybook/react'; + +import Input from '.'; + +const meta = { + title: 'Input', + component: Input, + parameters: { + layout: 'centered', + }, + tags: ['autodocs'], + argTypes: { + color: { options: ['client', 'productOwner', 'developer', 'admin'] }, + }, +} satisfies Meta; + +export default meta; + +type Story = StoryObj; + +export const Example: Story = { + args: { + color: 'developer', + onChange: () => {} + }, +}; diff --git a/src/components/Input/index.tsx b/src/components/Input/index.tsx index d4521c4..c2f57bd 100644 --- a/src/components/Input/index.tsx +++ b/src/components/Input/index.tsx @@ -1,4 +1,5 @@ -import { Text } from '..'; +import Text from '../Text'; + import { Upload } from '../../assets'; import { Wrapper } from './styles'; diff --git a/src/components/Link/index.stories.ts b/src/components/Link/index.stories.ts new file mode 100644 index 0000000..3725ae5 --- /dev/null +++ b/src/components/Link/index.stories.ts @@ -0,0 +1,29 @@ +import type { Meta, StoryObj } from '@storybook/react'; + +import Link from '.'; + +const meta = { + title: 'Link', + component: Link, + parameters: { + layout: 'centered', + }, + tags: ['autodocs'], + argTypes: { + color: { options: ['success', 'error', 'warning', 'black'] }, + }, +} satisfies Meta; + +export default meta; + +type Story = StoryObj; + +export const Example: Story = { + args: { + color: 'success', + children: 'Link', + url: true, + href: 'https://hazemkrimi.tech', + target: '_blank' + }, +}; diff --git a/src/components/Link/index.tsx b/src/components/Link/index.tsx index cdf1bd8..149492b 100644 --- a/src/components/Link/index.tsx +++ b/src/components/Link/index.tsx @@ -1,4 +1,4 @@ -import { Link as RouterLink } from 'react-router-dom'; +import { JSX } from 'react'; import { Wrapper } from './styles'; type LinkProps = { @@ -18,7 +18,7 @@ type LinkProps = { | string; selected?: boolean; className?: string; - iconLeft?: React.FunctionComponentElement>; + iconLeft?: React.ReactNode; onClick?: () => void; target?: '_self' | '_blank'; }; @@ -35,10 +35,10 @@ const Link = ({ return ( {href && !url ? ( - + {iconLeft && {iconLeft}} {children} - + ) : ( {iconLeft && {iconLeft}} diff --git a/src/components/Menu/index.stories.ts b/src/components/Menu/index.stories.ts new file mode 100644 index 0000000..7b736f4 --- /dev/null +++ b/src/components/Menu/index.stories.ts @@ -0,0 +1,27 @@ +import type { Meta, StoryObj } from '@storybook/react'; + +import Menu from '.'; + +const meta = { + title: 'Menu', + component: Menu, + parameters: { + layout: 'centered', + }, + tags: ['autodocs'], +} satisfies Meta; + +export default meta; + +type Story = StoryObj; + +export const Example: Story = { + args: { + items: [ + { + label: 'Hello, World!', + } + ], + component: 'component', + }, +}; diff --git a/src/components/Menu/index.tsx b/src/components/Menu/index.tsx index 127981f..8c014fe 100644 --- a/src/components/Menu/index.tsx +++ b/src/components/Menu/index.tsx @@ -1,11 +1,12 @@ import { useEffect, useRef, useState } from 'react'; import { Wrapper } from './styles'; -import { Text } from '..'; + +import Text from '../Text'; type MenuProps = { className?: string; items: Array<{ - icon: React.FunctionComponentElement>; + icon?: React.ReactNode; avoid?: boolean; label: string; action?: () => void; @@ -16,7 +17,7 @@ type MenuProps = { const Menu = ({ items, component, className }: MenuProps) => { const [open, setOpen] = useState(false); const componentRef = useRef(null); - const parentComponentRef = useRef(); + const parentComponentRef = useRef(null); const openMenu = () => setOpen(true); const closeMenu = () => setOpen(false); @@ -31,7 +32,7 @@ const Menu = ({ items, component, className }: MenuProps) => { parentComponentRef.current?.removeEventListener('mouseenter', openMenu); componentRef.current?.removeEventListener('mouseleave', closeMenu); }; - }, []); + }, [component]); return ( ; + +export default meta; + +type Story = StoryObj; + +export const Example: Story = { + args: { + color: 'productOwner', + title: 'Modal', + description: 'This is a modal!', + onConfirm: () => {}, + onClose: () => {}, + }, +}; diff --git a/src/components/Modal/index.tsx b/src/components/Modal/index.tsx index e916e94..2fa4ebb 100644 --- a/src/components/Modal/index.tsx +++ b/src/components/Modal/index.tsx @@ -1,5 +1,10 @@ +import { JSX } from 'react'; import { theme } from '../../themes'; -import { Box, Button, Text } from '..'; + +import Box from '../Box'; +import Button from '../Button'; +import Text from '../Text'; + import { Wrapper } from './styles'; type ModalProps = { diff --git a/src/components/Navbar/index.tsx b/src/components/Navbar/index.tsx deleted file mode 100644 index a1ea3d6..0000000 --- a/src/components/Navbar/index.tsx +++ /dev/null @@ -1,172 +0,0 @@ -import { useReactiveVar } from '@apollo/client'; -import { useNavigate, useLocation } from 'react-router'; -import { roleVar, tokenVar, userVar } from '../../graphql/state'; -import { Wrapper } from './styles'; -import { Avatar, Link, Menu, Text } from '..'; -import { Settings, Logout, Logo } from '../../assets'; - -const Navbar = () => { - const user = useReactiveVar(userVar); - const role = useReactiveVar(roleVar); - const navigate = useNavigate(); - const location = useLocation(); - - return ( - - - - - -
-
- - - {user?.firstName} {user?.lastName} - -
- , - label: 'Settings', - action: () => navigate('/settings'), - }, - { - icon: , - label: 'Logout', - action: () => { - tokenVar(undefined); - localStorage.removeItem('token'); - navigate('/login'); - }, - avoid: true, - }, - ]} - /> - - ); -}; - -export default Navbar; diff --git a/src/components/Navbar/styles.ts b/src/components/Navbar/styles.ts deleted file mode 100644 index a2d1530..0000000 --- a/src/components/Navbar/styles.ts +++ /dev/null @@ -1,47 +0,0 @@ -import styled from 'styled-components'; - -type WrapperProps = { - color?: 'client' | 'productOwner' | 'developer' | 'admin'; -}; - -export const Wrapper = styled.div` - background: ${({ theme }) => theme.colors.white.main}; - box-shadow: 0px 1px 10px rgba(0, 0, 0, 0.25); - display: flex; - flex-direction: row; - align-items: center; - padding: 15px 45px 15px 120px; - user-select: none; - position: sticky; - top: 0; - z-index: 99; - - svg { - display: flex; - align-items: center; - } - - .logo-icon { - fill: ${({ theme, color }) => - color ? theme.colors[color].main : theme.colors.client.main}; - } - - nav { - flex-grow: 1; - margin-left: 60px; - display: grid; - grid-template-columns: repeat(4, auto); - column-gap: 20px; - justify-content: flex-start; - } - - .user { - display: flex; - flex-direction: row; - align-items: center; - - p { - margin-left: 5px; - } - } -`; diff --git a/src/components/Search/index.stories.ts b/src/components/Search/index.stories.ts new file mode 100644 index 0000000..422b0ed --- /dev/null +++ b/src/components/Search/index.stories.ts @@ -0,0 +1,28 @@ +import type { Meta, StoryObj } from '@storybook/react'; + +import Search from '.'; + +const meta = { + title: 'Search', + component: Search, + parameters: { + layout: 'centered', + }, + tags: ['autodocs'], + argTypes: { + color: { options: ['client', 'productOwner', 'developer', 'admin', 'error'] }, + value: { control: 'text' }, + }, +} satisfies Meta; + +export default meta; + +type Story = StoryObj; + +export const Example: Story = { + args: { + color: 'productOwner', + value: '', + onChange: () => {}, + }, +}; diff --git a/src/components/Search/index.tsx b/src/components/Search/index.tsx index 19b3a0a..b1ca257 100644 --- a/src/components/Search/index.tsx +++ b/src/components/Search/index.tsx @@ -1,5 +1,6 @@ import { Wrapper } from './styles'; -import { Search as SearchIcon } from '../../assets'; + +import SearchIcon from '../../assets/icons/search.svg?react'; type SearchProps = { className?: string; diff --git a/src/components/SectionSelector/index.tsx b/src/components/SectionSelector/index.tsx deleted file mode 100644 index ba7c21e..0000000 --- a/src/components/SectionSelector/index.tsx +++ /dev/null @@ -1,34 +0,0 @@ -import { Wrapper } from './styles'; - -type SectionSelectorProps = { - icon: React.FunctionComponentElement>; - text: string; - color: 'client' | 'productOwner' | 'developer' | 'admin'; - selected?: boolean; - disabled?: boolean; - onClick?: () => void; -}; - -const SectionSelector = ({ - icon, - text, - color, - selected = false, - disabled = false, - onClick, -}: SectionSelectorProps) => { - return ( - - {icon && {icon}} - {text} - - ); -}; - -export default SectionSelector; diff --git a/src/components/SectionSelector/styles.ts b/src/components/SectionSelector/styles.ts deleted file mode 100644 index fb59760..0000000 --- a/src/components/SectionSelector/styles.ts +++ /dev/null @@ -1,119 +0,0 @@ -import styled, { css } from 'styled-components'; - -type WrapperProps = { - icon: React.FunctionComponentElement>; - color: 'client' | 'productOwner' | 'developer' | 'admin'; - selected: boolean; - disabled: boolean; -}; - -export const Wrapper = styled.div` - width: 100%; - height: auto; - max-height: 50px; - padding: 15px 20px; - border-radius: 10px; - user-select: none; - cursor: pointer; - - ${({ icon }) => { - if (icon) - return css` - display: flex; - flex-direction: row; - align-items: center; - `; - return ''; - }} - - .icon svg { - display: flex; - align-items: center; - } - - .icon.left { - margin-right: 0.5rem; - } - - ${({ color, theme, selected }) => { - switch (color) { - case 'client': - return css` - color: ${selected - ? theme.colors.client.main - : theme.colors.black.main}; - background: ${selected ? theme.colors.client.light : 'none'}; - - svg path { - stroke: ${selected - ? theme.colors.client.main - : theme.colors.black.main}; - } - `; - case 'productOwner': - return css` - color: ${selected - ? theme.colors.productOwner.main - : theme.colors.black.main}; - background: ${selected ? theme.colors.productOwner.light : 'none'}; - - svg path { - stroke: ${selected - ? theme.colors.productOwner.main - : theme.colors.black.main}; - } - `; - case 'developer': - return css` - color: ${selected - ? theme.colors.developer.main - : theme.colors.black.main}; - background: ${selected ? theme.colors.developer.light : 'none'}; - - svg path { - stroke: ${selected - ? theme.colors.developer.main - : theme.colors.black.main}; - } - `; - case 'admin': - return css` - color: ${selected - ? theme.colors.admin.main - : theme.colors.black.main}; - background: ${selected ? theme.colors.admin.light : 'none'}; - - svg path { - stroke: ${selected - ? theme.colors.admin.main - : theme.colors.black.main}; - } - `; - default: - return css` - color: ${selected - ? theme.colors.client.main - : theme.colors.black.main}; - background: ${selected ? theme.colors.client.light : 'none'}; - - svg path { - stroke: ${selected - ? theme.colors.client.main - : theme.colors.black.main}; - } - `; - } - }} - - ${({ disabled, theme }) => - disabled && - css` - cursor: default; - color: ${theme.colors.gray.main}; - background: none; - - svg path { - stroke: ${theme.colors.gray.main}; - } - `}; -`; diff --git a/src/components/Select/index.stories.ts b/src/components/Select/index.stories.ts new file mode 100644 index 0000000..0a84352 --- /dev/null +++ b/src/components/Select/index.stories.ts @@ -0,0 +1,33 @@ +import type { Meta, StoryObj } from '@storybook/react'; + +import Select from '.'; + +const meta = { + title: 'Select', + component: Select, + parameters: { + layout: 'centered', + }, + tags: ['autodocs'], + argTypes: { + color: { options: ['client', 'productOwner', 'developer', 'admin', 'error'] }, + value: { control: 'text' }, + }, +} satisfies Meta; + +export default meta; + +type Story = StoryObj; + +export const Example: Story = { + args: { + color: 'productOwner', + value: '', + options: [ + { value: '1', label: 'Option 1' }, + { value: '2', label: 'Option 2' }, + ], + name: 'select', + onChange: () => { }, + }, +}; diff --git a/src/components/Select/index.tsx b/src/components/Select/index.tsx index 9fbd966..bd0db45 100644 --- a/src/components/Select/index.tsx +++ b/src/components/Select/index.tsx @@ -1,5 +1,6 @@ import { Wrapper } from './styles'; -import { Text } from '..'; + +import Text from '../Text'; type SelectProps = { className?: string; @@ -15,9 +16,9 @@ type SelectProps = { | 'white'; error?: boolean; errorMessage?: string; - options: Array<{ value: any; label: string }>; + options: Array<{ value: string | number; label: string }>; value: string; - select?: any; + selected?: string | number; name: string; label?: string; fullWidth?: boolean; @@ -30,7 +31,7 @@ const Select = ({ label, name, value, - select = null, + selected = undefined, options, onChange, onBlur, @@ -55,7 +56,7 @@ const Select = ({