feat: Animate Add to Cart List interactions (UX)

- Increased qty in cart on clicking add to cart for existing item
- Simplified macro arguments
- Navbar cart icon animation
- Explore button for template item in card
- Add to cart button animation
diff --git a/erpnext/e_commerce/shopping_cart/cart.py b/erpnext/e_commerce/shopping_cart/cart.py
index a5f38c6..c2c94a3 100644
--- a/erpnext/e_commerce/shopping_cart/cart.py
+++ b/erpnext/e_commerce/shopping_cart/cart.py
@@ -138,7 +138,7 @@
 				"additional_notes": additional_notes
 			})
 		else:
-			quotation_items[0].qty = qty
+			quotation_items[0].qty = qty + 1
 			quotation_items[0].additional_notes = additional_notes
 
 	apply_cart_settings(quotation=quotation)
@@ -153,9 +153,8 @@
 
 	set_cart_count(quotation)
 
-	context = get_cart_quotation(quotation)
-
 	if cint(with_items):
+		context = get_cart_quotation(quotation)
 		return {
 			"items": frappe.render_template("templates/includes/cart/cart_items.html",
 				context),
@@ -164,8 +163,7 @@
 		}
 	else:
 		return {
-			'name': quotation.name,
-			'shopping_cart_menu': get_shopping_cart_menu(context)
+			'name': quotation.name
 		}
 
 @frappe.whitelist()
diff --git a/erpnext/e_commerce/web_template/item_card_group/item_card_group.html b/erpnext/e_commerce/web_template/item_card_group/item_card_group.html
index fe061d5..889a228 100644
--- a/erpnext/e_commerce/web_template/item_card_group/item_card_group.html
+++ b/erpnext/e_commerce/web_template/item_card_group/item_card_group.html
@@ -25,8 +25,7 @@
 			{%- if item -%}
 				{%- set item = frappe.get_doc("Item", item) -%}
 				{{ item_card(
-					item.item_name, item.image, item.route, item.description,
-					None, item.item_group, values['card_' + index + '_featured'],
+					item, is_featured=values['card_' + index + '_featured'],
 					True, "Center"
 				) }}
 			{%- endif -%}
diff --git a/erpnext/public/js/shopping_cart.js b/erpnext/public/js/shopping_cart.js
index 6553801..bcfa983 100644
--- a/erpnext/public/js/shopping_cart.js
+++ b/erpnext/public/js/shopping_cart.js
@@ -93,9 +93,6 @@
 				btn: opts.btn,
 				callback: function(r) {
 					shopping_cart.set_cart_count();
-					if (r.message.shopping_cart_menu) {
-						$('.shopping-cart-menu').html(r.message.shopping_cart_menu);
-					}
 					if(opts.callback)
 						opts.callback(r);
 				}
@@ -129,6 +126,10 @@
 
 		if(cart_count) {
 			$badge.html(cart_count);
+			$cart.addClass('cart-animate');
+			setTimeout(() => {
+				$cart.removeClass('cart-animate');
+			}, 500);
 		} else {
 			$badge.remove();
 		}
diff --git a/erpnext/public/scss/shopping_cart.scss b/erpnext/public/scss/shopping_cart.scss
index 4317279..8380f6c 100644
--- a/erpnext/public/scss/shopping_cart.scss
+++ b/erpnext/public/scss/shopping_cart.scss
@@ -363,6 +363,31 @@
 	}
 }
 
+.cart-animate {
+	animation: wiggle 0.5s linear;
+}
+@keyframes wiggle {
+	8%,
+	41% {
+		transform: translateX(-10px);
+	}
+	25%,
+	58% {
+		transform: translate(10px);
+	}
+	75% {
+		transform: translate(-5px);
+	}
+	92% {
+		transform: translate(5px);
+	}
+	0%,
+	100% {
+		transform: translate(0);
+	}
+}
+
+
 
 #page-cart {
 	.shopping-cart-header {
@@ -557,16 +582,50 @@
 	}
 }
 
-.btn-add-to-cart-list {
+.btn-explore-variants {
+	box-shadow: none;
+	margin: var(--margin-sm) 0;
+	margin-left: 18px;
+	max-height: 30px; // to avoid resizing on window resize
+	flex: none;
+	transition: 0.3s ease;
+	color: var(--orange-500);
+	background-color: white;
+	border: 1px solid var(--orange-500);
+
+	&:hover {
+		color: white;
+		background-color: var(--orange-500);
+	}
+}
+
+.btn-add-to-cart-list{
+	box-shadow: none;
+	margin: var(--margin-sm) 0;
+	max-height: 30px; // to avoid resizing on window resize
+	flex: none;
+	transition: 0.3s ease;
+}
+
+.not-added {
+	margin-left: 18px;
 	color: var(--blue-500);
 	background-color: white;
-	box-shadow: none;
 	border: 1px solid var(--blue-500);
-	margin: var(--margin-sm) 0;
-	flex: none;
 
 	&:hover {
 		background-color: var(--blue-500);
 		color: white;
 	}
 }
+
+.added-to-cart {
+	margin-left: 18px;
+	background-color: var(--dark-green-400);
+	color: white;
+	border: 2px solid var(--green-300);
+
+	&:hover {
+		color: white;
+	}
+}
diff --git a/erpnext/templates/includes/macros.html b/erpnext/templates/includes/macros.html
index 73c8745..818316c 100644
--- a/erpnext/templates/includes/macros.html
+++ b/erpnext/templates/includes/macros.html
@@ -59,13 +59,17 @@
 
 {% endmacro %}
 
-{%- macro item_card(title, image, url, description, rate, category, in_stock=None, is_featured=False, is_full_width=False, align="Left") -%}
+{%- macro item_card(item, is_featured=False, is_full_width=False, align="Left") -%}
 {%- set align_items_class = resolve_class({
 	'align-items-end': align == 'Right',
 	'align-items-center': align == 'Center',
 	'align-items-start': align == 'Left',
 }) -%}
 {%- set col_size = 3 if is_full_width else 4 -%}
+{%- set title = item.item_name or item.item_code -%}
+{%- set image = item.website_image or item.image -%}
+{%- set description = item.website_description or item.description-%}
+
 {% if is_featured %}
 <div class="col-sm-{{ col_size*2 }} item-card">
 	<div class="card featured-item {{ align_items_class }}">
@@ -75,12 +79,12 @@
 				<img class="card-img" src="{{ image }}" alt="{{ title }}">
 			</div>
 			<div class="col-md-6">
-				{{ item_card_body(title, description, url, rate, category, is_featured, align) }}
+				{{ item_card_body(title, description, item, is_featured, align) }}
 			</div>
 		</div>
 		{% else %}
 			<div class="col-md-12">
-				{{ item_card_body(title, description, url, rate, category, is_featured, align) }}
+				{{ item_card_body(title, description, item, is_featured, align) }}
 			</div>
 		{% endif %}
 	</div>
@@ -90,24 +94,24 @@
 	<div class="card {{ align_items_class }}">
 		{% if image %}
 			<div class="card-img-container">
-				<a href="/{{ url or '#' }}" style="text-decoration: none;">
+				<a href="/{{ item.route or '#' }}" style="text-decoration: none;">
 					<img class="card-img" src="{{ image }}" alt="{{ title }}">
 				</a>
 			</div>
 		{% else %}
-		<a href="/{{ url or '#' }}" style="text-decoration: none;">
+		<a href="/{{ item.route or '#' }}" style="text-decoration: none;">
 			<div class="card-img-top no-image">
 				{{ frappe.utils.get_abbr(title) }}
 			</div>
 		</a>
 		{% endif %}
-		{{ item_card_body(title, description, url, rate, category, is_featured, align, in_stock) }}
+		{{ item_card_body(title, description, item, is_featured, align) }}
 	</div>
 </div>
 {% endif %}
 {%- endmacro -%}
 
-{%- macro item_card_body(title, description, url, rate, category, is_featured, align, in_stock=None) -%}
+{%- macro item_card_body(title, description, item, is_featured, align) -%}
 {%- set align_class = resolve_class({
 	'text-right': align == 'Right',
 	'text-center': align == 'Center' and not is_featured,
@@ -116,33 +120,44 @@
 <div class="card-body {{ align_class }}" style="width:100%">
 
 	<div style="margin-top: 16px; display: flex;">
-		<a href="/{{ url or '#' }}">
+		<a href="/{{ item.route or '#' }}">
 			<div class="product-title">{{ title or '' }}</div>
 		</a>
-		{% if in_stock %}
-			<span class="indicator {{ in_stock }} card-indicator"></span>
+		{% if item.in_stock %}
+			<span class="indicator {{ item.in_stock }} card-indicator"></span>
 		{% endif %}
-		<input class="level-item list-row-checkbox hidden-xs"
-			type="checkbox" data-name="{{ title }}" style="display: none !important;">
-		<div class="like-action"
-			data-name="{{ title }}" data-doctype="Item">
-			<svg class="icon sm">
-				<use class="wish-icon" href="#icon-heart"></use>
-			</svg>
-		</div>
+		{% if not item.has_variants %}
+			<input class="level-item list-row-checkbox hidden-xs"
+				type="checkbox" data-name="{{ title }}" style="display: none !important;">
+			<div class="like-action"
+				data-name="{{ title }}" data-doctype="Item">
+				<svg class="icon sm">
+					<use class="wish-icon" href="#icon-heart"></use>
+				</svg>
+			</div>
+		{% endif %}
 	</div>
 	{% if is_featured %}
-	<div class="product-price">{{ rate or '' }}</div>
+	<div class="product-price">{{ item.formatted_price or '' }}</div>
 	<div class="product-description ellipsis">{{ description or '' }}</div>
 	{% else %}
-	<div class="product-category">{{ category or '' }}</div>
+	<div class="product-category">{{ item.item_group or '' }}</div>
 	<div style="display: flex;">
-		{% if rate %}
-		<div class="product-price" style="width: 60%;">{{ rate or '' }}</div>
+		{% if item.formatted_price %}
+		<div class="product-price">{{ item.formatted_price or '' }}</div>
 		{% endif %}
-		<div class="btn btn-sm btn-add-to-cart-list">
-			{{ _('Add to Cart') }}
-		</div>
+		{% if item.has_variants %}
+		<a href="/{{ item.route or '#' }}">
+			<div class="btn btn-sm btn-explore-variants">
+				{{ _('Explore') }}
+			</div>
+		</a>
+		{% else %}
+			<div id="{{ item.name }}" class="btn btn-sm btn-add-to-cart-list not-added"
+				data-item-code="{{ item.item_code }}">
+				{{ _('Add to Cart') }}
+			</div>
+		{% endif %}
 	</div>
 	{% endif %}
 </div>
diff --git a/erpnext/www/all-products/index.js b/erpnext/www/all-products/index.js
index 37e07f4..4572ee7 100644
--- a/erpnext/www/all-products/index.js
+++ b/erpnext/www/all-products/index.js
@@ -2,6 +2,7 @@
 	class ProductListing {
 		constructor() {
 			this.bind_filters();
+			this.bind_card_actions();
 			this.bind_search();
 			this.restore_filters_state();
 		}
@@ -71,8 +72,35 @@
 			}, 1000));
 		}
 
-		make_filters() {
+		bind_card_actions() {
+			$('.page_content').on('click', '.btn-add-to-cart-list', (e) => {
+				const $btn = $(e.currentTarget);
+				$btn.prop('disabled', true);
 
+				this.animate_add_to_cart($btn);
+
+				const item_code = $btn.data('item-code');
+				erpnext.shopping_cart.update_cart({
+					item_code,
+					qty: 1
+				});
+
+			});
+		}
+
+		animate_add_to_cart(button) {
+			// Create 'added to cart' animation
+			let btn_id = "#" + button[0].id;
+			button.removeClass('not-added');
+			button.addClass('added-to-cart');
+			$(btn_id).text('Added to Cart');
+
+			// undo
+			setTimeout(() => {
+				button.removeClass('added-to-cart');
+				button.addClass('not-added');
+				$(btn_id).text('Add to Cart');
+			}, 2000);
 		}
 
 		bind_search() {
diff --git a/erpnext/www/all-products/item_row.html b/erpnext/www/all-products/item_row.html
index 665936d..072e359 100644
--- a/erpnext/www/all-products/item_row.html
+++ b/erpnext/www/all-products/item_row.html
@@ -1,6 +1,4 @@
 {% from "erpnext/templates/includes/macros.html" import item_card, item_card_body %}
 
-{{ item_card(
-	item.item_name or item.name, item.website_image or item.image, item.route, item.website_description or item.description,
-	item.formatted_price, item.item_group, in_stock=item.in_stock
-) }}
+{{ item_card(item) }}
+