feature: responsive menu

This commit is contained in:
Benno Tielen 2024-11-22 18:22:12 +01:00
parent 2d01ae6dbf
commit ab83bf0990
8 changed files with 557 additions and 218 deletions

View file

@ -16,7 +16,181 @@ export default function RootLayout({
return ( return (
<html lang="en" className={defaultFont.className}> <html lang="en" className={defaultFont.className}>
<body> <body>
<Menu /> <Menu menu={{
leftItems: [
{
text: 'Home',
href: '/'
},
{
text: 'Gemeinschaft finden',
megaMenu: {
text: {
quote: '',
source: ''
},
groups: [
{
title: "Gemeinden",
items: [
{
title: "St. Richard",
description: "Mehr informationen",
href: "/gemeinde/st-richard"
},
{
title: "St. Christophorus",
description: "Mehr informationen",
href: "/gemeinde/st-christophorus"
},
{
title: "St. Clara",
description: "Mehr informationen",
href: "/gemeinde/st-clara"
},
]
},
{
title: "Gruppen",
items: [
{
title: "Kathoccino",
description: "Begegnung mit Gott",
href: "https://"
},
{
title: "Credo & Agape",
description: "Gebet der Meditation",
href: "https://"
},
{
title: "Mädchengruppe",
description: "Stille Begegnung mit Gott",
href: "https://"
},
{
title: "Alphakurs",
description: "Dank, Ehre und Freude",
href: "https://"
},
]
},
{
title: "Aktivitaten",
items: [
{
title: "Kochen",
description: "Begegnung mit Gott",
href: "https://"
},
{
title: "Lernen",
description: "Gebet der Meditation",
href: "https://"
},
{
title: "Wandern",
description: "Stille Begegnung mit Gott",
href: "https://"
},
{
title: "Singen",
description: "Dank, Ehre und Freude",
href: "https://"
},
]
}
]
}
},
{
text: 'Glauben lauben',
megaMenu: {
text: {
quote: '',
source: ''
},
groups: [
{
title: "Sakramenten",
items: [
{
title: "Taufe",
description: "Neues Leben in Christus",
href: "https://"
},
{
title: "Eucharistie",
description: "Gemeinschaft durch Brot und Wein",
href: "https://"
},
{
title: "Firmung",
description: "Stärkung im Heiligen Geist",
href: "https://"
},
{
title: "Ehe",
description: "Bund in Liebe, Treue",
href: "https://"
},
{
title: "Beichte",
description: "Sündenbekenntnis, Vergebung und Neuanfang mit Gottes Gnade",
href: "https://"
},
{
title: "Krankensalbung",
description: "Stärkung und Gottes Beistand",
href: "https://"
}
]
},
{
title: "Gebet",
items: [
{
title: "Gottesdienste",
description: "Begegnung mit Gott",
href: "https://"
},
{
title: "Rosenkranz",
description: "Gebet der Meditation",
href: "https://"
},
{
title: "Anbetung",
description: "Stille Begegnung mit Gott",
href: "https://"
},
{
title: "Lobpreis",
description: "Dank, Ehre und Freude",
href: "https://"
},
]
}
]
}
},
{
text: 'Kontakt',
href: '/kontakt'
}
],
rightItems: [
{
text: 'Mithelfen',
href: '/mithelfen',
},
{
text: 'Neu hier?',
href: '/ich-bin-neu',
display: "button"
}
]
}} />
<main className={"mainContent"}> <main className={"mainContent"}>
{children} {children}
</main> </main>

View file

@ -12,6 +12,7 @@ type MegaMenuProps = {
type ItemProps = { type ItemProps = {
title: string; title: string;
description: string description: string
icon?: string
href: string href: string
} }
@ -20,11 +21,13 @@ type ItemGroupProps = {
items: ItemProps[] items: ItemProps[]
} }
const Item = ({href, title, description}: ItemProps) => { const Item = ({href, title, description, icon}: ItemProps) => {
return ( return (
<Link href={href} className={styles.item}> <Link href={href} className={styles.item}>
<div className={styles.itemIcon}> {icon &&
</div> <div className={styles.itemIcon}>
</div>
}
<div> <div>
<div className={styles.itemTitle}> <div className={styles.itemTitle}>
{title} {title}
@ -41,7 +44,9 @@ const ItemGroup = ({title, items}: ItemGroupProps) => {
return ( return (
<div className={styles.itemGroup}> <div className={styles.itemGroup}>
<div className={styles.groupTitle}>{title}</div> <div className={styles.groupTitle}>{title}</div>
{items.map(item => <Item key={item.title} title={item.title} href={item.href} description={item.description} />)} <div className={styles.itemGroupContent}>
{items.map(item => <Item key={item.title} title={item.title} href={item.href} description={item.description} />)}
</div>
</div> </div>
) )
} }

View file

@ -1,10 +1,8 @@
@import "template.scss"; @import "template.scss";
$width: 220px;
.menu { .menu {
background-color: $shade3; background-color: $shade3;
display: inline-flex; display: flex;
gap: 20px; gap: 20px;
} }
@ -36,7 +34,6 @@ $width: 220px;
.itemGroup { .itemGroup {
padding: 40px; padding: 40px;
width: $width;
} }
.groupTitle { .groupTitle {
@ -69,3 +66,55 @@ $width: 220px;
font-weight: 300; font-weight: 300;
line-height: 95%; line-height: 95%;
} }
@media screen and (max-width: 576px) {
.menu {
flex-direction: column;
gap: 30px;
background-color: inherit;
}
.menu, .itemGroup, .groupTitle, .itemTitle {
font-size: 15px;
}
.itemGroup {
padding: 0px;
}
.groupTitle {
margin: 0;
color: #2c2c2c;
}
.itemGroupContent {
display: flex;
flex-wrap: wrap;
gap: 10px
}
.itemDescription {
color: #2c2c2c;
}
.item {
flex: 1 1 40%;
height: 100px;
box-sizing: border-box;
padding: 10px;
background-color: $shade3;
text-align: center;
margin: 0;
border-radius: 5px;
justify-content: center;
}
.itemDescription {
font-weight: 300;
font-size: 11px;
}
.bibleText {
display: none;
}
}

View file

@ -9,5 +9,181 @@ type Story = StoryObj<typeof Menu>
export default meta export default meta
export const Default: Story = { export const Default: Story = {
args: {}, args: {
menu: {
leftItems: [
{
text: 'Home',
href: '/'
},
{
text: 'Gemeinschaft finden',
megaMenu: {
text: {
quote: '',
source: ''
},
groups: [
{
title: "Gemeinden",
items: [
{
title: "St. Richard",
description: "Mehr informationen",
href: "/gemeinde/st-richard"
},
{
title: "St. Christophorus",
description: "Mehr informationen",
href: "/gemeinde/st-christophorus"
},
{
title: "St. Clara",
description: "Mehr informationen",
href: "/gemeinde/st-clara"
},
]
},
{
title: "Gruppen",
items: [
{
title: "Kathoccino",
description: "Begegnung mit Gott",
href: "https://"
},
{
title: "Credo & Agape",
description: "Gebet der Meditation",
href: "https://"
},
{
title: "Mädchengruppe",
description: "Stille Begegnung mit Gott",
href: "https://"
},
{
title: "Alphakurs",
description: "Dank, Ehre und Freude",
href: "https://"
},
]
},
{
title: "Aktivitaten",
items: [
{
title: "Kochen",
description: "Begegnung mit Gott",
href: "https://"
},
{
title: "Lernen",
description: "Gebet der Meditation",
href: "https://"
},
{
title: "Wandern",
description: "Stille Begegnung mit Gott",
href: "https://"
},
{
title: "Singen",
description: "Dank, Ehre und Freude",
href: "https://"
},
]
}
]
}
},
{
text: 'Glauben lauben',
megaMenu: {
text: {
quote: '',
source: ''
},
groups: [
{
title: "Sakramenten",
items: [
{
title: "Taufe",
description: "Neues Leben in Christus",
href: "https://"
},
{
title: "Eucharistie",
description: "Gemeinschaft durch Brot und Wein",
href: "https://"
},
{
title: "Firmung",
description: "Stärkung im Heiligen Geist",
href: "https://"
},
{
title: "Ehe",
description: "Bund in Liebe, Treue",
href: "https://"
},
{
title: "Beichte",
description: "Sündenbekenntnis, Vergebung und Neuanfang mit Gottes Gnade",
href: "https://"
},
{
title: "Krankensalbung",
description: "Stärkung und Gottes Beistand",
href: "https://"
}
]
},
{
title: "Gebet",
items: [
{
title: "Gottesdienste",
description: "Begegnung mit Gott",
href: "https://"
},
{
title: "Rosenkranz",
description: "Gebet der Meditation",
href: "https://"
},
{
title: "Anbetung",
description: "Stille Begegnung mit Gott",
href: "https://"
},
{
title: "Lobpreis",
description: "Dank, Ehre und Freude",
href: "https://"
},
]
}
]
}
},
{
text: 'Kontakt',
href: '/kontakt'
}
],
rightItems: [
{
text: 'Mithelfen',
href: '/mithelfen',
},
{
text: 'Neu hier?',
href: '/ich-bin-neu',
display: "button"
}
]
}
},
} }

View file

@ -4,216 +4,88 @@ import styles from './styles.module.scss'
import MenuIcon from './menu.svg' import MenuIcon from './menu.svg'
import Image from 'next/image' import Image from 'next/image'
import classNames from 'classnames' import classNames from 'classnames'
import {Menu as MenuType, MenuItem as MenuItemType} from "./menu.types"
import { Logo } from '@/components/Logo/Logo'
import { useState } from 'react' import { useState } from 'react'
import { MegaMenu } from '@/components/MegaMenu/MegaMenu' import { MegaMenu } from '@/components/MegaMenu/MegaMenu'
const MenuItem = ({text, href, display = "normal", megaMenu}: MenuItemType) => {
const className = classNames({
[styles.menuLink]: display === "normal",
[styles.button]: display === "button"
});
export const Menu = () => { const [displayMegaMenu, setDisplayMegaMenu] = useState(false)
const [displayMenu2, setDisplayMenu2] = useState(false);
const [displayMenu1, setDisplayMenu1] = useState(false);
const displayFirstMenu = () => {
setDisplayMenu1(true);
setDisplayMenu2(false);
}
const displaySecondMenu = () => {
setDisplayMenu2(true)
setDisplayMenu1(false)
}
const displayNothing = () => {
setDisplayMenu1(false);
setDisplayMenu2(false);
}
return ( return (
<> <>
<nav className={classNames(styles.nav)}> <a className={className} href={href} onClick={() => setDisplayMegaMenu(!displayMegaMenu)}>
<div className={styles.navMobile}> {text}
<Image src={MenuIcon} width={25} height={25} alt={'Menu'} /> </a>
</div>
<div className={styles.itemsLeft}>
<a className={styles.menuLink} href={'/'} onMouseEnter={displayNothing}>
Home
</a>
<a className={styles.menuLink} href={''} onMouseEnter={displayFirstMenu}>
Gemeinschaft finden
</a>
<a className={styles.menuLink} href={''} onMouseEnter={displaySecondMenu}>
Glauben leben
</a>
<a className={styles.menuLink} href={''} onMouseEnter={displayNothing}>
Kontakt
</a>
</div>
<div className={styles.itemsRight}> {megaMenu && displayMegaMenu &&
<div> <div className={styles.megaMenu}>
<a className={styles.menuLink} href={''}> <MegaMenu bibleText={megaMenu.text.quote} bibleBook={megaMenu.text.source} groups={megaMenu.groups} />
Mithelfen
</a>
</div>
<div>
<button className={styles.button}>Neu hier?</button>
</div>
</div> </div>
</nav> }
<div </>
className={styles.megaMenu}
style={{ display: displayMenu2 ? 'block' : 'none', opacity: displayMenu2 ? 1 : 0 }} )
onMouseLeave={() => setDisplayMenu2(false)} }
>
<MegaMenu type MenuItemsProps = {
bibleText={"Ich will den HERRN loben allezeit; sein Lob soll immerdar in meinem Munde sein. Meine Seele soll sich rühmen des HERRN, dass es die Elenden hören und sich freuen."} items: MenuItemType[]
bibleBook={"Psalm 34 2,3"} }
onClick={() => setDisplayMenu2(false)}
groups={[ const MenuItems = ({items}: MenuItemsProps) => {
{ return (
title: "Sakramenten", <>
items: [ {items.map(item =>
{ <MenuItem
title: "Taufe", key={item.text}
description: "Neues Leben in Christus", text={item.text}
href: "https://" href={item.href}
}, display={item.display}
{ megaMenu={item.megaMenu}
title: "Eucharistie", />
description: "Gemeinschaft durch Brot und Wein", )}
href: "https://" </>
}, )
{ }
title: "Firmung",
description: "Stärkung im Heiligen Geist", type MenuProps = {
href: "https://" menu: MenuType
}, }
{
title: "Ehe", export const Menu = ({menu}: MenuProps) => {
description: "Bund in Liebe, Treue",
href: "https://" const [displayMenuMobile, setDisplayMenuMobile] = useState(false)
},
{
title: "Beichte", return (
description: "Sündenbekenntnis, Vergebung und Neuanfang mit Gottes Gnade", <>
href: "https://" <nav className={classNames(styles.nav, {[styles.full]: displayMenuMobile})}>
}, <div className={styles.navMobile}>
{ <Logo withText={false} height={30} color={"#426156"}/>
title: "Krankensalbung", <Image
description: "Stärkung und Gottes Beistand", src={MenuIcon}
href: "https://" width={25}
} height={25}
] alt={'Menu'}
}, onClick={() => setDisplayMenuMobile(!displayMenuMobile)}
{ />
title: "Gebet", </div>
items: [
{ <div className={classNames(styles.itemsLeft, {[styles.hide]: !displayMenuMobile})}>
title: "Gottesdienste", <MenuItems items={menu.leftItems} />
description: "Begegnung mit Gott", </div>
href: "https://"
}, <div className={classNames(styles.itemsRight, {[styles.hide]: !displayMenuMobile})}>
{ <MenuItems items={menu.rightItems} />
title: "Rosenkranz", </div>
description: "Gebet der Meditation",
href: "https://" </nav>
},
{
title: "Anbetung",
description: "Stille Begegnung mit Gott",
href: "https://"
},
{
title: "Lobpreis",
description: "Dank, Ehre und Freude",
href: "https://"
},
]
}
]} />
</div>
<div
className={styles.megaMenu}
style={{ display: displayMenu1 ? 'block' : 'none', opacity: displayMenu1 ? 1 : 0 }}
onMouseLeave={() => setDisplayMenu1(false)}
>
<MegaMenu
bibleText={"„Denn wo zwei oder drei in meinem Namen versammelt sind, da bin ich mitten unter ihnen.“"}
bibleBook={"Matt 18-2"}
onClick={() => setDisplayMenu1(false)}
groups={[
{
title: "Gemeinden",
items: [
{
title: "St. Richard",
description: "Mehr informationen",
href: "/gemeinde/st-richard"
},
{
title: "St. Christophorus",
description: "Mehr informationen",
href: "/gemeinde/st-christophorus"
},
{
title: "St. Clara",
description: "Mehr informationen",
href: "/gemeinde/st-clara"
},
]
},
{
title: "Gruppen",
items: [
{
title: "Kathoccino",
description: "Begegnung mit Gott",
href: "https://"
},
{
title: "Credo & Agape",
description: "Gebet der Meditation",
href: "https://"
},
{
title: "Mädchengruppe",
description: "Stille Begegnung mit Gott",
href: "https://"
},
{
title: "Alphakurs",
description: "Dank, Ehre und Freude",
href: "https://"
},
]
},
{
title: "Aktivitaten",
items: [
{
title: "Kochen",
description: "Begegnung mit Gott",
href: "https://"
},
{
title: "Lernen",
description: "Gebet der Meditation",
href: "https://"
},
{
title: "Wandern",
description: "Stille Begegnung mit Gott",
href: "https://"
},
{
title: "Singen",
description: "Dank, Ehre und Freude",
href: "https://"
},
]
}
]} />
</div>
</> </>
) )

View file

@ -0,0 +1,33 @@
export type Menu = {
leftItems: MenuItem[]
rightItems: MenuItem[]
}
export type MenuItem = {
text: string,
href?: string
megaMenu?: MegaMenu
display?: "normal" | "button"
}
type MegaMenu = {
groups: MegaMenuGroup[]
text: MegaMenuText
}
type MegaMenuGroup = {
title: string
items: MegaMenuItem[]
}
type MegaMenuItem = {
title: string,
description: string
href: string
icon?: string
}
type MegaMenuText = {
quote: string
source: string
}

View file

@ -2,7 +2,6 @@
.nav { .nav {
display: flex; display: flex;
align-items: center;
gap: 20px; gap: 20px;
color: $base-color; color: $base-color;
padding: 15px 45px; padding: 15px 45px;
@ -14,6 +13,8 @@
box-sizing: border-box; box-sizing: border-box;
z-index: 1; z-index: 1;
backdrop-filter: blur(8px); backdrop-filter: blur(8px);
font-size: 18px;
align-items: baseline;
} }
.navMobile { .navMobile {
@ -23,6 +24,7 @@
.itemsLeft { .itemsLeft {
display: flex; display: flex;
gap: 30px; gap: 30px;
flex-grow: 1;
} }
.menuLink { .menuLink {
@ -30,6 +32,7 @@
text-decoration: none; text-decoration: none;
font-weight: 600; font-weight: 600;
transition: opacity 100ms ease-in; transition: opacity 100ms ease-in;
cursor: pointer;
} }
.menuLink:hover { .menuLink:hover {
@ -37,10 +40,8 @@
} }
.itemsRight { .itemsRight {
margin-left: auto;
display: flex; display: flex;
gap: 20px; gap: 20px;
justify-content: flex-end;
align-items: baseline; align-items: baseline;
} }
@ -48,6 +49,8 @@
padding: 10px; padding: 10px;
border-radius: 10px; border-radius: 10px;
border: none; border: none;
color: inherit;
text-decoration: none;
background-color: #eeeeee; background-color: #eeeeee;
transition: background-color 0.1s ease-in-out; transition: background-color 0.1s ease-in-out;
font-family: inherit; font-family: inherit;
@ -62,17 +65,44 @@
.megaMenu { .megaMenu {
position: fixed; position: fixed;
top: 76px; top: 76px;
left: 0;
width: 100%;
z-index: 8; z-index: 8;
opacity: 0;
transition: opacity 0.2s ease-in-out;
} }
@media screen and (max-width: 800px) { @media screen and (max-width: 800px) {
.nav {
flex-direction: column;
padding: 15px 15px;
align-items: inherit;
}
.megaMenu {
position: inherit;
}
.navMobile { .navMobile {
display: block; display: flex;
align-items: center;
justify-content: space-between;
} }
.itemsLeft { .itemsLeft {
padding-bottom: 15px;
border-bottom: 1px solid #d0d0d0;
}
.itemsLeft, .itemsRight {
gap: 10px;
flex-direction: column;
}
.hide {
display: none; display: none;
} }
.full {
height: 100vh;
overflow: scroll;
}
} }