diff --git a/website/client/assets/scss/colors.scss b/website/client/assets/scss/colors.scss index cc653f33d9..6e54888ef7 100644 --- a/website/client/assets/scss/colors.scss +++ b/website/client/assets/scss/colors.scss @@ -61,3 +61,12 @@ $green-100: #5AEAB2; $green-500: #A6FFDF; $suggested-item-color: #D5C8FF; + +$healer-color: #cf8229; +$rogue-color: #4F2A93; +$warrior-color: #B01515; +$wizard-color: #1f6ea2; + +$gems-color: #24CC8F; +$gold-color: #FFA623; +$hourglass-color: #2995CD; diff --git a/website/client/assets/scss/icon.scss b/website/client/assets/scss/icon.scss index 78a9b8b8a2..bdb2fa4345 100644 --- a/website/client/assets/scss/icon.scss +++ b/website/client/assets/scss/icon.scss @@ -28,6 +28,12 @@ height: 12px; } +.icon-24 { + width: 24px; + height: 24px; +} + + .icon-10 { width: 10px; height: 10px; diff --git a/website/client/assets/scss/popover.scss b/website/client/assets/scss/popover.scss index b15566fdab..8e165ec10b 100644 --- a/website/client/assets/scss/popover.scss +++ b/website/client/assets/scss/popover.scss @@ -36,17 +36,3 @@ margin-bottom: 0px; } -.popover-content-attr { - width: 50%; - display: inline-block; - font-weight: bold; - margin-bottom: 4px; - - &-key { - color: $white; - } - - &-val { - color: $green-10; - } -} diff --git a/website/client/assets/scss/typography.scss b/website/client/assets/scss/typography.scss index 4076d98594..9dceb3ed35 100644 --- a/website/client/assets/scss/typography.scss +++ b/website/client/assets/scss/typography.scss @@ -68,3 +68,8 @@ h4 { font-size: 14px; line-height: 1.43; } + +.textCondensed { + font-family: 'Roboto Condensed', sans-serif; + font-weight: bold; +} diff --git a/website/client/components/inventory/equipment/attributesGrid.vue b/website/client/components/inventory/equipment/attributesGrid.vue new file mode 100644 index 0000000000..6cbacdd3a0 --- /dev/null +++ b/website/client/components/inventory/equipment/attributesGrid.vue @@ -0,0 +1,169 @@ + + + + + diff --git a/website/client/components/inventory/equipment/attributesPopover.vue b/website/client/components/inventory/equipment/attributesPopover.vue index 2b3adc8ba2..731d649f34 100644 --- a/website/client/components/inventory/equipment/attributesPopover.vue +++ b/website/client/components/inventory/equipment/attributesPopover.vue @@ -8,15 +8,25 @@ div div(v-else) h4.popover-content-title {{ itemText }} .popover-content-text {{ itemNotes }} - .popover-content-attr(v-for="attr in ATTRIBUTES", :key="attr") - span.popover-content-attr-key {{ `${$t(attr)}: ` }} - span.popover-content-attr-val {{ `+${item[attr]}` }} + attributesGrid(:item="item") + + diff --git a/website/client/components/shops/market/index.vue b/website/client/components/shops/market/index.vue index 6fb5b45190..8249f0ee73 100644 --- a/website/client/components/shops/market/index.vue +++ b/website/client/components/shops/market/index.vue @@ -255,13 +255,6 @@ margin: 24px auto; } - .bordered { - border-radius: 2px; - background-color: #f9f9f9; - margin-bottom: 24px; - padding: 24px 24px 10px; - } - .item-wrapper.bordered-item .item { width: 112px; height: 112px; @@ -359,7 +352,7 @@ import Avatar from 'client/components/avatar'; import SellModal from './sellModal.vue'; - import EquipmentAttributesGrid from './equipmentAttributesGrid.vue'; + import EquipmentAttributesGrid from '../../inventory/equipment/attributesGrid.vue'; import SelectMembersModal from 'client/components/selectMembersModal.vue'; import svgPin from 'assets/svg/pin.svg'; diff --git a/website/client/components/shops/market/sellModal.vue b/website/client/components/shops/market/sellModal.vue index 8eee123848..cfeaef7b48 100644 --- a/website/client/components/shops/market/sellModal.vue +++ b/website/client/components/shops/market/sellModal.vue @@ -63,15 +63,6 @@ width: 282px; } - .content-text { - font-family: 'Roboto', sans-serif; - font-size: 14px; - font-weight: normal; - line-height: 1.43; - - width: 400px; - } - span.svg-icon.inline.icon-32 { height: 32px; width: 32px; diff --git a/website/client/components/shops/quests/buyQuestModal.vue b/website/client/components/shops/quests/buyQuestModal.vue index 42dd2905e7..483ee77717 100644 --- a/website/client/components/shops/quests/buyQuestModal.vue +++ b/website/client/components/shops/quests/buyQuestModal.vue @@ -81,14 +81,6 @@ margin-bottom: 10px; } - .content-text { - font-family: 'Roboto', sans-serif; - font-size: 14px; - font-weight: normal; - line-height: 1.43; - width: 400px; - } - .right-sidebar { position: absolute; right: -350px; diff --git a/website/client/components/shops/quests/index.vue b/website/client/components/shops/quests/index.vue index 0f499129d0..9f52c66a44 100644 --- a/website/client/components/shops/quests/index.vue +++ b/website/client/components/shops/quests/index.vue @@ -241,13 +241,6 @@ margin: 24px auto; } - .bordered { - border-radius: 2px; - background-color: #f9f9f9; - margin-bottom: 24px; - padding: 24px 24px 10px; - } - .group { display: inline-block; width: 33%; diff --git a/website/client/components/shops/seasonal/index.vue b/website/client/components/shops/seasonal/index.vue index 1c30460371..80a95dcd53 100644 --- a/website/client/components/shops/seasonal/index.vue +++ b/website/client/components/shops/seasonal/index.vue @@ -149,13 +149,6 @@ margin: 24px auto; } - .bordered { - border-radius: 2px; - background-color: #f9f9f9; - margin-bottom: 24px; - padding: 24px 24px 10px; - } - .group { display: inline-block; width: 50%; diff --git a/website/client/components/shops/timeTravelers/index.vue b/website/client/components/shops/timeTravelers/index.vue index e3ff050662..f0b24f7c78 100644 --- a/website/client/components/shops/timeTravelers/index.vue +++ b/website/client/components/shops/timeTravelers/index.vue @@ -129,13 +129,6 @@ margin: 24px auto; } - .bordered { - border-radius: 2px; - background-color: #f9f9f9; - margin-bottom: 24px; - padding: 24px 24px 10px; - } - .group { display: inline-block; width: 33%; diff --git a/website/client/components/userMenu/profile.vue b/website/client/components/userMenu/profile.vue index 204d7e511e..1e7a2c9a39 100644 --- a/website/client/components/userMenu/profile.vue +++ b/website/client/components/userMenu/profile.vue @@ -123,39 +123,26 @@ div .col-12.col-md-6 h2.text-center {{$t('equipment')}} .well - .col-12.col-md-4.item-wrapper - .box(:class='{white: equippedItems.eyewear && equippedItems.eyewear.indexOf("base_0") === -1}') - div(:class="`shop_${equippedItems.eyewear}`") - h3 {{$t('eyewear')}} - .col-12.col-md-4.item-wrapper - .box(:class='{white: equippedItems.head && equippedItems.head.indexOf("base_0") === -1}') - div(:class="`shop_${equippedItems.head}`") - h3 {{$t('headgearCapitalized')}} - .col-12.col-md-4.item-wrapper - .box(:class='{white: equippedItems.headAccessory && equippedItems.headAccessory.indexOf("base_0") === -1}') - div(:class="`shop_${equippedItems.headAccessory}`") - h3 {{$t('headAccess')}} - .col-12.col-md-4.item-wrapper - .box(:class='{white: equippedItems.back && equippedItems.back.indexOf("base_0") === -1}') - div(:class="`shop_${equippedItems.back}`") - h3 {{$t('backAccess')}} - .col-12.col-md-4.item-wrapper - .box(:class='{white: equippedItems.armor && equippedItems.armor.indexOf("base_0") === -1}') - div(:class="`shop_${equippedItems.armor}`") - h3 {{$t('armorCapitalized')}} - .col-12.col-md-4.item-wrapper - .box(:class='{white: equippedItems.body && equippedItems.body.indexOf("base_0") === -1}') - div(:class="`shop_${equippedItems.body}`") - h3 {{$t('bodyAccess')}} - .col-12.col-md-4.item-wrapper - .box(:class='{white: equippedItems.weapon && equippedItems.weapon.indexOf("base_0") === -1}') - div(:class="`shop_${equippedItems.weapon}`") - h3 {{$t('mainHand')}} - .col-12.col-md-4.item-wrapper - .col-12.col-md-4.item-wrapper - .box(:class='{white: equippedItems.shield && equippedItems.shield.indexOf("base_0") === -1}') - div(:class="`shop_${equippedItems.shield}`") - h3 {{$t('offHand')}} + .col-12.col-md-4.item-wrapper(v-for="(label, key) in equipTypes") + .box( + :id="key", + v-if="label !== 'skip'", + :class='{white: equippedItems[key] && equippedItems[key].indexOf("base_0") === -1}' + ) + div(:class="`shop_${equippedItems[key]}`") + b-popover( + v-if="label !== 'skip' && equippedItems[key] && equippedItems[key].indexOf(\"base_0\") === -1", + :target="key", + triggers="hover", + :placement="'right'", + :preventOverflow="false", + ) + h4.gearTitle {{ getGearTitle(equippedItems[key]) }} + attributesGrid.attributesGrid( + :item="content.gear.flat[equippedItems[key]]", + ) + + h3(v-if="label !== 'skip'") {{ label }} .col-12.col-md-6 h2.text-center {{$t('costume')}} .well @@ -292,6 +279,11 @@ div .modal-content { background: #f9f9f9; } + + .gearTitle { + color: white; + margin-bottom: 20px; + } } .message-icon svg { @@ -595,6 +587,7 @@ import achievementsLib from '../../../common/script/libs/achievements'; // @TODO: EMAILS.COMMUNITY_MANAGER_EMAIL const COMMUNITY_MANAGER_EMAIL = 'admin@habitica.com'; import Content from '../../../common/script/content'; +import attributesGrid from 'client/components/inventory/equipment/attributesGrid'; const DROP_ANIMALS = keys(Content.pets); const TOTAL_NUMBER_OF_DROP_ANIMALS = DROP_ANIMALS.length; @@ -612,6 +605,7 @@ export default { sendGemsModal, MemberDetails, toggleSwitch, + attributesGrid, }, data () { return { @@ -636,6 +630,17 @@ export default { selectedPage: 'profile', achievements: {}, content: Content, + equipTypes: { + eyewear: this.$t('eyewear'), + head: this.$t('headgearCapitalized'), + headAccessory: this.$t('headAccess'), + back: this.$t('backAccess'), + armor: this.$t('armorCapitalized'), + body: this.$t('bodyAccess'), + weapon: this.$t('mainHand'), + _skip: 'skip', + shield: this.$t('offHand'), + }, stats: { str: { title: 'strength', @@ -755,6 +760,9 @@ export default { userName: this.user.profile.name, }); }, + getGearTitle (key) { + return this.flatGear[key].text(); + }, getProgressDisplay () { // let currentLoginDay = Content.loginIncentives[this.user.loginIncentives]; // if (!currentLoginDay) return this.$t('checkinReceivedAllRewardsMessage'); diff --git a/website/client/mixins/stats.js b/website/client/mixins/stats.js new file mode 100644 index 0000000000..89131e712a --- /dev/null +++ b/website/client/mixins/stats.js @@ -0,0 +1,69 @@ +let emptyStats = () => { + return { + str: 0, + int: 0, + per: 0, + con: 0, + }; +}; + +export default { + computed: { + stats () { + let gearStats = this.getItemStats(this.item); + let classBonus = this.getClassBonus(this.item); + + let sumNewGearStats = this.calculateStats(gearStats, classBonus, (a1, a2) => { + return a1 + a2; + }); + + return { + gear: gearStats, + classBonus, + sum: sumNewGearStats, + }; + }, + }, + methods: { + getItemStats (item) { + let result = emptyStats(); + + if (!item) { + return result; + } + + for (let attr of this.ATTRIBUTES) { + result[attr] = Number(item[attr]); + } + + return result; + }, + getClassBonus (item) { + let result = emptyStats(); + + if (!item) { + return result; + } + + let itemStats = this.getItemStats(item); + + let userClass = this.user.stats.class; + if (userClass === item.klass || userClass === item.specialClass) { + for (let attr of this.ATTRIBUTES) { + result[attr] = itemStats[attr] * 0.5; + } + } + + return result; + }, + calculateStats (srcStats, otherStats, func) { + let result = emptyStats(); + + for (let attr of this.ATTRIBUTES) { + result[attr] = func(srcStats[attr], otherStats[attr]); + } + + return result; + }, + }, +}; diff --git a/website/common/locales/en/character.json b/website/common/locales/en/character.json index 51a7013b30..162fa6e701 100644 --- a/website/common/locales/en/character.json +++ b/website/common/locales/en/character.json @@ -64,6 +64,7 @@ "classBonusText": "Your class (Warrior, if you haven't unlocked or selected another class) uses its own equipment more effectively than gear from other classes. Equipped gear from your current class gets a 50% boost to the Stat bonus it grants.", "classEquipBonus": "Class Bonus", "battleGear": "Battle Gear", + "gear": "Gear", "battleGearText": "This is the gear you wear into battle; it affects numbers when interacting with your tasks.", "autoEquipBattleGear": "Auto-equip new gear", "costume": "Costume",