1761 objects settings add a cover image (#2096)
* add image * overflow hidden * add close button * add animation to cover image * use cookie to store user preference * refactor to have a reusable component called AnimatedFadeOut * corrected close button position * modified according to comments
This commit is contained in:
Binary file not shown.
|
After Width: | Height: | Size: 119 KiB |
@ -0,0 +1,58 @@
|
|||||||
|
import { useState } from 'react';
|
||||||
|
import { useTheme } from '@emotion/react';
|
||||||
|
import styled from '@emotion/styled';
|
||||||
|
|
||||||
|
import { IconX } from '@/ui/display/icon';
|
||||||
|
import { LightIconButton } from '@/ui/input/button/components/LightIconButton';
|
||||||
|
import { AnimatedFadeOut } from '@/ui/utilities/animation/components/AnimatedFadeOut';
|
||||||
|
import { cookieStorage } from '~/utils/cookie-storage';
|
||||||
|
|
||||||
|
import CoverImage from '../assets/build-your-business-logic.jpg';
|
||||||
|
|
||||||
|
const StyledCoverImageContainer = styled.div`
|
||||||
|
border: 1px solid ${({ theme }) => theme.border.color.medium};
|
||||||
|
border-radius: ${({ theme }) => theme.border.radius.md};
|
||||||
|
overflow: hidden;
|
||||||
|
position: relative;
|
||||||
|
width: 100%;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const StyledCoverImage = styled.img`
|
||||||
|
height: 100%;
|
||||||
|
object-fit: cover;
|
||||||
|
width: 100%;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const StyledLighIconButton = styled(LightIconButton)`
|
||||||
|
position: absolute;
|
||||||
|
right: ${({ theme }) => theme.spacing(1)};
|
||||||
|
top: ${({ theme }) => theme.spacing(1)};
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const SettingsObjectCoverImage = () => {
|
||||||
|
const theme = useTheme();
|
||||||
|
|
||||||
|
const [cookieState, setCookieState] = useState(
|
||||||
|
cookieStorage.getItem('settings-object-cover-image'),
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<AnimatedFadeOut
|
||||||
|
isOpen={cookieState !== 'closed'}
|
||||||
|
marginBottom={theme.spacing(8)}
|
||||||
|
>
|
||||||
|
<StyledCoverImageContainer>
|
||||||
|
<StyledCoverImage src={CoverImage} alt="Build your business logic" />
|
||||||
|
<StyledLighIconButton
|
||||||
|
Icon={IconX}
|
||||||
|
accent="tertiary"
|
||||||
|
size="small"
|
||||||
|
onClick={() => {
|
||||||
|
cookieStorage.setItem('settings-object-cover-image', 'closed');
|
||||||
|
setCookieState('closed');
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</StyledCoverImageContainer>
|
||||||
|
</AnimatedFadeOut>
|
||||||
|
);
|
||||||
|
};
|
||||||
@ -5,3 +5,5 @@ export const animation = {
|
|||||||
normal: 0.3,
|
normal: 0.3,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type AnimationDuration = 'instant' | 'fast' | 'normal';
|
||||||
|
|||||||
@ -1,19 +1,26 @@
|
|||||||
|
import { useTheme } from '@emotion/react';
|
||||||
import { motion } from 'framer-motion';
|
import { motion } from 'framer-motion';
|
||||||
|
|
||||||
|
import { AnimationDuration } from '@/ui/theme/constants/animation';
|
||||||
|
|
||||||
type AnimatedEaseInProps = Omit<
|
type AnimatedEaseInProps = Omit<
|
||||||
React.ComponentProps<typeof motion.div>,
|
React.ComponentProps<typeof motion.div>,
|
||||||
'initial' | 'animated' | 'transition'
|
'initial' | 'animated' | 'transition'
|
||||||
> & {
|
> & {
|
||||||
duration?: number;
|
duration?: AnimationDuration;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const AnimatedEaseIn = ({
|
export const AnimatedEaseIn = ({
|
||||||
children,
|
children,
|
||||||
duration = 0.3,
|
duration = 'normal',
|
||||||
}: AnimatedEaseInProps) => {
|
}: AnimatedEaseInProps) => {
|
||||||
|
const theme = useTheme();
|
||||||
const initial = { opacity: 0 };
|
const initial = { opacity: 0 };
|
||||||
const animate = { opacity: 1 };
|
const animate = { opacity: 1 };
|
||||||
const transition = { ease: 'linear', duration };
|
const transition = {
|
||||||
|
ease: 'linear',
|
||||||
|
duration: theme.animation.duration[duration],
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<motion.div initial={initial} animate={animate} transition={transition}>
|
<motion.div initial={initial} animate={animate} transition={transition}>
|
||||||
|
|||||||
@ -0,0 +1,42 @@
|
|||||||
|
import { useTheme } from '@emotion/react';
|
||||||
|
import { AnimatePresence, motion } from 'framer-motion';
|
||||||
|
|
||||||
|
import { AnimationDuration } from '@/ui/theme/constants/animation';
|
||||||
|
|
||||||
|
type AnimatedFadeOutProps = {
|
||||||
|
isOpen: boolean;
|
||||||
|
children: React.ReactNode;
|
||||||
|
duration?: AnimationDuration;
|
||||||
|
marginBottom?: string;
|
||||||
|
marginTop?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const AnimatedFadeOut = ({
|
||||||
|
isOpen,
|
||||||
|
children,
|
||||||
|
duration = 'normal',
|
||||||
|
marginBottom,
|
||||||
|
marginTop,
|
||||||
|
}: AnimatedFadeOutProps) => {
|
||||||
|
const theme = useTheme();
|
||||||
|
return (
|
||||||
|
<AnimatePresence>
|
||||||
|
{isOpen && (
|
||||||
|
<motion.div
|
||||||
|
initial={{
|
||||||
|
opacity: 1,
|
||||||
|
marginBottom: marginBottom ?? 0,
|
||||||
|
marginTop: marginTop ?? 0,
|
||||||
|
}}
|
||||||
|
exit={{ opacity: 0, height: 0, marginBottom: 0, marginTop: 0 }}
|
||||||
|
transition={{
|
||||||
|
duration: theme.animation.duration[duration],
|
||||||
|
ease: 'easeOut',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</motion.div>
|
||||||
|
)}
|
||||||
|
</AnimatePresence>
|
||||||
|
);
|
||||||
|
};
|
||||||
@ -8,6 +8,7 @@ import {
|
|||||||
activeObjectItems,
|
activeObjectItems,
|
||||||
disabledObjectItems,
|
disabledObjectItems,
|
||||||
} from '@/settings/data-model/constants/mockObjects';
|
} from '@/settings/data-model/constants/mockObjects';
|
||||||
|
import { SettingsObjectCoverImage } from '@/settings/data-model/objects/SettingsObjectCoverImage';
|
||||||
import {
|
import {
|
||||||
IconChevronRight,
|
IconChevronRight,
|
||||||
IconDotsVertical,
|
IconDotsVertical,
|
||||||
@ -76,52 +77,28 @@ export const SettingsObjects = () => {
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</SettingsHeaderContainer>
|
</SettingsHeaderContainer>
|
||||||
<Section>
|
<div>
|
||||||
<H2Title title="Existing objects" />
|
<SettingsObjectCoverImage />
|
||||||
<Table>
|
<Section>
|
||||||
<StyledTableRow>
|
<H2Title title="Existing objects" />
|
||||||
<TableHeader>Name</TableHeader>
|
<Table>
|
||||||
<TableHeader>Type</TableHeader>
|
<StyledTableRow>
|
||||||
<TableHeader align="right">Fields</TableHeader>
|
<TableHeader>Name</TableHeader>
|
||||||
<TableHeader align="right">Instances</TableHeader>
|
<TableHeader>Type</TableHeader>
|
||||||
<TableHeader></TableHeader>
|
<TableHeader align="right">Fields</TableHeader>
|
||||||
</StyledTableRow>
|
<TableHeader align="right">Instances</TableHeader>
|
||||||
<TableSection title="Active">
|
<TableHeader></TableHeader>
|
||||||
{activeObjectItems.map((objectItem) => (
|
</StyledTableRow>
|
||||||
<StyledTableRow
|
<TableSection title="Active">
|
||||||
key={objectItem.name}
|
{activeObjectItems.map((objectItem) => (
|
||||||
onClick={() =>
|
<StyledTableRow
|
||||||
navigate(
|
key={objectItem.name}
|
||||||
`/settings/objects/${objectItem.name.toLowerCase()}`,
|
onClick={() =>
|
||||||
)
|
navigate(
|
||||||
}
|
`/settings/objects/${objectItem.name.toLowerCase()}`,
|
||||||
>
|
)
|
||||||
<StyledNameTableCell>
|
}
|
||||||
<objectItem.Icon size={theme.icon.size.md} />
|
>
|
||||||
{objectItem.name}
|
|
||||||
</StyledNameTableCell>
|
|
||||||
<TableCell>
|
|
||||||
{objectItem.type === 'standard' ? (
|
|
||||||
<StyledTag color="blue" text="Standard" />
|
|
||||||
) : (
|
|
||||||
<StyledTag color="orange" text="Custom" />
|
|
||||||
)}
|
|
||||||
</TableCell>
|
|
||||||
<TableCell align="right">{objectItem.fields}</TableCell>
|
|
||||||
<TableCell align="right">{objectItem.instances}</TableCell>
|
|
||||||
<StyledIconTableCell>
|
|
||||||
<StyledIconChevronRight
|
|
||||||
size={theme.icon.size.md}
|
|
||||||
stroke={theme.icon.stroke.sm}
|
|
||||||
/>
|
|
||||||
</StyledIconTableCell>
|
|
||||||
</StyledTableRow>
|
|
||||||
))}
|
|
||||||
</TableSection>
|
|
||||||
{!!disabledObjectItems.length && (
|
|
||||||
<TableSection title="Disabled">
|
|
||||||
{disabledObjectItems.map((objectItem) => (
|
|
||||||
<StyledTableRow key={objectItem.name}>
|
|
||||||
<StyledNameTableCell>
|
<StyledNameTableCell>
|
||||||
<objectItem.Icon size={theme.icon.size.md} />
|
<objectItem.Icon size={theme.icon.size.md} />
|
||||||
{objectItem.name}
|
{objectItem.name}
|
||||||
@ -136,7 +113,7 @@ export const SettingsObjects = () => {
|
|||||||
<TableCell align="right">{objectItem.fields}</TableCell>
|
<TableCell align="right">{objectItem.fields}</TableCell>
|
||||||
<TableCell align="right">{objectItem.instances}</TableCell>
|
<TableCell align="right">{objectItem.instances}</TableCell>
|
||||||
<StyledIconTableCell>
|
<StyledIconTableCell>
|
||||||
<StyledIconDotsVertical
|
<StyledIconChevronRight
|
||||||
size={theme.icon.size.md}
|
size={theme.icon.size.md}
|
||||||
stroke={theme.icon.stroke.sm}
|
stroke={theme.icon.stroke.sm}
|
||||||
/>
|
/>
|
||||||
@ -144,9 +121,38 @@ export const SettingsObjects = () => {
|
|||||||
</StyledTableRow>
|
</StyledTableRow>
|
||||||
))}
|
))}
|
||||||
</TableSection>
|
</TableSection>
|
||||||
)}
|
{!!disabledObjectItems.length && (
|
||||||
</Table>
|
<TableSection title="Disabled">
|
||||||
</Section>
|
{disabledObjectItems.map((objectItem) => (
|
||||||
|
<StyledTableRow key={objectItem.name}>
|
||||||
|
<StyledNameTableCell>
|
||||||
|
<objectItem.Icon size={theme.icon.size.md} />
|
||||||
|
{objectItem.name}
|
||||||
|
</StyledNameTableCell>
|
||||||
|
<TableCell>
|
||||||
|
{objectItem.type === 'standard' ? (
|
||||||
|
<StyledTag color="blue" text="Standard" />
|
||||||
|
) : (
|
||||||
|
<StyledTag color="orange" text="Custom" />
|
||||||
|
)}
|
||||||
|
</TableCell>
|
||||||
|
<TableCell align="right">{objectItem.fields}</TableCell>
|
||||||
|
<TableCell align="right">
|
||||||
|
{objectItem.instances}
|
||||||
|
</TableCell>
|
||||||
|
<StyledIconTableCell>
|
||||||
|
<StyledIconDotsVertical
|
||||||
|
size={theme.icon.size.md}
|
||||||
|
stroke={theme.icon.stroke.sm}
|
||||||
|
/>
|
||||||
|
</StyledIconTableCell>
|
||||||
|
</StyledTableRow>
|
||||||
|
))}
|
||||||
|
</TableSection>
|
||||||
|
)}
|
||||||
|
</Table>
|
||||||
|
</Section>
|
||||||
|
</div>
|
||||||
</SettingsPageContainer>
|
</SettingsPageContainer>
|
||||||
</SubMenuTopBarContainer>
|
</SubMenuTopBarContainer>
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in New Issue
Block a user