Skip to content

Commit

Permalink
feat(ux): Shrink maximised side menu (#2541)
Browse files Browse the repository at this point in the history
  • Loading branch information
rossbulat authored Feb 18, 2025
1 parent 8d72615 commit 2708b07
Show file tree
Hide file tree
Showing 14 changed files with 126 additions and 193 deletions.
8 changes: 3 additions & 5 deletions packages/app/src/common-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -135,11 +135,7 @@ export interface PageItem {
hash: string
Entry: FC<PageProps>
lottie: AnyJson
action?: {
type: string
status: string
text?: string | undefined
}
bullet?: BulletType
}

export type PagesConfigItems = PageItem[]
Expand All @@ -157,3 +153,5 @@ export type AnyApi = any

// eslint-disable-next-line @typescript-eslint/no-explicit-any
export type AnyMetaBatch = any

export type BulletType = 'success' | 'accent' | 'warning' | 'danger'
60 changes: 17 additions & 43 deletions packages/app/src/library/SideMenu/Main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,15 +29,15 @@ export const Main = () => {
const { pathname } = useLocation()
const { inPool } = useActivePool()
const { networkData } = useNetwork()
const {
getPoolSetupPercent,
getNominatorSetupPercent,
}: SetupContextInterface = useSetup()
const { getNominations } = useBalances()
const { getBondedAccount } = useBonded()
const { accounts } = useImportedAccounts()
const { formatWithPrefs } = useValidators()
const { activeAccount } = useActiveAccounts()
const {
getPoolSetupPercent,
getNominatorSetupPercent,
}: SetupContextInterface = useSetup()
const { sideMenuMinimised }: UIContextInterface = useUi()
const { inSetup: inNominatorSetup, addressDifferentToStash } = useStaking()

Expand All @@ -54,64 +54,41 @@ export const Main = () => {
pages: Object.assign(PagesConfig),
})

// Configure side menu bullets for active account
useEffect(() => {
if (!accounts.length) {
return
}

// inject actions into menu items
const pages = Object.assign(pageConfig.pages)
// Inject actions into menu items
const pages: PageItem[] = Object.assign(pageConfig.pages)

let i = 0
for (const { uri } of pages) {
// set undefined action as default
pages[i].action = undefined
if (uri === `${import.meta.env.BASE_URL}`) {
const warning = !syncing && controllerDifferentToStash
if (warning) {
pages[i].action = {
type: 'bullet',
status: 'warning',
}
pages[i].bullet = 'warning'
}
}

if (uri === `${import.meta.env.BASE_URL}nominate`) {
// configure Stake action
const staking = !inNominatorSetup()
const warning =
(!syncing && controllerDifferentToStash) ||
(!inNominatorSetup() && fullCommissionNominees.length > 0)

if (staking) {
pages[i].action = {
type: 'text',
status: 'success',
text: t('active'),
}
pages[i].bullet = 'accent'
}
if (warning) {
pages[i].action = {
type: 'bullet',
status: 'warning',
}
if (
(!syncing && controllerDifferentToStash) ||
(!inNominatorSetup() && fullCommissionNominees.length > 0)
) {
pages[i].bullet = 'warning'
}
}

if (uri === `${import.meta.env.BASE_URL}pools`) {
// configure Pools action

if (inPool()) {
pages[i].action = {
type: 'text',
status: 'success',
text: t('active'),
}
pages[i].bullet = 'accent'
}
}
i++
}

setPageConfig({
categories: pageConfig.categories,
pages,
Expand All @@ -137,22 +114,19 @@ export const Main = () => {
{pageConfig.categories.map(
({ id: categoryId, key: categoryKey }: PageCategory) => (
<div className="inner" key={`sidemenu_category_${categoryId}`}>
{/* display heading if not `default` (used for top links) */}
{categoryKey !== 'default' && (
<Heading title={t(categoryKey)} minimised={sideMenuMinimised} />
)}

{/* display category links */}
{pagesToDisplay.map(
({ category, hash, key, lottie, action }: PageItem) => (
({ category, hash, key, lottie, bullet }: PageItem) => (
<Fragment key={`sidemenu_page_${categoryId}_${key}`}>
{category === categoryId && (
<Primary
name={t(key)}
to={hash}
active={hash === pathname}
lottie={lottie}
action={action}
bullet={bullet}
minimised={sideMenuMinimised}
/>
)}
Expand Down
51 changes: 5 additions & 46 deletions packages/app/src/library/SideMenu/Primary/Wrappers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ export const Wrapper = styled(motion.div)`
margin: 0.7rem 0.2rem 0.5rem 0;
padding: 0.65rem 0rem;
&.success {
&.success,
&.accent {
border: 1px solid var(--accent-color-primary);
}
&.warning {
Expand All @@ -34,9 +35,9 @@ export const Wrapper = styled(motion.div)`
.dotlottie {
color: var(--text-color-primary);
margin-left: 0.25rem;
margin-right: 0.65rem;
width: 1.35rem;
height: 1.35rem;
margin-right: 0.5rem;
width: 1.2rem;
height: 1.2rem;
.fa-icon {
margin: 0 0.15rem;
}
Expand All @@ -52,48 +53,6 @@ export const Wrapper = styled(motion.div)`
padding: 0;
line-height: 1.35rem;
}
.action {
color: var(--status-success-color);
display: flex;
flex: 1;
font-size: 0.88rem;
flex-flow: row wrap;
justify-content: flex-end;
margin-right: 0.4rem;
opacity: 0.7;
> span {
&.success {
color: var(--accent-color-primary);
border: 1px solid var(--accent-color-primary);
}
&.warning {
color: var(--accent-color-secondary);
border: 1px solid var(--accent-color-secondary);
}
border-radius: 0.5rem;
padding: 0.15rem 0.5rem;
}
&.success {
svg {
color: var(--status-success-color);
}
}
&.warning {
svg {
color: var(--accent-color-secondary);
}
}
&.minimised {
> svg {
flex: 0;
position: absolute;
right: -3px;
top: -4px;
}
}
}
&.active {
background: var(--highlight-primary);
Expand Down
36 changes: 9 additions & 27 deletions packages/app/src/library/SideMenu/Primary/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,44 +7,21 @@ import { useUi } from 'contexts/UI'
import { useDotLottieButton } from 'hooks/useDotLottieButton'
import { Link } from 'react-router-dom'
import type { PrimaryProps } from '../types'
import { BulletWrapper } from '../Wrapper'
import { Wrapper } from './Wrappers'

export const Primary = ({
name,
active,
to,
action,
bullet,
minimised,
lottie,
}: PrimaryProps) => {
const { setSideMenu } = useUi()

const { icon, play } = useDotLottieButton(lottie)

let Action = null
const actionStatus = action?.status ?? null

switch (action?.type) {
case 'text':
Action = (
<div className="action text">
<span className={actionStatus || undefined}>
{action?.text ?? ''}
</span>
</div>
)
break
case 'bullet':
Action = (
<div className={`action ${actionStatus}`}>
<FontAwesomeIcon icon={faCircle} transform="shrink-4" />
</div>
)
break
default:
Action = null
}

return (
<Link
to={to}
Expand All @@ -58,7 +35,7 @@ export const Primary = ({
<Wrapper
className={`${active ? `active` : `inactive`}${
minimised ? ` minimised` : ``
}${action ? ` ${actionStatus}` : ``}`}
}${bullet ? ` ${bullet}` : ``}`}
whileHover={{ scale: 1.02 }}
whileTap={{ scale: 0.98 }}
transition={{
Expand All @@ -70,7 +47,12 @@ export const Primary = ({
</div>
{!minimised && (
<>
<h4 className="name">{name}</h4> {Action}
<h4 className="name">{name}</h4>
{bullet && (
<BulletWrapper className={bullet}>
<FontAwesomeIcon icon={faCircle} transform="shrink-6" />
</BulletWrapper>
)}
</>
)}
</Wrapper>
Expand Down
23 changes: 6 additions & 17 deletions packages/app/src/library/SideMenu/Secondary/Wrappers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export const Wrapper = styled(motion.button)<MinimisedProps>`
flex-flow: row wrap;
align-items: center;
position: relative;
padding: 0.75rem 0rem 0.75rem 0.5rem;
padding: 0rem 0.5rem;
margin: 0.8rem 0.2rem 1rem 0;
width: 100%;
Expand All @@ -26,13 +26,6 @@ export const Wrapper = styled(motion.button)<MinimisedProps>`
color: var(--text-color-primary);
margin-left: 0.2rem;
}
.action {
color: var(--text-color-primary);
flex: 1;
display: flex;
flex-flow: row wrap;
justify-content: flex-end;
}
&.active {
background: var(--highlight-primary);
Expand All @@ -59,7 +52,7 @@ export const MinimisedWrapper = styled(motion.button)`
justify-content: center;
align-items: center;
position: relative;
padding: 0rem 0rem;
padding: 0;
margin: 0.6rem 0 1.15rem 0;
min-height: 3.2rem;
width: 100%;
Expand All @@ -73,14 +66,7 @@ export const MinimisedWrapper = styled(motion.button)`
.icon {
margin: 0;
}
.action {
&.minimised {
flex: 0;
position: absolute;
top: -2px;
right: -13px;
}
}
&.success {
border: 1px solid var(--status-success-color-transparent);
}
Expand All @@ -93,6 +79,9 @@ export const MinimisedWrapper = styled(motion.button)`
`

export const IconWrapper = styled.div<{ $minimised: boolean }>`
height: 2rem;
display: flex;
align-items: center;
margin-left: ${(props) => (props.$minimised ? 0 : '0.25rem')};
margin-right: ${(props) => (props.$minimised ? 0 : '0.65rem')};
Expand Down
11 changes: 9 additions & 2 deletions packages/app/src/library/SideMenu/Secondary/index.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
// Copyright 2025 @polkadot-cloud/polkadot-staking-dashboard authors & contributors
// SPDX-License-Identifier: GPL-3.0-only

import { faCircle } from '@fortawesome/free-solid-svg-icons'
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import type { SecondaryProps } from '../types'
import { BulletWrapper } from '../Wrapper'
import { IconWrapper, MinimisedWrapper, Wrapper } from './Wrappers'

export const Secondary = ({
action,
bullet,
classes,
name,
icon,
Expand Down Expand Up @@ -39,7 +42,11 @@ export const Secondary = ({
{!minimised && (
<>
<div className="name">{name}</div>
{action && <div className="action">{action}</div>}
{bullet && (
<BulletWrapper className={bullet}>
<FontAwesomeIcon icon={faCircle} transform="shrink-6" />
</BulletWrapper>
)}
</>
)}
</StyledWrapper>
Expand Down
Loading

0 comments on commit 2708b07

Please sign in to comment.