How to make sidenav mobile link in react js about this situation? - reactjs

I want to make the sidenav mobile to show when clicking.
I tried to use jquery, but don't know how to configure in webpack.
const SignedOutLinks = () => {
return (
<div>
<NavLink to="#" className="sidenav-trigger nav-wrapper" data-target="mobile-links">
<i className="material-icons">menu</i>
</NavLink>
<ul className="right hide-on-med-and-down">
<li className="waves-effect waves-light">
<NavLink to="/signup">Signup</NavLink>
</li>
<li className="waves-effect waves-light">
<NavLink to="/signin">Login</NavLink>
</li>
</ul>
<ul className="sidenav" id="mobile-links">
<li className="waves-effect waves-light">
<NavLink to="/signup">Signup</NavLink>
</li>
<li className="waves-effect waves-light">
<NavLink to="/signin">Login</NavLink>
</li>
</ul>
</div>
);
};

if you want to write it, this is some code i make:
or this link
react:
class Drawer extends React.Component{
constructor(props){
super(props)
this.state = {
open: false,
}
}
handleDrawer(){
let currentState = this.state.open
this.setState({open: !currentState})
}
componentDidMount(){
if (this.state.open = true){
document.addEventListener("keydown", (event) => {
if (event.keyCode === 27){
this.setState({open: false})
}
})
}
}
handleClickOut(){
if(this.state.open === true){
this.setState({open: false})
}
}
render(){
console.log(this.state)
return (
<div>
<div
onClick={this.handleClickOut.bind(this)}
className={this.state.open ? "deactive" : "container"}>
<button onClick={this.handleDrawer.bind(this)}>Click on me to see the
drawer</button>
</div>
<div className={this.state.open ? "active" : "drawer"}>Hellllo i'm a
drawer</div>
</div>
)
}
}
export default Drawer
css:
.drawer {
display: none;
}
.active {
display: show;
position: absolute;
left: 0;
width: 25vw;
height: 100vh;
background-color: #C10E00;
transition: display 0.4s ease-in-out;
text-align: center;
padding: 10px;
}
.container {
position: relative;
text-align: center;
}
.deactive {
position: absolute;
text-align: center;
background-color: #FF5346;
width: 100vw;
height: 100vh;
transition: 0.4s ease-in-out;
opacity: 0.5;
}
button {
width: 300px;
height: 150px;
background-color: #910B00;
color: white;
box-shadow: 2px 5px grey;
margin: 25px;
}
or if you want to get it full coded you can use Material-UI framework

Related

Why are my link tags delayed before activating in react

I set up a list of React Link tags in my website and when one gets clicked on, it should immediately automatically scroll down to the section the user clicks on. That works, however, for whatever reason there's about a 1-2 second delay before this action actually occurs after a click. I've been trying to figure out what is causing this but I can't figure out what the problem is.
Here is the NavBar component:
import React from "react";
import { Link } from 'react-scroll';
import { FaBars, FaTimes } from 'react-icons/fa';
import { useState, useEffect } from "react";
import './Navbar.css';
const Navbar = () => {
const [click, setClick] = useState(false);
const handleClick = () => setClick(!click);
const closeMenu = () => setClick(false);
const [fix, setFix] = useState(window.scrollY >= 950);
useEffect(() => {
const setFixed = () => {
setFix(window.scrollY >= 950);
};
window.addEventListener("scroll", setFixed);
return () => {
window.removeEventListener("scroll", setFixed);
};
}, []);
return (
<div className={fix ? 'header active' : 'header'}>
<nav className={fix ? 'navbar fixed' : 'navbar'}>
<div className='hamburger' onClick={handleClick}>
{click ? (<FaTimes size={30} style={{ color: '#ffffff' }} />)
: (<FaBars size={30} style={{ color: '#ffffff' }} />)}
</div>
<ul className={click ? "nav-menu active" : "nav-menu"}>
<li className='nav-item'>
<Link to="header" spy={true} smooth={true} offset={-100} onClick={closeMenu}>Home</Link>
</li>
<li className='nav-item'>
<Link to="aboutMe" spy={true} smooth={true} offset={-100} onClick={closeMenu}>About</Link>
</li>
<li className='nav-item'>
<Link to="portfolio" spy={true} smooth={true} offset={-100} onClick={closeMenu}>Projects</Link>
</li>
<li className='nav-item'>
<Link to="resume" spy={true} smooth={true} offset={-100} onClick={closeMenu}>Resume</Link>
</li>
</ul>
</nav>
</div>
)
}
export default Navbar;
Here is the css for the NavBar component:
.header {
position: fixed;
height: 90px;
width: 100%;
top: 0;
left: 0;
z-index: 1;
transition: .3s ease-in;
overflow: hidden;
background-color: transparent;
}
.header.active {
background-color: rgba(0,0,0,.9);
}
.header .navbar {
display: flex;
justify-content: center;
align-items: center;
margin: auto;
height: 100%;
padding: 0 1rem;
}
.header .nav-menu a {
color: #ffffff;
}
.header .nav-menu {
display: flex;
}
.header .nav-item {
padding: 1rem;
font-weight: 500;
}
.header .nav-item a:hover {
padding-bottom: 4px;
color: #d4af37;
cursor: pointer;
}
.nav-menu a.active {
color: #d4af37;
text-decoration: none;
}
.hamburger {
display: none;
}
.nav-item {
list-style: none;
}
#homeLink {
text-decoration: none;
}
#media screen and (max-width:940px) {
.header {
max-width: 100%;
background-color: rgba(0,0,0,.9);
}
.header .navbar {
max-width: 100%;
justify-content: space-between;
}
.hamburger {
display: block;
}
.nav-menu {
position: fixed;
left: -100%;
top: 90px;
flex-direction: column;
background-color: rgba(0,0,0,.9);
width: 100%;
height: 90vh;
z-index: 999;
text-align: center;
transition: .3s;
}
.nav-menu.active {
left: 0;
}
.nav-item {
margin: 1.5rem 0;
}
.header .navbar img {
width: 150px;
}
}
Played around with it a bit more. I found that the smooth={true} prop in the Link tags was what slowed it down. Not entirely sure why that was the case, but removing it made my navbar work as intended.

The Dialog component is not closing correctly

I have a problem with the React.js Dialog component which contains a list of items. There is also an overlay in the Dialog. It closes automatically when the user clicks on it. But the scenario is something different. The dialog also includes a list of items that have some external links wrapped around the <a> element and some with the <div>.
But the method of closing the dialog is not working properly. The Dialog automatically closes when I click inside any list item.
Please see this:
My goal was to close the dialog whenever the user clicked on the overlay or whenever the user clicked on the list item wrapped with the <a> element. Otherwise, it should not be closed.
I still can't figure out What is the correct approach to tackle this issue?
CodeSandbox link
App.js
import React, { useState } from 'react';
import Dialog from './Dialog';
import './App.css';
const App = () => {
const [isOpen, setIsOpen] = useState(false);
const onClickHandler = (isFalse) => {
if (!isFalse) {
setIsOpen(false);
} else {
setIsOpen(!isOpen);
}
};
return (
<div>
<button type="button" onClick={onClickHandler}>
Open Dialog
</button>
<Dialog isOpen={isOpen} onClick={onClickHandler} />
</div>
);
};
export default App;
Dialog.js
import React from 'react';
const Dialog = (props) => {
const { isOpen, onClick } = props;
const onCloseHandle = () => {
onClick(false);
};
return (
<div
className={isOpen ? 'dialog-wrap open' : 'dialog-wrap'}
onClick={onCloseHandle}
>
<div className="dialog">
<ul className="dialog-list">
<li>
<a
href="https://reactjs.org"
target="_blank"
rel="noopener noreferrer"
>
React.js
</a>
</li>
<li>
<a
href="https://reactjs.org"
target="_blank"
rel="noopener noreferrer"
>
Another Link
</a>
</li>
<li>
<div>Should Not Close onClick</div>
</li>
<li>
<div>Should Not Close onClick</div>
</li>
</ul>
</div>
</div>
);
};
export default Dialog;
App.css
*,:before,:after {
box-sizing: border-box;
}
.dialog-wrap.open {
display: flex;
}
.dialog-wrap {
display: none;
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
z-index: 999;
overflow-y: auto;
-webkit-overflow-scrolling: touch;
padding: 16px;
background-color: rgba(0,0,0,0.66);
}
#media (min-width: 640px) {
.dialog-wrap {
padding: 48px 32px;
}
}
#media (min-width: 1024px) {
.dialog-wrap {
padding-left: 40px;
padding-right: 40px;
}
}
.dialog {
position: relative;
margin: auto;
background-color: #fff;
border: 1px solid rgba(0, 0, 0, 0.1);
box-shadow: 0 12px 16px rgba(0, 0, 0, 0.08);
border-radius: 4px;
width: 500px;
}
.dialog-list {
margin-bottom: 0;
padding-left: 0;
color: #333;
list-style: none;
}
.dialog-list > li {
border-bottom: 1px solid #eee;
padding: 24px;
}
.dialog-list > li > a {
color: #333;
display: block;
text-decoration: none;
}
.dialog-list > li > div {
cursor: pointer;
}
in this situation, I would create a .dialog-background element and give onCloseHandle to that.
I also hive my a elements the onCloseHandle as onClick prop as well
If you do not want to change your react tree you can decide that from the event like this:
<div
className={isOpen ? "dialog-wrap open" : "dialog-wrap"}
onClick={(e) => {
if (!e.target.closest('.dialog') || e.target.closest('a')) {
onClick(false)
}
}}
/>
I think your click event is propagating up the elements, and triggering onCloseHandle on your .dialog-wrap.
The simplest solution to this would be to use Event.stopPropagation() on the <div className="dialog">
E.g.
<div className="dialog" onClick={ e => e.stopPropagation() }>
(React technically uses "synthetic events", but they still include a stopPropagation option as long as it's being interacted with inside React)

I've seen all of the other answers, REALLY struggling with Sticky Footer in React. WON'T STICK TO THE BOTTOM

I am trying to get my footer to stick to the bottom and not cover any body elements toward the bottom of the screen and I cannot seem to figure it out. Here is my footer.js
import React from "react";
import './Stylesheets/Footer.css';
import NavbarBrand from 'react-bootstrap/NavbarBrand';
import Navbar from 'react-bootstrap/Navbar';
import Container from 'react-bootstrap/Container';
class Footer extends React.Component {
state = { clicked: false }
handleClick = () => {
this.setState({ clicked: !this.state.clicked })
}
render() {
return (
<footer className="footerItems">
<div className="phantom"></div>
<div>
<Navbar>
<Container>
<NavbarBrand className="wrapper">
<i class="fab fa-2x fa-github"></i>
<i class="fab fa-2x fa-facebook-square"></i>
<i class="fab fa-2x fa-twitter-square"></i>
<i class="fab fa-2x fa-instagram"></i>
</NavbarBrand>
</Container>
</Navbar>
</div>
</footer>
)
}
}
export default Footer
I am trying to use a phantom <div> to force some additional spacing but that is not working. Here is the corresponding css file.
footer {
height: 80px;
margin-top: -200px;
bottom: 0;
z-index: 999;
}
.phantom {
display: 'block';
padding: '20px';
height: '60px';
width: '100%';
}
.footerItems {
position: fixed;
width: 100%;
background: linear-gradient(90deg, rgb(110, 94, 254) 0%, rgba(73, 63, 252, 1) 100%);
display: flex;
justify-content: center;
}
.wrapper {
align-items: center;
height: 100vh;
}
.wrapper i {
padding: 10px;
text-shadow: 0px 6px 8px rgba(0, 0, 0, 0.6);
transition: all ease-in-out 150ms;
}
.wrapper a:nth-child(1) {
color: #080202;
}
.wrapper a:nth-child(2) {
color: white;
}
.wrapper a:nth-child(3) {
color: #1DA1F2;
}
.wrapper a:nth-child(4){
color: #f24f1d;
}
.wrapper i:hover {
margin-top: -3px;
text-shadow: 0px 14px 10px rgba(0, 0, 0, 0.4);
}
Any thoughts or suggestions??
THANK YOU
Here's a solution using position: sticky. The main things to note here is that the main div needs to be at least the height of the page, that way the top property can force it to the bottom. The bottom property then forces it to stay at the bottom even if scrolled past.
This doesn't remove the footer from affecting the height of the page, so it'll all be scrollable without issue.
The other thing to note is that this solution (as written) is based on knowing the height of the footer in advance, so I put a custom css property --footer-height: 60px to set that.
I'm not really sure why the icons and things don't show on the footer as given, but that's a different question
const { NavbarBrand, Navbar, Container } = ReactBootstrap;
class Footer extends React.Component {
state = {
clicked: false,
};
handleClick = () => {
this.setState({
clicked: !this.state.clicked,
});
};
render() {
return (
<footer className="footerItems">
<div className="phantom"> </div>
<div>
<Navbar>
<Container>
<NavbarBrand className="wrapper">
<a href="http://www.github.com" target="_blank">
<i class="fab fa-2x fa-github"> </i>
</a>
<a href="http://www.facebook.com" target="_blank">
<i class="fab fa-2x fa-facebook-square"> </i>
</a>
<a href="http://www.twitter.com" target="_blank">
<i class="fab fa-2x fa-twitter-square"> </i>
</a>
<a href="http://www.instagram.com" target="_blank">
<i class="fab fa-2x fa-instagram"> </i>
</a>
</NavbarBrand>
</Container>
</Navbar>
</div>
</footer>
);
}
}
ReactDOM.render(
<div className="main">
<div className="content">Content!</div> <Footer />
</div>,
document.getElementById('root')
);
.main {
min-height: 100vh;
--footer-height: 60px;
}
.content {
height: 100vh;
background: linear-gradient(0deg, green 0%, white 100%);
}
footer {
height: var(--footer-height);
position: sticky;
top: calc(100vh - var(--footer-height));
bottom: 0;
}
.phantom {
display: block;
padding: 20px;
height: var(--footer-height);
width: 100%;
}
.footerItems {
/*position: fixed;*/
width: 100%;
background: linear-gradient(90deg, rgb(110, 94, 254) 0%, rgba(73, 63, 252, 1) 100%);
display: flex;
justify-content: center;
}
.wrapper {
align-items: center;
/*height: 100vh*/
;
}
.wrapper i {
padding: 10px;
text-shadow: 0px 6px 8px rgba(0, 0, 0, 0.6);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.13.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.13.1/umd/react-dom.production.min.js"></script>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css" integrity="sha384-9aIt2nRpC12Uk9gS9baDl411NQApFmC26EwAOH8WgZl5MYYxFfc+NcPb1dKGj7Sk" crossorigin="anonymous" />
<script src="https://unpkg.com/react-bootstrap#next/dist/react-bootstrap.min.js" crossorigin></script>
<div id="root" />

Next js font awesome and google fonts

Hoping to get some help on an issue I have been having in Next js. I am using Fontawesome-react package for icon imports which is working fine but when I attempt to load in a google font style sheet into the head of my main component, it changes the fonts but makes the font awesome icons disappear. I have tried a couple of different solutions such as loading the font locally and utilizing _document and _app components but none fix the issue I am having. Everything ends up changing the font but still gets rid of all the font awesome icons from every part of my app. I will copy in the Nav component I have and the Layout component that holds everything.
Thank you for any help!
import React from 'react'
import Nav from './nav/Nav'
import Head from 'next/head'
import Footer from './Footer'
type Props = {
title?: string
}
const Layout: React.FC<Props> = ({ children, title = 'Macros' }) => {
return (
<div>
<Head>
<title>{title}</title>
<link
href="https://fonts.googleapis.com/css?family=Darker+Grotesque&display=swap"
rel="stylesheet"
/>
</Head>
<Nav />
<div id="pageContent">{children}</div>
<Footer />
<style jsx global>{`
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
h1,
h2,
h3,
h4,
h5 {
font-weight: lighter;
font-family: 'Darker Grotesque', sans-serif;
}
#pageContent {
padding: 8rem 1rem;
}
`}</style>
</div>
)
}
export default Layout
import React, { useState } from 'react'
import { FontAwesomeIcon } from '#fortawesome/react-fontawesome'
import { faBars, faSearch, faPlus } from '#fortawesome/free-solid-svg-icons'
import Link from 'next/link'
const NavBar: React.FC = () => {
const [navBarStatus, isOpen] = useState<Boolean>(false)
const toggleMenu = () => {
isOpen(navBarStatus ? false : true)
}
return (
<nav id="navContainer">
<div id="mobileNav">
<ul id="navBarTop">
<li>
<button type="button" className="navIcon" onClick={toggleMenu}>
<FontAwesomeIcon icon={faBars} />
</button>
</li>
<li>
<Link href="/">
<a>
<h3>Macro</h3>
</a>
</Link>
</li>
<li>
<button type="button" className="navIcon">
<FontAwesomeIcon icon={faSearch} />
</button>
</li>
</ul>
<ul id="navbarBottom">
<li>Top</li>
<li>New</li>
<li>Protein</li>
<li>Carbs</li>
<li>Fats</li>
</ul>
</div>
<div id="appDrawer">
<ul id="topIcons">
<li>
<button type="button" className="navIcon" onClick={toggleMenu}>
<FontAwesomeIcon icon={faBars} />
</button>
</li>
<li>
<button type="button" className="navIcon">
<FontAwesomeIcon icon={faPlus} />
</button>
</li>
</ul>
<nav>
<ul id="menuList">
<Link href="/">
<a>
<p>Home</p>
</a>
</Link>
<Link href="/">
<a>Favorites</a>
</Link>
<Link href="/">
<a>Notifications</a>
</Link>
<Link href="/">
<a>Login/Sign up</a>
</Link>
</ul>
</nav>
</div>
<style jsx>{`
#navContainer {
background-color: #504761;
color: white;
position: fixed;
width: 100%;
}
#navContainer a {
text-decoration: none;
color: white;
}
#mobileNav {
display: ${navBarStatus ? 'none' : ''};
}
#navBarTop {
color: white;
display: flex;
justify-content: space-between;
list-style: none;
padding: 1rem 1rem 0.5rem 1rem;
font-size: 1.5rem;
}
.navIcon {
color: white;
border: none;
background-color: #504761;
font-size: 1.5rem;
}
#navbarBottom {
display: flex;
list-style: none;
justify-content: space-evenly;
padding: 1rem 0;
}
#appDrawer {
display: ${navBarStatus ? 'block' : 'none'};
background-color: #504761;
height: 100vh;
}
#topIcons {
display: flex;
justify-content: space-between;
list-style: none;
padding: 1rem;
font-size: 1.5rem;
}
#menuList {
padding: 2rem 0 2rem 1rem;
display: flex;
flex-direction: column;
}
#menuList a {
font-size: 2rem;
margin: 1rem 0;
}
`}</style>
</nav>
)
}
export default NavBar

How to get a particular div into fullscreen(full window size) in reactjs

I am making a Image viewer in ReactJs as I am newbie in this so I stuck at a point. actually I have to add a full screen option. when user click on any particular image the image is open and there is a option like next,prev,close,rotate and fullscreen(that is takes height and width of browser) so when user click on full screen that particular image will get the full window size and user still have option like rotate,next.close and prev. I searched for so many solution but nothing worked.
I tried so many things but it only does the fullscreen whole body but I want .center-image to be full screen with options as I said. This is the gallary modal component.
class GalleryModal extends React.Component {
constructor(props) {
super(props);
this.state = {
rotation: 0
};
this.rotate = this.rotate.bind(this);
}
render() {
const { rotation } = this.state;
if (this.props.isOpen === false) {
return null;
}
return (
<div className="modal-overlay" name={this.props.name}>
<div className="modal-body">
<a href="#" className="button" onClick={() => this.rotate()}>
<i className="fas fa-sync-alt" />
</a>
<a href="#" className="button" onClick={this.props.onPrev}>
<i className="fas fa-angle-left" />
</a>
<img
className="center_image"
id="image"
src={this.props.src}
style={{ transform: `rotate(${rotation}deg)` }}
/>
<a href="#" className="button" onClick={this.props.onNext}>
<i className="fas fa-angle-right" />
</a>
<a
className="modal-close"
href="#"
onClick={this.props.onClick}
>
<span className="fa fa-times" />
</a>
</div>
</div>
);
}
rotate() {
let newRotation = this.state.rotation + 90;
if (newRotation >= 360) {
newRotation = -360;
}
this.setState({
rotation: newRotation
});
}
}
Full code
This is my code and I am confused how to add the fullscreen option and where to add it .
I recommend using css viewport units, setting a component to height: 100vh and width: 100vw will make it fullscreen. You then conditionally render the component based on when you want it to be fullscreen.
Had to use some css tricks, but I believe this is what you're looking to achieve. The image is centered and takes up the maximum amount of width that is available within the window; however, if you stretch the window, it'll adjust its width up until it hits its max width (not advised to stretch it beyond its max value, otherwise, you'll get pixelation).
I did simplify your code a bit by elevating state and class methods to a single container, as well as, used setState() callbacks to manage state more efficiently and the ternary operator (cond ? true : false) in replace of simple if/else conditional statements.
Working example: https://codesandbox.io/s/zr5k7v0zp3
containers/Gallery/Gallery.js
import React from "react";
import GalleryImages from "../../components/GalleryImages/galleryImages";
import GalleryModal from "../../components/GalleryModal/galleryModal";
const imgUrls = [
"https://source.unsplash.com/3Z70SDuYs5g/800x600",
"https://source.unsplash.com/01vFmYAOqQ0/800x600",
"https://source.unsplash.com/2Bjq3A7rGn4/800x600",
"https://source.unsplash.com/t20pc32VbrU/800x600",
"https://source.unsplash.com/pHANr-CpbYM/800x600",
"https://source.unsplash.com/3PmwYw2uErY/800x600",
"https://source.unsplash.com/uOi3lg8fGl4/800x600",
"https://source.unsplash.com/CwkiN6_qpDI/800x600",
"https://source.unsplash.com/9O1oQ9SzQZQ/800x600",
"https://source.unsplash.com/E4944K_4SvI/800x600",
"https://source.unsplash.com/-hI5dX2ObAs/800x600",
"https://source.unsplash.com/vZlTg_McCDo/800x600"
];
export default class Gallery extends React.Component {
constructor(props) {
super(props);
this.state = {
imgIndex: 0,
imgUrlLength: imgUrls.length,
showModal: false,
rotation: 0
};
this.openModal = this.openModal.bind(this);
this.closeModal = this.closeModal.bind(this);
this.nextClick = this.nextClick.bind(this);
this.prevClick = this.prevClick.bind(this);
this.rotateImage = this.rotateImage.bind(this);
}
openModal(index) {
this.setState({
showModal: true,
imgIndex: index
});
}
closeModal() {
this.setState({
showModal: false,
imgIndex: 0,
rotation: 0
});
}
nextClick() {
this.setState(prevState => {
return {
imgIndex:
prevState.imgIndex === prevState.imgUrlLength - 1
? 0
: prevState.imgIndex + 1
};
});
}
prevClick() {
this.setState(prevState => {
return {
imgIndex:
prevState.imgIndex === 0
? prevState.imgUrlLength - 1
: prevState.imgIndex - 1
};
});
}
rotateImage() {
this.setState(prevState => {
return {
rotation: prevState.rotation + 90 <= 270 ? prevState.rotation + 90 : 0
};
});
}
render() {
return (
<div className="container-fluid gallery-container">
<GalleryImages imgUrls={imgUrls} openModal={this.openModal} />
<GalleryModal
isOpen={this.state.showModal}
onClick={this.closeModal}
onNext={this.nextClick}
onPrev={this.prevClick}
rotateImage={this.rotateImage}
rotation={this.state.rotation}
src={imgUrls[this.state.imgIndex]}
/>
</div>
);
}
}
components/GalleryImages/galleryImages.js
import React from "react";
import PropTypes from "prop-types";
const GalleryImages = ({ imgUrls, openModal }) => {
return (
<div className="row">
{imgUrls.map((url, index) => {
return (
<div key={index} className="col-sm-6 col-md-3 col-xl-2">
<div className="gallery-card">
<img
key={index}
className="gallery-thumbnail"
src={url}
alt={`Image number ${index + 1}`}
/>
<span
className="card-icon-open fa fa-expand"
onClick={() => openModal(index)}
/>
</div>
</div>
);
})}
</div>
);
};
GalleryImages.propTypes = {
imgUrls: PropTypes.arrayOf(PropTypes.string).isRequired,
openModal: PropTypes.func.isRequired
};
export default GalleryImages;
components/GalleryModal/galleryModal.js
import React from "react";
import PropTypes from "prop-types";
const GalleryModal = ({
isOpen,
onClick,
onNext,
onPrev,
rotateImage,
rotation,
src
}) => {
return isOpen ? (
<div className="modal-overlay">
<div className="modal-body">
<div className="close-modal">
<a className="modal-close" href="#" onClick={onClick}>
<span className="fa fa-times" />
</a>
</div>
<div className="rotate-container">
<a href="#" className="button" onClick={rotateImage}>
<i style={{ fontSize: 44 }} className="fas fa-sync-alt" />
</a>
</div>
<div className="image-container">
<div>
<a href="#" className="button" onClick={onPrev}>
<i className="fas fa-angle-left" />
</a>
</div>
<div>
<img
src={src}
style={{ transform: `rotate(${rotation}deg)`, width: "100%" }}
/>
</div>
<div>
<a href="#" className="button" onClick={onNext}>
<i className="fas fa-angle-right" />
</a>
</div>
</div>
</div>
</div>
) : null;
};
GalleryModal.propTypes = {
isOpen: PropTypes.bool.isRequired,
onClick: PropTypes.func.isRequired,
onNext: PropTypes.func.isRequired,
onPrev: PropTypes.func.isRequired,
rotateImage: PropTypes.func.isRequired,
rotation: PropTypes.number.isRequired,
src: PropTypes.string
};
export default GalleryModal;
styles.css
html,
body {
min-height: 100%;
height: 100%;
}
html {
font-size: 16px;
}
body {
position: relative;
font-size: 100%;
}
.button {
font-size: 50px;
color: #eee;
margin: 5px;
}
.card-icon-open {
display: block;
position: relative;
left: 45%;
top: 35px;
font-size: 30px;
width: 30px;
color: #fff;
cursor: pointer;
opacity: 0;
transform: translate(0%, -400%);
transition: all 0.25s ease-in-out;
}
.card-icon-open:focus,
.card-icon-open:hover {
color: #111;
}
.close-modal {
position: fixed;
top: 0;
right: 5px;
}
.fullscreen {
position: relative;
text-decoration: none;
font-size: 25px;
color: #eee;
z-index: 999;
}
.fullscreen:hover,
.fullscreen:focus,
.fullscreen:blur {
text-decoration: none;
color: red;
}
.gallery-container {
padding-top: 10px;
}
.gallery-card {
position: relative;
overflow: hidden;
margin-bottom: 10px;
}
.gallery-thumbnail {
max-width: 100%;
height: auto;
border-radius: 4px;
}
.gallery-thumbnail:focus ~ .card-icon-open,
.gallery-thumbnail:hover ~ .card-icon-open,
.gallery-thumbnail ~ .card-icon-open:focus,
.gallery-thumbnail ~ .card-icon-open:hover {
opacity: 1;
}
.image-container {
display: flex;
justify-content: center;
align-items: center;
}
.image-rotate {
font-size: 44px;
}
.modal-overlay {
position: fixed;
top: 0;
left: 0;
z-index: 10;
width: 100%;
height: 100%;
background: rgba(21, 21, 21, 0.75);
}
.modal-body {
position: relative;
top: 15%;
z-index: 11;
padding: 0;
overflow: hidden;
max-width: 100%;
max-height: 100%;
}
.modal-close {
font-size: 44px;
z-index: 99;
color: #eee;
transition: all 0.25s ease-in-out;
}
.modal-close:focus,
.modal-close:hover {
color: red;
}
.rotate-container {
font-size: 44px;
position: fixed;
top: 0;
left: 5px;
}
Found this library which does exactly what you describe:
https://www.npmjs.com/package/react-fullscreen-image
You can use as is or look into the code for guidance

Resources