Client/Inventory/Items (#8734)

* client: start working on Inventory/Items

* i18n changes and fixes

* initial displaying of eggs, food and potions + sorting

* add missing files

* remove comment

* show food, eggs and potions

* add label to dropdowns acting as select menus

* popovers

* move badge to slot and component if necessary, general refactor

* fix quantity ordering

* some special items, reorganize
This commit is contained in:
Matteo Pagliazzi
2017-05-22 16:30:52 +02:00
committed by GitHub
parent f267456a30
commit 9e1f7f3811
16 changed files with 350 additions and 120 deletions

View File

@@ -7,10 +7,10 @@ nav.navbar.navbar-inverse.fixed-top.navbar-toggleable-sm
ul.navbar-nav.mr-auto
router-link.nav-item(tag="li", :to="{name: 'tasks'}", exact)
a.nav-link(v-once) {{ $t('tasks') }}
router-link.nav-item.dropdown(tag="li", :to="{name: 'inventory'}", :class="{'active': $route.path.startsWith('/inventory')}")
router-link.nav-item.dropdown(tag="li", :to="{name: 'items'}", :class="{'active': $route.path.startsWith('/inventory')}")
a.nav-link(v-once) {{ $t('inventory') }}
.dropdown-menu
router-link.dropdown-item(:to="{name: 'inventory'}", exact) {{ $t('inventory') }}
router-link.dropdown-item(:to="{name: 'items'}", exact) {{ $t('items') }}
router-link.dropdown-item(:to="{name: 'equipment'}") {{ $t('equipment') }}
router-link.dropdown-item(:to="{name: 'stable'}") {{ $t('stable') }}
router-link.nav-item(tag="li", :to="{name: 'market'}", exact)

View File

@@ -6,7 +6,7 @@
.form
h2(v-once) {{ $t('filter') }}
h3 {{ this.groupBy === 'type' ? 'Type' : $t('class') }}
h3 {{ this.groupBy === 'type' ? $t('equipmentType') : $t('class') }}
.form-group
.form-check(
v-for="group in itemsGroups",
@@ -15,19 +15,21 @@
label.custom-control.custom-checkbox
input.custom-control-input(type="checkbox", v-model="viewOptions[group.key].selected")
span.custom-control-indicator
span.custom-control-description(v-once) {{ $t(group.label) }}
span.custom-control-description(v-once) {{ group.label }}
.col-10.standard-page
.clearfix
h1.float-left.mb-0.page-header(v-once) {{ $t('equipment') }}
.float-right
b-dropdown(text="Sort by", right=true)
span.dropdown-label {{ $t('sortBy') }}
b-dropdown(:text="'Sort 1'", right=true)
b-dropdown-item(href="#") Option 1
b-dropdown-item(href="#") Option 2
b-dropdown-item(href="#") Option 3
b-dropdown(text="Group by", right=true)
b-dropdown-item(@click="groupBy = 'type'", :class="{'dropdown-item-active': groupBy === 'type'}") Type
b-dropdown-item(@click="groupBy = 'class'", :class="{'dropdown-item-active': groupBy === 'class'}") {{ $t('class') }}
span.dropdown-label {{ $t('groupBy2') }}
b-dropdown(:text="$t(groupBy === 'type' ? 'equipmentType' : 'class')", right=true)
b-dropdown-item(@click="groupBy = 'type'", :active="groupBy === 'type'") {{ $t('equipmentType') }}
b-dropdown-item(@click="groupBy = 'class'", :active="groupBy === 'class'") {{ $t('class') }}
drawer(
:title="$t('equipment')",
@@ -52,7 +54,7 @@
:placement="'top'"
)
span(slot="content")
.popover-content-title {{ $t(drawerPreference+'PopoverText') }}
.popover-content-text {{ $t(drawerPreference+'PopoverText') }}
toggle-switch.float-right(
:label="$t(costume ? 'useCostume' : 'autoEquipBattleGear')",
@@ -66,23 +68,25 @@
:key="group",
:item="flatGear[activeItems[group]]",
:itemContentClass="flatGear[activeItems[group]] ? 'shop_' + flatGear[activeItems[group]].key : null",
:showPopover="!!flatGear[activeItems[group]] && flatGear[activeItems[group]].key.indexOf('_base_0') === -1",
:label="$t(label)",
:selected="true",
:emptyItem="!flatGear[activeItems[group]] || flatGear[activeItems[group]].key.indexOf('_base_0') !== -1",
:label="label",
:popoverPosition="'top'",
:starVisible="!costume || user.preferences.costume",
@click="equip",
)
template(slot="popoverContent", scope="ctx")
equipmentAttributesPopover(:item="ctx.item")
template(slot="itemBadge", scope="ctx")
starBadge(
:selected="true",
:show="!costume || user.preferences.costume",
@click="equip(ctx.item)",
)
div(
v-for="group in itemsGroups",
v-if="viewOptions[group.key].selected",
:key="group.key",
)
h2
| {{ $t(group.label) }}
| {{ group.label }}
|
span.badge.badge-pill.badge-default {{items[group.key].length}}
@@ -92,20 +96,23 @@
v-if="viewOptions[group.key].open || index < itemsPerLine",
:item="item",
:itemContentClass="'shop_' + item.key",
:showPopover="item && item.key.indexOf('_base_0') === -1",
:emptyItem="!item || item.key.indexOf('_base_0') !== -1",
:key="item.key",
:selected="activeItems[item.type] === item.key",
:starVisible="!costume || user.preferences.costume",
@click="equip",
)
template(slot="itemBadge", scope="ctx")
starBadge(
:selected="activeItems[ctx.item.type] === ctx.item.key",
:show="!costume || user.preferences.costume",
@click="equip(ctx.item)",
)
template(slot="popoverContent", scope="ctx")
equipmentAttributesPopover(:item="ctx.item")
div(v-if="items[group.key].length === 0")
p(v-once) {{ $t('noGearItemsOfType', { type: $t(group.label) }) }}
p(v-once) {{ $t('noGearItemsOfType', { type: group.label }) }}
a.btn.btn-show-more(
v-if="items[group.key].length > itemsPerLine",
@click="viewOptions[group.key].open = !viewOptions[group.key].open"
) {{ viewOptions[group.key].open ? $t('showLessGearItems', { type: $t(group.label) }) : $t('showAllGearItems', { type: $t(group.label), items: items[group.key].length }) }}
) {{ viewOptions[group.key].open ? $t('showLessGearItems', { type: group.label }) : $t('showAllGearItems', { type: group.label, items: items[group.key].length }) }}
</template>
<style lang="scss" scoped>
@@ -126,13 +133,18 @@ import bPopover from 'bootstrap-vue/lib/components/popover';
import toggleSwitch from 'client/components/ui/toggleSwitch';
import Item from 'client/components/inventory/item';
import EquipmentAttributesPopover from 'client/components/inventory/equipmentAttributesPopover';
import EquipmentAttributesPopover from 'client/components/inventory/equipment/attributesPopover';
import StarBadge from 'client/components/inventory/starBadge';
import Drawer from 'client/components/inventory/drawer';
import i18n from 'common/script/i18n';
export default {
name: 'Equipment',
components: {
Item,
EquipmentAttributesPopover,
StarBadge,
Drawer,
bDropdown,
bDropdownItem,
@@ -145,25 +157,25 @@ export default {
searchText: null,
searchTextThrottled: null,
costume: false,
groupBy: 'type', // or 'class' TODO move to router?
groupBy: 'type', // or 'class'
gearTypesToStrings: Object.freeze({ // TODO use content.itemList?
headAccessory: 'headAccessoryCapitalized',
head: 'headgearCapitalized',
eyewear: 'eyewear',
weapon: 'weaponCapitalized',
shield: 'offhandCapitalized',
armor: 'armorCapitalized',
body: 'body',
back: 'back',
headAccessory: i18n.t('headAccessoryCapitalized'),
head: i18n.t('headgearCapitalized'),
eyewear: i18n.t('eyewear'),
weapon: i18n.t('weaponCapitalized'),
shield: i18n.t('offhandCapitalized'),
armor: i18n.t('armorCapitalized'),
body: i18n.t('body'),
back: i18n.t('back'),
}),
gearClassesToStrings: Object.freeze({
warrior: 'warrior', // TODO immediately calculate $(label) instead of all the times
wizard: 'mage',
rogue: 'rogue',
healer: 'healer',
special: 'special',
mystery: 'mystery',
armoire: 'armoireText',
warrior: i18n.t('warrior'),
wizard: i18n.t('mage'),
rogue: i18n.t('rogue'),
healer: i18n.t('healer'),
special: i18n.t('special'),
mystery: i18n.t('mystery'),
armoire: i18n.t('armoireText'),
}),
viewOptions: {},
};

View File

@@ -1,7 +1,7 @@
<template lang="pug">
.row
secondary-menu.col-12
router-link.nav-link(:to="{name: 'inventory'}", exact) {{ $t('inventory') }}
router-link.nav-link(:to="{name: 'items'}", exact) {{ $t('items') }}
router-link.nav-link(:to="{name: 'equipment'}") {{ $t('equipment') }}
router-link.nav-link(:to="{name: 'stable'}") {{ $t('stable') }}
.col-12

View File

@@ -1,27 +1,23 @@
<template lang="pug">
div(v-if="emptyItem")
.item-wrapper
.item.item-empty
.item-content
span.item-label(v-if="label") {{ label }}
b-popover(
v-else,
:triggers="['hover']",
:placement="popoverPosition",
v-if="showPopover",
@click="click",
)
span(slot="content")
slot(name="popoverContent", :item="item")
.item-wrapper
.item
span.badge.badge-pill(
:class="{'item-selected-badge': selected === true}",
@click="click",
v-if="starVisible"
) &#9733;
slot(name="itemBadge", :item="item")
span.item-content(:class="itemContentClass")
span.item-label(v-if="label") {{ label }}
div(v-else)
.item-wrapper
.item.item-empty
.item-content
span.item-label(v-if="label") {{ label }}
</template>
<script>
@@ -39,18 +35,12 @@ export default {
itemContentClass: {
type: String,
},
selected: {
type: Boolean,
},
starVisible: {
type: Boolean,
},
label: {
type: String,
},
showPopover: {
emptyItem: {
type: Boolean,
default: true,
default: false,
},
popoverPosition: {
type: String,

View File

@@ -0,0 +1,154 @@
<template lang="pug">
.row
.col-2.standard-sidebar
.form-group
input.form-control.input-search(type="text", v-model="searchText", :placeholder="$t('search')")
.form
h2(v-once) {{ $t('filter') }}
h3(v-once) {{ $t('equipmentType') }}
.form-group
.form-check(
v-for="group in groups",
:key="group.key",
)
label.custom-control.custom-checkbox
input.custom-control-input(type="checkbox", v-model="group.selected")
span.custom-control-indicator
span.custom-control-description(v-once) {{ $t(group.key) }}
.col-10.standard-page
.clearfix
h1.float-left.mb-0.page-header(v-once) {{ $t('items') }}
.float-right
span.dropdown-label {{ $t('sortBy') }}
b-dropdown(:text="$t(sortBy)", right=true)
b-dropdown-item(@click="sortBy = 'quantity'", :active="sortBy === 'quantity'") {{ $t('quantity') }}
b-dropdown-item(@click="sortBy = 'AZ'", :active="sortBy === 'AZ'") {{ $t('AZ') }}
div(
v-for="group in groups",
v-if="group.selected",
:key="group.key",
)
h2
| {{ $t(group.key) }}
|
span.badge.badge-pill.badge-default {{group.quantity}}
.items
item(
v-for="({data: item, quantity}, index) in items[group.key]",
v-if="group.open || index < itemsPerLine",
:item="item",
:key="item.key",
:itemContentClass="`${group.classPrefix}${item.key}`"
:selected="true",
)
template(slot="popoverContent", scope="ctx")
h4.popover-content-title {{ ctx.item.text() }}
.popover-content-text {{ ctx.item.notes() }}
template(slot="itemBadge", scope="ctx")
span.badge.badge-pill.badge-item.badge-quantity {{ quantity }}
div(v-if="items[group.key].length === 0")
p(v-once) {{ $t('noGearItemsOfType', { type: $t(group.key) }) }}
a.btn.btn-show-more(
v-if="items[group.key].length > itemsPerLine",
@click="group.open = !group.open"
) {{ group.open ? $t('showLessGearItems', { type: $t(group.key) }) : $t('showAllGearItems', { type: $t(group.key), items: items[group.key].length }) }}
</template>
<style lang="scss" scoped>
</style>
<script>
import { mapState } from 'client/libs/store';
import each from 'lodash/each';
import throttle from 'lodash/throttle';
import bDropdown from 'bootstrap-vue/lib/components/dropdown';
import bDropdownItem from 'bootstrap-vue/lib/components/dropdown-item';
import Item from 'client/components/inventory/item';
const allowedSpecialItems = ['snowball', 'spookySparkles', 'shinySeed', 'seafoam'];
const groups = [
['eggs', 'Pet_Egg_'],
['hatchingPotions', 'Pet_HatchingPotion_'],
['food', 'Pet_Food_'],
['special', 'inventory_special_', allowedSpecialItems],
].map(([group, classPrefix, allowedItems]) => {
return {
key: group,
quantity: 0,
selected: true,
open: false,
classPrefix,
allowedItems,
};
});
export default {
name: 'Items',
components: {
Item,
bDropdown,
bDropdownItem,
},
data () {
return {
itemsPerLine: 9,
searchText: null,
searchTextThrottled: null,
groups,
sortBy: 'quantity', // or 'AZ'
};
},
watch: {
searchText: throttle(function throttleSearch () {
this.searchTextThrottled = this.searchText;
}, 250),
},
computed: {
...mapState({
content: 'content',
user: 'user.data',
}),
items () {
const searchText = this.searchTextThrottled;
const itemsByType = {};
this.groups.forEach(group => {
const groupKey = group.key;
let itemsArray = itemsByType[groupKey] = [];
const contentItems = this.content[groupKey];
each(this.user.items[groupKey], (itemQuantity, itemKey) => {
if (itemQuantity > 0 && (!group.allowedItems || group.allowedItems.indexOf(itemKey) !== -1)) {
const item = contentItems[itemKey];
const isSearched = !searchText || item.text().toLowerCase().indexOf(searchText) !== -1;
if (isSearched) {
itemsArray.push({
data: item,
quantity: itemQuantity,
});
group.quantity += itemQuantity;
}
}
});
itemsArray.sort((a, b) => {
if (this.sortBy === 'quantity') {
return b.quantity - a.quantity;
} else { // AZ
return a.data.text().localeCompare(b.data.text());
}
});
});
return itemsByType;
},
},
};
</script>

View File

@@ -0,0 +1,48 @@
<template lang="pug">
span.badge.badge-pill.badge-item.badge-star(
:class="{'item-selected-badge': selected === true}",
@click="click",
v-if="show",
) &#9733;
</template>
<style lang="scss">
@import '~client/assets/scss/colors.scss';
.badge-star {
cursor: pointer;
display: none;
left: -9px;
color: $gray-400;
background: $white;
padding: 4.5px 6px;
&.item-selected-badge {
display: block;
background: $teal-50;
color: $white;
}
}
.item:hover > .badge-star {
display: block;
}
</style>
<script>
export default {
props: {
show: {
type: Boolean,
},
selected: {
type: Boolean,
},
},
methods: {
click () {
this.$emit('click');
},
},
};
</script>