<div id="content"></div>
//usual reset stuff
*,
*:before,
*:after,
ul,
li,
a,
button,
input,
h1,
h2,
h3,
h4,
h5,
h6,
p,
img,
image,
svg,
path,
g,
canvas {
margin: 0;
padding: 0;
box-sizing: border-box;
background-color: transparent;
border: none;
text-decoration: none;
font-family: 'Roboto';
user-select: none;
list-style: none;
position: relative;
}
@mixin size($width:inherit, $height:inherit) {
width: $width;
height: $height;
}
@mixin flex($vertical, $horizontal, $direction:row) {
display: flex;
align-items: $vertical;
justify-content: $horizontal;
flex-direction: $direction;
}
@mixin border-radius($topLeft:50%, $topRight:50%, $botLeft:50%, $botRight:50%) {
border-top-left-radius: $topLeft;
border-top-right-radius: $topRight;
border-bottom-left-radius: $botLeft;
border-bottom-right-radius: $botRight;
}
$deepBlue-5: #f1f3f4;
$deepBlue-10: #e4e6ea;
$deepBlue-20: #CCCED5;
$deepBlue-40: #999EAC;
$deepBlue-60: #666D82;
$deepBlue-80: #333D59;
$deepBlue-90: #192445;
$deepBlue-100: #000C2F;
$deepBlue-120: #000923;
$blue: #2E90EB;
$salmon: #f56b72;
$swipes-shadow-one: 0 1px 3px rgba(0, 0, 0, 0.06),
0 1px 2px rgba(0, 0, 0, 0.12);
$swipes-shadow-two: 0 3px 6px rgba(0, 0, 0, 0.16),
0 3px 6px rgba(0, 0, 0, 0.23);
$swipes-shadow-three: 0 10px 20px rgba(0, 0, 0, 0.19),
0 6px 6px rgba(0, 0, 0, 0.23);
$swipes-shadow-four: 0 14px 28px rgba(0, 0, 0, 0.25),
0 10px 10px rgba(0, 0, 0, 0.22);
$swipes-shadow-five: 0 19px 38px rgba(0, 0, 0, 0.30),
0 15px 12px rgba(0, 0, 0, 0.22);
html,
body {
@include size(100%);
@include flex(center, center);
min-height: 100vh;
margin: 0;
padding: 0;
background-color: #FAFAFA;
font-family: 'Roboto';
}
// Custome SCSS
.sw-loader__wrapper {
position:relative;
&--center {
position:absolute;
left: 50%;
top:50%;
transform: translate(-50%, -50%);
}
.sw-loader__holder {
@include size(70%, 70%);
margin-left: 15%; margin-top: 15%;
position: relative;
transform: rotate(-45deg);
.rect {
@include size(100%, 100%);
position: absolute;
left: 0; top: 0;
background: linear-gradient(
to right,
#141562,
#486FBC,
#EAB5A1,
#8DD6FF,
#4973C9,
#D07CA7,
#F4915E,
#F5919E,
#B46F89,
#141562,
#486FBC);
background-position: 0% 50%;
background-size: 1000% 1000%;
overflow: hidden;
animation: moveGradient 15s infinite;
}
}
}
@keyframes moveGradient {
to {
background-position: 100% 50%;
}
}
View Compiled
const { PropTypes } = React;
const TIMER = 150; // Milliseconds between moving the next block
const TRANSITION = .5 // Seconds to actually move one block
const DEF_SIZE = 60; // Pixels height/width
const GUTTER = 5; // Spacing in percentage between tiles
const initialState = {
positions: {
1: 'alpha',
2: 'bravo',
3: 'charlie',
4: null,
5: 'delta',
6: 'echo',
7: 'foxtrot'
},
stateNumber: 0
}
class Loader extends React.Component {
constructor(props) {
super(props)
this.state = initialState;
this.setNextState = this.setNextState.bind(this);
}
componentDidMount() {
this.setTimer(TIMER);
}
setTimer(time){
if(this.timer){
clearInterval(this.timer);
}
this.timer = setInterval(this.setNextState, time);
}
componentWillUnmount(){
clearInterval(this.timer);
}
clipPathForPosition(position){
position = parseInt(position, 10);
const SIZE = (100-2*GUTTER)/3;
const VAR0 = '0% ';
const VAR1 = (SIZE+GUTTER) + '% ';
const VAR2 = (2*SIZE+2*GUTTER) + '% ';
switch(position){
case 1: return 'inset(' + VAR1 + VAR2 + VAR1 + VAR0 + ' round 5%)';
case 2: return 'inset(' + VAR0 + VAR2 + VAR2 + VAR0 + ' round 5%)';
case 3: return 'inset(' + VAR0 + VAR1 + VAR2 + VAR1 + ' round 5%)';
case 4: return 'inset(' + VAR1 + VAR1 + VAR1 + VAR1 + ' round 5%)';
case 5: return 'inset(' + VAR2 + VAR1 + VAR0 + VAR1 + ' round 5%)';
case 6: return 'inset(' + VAR2 + VAR0 + VAR0 + VAR2 + ' round 5%)';
case 7: return 'inset(' + VAR1 + VAR0 + VAR1 + VAR2 + ' round 5%)';
}
}
tileIndexToMove(){
switch(this.state.stateNumber){
case 0: return 7;
case 1: return 6;
case 2: return 5;
case 3: return 4;
case 4: return 3;
case 5: return 2;
case 6: return 1;
case 7: return 4;
}
}
positionForTile(radioCommand){
for(var position in this.state.positions){
var tile = this.state.positions[position];
if(tile === radioCommand){
return position;
}
}
}
setNextState(){
const currentPositions = this.state.positions;
const emptyIndex = this.positionForTile(null);
const indexToMove = this.tileIndexToMove();
const newPositions = Object.assign({}, currentPositions, {
[indexToMove]: null,
[emptyIndex]: currentPositions[indexToMove]
});
const currentState = this.state.stateNumber;
const nextState = (currentState === 7) ? 0 : currentState + 1;
this.setState({stateNumber: nextState, positions: newPositions});
}
renderTiles(){
return ['alpha', 'bravo', 'charlie', 'delta', 'echo', 'foxtrot'].map((radioCommand) => {
const pos = this.positionForTile(radioCommand);
const styles = {
transition: (TRANSITION) + 's cubic-bezier(0.86, 0, 0.07, 1)',
WebkitClipPath: this.clipPathForPosition(pos)
}
return <div key={"rect-" + radioCommand} style={styles} className={"rect " + radioCommand} />
})
}
render() {
const { size, style, center } = this.props;
const styles = Object.assign({
width: DEF_SIZE + 'px',
height: DEF_SIZE + 'px'
}, style);
if ( size ) {
styles.width = size + 'px';
styles.height = size + 'px';
}
let className = "sw-loader__wrapper"
if(center){
className += " sw-loader__wrapper--center";
}
return (
<div style={styles} className={className}>
<div className="sw-loader__holder">
{this.renderTiles()}
</div>
</div>
)
}
}
class Container extends React.Component {
render() {
const data = {
size: 200
};
return <Loader {...data} />
}
}
ReactDOM.render(<Container />, document.getElementById('content'))
View Compiled
This Pen doesn't use any external CSS resources.