Skip to content

Commit

Permalink
Add dropdown menu to navbar (#4188)
Browse files Browse the repository at this point in the history
* Add dropdown menu to navbar

* Fix linting issues with new navbar

* Change item description to reflect revue being added to contact page
  • Loading branch information
falbru committed Oct 24, 2023
1 parent 561d52a commit 687d756
Show file tree
Hide file tree
Showing 13 changed files with 328 additions and 61 deletions.
37 changes: 0 additions & 37 deletions app/components/Header/Header.css
Original file line number Diff line number Diff line change
Expand Up @@ -121,43 +121,6 @@
}
}

.navigation {
display: flex;
flex-direction: row;
justify-content: space-around;
align-items: center;
flex: 2;
white-space: nowrap;
margin-right: 5px;

@media (--mobile-device) {
display: none;
}
}

.navigation a {
font-size: var(--font-size-lg);
padding: 10px 1rem;
height: 100%;
color: var(--lego-font-color);
display: flex;
align-items: center;
justify-content: center;
position: relative;
transition: color var(--linear-medium);
white-space: nowrap;

&:hover,
&.activeItem {
color: var(--color-gray-7);
}

&:hover::after,
&.activeItem::after {
transform: scaleX(1);
}
}

.logoLightMode,
.logoDarkMode {
display: none;
Expand Down
41 changes: 41 additions & 0 deletions app/components/Header/Navbar/AboutDropdown.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import ItemGrid from './ItemGrid';
import type { ItemProps } from './Item';

const AboutDropdown = () => {
const items: ItemProps[] = [
{
title: 'Generelt',
description: 'Alt du trenger å vite om landets beste linjeforening',
to: '/pages/info-om-abakus',
},
{
title: 'For bedrifter',
description: 'Les om alt Abakus kan tilby din bedrift',
to: '/pages/bedrifter/for-bedrifter',
},
{
title: 'Interessegrupper',
description: 'Utforsk og engasjer deg i en interessegruppe',
to: '/interestgroups',
},
{
title: 'Revyen',
description: 'Les om revyen og revygruppene i Abakus',
to: '/pages/grupper/104-revyen',
},
{
title: 'Komiteer',
description: 'Les om ansvarsområdene til komiteene i Abakus',
to: '/pages/komiteer/4',
},
{
title: 'Kontakt Abakus',
description: 'Nå ut til Hovedstyret, revyen eller komiteene',
to: '/contact',
},
];

return <ItemGrid items={items} />;
};

export default AboutDropdown;
17 changes: 17 additions & 0 deletions app/components/Header/Navbar/CareerDropdown.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import ItemList from './ItemList';
import type { ItemProps } from './Item';

const CareerDropdown = () => {
const items: ItemProps[] = [
{
title: 'Jobbannonser',
iconName: 'newspaper-outline',
to: '/joblistings',
},
{ title: 'Bedrifter', iconName: 'briefcase-outline', to: '/companies' },
];

return <ItemList items={items} />;
};

export default CareerDropdown;
4 changes: 4 additions & 0 deletions app/components/Header/Navbar/EventsDropwdown.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
.items {
display: flex;
flex-direction: column;
}
13 changes: 13 additions & 0 deletions app/components/Header/Navbar/EventsDropwdown.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import ItemList from './ItemList';
import type { ItemProps } from './Item';

const EventsDropdown = () => {
const items: ItemProps[] = [
{ title: 'Liste', iconName: 'list-outline', to: '/events' },
{ title: 'Kalender', iconName: 'calendar-outline', to: '/events/calendar' },
];

return <ItemList items={items} />;
};

export default EventsDropdown;
28 changes: 28 additions & 0 deletions app/components/Header/Navbar/Item.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
.item {
color: var(--lego-font-color);
cursor: pointer;
padding: 0.4rem;
width: 250px;
border-radius: var(--border-radius-md);

&:hover {
background-color: var(--additive-background);
}
}

.description {
color: var(--secondary-font-color);
font-size: var(--font-size-sm);
line-height: 1.2rem;
}

.item .titleIcon {
opacity: 0;
transition: var(--easing-medium);
font-size: var(--font-size-sm);
}

.item:hover .titleIcon {
opacity: 1;
translate: 0.3rem;
}
34 changes: 34 additions & 0 deletions app/components/Header/Navbar/Item.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { Link } from 'react-router-dom';
import Icon from 'app/components/Icon';
import Flex from 'app/components/Layout/Flex';
import TextWithIcon from 'app/components/TextWithIcon';
import styles from './Item.css';

export type ItemProps = {
title: string;
iconName?: string;
to: string;
description?: string;
};

const Item = ({ iconName, title, to, description }: ItemProps) => {
return (
<Link to={to} className={styles.item}>
{iconName ? (
<TextWithIcon iconName={iconName} content={title} />
) : (
<Flex alignItems="center">
{title}{' '}
<Icon
size={18}
className={styles.titleIcon}
name="chevron-forward-outline"
/>
</Flex>
)}
{description && <p className={styles.description}>{description}</p>}
</Link>
);
};

export default Item;
4 changes: 4 additions & 0 deletions app/components/Header/Navbar/ItemGrid.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
.grid {
display: grid;
grid-template-columns: 1fr 1fr;
}
24 changes: 24 additions & 0 deletions app/components/Header/Navbar/ItemGrid.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import Item from './Item';
import styles from './ItemGrid.css';
import type { ItemProps } from './Item';

type Props = {
items: ItemProps[];
};

const ItemGrid = ({ items }: Props) => {
return (
<div className={styles.grid}>
{items.map((item) => (
<Item
key={item.title}
title={item.title}
description={item.description}
to={item.to}
/>
))}
</div>
);
};

export default ItemGrid;
24 changes: 24 additions & 0 deletions app/components/Header/Navbar/ItemList.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import Flex from 'app/components/Layout/Flex';
import Item from './Item';
import type { ItemProps } from './Item';

type Props = {
items: ItemProps[];
};

const ItemList = ({ items }: Props) => {
return (
<Flex column={true}>
{items.map((item) => (
<Item
key={item.title}
iconName={item.iconName}
title={item.title}
to={item.to}
/>
))}
</Flex>
);
};

export default ItemList;
43 changes: 43 additions & 0 deletions app/components/Header/Navbar/Navbar.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
.navigation {
display: flex;
flex-direction: row;
justify-content: space-around;
align-items: center;
flex: 2;
white-space: nowrap;
margin-right: 5px;

@media (--mobile-device) {
display: none;
}
}

.navigation a {
font-size: var(--font-size-lg);
padding: 10px 1rem;
height: 100%;
color: var(--lego-font-color);
display: flex;
align-items: center;
justify-content: center;
position: relative;
transition: color var(--linear-medium);
white-space: nowrap;

&:hover,
&.activeItem {
color: var(--color-gray-7);
}

&:hover::after,
&.activeItem::after {
transform: scaleX(1);
}
}

.navbarDropdown {
width: auto;
padding: 15px;
margin: 0;
padding-top: 10px;
}
94 changes: 94 additions & 0 deletions app/components/Header/Navbar/Navbar.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
import { useState } from 'react';
import { NavLink } from 'react-router-dom';
import Dropdown from 'app/components/Dropdown';
import AboutDropdown from './AboutDropdown';
import CareerDropdown from './CareerDropdown';
import EventsDropdown from './EventsDropwdown';
import styles from './Navbar.css';
import type { ReactElement } from 'react';

type Props = {
loggedIn: boolean;
};

type NavbarLink = {
title: string;
to: string;
visibility: 'logged-in-only' | 'logged-out-only' | 'always';
dropdown?: ReactElement;
};

const Navbar = ({ loggedIn }: Props) => {
const [visibleDropdown, setVisibleDropdown] = useState(false);
const [hoverIndex, setHoverIndex] = useState(0);

const links: NavbarLink[] = [
{
title: 'For bedrifter',
to: '/pages/bedrifter/for-bedrifter',
visibility: 'logged-out-only',
},
{
title: 'Arrangementer',
to: '/events',
dropdown: <EventsDropdown />,
visibility: 'always',
},
{
title: 'Karriere',
to: '/joblistings',
dropdown: <CareerDropdown />,
visibility: 'logged-in-only',
},
{
title: 'Om Abakus',
to: '/pages/info-om-abakus',
dropdown: <AboutDropdown />,
visibility: 'always',
},
];

return (
<div
className={styles.navigation}
onMouseEnter={() => setVisibleDropdown(true)}
onMouseLeave={() => setVisibleDropdown(false)}
>
{links.map((link, i) => {
if (
(link.visibility == 'logged-in-only' && !loggedIn) ||
(link.visibility == 'logged-out-only' && loggedIn)
)
return;

const navLinkItem = (
<NavLink
key={link.to}
to={link.to}
activeClassName={styles.activeItem}
onMouseEnter={() => setHoverIndex(i)}
>
{link.title}
</NavLink>
);

if (link.dropdown == null) return navLinkItem;

return (
<Dropdown
key={link.to}
show={visibleDropdown && hoverIndex == i}
toggle={() => setVisibleDropdown(false)}
triggerComponent={navLinkItem}
contentClassName={styles.navbarDropdown}
closeOnContentClick={true}
>
{link.dropdown}
</Dropdown>
);
})}
</div>
);
};

export default Navbar;

0 comments on commit 687d756

Please sign in to comment.