I have added a button on my site which let's the users change to dark or light mode whenever they want. I added the button with a moon icon on it, but the problem is that I want that the moon icon changes to sun icon when the user is in dark mode. And changes to moon icon when user is in light mode.
function myfunction(e) {
console.log("you clicked");
document.documentElement.classList.toggle("dark-mode");
document.querySelectorAll(".inverted").forEach((result) => {
result.classList.toggle("invert");
});
}
const btn = document.querySelector('.btn')
btn.addEventListener('click', myfunction);
.dark-mode {
filter: invert(1) hue-rotate(180deg);
}
.invert {
filter: invert(1) hue-rotate(180deg);
}
<button class="btn"><img src='moon.png'></img></button>
The .inverted class in js is because I don't want the images to invert their colors.. so I gave all the images a class='inverted'
So, this is what I've done and someone please let me know how I should change the icon to moon and sun depending on the current mode (light or dark)
Thanks!
You could add the sun as another image to the button and change the visibility of the two images via your .dark-mode css class.
So whenever the .dark-mode class is present the moon gets hidden and the sun gets shown.
function myfunction(e) {
console.log("you clicked");
document.documentElement.classList.toggle("dark-mode");
document.querySelectorAll(".inverted").forEach((result) => {
result.classList.toggle("invert");
});
}
const btn = document.querySelector('.btn')
btn.addEventListener('click', myfunction);
.dark-mode {
filter: invert(1) hue-rotate(180deg);
}
.invert {
filter: invert(1) hue-rotate(180deg);
}
/* button handling */
.moon {
display: block;
}
.sun {
display: none;
}
.dark-mode .moon {
display: none;
}
.dark-mode .sun {
display: block;
}
<button class="btn">
<img class="moon" src="moon.png" alt="moon"></img>
<img class="sun" src="sun.png" alt="sun"></img>
</button>
You could go with the CSS approach as in #Fabian's answer. If you would like to go with JS, you could simply use a flag to indicate whether or not the user switched to dark mode, and dynamically set the icon based on it.
let isDarkMode = document.documentElement.classList.contains("dark-mode");
function myfunction(e) {
document.documentElement.classList.toggle("dark-mode");
document.querySelectorAll(".inverted").forEach((result) => {
result.classList.toggle("invert");
});
e.currentTarget.querySelector("img").src = isDarkMode ? "sun.png" : "moon.png";
}
You can use the below reference for the toggle button from light mode to dark mode and dark mode to light mode.
body {
height: 100vh;
display: flex;
align-items: center;
justify-content: center;
}
.toggle-checkbox {
position: absolute;
opacity: 0;
cursor: pointer;
height: 0;
width: 0;
}
.toggle-slot {
position: relative;
height: 10em;
width: 20em;
border: 5px solid #e4e7ec;
border-radius: 10em;
background-color: white;
box-shadow: 0px 10px 25px #e4e7ec;
transition: background-color 250ms;
}
.toggle-checkbox:checked ~ .toggle-slot {
background-color: #374151;
}
.toggle-button {
transform: translate(11.75em, 1.75em);
position: absolute;
height: 6.5em;
width: 6.5em;
border-radius: 50%;
background-color: #ffeccf;
box-shadow: inset 0px 0px 0px 0.75em #ffbb52;
transition: background-color 250ms, border-color 250ms, transform 500ms cubic-bezier(.26,2,.46,.71);
}
.toggle-checkbox:checked ~ .toggle-slot .toggle-button {
background-color: #485367;
box-shadow: inset 0px 0px 0px 0.75em white;
transform: translate(1.75em, 1.75em);
}
.sun-icon {
position: absolute;
height: 6em;
width: 6em;
color: #ffbb52;
}
.sun-icon-wrapper {
position: absolute;
height: 6em;
width: 6em;
opacity: 1;
transform: translate(2em, 2em) rotate(15deg);
transform-origin: 50% 50%;
transition: opacity 150ms, transform 500ms cubic-bezier(.26,2,.46,.71);
}
.toggle-checkbox:checked ~ .toggle-slot .sun-icon-wrapper {
opacity: 0;
transform: translate(3em, 2em) rotate(0deg);
}
.moon-icon {
position: absolute;
height: 6em;
width: 6em;
color: white;
}
.moon-icon-wrapper {
position: absolute;
height: 6em;
width: 6em;
opacity: 0;
transform: translate(11em, 2em) rotate(0deg);
transform-origin: 50% 50%;
transition: opacity 150ms, transform 500ms cubic-bezier(.26,2.5,.46,.71);
}
.toggle-checkbox:checked ~ .toggle-slot .moon-icon-wrapper {
opacity: 1;
transform: translate(12em, 2em) rotate(-15deg);
}
<head>
<script src="https://code.iconify.design/1/1.0.4/iconify.min.js"> </script>
</head>
<label>
<input class='toggle-checkbox' type='checkbox'>
<div class='toggle-slot'>
<div class='sun-icon-wrapper'>
<div class="iconify sun-icon" data-icon="feather-sun" data-inline="false"></div>
</div>
<div class='toggle-button'></div>
<div class='moon-icon-wrapper'>
<div class="iconify moon-icon" data-icon="feather-moon" data-inline="false"></div>
</div>
</div>
</label>
function myfunction(e) {
const doc = document.documentElement
doc.classList.toggle("dark-mode");
document.querySelectorAll(".inverted").forEach((result) => {
result.classList.toggle("invert");
});
const img = e.currentTarget.querySelector('img')
const label = e.currentTarget.querySelector('span')
if (doc.classList.contains('dark-mode')) {
img.src = 'sun.png'
label.innerHTML = 'Light mode'
} else {
img.src = 'moon.png'
label.innerHTML = 'Dark mode'
}
}
const btn = document.querySelector('.btn')
btn.addEventListener('click', myfunction);
.dark-mode {
filter: invert(1) hue-rotate(180deg);
}
.invert {
filter: invert(1) hue-rotate(180deg);
}
'
<button class="btn">
<img src='moon.png' alt="" />
<span>Dark mode</span>
</button>
Related
The first one is working while the other one is not uploading and neither previewing the image I want to upload. I want both the image uploader and preview. But the first one is working only. I am using the same JavaScript for the Image uploader and preview. Simple word the code for HTML is copied and JavaScript is the same too. Kindly change it and make both inputs work correctly.
// Design By
// - https://dribbble.com/shots/13992184-File-Uploader-Drag-Drop
// Select Upload-Area
const uploadArea = document.querySelector('#uploadArea')
// Select Drop-Zoon Area
const dropZoon = document.querySelector('#dropZoon');
// Loading Text
const loadingText = document.querySelector('#loadingText');
// Slect File Input
const fileInput = document.querySelector('#fileInput');
// Select Preview Image
const previewImage = document.querySelector('#previewImage');
// File-Details Area
const fileDetails = document.querySelector('#fileDetails');
// Uploaded File
const uploadedFile = document.querySelector('#uploadedFile');
// Uploaded File Info
const uploadedFileInfo = document.querySelector('#uploadedFileInfo');
// Uploaded File Name
const uploadedFileName = document.querySelector('.uploaded-file__name');
// Uploaded File Icon
const uploadedFileIconText = document.querySelector('.uploaded-file__icon-text');
// Uploaded File Counter
const uploadedFileCounter = document.querySelector('.uploaded-file__counter');
// ToolTip Data
const toolTipData = document.querySelector('.upload-area__tooltip-data');
// Images Types
const imagesTypes = [
"jpeg",
"png",
"svg",
"gif"
];
// Append Images Types Array Inisde Tooltip Data
toolTipData.innerHTML = [...imagesTypes].join(', .');
// When (drop-zoon) has (dragover) Event
dropZoon.addEventListener('dragover', function (event) {
// Prevent Default Behavior
event.preventDefault();
// Add Class (drop-zoon--over) On (drop-zoon)
dropZoon.classList.add('drop-zoon--over');
});
// When (drop-zoon) has (dragleave) Event
dropZoon.addEventListener('dragleave', function (event) {
// Remove Class (drop-zoon--over) from (drop-zoon)
dropZoon.classList.remove('drop-zoon--over');
});
// When (drop-zoon) has (drop) Event
dropZoon.addEventListener('drop', function (event) {
// Prevent Default Behavior
event.preventDefault();
// Remove Class (drop-zoon--over) from (drop-zoon)
dropZoon.classList.remove('drop-zoon--over');
// Select The Dropped File
const file = event.dataTransfer.files[0];
// Call Function uploadFile(), And Send To Her The Dropped File :)
uploadFile(file);
});
// When (drop-zoon) has (click) Event
dropZoon.addEventListener('click', function (event) {
// Click The (fileInput)
fileInput.click();
});
// When (fileInput) has (change) Event
fileInput.addEventListener('change', function (event) {
// Select The Chosen File
const file = event.target.files[0];
// Call Function uploadFile(), And Send To Her The Chosen File :)
uploadFile(file);
});
// Upload File Function
function uploadFile(file) {
// FileReader()
const fileReader = new FileReader();
// File Type
const fileType = file.type;
// File Size
const fileSize = file.size;
// If File Is Passed from the (File Validation) Function
if (fileValidate(fileType, fileSize)) {
// Add Class (drop-zoon--Uploaded) on (drop-zoon)
dropZoon.classList.add('drop-zoon--Uploaded');
// Show Loading-text
loadingText.style.display = "block";
// Hide Preview Image
previewImage.style.display = 'none';
// Remove Class (uploaded-file--open) From (uploadedFile)
uploadedFile.classList.remove('uploaded-file--open');
// Remove Class (uploaded-file__info--active) from (uploadedFileInfo)
uploadedFileInfo.classList.remove('uploaded-file__info--active');
// After File Reader Loaded
fileReader.addEventListener('load', function () {
// After Half Second
setTimeout(function () {
// Add Class (upload-area--open) On (uploadArea)
uploadArea.classList.add('upload-area--open');
// Hide Loading-text (please-wait) Element
loadingText.style.display = "none";
// Show Preview Image
previewImage.style.display = 'block';
// Add Class (file-details--open) On (fileDetails)
fileDetails.classList.add('file-details--open');
// Add Class (uploaded-file--open) On (uploadedFile)
uploadedFile.classList.add('uploaded-file--open');
// Add Class (uploaded-file__info--active) On (uploadedFileInfo)
uploadedFileInfo.classList.add('uploaded-file__info--active');
}, 500); // 0.5s
// Add The (fileReader) Result Inside (previewImage) Source
previewImage.setAttribute('src', fileReader.result);
// Add File Name Inside Uploaded File Name
uploadedFileName.innerHTML = file.name;
// Call Function progressMove();
progressMove();
});
// Read (file) As Data Url
fileReader.readAsDataURL(file);
} else { // Else
this; // (this) Represent The fileValidate(fileType, fileSize) Function
};
};
// Progress Counter Increase Function
function progressMove() {
// Counter Start
let counter = 0;
// After 600ms
setTimeout(() => {
// Every 100ms
let counterIncrease = setInterval(() => {
// If (counter) is equle 100
if (counter === 100) {
// Stop (Counter Increase)
clearInterval(counterIncrease);
} else { // Else
// plus 10 on counter
counter = counter + 10;
// add (counter) vlaue inisde (uploadedFileCounter)
uploadedFileCounter.innerHTML = `${counter}%`
}
}, 100);
}, 600);
};
// Simple File Validate Function
function fileValidate(fileType, fileSize) {
// File Type Validation
let isImage = imagesTypes.filter((type) => fileType.indexOf(`image/${type}`) !== -1);
// If The Uploaded File Type Is 'jpeg'
if (isImage[0] === 'jpeg') {
// Add Inisde (uploadedFileIconText) The (jpg) Value
uploadedFileIconText.innerHTML = 'jpg';
} else { // else
// Add Inisde (uploadedFileIconText) The Uploaded File Type
uploadedFileIconText.innerHTML = isImage[0];
};
// If The Uploaded File Is An Image
if (isImage.length !== 0) {
// Check, If File Size Is 2MB or Less
if (fileSize <= 2000000) { // 2MB :)
return true;
} else { // Else File Size
return alert('Please Your File Should be 2 Megabytes or Less');
};
} else { // Else File Type
return alert('Please make sure to upload An Image File Type');
};
};
// :)
/* General Styles */
* {
box-sizing: border-box;
}
:root {
--clr-white: rgb(255, 255, 255);
--clr-black: rgb(0, 0, 0);
--clr-light: rgb(245, 248, 255);
--clr-light-gray: rgb(196, 195, 196);
--clr-blue: rgb(63, 134, 255);
--clr-light-blue: rgb(171, 202, 255);
}
body {
margin: 0;
padding: 0;
background-color: var(--clr-light);
color: var(--clr-black);
font-family: 'Poppins', sans-serif;
font-size: 1.125rem;
min-height: 100vh;
display: flex;
justify-content: center;
align-items: center;
}
/* End General Styles */
/* Upload Area */
.upload-area {
width: 100%;
max-width: 25rem;
background-color: var(--clr-white);
box-shadow: 0 10px 60px rgb(218, 229, 255);
border: 2px solid var(--clr-light-blue);
border-radius: 24px;
padding: 2rem 1.875rem 5rem 1.875rem;
margin: 0.625rem;
text-align: center;
}
.upload-area--open { /* Slid Down Animation */
animation: slidDown 500ms ease-in-out;
}
#keyframes slidDown {
from {
height: 28.125rem; /* 450px */
}
to {
height: 35rem; /* 560px */
}
}
/* Header */
.upload-area__header {
}
.upload-area__title {
font-size: 1.8rem;
font-weight: 500;
margin-bottom: 0.3125rem;
}
.upload-area__paragraph {
font-size: 0.9375rem;
color: var(--clr-light-gray);
margin-top: 0;
}
.upload-area__tooltip {
position: relative;
color: var(--clr-light-blue);
cursor: pointer;
transition: color 300ms ease-in-out;
}
.upload-area__tooltip:hover {
color: var(--clr-blue);
}
.upload-area__tooltip-data {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -125%);
min-width: max-content;
background-color: var(--clr-white);
color: var(--clr-blue);
border: 1px solid var(--clr-light-blue);
padding: 0.625rem 1.25rem;
font-weight: 500;
opacity: 0;
visibility: hidden;
transition: none 300ms ease-in-out;
transition-property: opacity, visibility;
}
.upload-area__tooltip:hover .upload-area__tooltip-data {
opacity: 1;
visibility: visible;
}
/* Drop Zoon */
.upload-area__drop-zoon {
position: relative;
height: 11.25rem; /* 180px */
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
border: 2px dashed var(--clr-light-blue);
border-radius: 15px;
margin-top: 2.1875rem;
cursor: pointer;
transition: border-color 300ms ease-in-out;
}
.upload-area__drop-zoon:hover {
border-color: var(--clr-blue);
}
.drop-zoon__icon {
display: flex;
font-size: 3.75rem;
color: var(--clr-blue);
transition: opacity 300ms ease-in-out;
}
.drop-zoon__paragraph {
font-size: 0.9375rem;
color: var(--clr-light-gray);
margin: 0;
margin-top: 0.625rem;
transition: opacity 300ms ease-in-out;
}
.drop-zoon:hover .drop-zoon__icon,
.drop-zoon:hover .drop-zoon__paragraph {
opacity: 0.7;
}
.drop-zoon__loading-text {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
display: none;
color: var(--clr-light-blue);
z-index: 10;
}
.drop-zoon__preview-image {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
object-fit: contain;
padding: 0.3125rem;
border-radius: 10px;
display: none;
z-index: 1000;
transition: opacity 300ms ease-in-out;
}
.drop-zoon:hover .drop-zoon__preview-image {
opacity: 0.8;
}
.drop-zoon__file-input {
display: none;
}
/* (drop-zoon--over) Modifier Class */
.drop-zoon--over {
border-color: var(--clr-blue);
}
.drop-zoon--over .drop-zoon__icon,
.drop-zoon--over .drop-zoon__paragraph {
opacity: 0.7;
}
/* (drop-zoon--over) Modifier Class */
.drop-zoon--Uploaded {
}
.drop-zoon--Uploaded .drop-zoon__icon,
.drop-zoon--Uploaded .drop-zoon__paragraph {
display: none;
}
/* File Details Area */
.upload-area__file-details {
height: 0;
visibility: hidden;
opacity: 0;
text-align: left;
transition: none 500ms ease-in-out;
transition-property: opacity, visibility;
transition-delay: 500ms;
}
/* (duploaded-file--open) Modifier Class */
.file-details--open {
height: auto;
visibility: visible;
opacity: 1;
}
.file-details__title {
font-size: 1.125rem;
font-weight: 500;
color: var(--clr-light-gray);
}
/* Uploaded File */
.uploaded-file {
display: flex;
align-items: center;
padding: 0.625rem 0;
visibility: hidden;
opacity: 0;
transition: none 500ms ease-in-out;
transition-property: visibility, opacity;
}
/* (duploaded-file--open) Modifier Class */
.uploaded-file--open {
visibility: visible;
opacity: 1;
}
.uploaded-file__icon-container {
position: relative;
margin-right: 0.3125rem;
}
.uploaded-file__icon {
font-size: 3.4375rem;
color: var(--clr-blue);
}
.uploaded-file__icon-text {
position: absolute;
top: 1.5625rem;
left: 50%;
transform: translateX(-50%);
font-size: 0.9375rem;
font-weight: 500;
color: var(--clr-white);
}
.uploaded-file__info {
position: relative;
top: -0.3125rem;
width: 100%;
display: flex;
justify-content: space-between;
}
.uploaded-file__info::before,
.uploaded-file__info::after {
content: '';
position: absolute;
bottom: -0.9375rem;
width: 0;
height: 0.5rem;
background-color: #ebf2ff;
border-radius: 0.625rem;
}
.uploaded-file__info::before {
width: 100%;
}
.uploaded-file__info::after {
width: 100%;
background-color: var(--clr-blue);
}
/* Progress Animation */
.uploaded-file__info--active::after {
animation: progressMove 800ms ease-in-out;
animation-delay: 300ms;
}
#keyframes progressMove {
from {
width: 0%;
background-color: transparent;
}
to {
width: 100%;
background-color: var(--clr-blue);
}
}
.uploaded-file__name {
width: 100%;
max-width: 6.25rem; /* 100px */
display: inline-block;
font-size: 1rem;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.uploaded-file__counter {
font-size: 1rem;
color: var(--clr-light-gray);
}
<!-- Upload Area -->
<div id="uploadArea" class="upload-area">
<!-- Header -->
<div class="upload-area__header">
<h1 class="upload-area__title">Upload your file</h1>
<p class="upload-area__paragraph">
File should be an image
<strong class="upload-area__tooltip">
Like
<span class="upload-area__tooltip-data"></span> <!-- Data Will be Comes From Js -->
</strong>
</p>
</div>
<!-- End Header -->
<!-- Drop Zoon -->
<div id="dropZoon" class="upload-area__drop-zoon drop-zoon">
<span class="drop-zoon__icon">
<i class='bx bxs-file-image'></i>
</span>
<p class="drop-zoon__paragraph">Drop your file here or Click to browse</p>
<span id="loadingText" class="drop-zoon__loading-text">Please Wait</span>
<img src="" alt="Preview Image" id="previewImage" class="drop-zoon__preview-image" draggable="false">
<input type="file" id="fileInput" class="drop-zoon__file-input" accept="image/*">
</div>
<!-- End Drop Zoon -->
<!-- File Details -->
<div id="fileDetails" class="upload-area__file-details file-details">
<h3 class="file-details__title">Uploaded File</h3>
<div id="uploadedFile" class="uploaded-file">
<div class="uploaded-file__icon-container">
<i class='bx bxs-file-blank uploaded-file__icon'></i>
<span class="uploaded-file__icon-text"></span> <!-- Data Will be Comes From Js -->
</div>
<div id="uploadedFileInfo" class="uploaded-file__info">
<span class="uploaded-file__name">Proejct 1</span>
<span class="uploaded-file__counter">0%</span>
</div>
</div>
</div>
<!-- End File Details -->
</div>
<!-- End Upload Area -->
<div class="mb-5 mt-5"></div>
<!-- Upload Area -->
<div id="uploadArea" class="upload-area">
<!-- Header -->
<div class="upload-area__header">
<h1 class="upload-area__title">Upload your file</h1>
<p class="upload-area__paragraph">
File should be an image
<strong class="upload-area__tooltip">
Like
<span class="upload-area__tooltip-data"></span> <!-- Data Will be Comes From Js -->
</strong>
</p>
</div>
<!-- End Header -->
<!-- Drop Zoon -->
<div id="dropZoon" class="upload-area__drop-zoon drop-zoon">
<span class="drop-zoon__icon">
<i class='bx bxs-file-image'></i>
</span>
<p class="drop-zoon__paragraph">Drop your file here or Click to browse</p>
<span id="loadingText" class="drop-zoon__loading-text">Please Wait</span>
<img src="" alt="Preview Image" id="previewImage" class="drop-zoon__preview-image" draggable="false">
<input type="file" id="fileInput" class="drop-zoon__file-input" accept="image/*">
</div>
<!-- End Drop Zoon -->
<!-- File Details -->
<div id="fileDetails" class="upload-area__file-details file-details">
<h3 class="file-details__title">Uploaded File</h3>
<div id="uploadedFile" class="uploaded-file">
<div class="uploaded-file__icon-container">
<i class='bx bxs-file-blank uploaded-file__icon'></i>
<span class="uploaded-file__icon-text"></span> <!-- Data Will be Comes From Js -->
</div>
<div id="uploadedFileInfo" class="uploaded-file__info">
<span class="uploaded-file__name">Proejct 1</span>
<span class="uploaded-file__counter">0%</span>
</div>
</div>
</div>
<!-- End File Details -->
</div>
<!-- End Upload Area -->
In JavaScript file you are using document.querySelector("")
That chooses only the first element in the HTML and you can't duplicate the two uploader and use the same selector in JavaScript.
You can with JavaScript select the two uploader & make the functions for the two uploaders with loop as an example.
If you need array of the elements you can use document.querySelectorAll("").
Since IDs such as #uploadArea, #dropZoon, etc. have become duplicated in the html code, then accordingly you install all handlers only for the first element.
I have slightly corrected your example so that you can install a lot of loaders:
// Design By
// - https://dribbble.com/shots/13992184-File-Uploader-Drag-Drop
uploadHandler({
uploadArea: document.querySelector("#uploadArea"),
dropZoon: document.querySelector("#dropZoon"),
loadingText: document.querySelector("#loadingText"),
fileInput: document.querySelector("#fileInput"),
previewImage: document.querySelector("#previewImage"),
fileDetails: document.querySelector("#fileDetails"),
uploadedFile: document.querySelector("#uploadedFile"),
uploadedFileInfo: document.querySelector("#uploadedFileInfo"),
uploadedFileName: document.querySelector(".uploaded-file__name"),
uploadedFileIconText: document.querySelector(".uploaded-file__icon-text"),
uploadedFileCounter: document.querySelector(".uploaded-file__counter"),
toolTipData: document.querySelector(".upload-area__tooltip-data"),
});
uploadHandler({
uploadArea: document.querySelector("#uploadArea-2"),
dropZoon: document.querySelector("#dropZoon-2"),
loadingText: document.querySelector("#loadingText-2"),
fileInput: document.querySelector("#fileInput-2"),
previewImage: document.querySelector("#previewImage-2"),
fileDetails: document.querySelector("#fileDetails-2"),
uploadedFile: document.querySelector("#uploadedFile-2"),
uploadedFileInfo: document.querySelector("#uploadedFileInfo-2"),
uploadedFileName: document.querySelector(".uploaded-file__name-2"),
uploadedFileIconText: document.querySelector(".uploaded-file__icon-text-2"),
uploadedFileCounter: document.querySelector(".uploaded-file__counter-2"),
toolTipData: document.querySelector(".upload-area__tooltip-data-2"),
});
function uploadHandler({
uploadArea,
dropZoon,
loadingText,
fileInput,
previewImage,
fileDetails,
uploadedFile,
uploadedFileInfo,
uploadedFileName,
uploadedFileIconText,
uploadedFileCounter,
toolTipData,
}) {
// Images Types
const imagesTypes = ["jpeg", "png", "svg", "gif"];
// Append Images Types Array Inisde Tooltip Data
toolTipData.innerHTML = [...imagesTypes].join(", .");
// When (drop-zoon) has (dragover) Event
dropZoon.addEventListener("dragover", function (event) {
// Prevent Default Behavior
event.preventDefault();
// Add Class (drop-zoon--over) On (drop-zoon)
dropZoon.classList.add("drop-zoon--over");
});
// When (drop-zoon) has (dragleave) Event
dropZoon.addEventListener("dragleave", function (event) {
// Remove Class (drop-zoon--over) from (drop-zoon)
dropZoon.classList.remove("drop-zoon--over");
});
// When (drop-zoon) has (drop) Event
dropZoon.addEventListener("drop", function (event) {
// Prevent Default Behavior
event.preventDefault();
// Remove Class (drop-zoon--over) from (drop-zoon)
dropZoon.classList.remove("drop-zoon--over");
// Select The Dropped File
const file = event.dataTransfer.files[0];
// Call Function uploadFile(), And Send To Her The Dropped File :)
uploadFile(file);
});
// When (drop-zoon) has (click) Event
dropZoon.addEventListener("click", function (event) {
// Click The (fileInput)
fileInput.click();
});
// When (fileInput) has (change) Event
fileInput.addEventListener("change", function (event) {
// Select The Chosen File
const file = event.target.files[0];
// Call Function uploadFile(), And Send To Her The Chosen File :)
uploadFile(file);
});
// Upload File Function
function uploadFile(file) {
// FileReader()
const fileReader = new FileReader();
// File Type
const fileType = file.type;
// File Size
const fileSize = file.size;
// If File Is Passed from the (File Validation) Function
if (fileValidate(fileType, fileSize)) {
// Add Class (drop-zoon--Uploaded) on (drop-zoon)
dropZoon.classList.add("drop-zoon--Uploaded");
// Show Loading-text
loadingText.style.display = "block";
// Hide Preview Image
previewImage.style.display = "none";
// Remove Class (uploaded-file--open) From (uploadedFile)
uploadedFile.classList.remove("uploaded-file--open");
// Remove Class (uploaded-file__info--active) from (uploadedFileInfo)
uploadedFileInfo.classList.remove("uploaded-file__info--active");
// After File Reader Loaded
fileReader.addEventListener("load", function () {
// After Half Second
setTimeout(function () {
// Add Class (upload-area--open) On (uploadArea)
uploadArea.classList.add("upload-area--open");
// Hide Loading-text (please-wait) Element
loadingText.style.display = "none";
// Show Preview Image
previewImage.style.display = "block";
// Add Class (file-details--open) On (fileDetails)
fileDetails.classList.add("file-details--open");
// Add Class (uploaded-file--open) On (uploadedFile)
uploadedFile.classList.add("uploaded-file--open");
// Add Class (uploaded-file__info--active) On (uploadedFileInfo)
uploadedFileInfo.classList.add("uploaded-file__info--active");
}, 500); // 0.5s
// Add The (fileReader) Result Inside (previewImage) Source
previewImage.setAttribute("src", fileReader.result);
// Add File Name Inside Uploaded File Name
uploadedFileName.innerHTML = file.name;
// Call Function progressMove();
progressMove();
});
// Read (file) As Data Url
fileReader.readAsDataURL(file);
} else {
// Else
this; // (this) Represent The fileValidate(fileType, fileSize) Function
}
}
// Progress Counter Increase Function
function progressMove() {
// Counter Start
let counter = 0;
// After 600ms
setTimeout(() => {
// Every 100ms
let counterIncrease = setInterval(() => {
// If (counter) is equle 100
if (counter === 100) {
// Stop (Counter Increase)
clearInterval(counterIncrease);
} else {
// Else
// plus 10 on counter
counter = counter + 10;
// add (counter) vlaue inisde (uploadedFileCounter)
uploadedFileCounter.innerHTML = `${counter}%`;
}
}, 100);
}, 600);
}
// Simple File Validate Function
function fileValidate(fileType, fileSize) {
// File Type Validation
let isImage = imagesTypes.filter(
(type) => fileType.indexOf(`image/${type}`) !== -1
);
// If The Uploaded File Type Is 'jpeg'
if (isImage[0] === "jpeg") {
// Add Inisde (uploadedFileIconText) The (jpg) Value
uploadedFileIconText.innerHTML = "jpg";
} else {
// else
// Add Inisde (uploadedFileIconText) The Uploaded File Type
uploadedFileIconText.innerHTML = isImage[0];
}
// If The Uploaded File Is An Image
if (isImage.length !== 0) {
// Check, If File Size Is 2MB or Less
if (fileSize <= 2000000) {
// 2MB :)
return true;
} else {
// Else File Size
return alert("Please Your File Should be 2 Megabytes or Less");
}
} else {
// Else File Type
return alert("Please make sure to upload An Image File Type");
}
}
}
// :)
/* General Styles */
* {
box-sizing: border-box;
}
:root {
--clr-white: rgb(255, 255, 255);
--clr-black: rgb(0, 0, 0);
--clr-light: rgb(245, 248, 255);
--clr-light-gray: rgb(196, 195, 196);
--clr-blue: rgb(63, 134, 255);
--clr-light-blue: rgb(171, 202, 255);
}
body {
margin: 0;
padding: 0;
background-color: var(--clr-light);
color: var(--clr-black);
font-family: 'Poppins', sans-serif;
font-size: 1.125rem;
min-height: 100vh;
display: flex;
justify-content: center;
align-items: center;
}
/* End General Styles */
/* Upload Area */
.upload-area {
width: 100%;
max-width: 25rem;
background-color: var(--clr-white);
box-shadow: 0 10px 60px rgb(218, 229, 255);
border: 2px solid var(--clr-light-blue);
border-radius: 24px;
padding: 2rem 1.875rem 5rem 1.875rem;
margin: 0.625rem;
text-align: center;
}
.upload-area--open { /* Slid Down Animation */
animation: slidDown 500ms ease-in-out;
}
#keyframes slidDown {
from {
height: 28.125rem; /* 450px */
}
to {
height: 35rem; /* 560px */
}
}
/* Header */
.upload-area__header {
}
.upload-area__title {
font-size: 1.8rem;
font-weight: 500;
margin-bottom: 0.3125rem;
}
.upload-area__paragraph {
font-size: 0.9375rem;
color: var(--clr-light-gray);
margin-top: 0;
}
.upload-area__tooltip {
position: relative;
color: var(--clr-light-blue);
cursor: pointer;
transition: color 300ms ease-in-out;
}
.upload-area__tooltip:hover {
color: var(--clr-blue);
}
.upload-area__tooltip-data {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -125%);
min-width: max-content;
background-color: var(--clr-white);
color: var(--clr-blue);
border: 1px solid var(--clr-light-blue);
padding: 0.625rem 1.25rem;
font-weight: 500;
opacity: 0;
visibility: hidden;
transition: none 300ms ease-in-out;
transition-property: opacity, visibility;
}
.upload-area__tooltip:hover .upload-area__tooltip-data {
opacity: 1;
visibility: visible;
}
/* Drop Zoon */
.upload-area__drop-zoon {
position: relative;
height: 11.25rem; /* 180px */
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
border: 2px dashed var(--clr-light-blue);
border-radius: 15px;
margin-top: 2.1875rem;
cursor: pointer;
transition: border-color 300ms ease-in-out;
}
.upload-area__drop-zoon:hover {
border-color: var(--clr-blue);
}
.drop-zoon__icon {
display: flex;
font-size: 3.75rem;
color: var(--clr-blue);
transition: opacity 300ms ease-in-out;
}
.drop-zoon__paragraph {
font-size: 0.9375rem;
color: var(--clr-light-gray);
margin: 0;
margin-top: 0.625rem;
transition: opacity 300ms ease-in-out;
}
.drop-zoon:hover .drop-zoon__icon,
.drop-zoon:hover .drop-zoon__paragraph {
opacity: 0.7;
}
.drop-zoon__loading-text {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
display: none;
color: var(--clr-light-blue);
z-index: 10;
}
.drop-zoon__preview-image {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
object-fit: contain;
padding: 0.3125rem;
border-radius: 10px;
display: none;
z-index: 1000;
transition: opacity 300ms ease-in-out;
}
.drop-zoon:hover .drop-zoon__preview-image {
opacity: 0.8;
}
.drop-zoon__file-input {
display: none;
}
/* (drop-zoon--over) Modifier Class */
.drop-zoon--over {
border-color: var(--clr-blue);
}
.drop-zoon--over .drop-zoon__icon,
.drop-zoon--over .drop-zoon__paragraph {
opacity: 0.7;
}
/* (drop-zoon--over) Modifier Class */
.drop-zoon--Uploaded {
}
.drop-zoon--Uploaded .drop-zoon__icon,
.drop-zoon--Uploaded .drop-zoon__paragraph {
display: none;
}
/* File Details Area */
.upload-area__file-details {
height: 0;
visibility: hidden;
opacity: 0;
text-align: left;
transition: none 500ms ease-in-out;
transition-property: opacity, visibility;
transition-delay: 500ms;
}
/* (duploaded-file--open) Modifier Class */
.file-details--open {
height: auto;
visibility: visible;
opacity: 1;
}
.file-details__title {
font-size: 1.125rem;
font-weight: 500;
color: var(--clr-light-gray);
}
/* Uploaded File */
.uploaded-file {
display: flex;
align-items: center;
padding: 0.625rem 0;
visibility: hidden;
opacity: 0;
transition: none 500ms ease-in-out;
transition-property: visibility, opacity;
}
/* (duploaded-file--open) Modifier Class */
.uploaded-file--open {
visibility: visible;
opacity: 1;
}
.uploaded-file__icon-container {
position: relative;
margin-right: 0.3125rem;
}
.uploaded-file__icon {
font-size: 3.4375rem;
color: var(--clr-blue);
}
.uploaded-file__icon-text {
position: absolute;
top: 1.5625rem;
left: 50%;
transform: translateX(-50%);
font-size: 0.9375rem;
font-weight: 500;
color: var(--clr-white);
}
.uploaded-file__info {
position: relative;
top: -0.3125rem;
width: 100%;
display: flex;
justify-content: space-between;
}
.uploaded-file__info::before,
.uploaded-file__info::after {
content: '';
position: absolute;
bottom: -0.9375rem;
width: 0;
height: 0.5rem;
background-color: #ebf2ff;
border-radius: 0.625rem;
}
.uploaded-file__info::before {
width: 100%;
}
.uploaded-file__info::after {
width: 100%;
background-color: var(--clr-blue);
}
/* Progress Animation */
.uploaded-file__info--active::after {
animation: progressMove 800ms ease-in-out;
animation-delay: 300ms;
}
#keyframes progressMove {
from {
width: 0%;
background-color: transparent;
}
to {
width: 100%;
background-color: var(--clr-blue);
}
}
.uploaded-file__name {
width: 100%;
max-width: 6.25rem; /* 100px */
display: inline-block;
font-size: 1rem;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.uploaded-file__counter {
font-size: 1rem;
color: var(--clr-light-gray);
}
<!-- Upload Area -->
<div id="uploadArea" class="upload-area">
<!-- Header -->
<div class="upload-area__header">
<h1 class="upload-area__title">Upload your file</h1>
<p class="upload-area__paragraph">
File should be an image
<strong class="upload-area__tooltip">
Like
<span class="upload-area__tooltip-data"></span> <!-- Data Will be Comes From Js -->
</strong>
</p>
</div>
<!-- End Header -->
<!-- Drop Zoon -->
<div id="dropZoon" class="upload-area__drop-zoon drop-zoon">
<span class="drop-zoon__icon">
<i class='bx bxs-file-image'></i>
</span>
<p class="drop-zoon__paragraph">Drop your file here or Click to browse</p>
<span id="loadingText" class="drop-zoon__loading-text">Please Wait</span>
<img src="" alt="Preview Image" id="previewImage" class="drop-zoon__preview-image" draggable="false">
<input type="file" id="fileInput" class="drop-zoon__file-input" accept="image/*">
</div>
<!-- End Drop Zoon -->
<!-- File Details -->
<div id="fileDetails" class="upload-area__file-details file-details">
<h3 class="file-details__title">Uploaded File</h3>
<div id="uploadedFile" class="uploaded-file">
<div class="uploaded-file__icon-container">
<i class='bx bxs-file-blank uploaded-file__icon'></i>
<span class="uploaded-file__icon-text"></span> <!-- Data Will be Comes From Js -->
</div>
<div id="uploadedFileInfo" class="uploaded-file__info">
<span class="uploaded-file__name">Proejct 1</span>
<span class="uploaded-file__counter">0%</span>
</div>
</div>
</div>
<!-- End File Details -->
</div>
<!-- End Upload Area -->
<div class="mb-5 mt-5"></div>
<!-- Upload Area -->
<div id="uploadArea-2" class="upload-area">
<!-- Header -->
<div class="upload-area__header">
<h1 class="upload-area__title">Upload your file</h1>
<p class="upload-area__paragraph">
File should be an image
<strong class="upload-area__tooltip">
Like
<span class="upload-area__tooltip-data-2"></span> <!-- Data Will be Comes From Js -->
</strong>
</p>
</div>
<!-- End Header -->
<!-- Drop Zoon -->
<div id="dropZoon-2" class="upload-area__drop-zoon drop-zoon">
<span class="drop-zoon__icon">
<i class='bx bxs-file-image'></i>
</span>
<p class="drop-zoon__paragraph">Drop your file here or Click to browse</p>
<span id="loadingText-2" class="drop-zoon__loading-text">Please Wait</span>
<img src="" alt="Preview Image" id="previewImage-2" class="drop-zoon__preview-image" draggable="false">
<input type="file" id="fileInput-2" class="drop-zoon__file-input" accept="image/*">
</div>
<!-- End Drop Zoon -->
<!-- File Details -->
<div id="fileDetails-2" class="upload-area__file-details file-details">
<h3 class="file-details__title">Uploaded File</h3>
<div id="uploadedFile-2" class="uploaded-file">
<div class="uploaded-file__icon-container">
<i class='bx bxs-file-blank uploaded-file__icon'></i>
<span class="uploaded-file__icon-text-2"></span> <!-- Data Will be Comes From Js -->
</div>
<div id="uploadedFileInfo-2" class="uploaded-file__info">
<span class="uploaded-file__name-2">Proejct 1</span>
<span class="uploaded-file__counter-2">0%</span>
</div>
</div>
</div>
<!-- End File Details -->
</div>
<!-- End Upload Area -->
In fact, all your code was wrapped in a separate function, to which the arguments of the same name are passed.
Of course, in my opinion, for the final result, this should be refactored for final use, using querySelectorAll for a list of root elements, followed by obtaining individual nested elements with querySelector.
I am trying to replicate the ripple effect from Material Design since the current app I am working on is going to get rid of Quasar; so I'm building all the elements from the ground up.
This effect:
I've watched a few videos doing this in just pure CSS and JS and I've tried to convert it into my project, but am getting caught up somewhere. I have the hover effect and the mouse location logging properly, but the ripple effect is just not triggering and I don't know why.
Any help would be greatly appreciated! Cheers!
CodeSandbox Code
CButton.vue
<template>
<button
#click="onClick"
:class="[
'c-btn',
`c-btn--${kind}`,
disabled ? `_disabled` : '',
kind === 'icon-round' ? 'shadow-5' : '',
]"
>
<transition
name="ripple"
#enter="rippleEnter"
#after-enter="afterRippleEnter"
>
<span v-if="ripple" ref="ripple" class="ripple" />
</transition>
<div class="_inner">
<div class="_text">
<slot>{{ btnText }}</slot>
</div>
</div>
</button>
</template>
<script>
export default {
name: "CcBtn",
components: {},
props: {
btnText: { type: String },
kind: { type: String, default: "main" },
isBusy: { type: Boolean, default: false },
/**
* HTML5 attribute
* #category state
*/
disabled: { type: Boolean, default: false },
color: { type: String, default: "" },
},
data() {
return {
ripple: false,
x: 0,
y: 0,
};
},
methods: {
onClick(e) {
this.x = e.layerX;
this.y = e.layerY;
this.ripple = !this.ripple;
console.log(`x`, this.x);
console.log(`y`, this.y);
console.log(`ripple`, this.ripple);
},
rippleEnter() {
this.$refs.ripple.style.top = `${this.y}px`;
this.$refs.ripple.style.left = `${this.x}px`;
},
afterRippleEnter() {
this.ripple = false;
},
},
};
</script>
<style lang="sass" scoped>
.c-btn
color: white
padding: 10px 16px
border-radius: 4px
line-height: 1em
min-height: 2em
font-weight: bold
font-size: 16px
color: White
cursor: pointer
border: 1px solid transparent
transition: background-color 0.5s
._inner
display: flex
align-items: center
justify-content: center
&--main
background: #9759ff
min-width: 228px
border-radius: 100px
&:hover
background-color: lighten(#9759ff, 10%)
&--sub
background: #f3eefe
min-width: 228px
border-radius: 100px
color: black
&:hover
background-color: darken(#f3eefe, 5%)
.ripple
display: block
width: 20px
height: 20px
border-radius: 10px
position: absolute
top: 0
left: 0
pointer-events: none
background-color: rgba(lighten(#9759ff, 20%), 0.8)
opacity: 0
transform: translate(-50%, -50%) scale(10)
transition: opacity 0.4s ease-in-out, transform 0.4s ease-in-out
&-enter
opacity: 1
transform: translate(-50%, -50%) scale(0)
</style>
App.vue
<template>
<CButton :btnText="'Button'" kind="main" />
<br />
<br />
<br />
<CButton :btnText="'Button'" kind="sub" />
</template>
<script>
import CButton from "./components/CButton.vue";
export default {
name: "App",
components: {
CButton,
},
};
</script>
Here is a working code for a button to have a ripple effect on click. Using CSS and JS:
function createRipple(event) {
const button = event.currentTarget;
const circle = document.createElement("span");
const diameter = Math.max(button.clientWidth, button.clientHeight);
const radius = diameter / 2;
circle.style.width = circle.style.height = `${diameter}px`;
circle.style.left = `${event.clientX - button.offsetLeft - radius}px`;
circle.style.top = `${event.clientY - button.offsetTop - radius}px`;
circle.classList.add("ripple");
const ripple = button.getElementsByClassName("ripple")[0];
if (ripple) {
ripple.remove();
}
button.appendChild(circle);
}
const buttons = document.getElementsByTagName("button");
for (const button of buttons) {
button.addEventListener("click", createRipple);
}
body {
height: 100vh;
margin: 0;
display: grid;
place-items: center;
}
#import url('https://fonts.googleapis.com/css2?family=Roboto&display=swap');
button {
position: relative;
overflow: hidden;
transition: background 400ms;
color: #fff;
background-color: #ff0000;
padding: 1rem 2rem;
font-family: 'Roboto', sans-serif;
font-size: 1.5rem;
outline: 0;
border: 0;
border-radius: 0.25rem;
box-shadow: 0 0 0.5rem rgba(0, 0, 0, 0.3); /* black with 30% opacity */
cursor: pointer;
}
span.ripple {
position: absolute;
border-radius: 50%;
transform: scale(0);
animation: ripple 600ms linear;
background-color: rgba(255, 255, 255, 0.7);
}
#keyframes ripple {
to {
transform: scale(4);
opacity: 0;
}
}
<button>Click For Effect</button>
I want the colour and size of a div box to animate and return to its original values when a button is clicked. Here is my code example:
document.getElementById("andAction").addEventListener("click", function() {
document.getElementById("box").classList.toggle("animi");
})
.thing {
transform: translate(150px, 100px);
}
.box {
background-color: #999;
padding: 2px;
color: black;
width:20px;
margin: 0 auto;
text-align: center;
color: #fff;
}
#keyframes blob {
0% {
background-color: #999;
}
50% {
background-color: #F9086D;
transform: scale(2);
background-color: red;
border-radius: 20px;
}
100% {
background-color: #999;
}
}
.animi {
animation-name: blob;
animation-duration:3s;
animation-iteration-count:1;
}
<button id="andAction" class="button">button</button>
<div id="box" class="box">1</div>
Problem
My problem is that I am doing it with toggle. Which means I have to click twice on the second time. Another variety was classList.add and then remove again. This leads to no result because the animation is not started for the user. the only thing I could do would be to work with timeout.
Question
I have the feeling there is another way?
You can listen to the onanimationend event to remove the class when the animation ended without relying on timers that are harder to maintain:
const boxElement = document.getElementById("box")
boxElement.addEventListener('animationend', (e) => {
// if the target it the box (it's triggered by animations on children too)
// and the animation name is `blob` (it's triggered by any animation)
// remove the class
if (e.target === boxElement && e.animationName === "blob") {
boxElement.classList.remove('animi');
}
})
document.getElementById("andAction").addEventListener("click", function() {
boxElement.classList.add("animi");
})
Just add some js to remove the class automatically after the animation finished and change your initial behaviour to not toggle but just add the class. You can achieve that by using https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/animationend_event.
const box=document.getElementById("box");
document.getElementById("andAction").addEventListener("click", function() {
box.classList.add("animi");
});
box.addEventListener('animationend', () => {
box.classList.remove("animi");
});
.thing {
transform: translate(150px, 100px);
}
.box {
background-color: #999;
padding: 2px;
color: black;
width: 20px;
margin: 0 auto;
text-align: center;
color: #fff;
}
#keyframes blob {
0% {
background-color: #999;
}
50% {
background-color: #F9086D;
transform: scale(2);
background-color: red;
border-radius: 20px;
}
100% {
background-color: #999;
}
}
.animi {
animation-name: blob;
animation-duration: 3s;
animation-iteration-count: 1;
}
<button id="andAction" class="button">button</button>
<div id="box" class="box">1</div>
I've found this script for a progress bar. It runs smoothly from 100% to 0% after clicking the button.
But how can I reset the progress bar after it hits the 0? I'm planning to use this script in a slideshow and it should be 100% again after it reaches 0.
Hope you can help me in the right direction.
Thnx,
Leon
document.querySelector("button").addEventListener("click", () => {
document.querySelector(".progress .bar").style.transitionDuration = "10s";
document.querySelector(".progress").className += " complete";
});
.progress {
width: 50%;
height: 2em;
border: 1px solid black;
}
.bar {
width: 100%;
background-color: deepskyblue;
color: white;
text-align: center;
line-height: 2em;
transition-property: width;
transition-timing-function: linear;
}
.progress.complete .bar {
width: 0%;
}
button {
margin-top: 1em;
}
<div class="progress">
<div class="bar">Loading...</div>
</div>
<button>
Start
</button>
You can reset the progress bar by removing the complete class.
document.querySelector("button.start").addEventListener("click", () => {
document.querySelector(".progress .bar").style.transitionDuration = "10s";
document.querySelector(".progress").className += " complete";
});
document.querySelector("button.reset").addEventListener("click", () => {
let className = document.querySelector(".progress").className;
if (className.indexOf(' complete') > -1) {
className = className.substr(0, className.indexOf(' complete'));
document.querySelector(".progress .bar").style.transitionDuration = "0s";
document.querySelector(".progress").className = className;
}
});
.progress {
width: 50%;
height: 2em;
border: 1px solid black;
}
.bar {
width: 100%;
background-color: deepskyblue;
color: white;
text-align: center;
line-height: 2em;
transition-property: width;
transition-timing-function: linear;
}
.progress.complete .bar {
width: 0%;
}
button {
margin-top: 1em;
}
<div class="progress">
<div class="bar">Loading...</div>
</div>
<button class="start">
Start
</button>
<button class="reset">
Reset
</button>
If you want this to be dynamic without any user interaction, you can use setTimeout, set to the same duration used in your animationDuration, within your click event Handler to reset the transition and remove the complete class.
const start = document.querySelector("#start")
const progressBar = document.querySelector(".progress .bar")
const progress = document.querySelector(".progress")
function resetProgressBar(){
progressBar.style.transitionDuration = "10s"
progress.classList.add("complete")
setTimeout(() => {
progress.classList.remove("complete")// <-- remove the class with width:0
progressBar.style.transitionDuration = "0.1s" //<-- Add a very small transitionDuration or none if you prefer
}, 10000)// <-- Set this timeout duration to the same as your transitionDuration
}
start.addEventListener("click", resetProgressBar);
.progress {
width: 50%;
height: 2em;
border: 1px solid black;
}
.bar {
width: 100%;
background-color: deepskyblue;
color: white;
text-align: center;
line-height: 2em;
transition-property: width;
transition-timing-function: linear;
}
.progress.complete .bar {
width: 0%;
}
button {
margin-top: 1em;
}
<div class="progress">
<div class="bar">Loading...</div>
</div>
<button id="start">
Start
</button>
For selector .progress .bar, use a listener for event transitionend, because you are using transition rules in css:
The transitionend event is fired when a CSS transition has completed.
Inside this event listener, set transitionDuration to the default value. And in the next step, remove class complete from .progress, which will return the previous width of the progress bar.
document.querySelector("button").addEventListener("click", () => {
document.querySelector(".progress .bar").style.transitionDuration = "10s";
document.querySelector(".progress").className += " complete";
});
document.querySelector(".progress .bar").addEventListener("transitionend", () => {
document.querySelector(".progress.complete .bar").style.transitionDuration = "";
document.querySelector(".progress").classList.remove("complete");
});
.progress {
width: 50%;
height: 2em;
border: 1px solid black;
}
.bar {
width: 100%;
background-color: deepskyblue;
color: white;
text-align: center;
line-height: 2em;
transition-property: width;
transition-timing-function: linear;
}
.progress.complete .bar {
width: 0%;
}
button {
margin-top: 1em;
}
<div class="progress">
<div class="bar">Loading...</div>
</div>
<button>
Start
</button>
Thnx for all your suggestions. I've implemented the last suggestion into my slideshow script.
It is running and it is refreshing after slide change. But somewhere on the ride it stops, I think it's confused when to start the progress bar.
Anyone an idea to make this more solid?
jQuery('.owl-carousel').owlCarousel({
items: 1,
margin: 0,
nav: false,
dots: false,
slideBy: 1,
rewind: false,
autoplay: true,
autoplayTimeout: 5000,
autoplaySpeed: 10000,
loop: true,
animateOut: 'fadeOut',
responsive: false,
mouseDrag: false,
touchDrag: false,
lazyLoadEager: 2
});
jQuery('.owl-carousel').on('changed.owl.carousel', function(event) {
document.querySelector(".progress .bar").style.transitionDuration = "5s";
document.querySelector(".progress").className += " complete";
})
document.querySelector(".progress .bar").addEventListener("transitionend", () => {
document.querySelector(".progress.complete .bar").style.transitionDuration = "5";
document.querySelector(".progress").classList.remove("complete");
});
.progress {
width: 50%;
height: 2em;
border: 1px solid black;
}
.bar {
width: 100%;
background-color: deepskyblue;
color: white;
text-align: center;
line-height: 2em;
transition-property: width;
transition-timing-function: linear;
}
.progress.complete .bar {
width: 0%;
}
button {
margin-top: 1em;
}
<div class="progress">
<div class="bar">Loading...</div>
</div>
<button>
Start
</button>
I have got a basic video player and i followed a tutorial on how to create it, but when you click on the play button, then nothing happens as it does not play the video. Also I have got a red bar on the video as the progress, which is displayed all the time, but i only want it to be displayed on hove, so how can I achieve this as i followed the same youtube video as above.
I have followed a youtube and searched the internet, but i have been unable to fin a solution.
HTML
<div class="c-video">
<video class="galaxy-video" src="../videoplayer/intro.mkv"></video>
<div class="controls">
<div class="blue-bar">
<div class="blue-juice"></div>
</div>
<div class="buttons">
<button id="play-pause"></button>
</div>
</div>
</div>
CSS
.galaxy-video{
width: 100%;
height: 700px;
}
.c-video{
width: 100%;
position: relative;
overflow: hidden;
}
.c-video:hover .controls{
transform: translateY(0);
}
.controls{
display: flex;
position: absolute;
bottom: 5px;
width: 1245px;
margin-left: 155px;
flex-wrap: wrap;
background: rgba(0, 0, 0, 0.7);
transform: translateY(100%);
transition: all 0.2s;
}
.buttons{
padding: 10px;
}
.buttons button{
background: none;
border:0;
outline: 0;
cursor: pointer;
}
.buttons button:before{
content: '\f144';
font-family: 'Font Awesome 5 Free';
width: 30px;
height: 30px;
display: inline-block;
font-size: 28px;
color: #fff;
-webkit-font-smoothing: antialiased;
}
.buttons button.play:before{
content: '\f144';
}
.buttons button.pause:before{
content: '\f28b';
}
.blue-bar{
height: 10px;
top: 0;
left:0;
width: 100%;
background: #000;
}
.blue-juice{
height:10px;
background-color: #ff0000;
}
Javascript
var video = document.querySelector(".galaxy-video");
var juice = document.querySelector(".blue-juice");
var btn = document.getElementById("play-pause");
function togglePlayPause() {
if (video.paused) {
btn.className = "pause";
video.play();
} else {
btn.className = "play";
video.pause();
}
}
btn.onclick = function() {
togglePlayPause();
};
Here is a screen shot of the red bar that i wish to only be displayed on hover:
https://imgur.com/AqtYNg4
Any help appreciated and thanks in advance.
(1)
"When you click on the play button, then nothing happens as it does not play the video."
You need to attach a listener to your button (listening for a "click" event).
<button id="play-pause" onClick="togglePlayPause();"> </button>
Then that should respond to your function togglePlayPause like this...
function togglePlayPause()
{
if (video.paused) { video.play(); btn.className = "pause"; }
else { video.pause(); btn.className = "play"; }
}
(2)
"Also I have got a red bar on the video as the progress, which is displayed all the time, but I only want it to be displayed on hover"
Simply add a "Hover" rule to the CSS of your target element.
.myDivID :hover {
//some hover-related code here...
}
The final setup could look like:
a) The target div is styled to have zero opacity (now is fully transparent).
<div class="blue-bar" style="opacity: 0">
b) Then your CSS rules would be like below (where opacity is animated to increase to 1.0)...
.blue-bar{
height: 10px;
top: 0;
left:0;
width: 100%;
background: #000;
}
.blue-bar:hover {
opacity: 1.0;
transition: transform 1.5s;
}
.blue-juice{
height:10px;
background-color: #ff0000;
}