Updated drawer to match entity drawer styling (#13665)

This commit is contained in:
Anna Everhart 2025-06-09 08:12:31 -07:00 committed by GitHub
parent c913aa4161
commit c997668110
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 287 additions and 56 deletions

View File

@ -76,7 +76,7 @@ export function AboutFieldTab({ properties }: AboutFieldTabProps) {
notes={notes}
refetch={delayedRefetchNotes}
/>
{!!notes?.length && <StyledDivider dashed />}
{!!notes?.length && <StyledDivider />}
<FieldDescription expandedField={expandedField} editableFieldInfo={editableFieldInfo} />
<FieldTags
expandedField={expandedField}

View File

@ -9,7 +9,7 @@ import { DeprecationIcon } from '@app/entityV2/shared/components/styled/Deprecat
import { REDESIGN_COLORS } from '@app/entityV2/shared/constants';
import { FieldPopularity } from '@app/entityV2/shared/tabs/Dataset/Schema/components/SchemaFieldDrawer/FieldPopularity';
import SchemaEditableContext from '@app/shared/SchemaEditableContext';
import { Button } from '@src/alchemy-components';
import { Button, colors } from '@src/alchemy-components';
import MarkAsDeprecatedButton from '@src/app/entityV2/shared/components/styled/MarkAsDeprecatedButton';
import { Deprecation, SubResourceType, UsageQueryResult } from '@types';
@ -21,13 +21,13 @@ const FieldDetailsWrapper = styled.div`
const FieldDetailsContent = styled.div`
display: flex;
gap: 10px;
border-bottom: 1px dashed;
border-color: rgba(0, 0, 0, 0.3);
border-bottom: 1px solid;
border-color: ${colors.gray[100]};
padding-bottom: 16px;
& > div {
&:not(:first-child) {
border-left: 1px dashed;
border-color: rgba(0, 0, 0, 0.3);
border-left: 1px solid;
border-color: ${colors.gray[100]};
}
}
`;

View File

@ -22,7 +22,7 @@ const FieldHeaderWrapper = styled.div`
padding: 16px;
display: flex;
justify-content: space-between;
border-bottom: 1px solid rgb(213, 213, 213);
border-bottom: 1px solid ${colors.gray[100]};
`;
const NameTypesWrapper = styled.div`

View File

@ -1,5 +1,4 @@
import { CodeOutlined, ReadOutlined, UnorderedListOutlined } from '@ant-design/icons';
import QueryStatsOutlinedIcon from '@mui/icons-material/QueryStatsOutlined';
import { BookOpen, ChartBar, Code, ListBullets } from '@phosphor-icons/react';
import { Drawer, Typography } from 'antd';
import React, { useCallback, useEffect, useMemo, useState } from 'react';
import styled from 'styled-components';
@ -181,7 +180,7 @@ export default function SchemaFieldDrawer({
const tabs: any = [
{
name: 'About',
icon: ReadOutlined,
icon: BookOpen,
component: AboutFieldTab,
properties: {
schemaFields,
@ -198,7 +197,7 @@ export default function SchemaFieldDrawer({
},
{
name: 'Statistics',
icon: QueryStatsOutlinedIcon,
icon: ChartBar,
component: StatsSidebarView,
properties: {
expandedField,
@ -212,14 +211,14 @@ export default function SchemaFieldDrawer({
name: 'Queries',
component: SchemaFieldQueriesSidebarTab,
description: 'View queries about this field',
icon: CodeOutlined,
icon: Code,
properties: { fieldPath: expandedField?.fieldPath },
},
{
name: 'Properties',
component: PropertiesTab,
description: 'View additional properties about this field',
icon: UnorderedListOutlined,
icon: ListBullets,
properties: {
fieldPath: expandedField?.fieldPath,
fieldUrn: expandedField?.schemaFieldEntity?.urn,

View File

@ -1,39 +1,126 @@
import { Tooltip } from '@components';
import { Tooltip, colors } from '@components';
import { Tabs } from 'antd';
import React from 'react';
import styled from 'styled-components/macro';
import { EntitySidebarTab } from '@app/entityV2/shared/types';
export const TABS_WIDTH = 56;
export const TABS_WIDTH = 64;
const UnborderedTabs = styled(Tabs)`
const UnborderedTabs = styled(Tabs).attrs({ className: 'schema-field-drawer-tabs' })`
height: 100%;
width: ${TABS_WIDTH}px;
&&& .ant-tabs-nav {
margin-bottom: 0;
box-sizing: border-box;
user-select: none;
overflow: visible;
background-color: #ffffff;
.ant-tabs-nav {
margin: 0;
width: ${TABS_WIDTH}px;
display: flex;
justify-content: center;
box-sizing: border-box;
overflow: visible;
}
&&& .ant-tabs-ink-bar {
.ant-tabs-nav-operations {
display: none;
}
&&& .ant-tabs-tab {
padding: 10px 10px 10px 10px;
margin: 8px 8px 16px 8px;
border-radius: 6px;
.ant-tabs-nav-wrap {
margin: 0;
padding: 0;
display: flex;
justify-content: center;
min-width: ${TABS_WIDTH}px;
box-sizing: border-box;
overflow: visible;
}
.ant-tabs-nav-list {
margin: 0;
gap: 4px;
width: ${TABS_WIDTH}px;
display: flex;
align-items: center;
padding: 4px 0px;
box-sizing: border-box;
overflow: visible;
}
.ant-tabs-ink-bar {
display: none;
}
.ant-tabs-tab {
padding: 0;
margin: 0 0 4px 0;
border-radius: 8px;
display: flex;
align-items: center;
justify-content: center;
width: 52px;
height: 52px;
transition: none;
overflow: visible;
.anticon {
margin-right: 0;
}
.ant-tabs-tab-btn {
color: inherit;
transition: none;
display: flex;
justify-content: center;
align-items: center;
width: 100%;
height: 100%;
}
&:hover {
background: linear-gradient(
180deg,
rgba(243, 244, 246, 0.5) -3.99%,
rgba(235, 236, 240, 0.5) 53.04%,
rgba(235, 236, 240, 0.5) 100%
);
box-shadow: 0px 0px 0px 1px rgba(139, 135, 157, 0.08);
}
&:last-child {
margin-bottom: 0;
}
}
&&& .ant-tabs-tab-active {
background-color: ${(p) => p.theme.styles['primary-color']};
.ant-tabs-tab-active {
background: linear-gradient(
180deg,
rgba(83, 63, 209, 0.04) -3.99%,
rgba(112, 94, 228, 0.04) 53.04%,
rgba(112, 94, 228, 0.04) 100%
);
box-shadow: 0px 0px 0px 1px rgba(108, 71, 255, 0.08);
.ant-tabs-tab-btn {
color: inherit;
}
&:hover {
background: linear-gradient(
180deg,
rgba(83, 63, 209, 0.04) -3.99%,
rgba(112, 94, 228, 0.04) 53.04%,
rgba(112, 94, 228, 0.04) 100%
);
box-shadow: 0px 0px 0px 1px rgba(139, 135, 157, 0.08);
}
}
&&& .ant-tabs-tab-active .ant-tabs-tab-btn {
color: #ffffff;
}
&&& .ant-tabs-content-holder {
.ant-tabs-content-holder {
display: none;
}
background-color: #ffffff;
`;
const Tab = styled(Tabs.TabPane)`
@ -43,35 +130,178 @@ const Tab = styled(Tabs.TabPane)`
align-items: center;
`;
const tabIconStyle = { fontSize: 20, margin: 0, display: 'flex' };
const TabIconContainer = styled.div<{ $isSelected?: boolean }>`
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
transition: none;
color: ${colors.gray[1800]};
width: 48px;
height: 48px;
padding: 0;
margin: 0;
gap: 2px;
user-select: none;
`;
const TabText = styled.span<{ $isSelected?: boolean }>`
font-size: 10px;
font-weight: ${(props) => (props.$isSelected ? '500' : '400')};
text-align: center;
transition: none;
user-select: none;
display: block;
width: 48px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
color: ${colors.gray[1800]};
${(props) =>
props.$isSelected &&
`
color: transparent;
background: linear-gradient(#7565d6 20%, #5340cc 80%);
background-clip: text;
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
`}
`;
const IconWrapper = styled.div<{ $isSelected?: boolean }>`
display: flex;
align-items: center;
justify-content: center;
transition: none;
width: 20px;
height: 18px;
position: relative;
/* For Phosphor icons */
svg {
${(props) => (props.$isSelected ? 'fill: url(#menu-item-selected-gradient) #533fd1;' : 'color: #8088a3;')}
width: 20px;
height: 20px;
min-width: 20px;
min-height: 20px;
max-width: 20px;
max-height: 20px;
padding: 0;
margin: 0;
transition: none;
}
/* For Ant Design icons */
span {
display: flex;
align-items: center;
justify-content: center;
${(props) => (props.$isSelected ? 'color: url(#menu-item-selected-gradient) #533fd1;' : 'color: #8088a3;')}
width: 20px;
height: 20px;
svg {
width: 20px;
height: 20px;
min-width: 20px;
min-height: 20px;
max-width: 20px;
max-height: 20px;
}
}
/* Ensure Phosphor icon weights are correctly applied */
.ph-fill {
fill: ${(props) => (props.$isSelected ? 'url(#menu-item-selected-gradient) #533fd1' : '#8088a3')};
}
`;
const TabTextWithTooltip = ({ text, isSelected }: { text: string; isSelected?: boolean }) => {
const textRef = React.useRef<HTMLSpanElement>(null);
const [isOverflowing, setIsOverflowing] = React.useState(false);
React.useEffect(() => {
const element = textRef.current;
if (element) {
setIsOverflowing(element.scrollWidth > element.clientWidth);
}
}, [text]);
return (
<Tooltip title={isOverflowing ? text : null} placement="left" showArrow={false}>
<TabText ref={textRef} $isSelected={isSelected}>
{text}
</TabText>
</Tooltip>
);
};
const GradientDefs = () => (
<svg width="0" height="0">
<defs>
<linearGradient id="menu-item-selected-gradient" x1="0%" y1="0%" x2="0%" y2="100%">
<stop offset="20%" stopColor="#7565d6" />
<stop offset="80%" stopColor="#5340cc" />
</linearGradient>
</defs>
</svg>
);
const TabsWrapper = styled.div`
width: ${TABS_WIDTH}px;
flex-shrink: 0;
box-sizing: border-box;
display: flex;
flex-direction: column;
align-items: center;
padding: 0;
margin: 0;
overflow: visible;
`;
type Props = {
tabs: EntitySidebarTab[];
selectedTab?: EntitySidebarTab;
onSelectTab: (name: string) => void;
};
export const SchemaFieldDrawerTabs = ({ tabs, selectedTab, onSelectTab }: Props) => {
return (
<UnborderedTabs
animated={false}
tabPosition="right"
activeKey={selectedTab?.name || ''}
size="large"
onTabClick={(name: string) => onSelectTab(name)}
>
{tabs.map((tab) => {
const TabIcon = tab.icon;
const { name } = tab;
return (
<Tab
tab={
<Tooltip title={name} placement="left" showArrow={false}>
<TabIcon style={tabIconStyle} data-testid={`${name}-field-drawer-tab-header`} />
</Tooltip>
}
key={tab.name}
/>
);
})}
</UnborderedTabs>
<TabsWrapper>
<GradientDefs />
<UnborderedTabs
animated={false}
tabPosition="right"
activeKey={selectedTab?.name || ''}
onTabClick={(name: string) => onSelectTab(name)}
>
{tabs.map((tab) => {
const TabIcon = tab.icon;
const SelectedTabIcon = tab.selectedIcon || tab.icon;
const { name } = tab;
const isSelected = selectedTab?.name === tab.name;
return (
<Tab
tab={
<TabIconContainer $isSelected={isSelected}>
<IconWrapper $isSelected={isSelected}>
{isSelected ? (
<SelectedTabIcon size={20} weight="fill" />
) : (
<TabIcon size={20} weight="regular" />
)}
</IconWrapper>
<TabTextWithTooltip text={name} isSelected={isSelected} />
</TabIconContainer>
}
key={tab.name}
data-testid={`${name}-field-drawer-tab-header`}
/>
);
})}
</UnborderedTabs>
</TabsWrapper>
);
};

View File

@ -8,6 +8,7 @@ import { decimalToPercentStr } from '@app/entityV2/shared/tabs/Dataset/Schema/ut
import SampleValueTag from '@app/entityV2/shared/tabs/Dataset/Stats/snapshot/SampleValueTag';
import { extractChartValuesFromFieldProfiles } from '@app/entityV2/shared/utils';
import { formatNumberWithoutAbbreviation } from '@app/shared/formatNumber';
import { colors } from '@src/alchemy-components';
import { DatasetFieldProfile, SchemaField } from '@types';
@ -38,8 +39,7 @@ const StatLabel = styled.div`
padding-top: 12px;
padding-bottom: 12px;
:not(:last-child) {
border-bottom: 1px dashed;
border-color: rgba(0, 0, 0, 0.3);
border-bottom: 1px solid ${colors.gray[100]};
}
`;

View File

@ -2,6 +2,7 @@ import { Divider } from 'antd';
import styled from 'styled-components';
import { REDESIGN_COLORS } from '@app/entityV2/shared/constants';
import { colors } from '@src/alchemy-components';
export const SectionHeader = styled.div`
margin-bottom: 8px;
@ -13,5 +14,6 @@ export const SectionHeader = styled.div`
`;
export const StyledDivider = styled(Divider)`
border-color: rgba(0, 0, 0, 0.3);
border-color: ${colors.gray[100]};
border-style: solid;
`;