Skip to content
Snippets Groups Projects
Unverified Commit f57be777 authored by Oisin Coveney's avatar Oisin Coveney Committed by GitHub
Browse files

fix(sdk): Add theming options for Collection Browser's empty content message (#44281)

parent 4d907fe8
No related branches found
No related tags found
No related merge requests found
import { type CSSProperties, useState } from "react";
import { type ComponentType, type CSSProperties, useState } from "react";
import { withPublicComponentWrapper } from "embedding-sdk/components/private/PublicComponentWrapper";
import { COLLECTION_PAGE_SIZE } from "metabase/collections/components/CollectionContent";
......@@ -37,6 +37,7 @@ type CollectionBrowserProps = {
onClick?: (item: CollectionItem) => void;
pageSize?: number;
visibleEntityTypes?: UserFacingEntityName[];
EmptyContentComponent?: ComponentType | null;
className?: string;
style?: CSSProperties;
};
......@@ -46,6 +47,7 @@ export const CollectionBrowserInner = ({
onClick,
pageSize = COLLECTION_PAGE_SIZE,
visibleEntityTypes = [...USER_FACING_ENTITY_NAMES],
EmptyContentComponent = null,
className,
style,
}: CollectionBrowserProps) => {
......@@ -84,6 +86,7 @@ export const CollectionBrowserInner = ({
pageSize={pageSize}
models={collectionTypes}
showActionMenu={false}
EmptyContentComponent={EmptyContentComponent ?? undefined}
/>
</Box>
);
......
......@@ -38,6 +38,18 @@ export const DEFAULT_METABASE_COMPONENT_THEME: MetabaseComponentTheme = {
hoverBackgroundColor: "var(--mb-color-brand)",
},
},
emptyContent: {
icon: {
width: "117",
height: "94",
},
title: {
fontSize: "1.5rem",
},
subtitle: {
fontSize: "1rem",
},
},
},
dashboard: {
backgroundColor: "var(--mb-color-bg-white)",
......
import type { CSSProperties } from "react";
import type { ColorName } from "metabase/lib/colors/types";
import type { MetabaseFontFamily } from "../fonts";
......@@ -135,7 +137,7 @@ export type MetabaseComponentTheme = {
scalar?: {
/** The primary numerical value */
value?: {
fontSize?: string;
fontSize?: CSSProperties["fontSize"];
lineHeight?: string;
};
};
......@@ -164,6 +166,18 @@ export type MetabaseComponentTheme = {
hoverTextColor: ColorCssVariableOrString;
};
};
emptyContent: {
icon: {
width: CSSProperties["width"];
height: CSSProperties["width"];
};
title: {
fontSize: CSSProperties["fontSize"];
};
subtitle: {
fontSize: CSSProperties["fontSize"];
};
};
};
};
......
/* eslint-disable react/prop-types */
import cx from "classnames";
import { useCallback, useEffect, useState } from "react";
import { type ComponentType, useCallback, useEffect, useState } from "react";
import {
ALL_MODELS,
......@@ -69,8 +69,23 @@ export type CollectionItemsTableProps = {
toggleItem: (item: CollectionItem) => void;
onClick: (item: CollectionItem) => void;
showActionMenu: boolean;
EmptyContentComponent?: ComponentType<{
collection?: Collection;
}>;
}>;
const DefaultEmptyContentComponent = ({
collection,
}: {
collection?: Collection;
}) => {
return (
<CollectionEmptyContent>
<CollectionEmptyState collection={collection} />
</CollectionEmptyContent>
);
};
export const CollectionItemsTable = ({
collectionId,
collection,
......@@ -91,6 +106,7 @@ export const CollectionItemsTable = ({
models = ALL_MODELS,
onClick,
showActionMenu = true,
EmptyContentComponent = DefaultEmptyContentComponent,
}: CollectionItemsTableProps) => {
const isEmbeddingSdk = useSelector(getIsEmbeddingSdk);
......@@ -168,11 +184,7 @@ export const CollectionItemsTable = ({
!loading && !hasPinnedItems && unpinnedItems.length === 0;
if (isEmpty && !loadingUnpinnedItems) {
return (
<CollectionEmptyContent>
<CollectionEmptyState collection={collection} />
</CollectionEmptyContent>
);
return <EmptyContentComponent collection={collection} />;
}
return (
......
import styled from "@emotion/styled";
export const EmptyStateRoot = styled.div`
display: flex;
flex-direction: column;
align-items: center;
`;
export const EmptyStateTitle = styled.div`
color: var(--mb-color-text-dark);
font-size: 1.5rem;
font-weight: bold;
line-height: 2rem;
margin-top: 2.5rem;
margin-bottom: 0.75rem;
`;
export const EmptyStateIconForeground = styled.path`
fill: var(--mb-color-bg-light);
stroke: var(--mb-color-brand);
......
import type { PropsWithChildren } from "react";
import { t } from "ttag";
import { isRootTrashCollection } from "metabase/collections/utils";
import NewItemMenu from "metabase/containers/NewItemMenu";
import Button from "metabase/core/components/Button";
import { color } from "metabase/lib/colors";
import { Icon, Text } from "metabase/ui";
import { Box, Icon, Stack, Text, useMantineTheme } from "metabase/ui";
import type { Collection } from "metabase-types/api";
import {
EmptyStateIconBackground,
EmptyStateIconForeground,
EmptyStateRoot,
EmptyStateTitle,
} from "./CollectionEmptyState.styled";
export interface CollectionEmptyStateProps {
......@@ -35,22 +34,22 @@ const CollectionEmptyState = ({
const TrashEmptyState = () => {
return (
<EmptyStateRoot data-testid="collection-empty-state">
<EmptyStateWrapper>
<Icon name="trash" size={80} color={color("brand-light")} />
<EmptyStateTitle>{t`Nothing here`}</EmptyStateTitle>
<Text size="1rem" color="text-medium" align="center" mb="1.5rem">
<EmptyStateSubtitle>
{t`Deleted items will appear here.`}
</Text>
</EmptyStateRoot>
</EmptyStateSubtitle>
</EmptyStateWrapper>
);
};
const ArchivedCollectionEmptyState = () => {
return (
<EmptyStateRoot data-testid="collection-empty-state">
<EmptyStateWrapper>
<CollectionEmptyIcon />
<EmptyStateTitle>{t`This collection is empty`}</EmptyStateTitle>
</EmptyStateRoot>
</EmptyStateWrapper>
);
};
......@@ -60,25 +59,32 @@ const DefaultCollectionEmptyState = ({
const canWrite = !!collection?.can_write;
return (
<EmptyStateRoot data-testid="collection-empty-state">
<EmptyStateWrapper>
<CollectionEmptyIcon />
<EmptyStateTitle>{t`This collection is empty`}</EmptyStateTitle>
<Text size="1rem" color="text-medium" align="center" mb="1.5rem">
<EmptyStateSubtitle>
{t`Use collections to organize and group dashboards and questions for your team or yourself`}
</Text>
</EmptyStateSubtitle>
{canWrite && (
<NewItemMenu
trigger={<Button icon="add">{t`Create a new…`}</Button>}
collectionId={collection?.id}
/>
)}
</EmptyStateRoot>
</EmptyStateWrapper>
);
};
const CollectionEmptyIcon = (): JSX.Element => {
const theme = useMantineTheme();
return (
<svg width="117" height="94" fill="none" xmlns="http://www.w3.org/2000/svg">
<svg
viewBox="0 0 117 94"
width={theme.other.collectionBrowser.emptyContent.icon.width}
height={theme.other.collectionBrowser.emptyContent.icon.height}
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<EmptyStateIconForeground
fillRule="evenodd"
clipRule="evenodd"
......@@ -93,5 +99,43 @@ const CollectionEmptyIcon = (): JSX.Element => {
);
};
const EmptyStateTitle = ({ children }: PropsWithChildren) => {
const theme = useMantineTheme();
return (
<Box
c="text-dark"
fz={theme.other.collectionBrowser.emptyContent.title.fontSize}
fw="bold"
lh="2rem"
mt="2.5rem"
mb="0.75rem"
>
{children}
</Box>
);
};
const EmptyStateSubtitle = ({ children }: PropsWithChildren) => {
const theme = useMantineTheme();
return (
<Text
size={theme.other.collectionBrowser.emptyContent.subtitle.fontSize}
color="text-medium"
align="center"
mb="1.5rem"
>
{children}
</Text>
);
};
const EmptyStateWrapper = ({ children }: PropsWithChildren) => {
return (
<Stack data-testid="collection-empty-state" align="center" spacing={0}>
{children}
</Stack>
);
};
// eslint-disable-next-line import/no-default-export -- deprecated usage
export default CollectionEmptyState;
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment