Skip to content

Commit

Permalink
feat: Add links to the minimap (#246)
Browse files Browse the repository at this point in the history
Co-authored-by: jared-dickman <[email protected]>
Co-authored-by: mparticle-automation <[email protected]>
  • Loading branch information
3 people authored May 30, 2024
1 parent 5319ce4 commit 80bd00c
Show file tree
Hide file tree
Showing 13 changed files with 646 additions and 211 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
## [1.15.1-minimap-linker.1](https://github.com/mParticle/aquarium/compare/v1.15.0...v1.15.1-minimap-linker.1) (2024-05-30)

# [1.15.0](https://github.com/mParticle/aquarium/compare/v1.14.0...v1.15.0) (2024-05-24)


Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@mparticle/aquarium",
"version": "1.15.0",
"version": "1.15.1-minimap-linker.1",
"description": "mParticle Component Library",
"license": "Apache-2.0",
"keywords": [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -135,9 +135,6 @@ const meta: Meta<typeof GlobalNavigation> = {
onMpHomeClick: () => {
alert('Going to mP!')
},
minimapOptions: {
show: true,
},
},
}
export default meta
Expand Down Expand Up @@ -486,12 +483,24 @@ export const MP: Story = {
tools: mpTools,
management: mpManagement,
orgs: mpOrgs,
minimapOptions: { overviewHref: '/', show: true },
minimapOptions: {
overviewHref: '/',
onLinkClick: link => alert(link.href),
onUnAuthorizedClick: link => alert(`unauthorized ${link?.href} `),
unauthorizedLinks: ['oversight', 'dataPlatform'],
links: [
{ linkId: 'oversight', href: '/oversight' },
{ linkId: 'dataPlatform', href: '/data-platform' },
{ linkId: 'customer360', href: '/customer-360' },
{ linkId: 'predictions', href: '/predictions' },
{ linkId: 'analytics', href: '/analytics' },
{ linkId: 'segmentation', href: '/segmentation' },
],
},
onMpHomeClick: () => {
alert('going to overview map')
},
avatarOptions: {
// src: "https://static-qa1.qa.corp.mparticle.com/appimg/logo_af_916397d2-9732-8de6-77cc-80e3bba120ca.png",
alt: 'avatar',
},
},
Expand All @@ -512,7 +521,6 @@ export const MPThousandOrgs: Story = {
tools={mpTools}
management={mpManagement}
orgs={thousandOrgs}
minimapOptions={{ overviewHref: '/' }}
onMpHomeClick={() => {
alert('going to overview map')
}}
Expand Down Expand Up @@ -1096,7 +1104,6 @@ export const MPWithoutLogo: Story = {
tools: mpTools,
management: mpManagement,
orgs: mpOrgs,
minimapOptions: { overviewHref: '/', show: true },
onMpHomeClick: () => {
alert('going to overview map')
},
Expand All @@ -1117,7 +1124,6 @@ export const MPWithBackgroundLogo: Story = {
tools: mpTools,
management: mpManagement,
orgs: mpOrgs,
minimapOptions: { overviewHref: '/', show: true },
onMpHomeClick: () => {
alert('going to overview map')
},
Expand All @@ -1138,7 +1144,6 @@ export const MPWithoutCustomSizeLogo: Story = {
tools: mpTools,
management: mpManagement,
orgs: mpOrgs,
minimapOptions: { overviewHref: '/', show: true },
onMpHomeClick: () => {
alert('going to overview map')
},
Expand Down
10 changes: 5 additions & 5 deletions src/components/navigation/GlobalNavigation/GlobalNavigation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,10 @@ import { NavigationSearch } from 'src/components/navigation/GlobalNavigation/Nav
import { NavigationList } from 'src/components/navigation/GlobalNavigation/NavigationList'
import { NavigationCreate } from 'src/components/navigation/GlobalNavigation/NavigationCreate'
import { WorkspaceSelector } from 'src/components/navigation/GlobalNavigation/WorkspaceSelector/WorkspaceSelector'
import { type IGlobalNavigationItem } from 'src/components/navigation/GlobalNavigation/GlobalNavigationItems'
import {
type IGlobalNavigationItem,
type IMiniMapOptions,
} from 'src/components/navigation/GlobalNavigation/GlobalNavigationItems'
import { NavigationItem } from 'src/components/navigation/GlobalNavigation/NavigationItem'
import { useNewExperienceReminder } from 'src/hooks/NewExperienceReminder/useNewExperienceReminder'
import { HomeButton } from 'src/components/navigation/GlobalNavigation/HomeButton'
Expand All @@ -37,10 +40,7 @@ export interface IGlobalNavigationProps {
onClick: () => void
withoutContainer?: boolean
}
minimapOptions: {
overviewHref?: string
show?: boolean
}
minimapOptions?: IMiniMapOptions
}

export const GlobalNavWidth = 90 as const
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,17 @@ export interface IGlobalNavigationLink extends IBaseGlobalNavigationItem {
}

export type IGlobalNavigationItem = IGlobalNavigationMenu | IGlobalNavigationLink

export type MiniMapLinks = 'oversight' | 'dataPlatform' | 'customer360' | 'predictions' | 'analytics' | 'segmentation'
export type MiniMapLink = {
linkId: MiniMapLinks
href: string
}

export interface IMiniMapOptions {
overviewHref: string
links: MiniMapLink[]
onLinkClick: (link: MiniMapLink) => void
onUnAuthorizedClick: (link?: MiniMapLink) => void
unauthorizedLinks: MiniMapLinks[]
}
86 changes: 55 additions & 31 deletions src/components/navigation/GlobalNavigation/HomeButton.tsx
Original file line number Diff line number Diff line change
@@ -1,49 +1,73 @@
import React from 'react'
import { Center, Icon, Popover, Tooltip } from 'src/components'
import MiniMap from 'src/components/navigation/MiniMap/MiniMap'
import { IMiniMapOptions } from 'src/components/navigation/GlobalNavigation/GlobalNavigationItems'

interface MpHomeButtonProps {
onClick: () => void
}

interface MinimapWithPopoverProps {
overviewHref: string
onClick: () => void
interface MinimapWithPopoverProps extends IMiniMapOptions {
onPopoverClick: () => void
}

interface TooltipWithButtonProps {
onClick: () => void
onTooltipClick: () => void
}

interface HomeButtonProps {
minimapOptions: {
overviewHref?: string
show?: boolean
}
minimapOptions?: IMiniMapOptions
onMpHomeClick: () => void
}
const MpHomeButton: React.FC<MpHomeButtonProps> = ({ onClick }) => (
<Center className="globalNavigation__mpHome" onClick={onClick}>
<Icon name="mpLogo" size="lg" color="white" />
</Center>
)

const MinimapWithPopover: React.FC<MinimapWithPopoverProps> = ({ overviewHref, onClick }) => (
<Popover content={() => <MiniMap overviewHref={overviewHref} />} placement="rightBottom" arrow={false}>
<MpHomeButton onClick={onClick} />
</Popover>
)

const TooltipWithButton: React.FC<TooltipWithButtonProps> = ({ onClick }) => (
<Tooltip title="mParticle Overview" placement="right">
<MpHomeButton onClick={onClick} />
</Tooltip>
)

export const HomeButton: React.FC<HomeButtonProps> = props => {
return props.minimapOptions?.show ? (
<MinimapWithPopover overviewHref={props.minimapOptions?.overviewHref ?? '/'} onClick={props.onMpHomeClick} />
) : (
<TooltipWithButton onClick={props.onMpHomeClick} />

function MpHomeButton(props: MpHomeButtonProps) {
return (
<Center className="globalNavigation__mpHome" onClick={props.onClick}>
<Icon name="mpLogo" size="lg" color="white" />
</Center>
)
}

function MinimapWithPopover(props: MinimapWithPopoverProps) {
return (
<Popover
content={() => (
<MiniMap
overviewHref={props.overviewHref}
onUnAuthorizedClick={props.onUnAuthorizedClick}
links={props.links}
onLinkClick={props.onLinkClick}
unauthorizedLinks={props.unauthorizedLinks}
/>
)}
placement="rightBottom"
arrow={false}>
<MpHomeButton onClick={props.onPopoverClick} />
</Popover>
)
}

function TooltipWithButton(props: TooltipWithButtonProps) {
return (
<Tooltip title="mParticle Overview" placement="right">
<MpHomeButton onClick={props.onTooltipClick} />
</Tooltip>
)
}

export function HomeButton(props: HomeButtonProps) {
if (!props.minimapOptions) {
return <TooltipWithButton onTooltipClick={props.onMpHomeClick} />
}

return (
<MinimapWithPopover
onUnAuthorizedClick={props.minimapOptions.onUnAuthorizedClick}
overviewHref={props.minimapOptions.overviewHref}
links={props.minimapOptions.links}
onLinkClick={props.minimapOptions.onLinkClick}
unauthorizedLinks={props.minimapOptions.unauthorizedLinks}
onPopoverClick={props.onMpHomeClick}
/>
)
}
39 changes: 32 additions & 7 deletions src/components/navigation/MiniMap/MiniMap.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,26 +3,51 @@ import './miniMap.css'
import React from 'react'
import { Button, ConfigProvider } from 'src/components'
import Logo from 'src/assets/svg/mp-logo-wordmark.svg?react'
import MiniMap from './miniMap.svg?react'
import { minimap } from './minimap-svg'
import { Flex } from 'src/components/layout/Flex/Flex'
export interface IMinimapProps {
overviewHref: string
}
import { ISvgLink, SvgLinker } from 'src/components/navigation/MiniMap/SvgLinker'
import { IMiniMapOptions, MiniMapLinks } from 'src/components/navigation/GlobalNavigation/GlobalNavigationItems'

type IMiniMapProps = IMiniMapOptions

const Minimap = (props: IMiniMapProps) => {
const elementIdMap: Record<MiniMapLinks, string> = {
oversight: 'OversightBtn',
dataPlatform: 'DataPlatformBtn',
customer360: 'c360Btn',
predictions: 'PredictionsBtn',
analytics: 'AnalyticsBtn',
segmentation: 'SegmentationBtn',
} as const

const svgLinks: ISvgLink[] = props.links.map(link => ({
elementId: elementIdMap[link.linkId],
href: link.href,
variant: 'drop-shadow',
isUnauthorized: props.unauthorizedLinks.includes(link.linkId),
}))

const Minimap: React.FC<IMinimapProps> = props => {
return (
<ConfigProvider>
<div className="minimap_container">
<div className="u-padding-sm">
<Flex align="normal" component="div" flex="0 1 auto" gap="small" justify="stretch" vertical wrap="nowrap">
<Flex align="center" justify="space-between">
<Logo />
<Button href={props.overviewHref || '/'}>Go to overview</Button>
</Flex>
<MiniMap />
<SvgLinker links={svgLinks} onLinkClick={handleLinkClick}>
{minimap}
</SvgLinker>
</Flex>
</div>
</ConfigProvider>
)
function handleLinkClick(svgLink: ISvgLink): void {
const miniMapLink = props.links.find(link => link.href === svgLink.href)!

if (svgLink.isUnauthorized) props.onUnAuthorizedClick(miniMapLink)
else props.onLinkClick(miniMapLink)
}
}

export default Minimap
55 changes: 55 additions & 0 deletions src/components/navigation/MiniMap/SvgLinker.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import React, { Children, ReactElement } from 'react'
import './miniMap.css'

export interface ISvgLink {
elementId: string
href: string
variant?: 'regular' | 'black' | 'drop-shadow'
isUnauthorized?: boolean
}

interface ISvgLinkerProps {
links: ISvgLink[]
children: React.ReactNode
onLinkClick: (link: ISvgLink) => void
}

export const SvgLinker = (props: ISvgLinkerProps) => {
const handleContainerClick = (e: React.MouseEvent) => {
e.preventDefault()
const target = e.target as HTMLElement
const href = target.closest('a')?.getAttribute('href')
const link = props.links.find(b => b.href === href)

if (link) props.onLinkClick(link)
}

return <div onClick={handleContainerClick}>{wrapButtonsIntoLinks(props.children)}</div>

function wrapButtonsIntoLinks(parent: React.ReactNode): React.ReactNode {
const wrapElement = (element: ReactElement): ReactElement => {
const { id, children } = element.props
const link = props.links.find(b => b.elementId === id)

if (link) {
const className = `svg-linker-root__button svg-linker-root__button--${link.variant}${
link.isUnauthorized ? ' svg-linker-root__button--disabled' : ''
}`

return (
<a key={id} href={link.href} className={className}>
{element}
</a>
)
}

const wrappedChildren = wrapButtonsIntoLinks(children)

return React.createElement(element.type, { ...element.props, children: wrappedChildren })
}

return Children.map(parent, child => (React.isValidElement(child) ? wrapElement(child as ReactElement) : child))
}
}

export default SvgLinker
Loading

0 comments on commit 80bd00c

Please sign in to comment.