I have a navigation bar with a unordered list and multiple items that contains links for the individual pages.
I want a yellow box to appear ontop of the link if i'm on that current page. I made the yellow boxes as you can see and i'm trying to think of the best approach for making the box appear on the concurrent page, any ideas?
Part i'm talking about:
const linkStyle = css`
text-decoration: none;
font-family: "Montserrat";
position: relative;
font-weight: 300;
font-style: normal;
color: ${theme.colors.text};
&::after {
background-color: ${theme.colors.primary};
width: 150%;
height: 40px;
content: "";
position: absolute;
transform: translateX(-50%);
top: -50px;
left: 50%;
}
`;
Full file Header.jsx
import React from "react";
import { css } from "emotion";
import { useTheme } from "emotion-theming";
const Header = () => {
const theme = useTheme();
const headerStyle = css`
position: absolute;
top: 0;
right: 0;
`;
const navStyle = css`
width: 1093px;
position: relative;
background-color: ${theme.colors["bg-nav"]};
display: flex;
justify-content: right;
height: 109px;
`;
const accountStyle = css`
width: 428px;
height: 109px;
background-color: ${theme.colors["alt-red"]};
`;
const ulStyle = css`
box-sizing: border-box;
padding: 0;
display: flex;
margin: 0;
font-size: 1rem;
align-items: center;
list-style: none;
`;
const itemStyle = css`
box-sizing: border-box;
padding: 0 30px;
`;
const linkStyle = css`
text-decoration: none;
font-family: "Montserrat";
position: relative;
font-weight: 300;
font-style: normal;
color: ${theme.colors.text};
&::after {
background-color: ${theme.colors.primary};
width: 150%;
height: 40px;
content: "";
position: absolute;
transform: translateX(-50%);
top: -50px;
left: 50%;
}
`;
return (
<header className={headerStyle}>
<nav className={navStyle}>
<ul className={ulStyle}>
<li className={itemStyle}>
<a className={linkStyle} href="/">
Home
</a>
</li>
<li className={itemStyle}>
<a className={linkStyle} href="/">
Menu
</a>
</li>
<li className={itemStyle}>
<a className={linkStyle} href="/">
Gallery
</a>
</li>
<li className={itemStyle}>
<a className={linkStyle} href="/">
Testiminials
</a>
</li>
<li className={itemStyle}>
<a className={linkStyle} href="/">
Contact Us
</a>
</li>
</ul>
<div className={accountStyle}></div>
</nav>
</header>
);
};
export default Header;
I think it depends on what library you are using for routing because each one does it differently. Assuming you are using the most popular (afaik) React Router library, then it would be a case of using a <NavLink> instead of a <Link>. When the current URL matches the <NavLink> you can add a custom class to activeClassName.
Here’s a link to what I’m referring to: https://github.com/ReactTraining/react-router/tree/master/packages/react-router-dom
With that in mind, here’s a simplified version of what you’d need to do:
import React from "react";
import { css } from "emotion";
import { useTheme } from "emotion-theming";
import { NavLink } from 'react-router-dom';
const Header = () => {
const activeClass = css`
/* active css styles go here */
`;
return (
<header>
<nav>
<ul>
<li>
<NavLink exact to="/" className={linkStyle} activeClassName={activeClass}>
Home
</NavLink>
</li>
<li>
<NavLink to="/menu" className={linkStyle} activeClassName={activeClass}>
Menu
</NavLink>
</li>
</ul>
</nav>
</header>
);
};
export default Header;
Related
I have prepared a multi-element slider that has no functionality yet. Its task is to move the elements by the number of visible elements on the screen. Unfortunately, I have to use js for this, react is out of the question.
I should use also redux with UseState from another file. Problem is I don't know how it should works in JS.
JS
import React from 'react';
import styles from './Brands.module.scss';
import Button from '../../common/Button/Button';
import { FontAwesomeIcon } from '#fortawesome/react-fontawesome';
import { faAngleLeft, faAngleRight } from '#fortawesome/free-solid-svg-icons';
const Brands = () => {
return (
<div className={styles.root}>
<div className='container'>
<div className='row'>
<div className={styles.thumbnailNavigationWrapper}>
<Button className={styles.arrow} variant='small'>
<FontAwesomeIcon icon={faAngleLeft}>Left</FontAwesomeIcon>
</Button>
<div className={styles.thumbnailMenu}>
<ul>
<li>
<a href='#' className={styles.activeThumbnail}>
<img src='/images/brands/brands-1.jpg' alt='brand'></img>
</a>
</li>
<li>
<a href='#'>
<img src='/images/brands/brands-2.jpg' alt='brands'></img>
</a>
</li>
<li>
<a href='#'>
<img src='/images/brands/brands-3.jpg' alt='brands'></img>
</a>
</li>
<li>
<a href='#'>
<img src='/images/brands/brands-4.jpg' alt='brands'></img>
</a>
</li>
<li>
<a href='#'>
<img src='/images/brands/brands-5.jpg' alt='brands'></img>
</a>
</li>
<li>
<a href='#'>
<img src='/images/brands/brands-6.jpg' alt='brands'></img>
</a>
</li>
</ul>
</div>
<Button className={styles.arrow} variant='small'>
<FontAwesomeIcon icon={faAngleRight}>Right</FontAwesomeIcon>
</Button>
</div>
</div>
</div>
</div>
);
};
export default Brands;
SCSS
#import "../../../styles/settings.scss";
.root {
padding: 2rem 0;
display: flex;
justify-content: center;
.thumbnailNavigationWrapper {
padding: 10px;
display: flex;
justify-content: space-between;
align-items: center;
width: 100%;
height: 90px;
border: 1px solid $new-furniture-border-color;
.arrow {
font-size: 20px;
height: 70px;
width: 30px;
display: flex;
align-items: center;
}
ul {
position: relative;
display: flex;
list-style: none;
margin: 0;
padding: 0;
li {
width: 150px;
height: 70px;
margin: 10px;
a {
opacity: 0.5;
img {
width: 100%;
height: 100%;
object-fit: cover;
}
}
}
}
}
}
Since all your list elements have the same width of 150px, you could create a state/variable (e. g. activeIndex) with the active list element index. When sliding, change the index (+/- 1) and give the slider a dynamic style attribute with a translateX(calc(activeIndex * 150px)) or something like this.
Does this help?
const menuBtn = document.querySelector('#menuBtn')
const exitBtn = document.querySelector('#exitBtn');
const menu = document.getElementsByClassName('menu');
menuBtn.addEventListener('click' , () => {
menu.style.display = 'block'
})
.fa.fa-bars.menuBtn {
color: #fff;
font-size: 35px;
cursor: pointer;
display: none;
}
.fa.fa-times-circle.exit {
color: white;
font-size: 35px;
cursor: pointer;
}
#media (max-width: 934px) {
.max-width {
padding: 0 50px;
}
.fa.fa-bars.menuBtn {
display: block;
}
.navbar .menu {
position: fixed;
height: 100vh;
width: 100%;
left: 0;
top: 0;
background-color: #111;
text-align: center;
padding-top: 110px;
display: none;
}
.menu{
display: none
}
.exit {
z-index: 999;
display: none;
margin: 1.8rem;
}
.navbar .menu li {
display: block;
}
.navbar .menu li a {
display: inline-block;
margin: 20px 0;
font-size: 35px;
}
}
<nav class="navbar" id="nav">
<div class="max-width">
<div class="logo"><a id="headSpan" href="index.html">Port<span>folio.</span></a></div>
<ul class="menu">
<li>Home</li>
<li>About</li>
<li>Skills</li>
<li>Projects</li>
<li>CV</li>
<li>Contact</li>
</ul>
<div>
<i class="fa fa-bars menuBtn" id="menuBtn" aria-hidden="true"></i>
</div>
<div class="exit">
<i class="fa fa-times-circle exit" id="exitBtn" aria-hidden="true"></i>
</div>
</div>
</nav>
How do I make it work ? I tested to see if the add event listener was working and it was working but when it comes to displaying the menu when clicked it does not work. Any idea what the issue may be ? I am not that good at using Javascript so any help would be appreciated . Thank you
document.getElementsByClassName('menu'); doesn't return a single element. It returns an HTMLCollection. So menu isn't an element and menu.style.display = 'block doesn't do what you're trying to do.
document.getElementsByClassName('menu') gets multiple elements, all of which have the class 'menu'. The function returns an HTMLCollection, but you can treat it like a list. If you want to use classes, I would recommend using:
var list = document.getElementsByClassName('menu')
for (var item of list) {
// Do Stuff Here
}
If you have multiple menus, consider using JQuery with the .each(function) method for functions.
I have been making a burger menu that works on desktop, opens and closes with an event listener.
It works fine but then i wanted to make it so that if the use clicked outside of the burger menu it also closes the menu.
I found a bit of java script that uses some logic to say that if not the navigation then close menu. it works when you click outside the menu but then the problem is that the toggle stops closing the menu.
I split my code up into two sections.
The first code block is the code working with the toggle.
The second block is the code that i'm using to try and make the click outside the menu work.
I think i have been staring at this for to long and cant seem to find a solution.
thanks in advance for any help.
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>
<style>
a{
color: #fff;
}
.ic-burger{
width: 50px;
height: 50px;
background: #000;
display: block;
position: relative;
z-index: 10;
}
.ic-nav ul {
list-style: none;
padding-left: 0px;
display: flex;
flex-direction: column;
right: 0px;
top: 0px;
height: 100%;
position: fixed;
z-index: 5;
overflow: auto;
margin: 0px;
padding-left: 20px;
padding-right: 20px;
}
html.ic-show .ic-nav:before{
content: '';
position: absolute;
top: 0;
left: auto;
right: 0;
bottom: 0;
background-color: rgba(18,18,18,0.7);
z-index: 1;
width: 100%
}
.ic-second-level{
opacity: 0;
visibility: hidden;
transition: all 200ms linear;
padding: 0px;
padding-top: 100px;
background: #1e1e1e;
}
html.ic-show .ic-second-level{
opacity: 1;
visibility: visible;
}
</style>
<nav class="ic-nav">
<!-- <div class="ic-burger-bkg"> -->
<ul class="ic-burger-container">
<li>
<a href="javascript:void(0);" class="ic-burger" aria-expanded="false" aria-controls="menu" id="burger-icon">
<div class="nav-icon">
Burger <br>toggle
</div>
</a>
<!-- ############ -->
<ul class="ic-second-level" role="region" id="menu" aria-labeledby="burger-icon">
<li class="top-li">
About
</li>
<li class="top-li">
News
</li>
<li class="top-li">
Team
</li>
<li class="top-li">
Contact
</li>
</ul>
<!-- ############ -->
</li>
</ul>
<!-- </div> -->
</nav>
</body>
<script>
var documentElement = document.querySelector("html");
var sidebarIsOpen = () => documentElement.classList.contains("ic-show");
var openSidebar = () => {
documentElement.classList.add("ic-show");
};
var closeSidebar = () => {
documentElement.classList.remove("ic-show");
};
document.querySelector('.ic-burger').addEventListener("click", function() {
sidebarIsOpen() ? closeSidebar() : openSidebar();
});
</script>
</html>
Here is the second bit of code i cant get to play friendly with the first.
let sidebar = document.querySelector(".ic-second-level");
document.addEventListener("mouseup", function(event){
// If the event didn't originate from the open button or the sidebar, close it
if(event.target !== sidebar && event.target !== openSidebar){
closeSidebar();
}
});
these are the two sources ive used to help me
https://dev.to/tongrhj/the-mistake-developers-make-when-coding-a-hamburger-menu-1deg
Click Outside To close slide menu Javascript
I am using event delegation to check if you click on the "ic-nav" element and then close it. Works like charm.
document.addEventListener('click',function(e){
if(e.target && e.target.classList == 'ic-nav'){
sidebarIsOpen() ? closeSidebar() : openSidebar();
}
});
var documentElement = document.querySelector("html");
var sidebarIsOpen = () => documentElement.classList.contains("ic-show");
var openSidebar = () => {
documentElement.classList.add("ic-show");
};
var closeSidebar = () => {
documentElement.classList.remove("ic-show");
};
document.querySelector('.ic-burger').addEventListener("click", function() {
sidebarIsOpen() ? closeSidebar() : openSidebar();
});
document.addEventListener('click',function(e){
if(e.target && e.target.classList == 'ic-nav'){
sidebarIsOpen() ? closeSidebar() : openSidebar();
}
});
a{
color: #fff;
}
.ic-burger{
width: 50px;
height: 50px;
background: #000;
display: block;
position: relative;
z-index: 10;
}
.ic-nav ul {
list-style: none;
padding-left: 0px;
display: flex;
flex-direction: column;
right: 0px;
top: 0px;
height: 100%;
position: fixed;
z-index: 5;
overflow: auto;
margin: 0px;
padding-left: 20px;
padding-right: 20px;
}
html.ic-show .ic-nav:before{
content: '';
position: absolute;
top: 0;
left: auto;
right: 0;
bottom: 0;
background-color: rgba(18,18,18,0.7);
z-index: 1;
width: 100%
}
.ic-second-level{
opacity: 0;
visibility: hidden;
transition: all 200ms linear;
padding: 0px;
padding-top: 100px;
background: #1e1e1e;
}
html.ic-show .ic-second-level{
opacity: 1;
visibility: visible;
}
<nav class="ic-nav">
<!-- <div class="ic-burger-bkg"> -->
<ul class="ic-burger-container">
<li>
<a href="javascript:void(0);" class="ic-burger" aria-expanded="false" aria-controls="menu" id="burger-icon">
<div class="nav-icon">
Burger <br>toggle
</div>
</a>
<!-- ############ -->
<ul class="ic-second-level" role="region" id="menu" aria-labeledby="burger-icon">
<li class="top-li">
About
</li>
<li class="top-li">
News
</li>
<li class="top-li">
Team
</li>
<li class="top-li">
Contact
</li>
</ul>
<!-- ############ -->
</li>
</ul>
<!-- </div> -->
</nav>
Why my damn footer won't stay at the bottom of the page?
import React from "react"
import Navbar from "./navbar"
import Footer from "./footer"
import Sidebar from "./sidebar"
import "./layoutplus.css"
const Layout = ({ children }) => {
return (
<>
<Navbar />
<div className="main-cont">
<main id="main-post" className="main-post">{children}</main>
<Sidebar id="sidebar" className="sidebar"/>
</div>
<Footer />
</>
)
}
export default Layout
import React from 'react'
import {Link} from 'gatsby'
import {FaFacebook, FaTwitter, FaInstagram} from 'react-icons/fa'
export default function Footer() {
return (
<div id="footer" className="footer">
<div className="footer-middle">
<ul>
<li><Link className="footer-link" to="/">Home</Link></li>
<li><Link className="footer-link" to="/guides">Guides</Link></li>
<li><Link className="footer-link" to="/about">About</Link></li>
</ul>
<div className="footer-bottom">
<ul className="footer-ul">
<li><Link to="//" ><FaFacebook className="footer-dot" /></Link></li>
<li><Link to="//"><FaTwitter className="footer-dot" /></Link></li>
<li><Link to="//"><FaInstagram className="footer-dot"/></Link></li>
</ul>
<p>Build with <Link style={{ textDecoration: "none", color: "#663399" }} to="https://www.gatsbyjs.com/">Gatsby</Link>.</p>
<p>©{new Date().getFullYear()} <Link className="footer-link" to="/about">blablabla</Link> - All Rights Reserved</p>
</div>
</div>
</div>
)
}
/*MAIN CONT*/
.main-cont {
max-width: 1344px;
margin: 0 auto;
display: grid;
height: 100vh;
grid-template-columns: 4.5fr 1.5fr;
grid-template-rows: 1fr 1fr;
gap: 1rem;
grid-template-areas:
"main-post test-ads"
"main-post test-hottopic";
padding-top: 40px;
}
#media only screen and (max-width: 800px) {
.main-cont {
grid-template-columns: 1fr;
grid-template-rows: 2fr 1fr 1fr;
grid-template-areas:
"main-post"
"test-ads"
"test-hottopic";
padding-right: 10px;
padding-left: 10px;
}
}
.main-post {
grid-area: main-post;
}
.test-ads {
grid-area: test-ads;
border: 1px solid greenyellow;
text-align: center;
}
.test-hottopic {
grid-area: test-hottopic;
border: 1px solid red;
text-align: center;
}
/*FOOTER*/
.footer {
position: fixed;
bottom: 0;
width: 100%;
text-align: center;
background: var(--bgGray);
margin: 0;
padding-bottom: 20px;
}
.footer-middle {
color: var(--mainWithe);
}
.footer-middle ul {
list-style: none;
color: var(--mainWhite);
padding: 0rem 2px;
}
.footer-middle li {
font-size: 1.2rem;
display: inline;
margin-right: 1.5rem;
}
.footer-bottom {
padding-top: 0.5rem;
padding-bottom: 2rem;
}
.footer-link {
color: var(--offWhite);
text-decoration: none;
}
.footer-link:hover {
color: var(--mainOrange);
}
.footer-ul {
list-style: none;
display: inline;
}
.footer-dot {
color: var(--offWhite);
height: 27px;
width: 27px;
}
.footer-dot:hover {
transition: var(--mainTransition);
color: var(--mainOrange);
}
The footer seems to stay at the bottom of the screen always, but never at the end of the page. I don't know why, this problem starts when I added the grid to the .main-cont container, because I need a grid nested into the body.
Anyone has a solution?
With Gatsby, you should struck the brain a little bit, since it's not that easy to access the wrappers of the content, but of course, it doable.
Taking your <Layout> as an example:
import React from "react"
import Navbar from "./navbar"
import Footer from "./footer"
import Sidebar from "./sidebar"
import "./layoutplus.css"
const Layout = ({ children }) => {
return (
<>
<Navbar />
<div className="main-cont">
<main id="main-post" className="main-post">{children}</main>
<Sidebar id="sidebar" className="sidebar"/>
</div>
<Footer />
</>
)
}
export default Layout
Using the previous structure, you can't access the wrapper of your components because Gatsby wraps it between an unreachable <div> with an empty class. However, what you can do is to wrap it again within a known class element, such as:
const Layout = ({ children }) => {
return (
<section className="site-wrapper">
<Navbar />
<div className="main-cont">
<main id="main-post" className="main-post">{children}</main>
<Sidebar id="sidebar" className="sidebar"/>
</div>
<Footer />
</section>
)
}
Given that site-wrapper class you can add the following CSS:
.site-wrapper {
display: flex;
min-height: 100vh;
flex-direction: column;
}
main {
flex-grow: 1;
}
Basically, you are telling the wrapper (site-wrapper) to expand until filling the viewport (100vh). Since your main tag (change it to the desired class if needed) can grow free (flex-grow: 1) so your footer will be always at the bottom of the page because it's pushed by the rest of the flexbox column.
Flexbox has better acceptance/fallback within old browsers than grid has, but you can achieve it either way, the idea is always to push (or let the main grow) the footer at the bottom without depending on the content above, using some minmax should do the trick using a grid-based approach.
I'd like set to different background images for my 'Home' and 'About' components within the react project I'm building. I gave the 'Home' and 'About' components their own stylesheets (styles.css and about.css, respectively), then added a background-image: url() for each, but they both ended up with the 'Home' background.
Any suggestions on how to have different backgrounds for your components, when using react router?
Code as follows:
Home.jsx
import React from 'react'
import './styles.css'
import hashi_logo_2 from './Photos/hashi_logo_2.png'
import {Link} from 'react-router-dom'
function Home() {
return (
<div className = 'home'>
<nav className = 'nav'>
<ul>
<Link to = '/about' style={{ textDecoration: 'none' }} >
<li className='list'>About</li>
</Link>
<li className='list'>Food</li>
<li className='list'>Events</li>
<li className='list'>News</li>
<Link to ='/shop' style={{ textDecoration: 'none' }} >
<li className='list'>Shop</li>
</Link>
<li className='list'>Contact</li>
<li className='list'>Blog</li>
</ul>
</nav>
<main>
<div class='main__image'>
<img src= {hashi_logo_2}/>
</div>
</main>
</div>
)
}
export default Home
styles.css (styling for 'Home')
html * {
box-sizing: border-box;
font-family: 'Permanent Marker', cursive;
}
body {
margin: 0;
padding:0;
background-image: url('./Photos/hashi_pic_blurred_2.jpg');
background-repeat: no-repeat;
background-size: cover;
backdrop-filter: brightness(100%);
}
/* Navigation */
.nav {
background-color:#8b0000;
margin:0;
padding: 15px 0;
opacity: 0.75;
position: fixed;
width:100%;
}
ul {
display:flex;
list-style: none;
flex-direction: row;
justify-content: space-around;
font-size: 20px;
}
.list {
list-style: none;
text-decoration: none;
color: white;
font-size: 25px;
}
.list:hover{
background-color: black;
}
/* Logo */
main {
text-align: center;
padding-top: 130px;
padding-top:180px;
}
img {
max-width: 40%;
height: auto;
}
About.jsx
import React from 'react'
import './about.css'
function About() {
return(
<div className = 'about'>
<p>
Hashigo Zake takes the provision of fine beer to new levels.
<br/>
<br/>
Seven days a week, 362 days a year, we serve the best that New Zealand's booming craft brewing industry has to offer.
We are also building the best range of imported beer that New Zealand has seen.
<br/>
We deal directly with breweries in Australia, Japan and the US and import many of the best beers in the Pacific rim.
<br/>
We also have access to some of the best beers coming from Europe.
<br/>
<br/>
We open at midday every day.
<br/>
Our location is 25 Taranaki St, Te Aro, Wellington, New Zealand.
</p>
<h2>"And he dreamed, and behold a ladder set up on the earth, and the top of it reached to heaven."</h2>
</div>
)
}
export default About
about.css
.about {
height:100%;
background-image: url('./Photos/hashi_taps.jpg');
}
p {
margin-top: 50px;
color: white;
text-align: center;
font-size: 30px;
/* background-color: rgb(139,0,0, 0.75); */
font-family: 'Open Sans', sans-serif;
padding-left: 50px;
padding-right: 20px;
transform: translateY(20%);
font-weight: bold;
}
h2 {
color: white;
text-align: center;
font-size: 40px;
padding-left: 20px;
padding-right: 20px;
margin-top: 400px;
transform: translateY(-450%);
}
import React from 'react';
import Home from './Home'
import About from './About'
import Shop from './Shop'
import {BrowserRouter as Router, Switch, Route} from 'react-router-dom'
function App() {
return (
<Router>
<div>
<Switch>
<Route path ='/' exact component = {Home}/>
<Route path = '/about' component = {About}/>
<Route path = '/shop' component = {Shop}/>
</Switch>
</div>
</Router>
)
}
export default App;