Last active
June 19, 2023 16:36
-
-
Save ryanlucas/20e5cd5749ffae86cc6289ab829600ec to your computer and use it in GitHub Desktop.
Animated Button
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Animated Button | |
Go | |
click -> Loading | |
Loading | |
successful -> Success | |
failure -> Error | |
Success | |
reset -> Go | |
Error | |
reset -> Go |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function add_styles(css_str){ | |
const StyleID = 'sketch_styles'; | |
let $s = document.querySelector('#' + StyleID); | |
if(null === $s){ | |
$s = document.createElement('style'); | |
$s.id = StyleID | |
document.head.appendChild($s) | |
} | |
$s.innerText = css_str.replace(/\r?\n|\r/g,''); | |
} | |
// Define CSS | |
add_styles(` | |
.animated-button { | |
background: white; | |
border: none; | |
border-radius: 60px; | |
box-shadow: 0 2px 8px rgba(0,0,0,0.1); | |
font-family: Corbel, "Lucida Grande", "Lucida Sans Unicode", "Lucida Sans", "DejaVu Sans", "Bitstream Vera Sans", "Liberation Sans", Verdana, "Verdana Ref", sans-serif; | |
font-size: 18px; | |
outline: none; | |
cursor: pointer; | |
font-weight: bolder; | |
letter-spacing: -0.4px; | |
display: flex; | |
flex-direction: row; | |
align-items: center; | |
justify-content: center; | |
transition: all 300ms ease-in; | |
height: 60px; | |
width: 60px; | |
color: #2ea5bd; | |
} | |
.animated-button[data-state="Go"] { | |
width: 140px; | |
} | |
.animated-button[data-state="Success"] { | |
background: #51c191; | |
} | |
.animated-button[data-state="Error"] { | |
background: #fd775f; | |
animation-name: shake; | |
animation-iteration-count: 1; | |
animation-timing-function: ease-in-out; | |
animation-duration: 600ms; | |
animation-delay: 300ms; | |
} | |
.animated-button .icon { | |
background: red; | |
width: 28px; | |
height: 28px; | |
pointerEvents: none; | |
} | |
[data-state="Go"] .icon { | |
background: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32"><defs><style>.a{fill:%2322a7c2;}</style></defs><path class="a" d="M18.54,5.13a1,1,0,0,0-1.41-.07L15.65,6.4a1,1,0,0,0-.08,1.42l4.91,5.42c.37.41.22.74-.33.74H4.39a1,1,0,0,0-1,1v2a1,1,0,0,0,1,1H20.47c.55,0,.69.33.31.73l-5.15,5.42a1,1,0,0,0,0,1.41l1.45,1.38a1,1,0,0,0,1.42,0L27.92,17a1.1,1.1,0,0,0,0-1.47Z"/></svg>'); | |
background-repeat: no-repeat; | |
background-size: contain; | |
} | |
[data-state="Loading"] .icon { | |
background: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32"><defs><style>.a{fill:%2322a7c2;}</style></defs><path class="a" d="M19.57,2.33h0a1.45,1.45,0,0,0,.9,1.47,12.56,12.56,0,1,1-17,11.73,12.42,12.42,0,0,1,.8-4.37,1.17,1.17,0,0,0-.7-1.52l-.12-.05a1.58,1.58,0,0,0-2,.95,15.13,15.13,0,0,0-.8,6A15.47,15.47,0,1,0,21.51,1.09,1.45,1.45,0,0,0,19.57,2.33Z"/></svg>'); | |
background-repeat: no-repeat; | |
background-size: contain; | |
animation-name: spinning; | |
animation-iteration-count: infinite; | |
animation-timing-function: linear; | |
animation-duration: 1s; | |
} | |
[data-state="Success"] .icon { | |
background: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32"><defs><style>.a{fill:%23fff;}</style></defs><path class="a" d="M28,7.82a2.51,2.51,0,0,0-4.47-1.19L13.18,20.12a.22.22,0,0,1-.19.09.21.21,0,0,1-.15-.06L8.17,16.06a2.55,2.55,0,0,0-1.65-.61,2.5,2.5,0,0,0-1.88.85,2.52,2.52,0,0,0,.23,3.53l6.69,5.84a2.73,2.73,0,0,0,4-.39L27.47,9.67A2.5,2.5,0,0,0,28,7.82Z"/></svg>'); | |
background-repeat: no-repeat; | |
background-size: contain; | |
animation-name: spin-in; | |
animation-iteration-count: 1; | |
animation-timing-function: linear; | |
animation-duration: 300ms; | |
} | |
[data-state="Error"] .icon { | |
background: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32"><defs><style>.a{fill:%23fff;}</style></defs><path class="a" d="M16,27.36a2.89,2.89,0,0,1-2.19-.7,2.44,2.44,0,0,1-.66-1.73v-.77a2.44,2.44,0,0,1,.66-1.73,2.89,2.89,0,0,1,2.19-.7,2.89,2.89,0,0,1,2.19.7,2.44,2.44,0,0,1,.66,1.73v.77a2.44,2.44,0,0,1-.66,1.73A2.89,2.89,0,0,1,16,27.36Zm-1-7.42-1.5-9.09V4.64h5v6.21l-1.47,9.09Z"/></svg>'); | |
background-repeat: no-repeat; | |
background-size: contain; | |
animation-name: spin-in; | |
animation-iteration-count: 1; | |
animation-timing-function: linear; | |
animation-duration: 300ms; | |
} | |
@keyframes spinning { | |
from { transform:rotate(0deg); } | |
to { transform:rotate(360deg); } | |
} | |
@keyframes spin-in { | |
0% { transform:rotate(-90deg); } | |
50% { transform:rotate(20deg); } | |
100% { transform:rotate(0deg); } | |
} | |
@keyframes shake { | |
from, | |
to { | |
transform: translate3d(0, 0, 0); | |
} | |
10%, | |
30%, | |
50%, | |
70%, | |
90% { | |
transform: translate3d(-4px, 0, 0); | |
} | |
20%, | |
40%, | |
60%, | |
80% { | |
transform: translate3d(4px, 0, 0); | |
} | |
} | |
`); | |
function render(model){ | |
const current_state_name = model.active_states[0].name; | |
let events = { | |
Go: ["click"], | |
Loading: ["successful", "failure"], | |
Error: ["reset"], | |
Success: ["reset"] | |
} | |
return <div style={{background: "#fff0ed",height: "100%", display: "flex", flexDirection: "row", alignItems: "center", justifyContent: "center"}}> | |
<button class="animated-button" data-state={current_state_name} | |
onClick={() => model.emit(events[current_state_name][Math.floor(Math.random()*events[current_state_name].length)])}> | |
<div class="icon" ></div> | |
</button> | |
</div>; | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment