feat: make nav menu as links (#3646)

This commit is contained in:
Yury Molodov 2023-01-13 09:45:07 +01:00 committed by Aliaksandr Valialkin
parent 5815a98957
commit e37bac07a0
No known key found for this signature in database
GPG key ID: A72BEC6CD3D0DED1
6 changed files with 141 additions and 44 deletions

View file

@ -58,11 +58,6 @@ const Header: FC = () => {
const [activeMenu, setActiveMenu] = useState(pathname);
const handleChangeTab = (value: string) => {
setActiveMenu(value);
navigate(value);
};
const headerSetup = useMemo(() => {
return ((routerOptions[pathname] || {}) as RouterOptions).header || {};
}, [pathname]);
@ -90,7 +85,7 @@ const Header: FC = () => {
>
{!appModeEnable && (
<div
className="vm-header__logo"
className="vm-header-logo"
onClick={onClickLogo}
style={{ color }}
>
@ -99,10 +94,10 @@ const Header: FC = () => {
)}
<div className="vm-header-nav">
<Tabs
isNavLink
activeItem={activeMenu}
items={routes.filter(r => !r.hide)}
color={color}
onChange={handleChangeTab}
/>
</div>
<div className="vm-header__settings">

View file

@ -2,6 +2,7 @@
.vm-header {
display: flex;
flex-wrap: wrap;
align-items: center;
justify-content: flex-start;
padding: $padding-small $padding-medium;
@ -11,15 +12,35 @@
padding: $padding-small 0;
}
&__logo {
@media (max-width: 1200px) {
gap: $padding-global;
.vm-tabs {
gap: 0;
}
}
&-logo {
position: relative;
display: flex;
align-items: center;
justify-content: center;
justify-content: flex-start;
cursor: pointer;
width: 100%;
max-width: 65px;
min-width: 65px;
margin-bottom: 2px;
overflow: hidden;
@media (max-width: 1200px) {
min-width: 14px;
max-width: 14px;
}
svg {
max-width: 65px;
min-width: 65px;
}
}
&-nav {

View file

@ -0,0 +1,57 @@
import React, { Component, FC, Ref } from "preact/compat";
import classNames from "classnames";
import { getCssVariable } from "../../../utils/theme";
import { TabItemType } from "./Tabs";
import TabItemWrapper from "./TabItemWrapper";
import "./style.scss";
interface TabItemProps {
activeItem: string
item: TabItemType
color?: string
onChange?: (value: string) => void
activeNavRef: Ref<Component>
isNavLink?: boolean
}
const TabItem: FC<TabItemProps> = ({
activeItem,
item,
color = getCssVariable("color-primary"),
activeNavRef,
onChange,
isNavLink
}) => {
const createHandlerClickTab = (value: string) => () => {
onChange && onChange(value);
};
return (
<TabItemWrapper
className={classNames({
"vm-tabs-item": true,
"vm-tabs-item_active": activeItem === item.value,
[item.className || ""]: item.className
})}
isNavLink={isNavLink}
to={item.value}
style={{ color: color }}
onClick={createHandlerClickTab(item.value)}
ref={activeItem === item.value ? activeNavRef : undefined}
>
{item.icon && (
<div
className={classNames({
"vm-tabs-item__icon": true,
"vm-tabs-item__icon_single": !item.label
})}
>
{item.icon}
</div>
)}
{item.label}
</TabItemWrapper>
);
};
export default TabItem;

View file

@ -0,0 +1,29 @@
import { ReactNode } from "react";
import React, { FC } from "preact/compat";
import { NavLink } from "react-router-dom";
interface TabItemWrapperProps {
to: string
isNavLink?: boolean
className: string
style: { color: string }
children: ReactNode
onClick: () => void
}
const TabItemWrapper: FC<TabItemWrapperProps> = ({ to, isNavLink, children, ...props }) => {
if (isNavLink) {
return (
<NavLink
to={to}
{...props}
>
{children}
</NavLink>
);
}
return <div {...props}>{children}</div>;
};
export default TabItemWrapper;

View file

@ -1,16 +1,24 @@
import React, { FC, useRef, useState } from "preact/compat";
import React, { Component, FC, useRef, useState } from "preact/compat";
import { ReactNode, useEffect } from "react";
import "./style.scss";
import classNames from "classnames";
import { getCssVariable } from "../../../utils/theme";
import useResize from "../../../hooks/useResize";
import TabItem from "./TabItem";
import "./style.scss";
export interface TabItemType {
value: string
label?: string
icon?: ReactNode
className?: string
}
interface TabsProps {
activeItem: string
items: {value: string, label?: string, icon?: ReactNode, className?: string}[]
items: TabItemType[]
color?: string
onChange: (value: string) => void
onChange?: (value: string) => void
indicatorPlacement?: "bottom" | "top"
isNavLink?: boolean
}
const Tabs: FC<TabsProps> = ({
@ -18,19 +26,16 @@ const Tabs: FC<TabsProps> = ({
items,
color = getCssVariable("color-primary"),
onChange,
indicatorPlacement = "bottom"
indicatorPlacement = "bottom",
isNavLink,
}) => {
const windowSize = useResize(document.body);
const activeNavRef = useRef<HTMLDivElement>(null);
const activeNavRef = useRef<Component>(null);
const [indicatorPosition, setIndicatorPosition] = useState({ left: 0, width: 0, bottom: 0 });
const createHandlerClickTab = (value: string) => () => {
onChange(value);
};
useEffect(() => {
if(activeNavRef.current) {
const { offsetLeft: left, offsetWidth: width, offsetHeight: height } = activeNavRef.current;
if(activeNavRef.current?.base instanceof HTMLElement) {
const { offsetLeft: left, offsetWidth: width, offsetHeight: height } = activeNavRef.current.base;
const positionTop = indicatorPlacement === "top";
setIndicatorPosition({ left, width, bottom: positionTop ? height - 2 : 0 });
}
@ -38,29 +43,15 @@ const Tabs: FC<TabsProps> = ({
return <div className="vm-tabs">
{items.map(item => (
<div
className={classNames({
"vm-tabs-item": true,
"vm-tabs-item_active": activeItem === item.value,
[item.className || ""]: item.className
})}
ref={activeItem === item.value ? activeNavRef : undefined}
<TabItem
key={item.value}
style={{ color: color }}
onClick={createHandlerClickTab(item.value)}
>
{item.icon && (
<div
className={classNames({
"vm-tabs-item__icon": true,
"vm-tabs-item__icon_single": !item.label
})}
>
{item.icon}
</div>
)}
{item.label}
</div>
activeItem={activeItem}
item={item}
onChange={onChange}
color={color}
activeNavRef={activeNavRef}
isNavLink={isNavLink}
/>
))}
<div
className="vm-tabs__indicator"

View file

@ -27,6 +27,10 @@
opacity: 1;
}
&:hover {
opacity: 0.8;
}
&__icon {
display: grid;
width: 15px;