Skip to content

Commit

Permalink
Merge pull request #50 from Quiddlee/feature/nav-bar-aptive
Browse files Browse the repository at this point in the history
Feature/nav bar aptive
  • Loading branch information
Quiddlee authored Jan 3, 2024
2 parents 7a90c9a + 3d05574 commit 849e810
Show file tree
Hide file tree
Showing 17 changed files with 487 additions and 160 deletions.
53 changes: 42 additions & 11 deletions src/components/Header/Header.tsx
Original file line number Diff line number Diff line change
@@ -1,28 +1,59 @@
import { useState } from 'react';

import { Link, useLocation, useNavigate } from 'react-router-dom';

import { useLanguage } from '@/shared/Context/hooks';
import Icon from '@/shared/ui/Icon';
import IconButton from '@/shared/ui/IconButton';
import DocsComp from '@components/DocsComp/DocsComp';
import ROUTES from '@shared/constants/routes';
import viewTransition from '@shared/lib/helpers/viewTransition';
import useScreen from '@shared/lib/hooks/useScreen';

const Header = () => {
const [isDocsShown, setIsDocsShown] = useState(false);
const { translation } = useLanguage();
const { pathname } = useLocation();
const isSettings = pathname.slice(1) === ROUTES.SETTINGS;
const navigate = useNavigate();
const isMobile = useScreen() === 'mobile';

const docsTooltip = translation.mainLayout.header.tooltips.docs;

function handleClick() {
viewTransition(() => navigate(-1));
}

return (
<>
<header className="col-start-1 col-end-2 flex justify-between sm:col-end-3">
<p>Here is still header</p>
<div>
<IconButton
onClick={() => setIsDocsShown((prev) => !prev)}
data-tooltip={docsTooltip}
data-testid="show_docs"
className="tooltipElem"
<header className="col-start-1 col-end-2 flex w-full items-center justify-end py-2 pr-2 sm:col-end-3">
{isSettings && !isMobile ? (
<h1 style={{ viewTransitionName: 'title' }} className="mr-auto flex items-center pl-4 font-readex_pro">
<button type="button" onClick={handleClick} className="flex h-12 w-12 items-center justify-center">
<IconButton className="animate-fade-in-screen duration-500">
<Icon>arrow_left_alts</Icon>
</IconButton>
</button>
<span className="animate-fade-in-settings">Settings</span>
</h1>
) : (
<h1
style={{
viewTransitionName: 'title',
}}
className="ml-[53px] mr-auto animate-fade-in-title font-readex_pro sm:ml-7 lg:ml-4"
>
<Icon>article</Icon>
</IconButton>
</div>
<Link to={ROUTES.WELCOME_PAGE}>GraphiQL</Link>
</h1>
)}
<IconButton
onClick={() => setIsDocsShown((prev) => !prev)}
data-tooltip={docsTooltip}
data-testid="show_docs"
className="tooltipElem"
>
<Icon>article</Icon>
</IconButton>
</header>
<DocsComp isShown={isDocsShown} setIsDocsShown={setIsDocsShown} />
</>
Expand Down
7 changes: 6 additions & 1 deletion src/components/Nav/Nav.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
import NavigationBar from '@components/Nav/ui/NavigationBar';
import NavigationDrawer from '@components/Nav/ui/NavigationDrawer';
import useScreen from '@shared/lib/hooks/useScreen';

const Nav = () => {
const screenType = useScreen();
const isMobile = screenType === 'mobile';

return (
<nav className="h-full w-full">
<NavigationDrawer />
{isMobile && <NavigationBar />} <NavigationDrawer />
</nav>
);
};
Expand Down
26 changes: 19 additions & 7 deletions src/components/Nav/ui/NavItem.tsx
Original file line number Diff line number Diff line change
@@ -1,32 +1,44 @@
import { FC, ReactNode } from 'react';

import { NavLink } from 'react-router-dom';
import { NavLink, NavLinkProps } from 'react-router-dom';

import cn from '@shared/lib/helpers/cn';

type NavButtonProps = {
type NavButtonProps = NavLinkProps & {
to: string;
children: ReactNode;
isExpand?: boolean;
};

const NavItem: FC<NavButtonProps> = ({ to, children, ...props }) => {
const NavItem: FC<NavButtonProps> = ({ to, style, isExpand, children, ...props }) => {
return (
<NavLink {...props} to={to}>
<NavLink
unstable_viewTransition
style={style}
className={cn('flex justify-center lg:inline', {
'max-w-[60px]': !isExpand,
})}
{...props}
to={to}
>
{({ isActive }) => (
<span
className={cn(
'group relative flex items-center gap-3 rounded-full py-4 pl-4 pr-6 ease-linear hover:bg-[color-mix(in_srgb,_var(--md-sys-color-inverse-surface)_8%,_transparent)] hover:duration-0 active:bg-[color-mix(in_srgb,_var(--md-sys-color-inverse-surface)_10%,_transparent)]',
'group relative flex w-full items-center justify-center gap-3 rounded-full ease-linear before:absolute before:-top-1 before:left-0.5 before:h-[32px] before:w-[56px] before:rounded-full hover:duration-0 before:hover:bg-[color-mix(in_srgb,_var(--md-sys-color-inverse-surface)_10%,_transparent)] lg:justify-start lg:py-4 lg:pl-4 lg:pr-6 lg:before:hidden lg:hover:bg-[color-mix(in_srgb,_var(--md-sys-color-inverse-surface)_8%,_transparent)] lg:active:bg-[color-mix(in_srgb,_var(--md-sys-color-inverse-surface)_10%,_transparent)]',
{
'text-on-secondary-container-text': isActive,
'origin-left justify-start py-4 pl-4 pr-6 duration-[inherit] ease-[inherit] before:hidden hover:bg-[color-mix(in_srgb,_var(--md-sys-color-inverse-surface)_8%,_transparent)] active:bg-[color-mix(in_srgb,_var(--md-sys-color-inverse-surface)_10%,_transparent)]':
isExpand,
},
)}
>
<span
className={cn(
'absolute left-0 top-0 h-full w-full scale-x-[.32] rounded-full py-4 pl-4 pr-6 opacity-0 transition-all duration-200 ease-linear',
'absolute -top-1 left-0.5 h-[32px] w-[56px] scale-x-[.32] rounded-full py-4 pl-4 pr-6 opacity-0 transition-all duration-200 ease-linear lg:left-0 lg:top-0 lg:h-full lg:w-full',
{
'scale-x-100 bg-secondary-container opacity-100 group-hover:bg-[color-mix(in_srgb,_var(--md-sys-color-secondary)_18%,_transparent)] group-active:bg-[color-mix(in_srgb,_var(--md-sys-color-secondary)_20%,_transparent)]':
'scale-x-100 bg-secondary-container opacity-100 group-active:bg-[color-mix(in_srgb,_var(--md-sys-color-secondary)_20%,_transparent)] lg:group-hover:bg-[color-mix(in_srgb,_var(--md-sys-color-secondary)_18%,_transparent)]':
isActive,
'left-0 top-0 h-full w-full': isExpand,
},
)}
/>
Expand Down
29 changes: 29 additions & 0 deletions src/components/Nav/ui/NavigationBar.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import NavItem from '@components/Nav/ui/NavItem';
import ROUTES from '@shared/constants/routes';
import { useLanguage } from '@shared/Context/hooks';
import cn from '@shared/lib/helpers/cn';
import Icon from '@shared/ui/Icon';

const NavigationBar = () => {
const { translation } = useLanguage();

return (
<ul className={cn('flex h-full w-full items-center justify-around gap-4 bg-surface lg:block lg:w-full')}>
<NavItem className="min-w-[60px]" data-testid="nav-welcome" to={ROUTES.WELCOME_PAGE}>
<div className="grid justify-items-center gap-2">
<Icon>spa</Icon>
<span className={cn('block text-sm lg:hidden')}>{translation.nav.navbar.welcome}</span>
</div>
</NavItem>

<NavItem className="min-w-[60px]" data-testid="nav-settings" to={ROUTES.SETTINGS}>
<div className="grid justify-items-center gap-2">
<Icon>settings</Icon>
<span className={cn('block text-sm lg:hidden')}>{translation.nav.navbar.settings}</span>
</div>
</NavItem>
</ul>
);
};

export default NavigationBar;
182 changes: 157 additions & 25 deletions src/components/Nav/ui/NavigationDrawer.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { useCallback, useEffect, useState } from 'react';

import NavItem from '@components/Nav/ui/NavItem';
import VirtualScroll from '@components/Nav/ui/VirtualScroll';
import AddView from '@components/ViewList/ui/AddView';
Expand All @@ -6,39 +8,169 @@ import ViewItem from '@components/ViewList/ui/ViewItem';
import ViewList from '@components/ViewList/ViewList';
import ROUTES from '@shared/constants/routes';
import { useLanguage } from '@shared/Context/hooks';
import cn from '@shared/lib/helpers/cn';
import viewTransition from '@shared/lib/helpers/viewTransition';
import useScreen from '@shared/lib/hooks/useScreen';
import Blackout from '@shared/ui/Blackout';
import Fab from '@shared/ui/Fab';
import Icon from '@shared/ui/Icon';
import IconButton from '@shared/ui/IconButton';

const NavigationDrawer = () => {
const { translation } = useLanguage();
const screenType = useScreen();
const [isActive, setIsActive] = useState(false);

const isDesktop = screenType === 'desktop';
const isMobile = screenType === 'mobile';

useEffect(() => {
if (isDesktop && isActive) {
setIsActive(false);
}
}, [isActive, isDesktop]);

const handleHideDrawer = useCallback(
function handleHideDrawer() {
if (!isDesktop && isActive) viewTransition(() => setIsActive(false));
},
[isActive, isDesktop],
);

const handleShowDrawer = useCallback(
function handleShowDrawer() {
if (!isDesktop) viewTransition(() => setIsActive(true));
},
[isDesktop],
);

return (
<article className="h-fit w-full text-on-surface-variant-text">
<ul>
<NavItem data-testid="nav-welcome" to={ROUTES.WELCOME_PAGE}>
<Icon>spa</Icon> {translation.nav.navbar.welcome}
</NavItem>

<NavItem data-testid="nav-settings" to={ROUTES.SETTINGS}>
<Icon>settings</Icon> {translation.nav.navbar.settings}
</NavItem>

<hr className="ml-4 border-outline-variant" />
</ul>
<ViewList
render={(view) => (
<ViewItem key={view.id} id={view.id}>
<span className="animation-delay-200 flex animate-fade-in-standard items-center">
<Icon>tab</Icon>
</span>
<span className="truncate group-hover:pe-8 [&:has(+_article_.visible)]:pe-8">{view.name}</span>
<Details id={view.id} />
</ViewItem>
<>
<Blackout isBlackout={isActive} unlock={handleHideDrawer} />

<article
className={cn(
'h-full w-20 overflow-hidden text-on-surface-variant-text transition-all duration-400 ease-emphasized-decelerate lg:relative lg:block lg:h-full lg:w-full lg:translate-y-0',
{
'absolute left-0 top-0 z-40 h-screen w-[384px] translate-y-0 overflow-auto rounded-r-3xl bg-surface-container p-3 duration-700':
isActive,
'absolute left-0 top-0 w-[90%] max-w-[384px] origin-left scale-x-50': isMobile,
'z-40 scale-x-100': isMobile && isActive,
},
)}
>
<AddView />
<VirtualScroll size="7" />
</ViewList>
</article>
<h2
className={cn('py-[18px] pl-4 pr-2 font-readex_pro text-on-surface-text', {
hidden: !isActive,
})}
>
GraphiQL
</h2>

<ul
className={cn('mb-11 grid w-20 justify-items-center gap-2 lg:hidden', {
hidden: isActive,
})}
>
<IconButton
className={cn({
'ml-2 mt-3 scale-x-[2]': isMobile,
})}
onClick={handleShowDrawer}
>
<Icon>menu</Icon>
</IconButton>
<Fab
className={cn({
hidden: isMobile,
})}
variant="tertiary"
>
<Icon slot="icon">play_arrow</Icon>
</Fab>
</ul>

<ul
className={cn('grid w-20 justify-center gap-4 lg:block lg:w-full lg:justify-start', {
'w-full justify-stretch': isActive,
hidden: isMobile,
})}
>
<NavItem
onClick={handleHideDrawer}
style={{
viewTransitionName: 'nav-welcome',
}}
isExpand={isActive}
data-testid="nav-welcome"
to={ROUTES.WELCOME_PAGE}
>
<div className="grid justify-items-center gap-2">
<Icon>spa</Icon>
<span
className={cn('block text-sm lg:hidden', {
hidden: isActive,
})}
>
{translation.nav.navbar.welcome}
</span>
</div>
<span
className={cn('hidden lg:block', {
block: isActive,
})}
>
{translation.nav.navbar.welcome}
</span>
</NavItem>

<NavItem
onClick={handleHideDrawer}
style={{
viewTransitionName: 'nav-settings',
}}
isExpand={isActive}
data-testid="nav-settings"
to={ROUTES.SETTINGS}
>
<div className="grid justify-items-center gap-2">
<Icon>settings</Icon>
<span
className={cn('block text-sm lg:hidden', {
hidden: isActive,
})}
>
{translation.nav.navbar.settings}
</span>
</div>
<span
className={cn('hidden lg:block', {
block: isActive,
})}
>
{translation.nav.navbar.settings}
</span>
</NavItem>

<hr className="invisible ml-4 border-outline-variant lg:visible" />
</ul>
<ViewList
isActive={isActive}
render={(view) => (
<ViewItem onClick={handleHideDrawer} key={view.id} id={view.id}>
<span className="animation-delay-200 flex animate-fade-in-standard items-center">
<Icon>tab</Icon>
</span>
<span className="truncate group-hover:pe-8 [&:has(+_article_.visible)]:pe-8">{view.name}</span>
<Details id={view.id} />
</ViewItem>
)}
>
<AddView />
<VirtualScroll size="7" />
</ViewList>
</article>
</>
);
};

Expand Down
Loading

0 comments on commit 849e810

Please sign in to comment.