feat(customHomePage): add generic module component (#13922)

This commit is contained in:
v-tarasevich-blitz-brain 2025-07-02 18:46:37 +03:00 committed by GitHub
parent 68130a33e4
commit cfadc80843
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 197 additions and 2 deletions

View File

@ -87,7 +87,7 @@ export type BorderRadiusOptions = 'none' | 'sm' | 'md' | 'lg' | 'xl' | 'full';
export type BoxShadowOptions = 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl' | 'inner' | 'outline' | 'dropdown' | 'none';
export type SpacingOptions = 'none' | 'sm' | 'md' | 'lg' | 'xl' | '2xl' | '3xl' | '4xl';
export type SpacingOptions = 'none' | 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl' | '3xl' | '4xl';
export type RotationOptions = '0' | '90' | '180' | '270';

View File

@ -1,12 +1,20 @@
import React from 'react';
import Module from '@app/homepageV2/module/Module';
import { ContentContainer, ContentWrapper, StyledVectorBackground } from '@app/homepageV2/styledComponents';
const HomePageContent = () => {
return (
<ContentWrapper>
<StyledVectorBackground />
<ContentContainer />
<ContentContainer>
<Module
name="Sample large module"
description="Description of the sample module"
type="sampleLarge"
visibility="global"
/>
</ContentContainer>
</ContentWrapper>
);
};

View File

@ -0,0 +1,14 @@
import React, { useMemo } from 'react';
import SampleLargeModule from '@app/homepageV2/module/modules/SampleLargeModule';
import { ModuleProps } from '@app/homepageV2/module/types';
export default function Module(props: ModuleProps) {
const Component = useMemo(() => {
// TODO: implement logic to map props.type to component
if (props.type === 'sampleLarge') return SampleLargeModule;
return SampleLargeModule;
}, [props.type]);
return <Component {...props} />;
}

View File

@ -0,0 +1,57 @@
import { borders, colors, radius, spacing } from '@components';
import React from 'react';
import styled from 'styled-components';
import ModuleContainer from '@app/homepageV2/module/components/ModuleContainer';
import ModuleDescription from '@app/homepageV2/module/components/ModuleDescription';
import ModuleMenu from '@app/homepageV2/module/components/ModuleMenu';
import ModuleName from '@app/homepageV2/module/components/ModuleName';
import PublicModuleBadge from '@app/homepageV2/module/components/PublicModuleBadge';
import { ModuleProps } from '@app/homepageV2/module/types';
const ModuleHeader = styled.div`
position: relative;
display: flex;
flex-direction: column;
gap: 2px;
border-radius: ${radius.lg} ${radius.lg} 0 0;
padding: ${spacing.md} ${spacing.md} ${spacing.xsm} ${spacing.md};
border-bottom: ${borders['1px']} ${colors.white};
:hover {
background: linear-gradient(180deg, #fff 0%, #fafafb 100%);
border-bottom: 1px solid ${colors.gray[100]};
}
`;
const FloatingRightHeaderSection = styled.div`
position: absolute;
display: flex;
flex-direction: row;
align-items: center;
gap: 8px;
padding-right: 16px;
right: 0px;
top: 0px;
height: 100%;
`;
const Content = styled.div`
padding: 16px;
`;
export default function LargeModule({ children, name, description, visibility }: React.PropsWithChildren<ModuleProps>) {
return (
<ModuleContainer $height="316px">
<ModuleHeader>
<ModuleName text={name} />
<ModuleDescription text={description} />
<FloatingRightHeaderSection>
<PublicModuleBadge isPublic={visibility === 'global'} />
<ModuleMenu />
</FloatingRightHeaderSection>
</ModuleHeader>
<Content>{children}</Content>
</ModuleContainer>
);
}

View File

@ -0,0 +1,15 @@
import { borders, colors, radius } from '@components';
import styled from 'styled-components';
const ModuleContainer = styled.div<{ $height: string }>`
background: ${colors.white};
border: ${borders['1px']} ${colors.gray[100]};
border-radius: ${radius.lg};
height: ${(props) => props.$height};
box-shadow:
0px 2px 18px 0px rgba(17, 7, 69, 0.01),
0px 4px 12px 0px rgba(17, 7, 69, 0.03);
`;
export default ModuleContainer;

View File

@ -0,0 +1,15 @@
import { Text } from '@components';
import React from 'react';
interface Props {
text?: string;
}
export default function ModuleDescription({ text }: Props) {
if (!text) return null;
return (
<Text color="gray" colorLevel={1700} size="md" weight="medium" lineHeight="xs">
{text}
</Text>
);
}

View File

@ -0,0 +1,42 @@
import { Icon, colors } from '@components';
import { Dropdown } from 'antd';
import React from 'react';
import styled from 'styled-components';
const StyledIcon = styled(Icon)`
:hover {
cursor: pointer;
}
` as typeof Icon;
export default function ModuleMenu() {
return (
<Dropdown
trigger={['click']}
menu={{
items: [
{
title: 'Edit',
key: 'edit',
label: 'Edit',
},
{
title: 'Duplicate',
label: 'Duplicate',
key: 'duplicate',
},
{
title: 'Delete',
label: 'Delete',
key: 'delete',
style: {
color: colors.red[500],
},
},
],
}}
>
<StyledIcon icon="DotsThreeVertical" source="phosphor" size="lg" />
</Dropdown>
);
}

View File

@ -0,0 +1,14 @@
import { Text } from '@components';
import React from 'react';
interface Props {
text?: string;
}
export default function ModuleName({ text }: Props) {
return (
<Text color="gray" colorLevel={600} size="xl" weight="bold" lineHeight="sm">
{text}
</Text>
);
}

View File

@ -0,0 +1,12 @@
import { Pill } from '@components';
import React from 'react';
interface Props {
isPublic?: boolean;
}
export default function PublicModuleBadge({ isPublic }: Props) {
if (!isPublic) return null;
return <Pill label="Public" color="gray" size="xs" />;
}

View File

@ -0,0 +1,8 @@
import React from 'react';
import LargeModule from '@app/homepageV2/module/components/LargeModule';
import { ModuleProps } from '@app/homepageV2/module/types';
export default function SampleLargeModule(props: ModuleProps) {
return <LargeModule {...props}>Content of the sample module</LargeModule>;
}

View File

@ -0,0 +1,9 @@
// TODO: adapt to DataHubPageModuleProperties
// the current props are just to draft some components
export interface ModuleProps {
name: string;
type: string;
visibility: 'personal' | 'global';
description?: string;
isPublic?: boolean;
}

View File

@ -30,6 +30,7 @@ export const ContentWrapper = styled.div`
`;
export const ContentContainer = styled.div`
position: relative; // to enable z-index
padding: 40px 160px 16px 160px;
background-color: ${colors.white};
height: 100%;