Skip to content

Commit

Permalink
Merge pull request #330 from WestpacGEL/313-gel-site-brand-selector-d…
Browse files Browse the repository at this point in the history
…ropdown-visual-and-interaction-differences

313 gel site brand selector dropdown visual and interaction differences
  • Loading branch information
samithaf authored Nov 22, 2023
2 parents 287361d + 3bb4ee5 commit c5363e3
Show file tree
Hide file tree
Showing 9 changed files with 121 additions and 55 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,11 @@ export function ActionBar() {
}}
aria-label="Change brand"
>
{BANK_OPTIONS.map(({ icon, key, label }) => (
{BANK_OPTIONS.map(({ icon: Icon, homePageClasses, key, label }) => (
<BrandSelect.Option href={`/design-system?brand=${key}`} key={key} textValue={label}>
<div className="flex w-full items-center justify-between">
<span className="typography-body-10">{label}</span>
{icon}
<Icon className={homePageClasses} />
</div>
</BrandSelect.Option>
))}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import { useState } from 'react';

import { formatComponentSlug } from '@/utils/format';

import { useSidebar } from '../../sidebar.context';

import { itemStyles } from './navigation.styles';
import { GroupProps, ItemProps, Level, ListProps, NavigationProps } from './navigation.types';

Expand Down Expand Up @@ -80,10 +82,13 @@ function Group({ label, level, crumbs, children, ...props }: GroupProps) {
function Item({ label, path, level, crumbs, brand, ...props }: ItemProps) {
const href = `/design-system/${path}?brand=${brand}`;
const active = crumbs[crumbs.length - 1] === label;
const { setOpen } = useSidebar();

return (
<li {...props}>
<Link
href={href}
onClick={() => setOpen(false)}
className={itemStyles({ level: level.toString() as Level, type: 'link', nested: level > 0, active })}
>
{formatComponentSlug(label)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@ import { tv } from 'tailwind-variants';

export const styles = tv(
{
base: 'flex h-10 cursor-pointer items-center justify-between border-t border-t-border bg-white px-3 py-[0.625rem] transition-colors first:border-t-0 hover:bg-light focus:bg-light',
base: 'box-content flex h-[2.5rem] cursor-pointer items-center justify-between border-t border-t-border bg-white px-3 py-[0.625rem] transition-colors first:border-t-0 hover:bg-light focus:bg-light',
variants: {
isFocused: {
true: 'bg-light',
},
isSelected: {
true: 'text-primary',
true: 'font-bold text-primary',
},
isDisabled: {
true: 'text-muted',
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
import { clsx } from 'clsx';
import { AnimatePresence, LazyMotion, m } from 'framer-motion';
import { useRef } from 'react';
import { DismissButton, Overlay, usePopover } from 'react-aria';

import { PopoverProps } from './popover.types';

const loadAnimations = () => import('./popover.utils').then(res => res.default);

export function Popover(props: PopoverProps) {
const ref = useRef<HTMLDivElement>(null);
const { popoverRef = ref, state, children, className, isNonModal } = props;
const { popoverRef = ref, state, children, className, isNonModal, portalContainer } = props;
const { popoverProps, underlayProps } = usePopover(
{
...props,
Expand All @@ -16,7 +19,7 @@ export function Popover(props: PopoverProps) {
);

return (
<Overlay>
<Overlay portalContainer={portalContainer}>
{!isNonModal && <div {...underlayProps} className="fixed inset-0" />}

<div
Expand All @@ -25,7 +28,30 @@ export function Popover(props: PopoverProps) {
className={clsx('z-10 border border-border bg-white shadow-lg', className)}
>
{!isNonModal && <DismissButton onDismiss={state.close} />}
{children}
<LazyMotion features={loadAnimations}>
<AnimatePresence initial mode="wait">
{state.isOpen && (
<m.div
className="overflow-hidden"
initial={{
height: 0,
opacity: 0,
}}
animate={{
height: 'auto',
opacity: 1,
}}
exit={{
height: 0,
opacity: 0,
}}
transition={{ duration: 0.3, ease: 'easeInOut' }}
>
{children}
</m.div>
)}
</AnimatePresence>
</LazyMotion>
<DismissButton onDismiss={state.close} />
</div>
</Overlay>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,6 @@ export type PopoverProps = Omit<AriaPopoverProps, 'popoverRef'> & {
children: React.ReactNode;
className?: string;
popoverRef?: React.RefObject<HTMLDivElement>;
portalContainer?: Element;
state: OverlayTriggerState;
} & HTMLAttributes<Element>;
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { domAnimation } from 'framer-motion';

export default domAnimation;
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { type SidebarSelectProps } from './sidebar-select.types';
export function SidebarSelect(props: SidebarSelectProps) {
// Create state based on the incoming props
const state = useSelectState(props);
const portalContainreRef = useRef<HTMLDivElement>(null);

// Get props for child elements from useSelect
const ref = useRef(null);
Expand All @@ -32,20 +33,26 @@ export function SidebarSelect(props: SidebarSelectProps) {

<button {...mergeProps(buttonProps, focusProps)} ref={ref} className={styles.button()}>
<div className={styles.textWrapper()}>
<div className="w-full" {...valueProps}>
{state.selectedItem ? state.selectedItem.rendered : 'Select an option'}
<div className="typography-body-11 w-full text-left leading-normal" {...valueProps}>
Change brand
</div>
</div>
<div aria-hidden="true" className={styles.iconWrapper()}>
{state.isOpen ? <ExpandLessIcon /> : <ExpandMoreIcon />}
</div>
{/* <SelectorIcon className={`h-5 w-5 ${isFocusVisible ? 'text-pink-500' : 'text-gray-500'}`} /> */}
</button>
{state.isOpen && (
<Popover state={state} triggerRef={ref} placement="bottom start" className={styles.popover()}>
<ListBox {...menuProps} state={state} />
</Popover>
)}
<div ref={portalContainreRef} />
<Popover
isNonModal
portalContainer={portalContainreRef.current ?? undefined}
state={state}
triggerRef={ref}
placement="bottom start"
className={styles.popover()}
>
<ListBox {...menuProps} state={state} />
</Popover>
</div>
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import React, { Key, useCallback, useEffect, useRef, useState } from 'react';
import { useOnClickOutside } from 'usehooks-ts';

import { BrandKey } from '@/app/types/brand.types';
import { CloseIcon } from '@/components/code/code.inject-components';
import { BANK_OPTIONS } from '@/constants/bank-options';

import { BackToGelSvg, Logo, Navigation, SidebarSelect } from './components';
Expand Down Expand Up @@ -53,41 +54,52 @@ export function Sidebar({ items }: SidebarProps) {
);

return (
<div
className={clsx(
'fixed top-0 z-[60] flex h-full w-[18.75rem] grow-0 flex-col border-r-0 bg-white text-text shadow-2xl transition-transform ease-in-out lg:bottom-0 lg:h-auto lg:-translate-x-0 lg:border-r lg:border-r-border lg:shadow-none',
{
'-translate-x-full': !open, //hide sidebar to the left when closed
},
)}
ref={outsideRef}
>
<Link href="/" className="flex h-15 items-center px-3" aria-label="GEL home">
<Logo brand={brand} />
</Link>
<div className="border-b border-b-border">
<SidebarSelect selectedKey={brand} onSelectionChange={handleChange} aria-label="Change brand">
{BANK_OPTIONS.map(({ icon, key, label }) => (
<SidebarSelect.Option key={key} textValue={label}>
<div className="flex w-full items-center justify-between">
<span className="typography-body-10">{label}</span>
{icon}
</div>
</SidebarSelect.Option>
))}
</SidebarSelect>
</div>
<nav
ref={listRef}
className={clsx('flex-1 overflow-y-auto overflow-x-hidden pb-4 transition-all', {
'shadow-[inset_rgba(0,0,0,0.26)_0_2px_5px]': scrolled,
})}
<>
<div
className={clsx(
'fixed top-0 z-[60] flex h-full w-[18.75rem] grow-0 flex-col border-r-0 bg-white text-text shadow-2xl transition-transform ease-in-out lg:bottom-0 lg:h-auto lg:-translate-x-0 lg:border-r lg:border-r-border lg:shadow-none',
{
'-translate-x-full': !open, //hide sidebar to the left when closed
},
)}
ref={outsideRef}
>
<Link href="/" className="block" aria-label="Back to GEL">
<BackToGelSvg />
<button className="absolute right-1 top-1 block h-6 w-6 p-1 md:hidden" onClick={() => setOpen(false)}>
<CloseIcon className="block text-muted" />
</button>
<Link href="/" className="flex h-15 items-center px-3" aria-label="GEL home">
<Logo brand={brand} />
</Link>
<Navigation items={items} brand={brand} />
</nav>
</div>
<div className="border-b border-b-border">
<SidebarSelect selectedKey={brand} onSelectionChange={handleChange} aria-label="Change brand">
{BANK_OPTIONS.map(({ icon: Icon, designSystemPageClasses, key, label }) => (
<SidebarSelect.Option key={key} textValue={label}>
<div className="flex w-full items-center justify-between">
<span className="typography-body-10">{label}</span>
{<Icon className={designSystemPageClasses} />}
</div>
</SidebarSelect.Option>
))}
</SidebarSelect>
</div>
<nav
ref={listRef}
className={clsx('flex-1 overflow-y-auto overflow-x-hidden pb-4 transition-all', {
'shadow-[inset_rgba(0,0,0,0.26)_0_2px_5px]': scrolled,
})}
>
<Link href="/" className="block" aria-label="Back to GEL">
<BackToGelSvg />
</Link>
<Navigation items={items} brand={brand} />
</nav>
</div>
<div
aria-hidden="true"
className={clsx({
'before:bg-black/40 z-[59] before:top-0 before:left-0 before:right-0 before:bottom-0 before:fixed': open,
})}
/>
</>
);
}
26 changes: 19 additions & 7 deletions apps/site/src/constants/bank-options.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,31 +4,43 @@ export const BANK_OPTIONS = [
{
key: 'wbc',
label: 'Westpac',
icon: <WBCLogo className="mr-1 block h-3 w-[2.75rem]" />,
icon: WBCLogo,
homePageClasses: 'mr-1 block h-3 w-[2.75rem]',
designSystemPageClasses: 'block h-3 w-[2.75rem]',
},
{
key: 'stg',
label: 'St.George',
icon: <STGDragonLogo className="block h-[2.375rem] w-9" />,
icon: STGDragonLogo,
homePageClasses: 'block h-[2.375rem] w-9',
designSystemPageClasses: 'block -mr-2 h-[2.375rem] w-9',
},
{
key: 'bom',
label: 'Bank of Melbourne',
icon: <BOMShieldLogo className="mr-[1rem] block h-[2.4375rem] w-[1.625rem]" />,
icon: BOMShieldLogo,
homePageClasses: 'mr-[1rem] block h-[2.4375rem] w-[1.625rem]',
designSystemPageClasses: 'block mr-[0.5rem] h-[2.4375rem] w-[1.625rem]',
},
{
key: 'bsa',
label: 'Bank SA',
icon: <BSAStackedLogo className="mr-[1rem] block h-[2.875rem] w-[1.6875rem]" />,
icon: BSAStackedLogo,
homePageClasses: 'mr-[1rem] block h-[2.875rem] w-[1.6875rem]',
designSystemPageClasses: 'block mr-[0.5rem] h-[2.875rem] w-[1.6875rem]',
},
{
key: 'wbg',
label: 'Westpac Group',
icon: <WBGLogo className="mr-[-0.5rem] block h-[0.5625rem] w-[4.375rem]" />,
icon: WBGLogo,
homePageClasses: 'mr-[-0.5rem] block h-[0.5625rem] w-[4.375rem]',
designSystemPageClasses: 'mr-[-0.5rem] block h-[0.5625rem] w-[4.375rem]',
},
{
key: 'rams',
label: 'Rams',
icon: <RAMSLogo className="mr-[-0.3125rem] block h-5 w-[3.4375rem]" />,
label: 'RAMS',
icon: RAMSLogo,
homePageClasses: 'mr-[-0.3125rem] block h-5 w-[3.4375rem]',
designSystemPageClasses: 'mr-[-0.5625rem] block h-6 w-[4.375rem]',
},
];

1 comment on commit c5363e3

@vercel
Copy link

@vercel vercel bot commented on c5363e3 Nov 22, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

gel-next-site – ./apps/site

gel-next-site.vercel.app
gel-next-site-git-main-westpacgel.vercel.app
gel-next-site-westpacgel.vercel.app

Please sign in to comment.