JSFiddle - React, Tailwind, and code Playground

by NOVUSIDEA

HTML

<script src="https://unpkg.com/[email protected]/dist/axios.js"></script>
<script src="https://unpkg.com/[email protected]/dist/vue.js"></script>
<div id="app">

    <div id="reactions">
        <react class="react-button" name="yes" :count="35">

            <div class="react-icon">
                <svg class="svg-symbol"><use xlink:href="#thumb-up"/></svg>
                <div class="loading"></div>
            </div>

            <div class="react-text">Ja</div>

            <template class="react-count" #count="{count: count}">
                <div class="react-count">{{ count }}</div>
            </template>

        </react>

        <react class="react-button" name="maybe" :count="10">
            <div class="react-icon">
                <svg class="svg-symbol"><use xlink:href="#maybe"/></svg>
                <div class="loading"></div>
            </div>
            <div class="react-text">Vielleicht</div>
            <template class="react-count" #count="{count: count}">
                <div class="react-count">{{ count }}</div>
            </template>
        </react>

        <react class="react-button" name="no" :count="23">
            <div class="react-icon">
                <svg class="svg-symbol"><use xlink:href="#thumb-down"/></svg>
                <div class="loading"></div>
            </div>
            <div class="react-text">Nein</div>
            <template class="react-count" #count="{count: count}">
                <div class="react-count">{{ count }}</div>
            </template>
        </react>
    </div>

</div>

<script type="text/x-template" id="react-button">
	<button @click="react" :class="{'reaction-loaded': loading}" :disabled="loading">
        <slot>{{ name }}</slot>
        <slot name="count" :count="count">[{{ count }}]</slot>
    </button>
</script>

<svg style="display:none">
    <symbol id="maybe" viewBox="0 0 24 24">
        <title>maybe</title>
        <path d="m11.979 2.0017c-1.395-0.06335-2.4009 1.6346-1.6774 2.8278 0.61323 1.2546...

CSS

* {
    box-sizing: border-box;
}

#reactions {
    display: flex;
    justify-content: space-around;
}

.react-button {
    background: beige;
    cursor: pointer;
    padding: 0;
    border: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    flex: 0 0 30%;
    max-width: 30%;
    font-size: 18px;
}

.react-button:disabled {
    opacity: 0.5;
}

.react-icon {
    font-size: 50px;
}

.svg-symbol {
    display: block;
    width: 1em;
    height: 1em;
}

.react-button .loading {
    position: relative;
    display: block;
    width: 1em;
    height: 1em;
    display: none;
}

.react-button .loading::before {
    content: ' ';
    position: absolute;
    top: 0.15em;
    left: 0.15em;
    right: 0.15em;
    bottom: 0.15em;
    border: 0.1em solid currentColor;
    border-bottom-color: transparent;
    border-radius: 1em;
    animation-name: spin;
    animation-duration: 0.8s;
    animation-timing-function: linear;
    animation-iteration-count: infinite;
}

.react-button.reaction-loaded .svg-symbol {
    display: none;
}

.react-button.reaction-loaded .loading {
    display: block;
}

@-webkit-keyframes spin {
    from {
        transform: rotate(0deg);
    }
    to {
        transform: rotate(360deg);
    }
}

JavaScript

Vue.component('react', {
	props: {
    	name: {
        	type: String,
            value: 'React',
        },
    },
    data: function () {
        return {
            loading: false,
            currentCount: 0,
        }
    },
	template: '#react-button',
    computed: {
    	count: {
        	get: function() {
                return this.currentCount;
            },
            set: function(value) {
                this.currentCount = value;
            }
        },
    },
    methods: {
    	react: function(){
        
        	var _this = this,
            	min = 150,
                max = 300,
            	randomNumber = Math.floor(Math.random() * max) + min;
                
            _this.loading = true;
            
            axios.post('/echo/json/', {count: _this.name}).then(function (response) {
            
            	setTimeout(function(){
                	_this.count++;
           			_this.loading = false;
                    console.log( response.data );
                }, randomNumber);
                
            }).catch(function (error) {
            
                //console.log(error);
                
            }).then(function () {
                
                //console.log('every time');
                
            });  

        }
    }
});

new Vue({
    el: '#app'
});