My project is running on vue3.
I have a Side navigation bar which consists of navigation links, it works well until I import bootstrap, which causes the icons to shift slightly and the buttons become smaller in size. I've tried the same with tailwind and the same issue occurs. The exact line that breaks it is the import of bootstraps min css file. (import "bootstrap/dist/css/bootstrap.min.css", inside of main.js).Below are screenshots and snippets of code for the navigation bar.
<script>
import NavBarLink from './NavBarLink.vue'
import {collapsed, toggleNavbar, navbarWidth} from './state'
export default{
props: {},
setup() {
return { collapsed, toggleNavbar, navbarWidth };
},
components: { NavBarLink }
}
</script>
<template>
<div class="sidebar" :style="{ width: navbarWidth }">
<span #click="toggleNavbar" style="margin-bottom: 15px;">
<i :class="`${collapsed ? 'fa-solid fa-bars': 'fa-solid fa-x'}`"></i>
</span>
<span v-if="!collapsed" class="logo">website.<span style="color: orange">club</span></span>
<span v-else class="logo">w<span style="color: orange">w</span></span>
<NavBarLink to="/about" icon="fa-solid fa-magnifying-glass">Search</NavBarLink>
<NavBarLink to="/plans" icon="fa-solid fa-tag">Plans</NavBarLink>
<NavBarLink to="/fart" icon="fa-solid fa-user">Profile</NavBarLink>
</div>
</template>
<style>
:root {
--navbar-bg-color: #0e0e0e;
--navbar-item-hover: #1d1d1d;
}
</style>
<style scoped>
.sidebar{
color: white;
background-color: var(--navbar-bg-color);
float: left;
position: fixed;
z-index: 1;
top: 0;
bottom: 0;
left: 0;
bottom: 0;
padding: 0.5rem;
transition: 0.3s ease;
display: flex;
flex-direction: column;
}
.logo {
font-size: larger;
font-family: Nexa;
padding-top:15px;
padding-bottom:15px;
}
</style>
<script>
import { computed } from 'vue'
import { useRoute } from 'vue-router'
import { collapsed } from './state'
export default {
props: {
to: { type: String, required: true },
icon: { type: String, required: true }
},
setup(props) {
const route = useRoute()
const isActive = computed(() => route.path === props.to)
return { isActive, collapsed }
}
}
</script>
<template>
<router-link :to="to" class="link" :class="{ active: isActive }">
<i class="icon" :class="icon"/>
<transition name="fade">
<span v-if="!collapsed">
<slot/>
</span>
</transition>
</router-link>
</template>
<style scoped>
.fade-enter-active,
.fade-leave-active {
transition: opacity 0.1s;
}
.fade-enter,
.fade-leave-to {
opacity: 0;
}
.link {
display: flex;
align-items: center;
cursor: pointer;
position: relative;
font-weight: 400;
user-select: none;
margin: 0.1em 0.1em;
padding: 0.4em;
border-radius: 0.25em;
height: 1.7em;
color: white;
text-decoration: none;
}
.link:hover {
transition: .17s;
background-color: var(--navbar-item-hover);
}
.link.active {
background-color: var(--navbar-item-hover);
}
.link .icon {
flex-shrink: 0;
width: 35px;
margin-right: 10px;
}
</style>
Is there a bootstrap component I can remove to make this function?
Related
I want to make my mobile menu have a dropdown when the main labels are clicked as they do for the regular desktop navigation. The dropdown works for the mobile menu, but it displays it on the left side of the main label. What I want it to do is expand or toggle/show underneath the top label when clicked if that makes sense. An example would be the mobile menu here: https://www.youtube.com/watch?v=JEV7WE0UBiQ&t=2738s, but in my case, I only need to go one dropdown deep.
Here are my Navbar and Dropdown components for review. I also provided the relevant CSS as well.
I know there is much to be improved and there are other small errors I am getting, but if I can get help on this part, that would be great. I've actually been using the help of ChatGPT to assist with some things, but it can only get me so far. Sometimes it's great, and other times I just want to punch it, lol!
import React, { useState } from "react";
import Link from "next/link";
import Dropdown from "./Dropdown";
import { menuItems, mobileMenuItems } from "./MenuItems";
// Import the FontAwesomeIcon component
import { FontAwesomeIcon } from "#fortawesome/react-fontawesome";
// import the icons you need
import {
faChevronDown,
faBars,
faXmark,
} from "#fortawesome/free-solid-svg-icons";
function Navbar() {
const [click, setClick] = useState(false);
const [dropdownOpen, setDropdownOpen] = useState({
dropdown1: false,
dropdown2: false,
dropdown3: false,
});
const handleClick = () => {
setClick(!click);
setDropdownOpen({ dropdown1: false, dropdown2: false, dropdown3: false });
};
const closeMobileMenu = () => {
setClick(false);
setDropdownOpen({ dropdown1: false, dropdown2: false, dropdown3: false });
};
const toggleDropdown = (dropdown) => {
if (window.innerWidth < 950) {
setDropdownOpen({ [dropdown]: !dropdownOpen[dropdown] });
} else {
setDropdownOpen({ [dropdown]: !dropdownOpen[dropdown] });
}
};
return (
<nav>
<div className="container mx-auto px-10 mb-8">
<div className="relative border-b w-full inline-block border-blue-400 py-8">
<div className="absolute inset-y-0 left-0 flex items-center sm:hidden">
{/* Mobile menu button*/}
<button
className="inline-flex p-2 rounded-md text-gray-400 hover:text-white hover:bg-violet-700 focus:outline-none focus:ring-2 focus:ring-inset focus:ring-white text-3xl md:hidden"
onClick={() => {
setClick(!click);
}}
>
<FontAwesomeIcon icon={click ? faXmark : faBars} />
</button>
</div>
<div className="flex-1 flex items-center justify-center sm:items-stretch sm:justify-start">
<div className="flex-1 flex flex-shrink-0 flex px-12 items-center ">
<h1 className="font-bold text-4xl cursor-pointer text-white">
My<span className="text-blue-500">site</span>
</h1>
</div>
<div className="hidden md:float-left md:contents">
<ul className="nav-menu">
{menuItems.map((link, index) => (
<li
key={index}
className="nav-item"
onMouseEnter={
link.dropdownType
? () => toggleDropdown(link.dropdownType)
: null
}
onMouseLeave={
link.dropdownType
? () => toggleDropdown(link.dropdownType)
: null
}
>
<Link href={link.href}>
<a className="menuItems nav-links">
{link.icon && (
<FontAwesomeIcon
className="px-2"
icon={link.icon}
style={{ fontSize: 20, color: link.color }}
/>
)}
{link.label}
{link.dropdownType && (
<span className="faChevronDown">
<FontAwesomeIcon
icon={faChevronDown}
></FontAwesomeIcon>
</span>
)}
</a>
</Link>
{link.dropdownType && dropdownOpen[link.dropdownType] && (
<Dropdown type={link.dropdownType} />
)}
</li>
))}
</ul>
</div>
</div>
</div>
</div>
{/* ----------------------Hamburger Menu----------------------- */}
<ul
className={click ? "mobileNav-menu active" : "sm:hidden mobileNav-menu"}
>
{mobileMenuItems.map((link, index) => (
<li key={index} className="nav-item">
<Link href={link.href}>
<a
onClick={
link.dropdownType
? () => toggleDropdown(link.dropdownType)
: closeMobileMenu
}
className="menuItems nav-links dropdown-toggle"
>
{link.icon && (
<FontAwesomeIcon
className="px-2"
icon={link.icon}
style={{ fontSize: 20, color: link.color }}
/>
)}
{link.label}
{link.dropdownType && (
<span className="faChevronDown">
<FontAwesomeIcon icon={faChevronDown}></FontAwesomeIcon>
</span>
)}
</a>
</Link>
{link.dropdownType && dropdownOpen[link.dropdownType] && (
<ul className="dropdown-menu">
<Dropdown type={link.dropdownType} onClick={closeMobileMenu} />
</ul>
)}
</li>
))}
</ul>
</nav>
);
}
export default Navbar;
and the Dropdown component
import React, { useState, useEffect } from "react";
import Link from "next/link";
import {
getFeaturedArticlesCategories,
getNewsCategories,
getReviewsCategories,
} from "../services";
function useCategories() {
const [categories, setCategories] = useState({
featured: [],
news: [],
reviews: [],
});
useEffect(() => {
let cancel = false;
const fetchCategories = async () => {
const featured = await getFeaturedArticlesCategories();
const news = await getNewsCategories();
const reviews = await getReviewsCategories();
if (!cancel) {
setCategories({ featured, news, reviews });
}
};
fetchCategories();
return () => {
cancel = true;
};
}, []);
return categories;
}
function Dropdown({ type, onClick }) {
const [click, setClick] = useState(false);
const categories = useCategories();
const handleClick = () => setClick(!click);
return (
<>
<ul
onClick={() => {
handleClick();
onClick();
}}
className={click ? "dropdown-menu clicked" : "dropdown-menu"}
>
{categories[type].map((item, { active }) => (
<Link href={`/${type}/${item.slug}`} key={item.slug}>
<a
className={`group flex justify-center items-center px-4 py-2 text-sm font-semibold cursor-pointer ${
active
? "text-gray-700"
: "menuItems hover:bg-indigo-500 transition-all duration-500 ease-in"
}`}
>
{item.name}
</a>
</Link>
))}
</ul>
</>
);
}
export default Dropdown;
and the CSS
//Nav Menu
.menuItems {
&:hover {
color: rgb(255, 0, 0);
}
}
.navbar {
width: 90%;
height: 6rem;
display: flex;
justify-content: center;
align-items: center;
font-size: 1.2rem;
padding-left: 2.5rem;
padding-right: 2.5rem;
margin-left: auto;
margin-right: auto;
margin-bottom: 5rem;
border-bottom-width: 1px;
border-color: #60a5fa;
}
.navbar-logo {
color: #fff;
justify-self: start;
margin-left: -1rem;
cursor: pointer;
text-decoration: none;
line-height: 2.5rem;
font-size: 2.25rem;
font-weight: 700;
}
.nav-menu {
display: grid;
grid-template-columns: repeat(5, auto);
grid-gap: 1rem;
list-style: none;
text-align: center;
width: 70vw;
justify-content: end;
margin-right: 2rem;
}
.nav-item {
display: flex;
align-items: center;
height: 4rem;
}
.nav-links {
color: white;
text-decoration: none;
padding: 0.5rem 1rem;
display: inline-flex;
font-weight: 600;
justify-content: center;
width: 100%;
cursor: pointer;
}
.nav-links:hover {
background-color: #1888ff;
border-radius: 4px;
transition: all 0.2s ease-out;
}
.faBars {
color: #fff;
}
.nav-links-mobile {
display: none;
}
.menu-icon {
display: none;
}
#media screen and (max-width: 950px) {
.NavbarItems {
position: relative;
}
.mobileNav-menu {
display: flex;
flex-direction: column;
width: 100%;
height: 90vh;
position: absolute;
padding-top: 5rem;
padding-bottom: 15rem;
padding-left: 1rem;
bottom: 0;
top: 5rem;
left: -100%;
opacity: 1;
transition: all 0.5s ease;
}
.mobileNav-menu.active {
background: #242222;
left: 0;
opacity: 1;
transition: all 0.5s ease;
z-index: 1;
}
.nav-links {
text-align: center;
padding: 2rem;
width: 100%;
display: table;
}
.nav-links:hover {
background-color: #1888ff;
border-radius: 0;
}
.navbar-logo {
position: absolute;
top: 0;
left: 0;
transform: translate(25%, 50%);
}
.menu-icon {
display: block;
position: absolute;
top: 0;
right: 0;
transform: translate(-100%, 60%);
font-size: 1.8rem;
cursor: pointer;
}
.faXmark {
color: #fff;
font-size: 2rem;
}
.faChevronDown {
margin-left: 0.5rem;
padding: 0.5rem;
}
.nav-links-mobile {
display: block;
text-align: center;
padding: 1.5rem;
margin: 2rem auto;
border-radius: 4px;
width: 80%;
background: #1888ff;
text-decoration: none;
color: #fff;
font-size: 1.5rem;
}
.nav-links-mobile:hover {
background: #fff;
color: #1888ff;
transition: 250ms;
}
}
//Dropdown
.dropdown-menu {
background: rgb(184, 183, 231);
width: 10rem;
position: absolute;
border-radius: 0.375rem;
top: 6rem;
list-style: none;
text-align: start;
z-index: 10;
}
.dropdown-menu li {
background: #1888ff;
cursor: pointer;
}
.dropdown-menu li:hover {
background: #5cabff;
}
.dropdown-menu.clicked {
display: none;
}
.dropdown-link {
display: block;
height: 100%;
width: 100%;
text-decoration: none;
color: #fff;
padding: 16px;
}
I am making a dashboard for my project in which I am also including navbar in it , but when I included navbar , it is covering the whole length of the screen . I tried a lot , but I am not that much pro in css , can anyone correct this code ??
Here is my dashboard code :
import React from 'react';
import Navbar from './components/Navbar/Navbar';
import RightNavbar from './components/RightNavbar/RightNavbar';
import styles from './App.module.scss';
function App({ history }) {
return (
<div>
<Navbar/>
<RightNavbar/>
<ToastContainer />
<div className = {styles.container}>
</div>
</div>
);
}
export default App;
Here is my Navbar code :
//STYLES
import styles from "./Navbar.module.scss";
//CONTEXT
import { useContext } from "react";
import NavContext from "../../Context/NavContext";
//REACT ROUTER
import { NavLink } from "react-router-dom";
//ICONS
import {
MdOutlineDashboard,
MdOutlineAnalytics,
MdOutlinedFlag,
MdPeopleOutline,
MdOutlineMessage,
MdOutlineLogout,
} from "react-icons/md";
import { IoMdLogIn } from "react-icons/io";
import { FaReact, FaTimes } from "react-icons/fa";
import { BsThreeDots } from "react-icons/bs";
import { VscDashboard } from "react-icons/vsc";
const NavUrl = ({ url, icon, description }) => {
const { nav, setNav } = useContext(NavContext);
const checkWindowSize = () => {
if (window.innerWidth < 1024) setNav(!nav);
};
return (
<li className={styles.li_navlink}>
<NavLink
to={`${url}`}
className={({ isActive }) => (isActive ? styles.active : undefined)}
onClick={() => checkWindowSize()}
>
{icon}
<span className={styles.description}>{description}</span>
</NavLink>
</li>
);
};
const Navbar = () => {
const { nav, setNav } = useContext(NavContext);
return (
<div
className={`${styles.navbar_container} ${
nav ? styles.navbar_mobile_active : undefined
}`}
>
<nav className={nav ? undefined : styles.nav_small}>
{/* LOGO */}
<div className={styles.logo}>
<VscDashboard className={styles.logo_icon} />
<FaTimes
className={styles.mobile_cancel_icon}
onClick={() => {
setNav(!nav);
}}
/>
</div>
{/* MENU */}
<ul className={styles.menu_container}>
{/* FIRST CATEGORY */}
<span className={styles.categories}>
{nav ? "Pages" : <BsThreeDots />}
</span>
<NavUrl
url="/"
icon={<MdOutlineDashboard />}
description="Dashboard"
/>
<NavUrl
url="analytics"
icon={<MdOutlineAnalytics />}
description="Analytics"
/>
<NavUrl
url="campaings"
icon={<MdOutlinedFlag />}
description="Campaings"
/>
<NavUrl url="team" icon={<MdPeopleOutline />} description="Team" />
<NavUrl
url="messages"
icon={<MdOutlineMessage />}
description="Messages"
/>
</ul>
{/* LOGOUT BUTTON */}
<div
className={`${styles.btn_logout}`}
onClick={() => {
setNav(!nav);
}}
>
<MdOutlineLogout />
</div>
</nav>
<div
className={nav ? styles.mobile_nav_background_active : undefined}
onClick={() => {
setNav(!nav);
}}
></div>
</div>
);
};
export default Navbar;
And here is my Navbar.module.scss :
.navbar_container {
--color_nav_bg: rgb(30, 41, 59);
--color_nav_txt: rgb(100, 116, 139);
--color_nav_ctg: rgb(226, 232, 240);
--color_nav_active: rgb(85, 79, 232);
--color_nav_not_active: rgb(61, 74, 94);
--color_nav_active_bg: rgb(15, 23, 42);
--nav_width: 16rem;
background: var(--color_nav_bg);
height: 100vh;
padding: var(--padding-md) var(--padding-sm);
transition: transform 300ms ease-in-out;
#media screen and (max-width: 1024px) {
transform: translateX(-100%);
position: absolute;
top: 0;
left: 0;
z-index: 12;
}
#media screen and (max-width: 18rem) {
width: 100vw;
}
}
.navbar_mobile_active {
#media screen and (max-width: 1024px) {
transform: translateX(0);
}
}
nav {
position: relative;
width: var(--nav_width);
height: 100%;
display: flex;
flex-direction: column;
overflow-y: scroll;
overflow-x: hidden;
-ms-overflow-style: none; /* IE and Edge */
scrollbar-width: none; /* Firefox */
transition: width linear 0.3s;
&::-webkit-scrollbar {
display: none;
}
}
.logo {
padding: 0 0.35rem;
font-size: 2.2rem;
display: flex;
.logo_icon {
color: var(--color_nav_active);
}
.mobile_cancel_icon {
display: none;
}
#media screen and (max-width: 1024px) {
.logo_icon {
display: none;
}
.mobile_cancel_icon {
display: block;
cursor: pointer;
font-size: 2.2rem;
padding: 0.2rem;
color: var(--color_nav_active);
}
}
}
.menu_container {
margin-top: var(--margin-lg);
display: flex;
flex-direction: column;
gap: 0.3rem;
}
.categories {
color: var(--color_nav_txt);
text-transform: uppercase;
font-size: 0.8rem;
margin-bottom: var(--margin-xxs);
svg {
font-size: 1rem;
}
}
.second_category {
margin-top: 3rem;
}
.li_navlink a {
display: flex;
align-items: center;
flex: 1;
padding: 0.5rem 0.75rem;
text-decoration: none;
color: var(--color_nav_ctg);
transition: all ease-in-out 0.2s;
.description {
margin-left: 0.5rem;
font-weight: 400;
transition: opacity 200ms ease;
}
svg {
font-size: 1.5rem;
color: var(--color_nav_not_active);
flex-shrink: 0;
}
&:hover {
background: var(--color_nav_active_bg);
}
&:hover svg {
color: var(--color_nav_active);
}
}
.li_navlink .active {
background: var(--color_nav_active_bg);
svg {
color: var(--color_nav_active);
}
}
.btn_logout {
margin-top: auto;
display: flex;
justify-content: flex-end;
transition: all ease-in-out 200ms;
padding: 0.5rem 0.75rem 0 0.75rem;
svg {
font-size: 1.5rem;
color: var(--color_nav_active);
cursor: pointer;
transform: scaleX(-1);
}
}
.mobile_nav_background_active {
width: 0;
height: 100vh;
transition: all ease-out 500ms;
transition-delay: 300ms;
cursor: pointer;
#media screen and (max-width: 1024px) {
display: block;
position: absolute;
top: 0;
left: calc(var(--nav_width) + var(--padding-md));
width: calc(100vw - var(--nav_width) - var(--padding-md));
background: rgba(0, 0, 0, 0.185);
z-index: -1;
}
}
//NAVIGATION SMALL
.nav_small {
width: 3rem;
.categories {
padding: 0 1rem;
}
.description {
opacity: 0;
}
.btn_logout {
svg {
transform: scaleX(1);
}
}
}
currently, to style my icons under the 'react-icons' library, I am using the 'IconContext.Provider' tag. However, is there a solution for me to change the size of the icon dynamically based on the size of my media ?
Is the only solution to go about doing this only with the global stylesheet? I am avoiding it as I have only just started using NextJs and I do not want my style to have a possible clash with other style. Hence, I am separating them into modules.
Thank you.
NavBar.Module.Css
#import url("https://fontlibrary.org//face/metropolis");
.siteTitleWrapper {
box-sizing: border-box;
display: table-cell;
vertical-align: middle;
}
.siteTitle {
font-family: "MetropolisRegular";
font-weight: 600;
font-style: normal;
font-size: 20px;
letter-spacing: 2px;
text-transform: uppercase;
color: #000;
margin: 0;
padding-top: 0;
padding-bottom: 0;
line-height: 1em;
white-space: nowrap;
}
.headerInner {
padding: 20px 0;
display: table;
width: 100%;
}
.mainNavigation {
text-align: right;
position: relative;
z-index: 1000;
display: block;
}
.NavItemsWrapper {
display: inline-flex;
align-items: center;
overflow: hidden;
cursor: pointer;
}
.NavItems {
font: "MetropolisRegular";
font-weight: 600;
font-style: normal;
font-size: 13px;
letter-spacing: 2px;
text-transform: uppercase;
text-decoration: none;
}
#media only screen and (max-width: 830px) {
.mainNavigation {
-webkit-font-smoothing: subpixel-antialiased;
display: inline-flexbox;
position: fixed;
bottom: 64px;
left: 0;
height: auto;
width: 100%;
background-color: #f7f7f7;
overflow: hidden;
text-align: center;
vertical-align: top;
}
.NavItems {
display: none;
}
}
NavBar.tsx
import Link from 'next/link'
import styles from '../styles/components/NavBar.module.css'
import {HiHome} from 'react-icons/hi'
import {FaBloggerB} from 'react-icons/fa'
import {AiOutlineFundProjectionScreen} from 'react-icons/ai'
import {BsPersonBadge} from 'react-icons/bs'
import {IconContext} from 'react-icons'
import { IconType } from 'react-icons/lib'
interface navItemsTypes {
icon: IconType,
category: string,
link: string
}
const navItems : navItemsTypes[] = [
{icon: HiHome, category: 'Home', link: '/'},
{icon: AiOutlineFundProjectionScreen, category: 'Projects', link: '/projects'},
{icon: FaBloggerB, category: 'Blogs', link: '/blogs'},
{icon: BsPersonBadge, category: 'About', link: '/about'},
]
const NavBar = () => {
return (
<div>
<nav className={styles.headerInner}>
<div className={styles.siteTitleWrapper}>
<h1 id="site-title" className={styles.siteTitle} ><Link href='/'>Hong Sheng Yang</Link></h1>
</div>
<div className={styles.mainNavigation}>
<IconContext.Provider value={{ size: '1em', style:{marginLeft:'3em',marginRight:'0.5em', color:'#000'}}}>
{navItems.map((item) => (
<div className={styles.NavItemsWrapper}>
<Link href={item.link}>
<span style={{display:'flex'}}>
<item.icon/>
<p className={styles.NavItems}>
{item.category}
</p>
</span>
</Link>
</div>
))}
</IconContext.Provider>
</div>
</nav>
</div>
)
}
export default NavBar
I did "npm i react-responsive" and import the following in my code
import { useMediaQuery } from 'react-responsive'
Additionally, I declared the sizes for mobile and phone with 2 const
const phoneViewNav = {
size: '1em',
}
const DesktopViewNav = {
size: '1.5em',
}
Lastly, I use the media query to check for the screen size and apply accordingly
const NavBar = () => {
const isDesktopOrLaptop = useMediaQuery({maxWidth:830})
const iconSize = isDesktopOrLaptop ? phoneViewNav : DesktopViewNav
const router = useRouter();
return (
<div id="nav">
....
<IconContext.Provider value={{ size: iconSize.size, style:{color:"#000"}}}> ...
</div> )}
I'm using the latest version of Bootstrap and want to toggle between the famous X icon and hamburger menu. I don't know if I can actually change the 3 lines of the menu since it's by default, but these 2 icons presently overlap each other.
So there are 2 questions here:
How can I toggle these two icons?
When the menu is clicked, it should have a complete white background (right now it doesn't completely cover the screen in white)
Sorry I don't have a sandbox example for you right now.
Thanks for your input!
/*JSX code*/
import React from 'react';
import { NavigationBarStyled } from './style';
import { Nav, Navbar } from 'react-bootstrap';
//IMAGES
import logo from '../../images/adyslogo.png';
import Image from 'react-bootstrap/Image';
import { GrCart } from 'react-icons/gr';
import CloseButton from '../../images/closebutton.svg';
const NavigationBar = () => {
return (
<NavigationBarStyled>
<Navbar expand='sm' fixed='top'>
<Navbar.Brand href='/'><Image src={logo} className='logo'/></Navbar.Brand>
<div className='close-button'>
<button type="button" className="x-closebutton" aria-label="Close">
<img src={CloseButton} className='x-button' alt="close configuration" draggable="false" />
</button>
<Navbar.Toggle aria-controls='basic-navbar-nav' className='hamburger-menu'/>
</div>
<Navbar.Collapse id='basic-navbar-nav'>
<Nav className='mr-auto'>
<Nav.Item><Nav.Link href='/' className="middle-menu">HOME</Nav.Link></Nav.Item>
<Nav.Item><Nav.Link href='/about' className="middle-menu">ABOUT</Nav.Link></Nav.Item>
<Nav.Item><Nav.Link href='/menu' className="middle-menu">MENU</Nav.Link></Nav.Item>
<Nav.Item><Nav.Link href='/gallery' className="middle-menu">GALLERY</Nav.Link></Nav.Item>
<Nav.Item><Nav.Link href='/contact' className="middle-menu">CONTACT</Nav.Link></Nav.Item>
</Nav>
<Nav className='ml-auto'>
<Nav.Item><Nav.Link href='/cart'><GrCart size='25px' className='cart'/></Nav.Link></Nav.Item>
</Nav>
</Navbar.Collapse>
</Navbar>
</NavigationBarStyled>
)
}
export default NavigationBar;
/*CSS*/
import styled from 'styled-components';
export const NavigationBarStyled = styled.nav`
.navbar {
background-color: #FFF;
height: 80px;
}
.navbar-brand, .navbar-nav .nav-link {
color: #273746 ;
font-size: 1rem;
font-weight: 600;
&:hover {
color: rgb(255, 20, 147);
}
}
.logo {
max-height: 60px;
max-width: 60px;
}
.middle-menu {
margin: 20px;
}
.cart {
margin-right: 50px;
}
.close-button {
display: flex;
align-items: flex-start;
justify-content: flex-start;
}
.x-closebutton {
display: flex;
align-items: flex-start;
justify-content: flex-start;
border: none;
background-color: #fff;
margin-right: -54px;
}
.x-button {
display: flex;
width: 45px;
height: 45px;
cursor: pointer;
}
.hamburger-menu {
border: none;
color: #000;
}
.mr-auto {
display: flex;
align-items: center;
background-color: white;
min-width: 100vw;
min-height: 100vh;
}
`;
It's actually rather easy to toggle state but, keep in mind you won't have the graceful height calculation which comes with Bootstrap.
I'll comment out what doesn't seem important to this answer...
import React, { Component } from "react";
//import { Link } from "gatsby";
//import Image from "./image";
import "../../scss/molecules/_topnav.scss";
//const helpers = require("../../helpers");
class Nav extends Component {
state = { collapse: true };
/*
componentDidMount() {
helpers.useIntersect(".navbar-collapse", "navbar-collapsed");
}
*/
constructor(props) {
super(props);
this.brandLogo = this.props.brandLogo;
this.listItems = this.props.pages
//.sort((a, b) => (a.node.navigationOrder || 100) - (b.node.navigationOrder || 100))
.map((page) => page.node.slug && page.node.pageName && !page.node.hideInNavigation && (
<li className="nav-item" key={page.node.id}>
<Link to={`${page.node.slug}`} className="nav-link" title={page.node.pageName}>{page.node.pageName}</Link>
</li>)
);
}
render() {
return (
<>
<nav className={[
"navbar",
"navbar-expand-lg",
"navbar-light",
"fixed-top",
this.state.collapse ? "" : "active"].join(" ")}
>
<a className="navbar-brand" href="/"><Image fluid={this.brandLogo} /></a>
<button
className="navbar-toggler"
type="button"
data-toggle="collapse"
data-target="#topnav"
aria-controls="topnav"
aria-expanded={!this.state.collapse}
aria-label="Toggle navigation" onClick={() => {
this.setState({ collapse: !this.state.collapse });
}
}>
<span className="navbar-toggler-icon"></span>
</button>
<div
className={[
"collapse",
"navbar-collapse",
"fade",
!this.state.collapse ? "show" : "",
].join(" ")} id="topnav">
<ul className="navbar-nav ml-lg-auto">{this.listItems}</ul>
</div>
</nav>
</>
);
}
}
export default Nav;
SCSS solution to cover state and mobile -vs- desktop navigation
A simple toggle between display "none" and "block". You can transition transforms to counter the missing height calculation.
We'll use the proper content characters to cover the icons.
It's a bit too much but I'll leave this file complete.
#import "../variables";
#import "../functions";
#import "../vendor/bootstrap/functions";
#import "../vendor/bootstrap/variables";
#import "../vendor/bootstrap/mixins";
#import "../vendor/bootstrap/transitions";
.navbar {
&.navbar-light {
transition: all ease 0.2s;
.navbar-brand {
transition: all ease 0.2s;
.image {
height: auto;
width: rem-value(142);
}
}
.nav-item {
align-items: center;
display: flex;
}
.nav-link {
font-family: $font-family-monospace;
font-size: rem-value(20);
}
#include media-breakpoint-up(md) {
.navbar-collapse {
&:not(.show) {
opacity: 1;
}
}
.nav-item {
margin: auto 1rem;
}
}
#include media-breakpoint-up(lg) {
.nav-item {
&:last-child {
.nav-link {
background-color: $primary;
border-radius: rem-value(3);
color: $white;
margin-left: 1.5rem;
&:hover,
&:active,
&:focus {
background-color: $brand-primary-headings;
}
}
}
}
}
#include media-breakpoint-down(md) {
background-color: $white;
box-shadow: 0 0 1px 1px $gray-300;
padding-top: 0;
padding-bottom: 0;
.navbar-brand {
transform: scale(0.65);
transform-origin: left;
padding-top: 0;
padding-bottom: 0;
}
.navbar-collapse {
&.collapse {
background: white;
margin: 0 -1rem;
height: 0;
transform: scale(0);
transform-origin: top center;
transition: all ease 0.5s;
padding: 1rem;
position: relative;
&.show {
height: calc(100vh - 80px);
transform: scale(1);
}
}
}
.navbar-toggler {
&[aria-expanded="true"] {
.navbar-toggler-icon {
background-image: none;
position: relative;
&:before {
content: "\00d7";
font-family: sans-serif;
font-size: rem-value(40);
line-height: 0.8;
position: absolute;
top: 0;
left: 0;
height: 100%;
width: 100%;
}
}
}
}
.nav-item {
border-bottom: 1px solid $gray-300;
margin: 0;
position: relative;
&:before {
content: "\203A";
line-height: 1.2;
font-size: rem-value(30);
color: $brand-primary-headings;
position: absolute;
right: 0.5rem;
width: rem-value(40);
height: rem-value(40);
text-align: center;
}
}
.nav-link {
line-height: 1.8;
width: 100%;
}
}
#at-root .scrolled & {
background-color: $white;
box-shadow: 0 0 1px 1px $gray-300;
padding-top: 0;
padding-bottom: 0;
.navbar-brand {
transform: scale(0.65);
padding-top: 0;
padding-bottom: 0;
}
}
}
}
Example can be seen at devlab.career
Hopefully with this example you can implement this too.
I need the content below the (tabs+selected-content) to respect the space of the absolute selected-content currently being displayed on the page within the parent container of relative. Anyone have any ideas how to do this?
code sandbox: https://codesandbox.io/s/tabs-content-space-respected-m0gql
Files
App.js
import "./styles.css";
import TabsWithContent from "./Components/TabsWithContent.js";
export default function App() {
return (
<div>
<TabsWithContent />
<h1 style={{textAlign: "center"}}>I am the next content, please respect my space</h1>
</div>
);
}
Components\TabsWithContent.js
import React, { useState } from "react";
// Data from backend
import { tabOneContent, tabTwoContent, tabThreeContent } from '../BackendData/TabsContent.js';
const TabsWithContent = () => {
// Variables
const [tabSelected, setTabSelected] = useState(1);
// Functions
const changeTab = (ev, tabNum) => {
ev.preventDefault();
setTabSelected(tabNum);
};
// Render
return (
<div className="div-tabs-with-content">
<div className="page-container-content">
<h2>Tabs Example</h2>
<div className="div-tabs">
<button onClick={ev => changeTab(ev, 1)} style={tabSelected === 1 ? {color: "#ffffff", backgroundColor: "#003478"} : {}}>Tab One</button>
<button onClick={ev => changeTab(ev, 2)} style={tabSelected === 2 ? {color: "#ffffff", backgroundColor: "#003478"} : {}}>Tab Two</button>
<button onClick={ev => changeTab(ev, 3)} style={tabSelected === 3 ? {color: "#ffffff", backgroundColor: "#003478"} : {}}>Tab Three</button>
</div>
<div className="div-tabs-content-container">
<section className={tabSelected === 1 ? "div-tabs-content active" : "div-tabs-content"}>
{tabOneContent.map((content, index) =>
<div key={index}><i className="fa fa-check"></i><p>{content}</p></div>
)}
</section>
<section className={tabSelected === 2 ? "div-tabs-content active" : "div-tabs-content"}>
{tabTwoContent.map((content, index) =>
<div key={index}><i className="fa fa-check"></i><p>{content}</p></div>
)}
</section>
<section className={tabSelected === 3 ? "div-tabs-content active" : "div-tabs-content"}>
{tabThreeContent.map((content, index) =>
<div key={index}><i className="fa fa-check"></i><p>{content}</p></div>
)}
</section>
</div>
</div>
</div>
);
};
export default TabsWithContent;
BackendData\TabsContent.js
const tabOneContent = ["Content One", "Content Two", "Content Three"];
const tabTwoContent = ["Content One", "Content Two", "Content Three", "Content Four", "Content Five", "Content Six"];
const tabThreeContent = ["Content One", "Content Two", "Content Three", "Content Four", "Content Five", "Content Six", "Content Seven", "Content Eight"];
export {
tabOneContent,
tabTwoContent,
tabThreeContent
}
index.css
.App {
font-family: sans-serif;
}
.page-container-content {
display: block;
position: relative;
width: 100%;
max-width: 1200px;
padding: 0 25px 0 25px;
margin: 0 auto;
}
.div-tabs-with-content {
display: block;
width: 100%;
margin-bottom: 60px;
}
.div-tabs-with-content h2 {
margin-bottom: 20px;
color: #003478;
font-family: sans-serif;
font-size: 2.8rem;
font-weight: 700;
line-height: 36px;
text-align: center;
}
.div-tabs {
display: flex;
justify-content: space-around;
margin-bottom: 2rem;
}
.div-tabs button {
height: 50px;
width: 210px;
color: #003478;
background-color: #ffffff;
border: none;
font-family: sans-serif;
font-size: 2.4rem;
font-weight: 600;
line-height: 3.6rem;
outline: none;
cursor: pointer;
}
.div-tabs button:hover {
opacity: 0.7;
color: white;
background-color: #003478;
transition: 0.2s ease-in;
}
.div-tabs-content-container {
display: block;
position: relative;
width: 100%;
}
.div-tabs-content {
position: absolute;
left: 26%;
display: flex;
flex-wrap: wrap;
justify-content: space-between;
width: 100%;
max-width: 600px;
visibility: hidden;
opacity: 0;
}
.div-tabs-content-container .active {
transition: opacity 0.75s;
visibility: visible;
opacity: 1;
}
.div-tabs-content div {
display: flex;
align-items: center;
width: 200px;
}
.div-tabs-content i {
width: 24px;
height: 24px;
font-size: 1.6rem;
padding: 2.5px;
margin-right: 10px;
font-weight: 300;
color: #003478;
border: 2px solid #003478;
border-radius: 50%;
}
.div-tabs-content p {
color: #000000;
font-size: 1.6rem;
font-weight: 300;
line-height: 26px;
}
Check the working solution - https://codesandbox.io/s/tabs-content-space-respected-forked-lzrkh
.div-tabs-content-container .active {
transition: opacity 0.75s;
visibility: visible;
opacity: 1;
position: relative; /* you can use unset also */
}
I think it solved your problem.