mirror of https://gitee.com/answerdev/answer.git
refactor(AccordionNav): Optimize the secondary navigation menu
This commit is contained in:
parent
1537f502f4
commit
a5a95c5f3d
|
@ -0,0 +1,7 @@
|
|||
.collapse-indicator {
|
||||
transition: all .2s ease;
|
||||
}
|
||||
|
||||
.expanding .collapse-indicator {
|
||||
transform: rotate(90deg);
|
||||
}
|
|
@ -1,44 +1,63 @@
|
|||
import React, { FC } from 'react';
|
||||
import { Accordion, Button, Stack } from 'react-bootstrap';
|
||||
import React, { FC, useEffect, useState } from 'react';
|
||||
import { Accordion, Nav } from 'react-bootstrap';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useNavigate, useMatch } from 'react-router-dom';
|
||||
|
||||
import { useAccordionButton } from 'react-bootstrap/AccordionButton';
|
||||
import classNames from 'classnames';
|
||||
|
||||
import { Icon } from '@/components';
|
||||
import './index.css';
|
||||
|
||||
function MenuNode({ menu, callback, activeKey, isLeaf = false }) {
|
||||
function MenuNode({
|
||||
menu,
|
||||
callback,
|
||||
activeKey,
|
||||
expanding = false,
|
||||
path = '/',
|
||||
}) {
|
||||
const { t } = useTranslation('translation', { keyPrefix: 'nav_menus' });
|
||||
const accordionClick = useAccordionButton(menu.name);
|
||||
const menuOnClick = (evt) => {
|
||||
evt.preventDefault();
|
||||
evt.stopPropagation();
|
||||
if (!isLeaf) {
|
||||
accordionClick(evt);
|
||||
}
|
||||
if (typeof callback === 'function') {
|
||||
callback(menu);
|
||||
}
|
||||
};
|
||||
const isLeaf = !menu.children.length;
|
||||
const href = isLeaf ? `${path}${menu.name}` : '#';
|
||||
|
||||
let menuCls = 'text-start text-dark text-nowrap shadow-none bg-body border-0';
|
||||
let menuVariant = 'light';
|
||||
if (activeKey === menu.name) {
|
||||
menuCls = 'text-start text-white text-nowrap shadow-none';
|
||||
menuVariant = 'primary';
|
||||
}
|
||||
return (
|
||||
<Button variant={menuVariant} className={menuCls} onClick={menuOnClick}>
|
||||
<Stack direction="horizontal">
|
||||
{!isLeaf ? <Icon name="chevron-right" className="me-1" /> : null}
|
||||
{t(menu.name)}
|
||||
<Nav.Item key={menu.name}>
|
||||
<Nav.Link
|
||||
eventKey={menu.name}
|
||||
as={isLeaf ? 'a' : 'button'}
|
||||
onClick={(evt) => {
|
||||
callback(evt, menu, href, isLeaf);
|
||||
}}
|
||||
href={href}
|
||||
className={classNames(
|
||||
'text-nowrap d-flex flex-nowrap align-items-center w-100',
|
||||
{ expanding, 'link-dark': activeKey !== menu.name },
|
||||
)}>
|
||||
<span className="me-auto">{t(menu.name)}</span>
|
||||
{menu.badgeContent ? (
|
||||
<span className="badge text-bg-dark ms-auto top-0">
|
||||
{menu.badgeContent}
|
||||
</span>
|
||||
<span className="badge text-bg-dark">{menu.badgeContent}</span>
|
||||
) : null}
|
||||
</Stack>
|
||||
</Button>
|
||||
{!isLeaf && (
|
||||
<Icon className="collapse-indicator" name="chevron-right" />
|
||||
)}
|
||||
</Nav.Link>
|
||||
{menu.children.length ? (
|
||||
<Accordion.Collapse eventKey={menu.name} className="ms-3">
|
||||
<>
|
||||
{menu.children.map((leaf) => {
|
||||
return (
|
||||
<MenuNode
|
||||
menu={leaf}
|
||||
callback={callback}
|
||||
activeKey={activeKey}
|
||||
path={path}
|
||||
key={leaf.name}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</>
|
||||
</Accordion.Collapse>
|
||||
) : null}
|
||||
</Nav.Item>
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -46,12 +65,9 @@ interface AccordionProps {
|
|||
menus: any[];
|
||||
path?: string;
|
||||
}
|
||||
const AccordionNav: FC<AccordionProps> = ({ menus, path = '/' }) => {
|
||||
const AccordionNav: FC<AccordionProps> = ({ menus = [], path = '/' }) => {
|
||||
const navigate = useNavigate();
|
||||
const pathMatch = useMatch(`${path}*`);
|
||||
if (!menus.length) {
|
||||
return null;
|
||||
}
|
||||
// auto set menu fields
|
||||
menus.forEach((m) => {
|
||||
if (!Array.isArray(m.children)) {
|
||||
|
@ -68,57 +84,50 @@ const AccordionNav: FC<AccordionProps> = ({ menus, path = '/' }) => {
|
|||
if (splat) {
|
||||
activeKey = splat;
|
||||
}
|
||||
const menuClick = (clickedMenu) => {
|
||||
const menuKey = clickedMenu.name;
|
||||
if (clickedMenu.children.length) {
|
||||
return;
|
||||
}
|
||||
if (activeKey !== menuKey) {
|
||||
const routePath = `${path}${menuKey}`;
|
||||
navigate(routePath);
|
||||
}
|
||||
const getOpenKey = () => {
|
||||
let openKey = '';
|
||||
menus.forEach((li) => {
|
||||
if (li.children.length) {
|
||||
const matchedChild = li.children.find((el) => {
|
||||
return el.name === activeKey;
|
||||
});
|
||||
if (matchedChild) {
|
||||
openKey = li.name;
|
||||
}
|
||||
}
|
||||
});
|
||||
return openKey;
|
||||
};
|
||||
|
||||
let defaultOpenKey;
|
||||
menus.forEach((li) => {
|
||||
if (li.children.length) {
|
||||
const matchedChild = li.children.find((el) => {
|
||||
return el.name === activeKey;
|
||||
});
|
||||
if (matchedChild) {
|
||||
defaultOpenKey = li.name;
|
||||
}
|
||||
const [openKey, setOpenKey] = useState(getOpenKey());
|
||||
const menuClick = (evt, menu, href, isLeaf) => {
|
||||
evt.preventDefault();
|
||||
evt.stopPropagation();
|
||||
if (isLeaf) {
|
||||
navigate(href);
|
||||
} else {
|
||||
setOpenKey(openKey === menu.name ? '' : menu.name);
|
||||
}
|
||||
});
|
||||
|
||||
};
|
||||
useEffect(() => {
|
||||
setOpenKey(getOpenKey());
|
||||
}, [activeKey]);
|
||||
return (
|
||||
<Accordion defaultActiveKey={defaultOpenKey} flush>
|
||||
<Stack direction="vertical" gap={1}>
|
||||
<Accordion activeKey={openKey} flush>
|
||||
<Nav variant="pills" className="flex-column" activeKey={activeKey}>
|
||||
{menus.map((li) => {
|
||||
return (
|
||||
<React.Fragment key={li.name}>
|
||||
<MenuNode menu={li} callback={menuClick} activeKey={activeKey} />
|
||||
{li.children.length ? (
|
||||
<Accordion.Collapse eventKey={li.name} className="ms-4">
|
||||
<Stack direction="vertical" gap={1}>
|
||||
{li.children.map((leaf) => {
|
||||
return (
|
||||
<MenuNode
|
||||
menu={leaf}
|
||||
callback={menuClick}
|
||||
activeKey={activeKey}
|
||||
isLeaf
|
||||
key={leaf.name}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</Stack>
|
||||
</Accordion.Collapse>
|
||||
) : null}
|
||||
</React.Fragment>
|
||||
<MenuNode
|
||||
menu={li}
|
||||
path={path}
|
||||
callback={menuClick}
|
||||
activeKey={activeKey}
|
||||
expanding={openKey === li.name}
|
||||
key={li.name}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</Stack>
|
||||
</Nav>
|
||||
</Accordion>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -77,9 +77,9 @@ const Index: FC = () => {
|
|||
useEffect(() => {
|
||||
getSeoSetting().then((setting) => {
|
||||
if (setting) {
|
||||
const formMeta = { ...formData };
|
||||
formMeta.robots.value = setting.robots;
|
||||
setFormData(formMeta);
|
||||
// const formMeta = { ...formData };
|
||||
// formMeta.robots.value = setting.robots;
|
||||
// setFormData(formMeta);
|
||||
}
|
||||
});
|
||||
}, []);
|
||||
|
|
Loading…
Reference in New Issue