Skip to content

Instantly share code, notes, and snippets.

@raprasad
Created August 27, 2020 22:23
Show Gist options
  • Save raprasad/c76141d996b469c4840426e845a3997e to your computer and use it in GitHub Desktop.
Save raprasad/c76141d996b469c4840426e845a3997e to your computer and use it in GitHub Desktop.
Vue/Bootstrap Template
<div id="app">
<nav class="navbar navbar-light fixed-top">
<div class="navbar-text ml-auto d-flex">
<button class="btn btn-sm btn-outline-success"
@click="sliderStatus = !sliderStatus">
<i class="fas fa-dollar-sign"></i></button>
<div class="dropdown ml-2" v-if="cart.length>0">
<button class="btn btn-success btn-sm dropdown-toggle"
id="cartDropdown" data-toggle="dropdown"
aria-haspopup="true" aria-expanded="false">
<span class="badge badge-pill badge-light">{{cartQty}}</span>
<i class="fas fa-shopping-cart mx-2"></i>
<price :value="Number(cartTotal)"></price>
</button>
<div class="dropdown-menu dropdown-menu-right"
aria-labelledby="cartDropdown">
<div v-for="(item, index) in cart" :key="index">
<div class="dropdown-item-text text-nowrap text-right">
<span class="badge badge-pill badge-warning align-text-top mr-1">{{item.qty}}</span>
{{item.product.name}}
<b><price :value="Number(item.qty * item.product.price)"></price></b>
<a href="#" @click.stop="deleteItem(index)"
class="badge badge-danger text-white">-</a>
</div>
</div>
</div>
</div>
</div>
</nav>
<h1>My Shop</h1>
<transition name="fade">
<div v-if="sliderStatus">
<div class="align-items-center" :class="sliderState">
<label :class="labelArr" for="formMax">max</label>
<input type="text" id="formMax" class="form-control mx-2"
:style="{'width': inputWidth + 'px', textAlign:'center'}" v-model="maximum">
<input type="range" class="custom-range" min="0" max="200" v-model="maximum">
</div>
</div>
</transition>
<product-list :products="products" :maximum="maximum" @add="addItem" ></product-list>
</div>
Vue.component('price', {
data: function() {
return {
}
},
props: {
value: Number,
prefix: {
type: String,
default: '$'
},
precision: {
type: Number,
default: 2
},
conversion: {
type: Number,
default: 1
}
},
template: '<span>{{ this.prefix + Number.parseFloat(this.value * this.conversion).toFixed(this.precision) }}</span>'
});
Vue.component('product-list', {
props: ['products', 'maximum'],
template: `
<transition-group name="fade" tag="div"
@beforeEnter="beforeEnter"
@enter="enter"
@leave="leave">
<div class="row d-none mb-3 align-items-center"
v-for="(item, index) in products" :key="item.id"
v-if="item.price<=Number(maximum)"
:data-index="index">
<div class="col-1 m-auto">
<button class="btn btn-info"
@click="$emit('add', item)">+</button>
</div>
<div class="col-4">
<img class="img-fluid d-block" :src="item.image" :alt="item.name">
</div>
<div class="col">
<h3 class="text-info">{{ item.name }}</h3>
<p class="mb-0">{{ item.description }}</p>
<div class="h5 float-right">
<price :value="Number(item.price)"></price></div>
</div>
</div>
</transition-group>
`,
methods: {
beforeEnter: function(el) {
el.className='d-none'
},
enter: function(el) {
var delay=el.dataset.index * 100;
setTimeout(function() {
el.className='row d-flex mb-3 align-items-center animated fadeInRight'
}, delay);
},
leave: function(el) {
var delay=el.dataset.index * 100;
setTimeout(function() {
el.className='row d-flex mb-3 align-items-center animated fadeOutRight'
}, delay);
},
}
});
var app = new Vue({
el: '#app',
data: {
inputWidth: 60,
sliderStatus: false,
labelArr: ['font-weight-bold', 'mr-2'],
maximum: 99,
products: null,
cart: []
},
filters: {
currency: function(value) {
return '$' + Number.parseFloat(value).toFixed(2);
}
},
computed: {
cartTotal: function() {
let sum = 0;
for (key in this.cart) {
sum = sum+(this.cart[key].product.price * this.cart[key].qty);
}
return sum;
},
cartQty: function() {
let qty = 0;
for (key in this.cart) {
qty = qty + this.cart[key].qty;
}
return qty;
},
sliderState: function() {
return this.sliderStatus ? 'd-flex': 'd-none'
}
},
methods: {
addItem: function(product) {
var whichProduct;
var existing = this.cart.filter(function(item, index) {
if (item.product.id == Number(product.id)) {
whichProduct = index;
return true;
} else {
return false;
}
});
if (existing.length) {
this.cart[whichProduct].qty++
} else {
this.cart.push({product: product, qty: 1})
}
},
deleteItem: function(id) {
if(this.cart[id].qty>1) {
this.cart[id].qty--;
} else {
this.cart.splice(id, 1);
}
}
},
mounted: function() {
fetch('https://hplussport.com/api/products/order/price')
.then(response => response.json())
.then(data => {
this.products = data;
})
}
});
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.6/umd/popper.min.js"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.2.1/js/bootstrap.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
.fade-enter, .fade-leave-to {
opacity: 0;
}
.fade-enter-active, .fade-leave-active {
transition: all 1s ease-in-out;
}
<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.2.1/css/bootstrap.min.css" rel="stylesheet" />
<link href="https://use.fontawesome.com/releases/v5.7.0/css/all.css" rel="stylesheet" />
<link href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/3.7.0/animate.min.css" rel="stylesheet" />

Vue/Bootstrap Template

This is a template for working with Vue.js with the Bootstrap framework pre-installed.

A Pen by Ray Villalobos on CodePen.

License.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment