Style adjustments in a reactJS dropdown Menu - javascript

I'm currently building a ReactJS App, and I needed to implement a dropdown menu.
I currently have the menu built, but I need help for two elements :
The style of the menu
The position of the menu
1 - Style of the menu
The menu looks like that :
But when I hoover the menu, there is a gap between the hovering of a link and the link itselfs.
For example :
Here I hoover 'Rename', but styling come under it...
2 - Position of the menu
Simple question : How can I choose myself the position of the menu in my page ?
Neither relative to the parent element nor in a fixed page position ?
Here are my source codes :
VerticalDots.js
import React from "react";
import "./VerticalDots.css";
export default class VerticalDots extends React.Component {
state = {
status: false,
elements: [
"Rename",
"Duplicate",
"Archive",
"Delete Permanently"
]
}
buttonClick = (e, curstat) => {
e.stopPropagation();
this.setState({ status: curstat });
};
displayElements(){
if(this.state.status){
return(
<div className="show-options">
{this.state.elements.map((value, key) => {
return (
<div className="data-row">{value}</div>
);
})}
</div>
);
}
}
render() {
return (
<div className="dropdown-root">
<div className="text-box">
<div className="button" onClick={e => this.buttonClick(e, !this.state.status)}>
<img src={require("../imgs/3dots-vertical.png")} alt="NotFound"/>
</div>
{this.displayElements()}
</div>
</div>
);
}
}
VerticalDots.css
.text-box {
width: 100px;
height: 40px;
position: relative;
text-align: left;
}
.button {
text-align: right;
font-size: 13px;
}
.show-options {
height: 110px;
width: 150px;
border: 1px solid #7A7A7A;
border-radius: 4px;
position: relative;
background: #EBEBEB;
cursor: pointer;
overflow-y: scroll;
overflow-x: hidden;
z-index: 1;
}
.data-row {
height: 20px;
text-align: left;
/* margin: 0px 10px 0px 10px; */
color: #25073C;
border-radius: 4px;
}
.data-row:hover {
background-color: #1464F6;
color: white;
}
.drop-text {
margin-top: 10px;
margin-left: 5px;
position: absolute;
}
.column9:hover{
background-color: red;
}

https://codesandbox.io/s/cool-engelbart-tuz4y
I couldn't recreate your first issue, can you please clarify further on what's happening on your end? It might be that you have other styles included that are causing that issue.
Regarding issue number 2, normal css rules apply to .show-options which is a child of .text-box. I am not sure how you want to position it, but one suggestion would be to use flex, something like:
.text-box {
height: auto;
display: flex;
flex-direction: column
}

I solved the problem, a hidden line-height was linked 3 branches above.
Thank you for your time !

Related

What changed in bootstrap 5 to make controls assume max size

I recently upgraded NodeJs to 16.13.0 from 14.x. One of the modules updated was bootstrap of course. I also had to get rid of my Jumbotron control because of the upgrade, but I don't think that's part of the issue I am having. I have quite a few <div> controls with the className marked as 'row'. However, after the upgrade, 'row' is being ignored and all other controls are on separate lines with max width set to container width.
For example, in the image you can see my Totals control shows Subtotal with the subtotal value on the next line. My Totals component:
import React from 'react';
import { GetTotal } from './CartHandler';
import { formatter } from '../common.js'
import "./Checkout.scss"
export default function TotalsBlock(props) {
let carttotal = GetTotal();
let shipping = 10.57;
let taxes = 4.93;
return (
<aside id="checkout" className="block col-1">
<h1>Total</h1>
<div className="row">
<label>Subtotal</label>
<label>{formatter.format(carttotal)}</label>
</div>
<div className="row">
<label>Shipping</label>
<label>{formatter.format(shipping)}</label>
</div>
<div className="row">
<label>Taxes</label>
<label>{formatter.format(taxes)}</label>
</div>
<hr/>
<div className="row">
<label>Total</label>
<label>{formatter.format(carttotal + shipping + taxes)}</label>
</div>
</aside>
);
}
... and Checkout.scss:
#checkout {
.row {
display: flex;
align-items: stretch;
justify-content: space-between;
margin-right: 0;
margin-left: 0;
font-size: 12px;
}
h1 {
font-size: 1rem;
font-weight: bold;
}
.col-1 {
flex: 1;
max-width: 33%;
}
.col-2 {
flex: 2;
max-width: 66%;
}
.header {
background-color: cornflowerblue;
color: white;
}
.block {
background-color: lightgray;
padding: 1rem;
margin: 0.5rem;
border-radius: 0.5rem;
}
.table-wrapper {
max-height: 200px;
overflow: auto;
}
th.price, th.quantity {
width: 10%;
}
.table-extra {
}
}
What changed in bootstrap 5 to not make 'row' work and why are my elements max size? I think these are both the same actual problem. Any help will be appreciated.
UPDATE
When I inspect with the Browser's DevTools .row width is set to 100%. I can uncheck it or set width to auto everything goes back to normal. However, I put width: auto in .row in the Checkout.scss it gets set to 100% anyway...
Not the best way I suppose...
I added:
.row > * {
width: auto;
}
...to Checkout.scss to overwrite bootstrap. I am all ears if anyone has a better Solution.

How to customize a div's scroll bar with css modules?

I'm trying to customize a div component's scroll bar like this :
Home.js
import classes from "./Home.module.scss";
function Home() {
return (
<div className={classes.scroll}>
<p>jasbdkajsdb</p>
<p>jasbdkajsdb</p>
<p>jasbdkajsdb</p>
<p>jasbdkajsdb</p>
<p>jasbdkajsdb</p>
</div>
);
}
Home.module.scss
.scroll {
&:-webkit-scrollbar {
width: 20px;
}
&:-webkit-scrollbar-thumb {
background: red;
border-radius: 25px;
}
&::-webkit-scrollbar-track {
background-color: red;
}
}
But the css doesn't apply . How can I customize a div's scrollbar ?
You are missing a colon on two of your selectors try this:
Home.module.scss
.scroll {
&::-webkit-scrollbar {
width: 5px;
}
&::-webkit-scrollbar-thumb {
background: red;
border-radius: 25px;
}
&::-webkit-scrollbar-track {
background-color: red;
}
}
See the full list of scrollbar pseudo-element selectors

jQuery/JavaScript if statement for two toggles

I have two toggles (toggle-1 and toggle-2) with different contents in a header. I would like to prevent the user to have both toggles active simultaneously (otherwise they overlap).
In the code below I tried to use if statements to hide one of the toggles if the other is already opened but it does not work.
Ideally, what I would like to happen is that if toggle-1 is active and the user clicks on toggle-2, then toggle-1 would come back to its original state and toggle-2 would be now active. The same the other way around.
I am not familiar with JavaScript yet and I'd really appreciate if you could tell me what I have done wrong and how it should be done to have my ideal result
Here's the link to my CodePen if you find it easier:
https://codepen.io/fergos2/pen/NWWxgEp
var myToggle
var oneToggle = $(document).ready(function() {
$('.toggle-1').click(function() {
$('.toggle-1').toggleClass('active')
$('.toggle-1-content').toggleClass('active')
})
})
var twoToggle = $(document).ready(function() {
$('.toggle-2').click(function() {
$('.toggle-2').toggleClass('active')
$('.toggle-2-content').toggleClass('active')
})
})
if (myToggle == oneToggle) {
$(document).ready(function() {
$('toggle-2-content').hide();
})
} else if (myToggle == twoToggle) {
$('toggle-1-content').hide();
}
.container {
width: 100%;
height: 1000px;
margin: 0 auto;
background-color: #eee;
}
.wrapper {
background-color: pink;
position: relative;
display: flex;
align-items: center;
}
.toggle-1,
.toggle-2 {
display: block;
width: 20px;
height: 20px;
float: left;
cursor: pointer;
color: white;
text-align: center;
background-color: green;
margin: 10px;
}
.toggle-1.active,
.toggle-2.active {
background-color: red;
}
.toggle-1-content,
.toggle-2-content {
display: none;
}
.toggle-1-content.active,
.toggle-2-content.active {
display: block;
background-color: white;
border: 1px solid black;
position: absolute;
top: 40px;
}
.toggle-1-content.active {
left: 0;
}
.toggle-2-content.active {
left: 50px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="container">
<div class="wrapper">
<div class="toggle-1">1</div>
<div class="toggle-1-content">
<p>Some content 1</p>
</div>
<div class="toggle-2">2</div>
<div class="toggle-2-content">
<p>Some content 2</p>
</div>
</div>
</div>
Several issues.
Please study the code below
too many $(document.ready... and no need to store the result of such a statement
Using a data-attribute and a common class, shortens the code a lot. DRY Don't repeat yourself
I simplified the content containers CSS too
$(function() { // on page load
$('.toggle').on("click", function() { // any of the toggles
const $wrapper = $(this).closest(".wrapper");
const id = $(this).data("id");
$(this).toggleClass('active'); // toggle clicked div
const show = $(this).is(".active"); // is it active after we toggled?
$wrapper
.find(".toggle") // find all toggles
.not(this) // exclude the one we clicked
.removeClass("active"); // remove class
$wrapper.find(".content").hide(); // hide any content divs
$("#" + id).toggle(show); // show the one belonging to the clicked toggle
})
})
.container {
width: 100%;
height: 1000px;
margin: 0 auto;
background-color: #eee;
}
.wrapper {
background-color: pink;
position: relative;
display: flex;
align-items: center;
}
.toggle {
display: block;
width: 20px;
height: 20px;
float: left;
cursor: pointer;
color: white;
text-align: center;
background-color: green;
margin: 10px;
}
.active {
background-color: red;
}
.content {
display: none;
background-color: white;
border: 1px solid black;
position: absolute;
top: 40px;
}
#div1 {
left: 0;
}
#div2 {
left: 50px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="container">
<div class="wrapper">
<div class="toggle" data-id="div1">1</div>
<div id="div1" class="content">
<p>Some content 1</p>
</div>
<div class="toggle" data-id="div2">2</div>
<div id="div2" class="content">
<p>Some content 2</p>
</div>
</div>
</div>
Working code:
$(document).ready(function() {
$('.toggle-1').click(function() {
if ($('.toggle-2').hasClass('active')) {
// remove toggle-2 active classes
$('.toggle-2').removeClass('active');
$('.toggle-2-content').removeClass('active');
}
$('.toggle-1').toggleClass('active');
$('.toggle-1-content').toggleClass('active');
});
$('.toggle-2').click(function() {
if ($('.toggle-1').hasClass('active')) {
// remove toggle-1 active classes
$('.toggle-1').removeClass('active');
$('.toggle-1-content').removeClass('active');
}
$('.toggle-2').toggleClass('active');
$('.toggle-2-content').toggleClass('active');
});
});
Here is the link to my working version.
A few things to keep in mind:
You don't need to call $(document).ready() multiple times. There's just no reason to call it multiple times on a single page as the event is only fired once.
You need to keep track of state somehow; hence the if ($('el').hasClass('classname')) syntax. Once you handle that properly, it's easy to ensure that each element is 'reset' to its original state when the other is clicked.
Hope that helps!
toggleClass accepts a second boolean parameter that forces the type of toggle, on or off. More than that you can also target multiple elements with a single jQuery call, so use that to your advantage since the classes applied have the same name.
So you could simplify your code to
$(document).ready(function() {
$('.toggle-1').click(function() {
$('.toggle-1, .toggle-1-content').toggleClass('active');
$('.toggle-2, .toggle-2-content').toggleClass('active', false)
})
$('.toggle-2').click(function() {
$('.toggle-2, .toggle-2-content').toggleClass('active');
$('.toggle-1, .toggle-1-content').toggleClass('active', false)
})
})
.container {
width: 100%;
height: 1000px;
margin: 0 auto;
background-color: #eee;
}
.wrapper {
background-color: pink;
position: relative;
display: flex;
align-items: center;
}
.toggle-1,
.toggle-2 {
display: block;
width: 20px;
height: 20px;
float: left;
cursor: pointer;
color: white;
text-align: center;
background-color: green;
margin: 10px;
}
.toggle-1.active,
.toggle-2.active {
background-color: red;
}
.toggle-1-content,
.toggle-2-content {
display: none;
}
.toggle-1-content.active,
.toggle-2-content.active {
display: block;
background-color: white;
border: 1px solid black;
position: absolute;
top: 40px;
}
.toggle-1-content.active {
left: 0;
}
.toggle-2-content.active {
left: 50px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="container">
<div class="wrapper">
<div class="toggle-1">1</div>
<div class="toggle-1-content">
<p>Some content 1</p>
</div>
<div class="toggle-2">2</div>
<div class="toggle-2-content">
<p>Some content 2</p>
</div>
</div>
</div>
You can use the method "removeClass" to remove the active class from the other toggle
var oneToggle = $(document).ready(function() {
$(".toggle-1").click(function() {
$(".toggle-1").toggleClass("active")
$(".toggle-1-content").toggleClass("active")
$(".toggle-2").removeClass("active")
$(".toggle-2-content").removeClass("active")
})
})
var twoToggle = $(document).ready(function() {
$(".toggle-2").click(function() {
$(".toggle-1").removeClass("active")
$(".toggle-1-content").removeClass("active")
$(".toggle-2").toggleClass("active")
$(".toggle-2-content").toggleClass("active")
})
})

How to stack cards for Solitaire?

Trying to do this project on my own running into some slight issues. I have decided to cut the card with overflow so that I can stack but the stack isn't exactly working. The goal is to get the cards to stack together more. I have attached a picture along with code for the css portion and code for the react portion, I pretty much use that same code in a component and call that component seven times to get all 7 columns. I have the functionality that loads the cards into the game. I have also included details concerning the steps I have tried from other articles that were similar to my question.
Here is my css code :
body {
background: #339900;
}
.container {
width: 1700px;
border: 1px solid blue;
}
span {
display: block;
}
.outline {
text-align: center;
background: #FFF;
color: #cc0033;
border: 1px solid black;
}
.scene {
width: 120px;
height: 180px;
perspective: 360px;
}
.top{
text-align: left;
}
.bottom{
text-align: right;
}
.topRow{
display: flex;
}
.drawPile {
display: flex;
margin-right: 300px;
width: 500px;
}
.finalStack {
width: 900px;
display: flex;
justify-content: space-between;
}
.bottomRow {
display: flex;
justify-content: space-between;
margin-top: 100px;
}
.drawFrom {
display: flex;
justify-content: center;
text-align: center;
align-content: center;
background: blue;
}
.black {
color: black;
}
.red {
color: red;
}
.deck {
display: flex;
height: 200px;
flex-direction: column;
}
.card {
flex: 100px 1 0;
border: solid 1px black;
border-radius: 5px;
background-color: white;
box-shadow: 3px 3px 3px gray;
width: 120px;
height: 180px;
}
.stackedCards {
max-height: 50px;
overflow: hidden;
}
.lastInStack {
overflow: auto;
}
Not sure if this is needed but I will post the code for each section. I am doing this in react.
render() {
console.log("BottomSection");
console.log(this.props);
const cards = this.props.cards;
console.log(cards);
return (
<div>
{cards.map((card, id) => (
<div key = {id} className="deck">
<div onClick = {this.clickingCard} draggable = "true" className = { id === this.props.cards.length -1 ? "card lastInStack outline scene column" : "card stackedCards outline scene column"}>
<div className={"top " + card.color}>
<span>{card.value}</span>{" "}
{card.suit === "hearts" ? (
<span>♥</span>
) : card.suit === "spades" ? (
<span>♠</span>
) : card.suit === "clubs" ? (
<span>♣</span>
) : (
<span>♦</span>
)}
</div>
{card.suit === "hearts" ? (
<h1 className={card.color}>♥</h1>
) : card.suit === "spades" ? (
<h1 className={card.color}>♠</h1>
) : card.suit === "clubs" ? (
<h1 className={card.color}>♣</h1>
) : (
<h1 className={card.color}>♦</h1>
)}
<div className={"bottom " + card.color}>
{card.suit === "hearts" ? (
<span>♥</span>
) : card.suit === "spades" ? (
<span>♠</span>
) : card.suit === "clubs" ? (
<span>♣</span>
) : (
<span>♦</span>
)}
<span>{card.value}</span>
{/* <hr/> */}
</div>
</div>
</div>
))}
</div>
);
}
Okay, so the idea here is to stack the cards up so that they are connected with no green space between the cards. I will have to turn the cards over or have a back side but right now I am just trying to stack the cards. I will worry about the backside and clicking a card to reveal its other side once I actually get everything to stack up correctly. I have tried to use margin-bottom at a negative amount however this seems to only stretch the card itself and make it longer. Not sure if this is because of the way I am creating each individual card instead of using images. I also tried using negative top and position relative as one of the articles recommended but didn't see a change. The other articles didn't seem to apply to my implementation.
.deck {
display: flex;
flex-direction: column;
}
.lastInstack {
/*leave blank no need for overflow*/
}
This is the solution to the way I implemented the code. The changes were looked into by Peter Ambruzs as well. The reason why it was not working is that of the height set on deck it separated each div by the height. Removing the height removes the separation.

How to keep flex element's width after removing contents?

I have this flexible layout and some JS https://jsfiddle.net/7k8t3xgc/3/
<div class="window">
<div class="left">
<div class="optional">optional content</div>
</div>
<div class="right">
<div class="wordpool"></div>
<div class="category"></div>
</div>
</div>
The .wordpool element is filled with some words that need to be moved to the .category element by clicking on them.
What is happening now, is that the .window element is shrinking in width when you click the words. Is there a way to prevent this behaviour? Only way I can think of is to calculate wordpools width on render and set it into a style attribute, but it has its drawbacks with responsiveness.
I can't remove the flex functionality, because both left (optional) and right panels need to be same width and centered.
I can't use static width as it needs to be responsive.
It can't be something like .window { width: 90%; } because of short content looking silly on wide screens.
Both left and right content changes between pages in my app (think of a quiz or Google Forms - can be text, can be images, checkboxes, radiobuttons etc.) but the HTML template is the same.
As you want it to be dynamic, based on the actual text width on load, add this line to your script
$(".window").css('min-width', $(".window").width() + 'px');
Updated fiddle
Instead of monitoring the resize event for smaller screens, you can do like this instead
Note, the width: 100% needs to be set using the script, if set in CSS, the calculation will be wrong
$(".window").css({'max-width':$(".window").width() + 'px','width':'100%'});
Updated fiddle 2
Just to provide another solution, that may or not be what you want:
Don't change the elements from container, just have them on both containers, and toggle the opacity.
You can rearrange them using flexbox and order
var buttons = [{
name: "lorem"
},
{
name: "ipsum"
},
{
name: "dolor"
},
{
name: "sit"
},
{
name: "amet"
}
];
$(document).ready(function() {
for (b of buttons) {
$('.wordpool').append($("<span>", {
class: "word",
id: b.name
}).html(b.name));
$('.category').append($("<span>", {
class: "word hidden",
id: b.name
}).html(b.name));
}
$(".wordpool").on("click", "span", function() {
$(this).toggleClass('hidden');
$(".category #" + $(this).attr('id')).toggleClass('hidden');
});
$(".category").on("click", "span", function() {
$(this).toggleClass('hidden');
$(".wordpool #" + $(this).attr('id')).toggleClass('hidden');
});
$("body").on("click", ".showoptional", function() {
$(".left").toggle();
});
});
html,
body {
height: 100%;
margin: 0;
}
.wrapper {
box-sizing: border-box;
width: 100%;
height: 100%;
padding: 20px;
display: flex;
justify-content: center;
align-items: center;
background: #f4efdc;
}
.showoptional {
position: absolute;
top: 5px;
left: 5px;
}
.window {
background: #fff;
box-shadow: 0 0 10px #ccc;
display: flex;
}
.left,
.right {
padding: 20px;
flex: 1 0 0px;
}
.left {
display: none;
}
.optional {
background: #eee;
text-align: center;
padding: 50px 0;
}
.word {
display: inline-block;
margin: 2px 5px;
padding: 3px 5px;
border: 1px solid #ddd;
cursor: pointer;
}
.hidden {
opacity: 0;
order: 99;
}
.wordpool {
text-align: center;
display: flex;
}
.category {
margin-top: 10px;
border: 1px solid #ccc;
min-height: 60px;
}
.category .word {
display: block;
text-align: center;
margin: 2px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="wrapper">
<input type="button" class="showoptional" value="Trigger optional content" />
<div class="window">
<div class="left">
<div class="optional">optional content</div>
</div>
<div class="right">
<div class="wordpool"></div>
<div class="category"></div>
</div>
</div>
</div>

Categories

Resources