mirror of
https://github.com/HabitRPG/habitica.git
synced 2025-12-16 06:07:21 +01:00
Inventory: fixes / layout (#11948)
Co-authored-by: Sabe Jones <sabrecat@gmail.com>
This commit is contained in:
52
test/api/v4/user/POST-user_unequip.test.js
Normal file
52
test/api/v4/user/POST-user_unequip.test.js
Normal file
@@ -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');
|
||||
});
|
||||
});
|
||||
});
|
||||
100
test/common/ops/unequip.js
Normal file
100
test/common/ops/unequip.js
Normal file
@@ -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('');
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -50,4 +50,5 @@ function loadStories () {
|
||||
req.keys().forEach(filename => req(filename));
|
||||
}
|
||||
|
||||
|
||||
configure(loadStories, module);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
7
website/client/src/assets/svg/equip.svg
Normal file
7
website/client/src/assets/svg/equip.svg
Normal file
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 24.0.3, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 16 16" style="enable-background:new 0 0 16 16;" xml:space="preserve">
|
||||
<path style="fill-rule:evenodd;clip-rule:evenodd;fill:#878190;" d="M12,7.9h2c0,4.1-3,7.5-7,8.1h0h0c-4-0.6-7-4-7-8.1V3l7-3v2.2
|
||||
L2,4.3v3.6c0,2.9,2.1,5.5,5,6C9.9,13.4,12,10.9,12,7.9z M14,2V0h-2v2h-2v2h2v2h2V4h2V2H14z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 570 B |
7
website/client/src/assets/svg/unequip.svg
Normal file
7
website/client/src/assets/svg/unequip.svg
Normal file
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 24.0.3, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 16 16" style="enable-background:new 0 0 16 16;" xml:space="preserve">
|
||||
<path style="fill-rule:evenodd;clip-rule:evenodd;fill:#878190;" d="M12,7.9h2c0,4.1-3,7.5-7,8.1h0h0c-4-0.6-7-4-7-8.1V3l7-3v2.2
|
||||
L2,4.3v3.6c0,2.9,2.1,5.5,5,6C9.9,13.4,12,10.9,12,7.9z M10,6h6V4h-6V6z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 552 B |
@@ -4,6 +4,7 @@
|
||||
v-for="attr in ATTRIBUTES"
|
||||
:key="attr"
|
||||
class="popover-content-attr"
|
||||
:class="`attr-${attr}`"
|
||||
>
|
||||
<div class="group-content">
|
||||
<span
|
||||
@@ -11,7 +12,7 @@
|
||||
:class="{'hasValue': hasSumValue(attr) }"
|
||||
>{{ `${$t(attr)}: ` }}</span>
|
||||
<span
|
||||
class="popover-content-attr-cell label value"
|
||||
class="popover-content-attr-cell label key-value value"
|
||||
:class="{'green': hasSumValue(attr) }"
|
||||
>{{ `${stats.sum[attr]}` }}</span>
|
||||
<span
|
||||
@@ -53,6 +54,16 @@
|
||||
width: calc(50% - 1px);
|
||||
background-color: $gray-50;
|
||||
|
||||
.attr-str, .attr-int {
|
||||
padding-top: 0.25rem;
|
||||
padding-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.attr-con, .attr-per {
|
||||
padding-bottom: 0.75rem;
|
||||
padding-top: 0.5rem;
|
||||
}
|
||||
|
||||
&:nth-of-type(even) {
|
||||
margin-left: 1px;
|
||||
}
|
||||
@@ -70,12 +81,12 @@
|
||||
}
|
||||
|
||||
.popover-content-attr-cell {
|
||||
width: 70%;
|
||||
width: 65%;
|
||||
text-align: left;
|
||||
|
||||
&:nth-of-type(even) {
|
||||
text-align: right;
|
||||
width: 30%;
|
||||
width: 35%;
|
||||
}
|
||||
|
||||
&.key {
|
||||
@@ -115,7 +126,7 @@
|
||||
.modal-body {
|
||||
|
||||
.group-content {
|
||||
padding: 8px 17px;
|
||||
padding: 0.25rem 1rem;
|
||||
}
|
||||
|
||||
.popover-content-attr {
|
||||
@@ -129,32 +140,43 @@
|
||||
|
||||
.popover-content-attr-cell {
|
||||
&.key {
|
||||
color: $gray-400;
|
||||
font-size: 16px;
|
||||
color: $gray-100;
|
||||
font-size: 0.875rem;
|
||||
font-weight: bold;
|
||||
line-height: 1.25;
|
||||
line-height: 1.71;
|
||||
|
||||
opacity: 0.5;
|
||||
|
||||
&.hasValue {
|
||||
color: $gray-50;
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
&.label {
|
||||
color: $gray-400;
|
||||
font-size: 12px;
|
||||
font-weight: bold;
|
||||
color: $gray-100;
|
||||
font-size: 0.75rem;
|
||||
line-height: 1.33;
|
||||
opacity: 0.5;
|
||||
|
||||
&.bold {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
&.key-value {
|
||||
line-height: 1.71;
|
||||
}
|
||||
|
||||
&.hasValue {
|
||||
color: $gray-200;
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
&.label.value {
|
||||
text-align: right;
|
||||
|
||||
&.green {
|
||||
color: $green-10;
|
||||
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,15 +4,11 @@
|
||||
id="equipgear-modal"
|
||||
:visible="true"
|
||||
:hide-header="true"
|
||||
:hide-footer="true"
|
||||
@change="onChange($event)"
|
||||
>
|
||||
<div class="close">
|
||||
<span
|
||||
class="svg-icon inline icon-10"
|
||||
aria-hidden="true"
|
||||
@click="hideDialog()"
|
||||
v-html="icons.close"
|
||||
></span>
|
||||
<div class="dialog-close">
|
||||
<close-icon @click="hideDialog()" />
|
||||
</div>
|
||||
<div
|
||||
v-if="item != null"
|
||||
@@ -23,11 +19,12 @@
|
||||
:member="user"
|
||||
:avatar-only="true"
|
||||
:with-background="true"
|
||||
:hide-class-badge="true"
|
||||
:override-avatar-gear="memberOverrideAvatarGear(item)"
|
||||
:sprites-margin="'0px auto auto -1px'"
|
||||
:show-visual-buffs="false"
|
||||
/>
|
||||
<h4 class="title">
|
||||
<h4 class="title mt-3">
|
||||
{{ itemText }}
|
||||
</h4>
|
||||
<div
|
||||
@@ -36,14 +33,14 @@
|
||||
></div>
|
||||
<span
|
||||
v-if="showClassTag"
|
||||
class="classTag"
|
||||
class="classTag mt-3"
|
||||
>
|
||||
<span
|
||||
class="svg-icon inline icon-24"
|
||||
class="svg-icon inline icon-16"
|
||||
v-html="icons[itemClass]"
|
||||
></span>
|
||||
<span
|
||||
class="className textCondensed"
|
||||
class="className"
|
||||
:class="itemClass"
|
||||
>{{ getClassName(itemClass) }}</span>
|
||||
</span>
|
||||
@@ -54,10 +51,17 @@
|
||||
:item="item"
|
||||
/>
|
||||
<button
|
||||
class="btn btn-primary"
|
||||
class="btn with-icon mt-4"
|
||||
:class="{'btn-primary': !isEquipped, 'btn-secondary': isEquipped }"
|
||||
@click="equipItem()"
|
||||
>
|
||||
{{ $t(isEquipped ? 'unequip' : 'equip') }}
|
||||
<span
|
||||
class="svg-icon color inline icon-16 mr-2"
|
||||
v-html="isEquipped ? icons.unEquip : icons.equip"
|
||||
></span>
|
||||
<span class="button-label">
|
||||
{{ $t(isEquipped ? 'unequip' : 'equip') }}
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -69,15 +73,38 @@
|
||||
</template>
|
||||
|
||||
<style lang="scss">
|
||||
|
||||
@import '~@/assets/scss/colors.scss';
|
||||
@import '~@/assets/scss/mixins.scss';
|
||||
|
||||
#equipgear-modal {
|
||||
@include centeredModal();
|
||||
|
||||
.modal-content {
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 14px 28px 0 #1a181d3d, 0 10px 10px 0 #1a181d47;
|
||||
}
|
||||
|
||||
.modal-body {
|
||||
padding: 2rem 1.5rem;
|
||||
}
|
||||
|
||||
.dialog-close {
|
||||
|
||||
}
|
||||
|
||||
.modal-dialog {
|
||||
width: 330px;
|
||||
|
||||
.text {
|
||||
min-height: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.text {
|
||||
font-size: 0.875rem;
|
||||
line-height: 1.71;
|
||||
text-align: center;
|
||||
color: $gray-50;
|
||||
}
|
||||
|
||||
.content {
|
||||
@@ -89,7 +116,6 @@
|
||||
}
|
||||
|
||||
.inner-content {
|
||||
margin: 33px auto auto;
|
||||
width: 282px;
|
||||
}
|
||||
|
||||
@@ -102,10 +128,11 @@
|
||||
|
||||
.className {
|
||||
height: 24px;
|
||||
font-size: 16px;
|
||||
line-height: 1.5;
|
||||
font-size: 0.875rem;
|
||||
line-height: 1.71;
|
||||
text-align: left;
|
||||
margin-left: 8px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.healer {
|
||||
@@ -124,10 +151,15 @@
|
||||
color: $wizard-color;
|
||||
}
|
||||
|
||||
.title {
|
||||
color: $gray-10;
|
||||
}
|
||||
|
||||
.attributesGrid {
|
||||
background-color: $gray-500;
|
||||
|
||||
margin: 10px 0 24px;
|
||||
margin: 1rem 0 0;
|
||||
border-radius: 4px;
|
||||
border: 1px solid #f4f4f4;
|
||||
}
|
||||
|
||||
.avatar {
|
||||
@@ -139,9 +171,9 @@
|
||||
}
|
||||
}
|
||||
|
||||
button.btn.btn-primary {
|
||||
margin-top: 24px;
|
||||
margin-bottom: 24px;
|
||||
button.btn {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -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,
|
||||
}),
|
||||
};
|
||||
},
|
||||
|
||||
@@ -1,65 +1,57 @@
|
||||
<template>
|
||||
<div class="row">
|
||||
<div class="standard-sidebar d-none d-sm-block">
|
||||
<div class="form-group">
|
||||
<input
|
||||
v-model="searchText"
|
||||
class="form-control input-search"
|
||||
type="text"
|
||||
:placeholder="$t('search')"
|
||||
>
|
||||
</div>
|
||||
<div class="form">
|
||||
<h2 v-once>
|
||||
{{ $t('filter') }}
|
||||
</h2>
|
||||
<h3>{{ groupBy === 'type' ? $t('equipmentType') : $t('class') }}</h3>
|
||||
<div class="form-group">
|
||||
<div
|
||||
v-for="group in itemsGroups"
|
||||
:key="group.key"
|
||||
class="form-check"
|
||||
<filter-sidebar>
|
||||
<div class="form-group" slot="search">
|
||||
<input
|
||||
v-model="searchText"
|
||||
class="form-control input-search"
|
||||
type="text"
|
||||
:placeholder="$t('search')"
|
||||
>
|
||||
<div class="custom-control custom-checkbox">
|
||||
<input
|
||||
:id="groupBy + group.key"
|
||||
v-model="viewOptions[group.key].selected"
|
||||
class="custom-control-input"
|
||||
type="checkbox"
|
||||
>
|
||||
<label
|
||||
v-once
|
||||
class="custom-control-label"
|
||||
:for="groupBy + group.key"
|
||||
>{{ group.label }}</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form">
|
||||
<filter-group :title="groupBy === 'type' ? $t('equipmentType') : $t('class')">
|
||||
<checkbox v-for="group in itemsGroups"
|
||||
:key="group.key"
|
||||
:id="groupBy + group.key"
|
||||
:checked.sync="viewOptions[group.key].selected"
|
||||
:text="group.label"/>
|
||||
</filter-group>
|
||||
</div>
|
||||
</filter-sidebar>
|
||||
</div>
|
||||
<div class="standard-page">
|
||||
<div class="clearfix">
|
||||
<h1
|
||||
v-once
|
||||
class="float-left mb-4 page-header"
|
||||
>
|
||||
{{ $t('equipment') }}
|
||||
</h1>
|
||||
<div class="float-right">
|
||||
<span class="dropdown-label">{{ $t('sortBy') }}</span>
|
||||
<b-dropdown
|
||||
:text="$t(selectedSortGearBy)"
|
||||
right="right"
|
||||
<div class="mb-4 float-left">
|
||||
<button
|
||||
class="page-header btn-flat equipment-type-button textCondensed"
|
||||
:class="{'active': !costumeMode}"
|
||||
@click="selectDrawerTab('equipment')"
|
||||
>
|
||||
<b-dropdown-item
|
||||
v-for="sort in sortGearBy"
|
||||
:key="sort"
|
||||
:active="selectedSortGearBy === sort"
|
||||
@click="selectedSortGearBy = sort"
|
||||
>
|
||||
{{ $t(sort) }}
|
||||
</b-dropdown-item>
|
||||
</b-dropdown>
|
||||
{{ $t('battleGear') }}
|
||||
</button>
|
||||
<button
|
||||
class="page-header btn-flat equipment-type-button textCondensed"
|
||||
:class="{'active': costumeMode}"
|
||||
@click="selectDrawerTab('costume')"
|
||||
>
|
||||
{{ $t('costume') }}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="float-right top-menu">
|
||||
<span class="dropdown-label">{{ $t('sortBy') }}</span>
|
||||
<select-translated-array
|
||||
:right="true"
|
||||
:items="sortGearBy"
|
||||
:value="selectedSortGearBy"
|
||||
@select="selectedSortGearBy = $event"
|
||||
class="inline"
|
||||
:inlineDropdown="false"
|
||||
/>
|
||||
|
||||
<span class="dropdown-label">{{ $t('groupBy2') }}</span>
|
||||
<b-dropdown
|
||||
:text="$t(groupBy === 'type' ? 'equipmentType' : 'class')"
|
||||
@@ -78,31 +70,37 @@
|
||||
{{ $t('class') }}
|
||||
</b-dropdown-item>
|
||||
</b-dropdown>
|
||||
|
||||
<span class="divider"></span>
|
||||
<unequip-dropdown />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<drawer
|
||||
:title="$t('equipment')"
|
||||
:no-title-bottom-padding="true"
|
||||
:error-message="(costumeMode && !user.preferences.costume) ? $t('costumeDisabled') : null"
|
||||
:open-status="openStatus"
|
||||
@toggled="drawerToggled"
|
||||
>
|
||||
<div slot="drawer-title-row" class="title-row-tabs">
|
||||
<div class="drawer-tab">
|
||||
<a
|
||||
class="drawer-tab-text"
|
||||
:class="{'drawer-tab-text-active': !costumeMode}"
|
||||
@click.prevent.stop="selectDrawerTab('equipment')"
|
||||
>{{ $t('battleGear') }}</a>
|
||||
</div>
|
||||
<div class="drawer-tab">
|
||||
<a
|
||||
class="drawer-tab-text"
|
||||
:class="{'drawer-tab-text-active': costumeMode}"
|
||||
@click.prevent.stop="selectDrawerTab('costume')"
|
||||
>{{ $t('costume') }}</a>
|
||||
</div>
|
||||
</div>
|
||||
<div slot="drawer-header">
|
||||
<div class="drawer-tab-container">
|
||||
<div class="drawer-tab text-right">
|
||||
<a
|
||||
class="drawer-tab-text"
|
||||
:class="{'drawer-tab-text-active': !costumeMode}"
|
||||
@click="selectDrawerTab('equipment')"
|
||||
>{{ $t('equipment') }}</a>
|
||||
</div>
|
||||
<div class="clearfix">
|
||||
<div class="drawer-tab float-left">
|
||||
<a
|
||||
class="drawer-tab-text"
|
||||
:class="{'drawer-tab-text-active': costumeMode}"
|
||||
@click="selectDrawerTab('costume')"
|
||||
>{{ $t('costume') }}</a>
|
||||
</div>
|
||||
<toggle-switch
|
||||
class="float-right align-with-tab"
|
||||
:label="$t(costumeMode ? 'useCostume' : 'autoEquipBattleGear')"
|
||||
@@ -115,7 +113,7 @@
|
||||
</div>
|
||||
<div
|
||||
slot="drawer-slider"
|
||||
class="items items-one-line"
|
||||
class="equipment items items-one-line"
|
||||
>
|
||||
<item
|
||||
v-for="(label, group) in gearTypesToStrings"
|
||||
@@ -130,7 +128,7 @@
|
||||
:popover-position="'top'"
|
||||
:show-popover="flatGear[activeItems[group]]
|
||||
&& Boolean(flatGear[activeItems[group]].text)"
|
||||
@click="equipItem(flatGear[activeItems[group]])"
|
||||
@click="openEquipDialog(flatGear[activeItems[group]])"
|
||||
>
|
||||
<template
|
||||
slot="popoverContent"
|
||||
@@ -142,8 +140,8 @@
|
||||
slot="itemBadge"
|
||||
slot-scope="context"
|
||||
>
|
||||
<starBadge
|
||||
:selected="true"
|
||||
<equip-badge
|
||||
:equipped="true"
|
||||
:show="!costumeMode || user.preferences.costume"
|
||||
@click="equipItem(context.item)"
|
||||
/>
|
||||
@@ -187,8 +185,8 @@
|
||||
slot="itemBadge"
|
||||
slot-scope="context"
|
||||
>
|
||||
<starBadge
|
||||
:selected="activeItems[context.item.type] === context.item.key"
|
||||
<equip-badge
|
||||
:equipped="activeItems[context.item.type] === context.item.key"
|
||||
:show="!costumeMode || user.preferences.costume"
|
||||
@click="equipItem(context.item)"
|
||||
/>
|
||||
@@ -215,17 +213,76 @@
|
||||
</template>
|
||||
|
||||
<style lang="scss">
|
||||
@import '~@/assets/scss/colors.scss';
|
||||
|
||||
.pointer {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.align-with-tab {
|
||||
margin-top: 3px;
|
||||
margin-right: 3px;
|
||||
}
|
||||
|
||||
.drawer-tab-text {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.equipment.items .item-empty {
|
||||
background: $gray-10 !important;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import '~@/assets/scss/colors.scss';
|
||||
|
||||
.page-header.btn-flat {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.title-row-tabs {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
|
||||
.drawer-tab {
|
||||
background: transparent;
|
||||
}
|
||||
}
|
||||
|
||||
.equipment-type-button {
|
||||
height: 2rem;
|
||||
font-size: 24px;
|
||||
font-weight: bold;
|
||||
font-stretch: condensed;
|
||||
line-height: 1.33;
|
||||
letter-spacing: normal;
|
||||
color: $gray-10;
|
||||
|
||||
margin-right: 1.125rem;
|
||||
padding-left: 0;
|
||||
padding-right: 0;
|
||||
padding-bottom: 2.5rem;
|
||||
|
||||
&.active, &:hover {
|
||||
color: $purple-300;
|
||||
box-shadow: 0px -0.25rem 0px $purple-300 inset;
|
||||
outline: none;
|
||||
}
|
||||
}
|
||||
|
||||
.divider {
|
||||
width: 0.063rem;
|
||||
height: 2rem;
|
||||
background-color: $gray-500;
|
||||
margin-left: 1rem;
|
||||
margin-right: 1rem;
|
||||
}
|
||||
|
||||
.top-menu {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
@@ -242,13 +299,19 @@ import toggleSwitch from '@/components/ui/toggleSwitch';
|
||||
import Item from '@/components/inventory/item';
|
||||
import ItemRows from '@/components/ui/itemRows';
|
||||
import EquipmentAttributesPopover from '@/components/inventory/equipment/attributesPopover';
|
||||
import StarBadge from '@/components/ui/starBadge';
|
||||
import Drawer from '@/components/ui/drawer';
|
||||
|
||||
import i18n from '@/../../common/script/i18n';
|
||||
|
||||
import EquipGearModal from './equipGearModal';
|
||||
|
||||
import FilterGroup from '@/components/ui/filterGroup';
|
||||
import FilterSidebar from '@/components/ui/filterSidebar';
|
||||
import Checkbox from '@/components/ui/checkbox';
|
||||
import UnequipDropdown from '@/components/inventory/equipment/unequipDropdown';
|
||||
import EquipBadge from '@/components/ui/equipBadge';
|
||||
import SelectTranslatedArray from '@/components/tasks/modal-controls/selectTranslatedArray';
|
||||
|
||||
const sortGearTypes = ['sortByName', 'sortByCon', 'sortByPer', 'sortByStr', 'sortByInt'];
|
||||
|
||||
const sortGearTypeMap = {
|
||||
@@ -262,10 +325,15 @@ const sortGearTypeMap = {
|
||||
export default {
|
||||
name: 'Equipment',
|
||||
components: {
|
||||
SelectTranslatedArray,
|
||||
EquipBadge,
|
||||
UnequipDropdown,
|
||||
Checkbox,
|
||||
FilterSidebar,
|
||||
FilterGroup,
|
||||
Item,
|
||||
ItemRows,
|
||||
EquipmentAttributesPopover,
|
||||
StarBadge,
|
||||
Drawer,
|
||||
toggleSwitch,
|
||||
EquipGearModal,
|
||||
@@ -452,6 +520,7 @@ export default {
|
||||
this.costumeMode = false;
|
||||
}
|
||||
setLocalSetting(CONSTANTS.keyConstants.CURRENT_EQUIPMENT_DRAWER_TAB, tabNameValue);
|
||||
this.$store.state.equipmentDrawerOpen = true;
|
||||
},
|
||||
openEquipDialog (item) {
|
||||
this.gearToEquip = item;
|
||||
|
||||
@@ -0,0 +1,123 @@
|
||||
<template>
|
||||
<b-dropdown
|
||||
right="right"
|
||||
toggle-class="with-icon"
|
||||
>
|
||||
<template v-slot:button-content>
|
||||
<span class="svg-icon inline color"
|
||||
v-html="icons.unequipIcon">
|
||||
</span>
|
||||
<span class="button-label" v-once>{{ $t('unequip') }}</span>
|
||||
</template>
|
||||
<b-dropdown-item
|
||||
@click="unequipBattleGear()"
|
||||
>
|
||||
{{ $t('battleGear') }}
|
||||
</b-dropdown-item>
|
||||
<b-dropdown-item
|
||||
@click="unequipCostume()"
|
||||
>
|
||||
{{ $t('costume') }}
|
||||
</b-dropdown-item>
|
||||
<b-dropdown-item
|
||||
@click="unequipPetMount()"
|
||||
>
|
||||
{{ $t('petAndMount') }}
|
||||
</b-dropdown-item>
|
||||
<b-dropdown-item
|
||||
@click="unequipBackground()"
|
||||
>
|
||||
{{ $t('background') }}
|
||||
</b-dropdown-item>
|
||||
<b-dropdown-item
|
||||
@click="unequipAllItems()"
|
||||
>
|
||||
{{ $t('allItems') }}
|
||||
</b-dropdown-item>
|
||||
</b-dropdown>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {
|
||||
UNEQUIP_ALL,
|
||||
UNEQUIP_COSTUME,
|
||||
UNEQUIP_EQUIPPED,
|
||||
UNEQUIP_BACKGROUND,
|
||||
UNEQUIP_PET_MOUNT,
|
||||
} from '../../../../../common/script/ops/unequip';
|
||||
|
||||
import unequipIcon from '@/assets/svg/unequip.svg';
|
||||
|
||||
export default {
|
||||
name: 'unequipDropdown',
|
||||
data () {
|
||||
return {
|
||||
icons: Object.freeze({
|
||||
unequipIcon,
|
||||
}),
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
unequipPetMountBackground () {
|
||||
this.$store.dispatch('user:unequip', {
|
||||
type: UNEQUIP_PET_MOUNT,
|
||||
});
|
||||
},
|
||||
unequipBattleGear () {
|
||||
this.$store.dispatch('user:unequip', {
|
||||
type: UNEQUIP_EQUIPPED,
|
||||
});
|
||||
},
|
||||
unequipCostume () {
|
||||
this.$store.dispatch('user:unequip', {
|
||||
type: UNEQUIP_COSTUME,
|
||||
});
|
||||
},
|
||||
unequipPetMount () {
|
||||
this.$store.dispatch('user:unequip', {
|
||||
type: UNEQUIP_PET_MOUNT,
|
||||
});
|
||||
},
|
||||
unequipBackground () {
|
||||
this.$store.dispatch('user:unequip', {
|
||||
type: UNEQUIP_BACKGROUND,
|
||||
});
|
||||
},
|
||||
unequipAllItems () {
|
||||
this.$store.dispatch('user:unequip', {
|
||||
type: UNEQUIP_ALL,
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import '~@/assets/scss/colors.scss';
|
||||
|
||||
::v-deep {
|
||||
.btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
&::after {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.svg-icon {
|
||||
width: 1rem;
|
||||
height: 1rem;
|
||||
margin-right: 0.5rem;
|
||||
}
|
||||
|
||||
.button-label {
|
||||
width: 3.25rem;
|
||||
height: 1.5rem;
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
line-height: 1.71;
|
||||
}
|
||||
|
||||
</style>
|
||||
@@ -5,71 +5,45 @@
|
||||
@mouseMoved="mouseMoved($event)"
|
||||
>
|
||||
<div class="standard-sidebar d-none d-sm-block">
|
||||
<div class="form-group">
|
||||
<input
|
||||
v-model="searchText"
|
||||
class="form-control input-search"
|
||||
type="text"
|
||||
:placeholder="$t('search')"
|
||||
>
|
||||
</div>
|
||||
<div class="form">
|
||||
<h2 v-once>
|
||||
{{ $t('filter') }}
|
||||
</h2>
|
||||
<h3 v-once>
|
||||
{{ $t('equipmentType') }}
|
||||
</h3>
|
||||
<div class="form-group">
|
||||
<div
|
||||
v-for="group in groups"
|
||||
:key="group.key"
|
||||
class="form-check"
|
||||
<filter-sidebar>
|
||||
<div class="form-group" slot="search">
|
||||
<input
|
||||
v-model="searchText"
|
||||
class="form-control input-search"
|
||||
type="text"
|
||||
:placeholder="$t('search')"
|
||||
>
|
||||
<div class="custom-control custom-checkbox">
|
||||
<input
|
||||
:id="group.key"
|
||||
v-model="group.selected"
|
||||
class="custom-control-input"
|
||||
type="checkbox"
|
||||
>
|
||||
<label
|
||||
v-once
|
||||
class="custom-control-label"
|
||||
:for="group.key"
|
||||
>{{ $t(group.key) }}</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form">
|
||||
<filter-group :title="$t('equipmentType')">
|
||||
<checkbox v-for="group in groups"
|
||||
:key="group.key"
|
||||
:id="group.key"
|
||||
:checked.sync="group.selected"
|
||||
:text="$t(group.key)"/>
|
||||
</filter-group>
|
||||
</div>
|
||||
</filter-sidebar>
|
||||
</div>
|
||||
<div class="standard-page">
|
||||
<div class="clearfix">
|
||||
<h1
|
||||
v-once
|
||||
class="float-left mb-4 page-header"
|
||||
class="float-left mb-3 page-header"
|
||||
>
|
||||
{{ $t('items') }}
|
||||
</h1>
|
||||
<div class="float-right">
|
||||
<span class="dropdown-label">{{ $t('sortBy') }}</span>
|
||||
<b-dropdown
|
||||
:text="$t(sortBy)"
|
||||
right="right"
|
||||
>
|
||||
<b-dropdown-item
|
||||
:active="sortBy === 'quantity'"
|
||||
@click="sortBy = 'quantity'"
|
||||
>
|
||||
{{ $t('quantity') }}
|
||||
</b-dropdown-item>
|
||||
<b-dropdown-item
|
||||
:active="sortBy === 'AZ'"
|
||||
@click="sortBy = 'AZ'"
|
||||
>
|
||||
{{ $t('AZ') }}
|
||||
</b-dropdown-item>
|
||||
</b-dropdown>
|
||||
<select-translated-array
|
||||
:right="true"
|
||||
:items="['quantity', 'AZ']"
|
||||
:value="sortBy"
|
||||
@select="sortBy = $event"
|
||||
class="inline"
|
||||
:inlineDropdown="false"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -80,7 +54,7 @@
|
||||
:key="group.key"
|
||||
>
|
||||
<!-- eslint-enable vue/no-use-v-if-with-v-for -->
|
||||
<h2 class="d-flex align-items-center mb-3">
|
||||
<h2 class="d-flex align-items-center mb-3 sub-header">
|
||||
{{ $t(group.key) }}
|
||||
<span
|
||||
v-if="group.key != 'special'"
|
||||
@@ -320,6 +294,8 @@
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import '~@/assets/scss/colors.scss';
|
||||
|
||||
.eggInfo, .hatchingPotionInfo {
|
||||
position: absolute;
|
||||
left: -500px;
|
||||
@@ -347,6 +323,7 @@
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
<script>
|
||||
@@ -356,6 +333,7 @@ import moment from 'moment';
|
||||
import Item from '@/components/inventory/item';
|
||||
import ItemRows from '@/components/ui/itemRows';
|
||||
import CountBadge from '@/components/ui/countBadge';
|
||||
import FilterSidebar from '@/components/ui/filterSidebar';
|
||||
|
||||
import cardsModal from './cards-modal';
|
||||
|
||||
@@ -369,6 +347,9 @@ import { createAnimal } from '@/libs/createAnimal';
|
||||
import notifications from '@/mixins/notifications';
|
||||
import DragDropDirective from '@/directives/dragdrop.directive';
|
||||
import MouseMoveDirective from '@/directives/mouseposition.directive';
|
||||
import FilterGroup from '@/components/ui/filterGroup';
|
||||
import Checkbox from '@/components/ui/checkbox';
|
||||
import SelectTranslatedArray from '@/components/tasks/modal-controls/selectTranslatedArray';
|
||||
|
||||
const allowedSpecialItems = ['snowball', 'spookySparkles', 'shinySeed', 'seafoam'];
|
||||
|
||||
@@ -391,6 +372,9 @@ let lastMouseMoveEvent = {};
|
||||
export default {
|
||||
name: 'Items',
|
||||
components: {
|
||||
SelectTranslatedArray,
|
||||
Checkbox,
|
||||
FilterGroup,
|
||||
Item,
|
||||
ItemRows,
|
||||
HatchedPetDialog,
|
||||
@@ -398,6 +382,7 @@ export default {
|
||||
startQuestModal,
|
||||
cardsModal,
|
||||
QuestInfo,
|
||||
FilterSidebar,
|
||||
},
|
||||
directives: {
|
||||
drag: DragDropDirective,
|
||||
|
||||
@@ -47,6 +47,7 @@
|
||||
|
||||
<style lang="scss">
|
||||
@import '~@/assets/scss/mixins.scss';
|
||||
@import '~@/assets/scss/colors.scss';
|
||||
|
||||
#hatching-modal {
|
||||
@include centeredModal();
|
||||
@@ -66,7 +67,7 @@
|
||||
font-weight: bold;
|
||||
line-height: 1.2;
|
||||
text-align: center;
|
||||
color: #4e4a57;
|
||||
color: $gray-50;
|
||||
}
|
||||
|
||||
.text {
|
||||
@@ -75,7 +76,7 @@
|
||||
font-size: 14px;
|
||||
line-height: 1.43;
|
||||
text-align: center;
|
||||
color: #686274;
|
||||
color: $gray-100;
|
||||
}
|
||||
|
||||
span.svg-icon.icon-10 {
|
||||
@@ -87,6 +88,27 @@
|
||||
.modal-footer {
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.potionEggGroup {
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.potionEggBackground {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
width: 112px;
|
||||
height: 112px;
|
||||
border-radius: 4px;
|
||||
background-color: $gray-700;
|
||||
|
||||
&:first-child {
|
||||
margin-right: 24px;
|
||||
}
|
||||
|
||||
div {
|
||||
margin: 0 auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
@@ -5,92 +5,92 @@
|
||||
@mouseMoved="mouseMoved($event)"
|
||||
>
|
||||
<div class="standard-sidebar d-none d-sm-block">
|
||||
<div>
|
||||
<filter-sidebar>
|
||||
<div slot="header">
|
||||
<div
|
||||
id="npmMattStable"
|
||||
class="npc_matt"
|
||||
></div>
|
||||
<b-popover
|
||||
triggers="hover"
|
||||
placement="right"
|
||||
target="npmMattStable"
|
||||
>
|
||||
<h4
|
||||
v-once
|
||||
class="popover-content-title"
|
||||
>
|
||||
{{ $t('mattBoch') }}
|
||||
</h4>
|
||||
<div
|
||||
v-once
|
||||
class="popover-content-text"
|
||||
>
|
||||
{{ $t('mattBochText1') }}
|
||||
</div>
|
||||
</b-popover>
|
||||
</div>
|
||||
<div
|
||||
id="npmMattStable"
|
||||
class="npc_matt"
|
||||
></div>
|
||||
<b-popover
|
||||
triggers="hover"
|
||||
placement="right"
|
||||
target="npmMattStable"
|
||||
slot="search"
|
||||
class="form-group"
|
||||
>
|
||||
<h4
|
||||
v-once
|
||||
class="popover-content-title"
|
||||
<input
|
||||
v-model="searchText"
|
||||
class="form-control input-search"
|
||||
type="text"
|
||||
:placeholder="$t('search')"
|
||||
>
|
||||
{{ $t('mattBoch') }}
|
||||
</h4>
|
||||
<div
|
||||
v-once
|
||||
class="popover-content-text"
|
||||
>
|
||||
{{ $t('mattBochText1') }}
|
||||
</div>
|
||||
</b-popover>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<input
|
||||
v-model="searchText"
|
||||
class="form-control input-search"
|
||||
type="text"
|
||||
:placeholder="$t('search')"
|
||||
>
|
||||
</div>
|
||||
<div class="form">
|
||||
<h2 v-once>
|
||||
{{ $t('filter') }}
|
||||
</h2>
|
||||
<h3 v-once>
|
||||
{{ $t('pets') }}
|
||||
</h3>
|
||||
<div class="form-group">
|
||||
<div
|
||||
v-for="petGroup in petGroups"
|
||||
:key="petGroup.key"
|
||||
class="form-check"
|
||||
>
|
||||
<div class="custom-control custom-checkbox">
|
||||
<input
|
||||
:id="petGroup.key"
|
||||
v-model="viewOptions[petGroup.key].selected"
|
||||
class="custom-control-input"
|
||||
type="checkbox"
|
||||
:disabled="viewOptions[petGroup.key].animalCount == 0"
|
||||
>
|
||||
<label
|
||||
v-once
|
||||
class="custom-control-label"
|
||||
:for="petGroup.key"
|
||||
>{{ petGroup.label }}</label>
|
||||
</div>
|
||||
|
||||
<filter-group :title="$t('pets')">
|
||||
<div class="form-group">
|
||||
<div
|
||||
v-for="petGroup in petGroups"
|
||||
:key="petGroup.key"
|
||||
class="form-check"
|
||||
>
|
||||
<div class="custom-control custom-checkbox">
|
||||
<input
|
||||
:id="petGroup.key"
|
||||
v-model="viewOptions[petGroup.key].selected"
|
||||
class="custom-control-input"
|
||||
type="checkbox"
|
||||
:disabled="viewOptions[petGroup.key].animalCount == 0"
|
||||
>
|
||||
<label
|
||||
v-once
|
||||
class="custom-control-label"
|
||||
:for="petGroup.key"
|
||||
>{{ petGroup.label }}</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<h3 v-once>
|
||||
{{ $t('mounts') }}
|
||||
</h3>
|
||||
<div class="form-group">
|
||||
<div
|
||||
v-for="mountGroup in mountGroups"
|
||||
:key="mountGroup.key"
|
||||
class="form-check"
|
||||
>
|
||||
<div class="custom-control custom-checkbox">
|
||||
<input
|
||||
:id="mountGroup.key"
|
||||
v-model="viewOptions[mountGroup.key].selected"
|
||||
class="custom-control-input"
|
||||
type="checkbox"
|
||||
:disabled="viewOptions[mountGroup.key].animalCount == 0"
|
||||
>
|
||||
<label
|
||||
v-once
|
||||
class="custom-control-label"
|
||||
:for="mountGroup.key"
|
||||
>{{ mountGroup.label }}</label>
|
||||
</filter-group>
|
||||
<filter-group :title="$t('mounts')">
|
||||
<div class="form-group">
|
||||
<div
|
||||
v-for="mountGroup in mountGroups"
|
||||
:key="mountGroup.key"
|
||||
class="form-check"
|
||||
>
|
||||
<div class="custom-control custom-checkbox">
|
||||
<input
|
||||
:id="mountGroup.key"
|
||||
v-model="viewOptions[mountGroup.key].selected"
|
||||
class="custom-control-input"
|
||||
type="checkbox"
|
||||
:disabled="viewOptions[mountGroup.key].animalCount == 0"
|
||||
>
|
||||
<label
|
||||
v-once
|
||||
class="custom-control-label"
|
||||
:for="mountGroup.key"
|
||||
>{{ mountGroup.label }}</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</filter-group>
|
||||
|
||||
<div class="form-group clearfix">
|
||||
<h3 class="float-left">
|
||||
{{ $t('hideMissing') }}
|
||||
@@ -101,7 +101,7 @@
|
||||
@change="updateHideMissing"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</filter-sidebar>
|
||||
</div>
|
||||
<div class="standard-page">
|
||||
<div class="clearfix">
|
||||
@@ -113,19 +113,14 @@
|
||||
</h1>
|
||||
<div class="float-right">
|
||||
<span class="dropdown-label">{{ $t('sortBy') }}</span>
|
||||
<b-dropdown
|
||||
:text="$t(selectedSortBy)"
|
||||
right="right"
|
||||
>
|
||||
<b-dropdown-item
|
||||
v-for="sort in sortByItems"
|
||||
:key="sort"
|
||||
:active="selectedSortBy === sort"
|
||||
@click="selectedSortBy = sort"
|
||||
>
|
||||
{{ $t(sort) }}
|
||||
</b-dropdown-item>
|
||||
</b-dropdown>
|
||||
<select-translated-array
|
||||
:right="true"
|
||||
:items="sortByItems"
|
||||
:value="selectedSortBy"
|
||||
@select="selectedSortBy = $event"
|
||||
class="inline"
|
||||
:inlineDropdown="false"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<h2 class="mb-3">
|
||||
@@ -174,8 +169,8 @@
|
||||
slot="itemBadge"
|
||||
slot-scope="context"
|
||||
>
|
||||
<starBadge
|
||||
:selected="context.item.key === currentPet"
|
||||
<equip-badge
|
||||
:equipped="context.item.key === currentPet"
|
||||
:show="isOwned('pet', context.item)"
|
||||
@click="selectPet(context.item)"
|
||||
/>
|
||||
@@ -183,13 +178,12 @@
|
||||
</petItem>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
<show-more-button
|
||||
v-if="petGroup.key !== 'specialPets' && !(petGroup.key === 'wackyPets' && selectedSortBy !== 'sortByColor')"
|
||||
class="btn btn-flat btn-show-more"
|
||||
:show-all="$_openedItemRows_isToggled(petGroup.key)"
|
||||
class="show-more-button"
|
||||
@click="setShowMore(petGroup.key)"
|
||||
>
|
||||
{{ $_openedItemRows_isToggled(petGroup.key) ? $t('showLess') : $t('showMore') }}
|
||||
</div>
|
||||
/>
|
||||
</div>
|
||||
<h2>
|
||||
{{ $t('mounts') }}
|
||||
@@ -234,8 +228,8 @@
|
||||
<template
|
||||
slot="itemBadge"
|
||||
>
|
||||
<starBadge
|
||||
:selected="item.key === currentMount"
|
||||
<equip-badge
|
||||
:equipped="item.key === currentMount"
|
||||
:show="isOwned('mount', item)"
|
||||
@click="selectMount(item)"
|
||||
/>
|
||||
@@ -243,13 +237,11 @@
|
||||
</mountItem>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
<show-more-button
|
||||
v-if="mountGroup.key !== 'specialMounts'"
|
||||
class="btn btn-flat btn-show-more"
|
||||
:show-all="$_openedItemRows_isToggled(mountGroup.key)"
|
||||
@click="setShowMore(mountGroup.key)"
|
||||
>
|
||||
{{ $_openedItemRows_isToggled(mountGroup.key) ? $t('showLess') : $t('showMore') }}
|
||||
</div>
|
||||
/>
|
||||
</div>
|
||||
<inventoryDrawer>
|
||||
<template
|
||||
@@ -332,50 +324,17 @@
|
||||
@import '~@/assets/scss/colors.scss';
|
||||
@import '~@/assets/scss/mixins.scss';
|
||||
|
||||
.standard-page .clearfix .float-right {
|
||||
margin-right: 24px;
|
||||
}
|
||||
|
||||
.inventory-item-container {
|
||||
padding: 20px;
|
||||
border: 1px solid;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.hatchablePopover {
|
||||
width: 180px
|
||||
}
|
||||
|
||||
.potionEggGroup {
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.potionEggBackground {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
|
||||
width: 112px;
|
||||
height: 112px;
|
||||
border-radius: 4px;
|
||||
background-color: #f9f9f9;
|
||||
|
||||
&:first-child {
|
||||
margin-right: 24px;
|
||||
}
|
||||
|
||||
& div {
|
||||
margin: 0 auto;
|
||||
}
|
||||
}
|
||||
|
||||
.GreyedOut {
|
||||
opacity: 0.3;
|
||||
}
|
||||
|
||||
.item.item-empty {
|
||||
width: 94px;
|
||||
height: 92px;
|
||||
border-radius: 2px;
|
||||
background-color: #edecee;
|
||||
}
|
||||
|
||||
@@ -389,6 +348,10 @@
|
||||
padding-right:0;
|
||||
}
|
||||
|
||||
.standard-page .clearfix .float-right {
|
||||
margin-right: 24px;
|
||||
}
|
||||
|
||||
.svg-icon.inline.icon-16 {
|
||||
vertical-align: bottom;
|
||||
}
|
||||
@@ -439,8 +402,7 @@
|
||||
width: 180px;
|
||||
|
||||
.potionEggGroup {
|
||||
margin: 0 auto;
|
||||
margin-top: 10px;
|
||||
margin: 10px auto 0;
|
||||
}
|
||||
|
||||
.potionEggBackground {
|
||||
@@ -456,7 +418,7 @@
|
||||
margin-right: 24px;
|
||||
}
|
||||
|
||||
& div {
|
||||
div {
|
||||
margin: 0 auto;
|
||||
}
|
||||
}
|
||||
@@ -480,7 +442,6 @@ import MountRaisedModal from './mountRaisedModal';
|
||||
import WelcomeModal from './welcomeModal';
|
||||
import HatchingModal from './hatchingModal';
|
||||
import toggleSwitch from '@/components/ui/toggleSwitch';
|
||||
import StarBadge from '@/components/ui/starBadge';
|
||||
import InventoryDrawer from '@/components/shared/inventoryDrawer';
|
||||
|
||||
import ResizeDirective from '@/directives/resize.directive';
|
||||
@@ -497,6 +458,11 @@ import petMixin from '@/mixins/petMixin';
|
||||
|
||||
import { CONSTANTS, setLocalSetting, getLocalSetting } from '@/libs/userlocalManager';
|
||||
import { isOwned } from '../../../libs/createAnimal';
|
||||
import FilterSidebar from '@/components/ui/filterSidebar';
|
||||
import FilterGroup from '@/components/ui/filterGroup';
|
||||
import ShowMoreButton from '@/components/ui/showMoreButton';
|
||||
import EquipBadge from '@/components/ui/equipBadge';
|
||||
import SelectTranslatedArray from '@/components/tasks/modal-controls/selectTranslatedArray';
|
||||
|
||||
// TODO Normalize special pets and mounts
|
||||
// import Store from '@/store';
|
||||
@@ -507,11 +473,15 @@ let lastMouseMoveEvent = {};
|
||||
|
||||
export default {
|
||||
components: {
|
||||
SelectTranslatedArray,
|
||||
EquipBadge,
|
||||
ShowMoreButton,
|
||||
FilterGroup,
|
||||
FilterSidebar,
|
||||
PetItem,
|
||||
FoodItem,
|
||||
MountItem,
|
||||
toggleSwitch,
|
||||
StarBadge,
|
||||
HatchedPetDialog,
|
||||
MountRaisedModal,
|
||||
WelcomeModal,
|
||||
@@ -832,9 +802,6 @@ export default {
|
||||
|
||||
return groupBy(mounts, groupKey);
|
||||
},
|
||||
hasDrawerTabItems (index) {
|
||||
return this.drawerTabs && this.drawerTabs[index].items.length !== 0;
|
||||
},
|
||||
// Actions
|
||||
updateHideMissing (newVal) {
|
||||
this.hideMissing = newVal;
|
||||
|
||||
@@ -2,14 +2,14 @@
|
||||
<div class="payments-column mx-auto mt-auto">
|
||||
<button
|
||||
v-if="stripeAvailable"
|
||||
class="btn btn-primary payment-button payment-item"
|
||||
class="btn btn-primary payment-button payment-item with-icon"
|
||||
:class="{disabled}"
|
||||
:disabled="disabled"
|
||||
@click="stripeFn()"
|
||||
>
|
||||
<div
|
||||
v-once
|
||||
class="svg-icon credit-card-icon"
|
||||
class="svg-icon color credit-card-icon"
|
||||
v-html="icons.creditCardIcon"
|
||||
></div>
|
||||
{{ $t('card') }}
|
||||
|
||||
@@ -11,18 +11,22 @@
|
||||
background: $gray-600;
|
||||
box-shadow: 0 1px 2px 0 rgba($black, 0.2);
|
||||
z-index: 9;
|
||||
height: 3rem;
|
||||
}
|
||||
|
||||
.nav-link {
|
||||
font-size: 16px;
|
||||
line-height: 1.5;
|
||||
padding: 16px 24px;
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
line-height: 1.71;
|
||||
text-align: center;
|
||||
|
||||
padding: 0.75rem;
|
||||
|
||||
color: $gray-50;
|
||||
|
||||
&.active {
|
||||
color: $purple-200;
|
||||
box-shadow: 0px -4px 0px $purple-300 inset;
|
||||
color: $purple-300;
|
||||
box-shadow: 0px -0.25rem 0px $purple-300 inset;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
|
||||
53
website/client/src/components/shared/closeIcon.vue
Normal file
53
website/client/src/components/shared/closeIcon.vue
Normal file
@@ -0,0 +1,53 @@
|
||||
<template>
|
||||
<button title="close dialog"
|
||||
@click="$emit('click', $event)">
|
||||
<div v-once
|
||||
class="svg-icon"
|
||||
v-html="icons.close"
|
||||
></div>
|
||||
</button>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import svgClose from '@/assets/svg/close.svg';
|
||||
|
||||
export default {
|
||||
name: 'closeIcon',
|
||||
data () {
|
||||
return {
|
||||
icons: Object.freeze({
|
||||
close: svgClose,
|
||||
}),
|
||||
};
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import '~@/assets/scss/colors.scss';
|
||||
|
||||
button {
|
||||
position: absolute;
|
||||
top: 1rem;
|
||||
right: 1rem;
|
||||
cursor: pointer;
|
||||
opacity: 1;
|
||||
|
||||
border: 0;
|
||||
outline: 0;
|
||||
padding: 0.125rem;
|
||||
background: transparent;
|
||||
width: 1rem;
|
||||
height: 1rem;
|
||||
|
||||
::v-deep svg path {
|
||||
stroke: $gray-200;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
::v-deep svg path {
|
||||
stroke: $gray-100;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,12 +1,23 @@
|
||||
<template>
|
||||
<drawer
|
||||
class="inventoryDrawer"
|
||||
:title="$t('quickInventory')"
|
||||
:no-title-bottom-padding="true"
|
||||
:error-message="inventoryDrawerErrorMessage(selectedDrawerItemType)"
|
||||
ref="drawer"
|
||||
>
|
||||
<div slot="drawer-title-row" class="title-row-tabs">
|
||||
<div class="drawer-tab" v-for="(tab, index) of filteredTabs"
|
||||
:key="tab.key">
|
||||
<a
|
||||
class="drawer-tab-text"
|
||||
:class="{'drawer-tab-text-active': filteredTabs[selectedDrawerTab].key === tab.key}"
|
||||
@click.prevent.stop="tabSelected(index); $refs.drawer.open();"
|
||||
>{{ tab.label }}</a>
|
||||
</div>
|
||||
</div>
|
||||
<div slot="drawer-header">
|
||||
<drawer-header-tabs
|
||||
:tabs="filteredTabs"
|
||||
:tabs="[]"
|
||||
@changedPosition="tabSelected($event)"
|
||||
>
|
||||
<div slot="right-item">
|
||||
@@ -15,7 +26,7 @@
|
||||
id="petLikeToEatMarket"
|
||||
class="drawer-help-text"
|
||||
>
|
||||
{{ $t('petLikeToEat') + ' ' }}
|
||||
<span>{{ $t('petLikeToEat') + ' ' }}</span>
|
||||
<span
|
||||
class="svg-icon inline icon-16"
|
||||
v-html="icons.information"
|
||||
@@ -178,5 +189,28 @@ export default {
|
||||
.drawer-slider {
|
||||
height: 126px;
|
||||
}
|
||||
|
||||
.drawer-tab-text {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.drawer-help-text {
|
||||
display: flex;
|
||||
margin-top: 0.65rem;
|
||||
|
||||
.svg-icon {
|
||||
position: inherit;
|
||||
top: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.title-row-tabs {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
|
||||
.drawer-tab {
|
||||
background: transparent;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
:class="{disabled: disabled}"
|
||||
:disabled="disabled"
|
||||
:value="selected"
|
||||
:hide-icon="true"
|
||||
@select="$emit('select', $event.value)"
|
||||
>
|
||||
<template v-slot:item="{ item, button }">
|
||||
|
||||
@@ -6,6 +6,9 @@
|
||||
class="array-select"
|
||||
:class="{disabled: disabled}"
|
||||
:disabled="disabled"
|
||||
:right="right"
|
||||
:hide-icon="false"
|
||||
:inline-dropdown="inlineDropdown"
|
||||
@select="selectItem($event)"
|
||||
>
|
||||
<template v-slot:item="{ item }">
|
||||
@@ -60,6 +63,13 @@ export default {
|
||||
type: Boolean,
|
||||
},
|
||||
value: [String, Number, Object],
|
||||
right: {
|
||||
type: Boolean,
|
||||
},
|
||||
inlineDropdown: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
|
||||
@@ -251,10 +251,6 @@
|
||||
padding-top: 16px;
|
||||
}
|
||||
|
||||
.input-search, .search-button {
|
||||
height: 40px;
|
||||
}
|
||||
|
||||
.tasks-navigation {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
129
website/client/src/components/ui/buttons.stories.js
Normal file
129
website/client/src/components/ui/buttons.stories.js
Normal file
@@ -0,0 +1,129 @@
|
||||
/* eslint-disable import/no-extraneous-dependencies */
|
||||
import { storiesOf } from '@storybook/vue';
|
||||
import { withKnobs } from '@storybook/addon-knobs';
|
||||
|
||||
import positiveIcon from '@/assets/svg/positive.svg';
|
||||
|
||||
const stories = storiesOf('Buttons', module);
|
||||
|
||||
stories.addDecorator(withKnobs);
|
||||
|
||||
stories
|
||||
.add('all', () => ({
|
||||
components: { },
|
||||
data () {
|
||||
return {
|
||||
icon: positiveIcon,
|
||||
};
|
||||
},
|
||||
template: `
|
||||
<div style="position: absolute; margin: 20px; display: flex; flex-direction: row;">
|
||||
<div class="mr-3">
|
||||
<h3>Button</h3>
|
||||
<button class="btn btn-primary">Button Primary</button>
|
||||
<br/><br/>
|
||||
<button class="btn btn-primary" disabled>Button Primary Disabled</button>
|
||||
<br/><br/>
|
||||
|
||||
<button class="btn btn-secondary">Button Secondary</button>
|
||||
<br/><br/>
|
||||
<button class="btn btn-secondary" disabled>Button Secondary Disabled</button>
|
||||
</div>
|
||||
<div class="">
|
||||
<h3>Button with Icon</h3>
|
||||
<button class="btn btn-primary with-icon">
|
||||
<span class="svg-icon color inline icon-12 mr-2"
|
||||
v-html="icon"
|
||||
>
|
||||
|
||||
</span>
|
||||
<span class="button-label">
|
||||
Button Primary
|
||||
</span>
|
||||
</button>
|
||||
<br/>
|
||||
<button class="btn btn-primary with-icon" disabled>
|
||||
<span class="svg-icon color inline icon-12 mr-2"
|
||||
v-html="icon"
|
||||
>
|
||||
|
||||
</span>
|
||||
<span class="button-label">
|
||||
Button Primary Disabled
|
||||
</span>
|
||||
</button>
|
||||
<br/>
|
||||
|
||||
<button class="btn btn-secondary with-icon">
|
||||
<span class="svg-icon color inline icon-12 mr-2"
|
||||
v-html="icon"
|
||||
>
|
||||
|
||||
</span>
|
||||
<span class="button-label">
|
||||
Button Secondary
|
||||
</span>
|
||||
</button>
|
||||
<br/>
|
||||
<button class="btn btn-secondary with-icon" disabled>
|
||||
<span class="svg-icon color inline icon-12 mr-2"
|
||||
v-html="icon"
|
||||
>
|
||||
|
||||
</span>
|
||||
<span class="button-label">
|
||||
Button Secondary Disabled
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
`,
|
||||
}))
|
||||
.add('dropdowns', () => ({
|
||||
components: { },
|
||||
data () {
|
||||
return {
|
||||
items: ['one', 'two', 'three'],
|
||||
};
|
||||
},
|
||||
template: `
|
||||
<div style="position: absolute; margin: 20px; display: flex; flex-direction: row;">
|
||||
<div class="mr-3">
|
||||
<h3>Dropdowns</h3>
|
||||
<b-dropdown
|
||||
text="Dropdown Primary"
|
||||
right="right"
|
||||
>
|
||||
<b-dropdown-item
|
||||
v-for="item in items"
|
||||
:key="item"
|
||||
>
|
||||
{{ item }}
|
||||
</b-dropdown-item>
|
||||
</b-dropdown>
|
||||
<br/><br/>
|
||||
<b-dropdown
|
||||
text="Dropdown Primary Disabled"
|
||||
right="right"
|
||||
disabled
|
||||
>
|
||||
</b-dropdown>
|
||||
</div>
|
||||
<div class="">
|
||||
<h3>Button</h3>
|
||||
<button class="btn btn-secondary">
|
||||
<span class="button-label">
|
||||
Button Primary
|
||||
</span>
|
||||
</button>
|
||||
<br/>
|
||||
<br/>
|
||||
<button class="btn btn-secondary" disabled>
|
||||
<span class="button-label">
|
||||
Button Primary Disabled
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
`,
|
||||
}));
|
||||
@@ -26,6 +26,13 @@
|
||||
label:not(:disabled):not(.disabled) {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.custom-control.custom-checkbox {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
|
||||
justify-items: center;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
|
||||
@@ -2,9 +2,14 @@
|
||||
<div class="drawer-container">
|
||||
<div
|
||||
class="drawer-title"
|
||||
:class="{'no-padding': noTitleBottomPadding}"
|
||||
@click="toggle()"
|
||||
>
|
||||
{{ title }}
|
||||
<div class="title-row">
|
||||
<slot name="drawer-title-row">
|
||||
<div class="text-only">{{ title }}</div>
|
||||
</slot>
|
||||
</div>
|
||||
<div
|
||||
class="drawer-toggle-icon svg-icon icon-10"
|
||||
:class="{ closed: !isOpen }"
|
||||
@@ -59,7 +64,7 @@
|
||||
.drawer-toggle-icon {
|
||||
position: absolute;
|
||||
right: 16px;
|
||||
top: 16px;
|
||||
bottom: 0;
|
||||
|
||||
&.closed {
|
||||
top: 10px;
|
||||
@@ -67,6 +72,7 @@
|
||||
}
|
||||
|
||||
.drawer-title {
|
||||
height: 2rem;
|
||||
position: relative;
|
||||
background-color: $gray-10;
|
||||
box-shadow: 0 1px 2px 0 rgba($black, 0.2);
|
||||
@@ -74,9 +80,30 @@
|
||||
border-top-right-radius: 8px;
|
||||
border-top-left-radius: 8px;
|
||||
text-align: center;
|
||||
line-height: 1.67;
|
||||
line-height: 1.33;
|
||||
color: $white;
|
||||
padding: 6px 0;
|
||||
|
||||
font-size: 12px;
|
||||
font-weight: bold;
|
||||
display: flex;
|
||||
|
||||
&.no-padding {
|
||||
padding-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.text-only {
|
||||
padding-top: 0.5rem;
|
||||
}
|
||||
|
||||
.title-row {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
|
||||
& > div {
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.drawer-content {
|
||||
@@ -103,13 +130,14 @@
|
||||
&-text {
|
||||
font-size: 12px;
|
||||
font-weight: bold;
|
||||
line-height: 1.67;
|
||||
text-align: center;
|
||||
color: $white;
|
||||
color: $gray-400;
|
||||
text-decoration: none !important;
|
||||
border-bottom: 2px solid transparent;
|
||||
padding: 0px 8px 8px 8px;
|
||||
padding: 0.5rem;
|
||||
|
||||
&-active {
|
||||
&-active, &:hover {
|
||||
color: $white !important;
|
||||
border-color: $purple-400;
|
||||
}
|
||||
}
|
||||
@@ -167,7 +195,6 @@ export default {
|
||||
props: {
|
||||
title: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
errorMessage: {
|
||||
type: String,
|
||||
@@ -175,10 +202,13 @@ export default {
|
||||
openStatus: {
|
||||
type: Number,
|
||||
},
|
||||
noTitleBottomPadding: {
|
||||
type: Boolean,
|
||||
},
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
open: true,
|
||||
isOpened: true,
|
||||
icons: Object.freeze({
|
||||
expand: expandIcon,
|
||||
minimize: minimizeIcon,
|
||||
@@ -189,13 +219,17 @@ export default {
|
||||
isOpen () {
|
||||
// Open status is a number so we can tell if the value was passed
|
||||
if (this.openStatus !== undefined) return this.openStatus === 1;
|
||||
return this.open;
|
||||
return this.isOpened;
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
toggle () {
|
||||
this.open = !this.isOpen;
|
||||
this.$emit('toggled', this.open);
|
||||
this.isOpened = !this.isOpen;
|
||||
this.$emit('toggled', this.isOpened);
|
||||
},
|
||||
open () {
|
||||
this.isOpened = true;
|
||||
this.$emit('toggled', this.isOpened);
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
99
website/client/src/components/ui/equipBadge.vue
Normal file
99
website/client/src/components/ui/equipBadge.vue
Normal file
@@ -0,0 +1,99 @@
|
||||
<template>
|
||||
<span
|
||||
v-if="show"
|
||||
class="badge badge-round badge-item badge-equip"
|
||||
:class="{'is-equipped': equipped === true}"
|
||||
@click.stop="click"
|
||||
>
|
||||
<div
|
||||
class="svg-icon color equip-icon"
|
||||
v-html="icons.equip"
|
||||
v-once
|
||||
>
|
||||
</div>
|
||||
<div
|
||||
class="svg-icon color unequip-icon"
|
||||
v-html="icons.unEquip"
|
||||
v-once
|
||||
>
|
||||
</div>
|
||||
</span>
|
||||
</template>
|
||||
|
||||
<style lang="scss">
|
||||
@import '~@/assets/scss/colors.scss';
|
||||
|
||||
.badge-equip {
|
||||
cursor: pointer;
|
||||
display: none;
|
||||
left: -9px;
|
||||
color: $gray-200;
|
||||
background: $white;
|
||||
padding: 0.375rem;
|
||||
|
||||
.unequip-icon {
|
||||
display: none;
|
||||
}
|
||||
|
||||
&.is-equipped {
|
||||
display: block;
|
||||
background: $teal-50;
|
||||
color: $white;
|
||||
|
||||
&:hover {
|
||||
.unequip-icon {
|
||||
display: block;
|
||||
color: $maroon-50;
|
||||
}
|
||||
|
||||
.equip-icon {
|
||||
display: none;
|
||||
}
|
||||
|
||||
background: $white;
|
||||
}
|
||||
}
|
||||
|
||||
&:hover:not(.is-equipped) {
|
||||
color: $purple-400;
|
||||
}
|
||||
|
||||
.svg-icon {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.item:hover > .badge-equip {
|
||||
display: block;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
import svgEquip from '@/assets/svg/equip.svg';
|
||||
import svgUnEquip from '@/assets/svg/unequip.svg';
|
||||
|
||||
export default {
|
||||
props: {
|
||||
show: {
|
||||
type: Boolean,
|
||||
},
|
||||
equipped: {
|
||||
type: Boolean,
|
||||
},
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
icons: Object.freeze({
|
||||
equip: svgEquip,
|
||||
unEquip: svgUnEquip,
|
||||
}),
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
click () {
|
||||
this.$emit('click');
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
36
website/client/src/components/ui/filterGroup.vue
Normal file
36
website/client/src/components/ui/filterGroup.vue
Normal file
@@ -0,0 +1,36 @@
|
||||
<template>
|
||||
<div>
|
||||
<h4>
|
||||
{{ title }}
|
||||
</h4>
|
||||
<div class="form-group">
|
||||
<slot></slot>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'filterGroup',
|
||||
props: ['title'],
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import '~@/assets/scss/colors.scss';
|
||||
|
||||
h4 {
|
||||
min-height: 1.5rem;
|
||||
}
|
||||
|
||||
.form-group ::v-deep {
|
||||
.form-check {
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.custom-checkbox {
|
||||
// min height for longer labels
|
||||
min-height: 1.5rem;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
27
website/client/src/components/ui/filterSidebar.vue
Normal file
27
website/client/src/components/ui/filterSidebar.vue
Normal file
@@ -0,0 +1,27 @@
|
||||
<template>
|
||||
<div class="filter">
|
||||
<slot name="header"></slot>
|
||||
<slot name="search"></slot>
|
||||
<div class="form">
|
||||
<h3 v-once class="filter-label">
|
||||
{{ $t('filters') }}
|
||||
</h3>
|
||||
<slot></slot>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'filterSidebar',
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import '~@/assets/scss/colors.scss';
|
||||
|
||||
.filter-label {
|
||||
min-height: 1.5rem;
|
||||
margin-bottom: 0.25rem;
|
||||
}
|
||||
</style>
|
||||
@@ -17,13 +17,11 @@
|
||||
{{ noItemsLabel }}
|
||||
</p>
|
||||
</div>
|
||||
<div
|
||||
<show-more-button
|
||||
v-if="items.length > itemsPerRow"
|
||||
class="btn btn-flat btn-show-more"
|
||||
@click="toggleItemsToShow()"
|
||||
>
|
||||
{{ showAll ? $t('showLess') : $t('showMore') }}
|
||||
</div>
|
||||
:show-all="showAll"
|
||||
/>
|
||||
<div
|
||||
v-else
|
||||
class="fill-height"
|
||||
@@ -32,12 +30,14 @@
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import '~@/assets/scss/colors.scss';
|
||||
|
||||
.fill-height {
|
||||
height: 38px; // button + margin + padding
|
||||
}
|
||||
|
||||
.item-rows {
|
||||
margin-right: -24px;
|
||||
margin-right: -1.5rem;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -45,9 +45,11 @@
|
||||
import _take from 'lodash/take';
|
||||
import ResizeDirective from '@/directives/resize.directive';
|
||||
import openedItemRowsMixin from '@/mixins/openedItemRows';
|
||||
import ShowMoreButton from '@/components/ui/showMoreButton';
|
||||
|
||||
|
||||
export default {
|
||||
components: { ShowMoreButton },
|
||||
directives: {
|
||||
resize: ResizeDirective,
|
||||
},
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
<template>
|
||||
<div>
|
||||
<b-dropdown
|
||||
class="inline-dropdown"
|
||||
class="select-list"
|
||||
:class="{'inline-dropdown':inlineDropdown}"
|
||||
:toggle-class="isOpened ? 'active' : null"
|
||||
:disabled="disabled"
|
||||
:right="right"
|
||||
@show="isOpened = true"
|
||||
@hide="isOpened = false"
|
||||
>
|
||||
@@ -21,7 +23,12 @@
|
||||
v-for="item in items"
|
||||
:key="keyProp ? item[keyProp] : item"
|
||||
:disabled="typeof item[disabledProp] === 'undefined' ? false : item[disabledProp]"
|
||||
:class="{active: item === selected, selectListItem: true}"
|
||||
:active="item === selected"
|
||||
:class="{
|
||||
active: item === selected,
|
||||
selectListItem: true,
|
||||
showIcon: !hideIcon && item === selected
|
||||
}"
|
||||
@click="selectItem(item)"
|
||||
>
|
||||
<slot
|
||||
@@ -32,6 +39,12 @@
|
||||
<!-- Fallback content -->
|
||||
{{ item }}
|
||||
</slot>
|
||||
|
||||
<div
|
||||
v-once
|
||||
class="svg-icon color check-icon"
|
||||
v-html="icons.check"
|
||||
></div>
|
||||
</b-dropdown-item>
|
||||
</b-dropdown>
|
||||
</div>
|
||||
@@ -40,9 +53,30 @@
|
||||
<style lang="scss" scoped>
|
||||
@import '~@/assets/scss/colors.scss';
|
||||
|
||||
.select-list ::v-deep .selectListItem {
|
||||
position: relative;
|
||||
|
||||
&:not(.showIcon) {
|
||||
.svg-icon.check-icon {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.svg-icon.check-icon.color {
|
||||
position: absolute;
|
||||
right: 0.855rem;
|
||||
top: 0.688rem;
|
||||
bottom: 0.688rem;
|
||||
width: 0.77rem;
|
||||
height: 0.615rem;
|
||||
color: $purple-300;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
import svgCheck from '@/assets/svg/check.svg';
|
||||
|
||||
export default {
|
||||
props: {
|
||||
items: {
|
||||
@@ -58,11 +92,24 @@ export default {
|
||||
disabledProp: {
|
||||
type: String,
|
||||
},
|
||||
hideIcon: {
|
||||
type: Boolean,
|
||||
},
|
||||
right: {
|
||||
type: Boolean,
|
||||
},
|
||||
inlineDropdown: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
isOpened: false,
|
||||
selected: this.value,
|
||||
icons: Object.freeze({
|
||||
check: svgCheck,
|
||||
}),
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
|
||||
41
website/client/src/components/ui/showMoreButton.vue
Normal file
41
website/client/src/components/ui/showMoreButton.vue
Normal file
@@ -0,0 +1,41 @@
|
||||
<template>
|
||||
<button class="btn btn-flat btn-show-more mb-4"
|
||||
@click="$emit('click')"
|
||||
>
|
||||
<span class="button-text">
|
||||
{{ showAll ? $t('showLess') : $t('showMore') }}
|
||||
</span>
|
||||
</button>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: ['showAll'],
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import '~@/assets/scss/colors.scss';
|
||||
|
||||
.btn-show-more {
|
||||
height: 2rem;
|
||||
padding-top: 0.25rem;
|
||||
padding-bottom: 0.25rem;
|
||||
border-radius: 2px;
|
||||
|
||||
.button-text {
|
||||
height: 1.5rem;
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
line-height: 1.71;
|
||||
text-align: center;
|
||||
color: $gray-100;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
.button-text {
|
||||
color: $purple-300;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
39
website/client/src/components/ui/toggleSwitch.stories.js
Normal file
39
website/client/src/components/ui/toggleSwitch.stories.js
Normal file
@@ -0,0 +1,39 @@
|
||||
/* eslint-disable import/no-extraneous-dependencies */
|
||||
import { storiesOf } from '@storybook/vue';
|
||||
import { text, withKnobs } from '@storybook/addon-knobs';
|
||||
import toggleSwitch from './toggleSwitch';
|
||||
|
||||
const stories = storiesOf('Toggle Switch', module);
|
||||
|
||||
stories.addDecorator(withKnobs);
|
||||
|
||||
stories
|
||||
.add('label only', () => ({
|
||||
components: { toggleSwitch },
|
||||
template: `
|
||||
<div style="position: absolute; margin: 20px">
|
||||
<toggle-switch :label="label"></toggle-switch>
|
||||
</div>
|
||||
`,
|
||||
props: {
|
||||
label: {
|
||||
default: text('Label', 'example text'),
|
||||
},
|
||||
},
|
||||
}))
|
||||
.add('with description', () => ({
|
||||
components: { toggleSwitch },
|
||||
template: `
|
||||
<div style="position: absolute; margin: 20px">
|
||||
<toggle-switch :label="label" :hover-text="description"></toggle-switch>
|
||||
</div>
|
||||
`,
|
||||
props: {
|
||||
label: {
|
||||
default: text('Label', 'example text'),
|
||||
},
|
||||
description: {
|
||||
default: text('Description', 'description text'),
|
||||
},
|
||||
},
|
||||
}));
|
||||
@@ -1,16 +1,23 @@
|
||||
<template>
|
||||
<div class="popover-box">
|
||||
<div
|
||||
:id="containerId"
|
||||
class="clearfix toggle-switch-outer"
|
||||
>
|
||||
<div
|
||||
v-if="label"
|
||||
class="float-left toggle-switch-description"
|
||||
:class="hoverText ? 'hasPopOver' : ''"
|
||||
:class="{'bold': boldLabel}"
|
||||
>
|
||||
<span>{{ label }}</span>
|
||||
</div>
|
||||
<span
|
||||
v-if="hoverText"
|
||||
:id="containerId"
|
||||
class="svg-icon inline icon-16 float-left"
|
||||
v-html="icons.information"
|
||||
>
|
||||
|
||||
</span>
|
||||
<div class="toggle-switch float-left">
|
||||
<input
|
||||
:id="toggleId"
|
||||
@@ -51,11 +58,16 @@
|
||||
<style lang="scss" scoped>
|
||||
@import '~@/assets/scss/colors.scss';
|
||||
|
||||
.toggle-switch-outer {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.toggle-switch {
|
||||
position: relative;
|
||||
width: 40px;
|
||||
user-select: none;
|
||||
margin-left: 9px;
|
||||
margin-left: 0.5rem;
|
||||
}
|
||||
|
||||
.toggle-switch-description {
|
||||
@@ -64,6 +76,10 @@
|
||||
}
|
||||
}
|
||||
|
||||
.svg-icon {
|
||||
margin: 2px 0.5rem 2px 0.5rem;
|
||||
}
|
||||
|
||||
.toggle-switch-checkbox {
|
||||
display: none;
|
||||
}
|
||||
@@ -74,7 +90,7 @@
|
||||
cursor: pointer;
|
||||
border-radius: 100px;
|
||||
margin-bottom: 0px;
|
||||
margin-top: 3px;
|
||||
margin-top: 2px;
|
||||
}
|
||||
|
||||
.toggle-switch-inner {
|
||||
@@ -110,7 +126,7 @@
|
||||
display: block;
|
||||
width: 20px;
|
||||
margin: -2px;
|
||||
margin-top: 1px;
|
||||
margin-top: 0;
|
||||
height: 20px;
|
||||
background: $white;
|
||||
position: absolute;
|
||||
@@ -133,9 +149,15 @@
|
||||
.toggle-switch-checkbox:checked + .toggle-switch-label .toggle-switch-switch {
|
||||
right: 0px;
|
||||
}
|
||||
|
||||
.bold {
|
||||
font-weight: bold;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
import svgInformation from '@/assets/svg/information.svg';
|
||||
|
||||
export default {
|
||||
model: {
|
||||
prop: 'checked',
|
||||
@@ -148,6 +170,10 @@ export default {
|
||||
label: {
|
||||
type: String,
|
||||
},
|
||||
boldLabel: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
checked: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
@@ -163,6 +189,10 @@ export default {
|
||||
// The container requires a unique id to link it to the pop-over
|
||||
containerId: this.generateId(),
|
||||
focused: false,
|
||||
|
||||
icons: Object.freeze({
|
||||
information: svgInformation,
|
||||
}),
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
|
||||
@@ -488,10 +488,10 @@
|
||||
margin-right: 1em;
|
||||
|
||||
button {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
padding: .7em;
|
||||
margin-right: .5em;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
padding: 0.5em;
|
||||
margin-right: 0.5em;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ import { togglePinnedItem as togglePinnedItemOp } from '@/../../common/script/op
|
||||
import changeClassOp from '@/../../common/script/ops/changeClass';
|
||||
import disableClassesOp from '@/../../common/script/ops/disableClasses';
|
||||
import openMysteryItemOp from '@/../../common/script/ops/openMysteryItem';
|
||||
import { unEquipByType } from '../../../../common/script/ops/unequip';
|
||||
import markPMSRead from '../../../../common/script/ops/markPMSRead';
|
||||
|
||||
export function fetch (store, options = {}) { // eslint-disable-line no-shadow
|
||||
@@ -223,3 +224,19 @@ export function newPrivateMessageTo (store, params) {
|
||||
userStyles,
|
||||
};
|
||||
}
|
||||
|
||||
export async function unequip (store, params) {
|
||||
const user = store.state.user.data;
|
||||
|
||||
unEquipByType(user, { params });
|
||||
|
||||
const response = await axios.post(`/api/v4/user/unequip/${params.type}`);
|
||||
|
||||
store.dispatch('snackbars:add', {
|
||||
title: 'Habitica',
|
||||
text: response.data.message,
|
||||
type: 'info',
|
||||
});
|
||||
|
||||
return response.data.data;
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ describe('DrawerComponent', () => {
|
||||
it('sets the correct default data', () => {
|
||||
expect(DrawerComponent.data).to.be.a('function');
|
||||
const defaultData = DrawerComponent.data();
|
||||
expect(defaultData.open).to.be.true;
|
||||
expect(defaultData.isOpened).to.be.true;
|
||||
});
|
||||
|
||||
it('renders the correct title', () => {
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
"selectWinner": "Select a winner and close the challenge:",
|
||||
"endChallenge": "End Challenge",
|
||||
"filter": "Filter",
|
||||
"filters": "Filters",
|
||||
"groups": "Groups",
|
||||
"category": "Category",
|
||||
"membership": "Membership",
|
||||
|
||||
@@ -4,5 +4,7 @@
|
||||
"eggsItemType": "Eggs",
|
||||
"hatchingPotionsItemType": "Hatching Potions",
|
||||
"specialItemType": "Special items",
|
||||
"lockedItem": "Locked Item"
|
||||
"lockedItem": "Locked Item",
|
||||
"petAndMount": "Pet and Mount",
|
||||
"allItems": "All Items"
|
||||
}
|
||||
|
||||
@@ -12,6 +12,11 @@
|
||||
"messageDontEnjoyFood": "<%= egg %> eats <%= foodText %> but doesn't seem to enjoy it.",
|
||||
"messageBought": "Bought <%= itemText %>",
|
||||
"messageUnEquipped": "<%= itemText %> unequipped.",
|
||||
"messageBattleGearUnEquipped": "Battle Gear unequipped.",
|
||||
"messageCostumeUnEquipped": "Costume unequipped.",
|
||||
"messagePetMountUnEquipped": "Pet and Mount unequipped.",
|
||||
"messageBackgroundUnEquipped": "Background unequipped.",
|
||||
"messageAllUnEquipped": "Everything unequipped.",
|
||||
"messageMissingEggPotion": "You're missing either that egg or that potion",
|
||||
"messageInvalidEggPotionCombo": "You can't hatch Quest Pet Eggs with Magic Hatching Potions! Try a different egg.",
|
||||
"messageAlreadyPet": "You already have that pet. Try hatching a different combination!",
|
||||
|
||||
@@ -87,6 +87,7 @@ import unlock from './ops/unlock';
|
||||
import updateTask from './ops/updateTask';
|
||||
// TODO under api.libs.statHelpers?
|
||||
import * as statHelpers from './statHelpers';
|
||||
import { unEquipByType } from './ops/unequip';
|
||||
|
||||
const api = {};
|
||||
api.content = content;
|
||||
@@ -182,6 +183,7 @@ api.ops = {
|
||||
reset,
|
||||
markPmsRead,
|
||||
pinnedGearUtils,
|
||||
unEquipByType,
|
||||
};
|
||||
|
||||
api.errorMessages = {
|
||||
|
||||
@@ -31,6 +31,7 @@ import openMysteryItem from './openMysteryItem';
|
||||
import scoreTask from './scoreTask';
|
||||
import markPmsRead from './markPMSRead';
|
||||
import * as pinnedGearUtils from './pinnedGearUtils';
|
||||
import { unEquipByType } from './unequip';
|
||||
|
||||
export default {
|
||||
sleep,
|
||||
@@ -66,4 +67,5 @@ export default {
|
||||
scoreTask,
|
||||
markPmsRead,
|
||||
pinnedGearUtils,
|
||||
unEquipByType,
|
||||
};
|
||||
|
||||
78
website/common/script/ops/unequip.js
Normal file
78
website/common/script/ops/unequip.js
Normal file
@@ -0,0 +1,78 @@
|
||||
import get from 'lodash/get';
|
||||
import content from '../content/index';
|
||||
import i18n from '../i18n';
|
||||
import {
|
||||
BadRequest,
|
||||
} from '../libs/errors';
|
||||
import errorMessage from '../libs/errorMessage';
|
||||
|
||||
export const UNEQUIP_PET_MOUNT = 'pet';
|
||||
export const UNEQUIP_BACKGROUND = 'background';
|
||||
export const UNEQUIP_ALL = 'all';
|
||||
export const UNEQUIP_COSTUME = 'costume';
|
||||
export const UNEQUIP_EQUIPPED = 'equipped';
|
||||
|
||||
const allTypes = [
|
||||
UNEQUIP_PET_MOUNT, UNEQUIP_BACKGROUND,
|
||||
UNEQUIP_ALL, UNEQUIP_COSTUME, UNEQUIP_EQUIPPED,
|
||||
];
|
||||
|
||||
function unequipEquipment (user, type) {
|
||||
for (const gearType of content.gearTypes) {
|
||||
user.items.gear[type][gearType] = `${gearType}_base_0`;
|
||||
}
|
||||
}
|
||||
|
||||
export function unEquipByType (user, req = {}) {
|
||||
// Being type a parameter followed by another parameter
|
||||
// when using the API it must be passes specifically in the URL, it's won't default to equipped
|
||||
const type = get(req, 'params.type', 'equipped');
|
||||
|
||||
if (allTypes.indexOf(type) === -1) {
|
||||
throw new BadRequest(errorMessage('invalidTypeEquip'));
|
||||
}
|
||||
|
||||
let message;
|
||||
|
||||
switch (type) { // eslint-disable-line default-case
|
||||
case UNEQUIP_PET_MOUNT: {
|
||||
user.items.currentPet = '';
|
||||
user.items.currentMount = '';
|
||||
|
||||
message = i18n.t('messagePetMountUnEquipped', {}, req.language);
|
||||
break;
|
||||
}
|
||||
case UNEQUIP_BACKGROUND: {
|
||||
user.preferences.background = '';
|
||||
|
||||
message = i18n.t('messageBackgroundUnEquipped', {}, req.language);
|
||||
break;
|
||||
}
|
||||
case UNEQUIP_ALL: {
|
||||
user.items.currentMount = '';
|
||||
user.items.currentPet = '';
|
||||
user.preferences.background = '';
|
||||
|
||||
unequipEquipment(user, UNEQUIP_COSTUME);
|
||||
unequipEquipment(user, UNEQUIP_EQUIPPED);
|
||||
|
||||
message = i18n.t('messageAllUnEquipped', {}, req.language);
|
||||
break;
|
||||
}
|
||||
|
||||
case UNEQUIP_COSTUME:
|
||||
case UNEQUIP_EQUIPPED: {
|
||||
unequipEquipment(user, type);
|
||||
|
||||
message = i18n.t(type === UNEQUIP_COSTUME
|
||||
? 'messageCostumeUnEquipped'
|
||||
: 'messageBattleGearUnEquipped', {}, req.language);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const res = [user.items];
|
||||
if (message) res.push(message);
|
||||
return res;
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
import { authWithHeaders } from '../../middlewares/auth';
|
||||
import * as userLib from '../../libs/user';
|
||||
import { verifyDisplayName } from '../../libs/user/validation';
|
||||
import common from '../../../common';
|
||||
|
||||
const api = {};
|
||||
|
||||
@@ -244,4 +245,38 @@ api.verifyDisplayName = {
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* @api {post} /api/v4/user/unequip/:type Unequip all items by type
|
||||
* @apiName UserUnEquipByType
|
||||
* @apiGroup User
|
||||
*
|
||||
* @apiParam (Path) {String="pet-mount-background","costume","equipped"} type The type of items
|
||||
* to unequip.
|
||||
*
|
||||
* @apiParamExample {URL} Example-URL
|
||||
* https://habitica.com/api/v4/user/unequip/equipped
|
||||
*
|
||||
* @apiSuccess {Object} data user.items
|
||||
* @apiSuccess {String} message Optional success message for unequipping an items
|
||||
*
|
||||
* @apiSuccessExample {json} Example return:
|
||||
* {
|
||||
* "success": true,
|
||||
* "data": {---DATA TRUNCATED---},
|
||||
* "message": "Battle Gear unequipped.
|
||||
* }
|
||||
*
|
||||
*/
|
||||
api.unequip = {
|
||||
method: 'POST',
|
||||
middlewares: [authWithHeaders()],
|
||||
url: '/user/unequip/:type',
|
||||
async handler (req, res) {
|
||||
const { user } = res.locals;
|
||||
const equipRes = common.ops.unEquipByType(user, req);
|
||||
await user.save();
|
||||
res.respond(200, ...equipRes);
|
||||
},
|
||||
};
|
||||
|
||||
export default api;
|
||||
|
||||
Reference in New Issue
Block a user