How do I stack two containers when they're in different components? - javascript

In my React app I am creating a task tracker and I have a form which is used to add or filter tasks in one component. In another component I am mapping through the tasks the list each task. I'm trying to put my task list on top of the form container.
TaskList.js
function TaskList({ tasks, setTasks, filterTasks }) {
return (
<div className='task-container'>
<ul className='task-list'>
{filterTasks.map((task) => (
<Task
task={task}
tasks={tasks}
setTasks={setTasks}
text={task.text}
id={task.id}
/>
))}
</ul>
</div>
);
}
TaskForm.js
return (
<div className='form-container'>
<form className='task-form'>
<input
value={inputText}
onChange={inputHandler}
type='text'
className='task-input'
/>
<button onClick={submitHandler} className='task-button' type='submit'>
<i className='fas fa-plus-square'></i>
</button>
<div className='select'>
<select onChange={statusHandler} name='tasks' className='filter-task'>
<option value='all'>All</option>
<option value='completed'>Completed</option>
<option value='uncompleted'>Uncompleted</option>
</select>
</div>
</form>
</div>
);
Styles
.form-container {
display: flex;
justify-content: center;
}
.task-form {
background-color: #222831;
width: 450px;
min-height: 300px;
display: flex;
justify-content: center;
margin: 0;
border-radius: 10px;
}
form input,
form button {
padding: 0.5rem;
border: none;
background: white;
margin: 0px 0px 0px 20px;
}
form button {
color: #ff6f47;
background: #f7fffe;
cursor: pointer;
transition: all 0.3s ease;
font-size: 2rem;
}
form button:hover {
background: #ff6f47;
color: white;
}
.task-container {
display: flex;
justify-content: center;
align-items: center;
}
.task-list {
min-width: 30%;
list-style: none;
padding: 0;
}
.task {
margin: 0.5rem;
background: white;
font-size: 1.5rem;
color: black;
display: flex;
justify-content: space-between;
align-items: center;
transition: all 1s ease;
}
.task-button {
margin: 0;
height: 64px;
margin-top: 12px;
}
.filter-task {
padding: 1rem;
}
.task li {
flex: 1;
}
.task-item {
padding: 0rem 0.5rem;
}
.task-input {
padding-left: 10px;
width: 200px;
height: 64px;
margin-top: 12px;
}
When changing the positioning to absolute, everything shifts to the left. I'm not sure how to make .task-container a child element of the .task-form.

I'm not sure if this is what you are looking for but to answer this part
"I'm trying to put my task list on top of the form container."
You should just be able to stack the components in whatever parent component you are rendering them in.
Hope this helps, not sure if it answers what you were asking.
function TaskList({}) {
return (
<div className='task-container'>
task list content
</div>
);
}
function TaskForm({}) {
return (
<div className='form-container'>
task form content
</div>
);
}
class App extends React.Component {
render() {
const {title} = this.props;
return (
<div>
<TaskList/>
<TaskForm/>
</div>
);
}
}
ReactDOM.render(
<App />,
document.getElementById("react")
);
.task-container {
display: flex;
justify-content: center;
align-items: center;
}
.form-container {
display: flex;
justify-content: center;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.1/umd/react-dom.production.min.js"></script>
<div id="react"></div>

Related

White line in div hides text (custom component)

I am currently working in ReactJS together with some SCSS / CSS stylings.
However, I made a component, that lists number codecs on hover.
In normal state it's a div, that indicates a small or big damage size.
When you hover on it, it opens the listed mentioned above.
For some reason, I always have this white line, ditching my number coded so I can't be read. What did I miss? My code is below.
Livedemo: https://stackblitz.com/edit/react-ts-cun89d?file=App.js
DAMAGE_SIZE_STATUSES = {
GREEN: 'green',
YELLOW: 'yellow',
RED: 'red',
};
'index.js'
...
const criticality =
// eslint-disable-next-line no-nested-ternary
critical && criticalConditions.some((condition) => condition.fulfilled)
? DAMAGE_SIZE_STATUSES.RED
: critical
? DAMAGE_SIZE_STATUSES.YELLOW
: DAMAGE_SIZE_STATUSES.GREEN;
const criticalityTextKey = getIndicatorStatusTextKey(criticality);
const criticalityIcon = getIndicatorStatusIcon(criticality);
return
<div className={classNames('DamageSizeIndicator', criticality)}>
<div className="content">
<div className="title">
<div className="criticality">
{criticalityIcon && <Icon type={criticalityIcon} theme="filled" />}
{t(criticalityTextKey)}
</div>
<div className="condition" />
</div>
{critical ? (
<ul className="critical-icds">
{criticalConditions.map((icd) => (
<li
key={`critical-icd_${icd.code}`}
className={classNames({
'icd-fulfilled': icd.fulfilled,
'icd-unfulfilled': !icd.fulfilled,
})}
>
<div className="icd-description">
<span>ICD {icd.code}</span>
<Tooltip title={icd.description}>{icd.description}</Tooltip>
</div>
<div className="icd-condition">
<span>
<Icon
type={
icd.fulfilled ? 'check-circle' : 'exclamation-circle'
}
/>
{t(getConditionFulfilledTextKey(icd.fulfilled))}
</span>
{icd.condition}
</div>
</li>
))}
</ul>
) : null}
styling.scss
#import 'src/app/variables.scss';
.DamageSizeIndicator {
display: flex;
flex-direction: column;
height: 72px;
justify-content: flex-start;
font-family: Arial, Helvetica, sans-serif;
font-weight: 450;
white-space: nowrap;
margin-left: 25px;
position: relative;
z-index: 2;
.content {
display: flex;
flex-direction: column;
box-shadow: $overlay-shadow;
border-radius: $overlay-radius;
position: absolute;
.title,
.critical-icds {
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
flex: 1;
border-radius: $overlay-radius;
padding: 10px;
transition: 0.2s linear all;
i {
margin-right: 0.5em;
}
}
.title {
background: $colorSubtleWhite;
font-size: $titleFontSize;
.condition {
display: none;
white-space: nowrap;
padding-left: 0.5em;
}
}
.critical-icds {
background: $colorSubtleGray;
font-size: $subTitleFontSize;
display: none;
list-style: none;
margin: 0;
flex-direction: column;
li {
width: 100%;
margin: 0;
display: flex;
flex-direction: column;
span {
color: $colorGray;
white-space: nowrap;
padding-right: 0.5em;
}
.icd-description,
.icd-condition {
color: $colorLightBlack;
position: relative;
max-width: 350px;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
&.icd-unfulfilled {
.icd-condition span {
color: $colorIndicatorYellow;
}
}
&.icd-fulfilled {
.icd-condition span {
color: $colorIndicatorGreen;
}
}
}
}
}
&:hover {
/* cursor: pointer; */
.content {
.title {
border-bottom-left-radius: 0;
border-bottom-right-radius: 0;
.condition {
display: block;
}
}
.critical-icds {
border-top-left-radius: 0;
border-top-right-radius: 0;
display: flex;
line-height: inherit;
li:not(:last-child) {
margin-bottom: 1rem;
}
}
}
}
&.green {
.content {
box-shadow: none;
.title .criticality {
color: $colorIndicatorGray;
}
}
pointer-events: none;
}
&.yellow {
.content .title .criticality {
color: $colorIndicatorYellow;
}
}
&.red {
.content .title .criticality {
color: $colorIndicatorRed;
}
}
}

Using Google reCAPTCHA On Node & JSX

I am trying to make the google recaptcha function properly on nodejs.
Currently the recaptcha doesn't work with the login function.
I want it to be required for the user to solve the recaptcha before logging in.
If you have any information on how to do this please let me know, I truly appreciate it
What I have in login.jsx is:
import { useContext,useRef } from "react";
import "./login.css";
import {loginCall} from "../../apiCalls";
import {AuthContext} from "../../context/AuthContext";
import {CircularProgress} from "#material-ui/core";
import {Link} from "react-router-dom";
import ReCAPTCHA from "react-google-recaptcha";
import ReactDOM from 'react-dom'
// This is for recaptcha:
function onChange(value) {
console.log("Captcha value:", value);
}
ReactDOM.render(
<ReCAPTCHA class = "reCAPTCHA"
sitekey="6LfOgRwfAAAAAE5mPhZiirYWIRhY-Tt5Sb5SQOt_"
onChange={onChange}
required
/>,
document.body.appendChild(document.createElement("root"))
);
////
export default function Login() {
const username = useRef();
const password = useRef();
const { user, isFetching, dispatch } = useContext(AuthContext);
const handleClick = (e) => {
e.preventDefault();
console.log("clicked");
loginCall(
{ username: username.current.value, password: password.current.value },
dispatch
);
};
console.log(user);
return (
<div className="login">
<div className="loginWrapper">
<div className="loginLeft">
<h3 className="loginLogo">Cybercsun</h3>
<span className="loginDesc">
Connect with friends and the world around you on Cybercsun.
</span>
</div>
<div className="loginRight">
<form className="loginBox" onSubmit={handleClick}>
<input
placeholder="Username"
type="username"
required
className="loginInput"
ref={username}
/>
<input
placeholder="Password"
type="password"
required
minLength="3"
className="loginInput"
ref={password}
/>
<button className="loginButton" type="submit" disabled={isFetching}>
{isFetching
? <CircularProgress color="white" size="20px"/>
: "Log In"}
</button>
<span className="loginForgot">Forgot Password?</span>
<Link to="/register" className="loginRegisterButton">
<button className="loginRegisterButton">
{isFetching ? (
<CircularProgress color="white" size="20px" />
) : (
"Create a New Account"
)}
</button>
</Link>
</form>
</div>
</div>
</div>
);
}
And this is what I have in login.css:
.login {
width: 100vw;
height: 100vh;
background-color: #f0f2f5;
display: flex;
align-items: center;
justify-content: center;
}
.loginWrapper {
width: 70%;
height: 70%;
display: flex;
}
.loginLeft,
.loginRight {
flex: 1;
display: flex;
flex-direction: column;
justify-content: center;
}
.loginLogo {
font-size: 50px;
font-weight: 800;
color: #ff0000;
margin-bottom: 10px;
}
.loginDesc {
font-size: 24px;
}
.loginBox{
height: 300px;
padding: 20px;
background-color: white;
border-radius: 10px;
display: flex;
flex-direction: column;
justify-content: space-between;
}
.loginInput{
height: 50px;
border-radius: 10px;
border: 1px solid gray;
font-size: 18px;
padding-left: 20px;
}
.loginInput:focus{
outline: none;
}
.loginButton{
height: 50px;
border-radius: 10px;
border: none;
background-color: #ff0000;
color: white;
font-size: 20px;
font-weight: 500;
cursor: pointer;
}
.loginButton:focus{
outline: none;
}
.loginButton:disabled{
cursor: not-allowed;
}
.reCAPTCHA{
position: absolute;
z-index: 999;
bottom: 160px;
right: 495px;
}
.loginForgot{
text-align: center;
color: #ff0000;
}
.loginRegisterButton{
width: 60%;
align-self: center;
height: 50px;
border-radius: 10px;
border: none;
background-color: #ff0000;
color: white;
font-size: 20px;
font-weight: 500;
cursor: pointer;
}
This is what it looks like:
IMG

How to add a click event outside an element? [duplicate]

This question already has answers here:
How do I detect a click outside an element?
(91 answers)
Closed 1 year ago.
The community reviewed whether to reopen this question 1 year ago and left it closed:
Original close reason(s) were not resolved
My current code opens up an input via a click by adding a class. I'm having trouble adding a second click that removes the added class when the user clicks off the input. I added a second click event but it just stops my first click event from working.
Is there a different way to approach this using pure JavaScript?
(Commented out failed attempt.)
let searchElement = document.querySelector('#searchElement');
let offCanvas = document.querySelector('#main');
searchElement.addEventListener('click', () => {
searchElement.classList.add('extendInputSearch');
});
// offCanvas.addEventListener('click', () => {
// searchElement.classList.remove('extendInputSearch');
// });
* {
padding: 0;
margin: 0;
}
html,
body {
height: 100%;
width: 100%;
}
main {
display: flex;
align-items: center;
justify-content: center;
height: 100%;
background-color: #e1e2f1;
}
form {
display: flex;
align-items: center;
justify-content: center;
width: 100%;
}
input {
width: 100%;
height: 32px;
border: none;
outline: none;
font-size: 1rem;
}
.inputSearch {
display: flex;
align-items: center;
width: 100%;
max-width: 15px;
padding: 8px 20px;
background-color: #ffffff;
border: 1px solid transparent;
border-radius: 6px;
transition: all 0.6s cubic-bezier(0.16, 1, 0.3, 1);
}
.inputSearch:hover {
border: 1px solid #7e51fa;
}
.inputSearch i {
color: #7e51fa;
margin-right: 20px;
}
.extendInputSearch {
max-width: 400px;
}
<link rel="stylesheet" href="https://pro.fontawesome.com/releases/v5.10.0/css/all.css" integrity="sha384-AYmEC3Yw5cVb3ZcuHtOA93w35dYTsvhLPVnYs9eStHfGJvOvKxVfELGroGkvsg+p" crossorigin="anonymous"/>
<main id="main">
<form>
<div id="searchElement" class="inputSearch">
<i class="fas fa-search"></i>
<input type="text" placeholder="Search">
</div>
</form>
</main>
The problem with your attempt is that the event listener to remove the class is applied to the entire #main element, which includes searchElement. That means both event listeners are applied to the searchElement, and when you click on the searchElement, the class is first added (with the first listener) and then removed (with the second listener).
To make it work, you need to change the second listener to specifically exclude the searchElement. For example, in this code, we add a click listener to the whole document. In the listener, we check if the click is outside the searchElement by using the Node.contains() function on the event parameter. If the clicked element is not a child of searchElement (that is, the click is outside searchElement), we remove the extendInputSearch class from searchElement.
let searchElement = document.querySelector('#searchElement');
searchElement.addEventListener('click', () => {
searchElement.classList.add('extendInputSearch');
});
document.addEventListener('click', (e) => {
if(!searchElement.contains(e.target)){
searchElement.classList.remove('extendInputSearch');
}
});
* {
padding: 0;
margin: 0;
}
html,
body {
height: 100%;
width: 100%;
}
main {
display: flex;
align-items: center;
justify-content: center;
height: 100%;
background-color: #e1e2f1;
}
form {
display: flex;
align-items: center;
justify-content: center;
width: 100%;
}
input {
width: 100%;
height: 32px;
border: none;
outline: none;
font-size: 1rem;
}
.inputSearch {
display: flex;
align-items: center;
width: 100%;
max-width: 15px;
padding: 8px 20px;
background-color: #ffffff;
border: 1px solid transparent;
border-radius: 6px;
transition: all 0.6s cubic-bezier(0.16, 1, 0.3, 1);
}
.inputSearch:hover {
border: 1px solid #7e51fa;
}
.inputSearch i {
color: #7e51fa;
margin-right: 20px;
}
.extendInputSearch {
max-width: 400px;
}
<link rel="stylesheet" href="https://pro.fontawesome.com/releases/v5.10.0/css/all.css" integrity="sha384-AYmEC3Yw5cVb3ZcuHtOA93w35dYTsvhLPVnYs9eStHfGJvOvKxVfELGroGkvsg+p" crossorigin="anonymous"/>
<main id="main">
<form>
<div id="searchElement" class="inputSearch">
<i class="fas fa-search"></i>
<input type="text" placeholder="Search">
</div>
</form>
</main>
try it:
let searchElement = document.querySelector('#searchElement');
let offCanvas = document.querySelector('#main');
searchElement.addEventListener('click', () => {
searchElement.classList.add('extendInputSearch');
});
document.addEventListener('click', (e) => {
const searchElement = document.querySelector('#searchElement');
if (e.target != searchElement && e.target != searchElement.querySelector('i') && e.target != searchElement.querySelector('input')) {
searchElement.classList.remove('extendInputSearch');
}
});
* {
padding: 0;
margin: 0;
}
html,
body {
height: 100%;
width: 100%;
}
main {
display: flex;
align-items: center;
justify-content: center;
height: 100%;
background-color: #e1e2f1;
}
form {
display: flex;
align-items: center;
justify-content: center;
width: 100%;
}
input {
width: 100%;
height: 32px;
border: none;
outline: none;
font-size: 1rem;
}
.inputSearch {
display: flex;
align-items: center;
width: 100%;
max-width: 15px;
padding: 8px 20px;
background-color: #ffffff;
border: 1px solid transparent;
border-radius: 6px;
transition: all 0.6s cubic-bezier(0.16, 1, 0.3, 1);
}
.inputSearch:hover {
border: 1px solid #7e51fa;
}
.inputSearch i {
color: #7e51fa;
margin-right: 20px;
}
.extendInputSearch {
max-width: 400px;
}
<link rel="stylesheet" href="https://pro.fontawesome.com/releases/v5.10.0/css/all.css" integrity="sha384-AYmEC3Yw5cVb3ZcuHtOA93w35dYTsvhLPVnYs9eStHfGJvOvKxVfELGroGkvsg+p" crossorigin="anonymous"/>
<main id="main">
<form>
<div id="searchElement" class="inputSearch">
<i class="fas fa-search"></i>
<input type="text" placeholder="Search">
</div>
</form>
</main>

Mapbox popups in a React app not showing up after deploying to Heroku

I have a Mapbox installed in my React app which shows up popups, but only when working in localhost. When I deploy to Heroku the styles look broken. They look a bit faded so I guess it's the styles which are broken, but I'm a bit lost wondering what I could change. We are also using bootstrap to style some components.
Popup in localhost /
Popup in Heroku
This is the styles file in apps.css
.mapboxgl-popup-content{
background: none !important;
padding: 0 !important;
}
.popup-border {
background: linear-gradient(to right, rgb(255, 189, 65), rgb(255, 200, 255));
padding: 4px;
border-radius: 10%;
opacity: 100%;
}
.popup-content {
margin: auto;
color: black;
display: flex;
flex-direction: column;
justify-content: flex-start;
border-radius: 10%;
background-color: white;
min-width: 250px;
opacity: 85%;
}
.popup-title {
padding: 0px 20px;
align-items: center;
justify-content: center;
text-align: center;
}
.popup-description {
margin: 0;
padding: 0px 20px;
align-items: flex-start;
justify-content: center;
text-align: center;
}
.popup-owner-attendees {
display: flex;
flex-direction: row;
justify-content: space-evenly;
text-align: center;
padding: 0px 20px;
}
.popup-list-title {
text-decoration: underline;
}
.orange-text {
color: orange;
border-bottom: 1px solid orange;
}
In case it helps, this is also the code for the popup inside the React component:
{selectedEvent ? (
<Popup
latitude={selectedEvent.location[1]}
longitude={selectedEvent.location[0]}
onClose={() => {
setSelectedEvent(null);
}}
>
<div>
<br />
<h4>
{selectedEvent.icon} {selectedEvent.title}
</h4>
<p>{selectedEvent.description}</p>
<p>
Host:
{selectedEvent.owner
? "#" + selectedEvent.owner.username
: "Anonymous"}
</p>
<p>
{/* ATTENDEES IS NOT BEING POPULATED */}
Attendees:
<ul>
{selectedEvent.attendees.map((attendee) => {
return <li>{attendee.username}</li>;
})}
</ul>
</p>
</div>
</Popup>
) : null}

Change the flex-direction on button click

I am trying to create an animation effect that moves two buttons when I click on them. I have the flex direction set up as a column in the container div and I essentially just want them to position as a flex row when I click on one of them (probably with a 1s animation). When I click on them currently nothing happens. Here is my code sample:
HTML
<header>
<div class="container">
<h1>Choose Your Allegiance</h1>
<div id="buttons">
<button class="fill"><img src="/assets/Jedi.png" alt="Jedi" /></button>
<button class="fill sith">
<img src="/assets/Sith.png" alt="Sith" />
</div>
</button>
</div>
</header>
CSS
.container {
width: 100vw;
display: flex;
flex-direction: column;
align-items: center;
}
.container.click {
flex-direction: row;
justify-content: space-around;
}
h1 {
margin-left: 5vw;
color: black;
font-family: "Poller One", cursive;
font-variant: small-caps;
font-size: 3rem;
margin-top: 6vh;
}
button {
color: white;
transition: 0.25s;
float: left;
margin: 2%;
}
button:hover,
button:focus {
border: 2px solid red;
color: black;
}
.fill {
height: 120px;
width: 150px;
background: transparent;
margin-top: 4vh;
outline: none;
border: none;
}
.fill:hover,
.fill:focus {
box-shadow: inset 0 0 0 4.5em #add8e6;
}
.sith:hover,
.sith:focus {
box-shadow: inset 0 0 0 4.5em black;
}
#buttons {
height: 100%;
width: 100vw;
padding-top: 10vh;
display: flex;
justify-content: center;
}
JS
document.querySelector("button").addEventListener("click", () => {
document.querySelector(".container").classList.toggle(".container.click");
});
There are a couple of changes you need to make to get this to work:
1. document.querySelector("button") is only selecting the first button. There are 2 you can add an event listener to the buttons
use document.querySelectorAll("button") to get all the buttons, and then you can loop through them adding an event Listener to each one:
document.querySelectorAll("button").forEach(function(button) {
button.addEventListener("click", () => {
document.querySelector(".container").classList.toggle("click");
});
});
A better way is to add an event listener to the buttons container - you can get the element using getElementById and then add the listener to it:
var buttons = document.getElementById("buttons");
buttons.addEventListener("click", (e) => {
document.querySelector(".container").classList.toggle("click");
});
2. You just use the class name when passing a class into toggle- you don't need the .. Also, you only need to toggle the click class as the container class will always apply. So what you need to use is .toggle("click");
Working Example (without your images):
var buttons = document.getElementById("buttons");
buttons.addEventListener("click", (e) => {
document.querySelector(".container").classList.toggle("click");
});
.container {
width: 100vw;
display: flex;
flex-direction: column;
align-items: center;
}
.container.click {
flex-direction: row;
justify-content: space-around;
}
h1 {
margin-left: 5vw;
color: black;
font-family: "Poller One", cursive;
font-variant: small-caps;
font-size: 3rem;
margin-top: 6vh;
}
button {
color: red;
transition: 0.25s;
float: left;
margin: 2%;
}
button:hover,
button:focus {
border: 2px solid red;
color: black;
}
.fill {
height: 120px;
width: 150px;
background: transparent;
margin-top: 4vh;
outline: none;
border: none;
}
.fill:hover,
.fill:focus {
box-shadow: inset 0 0 0 4.5em #add8e6;
}
.sith:hover,
.sith:focus {
box-shadow: inset 0 0 0 4.5em black;
}
#buttons {
height: 100%;
width: 100vw;
padding-top: 10vh;
display: flex;
justify-content: center;
}
<header>
<div class="container">
<h1>Choose Your Allegiance</h1>
<div id="buttons">
<button class="fill">Jedi</button>
<button class="fill sith">Sith</button>
</div>
</div>
</header>
As for animating this change, unfortunately CSS animations cannot be applied to flexbox direction property.
You are using classList.toggle wrong. You'll need to do this instead:
const container = document.querySelector(".container");
container.classList.toggle("click");
Documentation on Element.classList here.

Categories