From cab15fc1fc0826bc775c727472c628da8dfd24aa Mon Sep 17 00:00:00 2001 From: Hana Xu Date: Thu, 7 Nov 2024 15:35:00 -0500 Subject: [PATCH 01/16] add product family to create dropdown menu --- .../src/components/PrimaryNav/PrimaryLink.tsx | 12 +- .../src/components/PrimaryNav/PrimaryNav.tsx | 45 +-- .../TopMenu/AddNewMenu/AddNewMenu.tsx | 262 +++++++++++------- 3 files changed, 196 insertions(+), 123 deletions(-) diff --git a/packages/manager/src/components/PrimaryNav/PrimaryLink.tsx b/packages/manager/src/components/PrimaryNav/PrimaryLink.tsx index 788c0e4e6d0..82111d89952 100644 --- a/packages/manager/src/components/PrimaryNav/PrimaryLink.tsx +++ b/packages/manager/src/components/PrimaryNav/PrimaryLink.tsx @@ -4,14 +4,18 @@ import * as React from 'react'; import { StyledActiveLink, StyledPrimaryLinkBox } from './PrimaryNav.styles'; import type { NavEntity } from './PrimaryNav'; +import type { CreateEntity } from 'src/features/TopMenu/AddNewMenu/AddNewMenu'; -export interface PrimaryLink { - activeLinks?: Array; +export interface BaseNavLink { attr?: { [key: string]: any }; - betaChipClassName?: string; - display: NavEntity; + display: CreateEntity | NavEntity; hide?: boolean; href: string; +} + +export interface PrimaryLink extends BaseNavLink { + activeLinks?: Array; + betaChipClassName?: string; isBeta?: boolean; onClick?: (e: React.ChangeEvent) => void; } diff --git a/packages/manager/src/components/PrimaryNav/PrimaryNav.tsx b/packages/manager/src/components/PrimaryNav/PrimaryNav.tsx index fd6b10de5c5..d282f93b5c4 100644 --- a/packages/manager/src/components/PrimaryNav/PrimaryNav.tsx +++ b/packages/manager/src/components/PrimaryNav/PrimaryNav.tsx @@ -33,7 +33,6 @@ import { linkIsActive } from './utils'; import type { PrimaryLink as PrimaryLinkType } from './PrimaryLink'; export type NavEntity = - | 'Account' | 'Account' | 'Betas' | 'Cloud Load Balancers' @@ -56,10 +55,18 @@ export type NavEntity = | 'VPC' | 'Volumes'; -interface PrimaryLinkGroup { +export type ProductFamily = + | 'Compute' + | 'Databases' + | 'Monitor' + | 'More' + | 'Networking' + | 'Storage'; + +export interface ProductFamilyLinkGroup { icon?: React.JSX.Element; - links: PrimaryLinkType[]; - title?: string; + links: T; + name?: ProductFamily; } export interface PrimaryNavProps { @@ -84,7 +91,9 @@ export const PrimaryNav = (props: PrimaryNavProps) => { const { data: preferences } = usePreferences(); const { mutateAsync: updatePreferences } = useMutatePreferences(); - const primaryLinkGroups: PrimaryLinkGroup[] = React.useMemo( + const productFamilyLinkGroups: ProductFamilyLinkGroup< + PrimaryLinkType[] + >[] = React.useMemo( () => [ { links: [ @@ -132,7 +141,7 @@ export const PrimaryNav = (props: PrimaryNavProps) => { href: '/linodes/create?type=One-Click', }, ], - title: 'Compute', + name: 'Compute', }, { icon: , @@ -150,7 +159,7 @@ export const PrimaryNav = (props: PrimaryNavProps) => { href: '/volumes', }, ], - title: 'Storage', + name: 'Storage', }, { icon: , @@ -172,7 +181,7 @@ export const PrimaryNav = (props: PrimaryNavProps) => { href: '/domains', }, ], - title: 'Networking', + name: 'Networking', }, { icon: , @@ -184,7 +193,7 @@ export const PrimaryNav = (props: PrimaryNavProps) => { isBeta: isDatabasesV2Beta, }, ], - title: 'Databases', + name: 'Databases', }, { icon: , @@ -200,7 +209,7 @@ export const PrimaryNav = (props: PrimaryNavProps) => { isBeta: flags.aclp?.beta, }, ], - title: 'Monitor', + name: 'Monitor', }, { icon: , @@ -219,7 +228,7 @@ export const PrimaryNav = (props: PrimaryNavProps) => { href: '/support', }, ], - title: 'More', + name: 'More', }, ], // eslint-disable-next-line react-hooks/exhaustive-deps @@ -282,8 +291,8 @@ export const PrimaryNav = (props: PrimaryNavProps) => { - {primaryLinkGroups.map((linkGroup, idx) => { - const filteredLinks = linkGroup.links.filter((link) => !link.hide); + {productFamilyLinkGroups.map((productFamily, idx) => { + const filteredLinks = productFamily.links.filter((link) => !link.hide); if (filteredLinks.length === 0) { return null; } @@ -298,7 +307,7 @@ export const PrimaryNav = (props: PrimaryNavProps) => { ) ); if (isActiveLink) { - activeProductFamily = linkGroup.title ?? ''; + activeProductFamily = productFamily.name ?? ''; } const props = { closeMenu, @@ -311,17 +320,17 @@ export const PrimaryNav = (props: PrimaryNavProps) => { return (
- {linkGroup.title ? ( // TODO: we can remove this conditional when Managed is removed + {productFamily.name ? ( // TODO: we can remove this conditional when Managed is removed <> - {linkGroup.icon} -

{linkGroup.title}

+ {productFamily.icon} +

{productFamily.name}

} isActiveProductFamily={ - activeProductFamily === linkGroup.title + activeProductFamily === productFamily.name } expanded={!collapsedAccordions.includes(idx)} isCollapsed={isCollapsed} diff --git a/packages/manager/src/features/TopMenu/AddNewMenu/AddNewMenu.tsx b/packages/manager/src/features/TopMenu/AddNewMenu/AddNewMenu.tsx index fbf557df079..5bbbd9a4a49 100644 --- a/packages/manager/src/features/TopMenu/AddNewMenu/AddNewMenu.tsx +++ b/packages/manager/src/features/TopMenu/AddNewMenu/AddNewMenu.tsx @@ -2,38 +2,45 @@ import KeyboardArrowDown from '@mui/icons-material/KeyboardArrowDown'; import KeyboardArrowUp from '@mui/icons-material/KeyboardArrowUp'; import { Box, - ListItemIcon, Menu, MenuItem, Stack, Typography, useTheme, } from '@mui/material'; +import { styled } from '@mui/material/styles'; import * as React from 'react'; import { Link } from 'react-router-dom'; import BucketIcon from 'src/assets/icons/entityIcons/bucket.svg'; import DatabaseIcon from 'src/assets/icons/entityIcons/database.svg'; -import DomainIcon from 'src/assets/icons/entityIcons/domain.svg'; -import FirewallIcon from 'src/assets/icons/entityIcons/firewall.svg'; -import KubernetesIcon from 'src/assets/icons/entityIcons/kubernetes.svg'; import LinodeIcon from 'src/assets/icons/entityIcons/linode.svg'; import NodebalancerIcon from 'src/assets/icons/entityIcons/nodebalancer.svg'; -import OneClickIcon from 'src/assets/icons/entityIcons/oneclick.svg'; -import PlacementGroupsIcon from 'src/assets/icons/entityIcons/placement-groups.svg'; -import VolumeIcon from 'src/assets/icons/entityIcons/volume.svg'; -import VPCIcon from 'src/assets/icons/entityIcons/vpc.svg'; import { Button } from 'src/components/Button/Button'; import { useIsDatabasesEnabled } from 'src/features/Databases/utilities'; import { useIsPlacementGroupsEnabled } from 'src/features/PlacementGroups/utils'; -interface LinkProps { - attr?: { [key: string]: boolean }; - description: string; - entity: string; - hide?: boolean; - icon: React.ComponentClass; - link: string; +import type { BaseNavLink } from 'src/components/PrimaryNav/PrimaryLink'; +import type { ProductFamilyLinkGroup } from 'src/components/PrimaryNav/PrimaryNav'; + +export type CreateEntity = + | 'Bucket' + | 'Database' + | 'Domain' + | 'Firewall' + | 'Image' + | 'Kubernetes' + | 'Linode' + | 'Longview' + | 'Marketplace' + | 'NodeBalancer' + | 'Object Storage' + | 'Placement Group' + | 'VPC' + | 'Volume'; + +interface MenuLink extends BaseNavLink { + description?: string; } export const AddNewMenu = () => { @@ -52,75 +59,93 @@ export const AddNewMenu = () => { setAnchorEl(null); }; - const links: LinkProps[] = [ - { - description: 'High performance SSD Linux servers', - entity: 'Linode', - icon: LinodeIcon, - link: '/linodes/create', - }, - { - description: 'Attach additional storage to your Linode', - entity: 'Volume', - icon: VolumeIcon, - link: '/volumes/create', - }, - { - description: 'Ensure your services are highly available', - entity: 'NodeBalancer', - icon: NodebalancerIcon, - link: '/nodebalancers/create', - }, + const productFamilyLinkGroups: ProductFamilyLinkGroup[] = [ { - description: 'Create a private and isolated network', - entity: 'VPC', - icon: VPCIcon, - link: '/vpcs/create', - }, - { - description: 'Control network access to your Linodes', - entity: 'Firewall', - icon: FirewallIcon, - link: '/firewalls/create', - }, - { - description: "Control your Linodes' physical placement", - entity: 'Placement Groups', - hide: !isPlacementGroupsEnabled, - icon: PlacementGroupsIcon, - link: '/placement-groups/create', - }, - { - description: 'Manage your DNS records', - entity: 'Domain', - icon: DomainIcon, - link: '/domains/create', - }, - { - description: 'High-performance managed database clusters', - entity: 'Database', - hide: !isDatabasesEnabled, - icon: DatabaseIcon, - link: '/databases/create', + icon: , + links: [ + { + description: 'High performance SSD Linux servers', + display: 'Linode', + href: '/linodes/create', + }, + { + description: 'Capture or upload Linux images', + display: 'Image', + href: '/images/create', + }, + { + description: 'Highly available container workloads', + display: 'Kubernetes', + href: '/kubernetes/clusters/create', + }, + { + description: "Control your Linodes' physical placement", + display: 'Placement Group', + hide: !isPlacementGroupsEnabled, + href: '/placement-groups/create', + }, + { + attr: { 'data-qa-one-click-add-new': true }, + description: 'Deploy applications with ease', + display: 'Marketplace', + href: '/linodes/create?type=One-Click', + }, + ], + name: 'Compute', }, { - description: 'Highly available container workloads', - entity: 'Kubernetes', - icon: KubernetesIcon, - link: '/kubernetes/create', + icon: , + links: [ + { + description: 'S3-compatible object storage', + display: 'Bucket', + href: '/object-storage/buckets/create', + }, + { + description: 'Attach additional storage to your Linode', + display: 'Volume', + href: '/volumes/create', + }, + ], + name: 'Storage', }, { - description: 'S3-compatible object storage', - entity: 'Bucket', - icon: BucketIcon, - link: '/object-storage/buckets/create', + icon: , + links: [ + { + description: 'Create a private and isolated network', + display: 'VPC', + href: '/vpcs/create', + }, + { + description: 'Control network access to your Linodes', + display: 'Firewall', + href: '/firewalls/create', + }, + { + description: 'Ensure your services are highly available', + display: 'NodeBalancer', + href: '/nodebalancers/create', + }, + { + description: 'Manage your DNS records', + display: 'Domain', + href: '/domains/create', + }, + ], + name: 'Networking', }, { - attr: { 'data-qa-one-click-add-new': true }, - description: 'Deploy applications with ease', - entity: 'Marketplace', - icon: OneClickIcon, - link: '/linodes/create?type=One-Click', + icon: , + links: [ + { + description: 'High-performance managed database clusters', + display: 'Database', + hide: !isDatabasesEnabled, + href: '/databases/create', + }, + ], + name: 'Databases', }, ]; @@ -166,31 +191,66 @@ export const AddNewMenu = () => { onClose={handleClose} open={open} > - {links.map( - (link, i) => - !link.hide && [ - - - - - - {link.entity} - {link.description} - - , - ] - )} + {productFamilyLinkGroups.map((productFamily) => ( + <> + + {productFamily.icon} + {productFamily.name} + + {productFamily.links.map( + (link) => + !link.hide && [ + + + + {link.display} + + {link.description} + + , + ] + )} + + ))} ); }; + +export const StyledHeading = styled('h3', { + label: 'StyledHeading', +})(({ theme }) => ({ + '& svg': { + height: 16, + marginRight: theme.spacing(1), + width: 16, + }, + alignItems: 'center', + background: 'rgb(247, 247, 250)', + display: 'flex', + fontSize: '0.75rem', + letterSpacing: '0.25px', + margin: 0, + padding: '8px 10px', + textTransform: 'uppercase', +})); From ec2b4b61ab05e472f8611ed3cdd7e1fd60be88ad Mon Sep 17 00:00:00 2001 From: Hana Xu Date: Thu, 7 Nov 2024 15:37:30 -0500 Subject: [PATCH 02/16] delete unused nav components --- .../PrimaryNav/AdditionalMenuItems.tsx | 40 -------- .../src/components/PrimaryNav/NavItem.tsx | 95 ------------------- 2 files changed, 135 deletions(-) delete mode 100644 packages/manager/src/components/PrimaryNav/AdditionalMenuItems.tsx delete mode 100644 packages/manager/src/components/PrimaryNav/NavItem.tsx diff --git a/packages/manager/src/components/PrimaryNav/AdditionalMenuItems.tsx b/packages/manager/src/components/PrimaryNav/AdditionalMenuItems.tsx deleted file mode 100644 index 21ebbe2e38e..00000000000 --- a/packages/manager/src/components/PrimaryNav/AdditionalMenuItems.tsx +++ /dev/null @@ -1,40 +0,0 @@ -import * as React from 'react'; - -import Help from 'src/assets/icons/help.svg'; - -import { NavItem, PrimaryLink } from './NavItem'; - -interface Props { - closeMenu: () => void; - dividerClasses: string; - isCollapsed?: boolean; - linkClasses: (href?: string) => string; - listItemClasses: string; -} - -export const AdditionalMenuItems = React.memo((props: Props) => { - const { isCollapsed } = props; - const links: PrimaryLink[] = [ - { - QAKey: 'help', - display: 'Get Help', - href: '/support', - icon: , - }, - ]; - - return ( - - {links.map((eachLink) => { - return ( - - ); - })} - - ); -}); diff --git a/packages/manager/src/components/PrimaryNav/NavItem.tsx b/packages/manager/src/components/PrimaryNav/NavItem.tsx deleted file mode 100644 index b42ac1ebe7a..00000000000 --- a/packages/manager/src/components/PrimaryNav/NavItem.tsx +++ /dev/null @@ -1,95 +0,0 @@ -import { Divider, Tooltip } from '@linode/ui'; -import * as React from 'react'; -import { Link } from 'react-router-dom'; -import { useStyles } from 'tss-react/mui'; - -import { ListItem } from 'src/components/ListItem'; -import { ListItemText } from 'src/components/ListItemText'; - -interface Props extends PrimaryLink { - closeMenu: () => void; - dividerClasses?: string; - isCollapsed?: boolean; - linkClasses: (href?: string) => string; - listItemClasses: string; -} - -export interface PrimaryLink { - QAKey: string; - display: string; - href?: string; - icon?: JSX.Element; - isDisabled?: () => string; - logo?: React.ComponentType; - onClick?: () => void; -} - -export const NavItem = React.memo((props: Props) => { - const { - QAKey, - closeMenu, - display, - href, - icon, - isCollapsed, - isDisabled, - linkClasses, - listItemClasses, - onClick, - } = props; - - const { cx } = useStyles(); - - if (!onClick && !href) { - throw new Error('A Primary Link needs either an href or an onClick prop'); - } - - return ( - /* - href takes priority here. So if an href and onClick - are provided, the onClick will not be applied - */ - - {href ? ( - - {icon && isCollapsed &&
{icon}
} - - - ) : ( - - { - props.closeMenu(); - /* disregarding undefined is fine here because of the error handling thrown above */ - onClick!(); - }} - aria-live="polite" - className={linkClasses()} - data-qa-nav-item={QAKey} - disabled={!!isDisabled ? !!isDisabled() : false} - > - - - - )} - -
- ); -}); From f04975953022317ef72662c2a1f1a5f2fe22bebb Mon Sep 17 00:00:00 2001 From: Hana Xu Date: Wed, 13 Nov 2024 13:37:40 -0500 Subject: [PATCH 03/16] fix tab index --- .../manager/src/features/TopMenu/AddNewMenu/AddNewMenu.tsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/manager/src/features/TopMenu/AddNewMenu/AddNewMenu.tsx b/packages/manager/src/features/TopMenu/AddNewMenu/AddNewMenu.tsx index 5bbbd9a4a49..c5617f16282 100644 --- a/packages/manager/src/features/TopMenu/AddNewMenu/AddNewMenu.tsx +++ b/packages/manager/src/features/TopMenu/AddNewMenu/AddNewMenu.tsx @@ -201,8 +201,6 @@ export const AddNewMenu = () => { (link) => !link.hide && [ { // We have to do this because in packages/manager/src/index.css we force underline links textDecoration: 'none', }} + tabIndex={0} > Date: Thu, 14 Nov 2024 12:11:21 -0500 Subject: [PATCH 04/16] desktop styling --- .../src/components/PrimaryNav/PrimaryLink.tsx | 1 - .../TopMenu/AddNewMenu/AddNewMenu.tsx | 176 +++++++++++------- 2 files changed, 108 insertions(+), 69 deletions(-) diff --git a/packages/manager/src/components/PrimaryNav/PrimaryLink.tsx b/packages/manager/src/components/PrimaryNav/PrimaryLink.tsx index 82111d89952..1e7ec07d1c0 100644 --- a/packages/manager/src/components/PrimaryNav/PrimaryLink.tsx +++ b/packages/manager/src/components/PrimaryNav/PrimaryLink.tsx @@ -23,7 +23,6 @@ export interface PrimaryLink extends BaseNavLink { interface PrimaryLinkProps extends PrimaryLink { closeMenu: () => void; isActiveLink: boolean; - isBeta?: boolean; isCollapsed: boolean; } diff --git a/packages/manager/src/features/TopMenu/AddNewMenu/AddNewMenu.tsx b/packages/manager/src/features/TopMenu/AddNewMenu/AddNewMenu.tsx index c5617f16282..35b60c81daa 100644 --- a/packages/manager/src/features/TopMenu/AddNewMenu/AddNewMenu.tsx +++ b/packages/manager/src/features/TopMenu/AddNewMenu/AddNewMenu.tsx @@ -1,13 +1,7 @@ +import { Box, Divider, omittedProps } from '@linode/ui'; import KeyboardArrowDown from '@mui/icons-material/KeyboardArrowDown'; import KeyboardArrowUp from '@mui/icons-material/KeyboardArrowUp'; -import { - Box, - Menu, - MenuItem, - Stack, - Typography, - useTheme, -} from '@mui/material'; +import { Menu, MenuItem, Stack, Typography, useTheme } from '@mui/material'; import { styled } from '@mui/material/styles'; import * as React from 'react'; import { Link } from 'react-router-dom'; @@ -59,7 +53,7 @@ export const AddNewMenu = () => { setAnchorEl(null); }; - const productFamilyLinkGroups: ProductFamilyLinkGroup[] = [ + const productFamilyLinkGroup: ProductFamilyLinkGroup[] = [ { icon: , links: [ @@ -93,22 +87,6 @@ export const AddNewMenu = () => { ], name: 'Compute', }, - { - icon: , - links: [ - { - description: 'S3-compatible object storage', - display: 'Bucket', - href: '/object-storage/buckets/create', - }, - { - description: 'Attach additional storage to your Linode', - display: 'Volume', - href: '/volumes/create', - }, - ], - name: 'Storage', - }, { icon: , links: [ @@ -135,6 +113,22 @@ export const AddNewMenu = () => { ], name: 'Networking', }, + { + icon: , + links: [ + { + description: 'S3-compatible object storage', + display: 'Bucket', + href: '/object-storage/buckets/create', + }, + { + description: 'Attach additional storage to your Linode', + display: 'Volume', + href: '/volumes/create', + }, + ], + name: 'Storage', + }, { icon: , links: [ @@ -149,6 +143,46 @@ export const AddNewMenu = () => { }, ]; + const ProductFamilyGroup = ( + productFamily: ProductFamilyLinkGroup + ) => { + return ( + <> + + {productFamily.icon} + {productFamily.name} + + {productFamily.links.map( + (link) => + !link.hide && [ + + + + {link.display} + + {link.description} + + , + ] + )} + + ); + }; + return ( { paper: { // UX requested a drop shadow that didn't affect the button. // If we revise our theme's shadows, we could consider removing - sx: { boxShadow: '0 2px 3px 3px rgba(0, 0, 0, 0.1)' }, + sx: { + boxShadow: '0 2px 3px 3px rgba(0, 0, 0, 0.1)', + [theme.breakpoints.up('md')]: { + maxWidth: '100%', + paddingBottom: 1, + paddingTop: 2, + }, + }, }, }} sx={{ @@ -191,46 +232,21 @@ export const AddNewMenu = () => { onClose={handleClose} open={open} > - {productFamilyLinkGroups.map((productFamily) => ( - <> - - {productFamily.icon} - {productFamily.name} - - {productFamily.links.map( - (link) => - !link.hide && [ - - - - {link.display} - - {link.description} - - , - ] - )} - - ))} + + {productFamilyLinkGroup.slice(0, 2).map((productFamily) => ( + <> + + {ProductFamilyGroup(productFamily)} + + + + ))} + + {productFamilyLinkGroup + .slice(2) + .map((productFamily) => ProductFamilyGroup(productFamily))} + + ); @@ -238,7 +254,8 @@ export const AddNewMenu = () => { export const StyledHeading = styled('h3', { label: 'StyledHeading', -})(({ theme }) => ({ + shouldForwardProp: omittedProps(['paddingTop']), +})<{ paddingTop?: boolean }>(({ theme, ...props }) => ({ '& svg': { height: 16, marginRight: theme.spacing(1), @@ -250,6 +267,29 @@ export const StyledHeading = styled('h3', { fontSize: '0.75rem', letterSpacing: '0.25px', margin: 0, - padding: '8px 10px', + padding: '8px 12px', textTransform: 'uppercase', + [theme.breakpoints.up('lg')]: { + background: 'inherit', + padding: `${props.paddingTop ? '16px' : '0px'} 16px 8px 16px`, + }, +})); + +export const StyledMenuItem = styled(MenuItem, { + label: 'StyledMenuItem', +})(({ theme }) => ({ + padding: '8px 14px', + // We have to do this because in packages/manager/src/index.css we force underline links + textDecoration: 'none !important', + [theme.breakpoints.up('md')]: { + padding: '8px 16px', + }, +})); + +export const StyledBox = styled(Box, { + label: 'StyledBox', +})(({ theme }) => ({ + [theme.breakpoints.up('md')]: { + display: 'flex', + }, })); From 223c4015b7bcecc8b516fd6527ac50527cf228b3 Mon Sep 17 00:00:00 2001 From: Hana Xu Date: Fri, 15 Nov 2024 11:31:28 -0500 Subject: [PATCH 05/16] fix tabbing --- .../TopMenu/AddNewMenu/AddNewMenu.tsx | 99 +++++++++---------- 1 file changed, 49 insertions(+), 50 deletions(-) diff --git a/packages/manager/src/features/TopMenu/AddNewMenu/AddNewMenu.tsx b/packages/manager/src/features/TopMenu/AddNewMenu/AddNewMenu.tsx index 35b60c81daa..dd1d0fb4c85 100644 --- a/packages/manager/src/features/TopMenu/AddNewMenu/AddNewMenu.tsx +++ b/packages/manager/src/features/TopMenu/AddNewMenu/AddNewMenu.tsx @@ -1,7 +1,14 @@ -import { Box, Divider, omittedProps } from '@linode/ui'; +import { Box, Divider, Paper, omittedProps } from '@linode/ui'; import KeyboardArrowDown from '@mui/icons-material/KeyboardArrowDown'; import KeyboardArrowUp from '@mui/icons-material/KeyboardArrowUp'; -import { Menu, MenuItem, Stack, Typography, useTheme } from '@mui/material'; +import { + MenuItem, + MenuList, + Popover, + Stack, + Typography, + useTheme, +} from '@mui/material'; import { styled } from '@mui/material/styles'; import * as React from 'react'; import { Link } from 'react-router-dom'; @@ -203,51 +210,50 @@ export const AddNewMenu = () => { > Create - - - {productFamilyLinkGroup.slice(0, 2).map((productFamily) => ( - <> - - {ProductFamilyGroup(productFamily)} - - - - ))} - - {productFamilyLinkGroup - .slice(2) - .map((productFamily) => ProductFamilyGroup(productFamily))} - - - + ({ + padding: `${theme.spacing(1)} 0`, + [theme.breakpoints.down('sm')]: { + padding: 0, + }, + })} + > + ({ + [theme.breakpoints.up('md')]: { + display: 'flex', + }, + })} + > + {productFamilyLinkGroup.slice(0, 2).map((productFamily) => ( + <> + + {ProductFamilyGroup(productFamily)} + + + + ))} + + {productFamilyLinkGroup + .slice(2) + .map((productFamily) => ProductFamilyGroup(productFamily))} + + + + ); }; @@ -264,6 +270,7 @@ export const StyledHeading = styled('h3', { alignItems: 'center', background: 'rgb(247, 247, 250)', display: 'flex', + fontFamily: 'LatoWebBold', fontSize: '0.75rem', letterSpacing: '0.25px', margin: 0, @@ -271,7 +278,7 @@ export const StyledHeading = styled('h3', { textTransform: 'uppercase', [theme.breakpoints.up('lg')]: { background: 'inherit', - padding: `${props.paddingTop ? '16px' : '0px'} 16px 8px 16px`, + padding: `${props.paddingTop ? '16px' : '8px'} 16px 6px 16px`, }, })); @@ -285,11 +292,3 @@ export const StyledMenuItem = styled(MenuItem, { padding: '8px 16px', }, })); - -export const StyledBox = styled(Box, { - label: 'StyledBox', -})(({ theme }) => ({ - [theme.breakpoints.up('md')]: { - display: 'flex', - }, -})); From 5adae13cac7e1624f8f2e67353a1d2f08fb70896 Mon Sep 17 00:00:00 2001 From: Hana Xu Date: Fri, 15 Nov 2024 12:18:54 -0500 Subject: [PATCH 06/16] clean up --- .../TopMenu/AddNewMenu/AddNewMenu.styles.ts | 64 ++++++++++++ .../TopMenu/AddNewMenu/AddNewMenu.tsx | 97 +++---------------- 2 files changed, 80 insertions(+), 81 deletions(-) create mode 100644 packages/manager/src/features/TopMenu/AddNewMenu/AddNewMenu.styles.ts diff --git a/packages/manager/src/features/TopMenu/AddNewMenu/AddNewMenu.styles.ts b/packages/manager/src/features/TopMenu/AddNewMenu/AddNewMenu.styles.ts new file mode 100644 index 00000000000..f8dbe13bf05 --- /dev/null +++ b/packages/manager/src/features/TopMenu/AddNewMenu/AddNewMenu.styles.ts @@ -0,0 +1,64 @@ +import { Paper, omittedProps } from '@linode/ui'; +import { MenuItem, MenuList, Typography } from '@mui/material'; +import { styled } from '@mui/material/styles'; + +export const StyledHeading = styled('h3', { + label: 'StyledHeading', + shouldForwardProp: omittedProps(['paddingTop']), +})<{ paddingTop?: boolean }>(({ theme, ...props }) => ({ + '& svg': { + height: 16, + marginRight: theme.spacing(1), + width: 16, + }, + alignItems: 'center', + background: 'rgb(247, 247, 250)', + display: 'flex', + fontFamily: 'LatoWebBold', + fontSize: '0.75rem', + letterSpacing: '0.25px', + margin: 0, + padding: '8px 12px', + textTransform: 'uppercase', + [theme.breakpoints.up('lg')]: { + background: 'inherit', + padding: `${props.paddingTop ? '16px' : '8px'} 16px 6px 16px`, + }, +})); + +export const StyledMenuItem = styled(MenuItem, { + label: 'StyledMenuItem', +})(({ theme }) => ({ + padding: '8px 14px', + // We have to do this because in packages/manager/src/index.css we force underline links + textDecoration: 'none !important', + [theme.breakpoints.up('md')]: { + padding: '8px 16px', + }, +})) as typeof MenuItem; + +export const StyledPaper = styled(Paper, { + label: 'StyledPaper', +})(({ theme }) => ({ + padding: `${theme.spacing(1)} 0`, + [theme.breakpoints.down('sm')]: { + padding: 0, + }, +})); + +export const StyledMenuList = styled(MenuList, { + label: 'StyledMenuList', +})(({ theme }) => ({ + [theme.breakpoints.up('md')]: { + display: 'flex', + }, +})); + +export const StyledLinkTypography = styled(Typography, { + label: 'StyledLinkTypography', +})(({ theme }) => ({ + color: theme.color.offBlack, + fontFamily: theme.font.bold, + fontSize: '1rem', + lineHeight: '1.4rem', +})); diff --git a/packages/manager/src/features/TopMenu/AddNewMenu/AddNewMenu.tsx b/packages/manager/src/features/TopMenu/AddNewMenu/AddNewMenu.tsx index dd1d0fb4c85..3d4e1ff6fe4 100644 --- a/packages/manager/src/features/TopMenu/AddNewMenu/AddNewMenu.tsx +++ b/packages/manager/src/features/TopMenu/AddNewMenu/AddNewMenu.tsx @@ -1,15 +1,7 @@ -import { Box, Divider, Paper, omittedProps } from '@linode/ui'; +import { Box, Divider } from '@linode/ui'; import KeyboardArrowDown from '@mui/icons-material/KeyboardArrowDown'; import KeyboardArrowUp from '@mui/icons-material/KeyboardArrowUp'; -import { - MenuItem, - MenuList, - Popover, - Stack, - Typography, - useTheme, -} from '@mui/material'; -import { styled } from '@mui/material/styles'; +import { Popover, Stack, Typography } from '@mui/material'; import * as React from 'react'; import { Link } from 'react-router-dom'; @@ -21,6 +13,14 @@ import { Button } from 'src/components/Button/Button'; import { useIsDatabasesEnabled } from 'src/features/Databases/utilities'; import { useIsPlacementGroupsEnabled } from 'src/features/PlacementGroups/utils'; +import { + StyledHeading, + StyledLinkTypography, + StyledMenuItem, + StyledMenuList, + StyledPaper, +} from './AddNewMenu.styles'; + import type { BaseNavLink } from 'src/components/PrimaryNav/PrimaryLink'; import type { ProductFamilyLinkGroup } from 'src/components/PrimaryNav/PrimaryNav'; @@ -32,7 +32,6 @@ export type CreateEntity = | 'Image' | 'Kubernetes' | 'Linode' - | 'Longview' | 'Marketplace' | 'NodeBalancer' | 'Object Storage' @@ -45,7 +44,6 @@ interface MenuLink extends BaseNavLink { } export const AddNewMenu = () => { - const theme = useTheme(); const [anchorEl, setAnchorEl] = React.useState(null); const open = Boolean(anchorEl); @@ -171,16 +169,7 @@ export const AddNewMenu = () => { {...link.attr} > - - {link.display} - + {link.display} {link.description} , @@ -191,13 +180,7 @@ export const AddNewMenu = () => { }; return ( - +