Refactor settings > data model section (#2031)
This commit is contained in:
@ -0,0 +1,3 @@
|
||||
<svg width="34" height="16" viewBox="0 0 34 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M1 7C0.447715 7 0 7.44772 0 8C0 8.55228 0.447715 9 1 9V7ZM33.7071 8.70711C34.0976 8.31658 34.0976 7.68342 33.7071 7.29289L27.3431 0.928932C26.9526 0.538408 26.3195 0.538408 25.9289 0.928932C25.5384 1.31946 25.5384 1.95262 25.9289 2.34315L31.5858 8L25.9289 13.6569C25.5384 14.0474 25.5384 14.6805 25.9289 15.0711C26.3195 15.4616 26.9526 15.4616 27.3431 15.0711L33.7071 8.70711ZM1 9H33V7H1V9Z" fill="#EBEBEB"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 520 B |
126
front/src/modules/settings/data-model/constants/mockObjects.ts
Normal file
126
front/src/modules/settings/data-model/constants/mockObjects.ts
Normal file
@ -0,0 +1,126 @@
|
||||
import {
|
||||
IconBrandLinkedin,
|
||||
IconBrandTwitter,
|
||||
IconBuildingSkyscraper,
|
||||
IconCurrencyDollar,
|
||||
IconFreeRights,
|
||||
IconGraph,
|
||||
IconHeadphones,
|
||||
IconLink,
|
||||
IconLuggage,
|
||||
IconPlane,
|
||||
IconTarget,
|
||||
IconUser,
|
||||
IconUserCircle,
|
||||
IconUsers,
|
||||
} from '@/ui/display/icon';
|
||||
|
||||
import { ObjectFieldItem } from '../types/ObjectFieldItem';
|
||||
|
||||
export const activeObjectItems = [
|
||||
{
|
||||
name: 'Companies',
|
||||
singularName: 'company',
|
||||
Icon: IconBuildingSkyscraper,
|
||||
type: 'standard',
|
||||
fields: 23,
|
||||
instances: 165,
|
||||
},
|
||||
{
|
||||
name: 'People',
|
||||
singularName: 'person',
|
||||
Icon: IconUser,
|
||||
type: 'standard',
|
||||
fields: 16,
|
||||
instances: 462,
|
||||
},
|
||||
];
|
||||
|
||||
export const disabledObjectItems = [
|
||||
{
|
||||
name: 'Travels',
|
||||
Icon: IconLuggage,
|
||||
type: 'custom',
|
||||
fields: 23,
|
||||
instances: 165,
|
||||
},
|
||||
{
|
||||
name: 'Flights',
|
||||
Icon: IconPlane,
|
||||
type: 'custom',
|
||||
fields: 23,
|
||||
instances: 165,
|
||||
},
|
||||
];
|
||||
|
||||
export const activeFieldItems: ObjectFieldItem[] = [
|
||||
{
|
||||
name: 'People',
|
||||
Icon: IconUser,
|
||||
type: 'standard',
|
||||
dataType: 'relation',
|
||||
},
|
||||
{
|
||||
name: 'URL',
|
||||
Icon: IconLink,
|
||||
type: 'standard',
|
||||
dataType: 'text',
|
||||
},
|
||||
{
|
||||
name: 'Linkedin',
|
||||
Icon: IconBrandLinkedin,
|
||||
type: 'standard',
|
||||
dataType: 'social',
|
||||
},
|
||||
{
|
||||
name: 'Account Owner',
|
||||
Icon: IconUserCircle,
|
||||
type: 'standard',
|
||||
dataType: 'teammate',
|
||||
},
|
||||
{
|
||||
name: 'Employees',
|
||||
Icon: IconUsers,
|
||||
type: 'custom',
|
||||
dataType: 'number',
|
||||
},
|
||||
];
|
||||
|
||||
export const disabledFieldItems: ObjectFieldItem[] = [
|
||||
{
|
||||
name: 'ICP',
|
||||
Icon: IconTarget,
|
||||
type: 'standard',
|
||||
dataType: 'boolean',
|
||||
},
|
||||
{
|
||||
name: 'Twitter',
|
||||
Icon: IconBrandTwitter,
|
||||
type: 'standard',
|
||||
dataType: 'social',
|
||||
},
|
||||
{
|
||||
name: 'Annual revenue',
|
||||
Icon: IconCurrencyDollar,
|
||||
type: 'standard',
|
||||
dataType: 'number',
|
||||
},
|
||||
{
|
||||
name: 'Is public',
|
||||
Icon: IconGraph,
|
||||
type: 'standard',
|
||||
dataType: 'boolean',
|
||||
},
|
||||
{
|
||||
name: 'Free tier?',
|
||||
Icon: IconFreeRights,
|
||||
type: 'custom',
|
||||
dataType: 'boolean',
|
||||
},
|
||||
{
|
||||
name: 'Priority support',
|
||||
Icon: IconHeadphones,
|
||||
type: 'custom',
|
||||
dataType: 'boolean',
|
||||
},
|
||||
];
|
||||
@ -0,0 +1 @@
|
||||
export const objectSettingsWidth = '512px';
|
||||
@ -0,0 +1,66 @@
|
||||
import { useState } from 'react';
|
||||
import { useTheme } from '@emotion/react';
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
import { IconBox, IconDatabase, IconFileCheck } from '@/ui/display/icon';
|
||||
|
||||
import { SettingsObjectTypeCard } from './SettingsObjectTypeCard';
|
||||
|
||||
const StyledContainer = styled.div`
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
gap: ${({ theme }) => theme.spacing(2)};
|
||||
width: 100%;
|
||||
`;
|
||||
|
||||
export const SettingsNewObjectType = () => {
|
||||
const theme = useTheme();
|
||||
const [selectedType, setSelectedType] = useState<string | null>(null);
|
||||
const handleCardClick = (selectedType: string) => {
|
||||
setSelectedType(selectedType);
|
||||
};
|
||||
return (
|
||||
<StyledContainer>
|
||||
<SettingsObjectTypeCard
|
||||
title="Standard"
|
||||
color="blue"
|
||||
selected={selectedType === 'Standard'}
|
||||
prefixIcon={
|
||||
<IconFileCheck
|
||||
size={theme.icon.size.lg}
|
||||
stroke={theme.icon.stroke.sm}
|
||||
color={theme.font.color.tertiary}
|
||||
/>
|
||||
}
|
||||
onClick={() => handleCardClick('Standard')}
|
||||
></SettingsObjectTypeCard>
|
||||
<SettingsObjectTypeCard
|
||||
title="Custom"
|
||||
color="orange"
|
||||
selected={selectedType === 'Custom'}
|
||||
prefixIcon={
|
||||
<IconBox
|
||||
size={theme.icon.size.lg}
|
||||
stroke={theme.icon.stroke.sm}
|
||||
color={theme.font.color.tertiary}
|
||||
/>
|
||||
}
|
||||
onClick={() => handleCardClick('Custom')}
|
||||
></SettingsObjectTypeCard>
|
||||
<SettingsObjectTypeCard
|
||||
title="Remote"
|
||||
soon
|
||||
disabled
|
||||
color="green"
|
||||
selected={selectedType === 'Remote'}
|
||||
prefixIcon={
|
||||
<IconDatabase
|
||||
size={theme.icon.size.lg}
|
||||
stroke={theme.icon.stroke.sm}
|
||||
color={theme.font.color.tertiary}
|
||||
/>
|
||||
}
|
||||
></SettingsObjectTypeCard>
|
||||
</StyledContainer>
|
||||
);
|
||||
};
|
||||
@ -0,0 +1,79 @@
|
||||
import { useTheme } from '@emotion/react';
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
import { IconCheck } from '@/ui/display/icon';
|
||||
import { SoonPill } from '@/ui/display/pill/components/SoonPill';
|
||||
import { Tag } from '@/ui/display/tag/components/Tag';
|
||||
import { ThemeColor } from '@/ui/theme/constants/colors';
|
||||
|
||||
const StyledObjectTypeCard = styled.div<SettingsObjectTypeCardProps>`
|
||||
${({ theme, disabled, selected }) => `
|
||||
background: ${theme.background.transparent.primary};
|
||||
cursor: ${disabled ? 'not-allowed' : 'pointer'};
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
font-family: ${theme.font.family};
|
||||
font-weight: 500;
|
||||
border-style: solid;
|
||||
border-width: '1px';
|
||||
padding: ${theme.spacing(3)};
|
||||
border-radius: ${theme.border.radius.sm};
|
||||
gap: ${theme.spacing(2)};
|
||||
border-color: ${
|
||||
selected ? theme.border.color.inverted : theme.border.color.medium
|
||||
};
|
||||
color: ${theme.font.color.primary};
|
||||
align-items: center;
|
||||
width: 140px;
|
||||
`}
|
||||
`;
|
||||
|
||||
const StyledTag = styled(Tag)`
|
||||
box-sizing: border-box;
|
||||
height: ${({ theme }) => theme.spacing(5)};
|
||||
`;
|
||||
|
||||
const StyledIconCheck = styled(IconCheck)`
|
||||
margin-left: auto;
|
||||
`;
|
||||
|
||||
type SettingsObjectTypeCardProps = {
|
||||
prefixIcon?: React.ReactNode;
|
||||
title: string;
|
||||
soon?: boolean;
|
||||
disabled?: boolean;
|
||||
color: ThemeColor;
|
||||
selected: boolean;
|
||||
onClick?: () => void;
|
||||
};
|
||||
|
||||
export const SettingsObjectTypeCard = ({
|
||||
prefixIcon,
|
||||
title,
|
||||
soon = false,
|
||||
selected,
|
||||
disabled = false,
|
||||
color,
|
||||
onClick,
|
||||
}: SettingsObjectTypeCardProps) => {
|
||||
const theme = useTheme();
|
||||
return (
|
||||
<div onClick={() => onclick}>
|
||||
<StyledObjectTypeCard
|
||||
title={title}
|
||||
soon={soon}
|
||||
disabled={disabled}
|
||||
color={color}
|
||||
selected={selected}
|
||||
onClick={onClick}
|
||||
>
|
||||
{prefixIcon}
|
||||
<StyledTag color={color} text={title} />
|
||||
{soon && <SoonPill />}
|
||||
{!disabled && selected && <StyledIconCheck size={theme.icon.size.md} />}
|
||||
</StyledObjectTypeCard>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export {};
|
||||
@ -0,0 +1,79 @@
|
||||
import { useTheme } from '@emotion/react';
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
import { IconDotsVertical } from '@/ui/display/icon';
|
||||
import { IconComponent } from '@/ui/display/icon/types/IconComponent';
|
||||
import { Tag } from '@/ui/display/tag/components/Tag';
|
||||
import { H2Title } from '@/ui/display/typography/components/H2Title';
|
||||
import { Section } from '@/ui/layout/section/components/Section';
|
||||
import { TableCell } from '@/ui/layout/table/components/TableCell';
|
||||
import { TableRow } from '@/ui/layout/table/components/TableRow';
|
||||
|
||||
type SettingsAboutSectionProps = {
|
||||
Icon: IconComponent;
|
||||
name: string;
|
||||
type: string;
|
||||
};
|
||||
|
||||
const StyledIconTableCell = styled(TableCell)`
|
||||
justify-content: center;
|
||||
padding-right: ${({ theme }) => theme.spacing(1)};
|
||||
`;
|
||||
|
||||
const StyledTableRow = styled(TableRow)`
|
||||
background-color: ${({ theme }) => theme.background.secondary};
|
||||
border: ${({ theme }) => `1px solid ${theme.border.color.medium}`};
|
||||
`;
|
||||
|
||||
const StyledNameTableCell = styled(TableCell)`
|
||||
color: ${({ theme }) => theme.font.color.primary};
|
||||
gap: ${({ theme }) => theme.spacing(2)};
|
||||
`;
|
||||
|
||||
const StyledTag = styled(Tag)`
|
||||
box-sizing: border-box;
|
||||
height: ${({ theme }) => theme.spacing(4)};
|
||||
`;
|
||||
|
||||
const StyledIconDotsVertical = styled(IconDotsVertical)`
|
||||
color: ${({ theme }) => theme.font.color.tertiary};
|
||||
`;
|
||||
|
||||
const StyledFlexContainer = styled.div`
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
`;
|
||||
|
||||
export const SettingsAboutSection = ({
|
||||
Icon,
|
||||
name,
|
||||
type,
|
||||
}: SettingsAboutSectionProps) => {
|
||||
const theme = useTheme();
|
||||
return (
|
||||
<Section>
|
||||
<H2Title title="About" description={`Manage you object`} />
|
||||
<StyledTableRow>
|
||||
<StyledNameTableCell>
|
||||
<Icon size={theme.icon.size.md} />
|
||||
{name}
|
||||
</StyledNameTableCell>
|
||||
<StyledFlexContainer>
|
||||
<TableCell>
|
||||
{type === 'standard' ? (
|
||||
<StyledTag color="blue" text="Standard" />
|
||||
) : (
|
||||
<StyledTag color="orange" text="Custom" />
|
||||
)}
|
||||
</TableCell>
|
||||
<StyledIconTableCell>
|
||||
<StyledIconDotsVertical
|
||||
size={theme.icon.size.md}
|
||||
stroke={theme.icon.stroke.sm}
|
||||
/>
|
||||
</StyledIconTableCell>
|
||||
</StyledFlexContainer>
|
||||
</StyledTableRow>
|
||||
</Section>
|
||||
);
|
||||
};
|
||||
@ -0,0 +1,63 @@
|
||||
import { css, useTheme } from '@emotion/react';
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
import {
|
||||
IconCheck,
|
||||
IconLink,
|
||||
IconNumbers,
|
||||
IconPlug,
|
||||
IconSocial,
|
||||
IconUserCircle,
|
||||
} from '@/ui/display/icon';
|
||||
import { IconComponent } from '@/ui/display/icon/types/IconComponent';
|
||||
|
||||
import { ObjectFieldItem } from '../../types/ObjectFieldItem';
|
||||
|
||||
const StyledDataType = styled.div<{ value: ObjectFieldItem['dataType'] }>`
|
||||
align-items: center;
|
||||
border: 1px solid transparent;
|
||||
border-radius: ${({ theme }) => theme.border.radius.sm};
|
||||
display: flex;
|
||||
font-size: ${({ theme }) => theme.font.size.sm};
|
||||
gap: ${({ theme }) => theme.spacing(1)};
|
||||
height: 20px;
|
||||
padding: 0 ${({ theme }) => theme.spacing(2)};
|
||||
|
||||
${({ theme, value }) =>
|
||||
value === 'relation'
|
||||
? css`
|
||||
border-color: ${theme.color.purple20};
|
||||
color: ${theme.color.purple};
|
||||
`
|
||||
: ''}
|
||||
`;
|
||||
|
||||
const dataTypes: Record<
|
||||
ObjectFieldItem['dataType'],
|
||||
{ label: string; Icon: IconComponent }
|
||||
> = {
|
||||
boolean: { label: 'True/False', Icon: IconCheck },
|
||||
number: { label: 'Number', Icon: IconNumbers },
|
||||
relation: { label: 'Relation', Icon: IconPlug },
|
||||
social: { label: 'Social', Icon: IconSocial },
|
||||
teammate: { label: 'Teammate', Icon: IconUserCircle },
|
||||
text: { label: 'Text', Icon: IconLink },
|
||||
};
|
||||
|
||||
type SettingsObjectFieldDataTypeProps = {
|
||||
value: ObjectFieldItem['dataType'];
|
||||
};
|
||||
|
||||
export const SettingsObjectFieldDataType = ({
|
||||
value,
|
||||
}: SettingsObjectFieldDataTypeProps) => {
|
||||
const theme = useTheme();
|
||||
const { label, Icon } = dataTypes[value];
|
||||
|
||||
return (
|
||||
<StyledDataType value={value}>
|
||||
<Icon size={theme.icon.size.sm} />
|
||||
{label}
|
||||
</StyledDataType>
|
||||
);
|
||||
};
|
||||
@ -0,0 +1,57 @@
|
||||
import { useTheme } from '@emotion/react';
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
import { IconDotsVertical } from '@/ui/display/icon';
|
||||
import { TableCell } from '@/ui/layout/table/components/TableCell';
|
||||
import { TableRow } from '@/ui/layout/table/components/TableRow';
|
||||
|
||||
import { ObjectFieldItem } from '../../types/ObjectFieldItem';
|
||||
|
||||
import { SettingsObjectFieldDataType } from './SettingsObjectFieldDataType';
|
||||
|
||||
export const StyledObjectFieldTableRow = styled(TableRow)`
|
||||
grid-template-columns: 180px 148px 148px 36px;
|
||||
`;
|
||||
|
||||
const StyledNameTableCell = styled(TableCell)`
|
||||
color: ${({ theme }) => theme.font.color.primary};
|
||||
gap: ${({ theme }) => theme.spacing(2)};
|
||||
`;
|
||||
|
||||
const StyledIconTableCell = styled(TableCell)`
|
||||
justify-content: center;
|
||||
padding-right: ${({ theme }) => theme.spacing(1)};
|
||||
`;
|
||||
|
||||
const StyledIconDotsVertical = styled(IconDotsVertical)`
|
||||
color: ${({ theme }) => theme.font.color.tertiary};
|
||||
`;
|
||||
|
||||
export const SettingsObjectFieldItemTableRow = ({
|
||||
fieldItem,
|
||||
}: {
|
||||
fieldItem: ObjectFieldItem;
|
||||
}) => {
|
||||
const theme = useTheme();
|
||||
|
||||
return (
|
||||
<StyledObjectFieldTableRow>
|
||||
<StyledNameTableCell>
|
||||
<fieldItem.Icon size={theme.icon.size.md} />
|
||||
{fieldItem.name}
|
||||
</StyledNameTableCell>
|
||||
<TableCell>
|
||||
{fieldItem.type === 'standard' ? 'Standard' : 'Custom'}
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<SettingsObjectFieldDataType value={fieldItem.dataType} />
|
||||
</TableCell>
|
||||
<StyledIconTableCell>
|
||||
<StyledIconDotsVertical
|
||||
size={theme.icon.size.md}
|
||||
stroke={theme.icon.stroke.sm}
|
||||
/>
|
||||
</StyledIconTableCell>
|
||||
</StyledObjectFieldTableRow>
|
||||
);
|
||||
};
|
||||
@ -0,0 +1,55 @@
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
import { IconComponent } from '@/ui/display/icon/types/IconComponent';
|
||||
import { H2Title } from '@/ui/display/typography/components/H2Title';
|
||||
import { IconPicker } from '@/ui/input/components/IconPicker';
|
||||
|
||||
import ArrowRight from '../assets/ArrowRight.svg';
|
||||
|
||||
import { SettingsObjectIconWithLabel } from './SettingsObjectIconWithLabel';
|
||||
|
||||
const StyledContainer = styled.div`
|
||||
align-items: center;
|
||||
display: flex;
|
||||
gap: ${({ theme }) => theme.spacing(4)};
|
||||
`;
|
||||
|
||||
const StyledArrowContainer = styled.div`
|
||||
align-items: center;
|
||||
display: flex;
|
||||
height: 32px;
|
||||
justify-content: center;
|
||||
`;
|
||||
|
||||
type SettingsObjectIconSectionProps = {
|
||||
Icon: IconComponent;
|
||||
iconKey: string;
|
||||
setIconPicker?: (icon: { Icon: IconComponent; iconKey: string }) => void;
|
||||
};
|
||||
|
||||
export const SettingsObjectIconSection = ({
|
||||
Icon,
|
||||
iconKey,
|
||||
setIconPicker,
|
||||
}: SettingsObjectIconSectionProps) => {
|
||||
return (
|
||||
<section>
|
||||
<H2Title
|
||||
title="Icon"
|
||||
description="The icon that will be displayed in the sidebar."
|
||||
/>
|
||||
<StyledContainer>
|
||||
<IconPicker
|
||||
selectedIconKey={iconKey}
|
||||
onChange={(icon) => {
|
||||
setIconPicker?.({ Icon: icon.Icon, iconKey: icon.iconKey });
|
||||
}}
|
||||
/>
|
||||
<StyledArrowContainer>
|
||||
<img src={ArrowRight} alt="Arrow right" width={32} height={16} />
|
||||
</StyledArrowContainer>
|
||||
<SettingsObjectIconWithLabel Icon={Icon} label="Workspaces" />
|
||||
</StyledContainer>
|
||||
</section>
|
||||
);
|
||||
};
|
||||
@ -0,0 +1,45 @@
|
||||
import { useTheme } from '@emotion/react';
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
import { IconComponent } from '@/ui/display/icon/types/IconComponent';
|
||||
|
||||
const StyledContainer = styled.div`
|
||||
align-items: center;
|
||||
display: flex;
|
||||
gap: ${({ theme }) => theme.spacing(3)};
|
||||
padding: ${({ theme }) => theme.spacing(1)};
|
||||
`;
|
||||
|
||||
const StyledSubContainer = styled.div`
|
||||
align-items: center;
|
||||
display: flex;
|
||||
gap: ${({ theme }) => theme.spacing(1)};
|
||||
`;
|
||||
const StyledItemLabel = styled.div`
|
||||
color: ${({ theme }) => theme.font.color.secondary};
|
||||
font-size: ${({ theme }) => theme.font.size.sm};
|
||||
font-style: normal;
|
||||
font-weight: ${({ theme }) => theme.font.size.md};
|
||||
line-height: ${({ theme }) => theme.text.lineHeight.md};
|
||||
`;
|
||||
|
||||
type SettingsObjectIconWithLabelProps = {
|
||||
Icon: IconComponent;
|
||||
label: string;
|
||||
};
|
||||
|
||||
export const SettingsObjectIconWithLabel = ({
|
||||
Icon,
|
||||
label,
|
||||
}: SettingsObjectIconWithLabelProps) => {
|
||||
const theme = useTheme();
|
||||
|
||||
return (
|
||||
<StyledContainer>
|
||||
<StyledSubContainer>
|
||||
<Icon size={theme.icon.size.md} stroke={theme.icon.stroke.sm} />
|
||||
<StyledItemLabel>{label}</StyledItemLabel>
|
||||
</StyledSubContainer>
|
||||
</StyledContainer>
|
||||
);
|
||||
};
|
||||
@ -0,0 +1,8 @@
|
||||
import { IconComponent } from '@/ui/display/icon/types/IconComponent';
|
||||
|
||||
export type ObjectFieldItem = {
|
||||
name: string;
|
||||
Icon: IconComponent;
|
||||
type: 'standard' | 'custom';
|
||||
dataType: 'boolean' | 'number' | 'relation' | 'social' | 'teammate' | 'text';
|
||||
};
|
||||
Reference in New Issue
Block a user