Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
15 changes: 13 additions & 2 deletions datahub-web-react/src/CustomThemeProvider.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import React, { useState } from 'react';
import { ThemeProvider } from 'styled-components';

import GlobalThemeStyles from '@app/GlobalThemeStyles';
import { loadIsDarkMode } from '@app/useIsDarkMode';
import { useIsThemeV2 } from '@app/useIsThemeV2';
import { useCustomThemeId } from '@app/useSetAppTheme';
import themes from '@conf/theme/themes';
Expand All @@ -15,15 +17,24 @@ const CustomThemeProvider = ({ children }: Props) => {
// Note: AppConfigContext not provided yet, so both of these calls rely on the DEFAULT_APP_CONFIG
const isThemeV2 = useIsThemeV2();
const customThemeId = useCustomThemeId();
const isDarkMode = loadIsDarkMode();

// Note: If custom theme id is a json file, it will only be loaded later in useSetAppTheme
const defaultTheme = isThemeV2 ? themes.themeV2 : themes.themeV1;
let defaultTheme = themes.themeV1;
if (isThemeV2 && isDarkMode) {
defaultTheme = themes.themeV2Dark;
} else if (isThemeV2) {
defaultTheme = themes.themeV2;
}
const customTheme = customThemeId ? themes[customThemeId] : null;
const [theme, setTheme] = useState<Theme>(customTheme ?? defaultTheme);

return (
<CustomThemeContext.Provider value={{ theme, updateTheme: setTheme }}>
<ThemeProvider theme={theme}>{children}</ThemeProvider>
<ThemeProvider theme={theme}>
<GlobalThemeStyles />
{children}
</ThemeProvider>
</CustomThemeContext.Provider>
);
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ const ActionsContainer = styled.div`
width: fit-content;
align-self: center;
border-radius: 12px;
box-shadow: 0px 4px 12px 0px rgba(9, 1, 61, 0.12);
box-shadow: ${(props) => props.theme.colors.shadowMd};

background-color: white;
background-color: ${(props) => props.theme.colors.bg};
position: absolute;
left: 50%;
bottom: 2px;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ import styled from 'styled-components';

export const DropdownWrapper = styled.div`
& .rc-virtual-list-scrollbar-thumb {
background: rgba(193, 196, 208, 0.8) !important;
background: ${({ theme }) => theme.colors.scrollbarThumb} !important;
}
& .rc-virtual-list-scrollbar-show {
background: rgba(193, 196, 208, 0.3) !important;
background: ${({ theme }) => theme.colors.scrollbarTrack} !important;
}
`;
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import React, { useState } from 'react';

import { AvatarImage, AvatarImageWrapper, AvatarText, Container } from '@components/components/Avatar/components';
import { AvatarProps } from '@components/components/Avatar/types';
import getAvatarColor, { getNameInitials } from '@components/components/Avatar/utils';
import { getAvatarVariant, getNameInitials } from '@components/components/Avatar/utils';
import { AvatarType } from '@components/components/AvatarStack/types';
import { Icon } from '@components/components/Icon';

Expand Down Expand Up @@ -30,7 +30,7 @@ export const Avatar = ({
return (
<Container onClick={onClick} $hasOnClick={!!onClick} $showInPill={showInPill}>
{(type === AvatarType.user || imageUrl) && (
<AvatarImageWrapper $color={getAvatarColor(name)} $size={size} $isOutlined={isOutlined}>
<AvatarImageWrapper $variant={getAvatarVariant(name)} $size={size} $isOutlined={isOutlined}>
{!hasError && imageUrl ? (
<AvatarImage src={imageUrl} onError={() => setHasError(true)} />
) : (
Expand All @@ -39,12 +39,12 @@ export const Avatar = ({
</AvatarImageWrapper>
)}
{type === AvatarType.group && !imageUrl && (
<AvatarImageWrapper $color={getAvatarColor(name)} $size={size} $isOutlined={isOutlined}>
<AvatarImageWrapper $variant={getAvatarVariant(name)} $size={size} $isOutlined={isOutlined}>
<Icon icon="UsersThree" source="phosphor" variant="filled" size="lg" />
</AvatarImageWrapper>
)}
{type === AvatarType.role && !imageUrl && (
<AvatarImageWrapper $color={getAvatarColor(name)} $size={size} $isOutlined={isOutlined}>
<AvatarImageWrapper $variant={getAvatarVariant(name)} $size={size} $isOutlined={isOutlined}>
{mapRoleIcon(name)}
</AvatarImageWrapper>
)}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,20 @@
import styled from 'styled-components';

import { getAvatarColorStyles, getAvatarNameSizes, getAvatarSizes } from '@components/components/Avatar/utils';
import {
AvatarColorVariant,
getAvatarColorStyles,
getAvatarNameSizes,
getAvatarSizes,
} from '@components/components/Avatar/utils';

import { colors } from '@src/alchemy-components/theme';
import { AvatarSizeOptions } from '@src/alchemy-components/theme/config';

export const Container = styled.div<{ $hasOnClick: boolean; $showInPill?: boolean }>`
display: inline-flex;
align-items: center;
gap: 4px;
border-radius: 20px;
border: ${(props) => props.$showInPill && `1px solid ${colors.gray[100]}`};
border: ${(props) => props.$showInPill && `1px solid ${props.theme.colors.border}`};
padding: ${(props) => props.$showInPill && '3px 6px 3px 4px'};

${(props) =>
Expand All @@ -23,20 +27,20 @@ export const Container = styled.div<{ $hasOnClick: boolean; $showInPill?: boolea
`;

export const AvatarImageWrapper = styled.div<{
$color: string;
$variant: AvatarColorVariant;
$size?: AvatarSizeOptions;
$isOutlined?: boolean;
}>`
${(props) => getAvatarSizes(props.$size)}

position: relative;
border-radius: 50%;
color: ${(props) => props.$color};
border: ${(props) => props.$isOutlined && `1px solid ${colors.gray[1800]}`};
color: ${(props) => props.theme.colors.textSecondary};
border: ${(props) => props.$isOutlined && `1px solid ${props.theme.colors.border}`};
display: flex;
align-items: center;
justify-content: center;
${(props) => getAvatarColorStyles(props.$color)}
${(props) => getAvatarColorStyles(props.$variant, props.theme.colors)}
`;

export const AvatarImage = styled.img`
Expand All @@ -47,7 +51,7 @@ export const AvatarImage = styled.img`
`;

export const AvatarText = styled.span<{ $size?: AvatarSizeOptions }>`
color: ${colors.gray[1700]};
color: ${(props) => props.theme.colors.textSecondary};
font-weight: 600;
font-size: ${(props) => getAvatarNameSizes(props.$size)};
`;
52 changes: 34 additions & 18 deletions datahub-web-react/src/alchemy-components/components/Avatar/utils.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
import { AvatarType } from '@components/components/AvatarStack/types';

import { colors } from '@src/alchemy-components/theme';

import { EntityType } from '@types';

export const getNameInitials = (userName: string) => {
if (!userName) return '';
const names = userName.trim().split(/[\s']+/); // Split by spaces or apostrophes
const names = userName.trim().split(/[\s']+/);
if (names.length === 1) {
const firstName = names[0];
return firstName.length > 1 ? firstName[0]?.toUpperCase() + firstName[1]?.toUpperCase() : firstName[0];
Expand All @@ -24,29 +22,47 @@ export function hashString(str: string) {
// eslint-disable-next-line
hash = (hash << 5) - hash + char;
// eslint-disable-next-line
hash = hash & hash; // Convert to 32bit integer
hash = hash & hash;
}
return Math.abs(hash);
}

const colorMap = {
[colors.violet[500]]: { backgroundColor: colors.gray[1000], border: `1px solid ${colors.violet[1000]}` },
[colors.blue[1000]]: { backgroundColor: colors.gray[1100], border: `1px solid ${colors.blue[200]}` },
[colors.gray[600]]: { backgroundColor: colors.gray[1500], border: `1px solid ${colors.gray[100]}` },
};
export type AvatarColorVariant = 'violet' | 'blue' | 'gray';

const avatarColors = Object.keys(colorMap);
const AVATAR_VARIANTS: AvatarColorVariant[] = ['violet', 'blue', 'gray'];

export const getAvatarColorStyles = (color) => {
return {
...colorMap[color],
};
};

export default function getAvatarColor(name: string) {
return avatarColors[hashString(name) % avatarColors.length];
export function getAvatarVariant(name: string): AvatarColorVariant {
return AVATAR_VARIANTS[hashString(name) % AVATAR_VARIANTS.length];
}

export const getAvatarColorStyles = (
variant: AvatarColorVariant,
themeColors: {
bgSurfaceBrand: string;
avatarBorderBrand: string;
bgSurfaceInfo: string;
avatarBorderInformation: string;
bgSurface: string;
border: string;
},
) => {
switch (variant) {
case 'violet':
return {
backgroundColor: themeColors.bgSurfaceBrand,
border: `1px solid ${themeColors.avatarBorderBrand}`,
};
case 'blue':
return {
backgroundColor: themeColors.bgSurfaceInfo,
border: `1px solid ${themeColors.avatarBorderInformation}`,
};
case 'gray':
default:
return { backgroundColor: themeColors.bgSurface, border: `1px solid ${themeColors.border}` };
}
};

export const getAvatarSizes = (size) => {
const sizeMap = {
sm: { width: '18px', height: '18px', fontSize: '8px' },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ const AvatarStackWithHover = ({

const renderTitle = (headerText, count) => (
<HeaderContainer>
<Text size="sm" color="gray" weight="bold">
<Text size="sm" weight="bold">
{headerText}
</Text>
<Badge count={count} size="xs" />
Expand Down
24 changes: 11 additions & 13 deletions datahub-web-react/src/alchemy-components/components/Bar/Bar.tsx
Original file line number Diff line number Diff line change
@@ -1,25 +1,23 @@
import React from 'react';
import { useTheme } from 'styled-components';

import { BarContainer, IndividualBar } from '@components/components/Bar/components';
import { BAR_HEIGHT_MULTIPLIER } from '@components/components/Bar/constant';
import { BarComponentProps } from '@components/components/Bar/types';

import { colors } from '@src/alchemy-components/theme';

const defaultProps: BarComponentProps = {
color: colors.violet[500],
coloredBars: 2,
size: 'default',
};
export const Bar = ({
color = defaultProps.color,
coloredBars = defaultProps.coloredBars,
size = defaultProps.size,
}: BarComponentProps) => {
export const Bar = ({ color, coloredBars = 2, size = 'default' }: BarComponentProps) => {
const theme = useTheme();
const resolvedColor = color ?? theme.colors.chartsBrandMedium;
const Bars = Array.from({ length: 3 }, (_, index) => {
const barHeight = (index + 2) * BAR_HEIGHT_MULTIPLIER[size];
return (
<IndividualBar key={index} size={size} height={barHeight} isColored={index < coloredBars} color={color} />
<IndividualBar
key={index}
size={size}
height={barHeight}
isColored={index < coloredBars}
color={resolvedColor}
/>
);
});
return <BarContainer>{Bars}</BarContainer>;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ export const BarContainer = styled.div`
export const IndividualBar = styled.div<{ height: number; isColored: boolean; color: string; size: string }>`
width: ${(props) => (props.size === 'default' ? '5px' : '3px')};
height: ${(props) => props.height}px;
background-color: ${(props) => (props.isColored ? props.color : '#C6C0E0')};
background-color: ${(props) => (props.isColored ? props.color : props.theme.colors.bgSurface)};
border-radius: 20px;
transition:
background-color 0.3s ease,
Expand Down
Loading
Loading