JSFiddle - React, Tailwind, and code Playground
HTML
<!DOCTYPE html>
<html lang="en" >
<head>
<meta charset="UTF-8">
<title>Update</title>
<link rel="stylesheet" href="./style.css">
</head>
<body>
<form id="form">
<div id="up" class="loading-dock">
<svg id="load-b" x="0px" y="0px" viewBox="0 0 150 150">
<circle class="loading-inner" cx="75" cy="75" r="60"/>
</svg>
<svg id="load" x="0px" y="0px" viewBox="0 0 150 150">
<circle class="loading-inner" cx="75" cy="75" r="60"/>
</svg>
<button type="submit" class="submit">Update</button>
<svg id="check" style="width:24px;height:24px" viewBox="0 0 24 24">
<path fill="#FFFFFF" d="M9,20.42L2.79,14.21L5.62,11.38L9,14.77L18.88,4.88L21.71,7.71L9,20.42Z" />
</svg>
</div>
</form>
<div id="content"></div>
<!-- partial -->
<script src="./script.js"></script>
</body>
</html>
CSS
@import url(https://fonts.googleapis.com/css?family=Roboto:400,300);
html {
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
html, body {
height: 100%;
width: 100%;
}
body {
font-family: 'Helvetica Neue', 'Roboto', sans-serif;
display: flex;
justify-content: center;
align-items: center;
}
.loading-dock {
background-color: white;
width: 300px;
height: 200px;
display: flex;
justify-content: center;
align-items: center;
}
button.submit {
cursor: pointer;
width: 160px;
height: 50px;
font-size: 17px;
font-weight: 600;
color: #58c996;
background-color: white;
border-radius: 40px;
border: 2px solid #58c996;
transition: all .2s;
letter-spacing: 1px;
font-family: 'Helvetica Neue', sans-serif;
}
button.submit:hover {
background: #58c996;
color: white;
}
button.submit:active {
transform: scale(0.95);
}
button.submit:focus {
outline: none;
background: #58c996;
color: white;
}
button.submit.popout {
animation: circle-to-button .5s linear forwards;
}
button.submit.return {
animation: fade-to-original .3s linear;
}
button.submit.return:hover {
background: #58c996;
color: white;
}
.loaded button.submit {
background-color: #58c996;
animation: button-to-circle .5s linear forwards;
animation-delay: .3s;
}
.loaded #load {
animation: loading-circle 3s linear forwards;
animation-delay: 1s;
}
#load, #load-b {
display: none;
position: absolute;
width: 58px;
height: 58px;
opacity: 0;
}
#load .loading-inner, #load-b .loading-inner {
stroke-dasharray: 900;
stroke-width: 8;
stroke-miterlimit: 10;
stroke-linecap: round;
stroke: #c3c3c3;
fill: transparent;
}
#load-b {
opacity: 0;
}
#load-b .loading-inner {
stroke: #58c996;
}
svg {
position: absolute;
display: none;
}
@keyframes loading-circle {
0% {
opacity: 1;
stroke-dashoffset: 0;
}
50% {
opacity: 1;
stroke-dashoffset: -100;
}
100% {
opacity: 1;
...
JavaScript
$('#form').submit(function () {
$.ajax({
method: "GET",
url: "https://jsonplaceholder.typicode.com/todos/1",
// data: $("#form").serialize(),
beforeSend: function (xhr) {
// inicia a transição do botão
$('.loading-dock').addClass('loaded');
$('#load').css('display', 'initial');
$('#load-b').css('display', 'initial');
setTimeout(function(){
$('#load').css('opacity', 1);
}, 750);
setTimeout(function(){
$('#load-b').css('opacity', 1);
}, 900);
},
success: function(data){
alert('deu certo..' + JSON.stringify(data));
// quando der tudo OK, eu reseto o botão
// colocado esse time out apenas para garantir que o timeout do beforeSend tenha sido executado.
setTimeout(function(){
$('.loading-dock').removeClass('loaded');
$('#load').css('display', 'none').css('opacity', 0);
$('#load-b').css('display', 'none').css('opacity', 0);
$('.submit').addClass('popout').html("");
setTimeout(function(){
$('#check').css("display", "block");
}, 300);
//reset all
setTimeout(function(){
$('.submit').removeClass("popout").addClass("return").html("Update");
$('#check').css("display", "none");
}, 1500);
}, 900);
},
error: function(a,b,c) {
// aqui você trata o erro...
alert('erro...');
}
});
return false;
});