diff --git a/docs/docs/developer/frontend/style-guide.mdx b/docs/docs/developer/frontend/style-guide.mdx index 35c34a915..9ef805a82 100644 --- a/docs/docs/developer/frontend/style-guide.mdx +++ b/docs/docs/developer/frontend/style-guide.mdx @@ -100,3 +100,36 @@ type MyType = { }; ``` +## Styling + +### Use StyledComponents + +Components should be styled with StyledComponents. + +```tsx +// ❌ Bad +
Hello World
+``` + +```tsx +// ✅ Good +const StyledTitle = styled.div` + color: red; +`; +``` + +Styled components should be prefixed with "Styled" to differentiate them from "real" components. + +```tsx +// ❌ Bad +const Title = styled.div` + color: red; +`; +``` + +```tsx +// ✅ Good +const StyledTitle = styled.div` + color: red; +`; +``` diff --git a/front/.eslintrc.js b/front/.eslintrc.js index 154da81b2..c86cd6f4f 100644 --- a/front/.eslintrc.js +++ b/front/.eslintrc.js @@ -48,6 +48,7 @@ module.exports = { 'simple-import-sort/exports': 'error', 'twenty/sort-css-properties-alphabetically': 'error', 'twenty/no-hardcoded-colors': 'error', + 'twenty/styled-components-prefixed-with-styled': 'error', 'func-style':['error', 'declaration', { 'allowArrowFunctions': true }], "@typescript-eslint/no-unused-vars": "off", "no-unused-vars": "off", diff --git a/front/src/modules/activities/components/ActivityBodyEditor.tsx b/front/src/modules/activities/components/ActivityBodyEditor.tsx index c574c7be8..52da0cb32 100644 --- a/front/src/modules/activities/components/ActivityBodyEditor.tsx +++ b/front/src/modules/activities/components/ActivityBodyEditor.tsx @@ -10,7 +10,7 @@ import { Activity, useUpdateActivityMutation } from '~/generated/graphql'; import { ACTIVITY_UPDATE_FRAGMENT } from '../graphql/fragments/activityUpdateFragment'; -const BlockNoteStyledContainer = styled.div` +const StyledBlockNoteStyledContainer = styled.div` width: 100%; `; @@ -70,8 +70,8 @@ export function ActivityBodyEditor({ activity, onChange }: OwnProps) { }); return ( - + - + ); } diff --git a/front/src/modules/activities/table/components/__stories__/CommentChip.stories.tsx b/front/src/modules/activities/table/components/__stories__/CommentChip.stories.tsx index f0f21781c..c2b627cef 100644 --- a/front/src/modules/activities/table/components/__stories__/CommentChip.stories.tsx +++ b/front/src/modules/activities/table/components/__stories__/CommentChip.stories.tsx @@ -15,7 +15,7 @@ const meta: Meta = { export default meta; type Story = StoryObj; -const TestCellContainer = styled.div` +const StyledTestCellContainer = styled.div` align-items: center; background: ${({ theme }) => theme.background.primary}; display: flex; @@ -51,10 +51,10 @@ export const InCellDefault: Story = { args: { count: 12 }, decorators: [ (Story) => ( - + Fake short text - + ), ], }; @@ -63,12 +63,12 @@ export const InCellOverlappingBlur: Story = { ...InCellDefault, decorators: [ (Story) => ( - + Fake long text to demonstrate ellipsis - + ), ], }; diff --git a/front/src/modules/auth/sign-in-up/components/HorizontalSeparator.tsx b/front/src/modules/auth/sign-in-up/components/HorizontalSeparator.tsx index d86c656fb..182924a2c 100644 --- a/front/src/modules/auth/sign-in-up/components/HorizontalSeparator.tsx +++ b/front/src/modules/auth/sign-in-up/components/HorizontalSeparator.tsx @@ -1,6 +1,6 @@ import styled from '@emotion/styled'; -const Separator = styled.div` +const StyledSeparator = styled.div` background-color: ${({ theme }) => theme.border.color.medium}; height: 1px; margin-bottom: ${({ theme }) => theme.spacing(3)}; @@ -9,5 +9,5 @@ const Separator = styled.div` `; export function HorizontalSeparator(): JSX.Element { - return ; + return ; } diff --git a/front/src/modules/companies/__stories__/CompanyChip.stories.tsx b/front/src/modules/companies/__stories__/CompanyChip.stories.tsx index 331c7b894..12816ad3d 100644 --- a/front/src/modules/companies/__stories__/CompanyChip.stories.tsx +++ b/front/src/modules/companies/__stories__/CompanyChip.stories.tsx @@ -11,11 +11,11 @@ const meta: Meta = { component: CompanyChip, decorators: [ (Story) => ( - + - + ), ComponentDecorator, ], @@ -24,7 +24,7 @@ const meta: Meta = { export default meta; type Story = StoryObj; -const TestCellContainer = styled.div` +const StyledTestCellContainer = styled.div` align-items: center; background: ${({ theme }) => theme.background.primary}; display: flex; diff --git a/front/src/modules/people/components/__stories__/PeopleChip.stories.tsx b/front/src/modules/people/components/__stories__/PeopleChip.stories.tsx index f28bb9dc5..aca369732 100644 --- a/front/src/modules/people/components/__stories__/PeopleChip.stories.tsx +++ b/front/src/modules/people/components/__stories__/PeopleChip.stories.tsx @@ -6,7 +6,7 @@ import { ComponentDecorator } from '~/testing/decorators/ComponentDecorator'; import { PersonChip } from '../PersonChip'; -const TestCellContainer = styled.div` +const StyledTestCellContainer = styled.div` align-items: center; background: ${({ theme }) => theme.background.primary}; display: flex; @@ -22,11 +22,11 @@ const meta: Meta = { component: PersonChip, decorators: [ (Story) => ( - + - + ), ComponentDecorator, ], diff --git a/front/src/modules/spreadsheet-import/components/ContinueButton.tsx b/front/src/modules/spreadsheet-import/components/ContinueButton.tsx index 9e89cc0cf..1d8930356 100644 --- a/front/src/modules/spreadsheet-import/components/ContinueButton.tsx +++ b/front/src/modules/spreadsheet-import/components/ContinueButton.tsx @@ -4,7 +4,7 @@ import { MainButton } from '@/ui/button/components/MainButton'; import { Modal } from '@/ui/modal/components/Modal'; import { CircularProgressBar } from '@/ui/progress-bar/components/CircularProgressBar'; -const Footer = styled(Modal.Footer)` +const StyledFooter = styled(Modal.Footer)` height: 60px; justify-content: center; padding: 0px; @@ -12,7 +12,7 @@ const Footer = styled(Modal.Footer)` padding-right: ${({ theme }) => theme.spacing(30)}; `; -const Button = styled(MainButton)` +const StyledButton = styled(MainButton)` width: 200px; `; @@ -27,11 +27,11 @@ export const ContinueButton = ({ title, isLoading, }: ContinueButtonProps) => ( -
-
+ ); diff --git a/front/src/modules/spreadsheet-import/components/Heading.tsx b/front/src/modules/spreadsheet-import/components/Heading.tsx index bb79bd862..e523162c6 100644 --- a/front/src/modules/spreadsheet-import/components/Heading.tsx +++ b/front/src/modules/spreadsheet-import/components/Heading.tsx @@ -6,20 +6,20 @@ export type Props = React.ComponentProps<'div'> & { description?: string; }; -const Container = styled.div` +const StyledContainer = styled.div` align-items: center; display: flex; flex-direction: column; `; -const Title = styled.span` +const StyledTitle = styled.span` color: ${({ theme }) => theme.font.color.primary}; font-size: ${({ theme }) => theme.font.size.lg}; font-weight: ${({ theme }) => theme.font.weight.semiBold}; text-align: center; `; -const Description = styled.span` +const StyledDescription = styled.span` color: ${({ theme }) => theme.font.color.primary}; font-size: ${({ theme }) => theme.font.size.sm}; font-weight: ${({ theme }) => theme.font.weight.regular}; @@ -29,9 +29,9 @@ const Description = styled.span` export function Heading({ title, description, ...props }: Props) { return ( - - {title} - {description && {description}} - + + {title} + {description && {description}} + ); } diff --git a/front/src/modules/spreadsheet-import/components/MatchColumnSelect.tsx b/front/src/modules/spreadsheet-import/components/MatchColumnSelect.tsx index 21ca3284c..704bcf72c 100644 --- a/front/src/modules/spreadsheet-import/components/MatchColumnSelect.tsx +++ b/front/src/modules/spreadsheet-import/components/MatchColumnSelect.tsx @@ -25,7 +25,7 @@ import { AppTooltip } from '@/ui/tooltip/AppTooltip'; import { useListenClickOutside } from '@/ui/utilities/pointer-event/hooks/useListenClickOutside'; import { useUpdateEffect } from '~/hooks/useUpdateEffect'; -const DropdownItem = styled.div` +const StyledDropdownItem = styled.div` align-items: center; background-color: ${({ theme }) => theme.background.tertiary}; border-radius: ${({ theme }) => theme.border.radius.sm}; @@ -42,7 +42,7 @@ const DropdownItem = styled.div` } `; -const DropdownLabel = styled.span<{ isPlaceholder: boolean }>` +const StyledDropdownLabel = styled.span<{ isPlaceholder: boolean }>` color: ${({ theme, isPlaceholder }) => isPlaceholder ? theme.font.color.tertiary : theme.font.color.primary}; display: flex; @@ -53,7 +53,7 @@ const DropdownLabel = styled.span<{ isPlaceholder: boolean }>` padding-right: ${({ theme }) => theme.spacing(1)}; `; -const FloatingDropdown = styled.div` +const StyledFloatingDropdown = styled.div` z-index: ${({ theme }) => theme.lastLayerZIndex}; `; @@ -147,7 +147,7 @@ export const MatchColumnSelect = ({ return ( <> - { // eslint-disable-next-line @typescript-eslint/ban-ts-comment @@ -158,14 +158,14 @@ export const MatchColumnSelect = ({ onClick={handleDropdownItemClick} > {renderIcon(value?.icon)} - + {value?.label ?? placeholder} - + - + {isOpen && createPortal( - + - , + , document.body, )} diff --git a/front/src/modules/spreadsheet-import/components/ModalCloseButton.tsx b/front/src/modules/spreadsheet-import/components/ModalCloseButton.tsx index aceadf765..8462b16dc 100644 --- a/front/src/modules/spreadsheet-import/components/ModalCloseButton.tsx +++ b/front/src/modules/spreadsheet-import/components/ModalCloseButton.tsx @@ -6,7 +6,7 @@ import { IconButton } from '@/ui/button/components/IconButton'; import { useDialog } from '@/ui/dialog/hooks/useDialog'; import { IconX } from '@/ui/icon/index'; -const CloseButtonContainer = styled.div` +const StyledCloseButtonContainer = styled.div` align-items: center; aspect-ratio: 1; display: flex; @@ -39,12 +39,12 @@ export const ModalCloseButton = ({ onClose }: ModalCloseButtonProps) => { return ( <> - + } onClick={handleClose} /> - + ); }; diff --git a/front/src/modules/spreadsheet-import/steps/components/MatchColumnsStep/components/ColumnGrid.tsx b/front/src/modules/spreadsheet-import/steps/components/MatchColumnsStep/components/ColumnGrid.tsx index 1b8f19799..2c1ee3f82 100644 --- a/front/src/modules/spreadsheet-import/steps/components/MatchColumnsStep/components/ColumnGrid.tsx +++ b/front/src/modules/spreadsheet-import/steps/components/MatchColumnsStep/components/ColumnGrid.tsx @@ -3,7 +3,7 @@ import styled from '@emotion/styled'; import type { Columns } from '../MatchColumnsStep'; -const GridContainer = styled.div` +const StyledGridContainer = styled.div` align-items: center; display: flex; flex-direction: column; @@ -12,7 +12,7 @@ const GridContainer = styled.div` width: 100%; `; -const Grid = styled.div` +const StyledGrid = styled.div` border: 1px solid ${({ theme }) => theme.border.color.medium}; border-radius: ${({ theme }) => theme.border.radius.md}; box-sizing: border-box; @@ -26,7 +26,7 @@ type HeightProps = { height?: `${number}px`; }; -const GridRow = styled.div` +const StyledGridRow = styled.div` box-sizing: border-box; display: flex; flex-direction: row; @@ -37,7 +37,7 @@ type PositionProps = { position: 'left' | 'right'; }; -const GridCell = styled.div` +const StyledGridCell = styled.div` align-items: center; box-sizing: border-box; display: flex; @@ -59,7 +59,7 @@ const GridCell = styled.div` }}; `; -const GridHeader = styled.div` +const StyledGridHeader = styled.div` align-items: center; background-color: ${({ theme }) => theme.background.tertiary}; box-sizing: border-box; @@ -98,29 +98,31 @@ export const ColumnGrid = ({ }: ColumnGridProps) => { return ( <> - - - - Imported data - Twenty fields - + + + + Imported data + Twenty fields + {columns.map((column, index) => { const userColumn = renderUserColumn(columns, index); const templateColumn = renderTemplateColumn(columns, index); if (React.isValidElement(userColumn)) { return ( - - {userColumn} - {templateColumn} - + + {userColumn} + + {templateColumn} + + ); } return null; })} - - + + ); }; diff --git a/front/src/modules/spreadsheet-import/steps/components/MatchColumnsStep/components/SubMatchingSelect.tsx b/front/src/modules/spreadsheet-import/steps/components/MatchColumnsStep/components/SubMatchingSelect.tsx index 01f7a848e..90c634679 100644 --- a/front/src/modules/spreadsheet-import/steps/components/MatchColumnsStep/components/SubMatchingSelect.tsx +++ b/front/src/modules/spreadsheet-import/steps/components/MatchColumnsStep/components/SubMatchingSelect.tsx @@ -11,12 +11,12 @@ import type { MatchedSelectOptionsColumn, } from '../MatchColumnsStep'; -const Container = styled.div` +const StyledContainer = styled.div` padding-bottom: ${({ theme }) => theme.spacing(1)}; padding-left: ${({ theme }) => theme.spacing(2)}; `; -const SelectLabel = styled.span` +const StyledSelectLabel = styled.span` color: ${({ theme }) => theme.font.color.primary}; font-size: ${({ theme }) => theme.font.size.sm}; font-weight: ${({ theme }) => theme.font.weight.medium}; @@ -40,8 +40,8 @@ export const SubMatchingSelect = ({ const value = options.find((opt) => opt.value === option.value); return ( - - {option.entry} + + {option.entry} ({ options={options} name={option.entry} /> - + ); }; diff --git a/front/src/modules/spreadsheet-import/steps/components/MatchColumnsStep/components/TemplateColumn.tsx b/front/src/modules/spreadsheet-import/steps/components/MatchColumnsStep/components/TemplateColumn.tsx index 760f4a47f..20181e469 100644 --- a/front/src/modules/spreadsheet-import/steps/components/MatchColumnsStep/components/TemplateColumn.tsx +++ b/front/src/modules/spreadsheet-import/steps/components/MatchColumnsStep/components/TemplateColumn.tsx @@ -18,14 +18,14 @@ import { ColumnType } from '../MatchColumnsStep'; import { SubMatchingSelect } from './SubMatchingSelect'; -const Container = styled.div` +const StyledContainer = styled.div` display: flex; flex-direction: column; min-height: 10px; width: 100%; `; -const AccordionButton = styled(ChakraAccordionButton)` +const StyledAccordionButton = styled(ChakraAccordionButton)` align-items: center; background-color: ${({ theme }) => theme.accent.secondary}; border: none; @@ -46,12 +46,12 @@ const AccordionButton = styled(ChakraAccordionButton)` } `; -const AccordionContainer = styled.div` +const StyledAccordionContainer = styled.div` display: flex; width: 100%; `; -const AccordionLabel = styled.span` +const StyledAccordionLabel = styled.span` color: ${({ theme }) => theme.font.color.primary}; display: flex; flex: 1; @@ -123,7 +123,7 @@ export const TemplateColumn = ({ ); return ( - + ({ name={column.header} /> {isSelect && ( - + - - + + {getAccordionTitle(fields, column)} - + - + {column.matchedOptions.map((option) => ( ({ - + )} - + ); }; diff --git a/front/src/modules/spreadsheet-import/steps/components/MatchColumnsStep/components/UserTableColumn.tsx b/front/src/modules/spreadsheet-import/steps/components/MatchColumnsStep/components/UserTableColumn.tsx index 351e3f0b8..e0d31c899 100644 --- a/front/src/modules/spreadsheet-import/steps/components/MatchColumnsStep/components/UserTableColumn.tsx +++ b/front/src/modules/spreadsheet-import/steps/components/MatchColumnsStep/components/UserTableColumn.tsx @@ -5,13 +5,13 @@ import { assertNotNull } from '~/utils/assert'; import type { Column } from '../MatchColumnsStep'; -const Container = styled.div` +const StyledContainer = styled.div` display: flex; flex-direction: column; width: 100%; `; -const Value = styled.span` +const StyledValue = styled.span` color: ${({ theme }) => theme.font.color.primary}; font-size: ${({ theme }) => theme.font.size.sm}; font-weight: ${({ theme }) => theme.font.weight.medium}; @@ -20,7 +20,7 @@ const Value = styled.span` white-space: nowrap; `; -const Example = styled.span` +const StyledExample = styled.span` color: ${({ theme }) => theme.font.color.tertiary}; font-size: ${({ theme }) => theme.font.size.sm}; font-weight: ${({ theme }) => theme.font.weight.medium}; @@ -42,9 +42,9 @@ export const UserTableColumn = ({ const entry = entries.find(assertNotNull); return ( - - {header} - {entry && {`ex: ${entry}`}} - + + {header} + {entry && {`ex: ${entry}`}} + ); }; diff --git a/front/src/modules/spreadsheet-import/steps/components/SelectHeaderStep/SelectHeaderStep.tsx b/front/src/modules/spreadsheet-import/steps/components/SelectHeaderStep/SelectHeaderStep.tsx index 784d25af4..e2f4839f7 100644 --- a/front/src/modules/spreadsheet-import/steps/components/SelectHeaderStep/SelectHeaderStep.tsx +++ b/front/src/modules/spreadsheet-import/steps/components/SelectHeaderStep/SelectHeaderStep.tsx @@ -12,7 +12,7 @@ const StyledHeading = styled(Heading)` margin-bottom: ${({ theme }) => theme.spacing(8)}; `; -const TableContainer = styled.div` +const StyledTableContainer = styled.div` display: flex; flex-grow: 1; height: 0px; @@ -42,13 +42,13 @@ export const SelectHeaderStep = ({ data, onContinue }: SelectHeaderProps) => { <> - + - + theme.spacing(8)}; `; -const RadioContainer = styled.div` +const StyledRadioContainer = styled.div` display: flex; flex-direction: column; flex-grow: 1; @@ -46,16 +46,16 @@ export const SelectSheetStep = ({ return ( <> - + - + setValue(value)} value={value}> {sheetNames.map((sheetName) => ( ))} - - + + handleOnContinue(value)} diff --git a/front/src/modules/spreadsheet-import/steps/components/Steps.tsx b/front/src/modules/spreadsheet-import/steps/components/Steps.tsx index 6e53f1fb4..8ca164109 100644 --- a/front/src/modules/spreadsheet-import/steps/components/Steps.tsx +++ b/front/src/modules/spreadsheet-import/steps/components/Steps.tsx @@ -8,7 +8,7 @@ import { useStepBar } from '@/ui/step-bar/hooks/useStepBar'; import { UploadFlow } from './UploadFlow'; -const Header = styled(Modal.Header)` +const StyledHeader = styled(Modal.Header)` background-color: ${({ theme }) => theme.background.secondary}; border-bottom: 1px solid ${({ theme }) => theme.border.color.medium}; height: 60px; @@ -36,13 +36,13 @@ export const Steps = () => { return ( <> -
+ {steps.map((key) => ( ))} -
+ ); diff --git a/front/src/modules/spreadsheet-import/steps/components/UploadFlow.tsx b/front/src/modules/spreadsheet-import/steps/components/UploadFlow.tsx index ce2db5bb4..6f4d7ad81 100644 --- a/front/src/modules/spreadsheet-import/steps/components/UploadFlow.tsx +++ b/front/src/modules/spreadsheet-import/steps/components/UploadFlow.tsx @@ -17,7 +17,7 @@ import { SelectSheetStep } from './SelectSheetStep/SelectSheetStep'; import { UploadStep } from './UploadStep/UploadStep'; import { ValidationStep } from './ValidationStep/ValidationStep'; -const ProgressBarContainer = styled(Modal.Content)` +const StyledProgressBarContainer = styled(Modal.Content)` align-items: center; display: flex; justify-content: center; @@ -209,13 +209,13 @@ export const UploadFlow = ({ nextStep }: Props) => { case StepType.loading: default: return ( - + - + ); } }; diff --git a/front/src/modules/spreadsheet-import/steps/components/UploadStep/UploadStep.tsx b/front/src/modules/spreadsheet-import/steps/components/UploadStep/UploadStep.tsx index c0fafd371..b0f15a6f1 100644 --- a/front/src/modules/spreadsheet-import/steps/components/UploadStep/UploadStep.tsx +++ b/front/src/modules/spreadsheet-import/steps/components/UploadStep/UploadStep.tsx @@ -6,7 +6,7 @@ import { Modal } from '@/ui/modal/components/Modal'; import { DropZone } from './components/DropZone'; -const Content = styled(Modal.Content)` +const StyledContent = styled(Modal.Content)` padding: ${({ theme }) => theme.spacing(6)}; `; @@ -27,8 +27,8 @@ export const UploadStep = ({ onContinue }: UploadProps) => { ); return ( - + - + ); }; diff --git a/front/src/modules/spreadsheet-import/steps/components/UploadStep/components/DropZone.tsx b/front/src/modules/spreadsheet-import/steps/components/UploadStep/components/DropZone.tsx index e35aacf0d..67c376580 100644 --- a/front/src/modules/spreadsheet-import/steps/components/UploadStep/components/DropZone.tsx +++ b/front/src/modules/spreadsheet-import/steps/components/UploadStep/components/DropZone.tsx @@ -8,7 +8,7 @@ import { readFileAsync } from '@/spreadsheet-import/utils/readFilesAsync'; import { MainButton } from '@/ui/button/components/MainButton'; import { useSnackBar } from '@/ui/snack-bar/hooks/useSnackBar'; -const Container = styled.div` +const StyledContainer = styled.div` align-items: center; background: ${({ theme }) => ` repeating-linear-gradient( @@ -55,7 +55,7 @@ const Container = styled.div` position: relative; `; -const Overlay = styled.div` +const StyledOverlay = styled.div` background: ${({ theme }) => theme.background.transparent.medium}; border-radius: ${({ theme }) => theme.border.radius.sm}; bottom: 0px; @@ -65,14 +65,14 @@ const Overlay = styled.div` top: 0px; `; -const Text = styled.span` +const StyledText = styled.span` color: ${({ theme }) => theme.font.color.primary}; font-size: ${({ theme }) => theme.font.size.sm}; font-weight: ${({ theme }) => theme.font.weight.medium}; text-align: center; `; -const Button = styled(MainButton)` +const StyledButton = styled(MainButton)` margin-top: ${({ theme }) => theme.spacing(2)}; width: 200px; `; @@ -125,19 +125,19 @@ export const DropZone = ({ onContinue, isLoading }: DropZoneProps) => { }); return ( - - {isDragActive && } + + {isDragActive && } {isDragActive ? ( - Drop file here... + Drop file here... ) : loading || isLoading ? ( - Processing... + Processing... ) : ( <> - Upload .xlsx, .xls or .csv file -