I made a program showing the price for BTC and i was going to make an chrome extension out of it.
But sadly, i wrote it in PHP. which google extensions does not support.
I looked up a script on Codepen.io to see if it will work at all,
and i found this one - https://codepen.io/magnificode/pen/KyMMOB?q=bitcoin+price+&limit=all&type=type-pens
JS file ->
const app = new Vue({
el: '.btc-badge',
data: {
btcUSD: '0.00',
upDown: 'up',
},
mounted() {
this.getInfo();
setInterval(()=> {
this.getInfo();
}, 1000*60);
},
methods: {
getInfo() {
axios.get('https://api.coindesk.com/v1/bpi/currentprice.json')
.then(response => {
const oldPrice = this.btcUSD
const newPrice = parseFloat(response.data.bpi.USD.rate_float).toFixed(2)
if (newPrice > oldPrice) {
this.upDown = 'up'
} else {
this.upDown = 'down'
}
this.btcUSD = newPrice
});
}
},
});
CSS file ->
body,html {
height: 100%;
}
body {
-webkit-font-smoothing: antialiased;
background-image: linear-gradient(to right, #ece9e6, #ccc);
font-smoothing: antialiased;
align-items: center;
color: #fafafa;
display: flex;
font-family: "macha";
height: 100%;
justify-content: center;
}
.card {
align-items: center;
background-image: linear-gradient(to top right, #141e30, #243b55);
border-radius: .4em;
box-shadow: 0 0 66px rgba(#000, 0.3);
display: flex;
flex-direction: column;
flex-wrap: wrap;
justify-content: center;
overflow: hidden;
padding: 1em;
position: relative;
width: 250px;
height: 300px;
z-index: 0;
&:after {
mix-blend-mode: overlay;
border: 1px solid #eee;
border-radius: .4em;
content: '';
height: calc(100% - 2em);
left: 0;
margin: 1em;
position: absolute;
top: 0;
width: calc(100% - 2em);
z-index: 1;
}
}
h1 {
letter-spacing: 0.05em;
margin: 0;
}
p {
margin: 0;
}
.up {
color: #42ffa8;
}
.down {
color: #ff0740;
&:after {
transform: rotate(180deg);
}
}
.up,
.down {
align-items: center;
display: flex;
&:after{
border-style: solid;
border-width: 0 5px 5px 5px;
border-color: transparent transparent currentColor transparent;
content: "";
height: 0;
margin-left: .5em;
margin-top: .1em;
width: 0;
}
}
svg {
bottom: -50%;
fill: #999;
left: -20%;
mix-blend-mode: overlay;
position: absolute;
transform: scaleX(-1);
width: 150%;
z-index: -1;
}
and the html file ->
try{Typekit.load({ async: true });}catch(e){}
<div class="btc-badge">
<div class="card">
<p>Current Bitcoin price</p>
<h1>${{ btcUSD }}</h1>
<p :class="upDown">{{upDown}}</p>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 125"><path d="M50 30L30 40 10 10v80h80V50L70 60"/></svg>
</div>
</doesnt took the code and put it in a folder, uploaded it and i pressed the little icon for my app. but now i saw that the prices doesn't show up.
Does anyone of you have any idea as to why this is happening?
Thanks - Jonas.
Related
I have a problem with my code that I use for item descriptions in my Prestashop store. The point is that when I add a description in html to the store, I do not provide the "ALT" attribute of the photo. I have scripts that do this automatically.
Here is the html code that I add to the full description of the item:
<img class="img" src="https://static.vecteezy.com/system/resources/previews/000/547/596/original/hearts-icons-vectors-illustrations.jpg" width="200" height="300">
After saving the changes, the code displayed in the browser looks like this:
<img class="img" src="https://static.vecteezy.com/system/resources/previews/000/547/596/original/hearts-icons-vectors-illustrations.jpg" alt="hearts icons vectors illustrations" width="200" height="300"><p class="alt">hearts-icons-vectors-illustrations.jpg</p>
The second part of the code that was added by the script is used to display the name of the photo when hovering over it.
And here is the problem. The point is that the script adds the same data that another script adds to the "ALT" of the photo. Without "-" and ".jpg" characters.
JS and CSS files are in the theme folder: "custom css" and "custom JS"
Here is the full code that I am using in my Prestashop store:
$(".img").wrap('<div class="alt-wrap"/>');
$(".img").each(function () {
$(this).after('<p class="alt">' + $(this).attr("alt") + "</p>");
});
$(document).ready(function () {
$("img").each(function () {
var $img = $(this);
var filename = $img.attr("src");
if (typeof attr == typeof undefined || attr == false) {
var altText = filename.substring(
filename.lastIndexOf("/") + 1,
filename.lastIndexOf(".")
);
altText = altText.replace("-", " ").replace(".jpg", "");
$img.attr("alt", altText);
}
});
});
.img2 {
max-width: 100%;
height: 100%;
margin: 0;
padding: 0px;
column-count: max-width;
background-color: white;
}
.img-wrap {
display: flex;
flex-wrap: wrap;
flex-direction: row;
justify-content: space-around;
}
.img {
display: block;
}
.alt-wrap {
display: block;
position: relative;
margin: 20px;
color: whitesmoke;
border: 5px solid transparent;
border-image: linear-gradient(to right, green 25%, yellow 25%, yellow 50%,red 50%, red 75%, magenta 75%) 5;
}
.alt-wrap p.alt {
position: absolute;
opacity: 0;
left: 0; right: 0; bottom: 0;
margin: 0;
padding: 15px;
font-size: 14px;
line-height: 22px;
background-color: transparent;
transition: all 10ms linear;
transition-delay: 300ms;
text-align: center;
}
.alt-wrap:hover > p.alt {
opacity: 1;
transition-delay: 0s;
text-align: center;
font-weight: 900;
color: white;
font-size: 150%;
border: 20px solid transparent;
margin-left: 1%;
margin-right: 1%;
text-shadow: 0 0 10px black;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="img2"><div class="img-wrap"><img class="img" src="https://static.vecteezy.com/system/resources/previews/000/547/596/original/hearts-icons-vectors-illustrations.jpg" width="200" height="300">
How can I change/optimize the above codes so that the name of the photo is displayed without the "-" and ".jpg" signs after hovering the mouse cursor?
Here on hover it shows "undefined" on my website it shows "hearts-icons-vectors-illustrations.jpg" I want it to show without "-" and ".jpg".
Prestashop version 1.7.7.3.
it's showing undefined that's why i am doing it by adding innerHTML
$(".alt").html(altText.replace(/-/g, " "));
I just added this line in your code it will replace all - with space so output will be what you want "hearts icons vectors illustrations"
$(".img").wrap('<div class="alt-wrap"/>');
$(".img").each(function () {
$(this).after('<p class="alt">' + $(this).attr("alt") + "</p>");
});
$(document).ready(function () {
$("img").each(function () {
var $img = $(this);
var filename = $img.attr("src");
let text = filename
if (typeof attr == typeof undefined || attr == false) {
var altText = filename.substring(
filename.lastIndexOf("/") + 1,
filename.lastIndexOf(".")
);
altText = altText.replace("-", " ").replace(".jpg", "");
$img.attr("alt", altText);
// it's showing undefined that's why i am doing it by adding innerHTML
$(this).next().html(altText.replace(/-/g, " "));
}
});
});
.img2 {
max-width: 100%;
height: 100%;
margin: 0;
padding: 0px;
column-count: max-width;
background-color: white;
}
.img-wrap {
display: flex;
flex-wrap: wrap;
flex-direction: row;
justify-content: space-around;
}
.img {
display: block;
}
.alt-wrap {
display: block;
position: relative;
margin: 20px;
color: whitesmoke;
border: 5px solid transparent;
border-image: linear-gradient(to right, green 25%, yellow 25%, yellow 50%,red 50%, red 75%, magenta 75%) 5;
}
.alt-wrap p.alt {
position: absolute;
opacity: 0;
left: 0; right: 0; bottom: 0;
margin: 0;
padding: 15px;
font-size: 14px;
line-height: 22px;
background-color: transparent;
transition: all 10ms linear;
transition-delay: 300ms;
text-align: center;
}
.alt-wrap:hover > p.alt {
opacity: 1;
transition-delay: 0s;
text-align: center;
font-weight: 900;
color: white;
font-size: 150%;
border: 20px solid transparent;
margin-left: 1%;
margin-right: 1%;
text-shadow: 0 0 10px black;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="img2"><div class="img-wrap"><img class="img" src="https://static.vecteezy.com/system/resources/previews/000/547/596/original/hearts-icons-vectors-illustrations.jpg" width="200" height="300">
I'm working on an announcement bar for my website, but I got stuck on positioning the "close" button.
The bar itself works just fine, but I couldn't get to position the "close" button at the right of the announcement bar, where you usually find them. I've tried using margin-right, padding and similar solutions but they didn't work.
Also, I wanted to find the best way to make the button disappear (along with the bar) once it's clicked
EDIT: Here's the solution, provided by GrafiCode.
Here's the code and you can see it running here:
HTML:
<div id="dabar" class="hideonload"></div>
CSS:
/* top-bar */
#dabar {
background: #1b1c1e;
color: #fff;
font-size: 14px;
position: fixed;
z-index: 1;
top: 0px;
left: 0px;
width: 100% !important;
padding: 10px 0px;
text-align: center;
}
#dabar a {
color: #b5e48c;
border-bottom: 1px;
}
.btn-close {
margin-left: calc(100vw - 48px);
margin-top: -16px;
border: 0;
padding: 0;
background: red;
border-radius: 50%;
width: 20px;
height: 20px;
display: flex;
flex-flow: nowrap;
justify-content: center;
align-items: center;
cursor: pointer;
transition: all 150ms;
}
.btn-close .icon-cross {
margin: 0;
padding: 0;
border: 0;
background: none;
position: relative;
width: 15px;
height: 15px;
}
.btn-close .icon-cross:before,
.btn-close .icon-cross:after {
content: '';
position: absolute;
top: 6.5px;
left: 0;
right: 0;
height: 2px;
background: #fff;
border-radius: 2px;
}
.btn-close .icon-cross:before {
transform: rotate(45deg);
}
.btn-close .icon-cross:after {
transform: rotate(-45deg);
}
.btn-close .icon-cross span {
display: block;
}
.btn-close:hover,
.btn-close:focus {
transform: rotateZ(90deg);
background: #05c;
}
JAVASCRIPT:
window.onload = function() //executes when the page finishes loading
{
setTimeout(func1, 2500);
};
function func1() {
var el = document.getElementById('dabar');
el.innerHTML = 'Empieza aquí | Start here<button class="btn-close" onclick="this.parentElement.style.display=\'none\'" ><span class="icon-cross"></span></button>';
el.className = 'showtopbar';
}
Thanks a lot for your time!
How do I do this to the progress bar like below:
.detail-load {
height: 42px;
border: 1px solid #A2B2C5;
padding: 1px;
border-radius: 10px;
}
.detail-load > .detail-loading {
background: #904BFF;
height: 100%;
border-radius: 10px;
}
.detail-load-text {
position: absolute;
right: 0;
left: 0;
top: 10px;
text-align: center;
color: #fff;
font-weight: 600;
font-size: 17px;
}
<div class="detail-pop-item">
<div class="detail-load">
<div class="detail-loading" style="width: 80%;"></div>
</div>
<div class="detail-load-text">80%</div>
</div>
The progress bar I want to make is like the image I shared above. Can anyone help?
You could use the clip-path property to achieve your desired result. I included some dummy javascript in the snippet to simulate loading.
You can set --loading-color-primary and --loading-color-secondary to any two colors you'd like.
const front = document.getElementById('progress-front');
const back = document.getElementById('progress-back');
let progress = 0;
setInterval(() => {
front.style.webkitClipPath = `inset(0 0 0 ${progress}%)`;
if(++progress >= 100) {
progress = 0;
}
front.innerHTML = back.innerHTML = progress + "%";
}, 50);
:root {
--loading-color-primary: purple;
--loading-color-secondary: white;
}
.progress {
position: relative;
display: flex;
font-size: 50px;
border: 2px solid var(--loading-color-primary);
overflow: hidden;
width: 100%;
}
.back {
display: flex;
justify-content: center;
align-items: center;
width: 100%;
background: var(--loading-color-primary);
color: var(--loading-color-secondary);
}
.front {
position: absolute;
display: flex;
justify-content: center;
align-items: center;
left: 0;
width: 100%;
right: 0;
top: 0;
bottom: 0;
background: var(--loading-color-secondary);
color: var(--loading-color-primary);
}
<div class="progress">
<div class="back" id="progress-back">0%</div>
<div class="front" id="progress-front">0%</div>
</div>
This is an example of what you want to accomplish:
https://codepen.io/robinrendle/pen/wKqmbW
<div class="wrapper">
<div class="bg">
<div class="el"></div>
</div>
</div>
$loadingTime: 10s;
$color: rgb(255,0,0);
body {
background-color: white;
}
#keyframes loading {
0% {
width: 0;
} 100% {
width: 100%;
}
}
#keyframes percentage {
#for $i from 1 through 100 {
$percentage: $i + "%";
#{$percentage} {
content: $percentage;
}
}
}
.bg {
background-color: $color;
animation: loading $loadingTime linear infinite;
}
.el{
color: $color;
width: 200px;
border: 1px solid $color;
&:after {
padding-left: 20px;
content: "0%";
display: block;
text-align: center;
font-size: 50px;
padding: 10px 20px;
color: rgb(0,255,255);
mix-blend-mode: difference;
animation: percentage $loadingTime linear infinite;
}
}
html {
height: 100%;
background-color: white;
font-family: 'PT Sans', sans-serif;
font-weight: bold;
}
body {
display: flex;
align-items: center;
justify-content: center;
height: 100%;
}
The key item here is the mix-blend-mode property which defines how an element's content should blend with its background.
You can learn more about it here and here.
I used a different approach, where you can set a CSS variable to control the length of the loading progress as well as displaying the value.
Because I used a pseudo-class to display the value, I needed to use a number hack, using counter-reset on the ::after pseudo-element.
As for having the dark text turn white, you can use mix-blend-mode: color-dodge. It's not perfect, as you can see, but perhaps good enough?
.detail-load {
height: 42px;
border: 1px solid #A2B2C5;
padding: 1px;
border-radius: 10px;
}
.detail-load > .detail-loading {
background: #904BFF;
height: 100%;
border-radius: 10px;
/* ADDED */
width: calc(var(--progress) * 1%);
position: relative;
}
.detail-load > .detail-loading::after {
font-weight: 600;
font-size: 17px;
/* ADDED */
counter-reset: number-hack var(--progress);
content: counter(number-hack)"%";
position: absolute;
right: 0px;
top: 50%;
transform: translate(50%, -50%);
color: #d2b6ff;
mix-blend-mode: color-dodge;
}
.detail-load > .detail-loading.grey-text::after {
color: #b5b5b5;
}
<div class="detail-pop-item">
<div class="detail-load">
<div class="detail-loading" style="--progress: 30"></div>
</div>
</div>
<div class="detail-pop-item">
<div class="detail-load">
<div class="grey-text detail-loading" style="--progress: 60"></div>
</div>
</div>
Following Veselin's answer, you just need to change the color attributes as follows:
$color: rgb(255,0,0); becomes $color: rgb(255,0,255);
and
.el{
...
&:after {
...
color: rgb(0,255,255);
}
}
becomes
.el{
...
&:after {
...
color: rgb(0,255,0);
}
}
The result is:
$loadingTime: 10s;
$color: rgb(255,0,255);
body {
background-color: white;
}
#keyframes loading {
0% {
width: 0;
} 100% {
width: 100%;
}
}
#keyframes percentage {
#for $i from 1 through 100 {
$percentage: $i + "%";
#{$percentage} {
content: $percentage;
}
}
}
.bg {
background-color: $color;
animation: loading $loadingTime linear infinite;
}
.el{
color: $color;
width: 200px;
border: 1px solid $color;
&:after {
padding-left: 20px;
content: "0%";
display: block;
text-align: center;
font-size: 50px;
padding: 10px 20px;
color: rgb(0,255,0);
mix-blend-mode: difference;
animation: percentage $loadingTime linear infinite;
}
}
html {
height: 100%;
background-color: white;
font-family: 'PT Sans', sans-serif;
font-weight: bold;
}
body {
display: flex;
align-items: center;
justify-content: center;
height: 100%;
}
I made this iPhone in HTML (Please do not pay attention to the spaghetti code, and it's in german, if it is necessary i can translate it with pleasure):
var time = document.getElementById("time");
var notification = document.getElementById("notification");
var notificationHeader = document.getElementById("notificationHeader");
var notificationDescription = document.getElementById("notificationDescription");
var verificationCode = Math.floor(1000 + Math.random() * 9000);
var input = document.getElementById("instagramNumberText");
var correctOrWrongCheck = document.getElementById("correctOrWrongCheck");
var verificationCodePTag = document.getElementById("verificationCode");
var instagram = document.getElementById("instagramApp");
var mail = document.getElementById("mailApp");
var createAccountButton = document.getElementById("createAccount");
var createAccountForm = document.getElementById("createAccountForm");
var verificationCodeInstagramPage = document.getElementById("verificationCodeInstagramPage");
var controlVerificationCodeButton = document.getElementById("controlVerificationCode");
var continueToInstagramAccountButton = document.getElementById("continueToInstagramAccount");
var verificationCodeEmailDescription = document.getElementById("verificationCodeEmailDescription");
var verificationCodeEmail = document.getElementById("verificationCodeEmail");
var erfolgreichAngemeldet = document.getElementById("erfolgreichAngemeldet");
var instagramAccount = document.getElementById("instagramAccount");
var instagramName = document.getElementById("instagramName");
var instagramNameInput = document.getElementById("instagramNameInput");
// Time
function checkTime(i) {
if (i < 10) {
i = "0" + i;
}
return i;
}
function startTime() {
var today = new Date();
var h = today.getHours();
var m = today.getMinutes();
// add a zero in front of numbers<10
m = checkTime(m);
document.getElementById('time').innerHTML = h + ":" + m;
t = setTimeout(function() {
startTime()
}, 500);
}
startTime();
// Insta
function controlVerificationCode() {
if (input.value == verificationCode) {
correctOrWrongCheck.innerHTML = "Der Code war korrekt!";
continueToInstagramAccountButton.style.display = "block";
continueToInstagramAccountButton.style.margin = "5px auto";
controlVerificationCodeButton.style.display = "none";
} else if (input.value !== verificationCode) {
correctOrWrongCheck.innerHTML = "Der Code ist leider Falsch!";
continueToInstagramAccountButton.style.display = "none";
controlVerificationCodeButton.style.display = "block";
}
}
verificationCodeEmailDescription.innerHTML = "Ihr Bestätigunscode lautet: " + verificationCode;
// OPEN AND CLOSE APPS
function openVerificationCodeInstagramPage() {
createAccountForm.style.display = "none";
verificationCodeInstagramPage.style.display = "block"
verificationCodeEmail.style.display = "block";
instagramName.value = instagramNameInput.value;
notification.style.transform = "translate(-50%, -50%) scale(0)";
notificationDescription.innerHTML = "Ihr Bestätigunscode lautet: ...";
setTimeout(
function() {
notification.style.transform = "translate(-50%, -50%) scale(1)";
}, 1000);
setTimeout(
function() {
notification.style.transform = "translate(-50%, -50%) scale(0)";
}, 7000);
}
function continueToInstagramAccount() {
verificationCodeInstagramPage.style.display = "none";
instagramAccount.style.display = "flex";
erfolgreichAngemeldet.display = "none";
notificationDescription.innerHTML = "Erfolgreich bei Instagram angemeldet"
notification.style.transform = "translate(-50%, -50%) scale(0)";
erfolgreichAngemeldet.style.display = "block";
setTimeout(
function() {
notification.style.transform = "translate(-50%, -50%) scale(1)";
}, 1000);
setTimeout(
function() {
notification.style.transform = "translate(-50%, -50%) scale(0)";
}, 7000);
var counter = 0;
var followers = document.getElementById('followers');
setTimeout(function(){
var st = setInterval(function(){
followers.innerHTML = ++counter;
},100)
},100);
}
function closeNotification() {
notification.style.transform = "translate(-50%, -50%) scale(0)";
}
function openInstagram() {
instagram.style.transform = "scale(1)";
}
function openMail() {
mail.style.transform = "scale(1)";
}
function closeApp() {
instagram.style.transform = "scale(0)";
mail.style.transform = "scale(0)";
}
window.onload = function() {
document.getElementById("instagramNumberText").value = '';
}
* {
margin: 0;
padding: 0;
font-family: 'Roboto',sans-serif;
user-select: none;
}
input:focus, textarea:focus {
outline: 0;
}
#phone {
height: 600px;
width: 350px;
border-radius: 50px;
position: absolute;
top: 600px;
left: 50%;
-ms-transform: translate(-50%, -50%);
transform: translate(-50%, -50%);
border-top: 90px solid;
border-right: 15px solid;
border-left: 15px solid;
border-bottom: 90px solid;
background-image: url("https://ioshacker.com/wp-content/uploads/2019/06/iOS-13-wallpaper.jpg");
background-position: center;
background-repeat: no-repeat;
background-size: cover;
}
.app {
box-shadow: 0 0 9px -4px #000;
}
#topbar {
padding: 0.3em;
color: #fff;
display: flex;
justify-content: space-between;
align-items: center;
height: 20px;
transform: translate(-4%,0) scale(0.9);
width: 370px;
}
#connection {
display: flex;
align-items: center;
width: 110px;
justify-content: space-around;
}
#battery {
display: flex;
align-items: center;
width: 110px;
justify-content: end;
}
#battery .bi-battery-full {
font-size: 23px;
margin-left: 5px;
}
#topbar .bi-wifi-2 {
font-size: 25px;
margin-top: -3px;
}
#time {
text-align: center;
}
#notification {
margin: 0;
position: absolute;
top: 365px;
left: 50%;
-ms-transform: translate(-50%, -50%) scale(0);
transform: translate(-50%, -50%) scale(0);
height: 85px;
width: 315px;
background: #EDEBED;
border-radius: 10px;
z-index: 10000;
transition: all 0.5s;
box-shadow: 0 0 10px -1px #525252;
padding: 0.5em 0 0.5em 1em;
display: flex;
flex-direction: column;
justify-content: center;
}
#notification h1 {
font-size: 23px;
}
#appsOne {
display: flex;
justify-content: space-around;
flex-wrap: wrap;
}
#instagramIcon, #verificationCode, #mailIcon {
margin: 20px;
}
.app {
font-size: 40px;
width: 50px;
height: 50px;
display: flex;
justify-content: center;
align-items: center;
border-radius: 10px;
transition: all 0.2s;
}
.app:hover {
cursor: pointer;
filter: brightness(90%);
}
.bi-instagram, .bi-envelope-fill {
width: 40px;
height: 40px;
color: #fff;
font-family: sans-serif;
}
/* Instagram */
#instagramIcon {
background: linear-gradient(45deg, #f09433 0%,#e6683c 25%,#dc2743 50%,#cc2366 75%,#bc1888 100%);
}
#instagramApp {
position: absolute;
top: 0;
left: 0;
background: #EAEAEA;
height: 100%;
width: 100%;
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
transition: all 0.3s;
transform: scale(0);
z-index: 99999;
text-align: center;
}
.instagramHeader {
font-family: 'Handlee', cursive;
font-size: 35px;
}
.instagramSecondHeader {
font-size: 15px;
width: 260px;
margin: 1em 0;
}
#instagramNameInput, #instagramEmail, #instagramNumberText {
font-size: 15px;
padding: 0.5em;
border: 1px solid #D1D1D1;
margin: 0.5em 0 0.5em 0;
width: 220px;
}
.instagramButton {
width: 236px;
font-size: 15px;
padding: 0.5em;
background: #3296F0;
color: #fff;
border: none;
margin: 0.5em 0;
transition: all 0.2s;
}
.instagramButton:hover {
filter: brightness(80%);
cursor: pointer;
}
#verificationCodeInstagramPage {
display: none;
}
#continueToInstagramAccount {
display: none;
}
#instagramAccount {
display: none;
justify-content: flex-start;
height: 100%;
width: 100%;
background: #f7f7f7;
flex-direction: column;
align-items: center;
}
#instagramName {
font-size: 20px;
text-align: left;
width: 85%;
padding: 20px 20px 15px 10px;
border-bottom: 1px solid gray;
height: 20px;
border-right: none;
border-top: none;
border-left: none;
background: none;
}
#profilePicture {
font-size: 35px;
width: 80px;
height: 80px;
display: flex;
justify-content: center;
align-items: center;
background: #eae9e9;
border-radius: 100000px;
margin: 20px;
border: 1px solid #6f6e6e;
color: #6f6e6e;
}
#instagramPictureAndNumbers {
display: inherit;
width: 360px;
}
#numbers {
width: 225px;
height: 45px;
margin: 35px 0 0 0;
}
#userDescription {
width: 320px;
font-size: 13px;
border: none;
background: none;
resize: none;
}
.bi-table {
font-size: 25px;
border-bottom: 1px solid;
width: 90%;
margin-top: 0.5em;
}
#emptyImages {
color: #c7c7c7;
margin: 100px;
font-size: 14px;
}
/* Mail */
#mailIcon {
background: linear-gradient(0deg, #05ffff 0%, #3cabe6 30%, #2763dc 70%);
}
#mailApp {
position: absolute;
top: 0;
left: 0;
background: #f6f6f6;
height: 100%;
width: 100%;
display: flex;
align-items: center;
justify-content: flex-start;
flex-direction: column;
transition: all 0.3s;
transform: scale(0);
z-index: 99999;
text-align: center;
}
#mailHeader {
font-size: 25px;
padding: 20px;
background: #fff;
width: 88%;
z-index: 999;
}
#verificationCodeEmail {
display: none;
}
.email {
background: #fff;
width: 97%;
padding: 5px;
border-top: 1px solid #e6e6e6;
}
.emailHeader {
text-align: left;
margin: 10px;
font-size: 25px;
}
#verificationCodeEmailDescription, #erfolgreichAngemeldetDescription {
text-align: left;
margin: 10px;
}
#erfolgreichAngemeldet {
display: none;
}
/* Home Button */
#homeButton {
position: absolute;
height: 60px;
width: 60px;
background: transparent;
z-index: 9999;
bottom: -107px;
border-radius: 100000px;
left: 50%;
-ms-transform: translate(-50%, -50%) rotate(-10deg);
transform: translate(-50%, -50%) rotate(-10deg);
border: 1px outset;
cursor: pointer;
}
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons#1.4.1/font/bootstrap-icons.css">
<link rel="preconnect" href="https://fonts.gstatic.com">
<link href="https://fonts.googleapis.com/css2?family=Roboto:wght#100;300;400&display=swap" rel="stylesheet">
<div id="notification" onclick="closeNotification();">
<h1 id="notificationHeader"><b>Neue Email erhalten!</b></h1>
<p id="notificationDescription"></p>
</div>
<div id="phone">
<div id="topbar">
<div id="connection">
<i class="bi bi-bar-chart-fill"></i>
LIDL LTE
<i class="bi bi-wifi-2"></i>
</div>
<p id="time"></p>
<div id="battery">
98%
<i class="bi bi-battery-full"></i>
</div>
</div>
<div id="slider">
<div id="appsOne">
<!-- Instagram -->
<div id="instagramIcon" class="app" onclick="openInstagram();"><i class="bi bi-instagram"></i></div>
<div id="instagramApp">
<form id="createAccountForm" action="#" onsubmit="openVerificationCodeInstagramPage(); return false;">
<h1 class="instagramHeader">Instagram</h1>
<p>Erstelle einen Account</p>
<input type="text" id="instagramNameInput" placeholder="Name" maxlength="12" autocomplete="off" required>
<input type="email" id="instagramEmail" placeholder="E-Mail" autocomplete="off" required>
<button type="submit" id="createAccount" class="instagramButton">Erstellen</button>
</form>
<div id="verificationCodeInstagramPage">
<h1 class="instagramHeader">Bestätigen</h1>
<p class="instagramSecondHeader">Wir haben ihn einen Bestätigungscode per Email gesendet!</p>
<input type="text" id="instagramNumberText" maxlength="4" onkeypress="return /[0-9]/i.test(event.key)" placeholder="Bestätigungscode"><br>
<button onclick="controlVerificationCode();" id="controlVerificationCode" class="instagramButton">Bestätigen</button>
<button class="instagramButton" id="continueToInstagramAccount" onclick="continueToInstagramAccount()">Weiter</button>
<p id="correctOrWrongCheck"></p>
</div>
<div id="instagramAccount">
<input type="text" id="instagramName">
<div id="instagramPictureAndNumbers">
<div id="profilePicture"><i class="bi bi-person-fill"></i></div>
<table id="numbers">
<tr>
<th id="posts">0</th>
<th id="followers">1</th>
<th id="following">0</th>
</tr>
<tr>
<td>Posts</td>
<td>Followers</td>
<td>Following</td>
</tr>
</table>
</div>
<textarea id="userDescription" placeholder="Beschreibung..." rows="10"></textarea>
<i class="bi bi-table"></i>
<p id="emptyImages">No images found</p>
</div>
</div>
<div id="appsTwo">
Second App Page
</div>
</div>
<!-- Mail App -->
<div id="mailIcon" class="app" onclick="openMail();"><i class="bi bi-envelope-fill"></i></div>
<div id="mailApp">
<h1 id="mailHeader">E-Mails</h1>
<div class="email" id="erfolgreichAngemeldet">
<h1 class="emailHeader">Instagram</h1>
<p class="emailDescription" id="erfolgreichAngemeldetDescription">Erfolgreich angemeldet</p>
</div>
<div class="email" id="verificationCodeEmail">
<h1 class="emailHeader">Instagram</h1>
<p class="emailDescription" id="verificationCodeEmailDescription">Ihr Bestätigunscode lautet</p>
</div>
</div>
</div>
<div id="homeButton" onclick="closeApp();"></div>
To see the iPhone better you should click on Full-Page in the snippet.
My problem was that I have 2 divs: #appsOne and #appsTwo which are in the div #slider. On the home page of the iPhone you can see two apps (#appsOne) and a text (#appsTwo) in the middle. The apps (#appsOne) should stay where they are but the text (#appsTwo) should be made on a second page with a horizontal scroll snap. How could I do that?
And here's an image, how it looks like without the slider and the #appsTwo div:
CSS Scroll-snapping
We can seperate the two 'screen's by wrapping each in a div with class panel.
To make the slider scrollable, we have to apply white-space: nowrap to force it into a single line. To make scroll-snap work horizontally, set scroll-snap-type to x and make it mandatory (scroll-snap-type: x mandatory;). This means that:
The visual viewport of this scroll container will rest on a snap point if it isn't currently scrolled. That means it snaps on that point when the scroll action finished, if possible. If content is added, moved, deleted or resized the scroll offset will be adjusted to maintain the resting on that snap point.MDN
We also set overscroll-behavior-x to contain which makes sure that no scroll chaining occurs to neighboring scrolling areas, e.g. underlying elements will not scroll.
We then apply scroll-snap-align: center to .panel. To prevent the overflowing contents in the panels, we also apply white-space: initial.
Result:
https://jsfiddle.net/Spectric/j7br8h5a/
JS Scroll-snapping (mouse drag)
We can take it one step further by adding support for user drag to scroll.
For this, we don't actually need scroll-snap at all. We can do it with pure JS.
Add an event listener for mousedown that sets isDown to true. Record the last position of the mouse.
Add an event listener for mousemove that checks whether the user is currently dragging (isDown == true). If the user is, calculate the distance from the current mouse position and the last mouse position, increment the slider's scrollLeft by the difference, and set the last position to the current position.
Add an event listener for mouseup that sets isDown to false and checks whether the slider's current scrollLeft is bigger than half. If it is, we can use scrollIntoView() on one panel to smoothly scroll it into the viewport.
To prevent scrolling when an app is opened, we can store the status in a variable which we set it to true when one of the open app function is called and false when the closeApp function is called. In the mousemove listener we also check whether this variable is true.
Best viewed in full-page mode
var time = document.getElementById("time");
var notification = document.getElementById("notification");
var notificationHeader = document.getElementById("notificationHeader");
var notificationDescription = document.getElementById("notificationDescription");
var verificationCode = Math.floor(1000 + Math.random() * 9000);
var input = document.getElementById("instagramNumberText");
var correctOrWrongCheck = document.getElementById("correctOrWrongCheck");
var verificationCodePTag = document.getElementById("verificationCode");
var instagram = document.getElementById("instagramApp");
var mail = document.getElementById("mailApp");
var createAccountButton = document.getElementById("createAccount");
var createAccountForm = document.getElementById("createAccountForm");
var verificationCodeInstagramPage = document.getElementById("verificationCodeInstagramPage");
var controlVerificationCodeButton = document.getElementById("controlVerificationCode");
var continueToInstagramAccountButton = document.getElementById("continueToInstagramAccount");
var verificationCodeEmailDescription = document.getElementById("verificationCodeEmailDescription");
var verificationCodeEmail = document.getElementById("verificationCodeEmail");
var erfolgreichAngemeldet = document.getElementById("erfolgreichAngemeldet");
var instagramAccount = document.getElementById("instagramAccount");
var instagramName = document.getElementById("instagramName");
var instagramNameInput = document.getElementById("instagramNameInput");
// Time
function checkTime(i) {
if (i < 10) {
i = "0" + i;
}
return i;
}
function startTime() {
var today = new Date();
var h = today.getHours();
var m = today.getMinutes();
// add a zero in front of numbers<10
m = checkTime(m);
document.getElementById('time').innerHTML = h + ":" + m;
t = setTimeout(function() {
startTime()
}, 500);
}
startTime();
// Insta
function controlVerificationCode() {
if (input.value == verificationCode) {
correctOrWrongCheck.innerHTML = "Der Code war korrekt!";
continueToInstagramAccountButton.style.display = "block";
continueToInstagramAccountButton.style.margin = "5px auto";
controlVerificationCodeButton.style.display = "none";
} else if (input.value !== verificationCode) {
correctOrWrongCheck.innerHTML = "Der Code ist leider Falsch!";
continueToInstagramAccountButton.style.display = "none";
controlVerificationCodeButton.style.display = "block";
}
}
verificationCodeEmailDescription.innerHTML = "Ihr Bestätigunscode lautet: " + verificationCode;
// OPEN AND CLOSE APPS
function openVerificationCodeInstagramPage() {
createAccountForm.style.display = "none";
verificationCodeInstagramPage.style.display = "block"
verificationCodeEmail.style.display = "block";
instagramName.value = instagramNameInput.value;
notification.style.transform = "translate(-50%, -50%) scale(0)";
notificationDescription.innerHTML = "Ihr Bestätigunscode lautet: ...";
setTimeout(
function() {
notification.style.transform = "translate(-50%, -50%) scale(1)";
}, 1000);
setTimeout(
function() {
notification.style.transform = "translate(-50%, -50%) scale(0)";
}, 7000);
}
function continueToInstagramAccount() {
verificationCodeInstagramPage.style.display = "none";
instagramAccount.style.display = "flex";
erfolgreichAngemeldet.display = "none";
notificationDescription.innerHTML = "Erfolgreich bei Instagram angemeldet"
notification.style.transform = "translate(-50%, -50%) scale(0)";
erfolgreichAngemeldet.style.display = "block";
setTimeout(
function() {
notification.style.transform = "translate(-50%, -50%) scale(1)";
}, 1000);
setTimeout(
function() {
notification.style.transform = "translate(-50%, -50%) scale(0)";
}, 7000);
var counter = 0;
var followers = document.getElementById('followers');
setTimeout(function() {
var st = setInterval(function() {
followers.innerHTML = ++counter;
}, 100)
}, 100);
}
function closeNotification() {
notification.style.transform = "translate(-50%, -50%) scale(0)";
}
var isAppOpened = false;
function openInstagram() {
isAppOpened = true;
instagram.style.transform = "scale(1)";
}
function openMail() {
isAppOpened = true;
mail.style.transform = "scale(1)";
}
function closeApp() {
isAppOpened = false;
instagram.style.transform = "scale(0)";
mail.style.transform = "scale(0)";
}
window.onload = function() {
document.getElementById("instagramNumberText").value = '';
}
const slider = document.getElementById("slider");
const panels = document.querySelectorAll('.panel');
var lastX = 0;
var isDown = false;
document.addEventListener("mousedown", function(e) {
lastX = e.pageX;
isDown = true;
})
document.addEventListener("mousemove", function(e) {
if (isDown && !isAppOpened) {
const curX = e.pageX;
const diff = lastX - curX;
slider.scrollLeft += diff;
lastX = curX;
}
})
document.addEventListener("mouseup", function() {
isDown = false;
slider.style.scrollBehavior = "smooth";
if (slider.scrollLeft > 175) {
panels[1].scrollIntoView();
} else {
panels[0].scrollIntoView();
}
slider.style.scrollBehavior = "unset";
})
* {
margin: 0;
padding: 0;
font-family: 'Roboto', sans-serif;
user-select: none;
}
input:focus,
textarea:focus {
outline: 0;
}
#phone {
height: 600px;
width: 350px;
border-radius: 50px;
position: absolute;
top: 600px;
left: 50%;
-ms-transform: translate(-50%, -50%);
transform: translate(-50%, -50%);
border-top: 90px solid;
border-right: 15px solid;
border-left: 15px solid;
border-bottom: 90px solid;
background-image: url("https://ioshacker.com/wp-content/uploads/2019/06/iOS-13-wallpaper.jpg");
background-position: center;
background-repeat: no-repeat;
background-size: cover;
}
.app {
box-shadow: 0 0 9px -4px #000;
}
#topbar {
padding: 0.3em;
color: #fff;
display: flex;
justify-content: space-between;
align-items: center;
height: 20px;
transform: translate(-4%, 0) scale(0.9);
width: 370px;
}
#connection {
display: flex;
align-items: center;
width: 110px;
justify-content: space-around;
}
#battery {
display: flex;
align-items: center;
width: 110px;
justify-content: end;
}
#battery .bi-battery-full {
font-size: 23px;
margin-left: 5px;
}
#topbar .bi-wifi-2 {
font-size: 25px;
margin-top: -3px;
}
#time {
text-align: center;
}
#notification {
margin: 0;
position: absolute;
top: 365px;
left: 50%;
-ms-transform: translate(-50%, -50%) scale(0);
transform: translate(-50%, -50%) scale(0);
height: 85px;
width: 315px;
background: #EDEBED;
border-radius: 10px;
z-index: 10000;
transition: all 0.5s;
box-shadow: 0 0 10px -1px #525252;
padding: 0.5em 0 0.5em 1em;
display: flex;
flex-direction: column;
justify-content: center;
}
#notification h1 {
font-size: 23px;
}
#appsOne {
display: flex;
justify-content: space-around;
flex-wrap: wrap;
}
#instagramIcon,
#verificationCode,
#mailIcon {
margin: 20px;
}
.app {
font-size: 40px;
width: 50px;
height: 50px;
display: flex;
justify-content: center;
align-items: center;
border-radius: 10px;
transition: all 0.2s;
}
.app:hover {
cursor: pointer;
filter: brightness(90%);
}
.bi-instagram,
.bi-envelope-fill {
width: 40px;
height: 40px;
color: #fff;
font-family: sans-serif;
}
/* Instagram */
#instagramIcon {
background: linear-gradient(45deg, #f09433 0%, #e6683c 25%, #dc2743 50%, #cc2366 75%, #bc1888 100%);
}
#instagramApp {
position: absolute;
top: 0;
left: 0;
background: #EAEAEA;
height: 100%;
width: 100%;
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
transition: all 0.3s;
transform: scale(0);
z-index: 99999;
text-align: center;
}
.instagramHeader {
font-family: 'Handlee', cursive;
font-size: 35px;
}
.instagramSecondHeader {
font-size: 15px;
width: 260px;
margin: 1em 0;
}
#instagramNameInput,
#instagramEmail,
#instagramNumberText {
font-size: 15px;
padding: 0.5em;
border: 1px solid #D1D1D1;
margin: 0.5em 0 0.5em 0;
width: 220px;
}
.instagramButton {
width: 236px;
font-size: 15px;
padding: 0.5em;
background: #3296F0;
color: #fff;
border: none;
margin: 0.5em 0;
transition: all 0.2s;
}
.instagramButton:hover {
filter: brightness(80%);
cursor: pointer;
}
#verificationCodeInstagramPage {
display: none;
}
#continueToInstagramAccount {
display: none;
}
#instagramAccount {
display: none;
justify-content: flex-start;
height: 100%;
width: 100%;
background: #f7f7f7;
flex-direction: column;
align-items: center;
}
#instagramName {
font-size: 20px;
text-align: left;
width: 85%;
padding: 20px 20px 15px 10px;
border-bottom: 1px solid gray;
height: 20px;
border-right: none;
border-top: none;
border-left: none;
background: none;
}
#profilePicture {
font-size: 35px;
width: 80px;
height: 80px;
display: flex;
justify-content: center;
align-items: center;
background: #eae9e9;
border-radius: 100000px;
margin: 20px;
border: 1px solid #6f6e6e;
color: #6f6e6e;
}
#instagramPictureAndNumbers {
display: inherit;
width: 360px;
}
#numbers {
width: 225px;
height: 45px;
margin: 35px 0 0 0;
}
#userDescription {
width: 320px;
font-size: 13px;
border: none;
background: none;
resize: none;
}
.bi-table {
font-size: 25px;
border-bottom: 1px solid;
width: 90%;
margin-top: 0.5em;
}
#emptyImages {
color: #c7c7c7;
margin: 100px;
font-size: 14px;
}
/* Mail */
#mailIcon {
background: linear-gradient(0deg, #05ffff 0%, #3cabe6 30%, #2763dc 70%);
}
#mailApp {
position: absolute;
top: 0;
left: 0;
background: #f6f6f6;
height: 100%;
width: 100%;
display: flex;
align-items: center;
justify-content: flex-start;
flex-direction: column;
transition: all 0.3s;
transform: scale(0);
z-index: 99999;
text-align: center;
}
#mailHeader {
font-size: 25px;
padding: 20px;
background: #fff;
width: 88%;
z-index: 999;
}
#verificationCodeEmail {
display: none;
}
.email {
background: #fff;
width: 97%;
padding: 5px;
border-top: 1px solid #e6e6e6;
}
.emailHeader {
text-align: left;
margin: 10px;
font-size: 25px;
}
#verificationCodeEmailDescription,
#erfolgreichAngemeldetDescription {
text-align: left;
margin: 10px;
}
#erfolgreichAngemeldet {
display: none;
}
/* Home Button */
#homeButton {
position: absolute;
height: 60px;
width: 60px;
background: transparent;
z-index: 9999;
bottom: -107px;
border-radius: 100000px;
left: 50%;
-ms-transform: translate(-50%, -50%) rotate(-10deg);
transform: translate(-50%, -50%) rotate(-10deg);
border: 1px outset;
cursor: pointer;
}
#slider {
white-space: nowrap;
position: relative;
overflow-x: scroll;
overflow-y: hidden;
-webkit-overflow-scrolling: touch;
height: calc(100% - 30px);
}
.panel {
display: inline-block;
width: 350px;
white-space: initial;
}
#appsTwo {
display: flex;
justify-content: space-around;
flex-wrap: wrap;
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons#1.4.1/font/bootstrap-icons.css">
<link rel="preconnect" href="https://fonts.gstatic.com">
<link href="https://fonts.googleapis.com/css2?family=Roboto:wght#100;300;400&display=swap" rel="stylesheet">
</head>
<body>
<div id="notification" onclick="closeNotification();">
<h1 id="notificationHeader"><b>Neue Email erhalten!</b></h1>
<p id="notificationDescription"></p>
</div>
<div id="phone">
<div id="topbar">
<div id="connection">
<i class="bi bi-bar-chart-fill"></i> LIDL LTE
<i class="bi bi-wifi-2"></i>
</div>
<p id="time"></p>
<div id="battery">
98%
<i class="bi bi-battery-full"></i>
</div>
</div>
<div id="slider">
<div class="panel">
<div id="appsOne">
<!-- Instagram -->
<div id="instagramIcon" class="app" onclick="openInstagram();"><i class="bi bi-instagram"></i></div>
<div id="instagramApp">
<form id="createAccountForm" action="#" onsubmit="openVerificationCodeInstagramPage(); return false;">
<h1 class="instagramHeader">Instagram</h1>
<p>Erstelle einen Account</p>
<input type="text" id="instagramNameInput" placeholder="Name" maxlength="12" autocomplete="off" required>
<input type="email" id="instagramEmail" placeholder="E-Mail" autocomplete="off" required>
<button type="submit" id="createAccount" class="instagramButton">Erstellen</button>
</form>
<div id="verificationCodeInstagramPage">
<h1 class="instagramHeader">Bestätigen</h1>
<p class="instagramSecondHeader">Wir haben ihn einen Bestätigungscode per Email gesendet!
</p>
<input type="text" id="instagramNumberText" maxlength="4" onkeypress="return /[0-9]/i.test(event.key)" placeholder="Bestätigungscode"><br>
<button onclick="controlVerificationCode();" id="controlVerificationCode" class="instagramButton">Bestätigen</button>
<button class="instagramButton" id="continueToInstagramAccount" onclick="continueToInstagramAccount()">Weiter</button>
<p id="correctOrWrongCheck"></p>
</div>
<div id="instagramAccount">
<input type="text" id="instagramName">
<div id="instagramPictureAndNumbers">
<div id="profilePicture"><i class="bi bi-person-fill"></i></div>
<table id="numbers">
<tr>
<th id="posts">0</th>
<th id="followers">1</th>
<th id="following">0</th>
</tr>
<tr>
<td>Posts</td>
<td>Followers</td>
<td>Following</td>
</tr>
</table>
</div>
<textarea id="userDescription" placeholder="Beschreibung..." rows="10"></textarea>
<i class="bi bi-table"></i>
<p id="emptyImages">No images found</p>
</div>
</div>
<div id="mailIcon" class="app" onclick="openMail();"><i class="bi bi-envelope-fill"></i></div>
<div id="mailApp">
<h1 id="mailHeader">E-Mails</h1>
<div class="email" id="erfolgreichAngemeldet">
<h1 class="emailHeader">Instagram</h1>
<p class="emailDescription" id="erfolgreichAngemeldetDescription">Erfolgreich angemeldet</p>
</div>
<div class="email" id="verificationCodeEmail">
<h1 class="emailHeader">Instagram</h1>
<p class="emailDescription" id="verificationCodeEmailDescription">Ihr Bestätigunscode lautet
</p>
</div>
</div>
</div>
</div>
<div class="panel">
<div id="appsTwo">
<div>
Second App Page
</div>
</div>
</div>
</div>
<div id="homeButton" onclick="closeApp();"></div>
</div>
</body>
</html>
Result:
You can hide the horizontal scrollbar by applying overflow-x:hidden to #slider
Is there a way I can hard code a number into the code instead of having "Goals completed: " and the progress bar still complete based on percentage? I do not want the users to see "Goals Completed" or have a input bar where they enter a number. I want to do all of that behind the scenes.
What I am really trying to do is get rid of the whole "Goals Completed: (input box)" prompt. So that I, for example, can just hard code: goals = 69 and then the progress circle reacts and shows 60% in the middle and 69 of 115 goals completed AND the green circle on the outside matches that. I do not want the user to be able to enter anywhere how many goals were completed or see a input prompt. I want to only be able to modify the number of goals completed behind the scenes in the JS code.
Here is my current code:
document.querySelector('.goals').addEventListener('change', function() {
var goals = parseInt(this.value);
var circle = document.querySelector('circle');
var percentdiv = document.querySelector('.percent');
var completed = document.querySelector('.completed');
completed.innerHTML = goals;
var totaldiv = document.querySelector('.total');
var total = totaldiv.innerHTML;
var pc = goals * 100 / total;
var r = circle.getAttribute('r').replace('%', '') * percentdiv.clientWidth / 100; //actual radius of the circle
var c = Math.PI * (r * 2); //circumference is 2*pi*r
if (isNaN(goals)) {
pc = 100;
} else if (pc < 0) {
pc = 0;
} else if (pc > 100) {
pc = 100;
}
document.querySelector('.number h2').innerHTML = Math.floor(pc) + '<span>%</span>';
var length = pc * c / 100;
circle.style.strokeDasharray = length + ' ' + (c - length);
circle.style.strokeWidth = (length > 0) ? '5%' : 0;
});
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
#progress-bar {
position: absolute;
left: 50%;
top: 55%;
transform: translate(-51%, -50%);
width: 40%;
}
.container {
position: relative;
width: 100%;
display: flex;
justify-content: space-around;
}
.container .card {
position: relative;
width: 400px;
display: flex;
justify-content: center;
align-items: center;
height: 400px;
border-radius: 4px;
text-align: center;
overflow: hidden;
transition: 0.5s;
}
.container .card:before {
content: '';
position: absolute;
top: 0;
left: -50%;
width: 100%;
height: 100%;
background: rgba(255, 255, 255, 0.03);
pointer-events: none;
z-index: 1;
}
.percent {
position: relative;
width: 300px;
height: 300px;
border-radius: 50%;
border-color: transparent;
border-width: 0;
border-style: none;
rbox-shadow: inset 0 0 50px #000;
background-image: radial-gradient(#444 0%, #222 70%, transparent 70%, transparent 100%);
rbackground: #222;
z-index: 1000;
}
.percent .number {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
border-radius: 50%;
}
.percent .number h2 {
color: #777;
font-weight: 700;
font-size: 40px;
transition: 0.5s;
}
.card:hover .percent .number h2 {
color: #fff;
font-size: 60px;
}
.percent .number h2 span {
font-size: 24px;
color: #777;
transition: 0.5s;
}
.card:hover .percent .number h2 span {
color: #fff;
}
.text {
position: relative;
color: #777;
margin-top: 40px;
font-weight: 700;
font-size: 18px;
letter-spacing: 1px;
text-transform: uppercase;
transition: 0.5s;
}
svg {
width: 100%;
height: 100%;
z-index: 1000;
}
svg circle {
fill: none;
stroke-width: 0;
stroke-linecap: round;
stroke: #00ff43;
}
<div class="container">
<div class="card">
<div class="box">
<div class="percent">
<svg>
<circle cx="50%" cy="50%" r="47.5%"></circle>
</svg>
<div class="number">
<h2>0<span>%</span></h2>
</div>
</div>
<h2 class="text"><span class="completed">0</span> of <span class="total">115</span> Goals Completed</h2>
</div>
</div>
</div>
Goals completed: <input class="goals" type='number' />
Rather than having your logic for updating the circle stored in the event handler for the input, have it as a separate function which you can then call with any number, e.g. setGoals(50) would update the circle to say 50 of 115 goals completed and 43%.
You can then optionally include the input box to change the displayed value in the circle, or just call setGoals(<some number here>) anywhere in your code.
This gives you the code snippet:
function setGoals(goals) {
const circle = document.querySelector('circle');
const percentdiv = document.querySelector('.percent');
const completed = document.querySelector('.completed');
completed.innerHTML = goals;
const totaldiv = document.querySelector('.total');
const total = totaldiv.innerHTML;
let pc = goals * 100 / total;
const r = circle.getAttribute('r').replace('%', '') * percentdiv.clientWidth / 100; //actual radius of the circle
const c = Math.PI * (r * 2); //circumference is 2*pi*r
if (isNaN(goals)) {
pc = 100;
} else if (pc < 0) {
pc = 0;
} else if (pc > 100) {
pc = 100;
}
document.querySelector('.number h2').innerHTML = Math.floor(pc) + '<span>%</span>';
const length = pc * c / 100;
circle.style.strokeDasharray = length + ' ' + (c - length);
circle.style.strokeWidth = (length > 0) ? '5%' : 0;
}
// For testing purposes, set up the input box to edit the number of displayed goals
document.querySelector('.goals').addEventListener('change', (e) => {
const goals = parseInt(e.target.value);
setGoals(goals);
});
// On page load, manually set the goals to 50 for demonstration purposes
setGoals(50);
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
#progress-bar {
position: absolute;
left: 50%;
top: 55%;
transform: translate(-51%, -50%);
width: 40%;
}
.container {
position: relative;
width: 100%;
display: flex;
justify-content: space-around;
}
.container .card {
position: relative;
width: 400px;
display: flex;
justify-content: center;
align-items: center;
height: 400px;
border-radius: 4px;
text-align: center;
overflow: hidden;
transition: 0.5s;
}
.container .card:before {
content: '';
position: absolute;
top: 0;
left: -50%;
width: 100%;
height: 100%;
background: rgba(255, 255, 255, 0.03);
pointer-events: none;
z-index: 1;
}
.percent {
position: relative;
width: 300px;
height: 300px;
border-radius: 50%;
border-color: transparent;
border-width: 0;
border-style: none;
rbox-shadow: inset 0 0 50px #000;
background-image: radial-gradient(#444 0%, #222 70%, transparent 70%, transparent 100%);
rbackground: #222;
z-index: 1000;
}
.percent .number {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
border-radius: 50%;
}
.percent .number h2 {
color: #777;
font-weight: 700;
font-size: 40px;
transition: 0.5s;
}
.card:hover .percent .number h2 {
color: #fff;
font-size: 60px;
}
.percent .number h2 span {
font-size: 24px;
color: #777;
transition: 0.5s;
}
.card:hover .percent .number h2 span {
color: #fff;
}
.text {
position: relative;
color: #777;
margin-top: 40px;
font-weight: 700;
font-size: 18px;
letter-spacing: 1px;
text-transform: uppercase;
transition: 0.5s;
}
svg {
width: 100%;
height: 100%;
z-index: 1000;
}
svg circle {
fill: none;
stroke-width: 0;
stroke-linecap: round;
stroke: #00ff43;
}
<div class="container">
<div class="card">
<div class="box">
<div class="percent">
<svg>
<circle cx="50%" cy="50%" r="47.5%"></circle>
</svg>
<div class="number">
<h2>0<span>%</span></h2>
</div>
</div>
<h2 class="text"><span class="completed">0</span> of <span class="total">115</span> Goals Completed</h2>
</div>
</div>
</div>
Goals completed: <input class="goals" type='number' />
...It's a little difficult to test here on Stack Overflow, but if you call setGoals(50) (or another number) then it'll update the displayed goals in the circle. I added the line setGoals(50) to the above code snippet as an example to show 50 goals on page load.