how to make a vertical slide of text in React - javascript

I am trying to make a vertical text slide. Having not found help in reactjs, I try to do it myself and I'm pretty happy with the result but a slight bug appears at the end of each word slide.
I imagine that there are several ways to create this animation but it is the only one that comes to me with my knowledge in JS.
Here my code:
import React, { useEffect, useRef, useState } from 'react'
const Version1 = () => {
const [ words, setWords ] = useState(['Victor', 'Alex', 'Lucie'])
const wrapperRef = useRef()
const handleAnim = () => {
setTimeout(() => {
const copyWords = [ ...words ];
const firstElem = copyWords.splice(1)
wrapperRef.current.style.transition = 'none';
wrapperRef.current.style.top = '0px'
setWords([ ...firstElem.concat(copyWords) ])
},1000);
wrapperRef.current.style.transition = '0.5s';
wrapperRef.current.style.top = '-70px'
}
useEffect(() => {
setTimeout(() => {
handleAnim()
}, 2000);
})
return (
<>
<div className="test-container">
<div className='test-title'>Hello</div>
<div className='text-container-word'>
<div ref={wrapperRef} className='text-container-word-wrapper'>
<span className='text-word'>{words[0]}</span>
<span className='text-word'>{words[1]}</span>
</div>
</div>
</div>
<style jsx>
{`
.test-container {
padding: 100px 0;
width: 100%;
display: flex;
}
.test-title {
font-size: 48px;
font-weight: bold;
color: blue;
}
.text-container-word {
position: relative;
width: 200px;
height: 70px;
background-color: green;
display: inline-block;
overflow: hidden;
margin-top: -7px;
}
.text-container-word-wrapper {
height: auto;
position: relative;
top: 0px;
}
.test-container h1 {
position: relative;
display: inline;
padding: 10px;
}
.text-word {
height: 70px;
font-size: 48px;
font-weight: bold;
display: block;
transition: 0.5s;
line-height: 70px;
}
`}
</style>
</>
)
}
export default Version1

Here is a pure css based solution that uses words from state without the useEffect hacks.
const {useState} = React;
function App() {
const [words, setWords] = useState(["Victor", "Alex", "Lucie", "Michael"]);
return (
<div className="App">
<div className="scroller">
<span>
{words[0]}
<br />
{words[1]}
<br />
{words[2]}
<br />
{words[3]}
</span>
</div>
</div>
);
}
ReactDOM.render(
<App/>,
document.getElementById("react")
);
.App {
font-family: sans-serif;
text-align: center;
}
.scroller {
height: 1.2em;
line-height: 1.2em;
position: relative;
overflow: hidden;
font-size: 40px;
text-align: center;
}
.scroller > span {
position: absolute;
top: 0;
animation: slide 6s infinite;
font-weight: bold;
background-color: green;
}
#keyframes slide {
0% {
top: 0;
}
25% {
top: -1.2em;
}
50% {
top: -2.4em;
}
75% {
top: -3.6em;
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script>
<div id="react">

set height and width with overflow-f:scroll
overflow-y: scroll;
you can also see this: https://www.w3schools.com/cssref/tryit.asp?filename=trycss3_overflow-y

Related

Console.log is telling me my div is null when I try and add a class to it

I'm adding a keydown eventlistener that'll simply make my box div show. However, when I press a key, nothing happens and instead the console tells me, "Uncaught TypeError: box is null".
No idea what the problem is, please help
Here's my App.js:
import "./styles.css"
const box = document.querySelector(".box");
const notification = document.querySelector(".notif");
window.onload = document.addEventListener("keydown", e => {
box.classList.add("active");
notification.classList.add("inactive");
})
function App() {
return (
<>
<div className='notif'>Press Any Key</div>
<div className='box'>
<h2>20</h2>
<h1>Shift</h1>
</div>
</>
);
}
export default App;
and the css:
#import url('https://fonts.googleapis.com/css2?family=Poppins&display=swap');
:root {
--teal: #00ccff;
--pink: #d400d4;
}
*, *::before, *::after {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: 'Poppins', sans-serif;
}
body {
display: flex;
min-height: 100vh;
align-items: center;
justify-content: center;
background: #0e1538;
}
.box {
position: relative;
width: 300px;
height: 300px;
display: flex;
justify-content: center;
align-items: center;
background: rgba(0,0,0,.5);
overflow: hidden;
border-radius: 20px;
flex-direction: column;
display: none;
}
.box.active {
display: flex;
}
.box::before {
content: '';
position: absolute;
width: 150px;
height: 140%;
background: linear-gradient(var(--teal), var(--pink));
animation: animate 4s linear infinite;
}
#keyframes animate {
0%{
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
.box::after {
content: '';
position: absolute;
background: #0e1538;
inset: 4px;
border-radius: 16px;
}
.box h2 {
position: relative;
color: white;
font-size: 5em;
z-index: 10;
}
.box h1 {
position: relative;
color: white;
z-index: 10;
background: rgba(0,0,0,.5);
width: 97.5%;
text-align: center;
letter-spacing: 5px;
}
.notif {
font-size: 3em;
background: var(--teal);
padding: 0 20px;
border-radius: 20px;
}
.notif.inactive {
display: none;
}
You should be maintaining/updating state with the new class information when you press a key. Add the listener within the useEffect (along with a cleanup function). When a key is pressed the listener calls a function that updates the state (in this case switching the active/inactive classes). The component is re-rendered, and the elements' class names are changed using a little helper function.
const { useEffect, useState } = React;
function Example() {
// Initialise state
const [ active, setActive ] = useState({
box: false,
notification: true
});
// A function to update the state
function toggleActive() {
setActive(prev => ({
box: !prev.box,
notification: !prev.notification
}));
}
// An effect that adds a listener, w/ a cleanup function
useEffect(() => {
window.addEventListener('keydown', toggleActive);
return () => {
window.removeEventListener('keydown', toggleActive);
}
}, []);
// Returns the active status of the element from state
function isActive(type) {
return active[type] ? 'active' : 'inactive';
}
return (
<div>
<div className={isActive('notification')}>
Press Any Key
</div>
<div className={isActive('box')}>
<h2>20</h2>
<h1>Shift</h1>
</div>
</div>
);
}
ReactDOM.render(
<Example />,
document.getElementById('react')
);
.active { color: red; }
.inactive { color: black; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.2/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.2/umd/react-dom.production.min.js"></script>
<div id="react"></div>
import "./styles.css"
import {useEffect} from 'react'
function App() {
useEffect(()=>{
const box = document.querySelector(".box");
const notification = document.querySelector(".notif");
document.addEventListener("keydown", e => {
box.classList.add("active");
notification.classList.add("inactive");
})
},[])
return (
<>
<div className='notif'>Press Any Key</div>
<div className='box'>
<h2>20</h2>
<h1>Shift</h1>
</div>
</>
);
}
export default App;

The way to optimize react and Typescript codes

In this case, I used React + TypeScript and ant-design. The following code works perfectly but I want the codes to be summarized as much as possible. This is about starting a site that has 3 pages. For example, how can I write this part (const { id, title, description, background } = splash;) so that I don't need to define (splashs[index].background , splashs[index].title, splashs[index].description) all the time.
Thank you in advance for your cooperation.
.splash {
height: 100vh;
position: relative;
overflow: hidden;
}
.bg {
background-color: var(--cjp);
}
.BgGradiant {
background: linear-gradient(107.78deg, rgba(80, 21, 100, 0) 1.87%, rgba(80, 21, 100, 0.05) 18.6%, rgba(80, 21, 100, 0.51) 25.79%, #1C3396 99.02%, #1C3396 51.08%);
}
.context{
width: 80%;
}
.content {
text-align: center;
}
.content h1,
.content p {
color: var(--cwh);
}
.backgroundImage>img {
position: absolute;
width: 100%;
height: 100%;
top: 0;
left: 0;
z-index: -1;
-o-object-fit: cover;
object-fit: cover;
}
.logo {
width: 100%;
text-align: center;
}
.btns {
display: flex !important;
align-items: center;
justify-content: space-between;
-webkit-margin-start: auto;
margin-inline-start: auto;
-webkit-margin-end: auto;
margin-inline-end: auto;
-webkit-margin-before: 2rem;
margin-block-start: 7rem;
}
.btns :global(.ant-btn){
background-color: var(--cwh);
border-radius: var(--borderRadius12);
position: relative;
padding: 4px 10px !important;
}
.btns :global(.ant-btn)::after{
content: "";
position: absolute;
width: 125%;
height: 125%;
top: 50%;
left: 50%;
border: 1px solid var(--chb);
border-radius: var(--borderRadius14);
transform: translate(-50%, -50%);
}
.btns :global(.ant-btn > span){
margin-left: 0 !important;
}
.btns :global(.ant-btn > span > svg){
fill: var(--cal);
}
.btnSkip {
background-color: unset;
outline: none;
border: none;
color: var(--cca);
}
.btnLogin{
-webkit-margin-before: 2rem;
margin-block-start: 7rem;
}
.btnLogin :global(.ant-btn){
border-radius: var(--borderRadius10);
background-color: var(--cwh);
color: var(--cjp);
}
.btnLogin :global(.ant-btn > span){
font-family: "Display-Bold";
}
.dots {
position: absolute;
bottom: 17%;
display: flex !important;
align-items: center;
justify-content: center;
left: 50%;
transform: translateX(-50%);
}
.dot {
width: 10px;
height: 10px;
border-radius: 50%;
}
.dotActive {
background-color: var(--cwh);
}
.dotDeActive {
background-color: var(--cca);
}
.dot:not(:last-child) {
-webkit-margin-end: 0.5rem;
margin-inline-end: 0.5rem;
}
.contentInner{
height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
-webkit-padding-before: 2rem;
padding-block-start: 2rem;
-webkit-padding-after: 3rem;
padding-block-end: 3rem;
}
.contentInner1{
justify-content: space-between;
}
.contentInner2{
justify-content: flex-end;
}
import React, { useState } from 'react';
import { useNavigate } from "react-router-dom";
import { Row, Col, Button } from 'antd';
import { ArrowRightOutlined } from '#ant-design/icons';
import Container from '../../Components/UI/Container/Container'
import classes from './Splash.module.css';
import { backgroundSplash1, backgroundSplash2, logoImage } from '../../Assets/index';
const Splash = () => {
let navigate = useNavigate();
const [index, setIndex] = useState<number>(0);
const {
splash,
bg,
BgGradiant,
context,
content,
backgroundImage,
logo,
btns,
btnLogin,
btnSkip,
dots,
dot,
dotActive,
dotDeActive,
contentInner,
contentInner1,
contentInner2,
} = classes
const splashs = [
{
id: 0,
title: 'Page 1 : title 1',
desctiption: '1- Lorem ipsum 1 ',
background: logoImage,
},
{
id: 1,
title: 'Page 2 : title 2',
desctiption: '2- Lorem ipsum 2 ',
background: backgroundSplash1,
},
{
id: 2,
title: 'Page 3 : title3',
desctiption: '3- Lorem ipsum 3',
background: backgroundSplash2,
}
];
const nextBnt = () => {
setIndex(index + 1);
if (index === splashs.length - 1) {
return navigate("/login");
}
}
const skipBtn = () => {
console.log('skip ');
return navigate("/login");
}
const loginBtn = () => {
return navigate("/login");
}
return (
<>
<Row>
<Col xs={24}>
<section
className={`${index === 0 ? bg : BgGradiant} ${splash}`}>
{
splashs.map((splash) => {
const { id, title, desctiption, background } = splash;
console.log(title, "title");
return (
<>
{
index !== 0 && (
<div className={backgroundImage}>
<img src={splashs[index].background} />
</div>
)
}
<Container key={id} className={backgroundImage}>
<div className={`${index === 0 ? contentInner1 : contentInner2} ${contentInner}`}>
{
index === 0 && (
<div className={logo}>
<img src={logoImage} alt="logoImage" />
</div>
)
}
<div className={context}>
<div className={content}>
<h1>{splashs[index].title}</h1>
<p>{splashs[index].desctiption}</p>
</div>
{/* BTNS */}
{
index === splashs.length - 1 ? (
<div className={btnLogin}>
<Button block onClick={loginBtn}>Login</Button>
</div>
) : (
<div className={btns}>
<button className={btnSkip} onClick={skipBtn}>skip</button>
<Button onClick={nextBnt}> <ArrowRightOutlined /></Button>
</div>
)
}
</div>
</div>
</Container>
</>
)
})
}
<div className={dots}>
{
Array.from({ length: 3 }).map((item, idx) => {
return (
<div key={idx} className={`${dot} ${index === idx ? dotActive : dotDeActive}`}></div>
)
})
}
</div>
</section>
</Col>
</Row>
</>
)
}
export default Splash;
Just an advice, your question isn't really well formulated so it's hard to understand what are you trying to accomplish. Try to keep the questions clear and remove any redundant code so the community can better understand it.
If I'm assuming correctly that you don't want to use splash[index] then you should change splash[index].title to title, same for the other props.
Since you already destructured the splash object with const { id, title, description, background } = splash; all these will be available.
Another thing here is, .map method returns the item in the array so I don't see the point in you using the index inside the loop to access the item from the array.

Creating an animation for a basic React slot machine

I'm quite new to react and a simple slot machine is my first mini-project. Currently I have completed the logic for displaying random emojis after the button is pressed. The next step for me, before styling and adding logic for winning/losing and a counter for coins etc is adding an animation.
https://codepen.io/fmressel/pen/vRLerN
This codepen is exactly the sort of thing I'm after, but as you can see it is structured quite differently to my code (below), and I'm pulling my hair out trying to figure out how I can get something similar to work for my project.
Any help much appreciated!
import React, { Component } from 'react'
import Contents from './Contents'
import './mainslots.css'
class Slots extends Component {
static defaultProps = {
fruits: ["🍒", "🍉", "🍊", "🍓", "🍇", "🥝"]
};
constructor(props) {
super(props);
this.state = {fruit1: '🍒', fruit2: '🍒', fruit3: '🍒', rolling: false};
this.roll = this.roll.bind(this);
};
roll = () => {
const dFruit1 = this.props.fruits[
Math.floor(Math.random() * this.props.fruits.length)
];
const dFruit2 = this.props.fruits[
Math.floor(Math.random() * this.props.fruits.length)
];
const dFruit3 = this.props.fruits[
Math.floor(Math.random() * this.props.fruits.length)
];
this.setState({fruit1: dFruit1, fruit2: dFruit2, fruit3: dFruit3, rolling: true});
setTimeout(() => {
this.setState({ rolling: false });
}, 700)
}
render(){
return(
<div className="SlotMachine">
<div className="SlotsContainer">
{this.state.fruit1}
{this.state.fruit2}
{this.state.fruit3}
</div>
<button className="spinner" onClick={this.roll} disabled={this.state.rolling}>
{this.state.rolling ? "Spinning..." : "Spin"}
</button>
</div>
);
}
}
export default Slots;
import React, { Component } from 'react'
class Contents extends Component {
Fruits = ["🍒", "🍉", "🍊", "🍓", "🍇", "🥝"];
render() {
return(
<div className="emptys">
{this.props.roll}
</div>
)
}
}
export default Contents
Here you go,
It was fun to develop :), you can run the below code snippet to review and I've added the comments in code, that will make things clear, please have a look,
Hope this will help,
const { createRef , Component } = React;
class Slots extends Component {
static defaultProps = {
fruits: ["🍒", "🍉", "🍊", "🍓", "🍇", "🥝"]
};
constructor(props) {
super(props);
this.state = { fruit1: "🍒", fruit2: "🍒", fruit3: "🍒", rolling: false };
// get ref of dic onn which elements will roll
this.slotRef = [createRef(), createRef(), createRef()];
}
// to trigger roolling and maintain state
roll = () => {
this.setState({
rolling: true
});
setTimeout(() => {
this.setState({ rolling: false });
}, 700);
// looping through all 3 slots to start rolling
this.slotRef.forEach((slot, i) => {
// this will trigger rolling effect
const selected = this.triggerSlotRotation(slot.current);
this.setState({ [`fruit${i + 1}`]: selected });
});
};
// this will create a rolling effect and return random selected option
triggerSlotRotation = ref => {
function setTop(top) {
ref.style.top = `${top}px`;
}
let options = ref.children;
let randomOption = Math.floor(
Math.random() * Slots.defaultProps.fruits.length
);
let choosenOption = options[randomOption];
setTop(-choosenOption.offsetTop + 2);
return Slots.defaultProps.fruits[randomOption];
};
render() {
return (
<div className="SlotMachine">
<div className="slot">
<section>
<div className="container" ref={this.slotRef[0]}>
{Slots.defaultProps.fruits.map((fruit, i) => (
<div key={i}>
<span>{fruit}</span>
</div>
))}
</div>
</section>
</div>
<div className="slot">
<section>
<div className="container" ref={this.slotRef[1]}>
{Slots.defaultProps.fruits.map(fruit => (
<div>
<span>{fruit}</span>
</div>
))}
</div>
</section>
</div>
<div className="slot">
<section>
<div className="container" ref={this.slotRef[2]}>
{Slots.defaultProps.fruits.map(fruit => (
<div>
<span>{fruit}</span>
</div>
))}
</div>
</section>
</div>
<div
className={!this.state.rolling ? "roll rolling" : "roll"}
onClick={!this.state.rolling && this.roll}
disabled={this.state.rolling}
>
{this.state.rolling ? "Rolling..." : "ROLL"}
</div>
</div>
);
}
}
ReactDOM.render(<Slots />, document.getElementById('react-root'));
.App {
font-family: sans-serif;
text-align: center;
}
.slot {
position: relative;
display: inline-block;
height: 100px;
width: 80px;
}
section {
position: absolute;
border-radius: 15px !important;
border: 3px solid black !important;
width: 70px;
height: 70px;
overflow: hidden;
background-color: grey;
border-radius: 2px;
border: 1px solid lightgrey;
color: white;
font-family: sans-serif;
text-align: center;
font-size: 25px;
line-height: 60px;
cursor: default;
}
.container {
position: absolute;
top: 2px;
width: 100%;
transition: top ease-in-out 0.5s;
text-align: center;
}
.roll {
width: 215px;
cursor: pointer;
background-color: yellow;
padding: 10px;
text-align: center;
font-size: 20px;
border-radius: 20px;
border: 3px solid black;
}
.rolling {
animation: blinkingText 1.2s infinite;
}
#keyframes blinkingText {
0% {
color: #000;
}
49% {
color: #000;
}
60% {
color: transparent;
}
99% {
color: transparent;
}
100% {
color: #000;
}
}
<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-root"></div>
I recreated the #VivekDoshi 's answer as a react FC.
const { useRef, useState} = React;
function Slots(){
const [fruit1,setFruit1] = useState("🍒");
const [fruit2,setFruit2] = useState("🍒");
const [fruit3,setFruit3] = useState("🍒");
const [rolling,setRolling] = useState(false);
let slotRef = [useRef(null), useRef(null), useRef(null)];
const fruits = ["🍒", "🍉", "🍊", "🍓", "🍇", "🥝"]
// to trigger roolling and maintain state
const roll = () => {
setRolling(true);
setTimeout(() => {
setRolling(false);
}, 700);
// looping through all 3 slots to start rolling
slotRef.forEach((slot, i) => {
// this will trigger rolling effect
const selected = triggerSlotRotation(slot.current);
if(i+1 == 1)
setFruit1(selected);
else if(i+1 == 2)
setFruit2(selected);
else
setFruit3(selected);
});
};
// this will create a rolling effect and return random selected option
const triggerSlotRotation = ref => {
function setTop(top) {
ref.style.top = `${top}px`;
}
let options = ref.children;
let randomOption = Math.floor(
Math.random() * fruits.length
);
let choosenOption = options[randomOption];
setTop(-choosenOption.offsetTop + 2);
return fruits[randomOption];
};
return (
<div className="SlotMachine">
<div className="slot">
<section>
<div className="container" ref={slotRef[0]}>
{fruits.map((fruit, i) => (
<div key={i}>
<span>{fruit}</span>
</div>
))}
</div>
</section>
</div>
<div className="slot">
<section>
<div className="container" ref={slotRef[1]}>
{fruits.map(fruit => (
<div>
<span>{fruit}</span>
</div>
))}
</div>
</section>
</div>
<div className="slot">
<section>
<div className="container" ref={slotRef[2]}>
{fruits.map(fruit => (
<div>
<span>{fruit}</span>
</div>
))}
</div>
</section>
</div>
<div
className={!rolling ? "roll rolling" : "roll"}
onClick={!rolling && roll}
disabled={rolling}>
{rolling ? "Rolling..." : "ROLL"}
</div>
</div>
);
};
ReactDOM.render(<Slots />, document.getElementById('react-root'));
.App {
font-family: sans-serif;
text-align: center;
}
.slot {
position: relative;
display: inline-block;
height: 100px;
width: 80px;
}
section {
position: absolute;
border-radius: 15px !important;
border: 3px solid black !important;
width: 70px;
height: 70px;
overflow: hidden;
background-color: grey;
border-radius: 2px;
border: 1px solid lightgrey;
color: white;
font-family: sans-serif;
text-align: center;
font-size: 25px;
line-height: 60px;
cursor: default;
}
.container {
position: absolute;
top: 2px;
width: 100%;
transition: top ease-in-out 0.5s;
text-align: center;
}
.roll {
width: 215px;
cursor: pointer;
background-color: yellow;
padding: 10px;
text-align: center;
font-size: 20px;
border-radius: 20px;
border: 3px solid black;
}
.rolling {
animation: blinkingText 1.2s infinite;
}
#keyframes blinkingText {
0% {
color: #000;
}
49% {
color: #000;
}
60% {
color: transparent;
}
99% {
color: transparent;
}
100% {
color: #000;
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script>
<div id="react-root"></div>

create an expand content or show more content button in react app

So i am trying to basically add a expand button to my react app that will reveal more information and i would prefer that the app expand the div size to reveal the additional content, so the its basically an expand button, i understand i need to utilize the usestate property and a function however i am having a hard time figuring out how do i update the css of the student div to expand and reveal the added information. The added information is the grades portion (FYI).
UPDATE: I have found a way to display the changes the problem i am facing is to get the state to start as isExpanded false so when a user clicks the plus button it expands to reveal the class hidden information again
here is my App.js file
import React, { useState } from "react";
import "./App.css";
export default function App() {
const [students, setStudents] = useState(null);
const [filterData, setFilterData ] = useState(null);
const [isExpanded, setIsExpanded] = useState(false);
const studentdata = 'https://www.hatchways.io/api/assessment/students';
function getStudents(){
fetch(studentdata)
.then(resp => resp.json())
.then(data => {
setFilterData(data.students);
setStudents(data.students);
setIsExpanded(false);
})
}
const searchByName = (event) => {
event.persist();
// Get the search term
const searchItem = event.target.value.toLowerCase().trim();
// If search term is empty fill with full students data
if(!searchItem.trim()) {
setFilterData(students);
}
// Search the name and if it found retun the same array
const serachIn = (firstName, lastName) => {
if(firstName.indexOf(searchItem) !== -1 || lastName.indexOf(searchItem) !== -1) {
return true;
}
let fullName = firstName.toLowerCase()+" "+lastName.toLowerCase();
if(fullName.indexOf(searchItem) !== -1) {
return true;
}
return false;
};
// Filter the array
const filteredData = students.filter((item) => {
return serachIn(item.firstName, item.lastName);
});
// Set the state with filtered data
setFilterData(filteredData);
}
function exp() {
if(isExpanded){
setIsExpanded(true);
}
}
return (
<div className="App">
<h1>Students</h1>
<div>
<button className="fetch-button" onClick={getStudents}>
Get Students
</button>
<br />
</div>
<div className="search" id="search">
<input type="text" name="serachByName" id="searchbar" placeholder="Search by name" onChange={(e) => searchByName(e)} ></input>
</div>
{filterData && filterData.map((student, index) => {
var total = 0;
for(var i = 0; i < student.grades.length; i++) {
var grade = parseInt(student.grades[i]);
total += grade;
}
const avg = total / student.grades.length;
const average = avg.toString();
const grade1 = student.grades[0];
const grade2 = student.grades[1];
const grade3 = student.grades[2];
const grade4 = student.grades[3];
const grade5 = student.grades[4];
const grade6 = student.grades[5];
const grade7 = student.grades[6];
const grade8 = student.grades[7];
return(
<div className={'student' + isExpanded ? 'expanded' : '' } key={index}>
<div className="image">
<img src={student.pic} id="icon"></img>
</div>
<div className="text">
<h3 id="name">{student.firstName} {student.lastName}</h3>
<p id="detail"><strong>EMAIL:</strong> {student.email}</p>
<p id="detail"><strong>COMPANY:</strong> {student.company}</p>
<p id="detail"><strong>SKILL:</strong> {student.skill}</p>
<p id="detail"><strong>AVERAGE:</strong>: {average}%</p>
<p id="detail" className="hidden">
<br></br>Test 1 :{grade1}
<br></br>Test 2 :{grade2}
<br></br>Test 3 :{grade3}
<br></br>Test 4 :{grade4}
<br></br>Test 5 :{grade5}
<br></br>Test 6 :{grade6}
<br></br>Test 7 :{grade7}
<br></br>Test 8 :{grade8}
</p>
</div>
<div className="expand">
<button className="expand_btn" onClick={exp()} id="expand_btn">+</button>
</div>
</div>
)}
)}
</div>
);
}
and my css file
#import url('https://fonts.googleapis.com/css?family=Bebas+Neue&display=swap');
#import url('https://fonts.googleapis.com/css?family=Roboto:300,400&display=swap');
.root{
width: 100vw;
height: 100vh;
background-color: black;
}
.App {
text-align: center;
width: 1000px;
height: 750px;
background-color: aliceblue;
border: 4px solid black;
border-radius: 5%;
margin-top: 75px;
margin-left: auto;
margin-right: auto;
overflow: scroll;
}
.student{
width: 80%;
height: 200px;
background-color: white;
display: flex;
align-items: center;
padding-top: 3%;
padding-bottom: 3%;
border: 2px solid lightblue;
margin-left: auto;
margin-right: auto;
}
.text{
text-align: left;
padding-left: 7%;
width: 300px;
}
.image{
padding-left: 15%;
}
#icon{
border-radius: 50%;
width: 150px;
height: 150px;
border: 2px solid black;
}
#name{
text-transform: capitalize;
font-family: 'Bebas Neue';
letter-spacing: 4px;
font-size: 40px;
margin-bottom: 10px;
margin-top: 10px;
}
#detail {
font-family: 'Roboto';
font-weight: 300;
line-height: normal;
margin: 0;
}
.search {
width: 80%;
height: 20px;
margin-left: auto;
margin-right: auto;
margin-top: 10px;
margin-bottom: 20px;
}
#searchbar {
width: 100%;
height: 30px;
font-family: 'Roboto';
font-size: 18px;
font-weight: 300;
}
.expand {
width: 100px;
height: 100px;
padding-left: 3%;
margin-bottom: 5%;
}
#expand_btn {
font-family: 'Bebas Neue';
font-size: 50px;
color: lightskyblue;
background-color: transparent;
border: none;
}
.hidden {
display: none;
}
.expanded{
width: 80%;
height: 300px;
background-color: white;
display: flex;
align-items: center;
padding-top: 3%;
padding-bottom: 3%;
border: 2px solid lightblue;
margin-left: auto;
margin-right: auto;
}
I have fixed the issue in this codesandbox - https://codesandbox.io/s/purple-bird-j5vrm
Check and let me know if this helps.
There are many ways to solve your problem. One way is adding isExpanded flag to each object in the students array so that each student object would know if that is expanded or not. And I have used the flag like this
className={"student " + student.isExpanded ? "expanded" : " "}
As per your implementation, isExpanded was being set globally so every student item would be set as Expanded and there was no way to know which item was expanded.
Note: I have implemented only for getStudents and not filterStudents.

Centering active element inside custom React carousel

I have a simple custom React carousel:
https://codesandbox.io/s/infallible-wood-740s2?fontsize=14
It goes through numbers from 1 to 100. I'm trying to have an active number centered with large font size, and its neighbors with smaller font size:
To progress through this carousel, you have to click on the carousel.
The issue is that progressing through the carousel numbers starts to misalign. I suppose that it is because of the wrong calculation for left property.
I've tried to tweak the formula, use React Transition Group, and find some existing package which could solve this issue, but I haven't succeeded. I would appreciate any help.
Component code:
import React, { Component } from "react";
import ReactDOM from "react-dom";
import {
Wrapper,
NumbersWrapper,
NumbersScroller,
NumberText
} from "./Numbers.style";
const hundred = new Array(100)
.fill(0)
.map((k, v) => ({ key: v, label: v + 1 }));
class Numbers extends Component {
constructor(props) {
super(props);
this.state = {
activeNumber: 0
};
}
setActiveNumber(number) {
this.setState({
activeNumber: number
});
}
render() {
const { activeNumber } = this.state;
const intAciveNumber = Number(activeNumber);
return (
<Wrapper>
<NumbersWrapper
onClick={() => this.setActiveNumber(intAciveNumber + 1)}
>
<NumbersScroller
style={{
left: `${130 - intAciveNumber * 55}px`
}}
>
{hundred.map(({ key, label }) => {
const isNeighbor =
key + 1 === activeNumber || key - 1 === activeNumber;
const isActive = key === activeNumber;
return (
<NumberText
key={key}
isNeighbor={isNeighbor}
isActive={isActive}
>
{label}
</NumberText>
);
})}
</NumbersScroller>
</NumbersWrapper>
</Wrapper>
);
}
}
export default Numbers;
const rootElement = document.getElementById("root");
ReactDOM.render(<Numbers />, rootElement);
Numbers.style.js:
import styled from "styled-components";
export const Wrapper = styled.div`
height: 549px;
width: 612px;
border-radius: 28px;
background-color: #ffffff;
margin-top: 116px;
padding: 26px 0 0 0;
display: flex;
flex-direction: column;
align-items: center;
position: absolute;
left: 50%;
top: 0%;
transform: translate(-50%, -10%);
overflow: hidden;
`;
export const NumbersWrapper = styled.div`
white-space: nowrap;
width: 359.5px;
overflow: hidden;
`;
export const NumbersScroller = styled.div`
transition: all 150ms ease-in;
position: relative;
left: 130px;
`;
const numberTextStyle = props => {
if (props.isNeighbor) {
return `
height: 88px;
width: 53px;
opacity: 0.45;
color: #6C879C;
font-size: 80px;
font-weight: 300;
letter-spacing: -1.6px;
line-height: 88px;
text-align: center;
`;
}
if (props.isActive) {
return `
height: 156px;
color: #6C879C;
font-size: 150px;
font-weight: 300;
letter-spacing: -3px;
line-height: 156px;
text-align: center;
`;
}
return `
opacity: 0.2;
color: #6C879C;
font-size: 40px;
font-weight: 300;
letter-spacing: -0.8px;
line-height: 48px;
text-align: center;
`;
};
export const NumberText = styled.span`
font-family: Avenir;
margin: 0 15px;
user-select: none;
&:first-child {
margin-left: 0;
}
&:last-child {
margin-right: 0;
}
${props => numberTextStyle(props)}
`;

Categories

Resources