diff --git a/website/client/components/creatorIntro.vue b/website/client/components/creatorIntro.vue
index 4cff8ea8b2..19ca0efc5e 100644
--- a/website/client/components/creatorIntro.vue
+++ b/website/client/components/creatorIntro.vue
@@ -163,32 +163,27 @@ b-modal#avatar-modal(title="", :size='editing ? "lg" : "md"', :hide-header='true
:class='{active: user.preferences.hair.bangs === option}')
.bangs.sprite.customize-option(:class="`hair_bangs_${option}_${user.preferences.hair.color}`", @click='set({"preferences.hair.bangs": option})')
#facialhair.row(v-if='activeSubPage === "facialhair"')
- .col-12.customize-options(v-if='editing')
- .head_0.option(@click='set({"preferences.hair.beard": 0})', :class="[{ active: user.preferences.hair.beard === 0 }, 'hair_base_0_' + user.preferences.hair.color]")
- .option(v-for='option in baseHair5',
- :class='{active: option.active, locked: option.locked}')
- .base.sprite.customize-option(:class="`hair_beard_${option.key}_${user.preferences.hair.color}`", @click='option.click')
- .gem-lock(v-if='option.locked')
- .svg-icon.gem(v-html='icons.gem')
- span 2
- .col-12.text-center(v-if='!userOwnsSet("hair", baseHair5Keys, "beard")')
- .gem-lock
- .svg-icon.gem(v-html='icons.gem')
- span 5
- button.btn.btn-secondary.purchase-all(@click='unlock(`hair.beard.${baseHair5Keys.join(",hair.beard.")}`)') {{ $t('purchaseAll') }}
.col-12.customize-options(v-if='editing')
.head_0.option(@click='set({"preferences.hair.mustache": 0})', :class="[{ active: user.preferences.hair.mustache === 0 }, 'hair_base_0_' + user.preferences.hair.color]")
- .option(v-for='option in baseHair6',
+ .option(v-for='option in baseHair5',
:class='{active: option.active, locked: option.locked}')
.base.sprite.customize-option(:class="`hair_mustache_${option.key}_${user.preferences.hair.color}`", @click='option.click')
.gem-lock(v-if='option.locked')
.svg-icon.gem(v-html='icons.gem')
span 2
- .col-12.text-center(v-if='!userOwnsSet("hair", baseHair6Keys, "mustache")')
+ .col-12.customize-options(v-if='editing')
+ .head_0.option(@click='set({"preferences.hair.beard": 0})', :class="[{ active: user.preferences.hair.beard === 0 }, 'hair_base_0_' + user.preferences.hair.color]")
+ .option(v-for='option in baseHair6',
+ :class='{active: option.active, locked: option.locked}')
+ .base.sprite.customize-option(:class="`hair_beard_${option.key}_${user.preferences.hair.color}`", @click='option.click')
+ .gem-lock(v-if='option.locked')
+ .svg-icon.gem(v-html='icons.gem')
+ span 2
+ .col-12.text-center(v-if="isPurchaseAllNeeded('hair', ['baseHair5', 'baseHair6'], ['mustache', 'beard'])")
.gem-lock
.svg-icon.gem(v-html='icons.gem')
span 5
- button.btn.btn-secondary.purchase-all(@click='unlock(`hair.mustache.${baseHair6Keys.join(",hair.mustache.")}`)') {{ $t('purchaseAll') }}
+ button.btn.btn-secondary.purchase-all(@click='unlock(`hair.mustache.${baseHair5Keys.join(",hair.mustache.")},hair.beard.${baseHair6Keys.join(",hair.beard.")}`)') {{ $t('purchaseAll') }}
#extra.section.container.customize-section(v-if='activeTopPage === "extra"')
.row.sub-menu
.col-3.offset-1.text-center.sub-menu-item(@click='changeSubPage("glasses")', :class='{active: activeSubPage === "glasses"}')
@@ -1010,8 +1005,8 @@ export default {
baseHair2Keys: [2, 4, 5, 6, 7, 8],
baseHair3Keys: [9, 10, 11, 12, 13, 14],
baseHair4Keys: [15, 16, 17, 18, 19, 20],
- baseHair5Keys: [1, 2, 3],
- baseHair6Keys: [1, 2],
+ baseHair5Keys: [1, 2],
+ baseHair6Keys: [1, 2, 3],
animalEarsKeys: ['bearEars', 'cactusEars', 'foxEars', 'lionEars', 'pandaEars', 'pigEars', 'tigerEars', 'wolfEars'],
icons: Object.freeze({
logoPurple,
@@ -1228,7 +1223,7 @@ export default {
let backgroundUpdate = this.backgroundUpdate; // eslint-disable-line
let keys = this.baseHair5Keys;
let options = keys.map(key => {
- return this.mapKeysToOption(key, 'hair', 'beard');
+ return this.mapKeysToOption(key, 'hair', 'mustache');
});
return options;
},
@@ -1237,7 +1232,7 @@ export default {
let backgroundUpdate = this.backgroundUpdate; // eslint-disable-line
let keys = this.baseHair6Keys;
let options = keys.map(key => {
- return this.mapKeysToOption(key, 'hair', 'mustache');
+ return this.mapKeysToOption(key, 'hair', 'beard');
});
return options;
},
@@ -1335,6 +1330,68 @@ export default {
return owns;
},
+ /**
+ * Allows you to find out whether you need the "Purchase All" button or not. If there are more than 2 unpurchased items, returns true, otherwise returns false.
+ * @param {string} category - The selected category.
+ * @param {string[]} keySets - The items keySets.
+ * @param {string[]} [types] - The items types (subcategories). Optional.
+ * @returns {boolean} - Determines whether the "Purchase All" button is needed (true) or not (false).
+ */
+ isPurchaseAllNeeded (category, keySets, types) {
+ const purchasedItemsLengths = [];
+ // If item types are specified, count them
+ if (types && types.length > 0) {
+ // Types can be undefined, so we must check them.
+ types.forEach((type) => {
+ if (this.user.purchased[category][type]) {
+ purchasedItemsLengths
+ .push(Object.keys(this.user.purchased[category][type]).length);
+ }
+ });
+ } else {
+ let purchasedItemsCounter = 0;
+
+ // If types are not specified, recursively
+ // search for purchased items in the category
+ const findPurchasedItems = (item) => {
+ if (typeof item === 'object') {
+ Object.values(item)
+ .forEach((innerItem) => {
+ if (typeof innerItem === 'boolean' && innerItem === true) {
+ purchasedItemsCounter += 1;
+ }
+ return findPurchasedItems(innerItem);
+ });
+ }
+ return purchasedItemsCounter;
+ };
+
+ findPurchasedItems(this.user.purchased[category]);
+ if (purchasedItemsCounter > 0) {
+ purchasedItemsLengths.push(purchasedItemsCounter);
+ }
+ }
+
+ // We don't need to count the key sets (below)
+ // if there are no purchased items at all.
+ if (purchasedItemsLengths.length === 0) {
+ return true;
+ }
+
+ const allItemsLengths = [];
+ // Key sets must be specify correctly.
+ keySets.forEach((keySet) => {
+ allItemsLengths.push(Object.keys(this[keySet]).length);
+ });
+
+ // Simply sum all the length values and
+ // write them into variables for the convenience.
+ const allItems = allItemsLengths.reduce((acc, val) => acc + val);
+ const purchasedItems = purchasedItemsLengths.reduce((acc, val) => acc + val);
+
+ const unpurchasedItems = allItems - purchasedItems;
+ return unpurchasedItems > 2;
+ },
prev () {
this.modalPage -= 1;
},
diff --git a/website/client/components/header/menu.vue b/website/client/components/header/menu.vue
index 09400e80d4..22800b5dc9 100644
--- a/website/client/components/header/menu.vue
+++ b/website/client/components/header/menu.vue
@@ -3,7 +3,7 @@ div
inbox-modal
creator-intro
profile
- b-navbar.navbar.navbar-inverse.fixed-top.navbar-expand-lg(type="dark")
+ b-navbar.navbar.navbar-inverse.fixed-top.navbar-expand-lg(type="dark", :class="navbarZIndexClass")
.navbar-header
.logo.svg-icon.d-none.d-xl-block(v-html="icons.logo")
.svg-icon.gryphon.d-md-block.d-none.d-xl-none
@@ -145,7 +145,16 @@ div
padding-right: 12.5px;
height: 56px;
box-shadow: 0 1px 2px 0 rgba($black, 0.24);
- z-index: 1042; // To stay above snakbar notifications and modals
+ }
+
+ .navbar-z-index {
+ &-normal {
+ z-index: 1080;
+ }
+
+ &-modal {
+ z-index: 1035;
+ }
}
.navbar-header {
@@ -327,7 +336,14 @@ export default {
user: 'user.data',
userHourglasses: 'user.data.purchased.plan.consecutive.trinkets',
groupPlans: 'groupPlans',
+ modalStack: 'modalStack',
}),
+ navbarZIndexClass () {
+ if (this.modalStack.length > 0) {
+ return 'navbar-z-index-modal';
+ }
+ return 'navbar-z-index-normal';
+ },
},
mounted () {
this.getUserGroupPlans();
diff --git a/website/client/components/snackbars/notifications.vue b/website/client/components/snackbars/notifications.vue
index 18705af494..22b0d78030 100644
--- a/website/client/components/snackbars/notifications.vue
+++ b/website/client/components/snackbars/notifications.vue
@@ -1,6 +1,6 @@
-.notifications
- div(v-for='notification in notifications', :key='notification.uuid')
+.notifications(:class="notificationsTopPos")
+ div(v-for='notification in notificationStore', :key='notification.uuid')
notification(:notification='notification')
@@ -8,13 +8,23 @@
.notifications {
position: fixed;
right: 10px;
- top: 65px;
width: 350px;
- z-index: 1041; // 1041 is above modal backgrounds
+ z-index: 1070; // 1070 is above modal backgrounds
+
+ &-top-pos {
+ &-normal {
+ top: 65px;
+ }
+
+ &-sleeping {
+ top: 105px;
+ }
+ }
}