displaying child div on hover on parent div in react js - javascript

Hello :) I am relatively new to react js, i am trying to apply animation on a div that is a child of another div, parent div " portfolio-product-item " displays featured image extracted from wp rest api, and child div " portfolio-product-item-details " has the contents of the post.
What i want to do is display the content when hovered over the featured image in parent div , my code is like this , how can i achieve it?
import React from 'react';
import Home from './Home';
require ('../../app.css');
require ('../../animate.min.css');
class Portfolio extends React.Component{
render(){
console.log(this.props.data.length);
var contents=[];
for (var i = 0; i < this.props.data.length; i++) {
contents.push(
<div className="col-xs-12 col-md-4">
<div id="portfolio-product-item" >
<img src={this.props.data[i].featured_image} />
<div ref= "productDetails" id ="portfolio-product-item-details" dangerouslySetInnerHTML={{__html: this.props.data[i].content.rendered}} />
</div>
</div>
);
}
return(
<div className = "container">
<div className="row">
<section className="portfolio">
<h1>Our Latest Work</h1>
<p id="below-header">These are some of the works that has been keeping us busy over the years. See for yourself what we can do.</p>
<div className="col-xs-12 ">
{contents}
</div>
</section>
</div>
</div>
)
}
}
export default Portfolio;

React allows to add / remove elements from the virtual DOM. Use the onMouseEnter and onMouseLeave to set show / hide state.
<img
onMouseEnter={() => this.setState({ show: true })}
onMouseLeave={() => this.setState({ show: false })}
/>
Then show / hide details based on the state:
{this.state.show ?
<div ref= "productDetails" id ="portfolio-product-item-details"
dangerouslySetInnerHTML={{__html: this.props.data[i].content.rendered}}
/>
: null}

My solution was something like this
import React from 'react';
import Home from './Home';
require ('../../app.css');
require ('../../animate.min.css');
class Portfolio extends React.Component{
render(){
var contents=[];
for (var i = 0; i < this.props.data.length; i++) {
var productImage ={
backgroundImage:'url('+ this.props.data[i].featured_image + ')',
backgroundSize: '100% 100%'
}
contents.push(
<div className="col-xs-12 col-md-6 col-lg-4">
<div id="portfolio-product-item" style ={productImage} >
<div ref= "productDetails" id ="portfolio-product-item-details" dangerouslySetInnerHTML={{__html: this.props.data[i].content.rendered}} />
</div>
</div>
);
}
return(
<div className = "container">
<div className="row">
<section className="portfolio">
<h1>Our Latest Work</h1>
<p id="below-header">These are some of the works that has been keeping us busy over the years. See for yourself what we can do.</p>
<div className="col-xs-12 ">
{contents}
</div>
</section>
</div>
</div>
)
}
}
export default Portfolio;
and css rules were like this
section.portfolio div#portfolio-product-item{
height:370px;
width:100%;
background: #f0f0f0;
margin:15px;
position:relative;
transform: rotate(4deg) ;
box-shadow: 5px 5px 5px #909090;
-webkit-font-smoothing: antialiased;
}
section.portfolio div#portfolio-product-item-details{
height:100%;
width:100%;
padding:10px;
text-align: center;
color:#ffffff;
position: absolute;
top:0;
background-color: #000000;
opacity:0;
}
section.portfolio div#portfolio-product-item-details:hover{
cursor:pointer;
opacity:0.9;
transition: all .5s ease-in-out;
}

Related

Unable to change BG Color through props

I've googled for endless hours to try and understand why this doesn't work I've heard a state setting system could be a possible solution, but I want to know if this works before proceeding. This should be much simpler to resolve the problem if possible.
In my CSS file I am using the following line of code in order to grab data from the parent.
.cards__item__pic-wrap::after {
background-color: attr(data-Color);
}
I set this variable like so in the parent JS file
data-Color = {props.color}>
I am able to get the backgroundColor to change when I do something like style = {{backgroundColor: props.color}} which is a common solution for many people. BUT that directly edits the style instead of the pseudo style I need in CSS (the .cards__item__pic-wrap::after)
My current code doesn't even display any background color and I have a feeling attr() is not returning my data properly and causing this.
Full code below:
Cards.css
.cards__item__pic-wrap::after {
content: attr(data-category);
position: absolute;
bottom: 0;
margin-left: 10px;
padding: 6px 8px;
max-width: calc((100%) - 60px);
font-size: 16px;
font-weight: 700;
color: #fff;
background-color: attr(data-Color);
box-sizing: border-box;
}
Cards.js
import CardItem from './CardItem';
import "./Cards.css"
function Cards() {
return (
<div className='cards'>
<h1> Keep up with the latest information.</h1>
<div className = "cards__container">
<div className = "cards_wrapper">
<ul className= "cards__items" >
<CardItem
src='/images/test.jpg'
text = "Guild's are finally released! Which batch are you?"
label ="Guild News"
color = '#1f98f4'
alt = "test"
path = "/not in use"/>
</ul>
</div>
</div>
</div>
);
}
export default Cards;
CardItem.js
import {Link} from 'react-router-dom';
function CardItem(props) {
return (
<>
<li className = "cards__item" >
<Link className= "cards__item__link" to = {props.path}>
<figure className = "cards__item__pic-wrap" data-category = {props.label} data-Color = {props.color}>
<img src = {props.src} alt= {props.alt} className = "cards__item__img" />
</figure>
<div className = "cards__item__info">
<h5 className ='cards__item__text'>{props.text}</h5>
</div>
{props.color}
</Link>
</li>
</>
);
}
export default CardItem;
You can achieve your goal using this code !
//in your css file
.cards__item__pic-wrap {
background-color: var(--data-color);
}
// in your CardItem.js file
<figure style={{ '--data-color': props.color, }} className="cards__item__pic-wrap" data-category={props.label}>
<img src={props.src} alt={props.alt} className="cards__item__img" />
</figure>
You could do something like this in your css:
.cards__item__pic-wrap[data-Color] {
background-color: attr(data-Color)
}
you would only be modifying the pic wrappers which have that property defined. In your component check if data-Color has been set otherwise render it without data-Color on
so if prop.color is undefined render like so:
<figure className = "cards__item__pic-wrap" data-category = {props.label}>
<img src = {props.src} alt= {props.alt} className = "cards__item__img" />
</figure>
otherwise
<figure className = "cards__item__pic-wrap" data-category = {props.label} data-Color = {props.color}>
<img src = {props.src} alt= {props.alt} className = "cards__item__img" />
</figure>

How do I create an overlay in React?

I am currently trying to create an overlay on an image when hovering. I am able to get a box displayed on screen but it's not placed over the image.
featured.js
const Featured = ({ images }) => {
if (!images || !Array.isArray(images)) return null;
return (
<section className={styles.featuredWrapper} id="work">
{images.map((image) => {
return (
<div className={styles.wrap}>
<GatsbyImage
image={image.gatsbyImageData}
alt="Link to the alt text"
className={styles.featuredImg}
/>
<div className={styles.featuredOverlay}>Test</div>
</div>
);
})}
</section>
);
};
featured.module.css
.featuredImg {
width: 100%;
position: relative;
}
.featuredOverlay {
position: absolute;
background: black;
opacity: 0.5;
width: 100%;
height: 100%;
z-index: 1;
}
Every explanation I see revolves around the use of positions absolute and relative which makes me think my issue is how I am rendering my component. Am I using the position properties on the wrong elements?
import { useState } from "react";
import "./styles.css";
function Home() {
const [showOverlay, setShowOverlay] = useState(false);
return (
<div>
<div className="main-container">
<div className="main-container__grid">
<img
src="https://miro.medium.com/max/2000/1*3SjDVyFY09xZ7NYMO5kj0g.png"
className="test"
alt="Placeholder"
onHover={() => setShowOverlay(true)}
/>
{showOverlay && <div className="targeting-box" />}
</div>
</div>
</div>
);
}
export default Home;

Focused elements display wrong style

I have element with width 400% and I want to move it to left by using translateX(-(index/4)*100%) when focused index changes.
Changing focused element translateX property with tab keyboard button displays it wrong on middle elements (1,2) even though using same hardcoded styling works as expected. What am I missing here?
const {useState} = React;
const App = () => {
const [curr, setCurr] = useState(0);
const carouselStyles = {
transform: `translateX(${-(curr / 4) * 100}%)`
// uncomment to see that styling works fine with hardcoded values 1,2..
// transform: `translateX(${-(1 / 4) * 100}%)`
};
const handleFocus = (num) => {
if (num !== curr) {
setCurr(num);
}
};
console.log(carouselStyles);
return (
<div>
<div className="carousel" style={carouselStyles}>
<div className="item">
11 very long text
<a href="/111" onFocus={() => handleFocus(0)}>
11111
</a>
</div>
<div className="item">
22 very long text
<a href="/222" onFocus={() => handleFocus(1)}>
22222
</a>
</div>
<div className="item">
33 very long text
<a href="/333" onFocus={() => handleFocus(2)}>
33333
</a>
</div>
<div className="item">
44 very long text
<a href="/444" onFocus={() => handleFocus(3)}>
44444
</a>
</div>
</div>
current: {curr}
</div>
);
}
// Render it
ReactDOM.render(
<App />,
document.getElementById("react")
);
.carousel {
display: flex;
align-items: center;
width: 400%;
}
.item {
flex: 0 1 100%;
text-align: center;
border: 1px solid black;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="react"></div>
I needed to prevent the scrolling and in my provided example its enough to add this line into handleFocus function
window.scrollTo(0, 0);
But in my real scenario parent wrapper also had overflow: hidden; which prevented above code from working. So I've used refs
const handleFocus = (num) => {
if (num !== curr) {
setCurr(num);
carouselRef.current.scrollTo(0, 0);
}
};
return (
<div ref={carouselRef}>
<div className="carousel" style={carouselStyles}>
...
</div>
current: {curr}
</div>
);

Tabbed dates for api content

in React i am attempting to add my api content to a series of tabs, so you click on a tab, and it will show any listings in the api matching that date.
my attempt, code of component is below
import context from "./apiContext";
import styled from "styled-components";
const Tab = styled.button`
font-size: 20px;
padding: 10px 60px;
cursor: pointer;
opacity: 0.6;
background: white;
border: 0;
outline: 0;
${({ active }) =>
active &&
`
border-bottom: 2px solid black;
opacity: 1;
`}
`;
const ButtonGroup = styled.div`
display: flex;
`;
const tabs = ["18-08-20", "19-08-20", "20-08-20"];
function Movies() {
const { films } = useContext(context);
console.log(films);
const [active, setActive] = useState(tabs[0]);
return (
<>
<div className="movies">
<div className="title">
<h1>
Movies: <span />
All Releases
</h1>
<div className="tab-menu">
<ButtonGroup>
{tabs.map((tab) => (
<Tab
key={tab.label}
active={active === tab}
onClick={() => setActive(tab)}
>
{tab.label}
</Tab>
))}
</ButtonGroup>
</div>
</div>
<div className="content">
{films
.filter((item) => item.PreShowStartTime === Date.parse({ active }))
.map((item, index) => (
<div class="card" key={index}>
<div class="title">
<span class="title">{item.Title}</span>{" "}
<span>
{new Date(item.PreShowStartTime).toLocaleDateString("en", {
day: "2-digit",
month: "short"
})}
</span>
</div>
</div>
))}
</div>
</div>
</>
);
}
export default Movies;
To view with live API:
https://codesandbox.io/s/strange-hoover-8hik2
On line 24, is my test array of dates, which also should show as the label of the tab.
You are going to have to format the dates returned by the API according to what you have defined in the tabs constant in your code (or vice versa). Currently your API returns example 2020-08-18T14:00:00 but your tabs has format 18-08-20.
So for that, on your filter condition, you can use something like:
new Date(item.PreShowStartTime).toJSON().slice(2, 10) === active
where active is the active date selected on the tab
https://codesandbox.io/s/reverent-yonath-pv8i0?file=/src/Movies.js:1293-1357
As a side note, you were also accessing tab.label to print your tab labels. tabs does not contain a property named label...

Modify DOM based on amount of divs after specific class

Is there any way to modify DOM based on amount div after specific class?
For example, if I have a div with a class called row and after that I have 4 div elements. Is there a way to change these 4 div element class depending on how many div elements there are?
Code:
<div class="row">
<div class="col-1-of-4">
some content
</div>
<div class="col-1-of-4">
some content
</div>
<div class="col-1-of-4">
some content
</div>
<div class="col-1-of-4">
some content
</div>
</div>
Another example I have a div class row again, but this time I want 3 div elements after that, then I would want these div elements to have a class called col-1-of-3, not col-1-of-4. If I would have just 2 div elements after that then class col-1-of-2 and if just one div element then no class at all.:
Code:
<div class="row">
<div class="col-1-of-3">
some content
</div>
<div class="col-1-of-3">
some content
</div>
<div class="col-1-of-3">
some content
</div>
</div>
Also these div elements with classes called col-1-of-4, col-1-of-3 and col-1-of-2 have their own div elements inside them, but they should stay like they were.
Is it possible to achieve with JavaScript or PHP?
You would need to write conditional blocks to handle this if I'm understanding you correctly (wanting a JS or PHP solution).
Note: It goes without saying that a similar solution can be completed with a CSS-only approach, as outlined here: Can CSS detect the number of children an element has?
Here's an example (using jQuery) with 3 sets of row's, with varying children (2, 3, 4):
$(function() {
var $rows = $(".row");
$rows.each(function() {
$row = $(this);
var $children = $(">div", $row),
total = $children.size();
$children.addClass("col-1-of-" + total);
});
});
.row {
border: 1px solid #000;
margin: 10px;
}
.row > div {
margin: 10px;
}
.row .col-1-of-2 {
border: 1px solid #f00;
}
.row .col-1-of-3 {
border: 1px solid #0f0;
}
.row .col-1-of-4 {
border: 1px solid #00f;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="row">
<div>
some content
</div>
<div>
some content
</div>
</div>
<div class="row">
<div>
some content
</div>
<div>
some content
</div>
<div>
some content
</div>
</div>
<div class="row">
<div>
some content
</div>
<div>
some content
</div>
<div>
some content
</div>
<div>
some content
</div>
</div>
When you run the snippet, you must inspect the elements. I've added borders so you can see the difference.
Theres a number of ways to achieve this. I'd maybe add another class name so you can easily identify groups of divs, and differentiate between parent and child divs. Does this help you get where you're going? Basically find the number of children in a row and then concatenate that number into the class name.
var x = document.getElementsByClassName('row')[0].childElementCount
var element = document.getElementsByClassName('row')[0];
element.classList.add(`col-1-of-${x}`);
.row {
width: 100%;
display:flex;
flex-grow: 1;
margin-bottom: 2px;
}
.col {
float:left;
background: rgba(255,0,0,.2);
text-align: center;
margin-right: 2px;
}
.col:first-child:nth-last-child(1),
.col:first-child:nth-last-child(1) ~ .col{
width: calc(100% / 1);
}
.col:first-child:nth-last-child(2),
.col:first-child:nth-last-child(2) ~ .col{
width: calc(100% / 2);
}
.col:first-child:nth-last-child(3),
.col:first-child:nth-last-child(3) ~ .col{
width: calc(100% / 3);
}
.col:first-child:nth-last-child(4),
.col:first-child:nth-last-child(4) ~ .col{
width: calc(100% / 4);
}
.col:first-child:nth-last-child(5),
.col:first-child:nth-last-child(5) ~ .col{
width: calc(100% / 5);
}
<div class="row">
<div class="col">1</div>
</div>
<div class="row">
<div class="col">1</div>
<div class="col">2</div>
</div>
<div class="row">
<div class="col">1</div>
<div class="col">2</div>
<div class="col">3</div>
</div>
<div class="row">
<div class="col">1</div>
<div class="col">2</div>
<div class="col">3</div>
<div class="col">4</div>
</div>
<div class="row">
<div class="col">1</div>
<div class="col">2</div>
<div class="col">3</div>
<div class="col">4</div>
<div class="col">5</div>
</div>
so this is with float, can be used in a sass/scss mixin to create code automagically. there should be also a flex solution but i dont have it at hand at the moment

Categories