diff --git a/src/components/Examples/ExamplesContent.tsx b/src/components/Examples/ExamplesContent.tsx index 6a4a4a916b..4ed10e4457 100644 --- a/src/components/Examples/ExamplesContent.tsx +++ b/src/components/Examples/ExamplesContent.tsx @@ -6,7 +6,7 @@ import { ImageProps } from '../Image'; import { examples, products } from '../../data/examples/'; import { filterSearchExamples } from './filter-search-examples'; import ExamplesNoResults from './ExamplesNoResults'; -import { ProductName } from '@ably/ui/core/ProductTile/data'; +import { ProductName } from 'src/components/ui/ProductTile/data'; import { useLocation } from '@reach/router'; export type SelectedFilters = { products: ProductName[]; useCases: string[] }; diff --git a/src/components/Examples/ExamplesFilter.tsx b/src/components/Examples/ExamplesFilter.tsx index b2ac11a9a3..31a3f58f0e 100644 --- a/src/components/Examples/ExamplesFilter.tsx +++ b/src/components/Examples/ExamplesFilter.tsx @@ -9,7 +9,7 @@ import ExamplesCheckbox from './ExamplesCheckbox'; import { SelectedFilters } from './ExamplesContent'; import { useOnClickOutside } from 'src/hooks/use-on-click-outside'; import { navigate } from 'gatsby'; -import { ProductName } from '@ably/ui/core/ProductTile/data'; +import { ProductName } from 'src/components/ui/ProductTile/data'; import { AdjustmentsHorizontalIcon, MagnifyingGlassIcon, XMarkIcon } from '@heroicons/react/24/outline'; // Matches Tailwind's `sm` screen (768px), where the filter switches from the diff --git a/src/components/Examples/ExamplesGrid.tsx b/src/components/Examples/ExamplesGrid.tsx index 285925a667..abb033eeab 100644 --- a/src/components/Examples/ExamplesGrid.tsx +++ b/src/components/Examples/ExamplesGrid.tsx @@ -2,7 +2,7 @@ import React, { useCallback } from 'react'; import Badge from 'src/components/ui/Badge'; import Icon from 'src/components/Icon'; import { IconName } from 'src/components/Icon/types'; -import { ProductName, products as dataProducts } from '@ably/ui/core/ProductTile/data'; +import { ProductName, products as dataProducts } from 'src/components/ui/ProductTile/data'; import cn from 'src/utilities/cn'; import { Image, ImageProps } from '../Image'; import { DEFAULT_EXAMPLE_LANGUAGES } from '../../data/examples/'; diff --git a/src/components/Homepage/PlatformAndProducts.tsx b/src/components/Homepage/PlatformAndProducts.tsx index 7ae8e40019..ee72ecc5c0 100644 --- a/src/components/Homepage/PlatformAndProducts.tsx +++ b/src/components/Homepage/PlatformAndProducts.tsx @@ -1,4 +1,4 @@ -import ProductTile from '@ably/ui/core/ProductTile'; +import ProductTile from 'src/components/ui/ProductTile'; import cn from 'src/utilities/cn'; import { Image, ImageProps, getImageFromList } from 'src/components/Image'; import type { PlatformProductsSectionData, PlatformCardData } from 'src/data/content/types'; diff --git a/src/components/ui/ProductTile.tsx b/src/components/ui/ProductTile.tsx new file mode 100644 index 0000000000..dbd2bcbc90 --- /dev/null +++ b/src/components/ui/ProductTile.tsx @@ -0,0 +1,180 @@ +import React from 'react'; +import { ArrowRightIcon } from '@heroicons/react/16/solid'; +import cn from 'src/utilities/cn'; +import { IconSize } from 'src/components/Icon/types'; +import LinkButton from './LinkButton'; +import { ProductName, products } from './ProductTile/data'; +import ProductIcon from './ProductTile/ProductIcon'; +import ProductLabel from './ProductTile/ProductLabel'; +import ProductDescription from './ProductTile/ProductDescription'; + +/** + * Props for the ProductTile component. + */ +export type ProductTileProps = { + /** + * The name of the product. + */ + name: ProductName; + + /** + * Indicates if the product tile is selected. If `undefined`, the product tile is not selectable. + * @default false + */ + selected?: boolean; + + /** + * Indicates if the product tile is on the "current" page. Changes CTA copy. + * @default false + */ + currentPage?: boolean; + + /** + * Additional CSS class names to apply to the product tile outer container. + */ + className?: string; + + /** + * Additional CSS class names to apply to the product description container. + */ + descriptionClassName?: string; + + /** + * Additional CSS class names to apply to the product name / label container. + */ + labelClassName?: string; + + /** + * Additional CSS class names to apply to the product icon. + */ + iconClassName?: string; + + /** + * Callback function to handle click events on the product tile. + */ + + onClick?: () => void; + + /** + * Indicates if the product description should be shown. + * @default true + */ + showDescription?: boolean; + + /** + * Indicates if the product label should be shown. + * @default true + */ + showLabel?: boolean; + + /** + * The size of the product icon. + * @default "40px" + */ + size?: IconSize; + + /** + * Indicates if the product icons should be animated. + * @default false + */ + animateIcons?: boolean; +}; + +const CONTAINER_GAP_RATIO = 3; + +const ProductTile = ({ + name, + selected, + currentPage, + className, + onClick, + showDescription = true, + showLabel = true, + size = '40px', + animateIcons = false, + descriptionClassName, + labelClassName, + iconClassName, +}: ProductTileProps) => { + const { icon, hoverIcon, label, description, link, unavailable } = products[name] ?? {}; + const numericalSize = parseInt(size, 10); + const containerPresent = showDescription || showLabel; + + return ( +