My function runs only once - javascript

I want my button to make text in textarea cut to the clipboard and
the button rotates simultaneously each time I click it. I got it to
work, however it only rotates once, next time I click it, it'll cut
the text but button will not rotate.
HTML
my button and textarea
<div class="box-2-wrap">
<textarea class="out-put"></textarea>
<button type="button" id="copyEmailsButton" onclick="copyEmails()">Copy Emails</button>
</div>
CSS
my stylesheet
.box-2-wrap {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
border: 0px solid #333;
}
.box-2-wrap textarea {
flex:1;
padding: 4%;
overflow-y: auto;
background-color: #333;
color: gold;
max-width: 100%;
min-width: 100%;
font-size: 110%;
border: none;
border-radius: 8px;
}
.box-2-wrap button {
align-items: flex-end;
justify-content: center;
padding: 10px 2%;
width: 50%;
margin: 6% auto;
background-color: #178E44;
color: white;
font-size: 120%;
border: none;
border-radius: 4px;
}
#keyframes rotate {
0% {
transform: rotate(0deg);
}
50% {
transform: rotate(360deg);
}
100% {
transform: rotate(0deg);
}
}
JS
my JavaScript
function unSelectAll(){
var output = document.getElementsByClassName("out-put")[0];
output.innerHTML = "";
}
}
function copyEmails(){
var output = document.getElementsByClassName("out-put")[0];
output.select();
document.execCommand('copy');
unSelectAll();
var copyEmailsButton = document.getElementById("copyEmailsButton");
if (copyEmailsButton.style.animation !== "rotate 1s") {
copyEmailsButton.style.animation = "rotate 1s";
}else{
copyEmailsButton.style.animation = "none";
}
}

In the if-else block in copyEmails you specify, that the button will rotate for one second, if the animation-style isn't set "to rotate 1s". But if it is, it will just set the animation-style to none.
If you click on the button a third time, you will notife, that it will rotate again. This is because with the 2nd click, you have set the animation Style to none again.
This means, your Button will switch and rotate every 2nd click!
To let the button rotate everytime you click, change the if-else block to:
copyEmailsButton.style.animation = "rotate 1s";
setTimeout(function() {
copyEmailsButton.style.animation = "none"
}, 1000);
This sets the animation style to none again after the animation is finished, every time you click the button.

1 there is an error in your unselctAll function, one extra close } should be removed
2 reset the button style before next click, as in this example below
function unSelectAll(){
var output = document.getElementsByClassName("out-put")[0];
output.innerHTML = "";
}
function copyEmails(){
var output = document.getElementsByClassName("out-put")[0];
output.select();
document.execCommand('copy');
unSelectAll();
var copyEmailsButton = document.getElementById("copyEmailsButton");
if (copyEmailsButton.style.animation !== "rotate 1s") {
copyEmailsButton.style.animation = "rotate 1s";
}else{
copyEmailsButton.style.animation = "none";
}
}
.box-2-wrap {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
border: 0px solid #333;
}
.box-2-wrap textarea {
flex:1;
padding: 4%;
overflow-y: auto;
background-color: #333;
color: gold;
max-width: 100%;
min-width: 100%;
font-size: 110%;
border: none;
border-radius: 8px;
}
.box-2-wrap button {
align-items: flex-end;
justify-content: center;
padding: 10px 2%;
width: 50%;
margin: 6% auto;
background-color: #178E44;
color: white;
font-size: 120%;
border: none;
border-radius: 4px;
}
#keyframes rotate {
0% {
transform: rotate(0deg);
}
50% {
transform: rotate(360deg);
}
100% {
transform: rotate(0deg);
}
}
<textarea class="out-put" onmouseover="copyEmailsButton.style.animation = 'none';" placeholder="always click here before clicking the button"></textarea>
<button type="button" id="copyEmailsButton" onclick="copyEmails()">Copy Emails</button>
</div>

Related

are querySelectorAll and getBoundingClientRect compatible?

I'm a very unexperienced developer. and I'm struggling to find a solution. I have two buttons with the same class, and a div called cursorFollower that actually follows the actual pageX and pageY positioning. Last week, and thanks to some people help I managed to change the cursorFollower shape based on the button it was hovering. the thing is that I can't manage to make it work with all buttons with same class. Someone suggested me to change it from querySelector to querySelectorAll to select all elements with the same class, but how to know which one is hovering at a time? Also for some reason while working on codepen it keeps saying that getBoundingClientRect should be now within a function, it was getting the size and positioning of the button as individual variables. I've included everything within a function but nothing is happening. Can someone tell me what I'm doing wrong and suggest me what to do instead?
let cursor = document.querySelector('.cursorFollower');
let button = document.querySelector('.menutext');
let buttonWidth = button.getBoundingClientRect().width;
let buttonHeight = button.getBoundingClientRect().height;
let buttonX = button.getBoundingClientRect().left;
let buttonY = button.getBoundingClientRect().top;
var onContainer = false;
const handleCursor = (e) => {
if (onContainer) {
cursor.setAttribute(
"style",
`left: ${buttonX}px;top: ${buttonY}px;width: ${buttonWidth}px;height: ${buttonHeight}px; transform: rotate(0deg); border: 1px solid #84c4b5;`
);
button.setAttribute(
"style",
`color: #84C4B5;`
);
} else {
cursor.setAttribute(
"style",
`left: width: 20px; height: 20px; transform: rotate(45deg); border: solid 1px #ffffff;`
);
cursor.style.left = e.pageX - 10 + 'px';
cursor.style.top = e.pageY - 10 + 'px';
button.setAttribute(
"style",
`color: #ffffff;`
);
}
};
document.addEventListener("mousemove", handleCursor);
button.onmouseover = () => {
onContainer = true;
};
button.onmouseleave = () => {
onContainer = false;
};
*{
margin: 0;
padding: 0;
}
.container {
position: relative;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
width:100%;
height: 100vh;
background-color: #0A193E;
color: white;
font-family: sans-serif;
font-size: 20px;
}
.container2 {
position: relative;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
width:100%;
height: 100vh;
background-color: green;
color: white;
font-family: sans-serif;
font-size: 20px;
}
.menutext {
padding: 10px 20px;
cursor: none;
transition: all 0.2s ease;
}
.cursorFollower {
width: 20px;
height: 20px;
position: absolute;
border: 2px solid white;
transition: all 0.2s ease-out;
pointer-events: none;
transform: rotate(45deg);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="container">
<p class="menutext">button1</p>
<p class="menutext">button2</p>
</div>
<div class="container2">
<p class="menutext">button3</p>
</div>
<div class="cursorFollower"></div>
The easiest thing to do is do away with the button mouseover/out handler altogether, and handle this all within the handleCursor function. If the event target has the class menutext apply your effect, although note you'll need to offset the cursors y position by the window.scrollY value:
let cursor = document.querySelector('.cursorFollower');
const handleCursor = (e) => {
var button = e.target;
if (button.classList.contains("menutext")) {
const boundingRect = button.getBoundingClientRect();
let buttonWidth = boundingRect.width;
let buttonHeight = boundingRect.height;
let buttonX = boundingRect.left;
let buttonY = window.scrollY + boundingRect.top;
cursor.setAttribute(
"style",
`left: ${buttonX}px;top: ${buttonY}px;width: ${buttonWidth}px;height: ${buttonHeight}px; transform: rotate(0deg); border: 1px solid #84c4b5;`
);
button.setAttribute(
"style",
`color: #84C4B5;`
);
} else {
cursor.setAttribute(
"style",
`left: width: 20px; height: 20px; transform: rotate(45deg); border: solid 1px #ffffff;`
);
cursor.style.left = e.pageX - 10 + 'px';
cursor.style.top = e.pageY - 10 + 'px';
button.setAttribute(
"style",
`color: #ffffff;`
);
}
};
document.addEventListener("mousemove", handleCursor);
*{
margin: 0;
padding: 0;
}
.container {
position: relative;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
width:100%;
height: 100vh;
background-color: #0A193E;
color: white;
font-family: sans-serif;
font-size: 20px;
}
.container2 {
position: relative;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
width:100%;
height: 100vh;
background-color: green;
color: white;
font-family: sans-serif;
font-size: 20px;
}
.menutext {
padding: 10px 20px;
cursor: none;
transition: all 0.2s ease;
}
.cursorFollower {
width: 20px;
height: 20px;
position: absolute;
border: 2px solid white;
transition: all 0.2s ease-out;
pointer-events: none;
transform: rotate(45deg);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="container">
<p class="menutext">button1</p>
<p class="menutext">button2</p>
</div>
<div class="container2">
<p class="menutext">button3</p>
</div>
<div class="cursorFollower"></div>

Javascript refactoring help needed

I have an image toggle triggered by button clicks and checkboxes. My code is currently working how I need it to, but I'm very new to JavaScript so I'm sure there is a cleaner way to do this.
A few notes:
This is for a client, so for confidentiality reasons, I cannot share the actual images, but the alt tags should tell the story.
I'm not allowed to use anything other than vanilla JS on the platform this will live, and all variables and functions have to have custom names, hence the funky naming.
var csDMU_checkbox = document.getElementById("csDMU_checkbox");
var csDMU_imageBefore = document.getElementById("before-image");
var csDMU_imageAfter = document.getElementById("after-image");
var csDMU_imageCombo = document.getElementById("combo-image");
var csDMU_switch = document.getElementById("switch");
var csDMU_toggle = document.getElementById("toggle");
function csDMU_toggleImage() {
if (csDMU_checkbox.checked == true) {
csDMU_imageBefore.style.display = "none";
csDMU_imageAfter.style.display = "block";
csDMU_imageCombo.style.display = "none";
} else {
csDMU_imageBefore.style.display = "block";
csDMU_imageAfter.style.display = "none";
csDMU_imageCombo.style.display = "none";
}
}
function csDMU_comboView() {
csDMU_imageCombo.style.display = "block";
csDMU_imageBefore.style.display = "none";
csDMU_imageAfter.style.display = "none";
csDMU_switch.style.display = "none";
csDMU_toggle.style.display = "block";
}
function csDMU_toggleView() {
csDMU_switch.style.display = "block";
csDMU_toggle.style.display = "none";
csDMU_imageBefore.style.display = "block";
csDMU_imageCombo.style.display = "none";
}
#import url('https://fonts.googleapis.com/css2?family=Libre+Franklin:ital,wght#0,400;0,700;1,400;1,700&display=swap');
body {
font-family: 'Libre Franklin', sans-serif;
}
.flexRow {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
}
/* The switch - the box around the slider */
.switch {
position: relative;
display: inline-block;
width: 119px;
height: 40px;
}
/* Hide default HTML checkbox */
.switch input {
opacity: 0;
width: 0;
height: 0;
}
/* The slider */
.slider {
position: absolute;
cursor: pointer;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: #243b43;
-webkit-transition: .4s;
transition: .4s;
}
.slider:before {
position: absolute;
content: "";
height: 32px;
width: 33px;
right: 4px;
bottom: 3px;
background: transparent -webkit-gradient(linear, left top, left bottom, from(#FFFFFF), color-stop(47%, #EDEDED), color-stop(73%, #D0D0D0), to(#E5E5E5)) 0% 0% no-repeat padding-box;
background: transparent linear-gradient(180deg, #FFFFFF 0%, #EDEDED 47%, #D0D0D0 73%, #E5E5E5 100%) 0% 0% no-repeat padding-box;
-webkit-box-shadow: 0px 3px 6px #00000029;
box-shadow: 0px 3px 6px #00000029;
border: 1px solid #FFFFFF;
-webkit-transition: .4s;
transition: .4s;
}
.slider:after {
content: "BEFORE";
display: block;
font-size: 14px;
line-height: 14px;
letter-spacing: 0.16px;
font-weight: bold;
color: #FFF;
position: relative;
top: 13px;
left: 10px;
}
input:checked + .slider {
background-color: #F26322;
}
input:focus + .slider {
-webkit-box-shadow: 0 0 1px #2196F3;
box-shadow: 0 0 1px #2196F3;
}
input:checked + .slider:before {
-webkit-transform: translateX(-75px);
transform: translateX(-75px);
}
input:checked + .slider:after {
content:'AFTER';
left: 50px;
}
/* Rounded sliders */
.slider.round {
border-radius: 34px;
}
.slider.round:before {
border-radius: 50%;
}
.combo-button,
.toggle-button{
width: 172px;
height: 40px;
margin-left: 20px;
border-radius: 100px;
border: 1px solid #C4C4C4;
color: #4a4b4d;
letter-spacing: 0.16px;
}
.combo-button:hover,
.combo-button:focus {
background-color: #002D5E;
color: #FFF;
}
.combo-button:focus {
outline: 0;
}
.toggle-button {
display: none;
width: 119px;
margin: 0;
}
.hand-img {
max-width: 700px;
margin-right: -20px;
display: block;
}
#after-image,
#combo-image {
display: none;
}
<html>
<body>
<div id="image-change">
<img src="" alt="before image" class="hand-img" id="before-image" />
<img src="" alt="after image" class="hand-img" id="after-image" />
<img src="" alt="combo image" class="hand-img" id="combo-image" />
</div>
<div class="flexRow">
<label class="switch" id="switch">
<input type="checkbox" id="csDMU_checkbox" onclick="csDMU_toggleImage()">
<span class="slider round"></span>
</label>
<button class="toggle-button" id="toggle" onclick="csDMU_toggleView()">TOGGLE VIEW</button>
<button class="combo-button" onclick="csDMU_comboView()">COMPARISON</button>
</div>
</body>
</html>
Well you could minimize your JS code by first selecting all the elements using one line selector, note that you need to write the selected elements in their order in HTML to get them right because we're destructuring the returned node list into variables so the order matters because it's an array and not an object, then you are writing repeatedly element.style.display = "some value" so you can write a function to do that using an array of elements as input and their display value to set as two arrays and just loop over the first array of the elements and assign the correct CSS display value according to the index, and use a ternary expression instead of If-Else statement too write less code, here is the full JS code
let [csDMU_imageBefore, csDMU_imageAfter, csDMU_imageCombo, csDMU_switch, csDMU_checkbox, csDMU_toggle] = document.querySelectorAll("#before-image, #after-image, #combo-image, #switch, #csDMU_checkbox, #toggle");
const setCssDisplay = (elements, values) => elements.forEach((element, index) => element.style.display = values[index]);
function csDMU_toggleImage() {
setCssDisplay([csDMU_imageBefore, csDMU_imageAfter, csDMU_imageCombo], csDMU_checkbox.checked ? ["none", "block", "none"] : ["block", "none", "none"]);
}
function csDMU_comboView() {
setCssDisplay([csDMU_imageCombo, csDMU_imageBefore, csDMU_imageAfter, csDMU_switch, csDMU_toggle], ["block", "none", "none", "none", "block"]);
}
function csDMU_toggleView() {
setCssDisplay([csDMU_switch, csDMU_toggle, csDMU_imageBefore, csDMU_imageCombo], ["block", "none", "block", "none"]);
}

How can I use translateY to successive display elements one a time?

Ultimately, for each click of a button, I want to display an element that contains new content. In other words...
You read content contained within a parent container
To see the next item click the button
When the button is clicked, the old content shifts downward. The new content flows down from the top of the container. It pauses in order to read the new content.
To get new content, press the button again.
I'm unclear as to how to accomplish this, and if it's even possible with a CSS Animation. With what I have posted, it just takes both elements and translates them down the vertical axis at once. How can this be refactored so that one element pauses and displays it's content using just vanilla JavaScript?
var div1 = document.querySelector(".first");
var div2 = document.querySelector(".second");
var button = document.querySelector("button");
var divs = [div1, div2];
button.addEventListener("click", function(event) {
event.preventDefault();
for (var i = divs.length - 1; i > -1; i--) {
var div = divs[i];
div.classList.remove("down_shift");
void div.offsetWidth;
div.classList.add("down_shift");
}
});
body {
background: #222;
}
section {
width: 50vw;
height: 300px;
border: 5px solid red;
margin: 50px auto;
overflow: hidden;
}
.first, .second {
width: inherit;
height: 300px;
background: red;
transform: translateY(-300px);
}
.second {
background: pink;
}
h1 {
margin: 0;
padding-top: 50px;
text-align: center;
}
.down_shift {
animation: down 1s ease-out;
}
#keyframes down{
from {
transform: translateY(0);
}
to {
transform: translateY(300px);
}
}
<section>
<div class="first"><h1>1</h1></div>
<div class="second"><h1>2</h1></div>
</section>
<button type="button">Click</button>
You can add a wrapper to the elements, and animate the wrapper
var wrapper = document.querySelector(".wrapper");
var button = document.querySelector("button");
button.addEventListener("click", function(event) {
event.preventDefault();
wrapper.style.transform = 'translateY(-300px)'
});
body {
background: #222;
}
section {
width: 50vw;
height: 300px;
border: 5px solid red;
margin: 50px auto;
overflow: hidden;
}
.first, .second {
width: inherit;
height: 300px;
background: red;
/* transform: translateY(-300px); */
}
.second {
background: pink;
}
.wrapper {
transition: all 1s ease-out;
}
h1 {
margin: 0;
padding-top: 50px;
text-align: center;
}
.down_shift {
animation: down 1s ease-out;
}
#keyframes down{
from {
transform: translateY(0);
}
to {
transform: translateY(300px);
}
}
<section>
<div class="wrapper">
<div class="first"><h1>1</h1></div>
<div class="second"><h1>2</h1></div>
</div>
</section>
<button type="button">Click</button>

How can I make this transition smooth instead of it jumping up

I am trying to implement a notification system in my app without the use of a library. Here is a gif of the issue: https://imgur.com/oRc11dM
And here is the jsfiddle of the gif: https://jsfiddle.net/w9yk7n54/
When you click on new notification button, already displayed notifications jump up to make room for the new notification and new notification slides in. I was wondering how I could make it so that they all smoothly go up together.
The notifications wont all be the same dimensions so I cant set static values for height/etc.
Thank you!
let btn = document.querySelector('button')
let container = document.querySelector('.notifications-container')
let notif_contents = [
"<p>1</p><p>1</p><p>1</p><p>1</p>",
"<p>test</p>",
"<div><h1>testtesttest</h1><p>yoloalsdfasdf</p></div>"
]
let current = 0
btn.onclick = () => {
let notif = document.createElement('div')
notif.classList.add('notif')
notif.innerHTML = notif_contents[current]
notif.addEventListener('animationend', () => {
notif.parentElement.removeChild(notif)
})
current++
container.append(notif)
}
* {
box-sizing: border-box;
}
.container {
height: 300px;
width: 400px;
border: 1px solid black;
position: absolute;
}
.notifications-container {
position: absolute;
top: 0;
right: 0;
height: 100%;
width: 200px;
background: rgba( 0, 0, 0, 0.2);
display: flex;
flex-flow: column nowrap;
justify-content: flex-end;
overflow: hidden;
}
.notif {
position: relative;
width: 100%;
padding: 10px;
border: 1px solid black;
animation: notifAnim 5s forwards;
transition: all .2s;
background: white;
}
button {
z-index: 100;
background: lightcoral;
color: white;
border: none;
padding: 10px;
font-size: 20px;
margin: 5px;
}
#keyframes notifAnim {
0% {
transform: translateY( 100%)
}
20% {
transform: translateY( 0)
}
80% {
transform: translateY( 0)
}
100% {
transform: translateY( 100%)
}
}
<div class="container">
<button>New Notification</button>
<div class="notifications-container"></div>
</div>
Your notif container has justify-content: flex-end. This means that whenever you add a new one, the previous ones will be pushed up with the height of the new one.
The "fix" is to give each element a negative margin-top equal to its height and integrate in your current transition getting margin-top back to 0.
Example:
let btn = document.querySelector('button'),
container = document.querySelector('.notifications-container'),
notif_contents = [
"<p>1</p><p>1</p><p>1</p><p>1</p>",
"<p>test</p>",
"<div><h1>testtesttest</h1><p>yoloalsdfasdf</p></div>",
"<code>another.test()</code>",
"<strong>another</strong> <i>test</i>"
]
btn.onclick = () => {
let notif = document.createElement('div'),
index = Math.floor(Math.random() * notif_contents.length)
notif.classList.add('notif')
notif.innerHTML = notif_contents[index]
notif.addEventListener('animationend', () => {
notif.parentElement.removeChild(notif)
})
container.append(notif)
notif.style.marginTop = '-' + notif.offsetHeight + 'px'
}
* {
box-sizing: border-box;
}
.container {
height: 300px;
width: 400px;
border: 1px solid #888;
position: absolute;
}
.notifications-container {
position: absolute;
top: 0;
right: 0;
height: 100%;
width: 200px;
background: rgba( 0, 0, 0, 0.2);
display: flex;
flex-flow: column nowrap;
justify-content: flex-end;
overflow: hidden;
}
.notif {
position: relative;
width: 100%;
padding: 10px;
border: 1px solid #ddd;
border-bottom: none;
animation: notifAnim 5s forwards;
background: white;
}
button {
z-index: 100;
background: lightcoral;
color: white;
border: none;
padding: 10px;
font-size: 20px;
margin: 5px;
}
#keyframes notifAnim {
0%,
100% {
transform: translateY( 100%)
}
20%,
80% {
transform: translateY( 0);
margin-top: 0
}
}
<div class="container">
<button>New Notification</button>
<div class="notifications-container"></div>
</div>
An idea is to insert new element with a height equal to 0 and you animate the height in addition to translate. Of course, you should use max-height since height are unknown and we cannot animate to auto:
let btn = document.querySelector('button')
let container = document.querySelector('.notifications-container')
let notif_contents = [
"<p>1</p><p>1</p><p>1</p><p>1</p>",
"<p>test</p>",
"<div><h1>testtesttest</h1><p>yoloalsdfasdf</p></div>"
]
let current = 0
btn.onclick = () => {
let notif = document.createElement('div')
notif.classList.add('notif')
notif.innerHTML = notif_contents[current]
notif.addEventListener('animationend', () => {
notif.parentElement.removeChild(notif)
})
current++
container.append(notif)
}
* {
box-sizing: border-box;
}
.container {
height: 300px;
width: 400px;
border: 1px solid black;
position: absolute;
}
.notifications-container {
position: absolute;
top: 0;
right: 0;
height: 100%;
width: 200px;
background: rgba( 0, 0, 0, 0.2);
display: flex;
flex-flow: column nowrap;
justify-content: flex-end;
overflow: hidden;
}
.notif {
position: relative;
width: 100%;
padding:0 10px;
max-height:0px;
border: 1px solid black;
animation: notifAnim 5s forwards;
transition: all .2s;
background: white;
}
button {
z-index: 100;
background: lightcoral;
color: white;
border: none;
padding: 10px;
font-size: 20px;
margin: 5px;
}
#keyframes notifAnim {
0% {
transform: translateY( 100%);
max-height:0;
padding:0 10px;
}
30% {
transform: translateY( 0);
max-height:300px;
padding:10px;
}
80% {
transform: translateY( 0);
max-height:300px;
padding:10px;
}
100% {
transform: translateY( 100%);
max-height:300px;
padding:10px;
}
}
<div class="container">
<button>New Notification</button>
<div class="notifications-container"></div>
</div>

How do I make a button like the JoinVideoCallButton in Discord?

JoinVideoCallButton
Hi!
I simply wonder if anyone here have any idea how to make such a hover effect that could be used for such double option buttons or navbars etc.
I have the css and html code for it but I have no idea how to make the effect work. Also, I wonder if it is possible without the use of Jquery?
body {
background-size: 100%;
margin: 0px;
background-color: gray;
}
.joinVideoCallButton-2Pohj0 {
-ms-flex-align: center;
-ms-flex-pack: center;
-webkit-box-align: center;
-webkit-box-pack: center;
-webkit-box-sizing: border-box;
align-items: center;
background-color: #43b581;
border-radius: 3px;
box-sizing: border-box;
cursor: pointer;
display: -webkit-box;
display: -ms-flexbox;
display: flex;
height: 36px;
justify-content: center;
overflow: hidden;
padding: 0 14px;
position: relative;
}
.joinVideoCallButton-2Pohj0 .underlay-1LCk7B {
-webkit-transition: opacity .1s ease;
background-color: #69c49a;
border-radius: 3px;
bottom: 0;
left: 0;
margin: 2px;
position: absolute;
top: 0;
transition: opacity .1s ease;
width: 50%;
flex: 1 1 auto;
}
.joinVideoCallButton-2Pohj0 .inner-1e8n63 {
cursor: pointer;
z-index: 1;
flex: 1 1 auto;
}
.flex-lFgbSz:first-child, .horizontal-2BEEBe>.flexChild-1KGW5q:first-child {
margin-left: 0;
}
.flex-lFgbSz, .horizontal-2BEEBe>.flexChild-1KGW5q {
margin-left: 10px;
margin-right: 10px;
}
.joinVideoCallButton-2Pohj0 .callDivider-_hMb9n {
background-color: #69c49a;
height: 20px;
margin: 0 2px;
opacity: .6;
width: 2px;
}
.joinVideoCallButton-2Pohj0 .icon-3tOP24 {
height: 16px;
width: 16px;
}
.joinVideoCallButton-2Pohj0 .buttonText-1b8lyZ {
color: #f6f6f7;
font-size: 14px;
margin-left: 8px;
margin-right: 8px;
text-transform: uppercase;
}
.wrapper-1XTKlU{
background-size:cover;
min-height:100vh;
overflow:hidden
}
.flexWrapper-1ztpWj{
height:100vh
}
.flex-3B1Tl4{
display:-webkit-box;
display:-ms-flexbox;
display:flex
}
.alignStart-pnSyE6{
-ms-flex-align:start;
-webkit-box-align:start;
align-items:flex-start
}
.alignEnd-3PVyen{
-ms-flex-align:end;
-webkit-box-align:end;
align-items:flex-end
}
.alignCenter-3VxkQP{
-ms-flex-align:center;
-webkit-box-align:center;
align-items:center
}
.alignStretch-1hwxMa{
-ms-flex-align:stretch;
-webkit-box-align:stretch;
align-items:stretch
}
.alignBaseline-4enZzv{
-ms-flex-align:baseline;
-webkit-box-align:baseline;
align-items:baseline
}
.justifyStart-2yIZo0{
-ms-flex-pack:start;
-webkit-box-pack:start;
justify-content:flex-start
}
.justifyEnd-1ceqOU{
-ms-flex-pack:end;
-webkit-box-pack:end;
justify-content:flex-end
}
.justifyCenter-29N31w{
-ms-flex-pack:center;
-webkit-box-pack:center;
justify-content:center
}
.justifyBetween-1d1Hto{
-ms-flex-pack:justify;
-webkit-box-pack:justify;
justify-content:space-between
}
.horizontal-2VE-Fw>.spacer-2Aeq3k,.horizontalReverse-k5PqxT>.spacer-2Aeq3k,.vertical-3X17r5>.spacer-2Aeq3k{
min-height:1px
}
.horizontal-2BEEBe>.flex-lFgbSz,.horizontal-2BEEBe>.flexChild-1KGW5q{
margin-left:10px;
margin-right:10px
}
.horizontal-2BEEBe>.flex-lFgbSz:first-child,.horizontal-2BEEBe>.flexChild-1KGW5q:first-child{
margin-left:0
}
.horizontal-2BEEBe>.flex-lFgbSz:last-child,.horizontal-2BEEBe>.flexChild-1KGW5q:last-child{
margin-right:0
}
<div class="flex-lFgbSz flex-3B1Tl4 horizontal-2BEEBe horizontal-2VE-Fw flex-3B1Tl4 directionRow-yNbSvJ justifyCenter-29N31w alignStretch-1hwxMa noWrap-v6g9vO private-channel-call-actions" style="">
<div class="joinVideoCallButton-2Pohj0">
<div class="underlay-1LCk7B" style="opacity: 1; transform: translateX(31.5781px);"></div>
<div class="flex-lFgbSz flex-3B1Tl4 horizontal-2BEEBe horizontal-2VE-Fw flex-3B1Tl4 directionRow-yNbSvJ justifyCenter-29N31w alignCenter-3VxkQP noWrap-v6g9vO inner-1e8n63" style="flex: 1 1 auto;">
<div class="flex-lFgbSz flex-3B1Tl4 horizontal-2BEEBe horizontal-2VE-Fw flex-3B1Tl4 directionRow-yNbSvJ justifyCenter-29N31w alignCenter-3VxkQP noWrap-v6g9vO callButton-205P-D" style="flex: 1 1 auto;"><img class="icon-3tOP24" src="http://discordapp.com/assets/0682cf612d4fed39efb57e0a1bcc8544.svg">
<div class="buttonText-1b8lyZ">Video</div>
</div>
<div class="callDivider-_hMb9n"></div>
<div class="flex-lFgbSz flex-3B1Tl4 horizontal-2BEEBe horizontal-2VE-Fw flex-3B1Tl4 directionRow-yNbSvJ justifyCenter-29N31w alignCenter-3VxkQP noWrap-v6g9vO callButton-205P-D" style="flex: 1 1 auto;">
<div class="buttonText-1b8lyZ">Voice</div><img class="icon-3tOP24" src="http://discordapp.com/assets/8b47456a037cc496c55ae8f871274018.svg"></div>
</div>
</div>
</div>
Part 1
The idea is fairly simple: you need to add an extra "hover box" element inside the button row, absolute position it, and finally just change the left value of the object according to the position of the cursor:
function relocateHoverBox(e) {
// Get all the needed values
// (idealy don't use as many variables)
let hoverBoxEl = e.target.closest(".btn-row").querySelector(".btn-row--hover-box");
let hoverBoxHalfWidth = hoverBoxEl.clientWidth / 2;
let containerX = e.target.closest(".btn-row").getBoundingClientRect().left;
let maxLeft = e.target.closest(".btn-row").clientWidth - hoverBoxEl.clientWidth;
let newLeftValue = e.pageX - containerX - hoverBoxHalfWidth;
// Apply new left value accordingly
if (newLeftValue >= 0) {
if (newLeftValue > maxLeft) {
hoverBoxEl.style.left = maxLeft + "px";
}
else {
hoverBoxEl.style.left = e.pageX - containerX - hoverBoxHalfWidth + "px";
}
}
else {
hoverBoxEl.style.left = 0 + "px";
}
}
// Set the hover box in the right position as soon as the mouse enters
const mouseoverHandler = function(e) {
relocateHoverBox(e);
}
// Update the hover box position
const mousemoveHandler = function(e) {
relocateHoverBox(e);
}
// Reset the hover box position
const mouseleaveHandler = function(e) {
e.target.closest(".btn-row").querySelector(".btn-row--hover-box").style.left = "";
}
document.getElementsByClassName("btn-row")[0].addEventListener('mousemove', mousemoveHandler);
document.getElementsByClassName("btn-row")[0].addEventListener('mouseenter', mouseoverHandler);
document.getElementsByClassName("btn-row")[0].addEventListener('mouseleave', mouseleaveHandler);
body {
margin: 0;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
background: #202225;
}
.btn-row {
display: flex;
justify-content: center;
align-items: center;
border-radius: 4px;
height: 48px;
background: #43b581;
position: relative;
}
.btn-row--hover-box {
width: 50%;
height: 44px;
border-radius: 2px;
position: absolute;
top: 50%;
left: 0;
transform: translateY(-50%);
}
.btn-row--hover-box:hover {
background: rgba(255, 255, 255, 0.25);
}
.btn {
background: transparent;
letter-spacing: .1rem;
padding: 0 1rem;
border: 0;
color: #fff;
height: 28px;
display: block;
font-weight: bold;
text-transform: uppercase;
}
<div class="btn-row">
<div class="btn-row--hover-box"></div>
<button class="btn">Option 1</button>
<button class="btn">Option 2</button>
</div>
Part 2
Also, I wonder if it is possible without the use of Jquery?
If by "Jquery" you actually mean the jQuery library, then just remember that it is a library, which means that it is only a collection of useful scripts written in a programming language, then since you can write your own scripts using that language, it is possible to do it without jQuery
If by "Jquery" you mean Javascript (the language in which jQuery is written), then it's not possible to do it without it, since you need it to follow the x-coordinate of the cursor.

Categories

Resources