From 1112674e6e5649229f3c9028a94f2115c97a1f8c Mon Sep 17 00:00:00 2001 From: Gaby Zifferman Date: Wed, 7 Aug 2024 18:56:59 +0200 Subject: [PATCH] feat: add variants to icons (#355) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Gabriel Tibúrcio Co-authored-by: mparticle-automation --- CHANGELOG.md | 14 + src/components/general/Icon/Icon.stories.tsx | 61 +++- src/components/general/Icon/Icon.tsx | 26 +- src/components/icons/index.ts | 32 +- src/constants/Icons.ts | 343 +++++++++++++++---- src/types/icons.ts | 79 +++++ 6 files changed, 448 insertions(+), 107 deletions(-) create mode 100644 src/types/icons.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index e49e6ce07..26a4f20db 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,20 @@ - Allow override theme for ConfigProvider ([#354](https://github.com/mParticle/aquarium/issues/354)) ([29cc614](https://github.com/mParticle/aquarium/commit/29cc614fe5869e80801646b33e71f3f52c640516)) +# [1.25.0-icons-variant.1](https://github.com/mParticle/aquarium/compare/v1.24.0...v1.25.0-icons-variant.1) (2024-08-06) + +### Bug Fixes + +- imports of icons ([9f5ac6c](https://github.com/mParticle/aquarium/commit/9f5ac6c047acea4bdee181f3d21e1bc080b52994)) + +### Features + +- Allow override theme for ConfigProvider ([#354](https://github.com/mParticle/aquarium/issues/354)) ([29cc614](https://github.com/mParticle/aquarium/commit/29cc614fe5869e80801646b33e71f3f52c640516)) +- icon-variants: update premium icon ([d7681d4](https://github.com/mParticle/aquarium/commit/d7681d49a0b63cc6aebb7874e72c0fb89afb8679)) +- icons-variant cleanup code ([bf83485](https://github.com/mParticle/aquarium/commit/bf83485b0867df3ee169e6b5e3ddf682f20245c0)) +- icons-variant cleanup code ([54dfc77](https://github.com/mParticle/aquarium/commit/54dfc77b8d28a9fcc0a55e9de5bdd919f607f0a3)) +- icons-variant: add documentation for icons ([28ffcc9](https://github.com/mParticle/aquarium/commit/28ffcc912eb183ee9ad16ca06149ca03ffe39544)) + # [1.24.0](https://github.com/mParticle/aquarium/compare/v1.23.0...v1.24.0) (2024-07-31) ### Features diff --git a/src/components/general/Icon/Icon.stories.tsx b/src/components/general/Icon/Icon.stories.tsx index 95c1b17ae..9a17c9932 100644 --- a/src/components/general/Icon/Icon.stories.tsx +++ b/src/components/general/Icon/Icon.stories.tsx @@ -3,8 +3,9 @@ import React, { type ReactNode } from 'react' import { Flex, Icon, type IIconProps } from 'src/components' import { Icons } from 'src/constants/Icons' -export const IconTable: React.FC = ({ color = 'black', size = 'lg', name }) => { +export const IconTable: React.FC = ({ color = 'black', size = 'lg', name, variant }) => { const allIcons = Object.keys(Icons) as Array + const iconGridStyle = { display: 'grid', gridTemplateColumns: 'repeat(6, 1fr)', @@ -13,24 +14,51 @@ export const IconTable: React.FC = ({ color = 'black', size = 'lg', justifyItems: 'center', } - return ( -
- {name // render either a single selected icon, or all possible icons - ? renderIcon(name) - : allIcons.map(renderIcon)} -
- ) + return
{name ? renderIcon(name) : allIcons.map(renderIcon)}
+ + function renderIcon(iconName: keyof typeof Icons): ReactNode { + const icon = Icons[iconName] + const isDeprecated = icon.deprecated + const textStyle = isDeprecated ? { textDecoration: 'line-through' } : {} - function renderIcon(iconName: IIconProps['name']): ReactNode { return ( - -

{iconName}

+ +

+ {isDeprecated ? 'deprecated ' : ''} + {iconName} +

) } } +const iconTableDocumentation = ` +### Icon Component Documentation + +The \`IconTable\` component is used to display a table of all available icons in the project. + +#### Props +- \`name\`: The name of the icon +- \`color\`: The color of the icon. Available options are \`default\`, \`primary\`, \`success\`, \`warning\`, \`error\`, \`info\`, \`white\`, \`black\`, \`text\`, \`strong\`, \`brand\`. +- \`size\`: The size of the icon. Available options are \`xxxxl\`, \`xxxl\`, \`xxl\`, \`xl\`, \`lg\`, \`md\`, \`sm\`, \`xs\`. +- \`variant\`: The variant of the icon. Available options are \`light\` and \`duo-tone\`. + +#### Updating Icons +To update the icons: + +1. **Add New Icons**: Add the new icon SVGs to the \`src/constants/Icons\` directory. The icons should be curated by Design and the svg must be minified. +2. **Update Icon Constants**: Update the \`Icons\` object in \`src/constants/Icons\` to include the new icons. +3. **Use Icons**: Use the updated icons in your components by referencing their names. + +#### Example Usage +\`\`\`jsx + +\`\`\` + +This will render the new icon with the specified size, color, and variant. +` + const meta: Meta = { title: 'Aquarium/General/Icons', component: IconTable, @@ -55,6 +83,17 @@ const meta: Meta = { 'brand', ], }, + variant: { + control: 'select', + options: ['light', 'duo-tone'], + }, + }, + parameters: { + docs: { + description: { + component: iconTableDocumentation, + }, + }, }, } diff --git a/src/components/general/Icon/Icon.tsx b/src/components/general/Icon/Icon.tsx index 4c157301d..d95bdb459 100644 --- a/src/components/general/Icon/Icon.tsx +++ b/src/components/general/Icon/Icon.tsx @@ -1,4 +1,6 @@ +import React from 'react' import { Icons } from 'src/constants/Icons' +import type { IconOptions, IconVariant, IconNames } from 'src/types/icons' import './icon.css' type IconSize = 'xxxxl' | 'xxxl' | 'xxl' | 'xl' | 'lg' | 'md' | 'sm' | 'xs' @@ -16,17 +18,29 @@ export type IconColor = | 'brand' export interface IIconProps { - name: keyof typeof Icons + name: IconNames color?: IconColor size?: IconSize + variant?: IconVariant } -export const Icon = (props: IIconProps) => { - const { color = 'default', size = 'lg' } = props +export const Icon: React.FC = ({ name, color = 'default', size = 'lg', variant }) => { + const icon: IconOptions = Icons[name] + + if (icon?.deprecated) { + console.warn(`Icon with name "${name}" is deprecated. Please use ${icon?.deprecated} instead.`) + } + + const iconVariant = variant ?? icon.default + const IconComponent = icon[iconVariant] ?? icon[icon.default] + + if (!IconComponent) { + console.error(`Icon with name "${name}" and variant "${iconVariant}" not found.`) + return null + } - const IconName = Icons[props.name] const className = `icon-size-${size} icon-color-${color}` - const iconId = `icon-${props.name}` + const iconId = `icon-${name}-${iconVariant}` - return + return } diff --git a/src/components/icons/index.ts b/src/components/icons/index.ts index 38ed28c63..8b4e3c370 100644 --- a/src/components/icons/index.ts +++ b/src/components/icons/index.ts @@ -1,7 +1,7 @@ import AddIcon from 'src/assets/svg/add.svg?react' import AlicornIcon from 'src/assets/svg/alicorn.svg?react' -import AnalyticsIcon from 'src/assets/svg/mp_pm_dt_analytics.svg?react' -import C360Icon from 'src/assets/svg/mp_pm_dt_c360.svg?react' +import AnalyticsIconDt from 'src/assets/svg/mp_pm_dt_analytics.svg?react' +import C360IconDt from 'src/assets/svg/mp_pm_dt_c360.svg?react' import CatalogIcon from 'src/assets/svg/mp_pm_lt_catalog.svg?react' import ChartColumnIcon from 'src/assets/svg/chart-column.svg?react' import ChartLineIcon from 'src/assets/svg/chart-line.svg?react' @@ -9,7 +9,7 @@ import CheckIcon from 'src/assets/svg/check.svg?react' import CircleNodesIcon from 'src/assets/svg/circle-nodes.svg?react' import CloudIcon from 'src/assets/svg/cloud.svg?react' import ConnectionsIcon from 'src/assets/svg/connections.svg?react' -import DataPlatform from 'src/assets/svg/mp_pm_dt_data-platform.svg?react' +import DataPlatformIconDt from 'src/assets/svg/mp_pm_dt_data-platform.svg?react' import DatabaseIcon from 'src/assets/svg/database.svg?react' import DsrIcon from 'src/assets/svg/mp_pm_lt_dsr.svg?react' import EmptyIcon from 'src/assets/svg/empty.svg?react' @@ -31,12 +31,12 @@ import PaywallIcon from 'src/assets/svg/paywall.svg?react' import MessageQuestionIcon from 'src/assets/svg/message-question.svg?react' import MpLogoIcon from 'src/assets/svg/mpLogo.svg?react' import ObservabilityIcon from 'src/assets/svg/mp_pm_lt_observability.svg?react' -import OversightIcon from 'src/assets/svg/mp_pm_dt_oversight.svg?react' -import PredictionsIconLight from 'src/assets/svg/mp_pm_lt_predictions.svg?react' -import SparklesIcon from 'src/assets/svg/mp_pm_dt_predictions.svg?react' +import OversightIconDt from 'src/assets/svg/mp_pm_dt_oversight.svg?react' +import PredictionsIcon from 'src/assets/svg/mp_pm_lt_predictions.svg?react' +import PredictionsIconDt from 'src/assets/svg/mp_pm_dt_predictions.svg?react' import RemoveIcon from 'src/assets/svg/remove.svg?react' import SearchIcon from 'src/assets/svg/search.svg?react' -import SegmentationIcon from 'src/assets/svg/mp_pm_dt_segmentation.svg?react' +import SegmentationIconDt from 'src/assets/svg/mp_pm_dt_segmentation.svg?react' import ShieldKeyholeIcon from 'src/assets/svg/shield-keyhole.svg?react' import SignoutIcon from 'src/assets/svg/signout.svg?react' import SplitIcon from 'src/assets/svg/split.svg?react' @@ -59,13 +59,13 @@ import DirectoryIcon from 'src/assets/svg/mp_pm_lt_directory.svg?react' import LockIcon from 'src/assets/svg/mp_act_lt_lock.svg?react' import UnlockIcon from 'src/assets/svg/mp_act_lt_unlock.svg?react' import NotificationIcon from 'src/assets/svg/mp_pm_lt_notification.svg?react' -import PremiumDtIcon from 'src/assets/svg/mp_info_dt_premium.svg?react' +import PremiumIconDt from 'src/assets/svg/mp_info_dt_premium.svg?react' export { AddIcon, AlicornIcon, - AnalyticsIcon, - C360Icon, + AnalyticsIconDt, + C360IconDt, CatalogIcon, ChartColumnIcon, ChartLineIcon, @@ -73,7 +73,7 @@ export { CircleNodesIcon, CloudIcon, ConnectionsIcon, - DataPlatform, + DataPlatformIconDt, DatabaseIcon, DsrIcon, EmptyIcon, @@ -96,12 +96,12 @@ export { MessageQuestionIcon, MpLogoIcon, ObservabilityIcon, - OversightIcon, - SparklesIcon, - PredictionsIconLight, + OversightIconDt, + PredictionsIconDt, + PredictionsIcon, RemoveIcon, SearchIcon, - SegmentationIcon, + SegmentationIconDt, ShieldKeyholeIcon, SignoutIcon, SplitIcon, @@ -123,5 +123,5 @@ export { LockIcon, UnlockIcon, NotificationIcon, - PremiumDtIcon, + PremiumIconDt, } diff --git a/src/constants/Icons.ts b/src/constants/Icons.ts index d236dbd79..576a3b7aa 100644 --- a/src/constants/Icons.ts +++ b/src/constants/Icons.ts @@ -1,8 +1,10 @@ +import { type IconOptions, type IconNames } from 'src/types/icons' + import { AddIcon, AlicornIcon, - AnalyticsIcon, - C360Icon, + AnalyticsIconDt, + C360IconDt, CatalogIcon, ChartColumnIcon, ChartLineIcon, @@ -10,7 +12,7 @@ import { CircleNodesIcon, CloudIcon, ConnectionsIcon, - DataPlatform, + DataPlatformIconDt, DatabaseIcon, DsrIcon, EmptyIcon, @@ -24,6 +26,7 @@ import { GridIcon, HeartIcon, HelpIcon, + HelpVideoIcon, IdentityIcon, JumpToIcon, LightBulbIcon, @@ -32,11 +35,12 @@ import { MessageQuestionIcon, MpLogoIcon, ObservabilityIcon, - OversightIcon, - PredictionsIconLight, + OversightIconDt, + PredictionsIconDt, + PredictionsIcon, RemoveIcon, SearchIcon, - SegmentationIcon, + SegmentationIconDt, ShieldKeyholeIcon, SignoutIcon, SplitIcon, @@ -49,81 +53,272 @@ import { WrenchIcon, ZoomIn, ZoomOut, - PremiumIcon, - HelpVideoIcon, + OpenTabIcon, ConversionIcon, - SparklesIcon, + PremiumIcon, NextIcon, PreviousIcon, - OpenTabIcon, DirectoryIcon, LockIcon, UnlockIcon, NotificationIcon, - PremiumDtIcon, + PremiumIconDt, } from 'src/components/icons' -export const Icons = { - C360: C360Icon, - add: AddIcon, - alicorn: AlicornIcon, - analytics: AnalyticsIcon, - catalog: CatalogIcon, - chartColumn: ChartColumnIcon, - chartLine: ChartLineIcon, - check: CheckIcon, - circleNodes: CircleNodesIcon, - cloud: CloudIcon, - connections: ConnectionsIcon, - database: DatabaseIcon, - dsr: DsrIcon, - empty: EmptyIcon, - enrichment: EnrichmentIcon, - event: EventIcon, - eventAttribute: EventAttributeIcon, - fitToScreen: FitToScreen, - folderClosed: FolderClosedIcon, - forwarding: ForwardingIcon, - gear: GearIcon, - grid: GridIcon, - heart: HeartIcon, - help: HelpIcon, - identity: IdentityIcon, - jumpTo: JumpToIcon, - lightBulb: LightBulbIcon, - liveStream: LiveStreamIcon, - paywall: PaywallIcon, - messageQuestion: MessageQuestionIcon, - mpLogo: MpLogoIcon, - observability: ObservabilityIcon, - oversight: OversightIcon, - remove: RemoveIcon, - search: SearchIcon, - segmentation: SegmentationIcon, - shieldKeyhole: ShieldKeyholeIcon, - signout: SignoutIcon, - siteMap: DataPlatform, - sparkles: SparklesIcon, - predictions: PredictionsIconLight, - split: SplitIcon, - systemAlerts: SystemAlertsIcon, - transformation: TransformationsIcon, - upload: UploadIcon, - userAttribute: UserAttributeIcon, - userProfiles: UserProfilesIcon, - users: UsersIcon, - wrench: WrenchIcon, - zoomIn: ZoomIn, - zoomOut: ZoomOut, - premium: PremiumIcon, - helpVideo: HelpVideoIcon, - conversion: ConversionIcon, - next: NextIcon, - previous: PreviousIcon, - openTab: OpenTabIcon, - directory: DirectoryIcon, - lock: LockIcon, - unlock: UnlockIcon, - notification: NotificationIcon, - premiumDt: PremiumDtIcon, +export const Icons: Record = { + add: { + light: AddIcon, + 'duo-tone': AddIcon, + default: 'duo-tone', + }, + alicorn: { + light: AlicornIcon, + default: 'light', + }, + analytics: { + 'duo-tone': AnalyticsIconDt, + default: 'duo-tone', + }, + C360: { + 'duo-tone': C360IconDt, + default: 'duo-tone', + }, + catalog: { + light: CatalogIcon, + default: 'light', + }, + chartColumn: { + light: ChartColumnIcon, + default: 'light', + }, + chartLine: { + light: ChartLineIcon, + default: 'light', + }, + check: { + light: CheckIcon, + default: 'light', + }, + circleNodes: { + light: CircleNodesIcon, + default: 'light', + }, + cloud: { + light: CloudIcon, + default: 'light', + }, + connections: { + light: ConnectionsIcon, + default: 'light', + }, + database: { + light: DatabaseIcon, + default: 'light', + }, + dsr: { + light: DsrIcon, + default: 'light', + }, + empty: { + light: EmptyIcon, + default: 'light', + }, + enrichment: { + light: EnrichmentIcon, + default: 'light', + }, + event: { + light: EventIcon, + default: 'light', + }, + eventAttribute: { + light: EventAttributeIcon, + default: 'light', + }, + fitToScreen: { + light: FitToScreen, + default: 'light', + }, + folderClosed: { + light: FolderClosedIcon, + default: 'light', + }, + forwarding: { + light: ForwardingIcon, + default: 'light', + }, + gear: { + light: GearIcon, + default: 'light', + }, + grid: { + light: GridIcon, + default: 'light', + }, + heart: { + light: HeartIcon, + default: 'light', + }, + help: { + light: HelpIcon, + default: 'light', + }, + identity: { + light: IdentityIcon, + default: 'light', + }, + jumpTo: { + light: JumpToIcon, + default: 'light', + }, + lightBulb: { + light: LightBulbIcon, + default: 'light', + }, + liveStream: { + light: LiveStreamIcon, + default: 'light', + }, + paywall: { + light: PaywallIcon, + default: 'light', + }, + messageQuestion: { + light: MessageQuestionIcon, + default: 'light', + }, + mpLogo: { + light: MpLogoIcon, + default: 'light', + }, + observability: { + light: ObservabilityIcon, + default: 'light', + }, + oversight: { + 'duo-tone': OversightIconDt, + default: 'duo-tone', + }, + remove: { + light: RemoveIcon, + default: 'light', + }, + search: { + light: SearchIcon, + default: 'light', + }, + segmentation: { + 'duo-tone': SegmentationIconDt, + default: 'duo-tone', + }, + shieldKeyhole: { + light: ShieldKeyholeIcon, + default: 'light', + }, + signout: { + light: SignoutIcon, + default: 'light', + }, + siteMap: { + 'duo-tone': DataPlatformIconDt, + default: 'duo-tone', + }, + sparkles: { + light: PredictionsIcon, + 'duo-tone': PredictionsIconDt, + default: 'duo-tone', + deprecated: 'predictions', + }, + predictions: { + light: PredictionsIcon, + 'duo-tone': PredictionsIconDt, + default: 'light', + }, + split: { + light: SplitIcon, + default: 'light', + }, + systemAlerts: { + light: SystemAlertsIcon, + default: 'light', + }, + transformation: { + light: TransformationsIcon, + default: 'light', + }, + upload: { + light: UploadIcon, + default: 'light', + }, + userAttribute: { + light: UserAttributeIcon, + default: 'light', + }, + userProfiles: { + light: UserProfilesIcon, + default: 'light', + }, + users: { + light: UsersIcon, + default: 'light', + }, + wrench: { + light: WrenchIcon, + default: 'light', + }, + zoomIn: { + light: ZoomIn, + default: 'light', + }, + zoomOut: { + light: ZoomOut, + default: 'light', + }, + premium: { + light: PremiumIcon, + 'duo-tone': PremiumIconDt, + default: 'light', + }, + premiumDt: { + light: PremiumIcon, + 'duo-tone': PremiumIconDt, + default: 'duo-tone', + deprecated: 'premium', + }, + helpVideo: { + light: HelpVideoIcon, + default: 'light', + }, + conversion: { + light: ConversionIcon, + default: 'light', + }, + next: { + light: NextIcon, + default: 'light', + }, + previous: { + light: PreviousIcon, + default: 'light', + }, + openTab: { + light: OpenTabIcon, + default: 'light', + }, + directory: { + light: DirectoryIcon, + default: 'light', + }, + lock: { + light: LockIcon, + default: 'light', + }, + unlock: { + light: UnlockIcon, + default: 'light', + }, + notification: { + light: NotificationIcon, + default: 'light', + }, } as const diff --git a/src/types/icons.ts b/src/types/icons.ts new file mode 100644 index 000000000..fa1fb7a61 --- /dev/null +++ b/src/types/icons.ts @@ -0,0 +1,79 @@ +import type { RequireAtLeastOne } from 'type-fest' + +export type IconVariant = 'light' | 'duo-tone' + +export type IconOptions = RequireAtLeastOne< + { + light?: React.ComponentType> + 'duo-tone'?: React.ComponentType> + default: IconVariant + deprecated?: string + }, + IconVariant +> + +// TODO: Mark icon names as @deprecated in ticket UNI-838. + +export type IconNames = + | 'add' + | 'alicorn' + | 'analytics' + | 'C360' + | 'catalog' + | 'chartColumn' + | 'chartLine' + | 'check' + | 'circleNodes' + | 'cloud' + | 'connections' + | 'database' + | 'dsr' + | 'empty' + | 'enrichment' + | 'event' + | 'eventAttribute' + | 'fitToScreen' + | 'folderClosed' + | 'forwarding' + | 'gear' + | 'grid' + | 'heart' + | 'help' + | 'identity' + | 'jumpTo' + | 'lightBulb' + | 'liveStream' + | 'paywall' + | 'messageQuestion' + | 'mpLogo' + | 'observability' + | 'oversight' + | 'predictions' + | 'remove' + | 'search' + | 'segmentation' + | 'shieldKeyhole' + | 'signout' + | 'siteMap' + | 'sparkles' + | 'premiumDt' + | 'split' + | 'systemAlerts' + | 'transformation' + | 'upload' + | 'userAttribute' + | 'userProfiles' + | 'users' + | 'wrench' + | 'zoomIn' + | 'zoomOut' + | 'premium' + | 'helpVideo' + | 'conversion' + | 'next' + | 'previous' + | 'openTab' + | 'directory' + | 'lock' + | 'unlock' + | 'notification'