Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

issue #30, make navbar sticky #40

Merged
merged 19 commits into from Jul 6, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 2 additions & 1 deletion package.json
Expand Up @@ -23,7 +23,8 @@
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
"eject": "react-scripts eject",
"lint": "eslint --fix src/"
},
"eslintConfig": {
"extends": [
Expand Down
16 changes: 12 additions & 4 deletions src/App.tsx
Expand Up @@ -2,14 +2,22 @@ import { Routes } from './routes/Routes'
import { Navigation } from './components/navigation/Navigation'
import { GlobalStyle } from './shared/styles/GlobalStyle'
import { UserProvider } from './shared/providers/UserProvider'
import { ScrollProvider } from './shared/providers/ScrollProvider'
import { Space } from './components/space'
import { useNavHeight } from './hooks/useNavHeight'

export const App = () => {
const { navHeight } = useNavHeight()

return (
<UserProvider>
<Routes>
<GlobalStyle />
<Navigation />
</Routes>
<ScrollProvider>
<Routes>
<GlobalStyle />
<Navigation />
<Space space={navHeight} />
</Routes>
</ScrollProvider>
</UserProvider>
)
}
Expand Down
162 changes: 113 additions & 49 deletions src/components/navigation/desktopnavigation/DesktopNavigation.tsx
@@ -1,18 +1,32 @@
import { useContext, useState } from 'react'
import React, { useContext, useState, useMemo } from 'react'
import { useHistory } from 'react-router-dom'
import { UserContext } from '../../../shared/providers/UserProvider'
import { Profile } from '../profile/Profile'
import { ScrollContext } from '../../../shared/providers/ScrollProvider'
import { useNavHeight } from '../../../hooks/useNavHeight'
import { UserContext } from '../../../shared/providers/UserProvider'
import { Cart } from '../../cart/Cart'
import { BackDrop } from '../../BackDrop'
import { CartToggler } from './components/CartToggler'
import styled from 'styled-components'
import RoutingPath from '../../../routes/RoutingPath'
import logotype from '../../../shared/images/codiclogotype.svg'
import { DropDownWrapper } from '../profile/profiledropdown/ProfileDropdown'

export const NavBG = () => {
const { fractions } = useContext(ScrollContext)

const opacity = useMemo(() => Math.max(0.5, 1 - fractions), [fractions])

return <WrapperBackground style={{ opacity: opacity }} />
}

export const DesktopNavigation = () => {
const history = useHistory()

const { navHeight } = useNavHeight()

const [isCartOpen, setIsCartOpen] = useState<boolean>(false)
const [authenticatedUser,] = useContext(UserContext)
const [authenticatedUser] = useContext(UserContext)

const displayAuthentication = () => {
return authenticatedUser.authenticated
Expand All @@ -24,71 +38,121 @@ export const DesktopNavigation = () => {
)
: <Button onClick={() => history.push(RoutingPath.signInView)}>Logga in</Button>
}

const heightStyle = useMemo(
() => ({ height: `${navHeight}rem` }),
[navHeight]
)
return (
<Wrapper>
<Image src={logotype} alt={''} onClick={() => history.push(RoutingPath.initialView)} />
<ParagraphWrapper>
<Paragraph>Vår Vision</Paragraph>
<Paragraph onClick={() => history.push(RoutingPath.employeeView)}>Team Codic</Paragraph>
<Paragraph onClick={() => history.push(RoutingPath.contactView)}>Kontakt</Paragraph>
<Paragraph onClick={() => history.push(RoutingPath.shopView)}>Butik</Paragraph>
</ParagraphWrapper>
<Cart isCartOpen={isCartOpen} setIsCartOpen={setIsCartOpen} />
{isCartOpen && <BackDrop drawerHandler={setIsCartOpen} />}
{displayAuthentication()}
<Wrapper style={heightStyle}>
<NavBG />
<Grid>
<GridCell col="3/3">
<Image
src={logotype}
alt={''}
onClick={() => history.push(RoutingPath.initialView)}
/>
</GridCell>
<GridCell col="5/9">
<ParagraphWrapper>
<Paragraph>Vår Vision</Paragraph>
<Paragraph onClick={() => history.push(RoutingPath.employeeView)}>
Team Codic
</Paragraph>
<Paragraph onClick={() => history.push(RoutingPath.contactView)}>
Kontakt
</Paragraph>
<Paragraph onClick={() => history.push(RoutingPath.shopView)}>
Butik
</Paragraph>
</ParagraphWrapper>
</GridCell>
<Cart isCartOpen={isCartOpen} setIsCartOpen={setIsCartOpen} />
{isCartOpen && <BackDrop drawerHandler={setIsCartOpen} />}
<GridCell col="18/18">{displayAuthentication()}</GridCell>
</Grid>
</Wrapper>
)
}

const Image = styled.img`
padding: 10px;
grid-column: 3/3;
cursor: pointer;
cursor: pointer;
max-height: 50%;
`

const Grid = styled.div`
display: grid;
grid-template-columns: repeat(20, 1fr);
width: 100%;
height: 100%;
`

const GridCell = styled.div`
grid-column: ${(props: { col?: string }) => props.col};
display: grid;
align-items: center;
max-height: 100%;
position: relative;
height: 100%;
`

const Wrapper = styled.nav`
display: grid;
grid-template-columns: repeat(20, 1fr);
background-color: #263746;
padding: 0.3%;
`
position: fixed;
top: 0;
left: 0;
z-index: 300;
width: 100%;
`

const WrapperBackground = styled.div`
position: absolute;
background-color: #263746;
left: 0;
top: 0;
width: 100%;
height: 100%;
z-index: -1;
`

const Paragraph = styled.p`
font-weight: 600;
cursor: pointer;
text-transform: uppercase;
color: white;
align-self: center;
`
font-weight: 600;
cursor: pointer;
text-transform: uppercase;
color: white;
align-self: center;
`

const Button = styled.p`
font-weight: 600;
color: white;
align-self: center;
text-transform: uppercase;
grid-column: 18/18;
cursor: pointer;
font-weight: 600;
color: white;
align-self: center;
text-transform: uppercase;
cursor: pointer;
`

export const Paragraph2 = styled.p`
font-weight: 600;
color: white;
align-self: center;
text-transform: uppercase;
grid-column: 18/18;
cursor: pointer;
font-weight: 600;
color: white;
align-self: center;
text-transform: uppercase;
grid-column: 18/18;
cursor: pointer;
`

const ParagraphWrapper = styled.div`
grid-column: 5/9;
display: flex;
justify-content: space-between
`
display: flex;
justify-content: space-between;
display: flex;
`

const ProfileWrapper = styled.div`
grid-column: 17/19;
display: flex;
justify-content: space-between
justify-content: center;
`
display: flex;
justify-content: space-between
justify-content: center;
height: 100%;
&:hover ${DropDownWrapper} {
visibility: visible;
opacity: 1;
}
`
1 change: 1 addition & 0 deletions src/components/navigation/profile/Profile.tsx
Expand Up @@ -22,6 +22,7 @@ const Paragraph = styled.p`
grid-column: 18/18;
cursor: pointer;
padding: 0px 35px;
height: 100%;
`

const ProfileWrapper = styled.div`
Expand Down
Expand Up @@ -13,10 +13,12 @@ import help from '../../../../shared/images/icons/help.png'
import feedback from '../../../../shared/images/icons/feedback.png'
import exit from '../../../../shared/images/icons/logout.png'
import AuthPath from '../../../../routes/AuthPath'
import { useNavHeight } from '../../../../hooks/useNavHeight'
import { nonAuthenticatedUser } from '../../../../shared/data/nonAuthenticatedUser'

export const ProfileDropdown = () => {
const [, setAuthenticatedUser] = useContext(UserContext)
const { navHeight } = useNavHeight()
const history = useHistory()

const logout = () => {
Expand All @@ -35,7 +37,7 @@ export const ProfileDropdown = () => {
}

return (
<DropDownWrapper>
<DropDownWrapper style={{ top: `${navHeight}rem`}}>
{newDropdownItem(profile, 'Din Profil', AuthPath.profileView)}
{newDropdownItem(heart, 'Sparade Produkter (4)')}
<Div onClick={() => logout()}>
Expand All @@ -54,43 +56,52 @@ export const ProfileDropdown = () => {


const Image = styled.img`
width: 24px;
height: 24px;
filter: brightness(0) invert(0.7);
align-self: center;
width: 24px;
height: 24px;
filter: brightness(0) invert(0.7);
align-self: center;
`

const Div = styled.div`
cursor: pointer;
display: flex;
&:hover ${Image} {
cursor: pointer;
display: flex;
&:hover ${Image} {
filter: brightness(0) invert(1);
}
}
`

const DropDownItem = styled.p`
font-size: 1.1rem;
color: white;
display: inline-block;
margin-left: 10px;

display: inline-block;
padding-left: 1rem;
height: 3rem;
display: flex;
justify-content: center;
align-items: center;
`

const HR = styled.hr`
display: block;
height: 1px;
border: 0;
border-top: 1px solid #ccc;
margin: 1em 0;
padding: 0;
display: block;
height: 1px;
border: 0;
border-top: 1px solid #ccc;
margin: 1em 0;
padding: 0;
`

export const DropDownWrapper = styled.div`
width: 20rem;
visibility: hidden;
position: absolute;
background-color: #263746;
padding: 10px 35px;
opacity: 0;
transition: visibility 0s, opacity 0.2s linear;
z-index: 100;
`
z-index: 100;

&:hover {
visibility: visible;
opacity: 1;
}
`
11 changes: 11 additions & 0 deletions src/components/space/index.tsx
@@ -0,0 +1,11 @@
import { FC } from 'react'
import styled from 'styled-components'
import { ISpace } from './types'


export const Space:FC<ISpace> = (props: ISpace) => <Wrapper space={props.space} />


const Wrapper = styled.div`
margin-top: ${(props: Partial<ISpace>) => props.space}rem
`
3 changes: 3 additions & 0 deletions src/components/space/types.ts
@@ -0,0 +1,3 @@
export interface ISpace {
space:number
}
12 changes: 12 additions & 0 deletions src/functions/interpolate.ts
@@ -0,0 +1,12 @@
/**
* method of constructing (finding) new data points based on
* the range of a discrete set of known data points
*/
export const interpolate = (start: number, end: number, precision: number) => {
const n =
Math.max(start / precision, end / precision) -
Math.min(start / precision, end / precision)
return Array.from(Array(n).keys())
.map((v) => start + v * precision)
.concat(end)
}
24 changes: 24 additions & 0 deletions src/hooks/useNavHeight.tsx
@@ -0,0 +1,24 @@
import { useContext, useState, useEffect } from 'react'
import { interpolate } from '../functions/interpolate'
import { ScrollContext } from '../shared/providers/ScrollProvider'
import {
DESKTOP_NAV_HEIGHT,
DESKTOP_NAV_HEIGHT_SMALL,
} from '../shared/styles/constants'

export const useNavHeight = () => {
const { scrollY } = useContext(ScrollContext)
const [height, setHeight] = useState(DESKTOP_NAV_HEIGHT)

const animation = interpolate(
DESKTOP_NAV_HEIGHT_SMALL,
DESKTOP_NAV_HEIGHT,
0.01
).reverse()

useEffect(() => {
setHeight(animation[Math.min(animation.length - 1, scrollY)])
}, [scrollY, setHeight])

return { navHeight: height }
}