diff --git a/test/api/v4/user/POST-user_unequip.test.js b/test/api/v4/user/POST-user_unequip.test.js new file mode 100644 index 0000000000..6437bbe703 --- /dev/null +++ b/test/api/v4/user/POST-user_unequip.test.js @@ -0,0 +1,52 @@ +import { + generateUser, +} from '../../../helpers/api-integration/v4'; +import { UNEQUIP_EQUIPPED } from '../../../../website/common/script/ops/unequip'; + +describe('POST /user/unequip', () => { + let user; + + beforeEach(async () => { + user = await generateUser({ + preferences: { + background: 'violet', + }, + items: { + currentMount: 'BearCub-Base', + currentPet: 'BearCub-Base', + gear: { + owned: { + weapon_warrior_0: true, + weapon_warrior_1: true, + weapon_warrior_2: true, + weapon_wizard_1: true, + weapon_wizard_2: true, + shield_base_0: true, + shield_warrior_1: true, + }, + equipped: { + weapon: 'weapon_warrior_2', + shield: 'shield_warrior_1', + }, + costume: { + weapon: 'weapon_warrior_2', + shield: 'shield_warrior_1', + }, + }, + }, + stats: { gp: 200 }, + }); + }); + + // More tests in common code unit tests + + context('Gear', () => { + it('should unequip all battle gear items', async () => { + await user.post(`/user/unequip/${UNEQUIP_EQUIPPED}`); + await user.sync(); + + expect(user.items.gear.equipped.weapon).to.eq('weapon_base_0'); + expect(user.items.gear.equipped.shield).to.eq('shield_base_0'); + }); + }); +}); diff --git a/test/common/ops/unequip.js b/test/common/ops/unequip.js new file mode 100644 index 0000000000..67825364d0 --- /dev/null +++ b/test/common/ops/unequip.js @@ -0,0 +1,100 @@ +/* eslint-disable camelcase */ + +import { + generateUser, +} from '../../helpers/common.helper'; +import { + UNEQUIP_ALL, + UNEQUIP_BACKGROUND, + UNEQUIP_COSTUME, + UNEQUIP_EQUIPPED, + UNEQUIP_PET_MOUNT, + unEquipByType, +} from '../../../website/common/script/ops/unequip'; + +describe('shared.ops.unequip', () => { + let user; + + beforeEach(() => { + user = generateUser({ + preferences: { + background: 'violet', + }, + items: { + currentMount: 'BearCub-Base', + currentPet: 'BearCub-Base', + gear: { + owned: { + weapon_warrior_0: true, + weapon_warrior_1: true, + weapon_warrior_2: true, + weapon_wizard_1: true, + weapon_wizard_2: true, + shield_base_0: true, + shield_warrior_1: true, + }, + equipped: { + weapon: 'weapon_warrior_2', + shield: 'shield_warrior_1', + }, + costume: { + weapon: 'weapon_warrior_2', + shield: 'shield_warrior_1', + }, + }, + }, + stats: { gp: 200 }, + }); + }); + + context('Gear', () => { + it('should unequip all battle gear items', () => { + unEquipByType(user, { params: { type: UNEQUIP_EQUIPPED } }); + + expect(user.items.gear.equipped.weapon).to.eq('weapon_base_0'); + expect(user.items.gear.equipped.shield).to.eq('shield_base_0'); + }); + }); + + context('Costume', () => { + it('should unequip all costume items', () => { + unEquipByType(user, { params: { type: UNEQUIP_COSTUME } }); + + expect(user.items.gear.costume.weapon).to.eq('weapon_base_0'); + expect(user.items.gear.costume.shield).to.eq('shield_base_0'); + }); + }); + + context('Pet and Mount', () => { + it('should unequip Pet and Mount', () => { + unEquipByType(user, { params: { type: UNEQUIP_PET_MOUNT } }); + + expect(user.items.currentMount).to.eq(''); + expect(user.items.currentPet).to.eq(''); + }); + }); + + context('Background', () => { + it('should unequip Background', () => { + unEquipByType(user, { params: { type: UNEQUIP_BACKGROUND } }); + + expect(user.preferences.background).to.eq(''); + }); + }); + + context('All Items', () => { + it('should unequip all Items', () => { + unEquipByType(user, { params: { type: UNEQUIP_ALL } }); + + expect(user.items.gear.equipped.weapon).to.eq('weapon_base_0'); + expect(user.items.gear.equipped.shield).to.eq('shield_base_0'); + + expect(user.items.gear.costume.weapon).to.eq('weapon_base_0'); + expect(user.items.gear.costume.shield).to.eq('shield_base_0'); + + expect(user.items.currentMount).to.eq(''); + expect(user.items.currentPet).to.eq(''); + expect(user.preferences.background).to.eq(''); + }); + }); +}); diff --git a/website/client/config/storybook/config.js b/website/client/config/storybook/config.js index aa6696576f..f7eca53d5d 100644 --- a/website/client/config/storybook/config.js +++ b/website/client/config/storybook/config.js @@ -50,4 +50,5 @@ function loadStories () { req.keys().forEach(filename => req(filename)); } + configure(loadStories, module); diff --git a/website/client/src/assets/scss/badge.scss b/website/client/src/assets/scss/badge.scss index 9616c9d6f6..2b1fdffb78 100644 --- a/website/client/src/assets/scss/badge.scss +++ b/website/client/src/assets/scss/badge.scss @@ -2,13 +2,15 @@ font-size: 12px; font-weight: bold; line-height: 1.33; - color: $gray-200; - padding: 4px 8px; + text-align: center; + color: $gray-100; + + padding: 0.25rem 0.5rem; box-shadow: 0 1px 3px 0 rgba($black, 0.12), 0 1px 2px 0 rgba($black, 0.24); } .badge-pill { - border-radius: 100px; + border-radius: 12px; } .badge-round { @@ -18,7 +20,7 @@ } .badge-default { - background: $gray-500; + background: $gray-600; box-shadow: none; } diff --git a/website/client/src/assets/scss/button.scss b/website/client/src/assets/scss/button.scss index f4ceeee397..4aae748d97 100644 --- a/website/client/src/assets/scss/button.scss +++ b/website/client/src/assets/scss/button.scss @@ -5,7 +5,7 @@ font-weight: bold; line-height: 1.71; border: 1px solid transparent; - padding: 0.219rem 1rem; + padding: 0.219rem 0.75rem; border-radius: 2px; box-shadow: 0 1px 3px 0 rgba($black, 0.12), 0 1px 2px 0 rgba($black, 0.24); color: $white; @@ -22,7 +22,7 @@ border-color: $purple-400; } - &:active, &.active:not(.btn-flat), &:disabled, &.disabled { + &:active, &.active:not(.btn-flat) { box-shadow: none; } @@ -30,6 +30,13 @@ cursor: default; opacity: 0.75; } + + &.with-icon { + height: 2rem; // otherwise would something set the height to 33px + display: flex; + flex-direction: row; + align-items: center; + } } .btn-front { @@ -41,34 +48,49 @@ .btn-primary { background: $purple-200; border: 1px solid transparent; - - &:hover:not(:disabled):not(.disabled) { - background: #5d3b9c; - border: 1px solid transparent; - } + --icon-color: #{$purple-500}; &:focus { background: $purple-200; border-color: $purple-400; + --icon-color: #{$white}; } &:not(:disabled):not(.disabled) { + &:hover { + background: #5d3b9c; + border: 1px solid transparent; + + --icon-color: #{$white}; + } + + &:active, &.active { + background: $purple-200; + border: 1px solid transparent; + + --icon-color: #{$white}; + } + &:active:focus, &.active:focus { box-shadow: none; border-color: $purple-400; } } - &:not(:disabled):not(.disabled):active, &:not(:disabled):not(.disabled).active { - background: $purple-200; - border: 1px solid transparent; - } - &:disabled, &.disabled { - background: $purple-200; + background: $gray-700; border: 1px solid transparent; cursor: default; - opacity: 0.75; + color: $gray-50; + + --icon-color: #{$gray-300}; + } + + + &.with-icon { + .svg-icon.color { + color: var(--icon-color); + } } } @@ -80,29 +102,27 @@ border: 1px solid transparent; color: $gray-50; + --icon-color: #{$gray-200}; + &:focus, &:active { color: $gray-50; background: $white; border-color: $purple-400; + + --icon-color: #{$purple-300}; } &:not(:disabled):not(.disabled) { - &:active:focus, - &.active:focus { + &:active, &.active { color: $purple-300; - box-shadow: none; - border-color: $purple-400; - } + --icon-color: #{$purple-300}; - &:active, - &.active { - color: $purple-300; - - &.dropdown-toggle { - color: $gray-50; + &:focus { + color: $purple-300; + box-shadow: none; + border-color: $purple-400; } - background: $white; border: 1px solid transparent; } @@ -110,12 +130,10 @@ &:hover { color: $purple-300; - &.dropdown-toggle { - color: $gray-50; - } - background: $white !important; border: 1px solid transparent; + + --icon-color: #{$purple-300}; } } @@ -125,6 +143,14 @@ border: 1px solid transparent; cursor: default; opacity: 0.75; + + --icon-color: #{$gray-300}; + } + + &.with-icon { + .svg-icon.color { + color: var(--icon-color); + } } } diff --git a/website/client/src/assets/scss/drawer.scss b/website/client/src/assets/scss/drawer.scss deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/website/client/src/assets/scss/dropdown.scss b/website/client/src/assets/scss/dropdown.scss index 0f810febcb..0589c35853 100644 --- a/website/client/src/assets/scss/dropdown.scss +++ b/website/client/src/assets/scss/dropdown.scss @@ -1,9 +1,8 @@ .dropdown > .btn { - padding: 0.25rem 0.75rem; + padding: 0.219rem 0.75rem; font-family: 'Roboto', sans-serif; font-size: 14px; font-weight: normal; - line-height: 1.43; } .dropdown-toggle:hover { @@ -25,6 +24,8 @@ border-right: 5px solid transparent; border-left: 5px solid transparent; vertical-align: 0; + margin-left: 1rem; + margin-bottom: 0.1rem; } .dropdown-menu { @@ -54,8 +55,8 @@ &:active, &:hover, &:focus, &.active { - background-color: rgba($purple-600, 0.32) !important; - color: $purple-200 !important; + background-color: rgba($purple-600, 0.25) !important; + color: $purple-300 !important; } &.dropdown-inactive { @@ -75,10 +76,17 @@ .dropdown-label { font-size: 14px; font-weight: bold; - line-height: 1.43; - color: $gray-10; + line-height: 1.71; margin-right: 20px; margin-left: 20px; + + height: 1.5rem; + font-stretch: normal; + font-style: normal; + text-align: right; + + margin-top: calc(0.25rem + 1px); // Padding of the dropdown buttons + button border width + margin-bottom: 0.25rem; } .dropdown-icon-item { diff --git a/website/client/src/assets/scss/form.scss b/website/client/src/assets/scss/form.scss index 11fbce2903..c5cf0b61f7 100644 --- a/website/client/src/assets/scss/form.scss +++ b/website/client/src/assets/scss/form.scss @@ -42,11 +42,16 @@ input, textarea, input.form-control, textarea.form-control { } &.input-search { - background-repeat: no-repeat; - background-position: center left 16px; - background-size: 16px 16px; - background-image: url(~@/assets/svg/for-css/search.svg); - padding-left: 40px; + height: 2rem; + border-radius: 2px; + border: solid 1px $gray-400; + background-color: $white; + + font-size: 14px; + line-height: 1.71; + color: $gray-200; + + padding: 0.25rem 1rem 0.25rem 0.75rem; } &.input-valid, &.input-invalid { @@ -170,7 +175,7 @@ input, textarea, input.form-control, textarea.form-control { } .form-check { - margin-bottom: 0.5rem; + margin-bottom: 0.875rem; padding-left: 0px; } @@ -182,17 +187,21 @@ $bg-disabled-control: #34303a; margin-bottom: .5rem; &-label { - padding-top: 3px; + padding-top: 2px; padding-left: 3px; - } - .custom-control-label::before { - width: 18px; - height: 18px; - background-size: 75% 75%; - background-color: transparent; - border: 2px solid $gray-200; - transition-property: box-shadow; + font-size: 14px; + line-height: 1.71; + color: $gray-50; + + &::before { + width: 18px; + height: 18px; + background-size: 75% 75%; + background-color: transparent; + border: 2px solid $gray-200; + transition-property: box-shadow; + } } } diff --git a/website/client/src/assets/scss/item.scss b/website/client/src/assets/scss/item.scss index 3b03d38a22..ffe1ae5807 100644 --- a/website/client/src/assets/scss/item.scss +++ b/website/client/src/assets/scss/item.scss @@ -5,10 +5,6 @@ margin-right: 24px; } -.items > div:last-of-type { - margin-right: 0px; -} - .item-wrapper { position: relative; display: inline-block; @@ -45,14 +41,13 @@ position: relative; width: 94px; height: 92px; - border-radius: 2px; + border-radius: 4px; background: $white; box-shadow: 0 1px 3px 0 rgba($black, 0.12), 0 1px 2px 0 rgba($black, 0.24); border: 1px solid transparent; cursor: pointer; &-empty { - background: $gray-10; box-shadow: none; cursor: auto; } @@ -85,7 +80,7 @@ margin: 0 auto; } -.drawer-content .item:hover { +.drawer-content .item.item-empty:hover { border-color: transparent; box-shadow: none; } diff --git a/website/client/src/assets/scss/page.scss b/website/client/src/assets/scss/page.scss index b424111b25..9c2a08b136 100644 --- a/website/client/src/assets/scss/page.scss +++ b/website/client/src/assets/scss/page.scss @@ -20,5 +20,18 @@ body { } .page-header { - color: $purple-200; + color: $purple-300; + + height: 2rem; + font-size: 24px; + font-weight: bold; + line-height: 1.33; +} + +.sub-header { + height: 1.75rem; + font-size: 20px; + font-weight: bold; + line-height: 1.4; + color: $gray-10; } diff --git a/website/client/src/assets/scss/typography.scss b/website/client/src/assets/scss/typography.scss index 5331e7b121..30474404ed 100644 --- a/website/client/src/assets/scss/typography.scss +++ b/website/client/src/assets/scss/typography.scss @@ -46,12 +46,16 @@ a, a:not([href]):not([tabindex]) { } // Headers -h1, h2, h3, h4, h5, h6 { +h1, h2, h5, h6 { font-family: 'Roboto Condensed', sans-serif; font-weight: bold; color: $gray-10; } +h3, h4 { + font-weight: bold; +} + h1 { font-size: 24px; line-height: 1.67; @@ -65,15 +69,15 @@ h2 { } h3 { - font-size: 16px; - line-height: 1.5; - color: $gray-50; - margin-bottom: 4px; + font-size: 0.875rem; + line-height: 1.71; + color: $gray-10; } h4 { - font-size: 14px; - line-height: 1.43; + font-size: 0.875rem; + line-height: 1.71; + color: $gray-100; } .textCondensed { diff --git a/website/client/src/assets/svg/equip.svg b/website/client/src/assets/svg/equip.svg new file mode 100644 index 0000000000..b36adf27d9 --- /dev/null +++ b/website/client/src/assets/svg/equip.svg @@ -0,0 +1,7 @@ + + + + + diff --git a/website/client/src/assets/svg/unequip.svg b/website/client/src/assets/svg/unequip.svg new file mode 100644 index 0000000000..cdffe603de --- /dev/null +++ b/website/client/src/assets/svg/unequip.svg @@ -0,0 +1,7 @@ + + + + + diff --git a/website/client/src/components/inventory/equipment/attributesGrid.vue b/website/client/src/components/inventory/equipment/attributesGrid.vue index 00bee8de14..4ef8a82528 100644 --- a/website/client/src/components/inventory/equipment/attributesGrid.vue +++ b/website/client/src/components/inventory/equipment/attributesGrid.vue @@ -4,6 +4,7 @@ v-for="attr in ATTRIBUTES" :key="attr" class="popover-content-attr" + :class="`attr-${attr}`" >
{{ `${$t(attr)}: ` }} {{ `${stats.sum[attr]}` }} -
- +
+
-

+

{{ itemText }}

{{ getClassName(itemClass) }} @@ -54,10 +51,17 @@ :item="item" />
@@ -69,15 +73,38 @@ @@ -154,14 +186,18 @@ import svgWarrior from '@/assets/svg/warrior.svg'; import svgWizard from '@/assets/svg/wizard.svg'; import svgRogue from '@/assets/svg/rogue.svg'; import svgHealer from '@/assets/svg/healer.svg'; +import svgEquipIcon from '@/assets/svg/equip.svg'; +import svgUnEquipIcon from '@/assets/svg/unequip.svg'; import Avatar from '@/components/avatar'; import attributesGrid from '@/components/inventory/equipment/attributesGrid.vue'; +import closeIcon from '@/components/shared/closeIcon'; export default { components: { Avatar, attributesGrid, + closeIcon, }, props: { item: { @@ -185,6 +221,8 @@ export default { wizard: svgWizard, rogue: svgRogue, healer: svgHealer, + equip: svgEquipIcon, + unEquip: svgUnEquipIcon, }), }; }, diff --git a/website/client/src/components/inventory/equipment/index.vue b/website/client/src/components/inventory/equipment/index.vue index 4b587f88d1..0be161765f 100644 --- a/website/client/src/components/inventory/equipment/index.vue +++ b/website/client/src/components/inventory/equipment/index.vue @@ -1,65 +1,57 @@