From 9e1f7f38112abe45a66225fd9434cb398cdfe6fd Mon Sep 17 00:00:00 2001 From: Matteo Pagliazzi Date: Mon, 22 May 2017 16:30:52 +0200 Subject: [PATCH] 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 --- website/client/README.md | 20 +++ website/client/assets/scss/badge.scss | 14 ++ website/client/assets/scss/dropdown.scss | 11 +- website/client/assets/scss/index.scss | 32 +--- website/client/assets/scss/item.scss | 36 +--- website/client/assets/scss/page.scss | 5 + website/client/assets/scss/utils.scss | 16 ++ website/client/components/appMenu.vue | 4 +- .../attributesPopover.vue} | 0 .../{equipment.vue => equipment/index.vue} | 86 +++++----- website/client/components/inventory/index.vue | 2 +- website/client/components/inventory/item.vue | 30 ++-- .../components/inventory/items/index.vue | 154 ++++++++++++++++++ .../client/components/inventory/starBadge.vue | 48 ++++++ website/client/router.js | 5 +- website/common/locales/en/newClient.json | 7 +- 16 files changed, 350 insertions(+), 120 deletions(-) create mode 100644 website/client/README.md create mode 100644 website/client/assets/scss/utils.scss rename website/client/components/inventory/{equipmentAttributesPopover.vue => equipment/attributesPopover.vue} (100%) rename website/client/components/inventory/{equipment.vue => equipment/index.vue} (78%) create mode 100644 website/client/components/inventory/items/index.vue create mode 100644 website/client/components/inventory/starBadge.vue diff --git a/website/client/README.md b/website/client/README.md new file mode 100644 index 0000000000..f553bbd3a4 --- /dev/null +++ b/website/client/README.md @@ -0,0 +1,20 @@ +#Running + - Open a terminal and type `npm run client:dev` + - Open a second terminal and type `npm start` + +#Preparation Reading +- Vue 2 (https://vuejs.org) + +- Webpack (https://webpack.github.io/) is the build system and it includes plugins for code transformation, right now we have: BabelJS for ES6 transpilation, eslint for code style, less and postcss for css compilation. The code comes from https://github.com/vuejs-templates/webpack which is a Webpack template for Vue, with some small modifications to adapt it to our use case. Docs http://vuejs-templates.github.io/webpack/ + +- We’re using `.vue` files that make it possible to have HTML, JS and CSS for each component together in a single location. They’re implemented as a webpack plugin and the docs can be found here http://vue-loader.vuejs.org/en/ + +- SemanticUI is the UI framework http://semantic-ui.com/. So far I’ve only used the CSS part, it also has JS plugins but I’ve yet to use them. It supports theming so if it’s not too difficult we’ll want to customize the base theme with our own styles instead of writing CSS rules to override the original styling. + +The code is in `/website/client`. We’re using something very similar to Vuex (equivalent of React’s Redux) for state management http://vuex.vuejs.org/en/index.html + +The API is almost the same except that we don’t use mutations but only actions because it would make it difficult to work with common code + +The project is developed directly in the `develop` branch as long as we’ll be able to avoid splitting it into a different branch. + +So far most of the work has been on the template, so there’s no complex logic to understand. The only thing I would suggest you to read about is Vuex for data management: it’s basically a Flux implementation: there’s a central store that hold the data for the entire app, and every change to the data must happen through an action, the data cannot be mutated directly. diff --git a/website/client/assets/scss/badge.scss b/website/client/assets/scss/badge.scss index 2679c665a7..629cb72011 100644 --- a/website/client/assets/scss/badge.scss +++ b/website/client/assets/scss/badge.scss @@ -4,6 +4,7 @@ line-height: 1.33; color: $gray-200; padding: 4px 8px; + box-shadow: 0 1px 1px 0 rgba($black, 0.12); } .badge-pill { @@ -12,4 +13,17 @@ .badge-default { background: $gray-500; + box-shadow: none; +} + +.badge-item { + position: absolute; + top: -9px; +} + +.badge-quantity { + color: $white; + right: -9px; + padding: 4.5px 8.5px; + background-color: $orange-100; } \ No newline at end of file diff --git a/website/client/assets/scss/dropdown.scss b/website/client/assets/scss/dropdown.scss index 0a1d9f4c04..54e47a70b2 100644 --- a/website/client/assets/scss/dropdown.scss +++ b/website/client/assets/scss/dropdown.scss @@ -40,7 +40,7 @@ outline: none; } - &:active, &:hover, &:focus, &.active, &.dropdown-item-active { + &:active, &:hover, &:focus, &.active { background-color: rgba(#d5c8ff, 0.32); color: $purple-200; } @@ -48,4 +48,13 @@ .dropdown + .dropdown { margin-left: 12px; +} + +.dropdown-label { + font-size: 14px; + font-weight: bold; + line-height: 1.43; + color: $gray-10; + margin-right: 20px; + margin-left: 20px; } \ No newline at end of file diff --git a/website/client/assets/scss/index.scss b/website/client/assets/scss/index.scss index 02609cd4c5..a162a8fe06 100644 --- a/website/client/assets/scss/index.scss +++ b/website/client/assets/scss/index.scss @@ -1,36 +1,16 @@ -// Functions - -// From Bootstrap 4 -// Replace `$search` with `$replace` in `$string` -// @author Hugo Giraudel -// @param {String} $string - Initial string -// @param {String} $search - Substring to replace -// @param {String} $replace ('') - New value -// @return {String} - Updated string -@function str-replace($string, $search, $replace: "") { - $index: str-index($string, $search); - - @if $index { - @return str-slice($string, 1, $index - 1) + $replace + str-replace(str-slice($string, $index + str-length($search)), $search, $replace); - } - - @return $string; -} - -// Variables +// Variables and Functions +@import './utils'; @import './colors'; -html, body { - height: 100%; - background: $gray-700; -} - * { transition-duration: .15s; transition-property: border-color, box-shadow, color; transition-timing-function: ease-in; } +// Generic components +@import './page'; + // Global styles @import './typography'; @import './form'; @@ -40,5 +20,3 @@ html, body { @import './popover'; @import './item'; -// Generic components -@import './page'; \ No newline at end of file diff --git a/website/client/assets/scss/item.scss b/website/client/assets/scss/item.scss index 39baee16e1..51161e1b8a 100644 --- a/website/client/assets/scss/item.scss +++ b/website/client/assets/scss/item.scss @@ -46,13 +46,13 @@ } .item .item-content { - position: absolute; - width: 40px; - height: 40px; - padding: 4px; - top: 22px; - right: 26px; + margin: auto; display: block; + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 0; } .item-label { @@ -64,26 +64,4 @@ text-align: center; color: $gray-400; margin-top: 4px; -} - -.item > .badge { - cursor: pointer; - display: none; - position: absolute; - top: -12px; - left: -12px; - color: $gray-400; - background: $white; - padding: 4.5px 6px; - box-shadow: 0 1px 1px 0 rgba($black, 0.12); - - &.item-selected-badge { - display: block; - background: $teal-50; - color: $white; - } -} - -.item:hover > .badge { - display: block; -} +} \ No newline at end of file diff --git a/website/client/assets/scss/page.scss b/website/client/assets/scss/page.scss index 5623267603..70509ad83c 100644 --- a/website/client/assets/scss/page.scss +++ b/website/client/assets/scss/page.scss @@ -1,3 +1,8 @@ +html, body { + height: 100%; + background: $gray-700; +} + .standard-sidebar { background: $gray-600; padding: 24px; diff --git a/website/client/assets/scss/utils.scss b/website/client/assets/scss/utils.scss new file mode 100644 index 0000000000..6acb42d26b --- /dev/null +++ b/website/client/assets/scss/utils.scss @@ -0,0 +1,16 @@ +// From Bootstrap 4 +// Replace `$search` with `$replace` in `$string` +// @author Hugo Giraudel +// @param {String} $string - Initial string +// @param {String} $search - Substring to replace +// @param {String} $replace ('') - New value +// @return {String} - Updated string +@function str-replace($string, $search, $replace: "") { + $index: str-index($string, $search); + + @if $index { + @return str-slice($string, 1, $index - 1) + $replace + str-replace(str-slice($string, $index + str-length($search)), $search, $replace); + } + + @return $string; +} \ No newline at end of file diff --git a/website/client/components/appMenu.vue b/website/client/components/appMenu.vue index 593a64475f..0f3e4fc58d 100644 --- a/website/client/components/appMenu.vue +++ b/website/client/components/appMenu.vue @@ -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) diff --git a/website/client/components/inventory/equipmentAttributesPopover.vue b/website/client/components/inventory/equipment/attributesPopover.vue similarity index 100% rename from website/client/components/inventory/equipmentAttributesPopover.vue rename to website/client/components/inventory/equipment/attributesPopover.vue diff --git a/website/client/components/inventory/equipment.vue b/website/client/components/inventory/equipment/index.vue similarity index 78% rename from website/client/components/inventory/equipment.vue rename to website/client/components/inventory/equipment/index.vue index f4476917ad..04d8d0dbd0 100644 --- a/website/client/components/inventory/equipment.vue +++ b/website/client/components/inventory/equipment/index.vue @@ -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 }) }} + + diff --git a/website/client/components/inventory/starBadge.vue b/website/client/components/inventory/starBadge.vue new file mode 100644 index 0000000000..7da197f3bc --- /dev/null +++ b/website/client/components/inventory/starBadge.vue @@ -0,0 +1,48 @@ + + + + + diff --git a/website/client/router.js b/website/client/router.js index 50f1562ce8..e067329f25 100644 --- a/website/client/router.js +++ b/website/client/router.js @@ -11,7 +11,8 @@ import UserTasks from './components/userTasks'; // Inventory import InventoryContainer from './components/inventory/index'; -import EquipmentPage from './components/inventory/equipment'; +import ItemsPage from './components/inventory/items/index'; +import EquipmentPage from './components/inventory/equipment/index'; import StablePage from './components/inventory/stable'; // Social @@ -39,7 +40,7 @@ export default new VueRouter({ path: '/inventory', component: InventoryContainer, children: [ - { name: 'inventory', path: '', component: Page }, + { name: 'items', path: 'items', component: ItemsPage }, { name: 'equipment', path: 'equipment', component: EquipmentPage }, { name: 'stable', path: 'stable', component: StablePage }, ], diff --git a/website/common/locales/en/newClient.json b/website/common/locales/en/newClient.json index 404a080950..e7e54abd6c 100644 --- a/website/common/locales/en/newClient.json +++ b/website/common/locales/en/newClient.json @@ -4,5 +4,10 @@ "showAllGearItems": "Show All <%= items %> <%= type %> Gear Items", "showLessGearItems": "Show Less <%= type %> Gear Items", "noGearItemsOfType": "You don't own any pieces of <%= type %>.", - "costumeDisabled": "You have disabled your costume." + "costumeDisabled": "You have disabled your costume.", + "items": "Items", + "sortBy": "Sort By", + "groupBy2": "Group By", + "quantity": "Quantity", + "AZ": "A-Z" }