Merged in develop
This commit is contained in:
@@ -1,121 +1,130 @@
|
||||
<template lang="pug">
|
||||
#app-header.row
|
||||
avatar#header-avatar(:user="user")
|
||||
div
|
||||
span.character-name {{user.profile.name}}
|
||||
span.character-level Lvl {{user.stats.lvl}}
|
||||
.progress-container.d-flex
|
||||
img.icon(src="~assets/header/png/health@3x.png")
|
||||
.progress
|
||||
.progress-bar.bg-danger(:style="{width: `${percent(user.stats.hp, MAX_HEALTH)}%`}")
|
||||
span {{user.stats.hp | round}} / {{MAX_HEALTH}}
|
||||
.progress-container.d-flex
|
||||
img.icon(src="~assets/header/png/experience@3x.png")
|
||||
.progress
|
||||
.progress-bar.bg-warning(:style="{width: `${percent(user.stats.exp, toNextLevel)}%`}")
|
||||
span {{user.stats.exp | round}} / {{toNextLevel}}
|
||||
.progress-container.d-flex(ng-if="user.flags.classSelected && !user.preferences.disableClasses")
|
||||
img.icon(src="~assets/header/png/magic@3x.png")
|
||||
.progress
|
||||
.progress-bar(:style="{width: `${percent(user.stats.mp, maxMP)}%`}")
|
||||
span {{user.stats.mp | round}} / {{maxMP}}
|
||||
member-details(:member="user", @click="$router.push({name: 'avatar'})")
|
||||
.view-party
|
||||
// TODO button should open the party members modal
|
||||
router-link.btn.btn-primary(:active-class="''", :to="{name: 'party'}") {{ $t('viewParty') }}
|
||||
.party-members.d-flex(v-if="partyMembers && partyMembers.length > 1")
|
||||
member-details(
|
||||
v-for="(member, $index) in partyMembers",
|
||||
:key="member._id",
|
||||
v-if="member._id !== user._id && $index < 10",
|
||||
:member="member",
|
||||
condensed=true,
|
||||
@onHover="expandMember(member._id)",
|
||||
:expanded="member._id === expandedMember",
|
||||
)
|
||||
.no-party.d-flex.justify-content-center.text-center(v-else)
|
||||
.align-self-center(v-once)
|
||||
h3 {{ $t('battleWithFriends') }}
|
||||
span.small-text(v-html="$t('inviteFriendsParty')")
|
||||
br
|
||||
// TODO link to party creation or party page if partying solo
|
||||
router-link.btn.btn-primary(:active-class="''", :to="{name: 'party'}") {{ $t('startAParty') }}
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import '~client/assets/scss/colors.scss';
|
||||
|
||||
// TODO move to colors.scss if used in other places
|
||||
$header-dark-background: #271B3D;
|
||||
$header-text-color: #D5C8FF;
|
||||
|
||||
/* TODO refactor: only partially ported from SemanticUI; */
|
||||
#app-header {
|
||||
padding-left: 14px;
|
||||
margin-top: 56px;
|
||||
background: $purple-50;
|
||||
height: 192px;
|
||||
color: $header-text-color;
|
||||
height: 204px;
|
||||
color: $header-color;
|
||||
flex-wrap: nowrap;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.character-name {
|
||||
display: block;
|
||||
font-size: 16px;
|
||||
margin-top: 32px;
|
||||
line-height: 1.5;
|
||||
color: $white;
|
||||
font-weight: bold;
|
||||
.no-party, .party-members {
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.character-level {
|
||||
display: block;
|
||||
font-size: 12px;
|
||||
margin-top: 4px;
|
||||
margin-bottom: 20px;
|
||||
line-height: 1;
|
||||
.party-members {
|
||||
}
|
||||
|
||||
#header-avatar {
|
||||
margin-top: 24px;
|
||||
margin-right: 1rem;
|
||||
.view-party {
|
||||
position: absolute;
|
||||
z-index: 10;
|
||||
right: 0;
|
||||
padding-right: 40px;
|
||||
height: 100%;
|
||||
background-image: linear-gradient(to right, rgba($purple-50, 0), $purple-50);
|
||||
|
||||
.btn {
|
||||
margin-top: 75%;
|
||||
}
|
||||
}
|
||||
|
||||
.progress-container {
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
.no-party {
|
||||
.small-text {
|
||||
color: $header-color;
|
||||
flex-wrap: nowrap;
|
||||
}
|
||||
|
||||
.progress-container > span {
|
||||
font-size: 12px;
|
||||
margin-left: 10px;
|
||||
line-height: 1em;
|
||||
}
|
||||
.no-party, .party-members {
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.progress-container > .icon {
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
.party-members {
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
.progress-container > .progress {
|
||||
width: 203px;
|
||||
margin: 0px;
|
||||
border-radius: 0px;
|
||||
height: 12px;
|
||||
background-color: $header-dark-background;
|
||||
}
|
||||
.no-party {
|
||||
.small-text {
|
||||
color: $header-color;
|
||||
}
|
||||
|
||||
.progress-container > .progress > .progress-bar {
|
||||
border-radius: 0px;
|
||||
height: 12px;
|
||||
min-width: 0px;
|
||||
h3 {
|
||||
color: $white;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
button {
|
||||
margin-top: 16px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
import Avatar from './avatar';
|
||||
import { mapState } from 'client/libs/store';
|
||||
|
||||
import { toNextLevel } from '../../common/script/statHelpers';
|
||||
import statsComputed from '../../common/script/libs/statsComputed';
|
||||
import percent from '../../common/script/libs/percent';
|
||||
import { mapGetters, mapActions } from 'client/libs/store';
|
||||
import MemberDetails from './memberDetails';
|
||||
import createPartyModal from './guilds/createPartyModal';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
Avatar,
|
||||
MemberDetails,
|
||||
createPartyModal,
|
||||
},
|
||||
methods: {
|
||||
percent,
|
||||
data () {
|
||||
return {
|
||||
expandedMember: null,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
...mapState({
|
||||
user: 'user.data',
|
||||
MAX_HEALTH: 'constants.MAX_HEALTH',
|
||||
...mapGetters({
|
||||
user: 'user:data',
|
||||
partyMembers: 'party:members',
|
||||
}),
|
||||
maxMP () {
|
||||
return statsComputed(this.user).maxMP;
|
||||
},
|
||||
methods: {
|
||||
...mapActions({
|
||||
getPartyMembers: 'party:getMembers',
|
||||
}),
|
||||
expandMember (memberId) {
|
||||
if (this.expandedMember === memberId) {
|
||||
this.expandedMember = null;
|
||||
} else {
|
||||
this.expandedMember = memberId;
|
||||
}
|
||||
},
|
||||
toNextLevel () { // Exp to next level
|
||||
return toNextLevel(this.user.stats.lvl);
|
||||
launchPartyModal () {
|
||||
this.$root.$emit('show::modal', 'create-party-modal');
|
||||
},
|
||||
},
|
||||
created () {
|
||||
this.getPartyMembers();
|
||||
},
|
||||
};
|
||||
</script>
|
||||
</script>
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
<template lang="pug">
|
||||
nav.navbar.navbar-inverse.fixed-top.navbar-toggleable-sm
|
||||
.navbar-header
|
||||
// TODO srcset / svg images
|
||||
img(src="~assets/header/png/logo@3x.png")
|
||||
.logo.svg-icon(v-html="icons.logo")
|
||||
.collapse.navbar-collapse
|
||||
ul.navbar-nav.mr-auto
|
||||
router-link.nav-item(tag="li", :to="{name: 'tasks'}", exact)
|
||||
@@ -13,20 +12,18 @@ nav.navbar.navbar-inverse.fixed-top.navbar-toggleable-sm
|
||||
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)
|
||||
a.nav-link(v-once) {{ $t('market') }}
|
||||
router-link.nav-item(tag="li", :to="{name: 'shops'}", exact)
|
||||
a.nav-link(v-once) {{ $t('shops') }}
|
||||
router-link.nav-item.dropdown(:to="{name: 'party'}")
|
||||
a.nav-link(v-once) {{ $t('party') }}
|
||||
router-link.nav-item.dropdown(tag="li", :to="{name: 'tavern'}", :class="{'active': $route.path.startsWith('/guilds')}")
|
||||
a.nav-link(v-once) {{ $t('guilds') }}
|
||||
.dropdown-menu
|
||||
router-link.dropdown-item(:to="{name: 'tavern'}") {{ $t('tavern') }}
|
||||
router-link.dropdown-item(:to="{name: 'myGuilds'}") {{ $t('myGuilds') }}
|
||||
router-link.dropdown-item(:to="{name: 'guildsDiscovery'}") {{ $t('guildsDiscovery') }}
|
||||
router-link.nav-item.dropdown(tag="li", :to="{name: 'tavern'}", :class="{'active': $route.path.startsWith('/social')}")
|
||||
a.nav-link(v-once) {{ $t('social') }}
|
||||
.dropdown-menu
|
||||
router-link.dropdown-item(:to="{name: 'inbox'}") {{ $t('inbox') }}
|
||||
router-link.dropdown-item(:to="{name: 'challenges'}") {{ $t('challenges') }}
|
||||
router-link.dropdown-item(:to="{name: 'party'}") {{ $t('party') }}
|
||||
router-link.nav-item(tag="li", :to="{name: 'challenges'}", exact)
|
||||
a.nav-link(v-once) {{ $t('challenges') }}
|
||||
router-link.nav-item.dropdown(tag="li", to="/help", :class="{'active': $route.path.startsWith('/help')}")
|
||||
a.nav-link(v-once) {{ $t('help') }}
|
||||
.dropdown-menu
|
||||
@@ -34,129 +31,197 @@ nav.navbar.navbar-inverse.fixed-top.navbar-toggleable-sm
|
||||
router-link.dropdown-item(to="/help/report-bug") {{ $t('reportBug') }}
|
||||
router-link.dropdown-item(to="/help/request-feature") {{ $t('requestAF') }}
|
||||
.item-with-icon
|
||||
img(src="~assets/header/png/gem@3x.png")
|
||||
span {{userGems}}
|
||||
.svg-icon(v-html="icons.gem")
|
||||
span {{userGems | roundBigNumber}}
|
||||
.item-with-icon
|
||||
img(src="~assets/header/png/gold@3x.png")
|
||||
span {{user.stats.gp | floor}}
|
||||
.item-with-icon
|
||||
img(src="~assets/header/png/notifications@3x.png")
|
||||
router-link.dropdown.item-with-icon(:to="{name: 'avatar'}")
|
||||
// TODO icons should be white when active
|
||||
img(src="~assets/header/png/user@3x.png")
|
||||
.svg-icon(v-html="icons.gold")
|
||||
span {{user.stats.gp | roundBigNumber}}
|
||||
.item-with-icon.item-notifications
|
||||
.svg-icon(v-html="icons.notifications")
|
||||
router-link.dropdown.item-with-icon.item-user(:to="{name: 'avatar'}")
|
||||
.svg-icon(v-html="icons.user")
|
||||
.dropdown-menu.dropdown-menu-right.user-dropdown
|
||||
router-link.dropdown-item(:to="{name: 'avatar'}") {{ $t('editAvatar') }}
|
||||
// .dropdown-divider
|
||||
router-link.dropdown-item.edit-avatar(:to="{name: 'avatar'}")
|
||||
h3 {{ user.profile.name }}
|
||||
span.small-text {{ $t('editAvatar') }}
|
||||
router-link.dropdown-item(:to="{name: 'inbox'}") {{ $t('inbox') }}
|
||||
router-link.dropdown-item(:to="{name: 'stats'}") {{ $t('stats') }}
|
||||
router-link.dropdown-item(:to="{name: 'achievements'}") {{ $t('achievements') }}
|
||||
// .dropdown-divider
|
||||
router-link.dropdown-item(:to="{name: 'settings'}") {{ $t('settings') }}
|
||||
// .dropdown-divider
|
||||
router-link.dropdown-item(to="/logout") {{ $t('logout') }}
|
||||
a.nav-link.dropdown-item(to="/", @click.prevent='logout()') {{ $t('logout') }}
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import '~client/assets/scss/colors.scss';
|
||||
@import '~client/assets/scss/colors.scss';
|
||||
@import '~client/assets/scss/utils.scss';
|
||||
|
||||
nav.navbar {
|
||||
background: $purple-100 url(~assets/header/png/bits.png) right no-repeat;
|
||||
padding: 0 1.5rem;
|
||||
height: 56px;
|
||||
}
|
||||
|
||||
.navbar-header {
|
||||
margin-right: 3rem;
|
||||
|
||||
img {
|
||||
height: 28px;
|
||||
}
|
||||
}
|
||||
|
||||
.nav-item {
|
||||
.nav-link {
|
||||
font-size: 16px;
|
||||
color: $white;
|
||||
font-weight: bold;
|
||||
line-height: 1.5;
|
||||
padding: 1rem 1.5rem;
|
||||
transition: none;
|
||||
nav.navbar {
|
||||
background: $purple-100 url(~assets/svg/for-css/bits.svg) right no-repeat;
|
||||
padding-left: 25px;
|
||||
padding-right: 12.5px;
|
||||
height: 56px;
|
||||
box-shadow: 0 1px 2px 0 rgba($black, 0.24);
|
||||
}
|
||||
|
||||
&:hover {
|
||||
.navbar-header {
|
||||
margin-right: 48px;
|
||||
|
||||
.logo {
|
||||
width: 128px;
|
||||
height: 28px;
|
||||
}
|
||||
}
|
||||
|
||||
.nav-item {
|
||||
.nav-link {
|
||||
font-size: 16px;
|
||||
color: $white;
|
||||
background: $purple-300;
|
||||
}
|
||||
}
|
||||
|
||||
&.active,&:hover {
|
||||
.nav-link {
|
||||
box-shadow: 0px -4px 0px $purple-300 inset;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Make the dropdown menu open on hover
|
||||
.dropdown:hover .dropdown-menu {
|
||||
display: block;
|
||||
margin-top: 0; // remove the gap so it doesn't close
|
||||
}
|
||||
|
||||
.dropdown-menu:not(.user-dropdown) {
|
||||
background: $purple-300;
|
||||
border-radius: 0px;
|
||||
border: none;
|
||||
box-shadow: none;
|
||||
padding: 0px;
|
||||
|
||||
border-bottom-right-radius: 5px;
|
||||
border-bottom-left-radius: 5px;
|
||||
|
||||
.dropdown-item {
|
||||
font-size: 16px;
|
||||
box-shadow: none;
|
||||
color: $white;
|
||||
border: none;
|
||||
|
||||
&.active {
|
||||
background: $purple-300;
|
||||
font-weight: bold;
|
||||
line-height: 1.5;
|
||||
padding: 16px 24px;
|
||||
transition: none;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background: $purple-200;
|
||||
.nav-link {
|
||||
color: $white;
|
||||
background: $purple-200;
|
||||
}
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
border-bottom-right-radius: 5px;
|
||||
border-bottom-left-radius: 5px;
|
||||
&.active:not(:hover) {
|
||||
.nav-link {
|
||||
box-shadow: 0px -4px 0px $purple-300 inset;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.item-with-icon {
|
||||
color: $white;
|
||||
font-weight: bold;
|
||||
padding: 0.75rem 0;
|
||||
padding-left: 1rem;
|
||||
|
||||
img {
|
||||
vertical-align: middle;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
margin-right: 0.5rem;
|
||||
// Make the dropdown menu open on hover
|
||||
.dropdown:hover .dropdown-menu {
|
||||
display: block;
|
||||
margin-top: 0; // remove the gap so it doesn't close
|
||||
}
|
||||
|
||||
.dropdown + .dropdown {
|
||||
margin-left: 0px;
|
||||
}
|
||||
|
||||
.dropdown-menu:not(.user-dropdown) {
|
||||
background: $purple-200;
|
||||
border-radius: 0px;
|
||||
border: none;
|
||||
box-shadow: none;
|
||||
padding: 0px;
|
||||
|
||||
border-bottom-right-radius: 5px;
|
||||
border-bottom-left-radius: 5px;
|
||||
|
||||
.dropdown-item {
|
||||
font-size: 16px;
|
||||
box-shadow: none;
|
||||
color: $white;
|
||||
border: none;
|
||||
line-height: 1.5;
|
||||
|
||||
&.active {
|
||||
background: $purple-300;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background: $purple-300;
|
||||
|
||||
&:last-child {
|
||||
border-bottom-right-radius: 5px;
|
||||
border-bottom-left-radius: 5px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.item-with-icon {
|
||||
color: $white;
|
||||
font-size: 16px;
|
||||
font-weight: normal;
|
||||
padding-top: 16px;
|
||||
padding-left: 16px;
|
||||
|
||||
.svg-icon {
|
||||
vertical-align: middle;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
margin-right: 8px;
|
||||
float: left;
|
||||
}
|
||||
}
|
||||
|
||||
.item-notifications, .item-user {
|
||||
padding-right: 12.5px;
|
||||
padding-left: 12.5px;
|
||||
color: $header-color;
|
||||
transition: none;
|
||||
|
||||
&:hover {
|
||||
color: $white;
|
||||
}
|
||||
|
||||
.svg-icon {
|
||||
margin-right: 0px;
|
||||
color: inherit;
|
||||
}
|
||||
}
|
||||
|
||||
.item-notifications {
|
||||
margin-left: 33.5px;
|
||||
}
|
||||
|
||||
.item-user .edit-avatar {
|
||||
h3 {
|
||||
color: $gray-10;
|
||||
margin-bottom: 0px;
|
||||
}
|
||||
|
||||
.small-text {
|
||||
color: $gray-200;
|
||||
font-style: normal;
|
||||
display: block;
|
||||
}
|
||||
|
||||
padding-top: 16px;
|
||||
padding-bottom: 16px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
import { mapState, mapGetters } from 'client/libs/store';
|
||||
import gemIcon from 'assets/svg/gem.svg';
|
||||
import goldIcon from 'assets/svg/gold.svg';
|
||||
import notificationsIcon from 'assets/svg/notifications.svg';
|
||||
import userIcon from 'assets/svg/user.svg';
|
||||
import logo from 'assets/svg/logo.svg';
|
||||
|
||||
export default {
|
||||
data () {
|
||||
return {
|
||||
icons: Object.freeze({
|
||||
gem: gemIcon,
|
||||
gold: goldIcon,
|
||||
notifications: notificationsIcon,
|
||||
user: userIcon,
|
||||
logo,
|
||||
}),
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
...mapGetters({
|
||||
userGems: 'user:gems',
|
||||
}),
|
||||
...mapState({user: 'user.data'}),
|
||||
},
|
||||
methods: {
|
||||
logout () {
|
||||
localStorage.removeItem('habit-mobile-settings');
|
||||
this.$router.go('/');
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
@@ -0,0 +1,230 @@
|
||||
<template lang="pug">
|
||||
.form-wrapper
|
||||
#top-background
|
||||
.seamless_stars_varied_opacity_repeat
|
||||
|
||||
#login-form
|
||||
.text-center
|
||||
div
|
||||
.svg-icon.gryphon(v-html="icons.gryphon")
|
||||
div
|
||||
.svg-icon.habitica-logo(v-html="icons.habiticaIcon")
|
||||
.form-group.row.text-center
|
||||
.col-6
|
||||
.btn.btn-secondary.social-button(@click='socialAuth("facebook")', v-once)
|
||||
.svg-icon.social-icon(v-html="icons.facebookIcon")
|
||||
| {{this.registering ? $t('signUpWithSocial', {social: 'Facebook'}) : $t('loginWithSocial', {social: 'Facebook'})}}
|
||||
.col-6
|
||||
.btn.btn-secondary.social-button(@click='socialAuth("google")', v-once)
|
||||
.svg-icon.social-icon(v-html="icons.googleIcon")
|
||||
| {{this.registering ? $t('signUpWithSocial', {social: 'Google'}) : $t('loginWithSocial', {social: 'Google'})}}
|
||||
.form-group
|
||||
label(for='usernameInput', v-once) {{$t('username')}}
|
||||
input#usernameInput.form-control(type='text', :placeholder='$t("usernamePlaceholder")', v-model='username')
|
||||
.form-group(v-if='registering')
|
||||
label(for='emailInput', v-once) {{$t('email')}}
|
||||
input#emailInput.form-control(type='email', :placeholder='$t("emailPlaceholder")', v-model='email')
|
||||
.form-group
|
||||
label(for='passwordInput', v-once) {{$t('password')}}
|
||||
input#passwordInput.form-control(type='password', :placeholder='$t("passwordPlaceholder")', v-model='password')
|
||||
.form-group(v-if='registering')
|
||||
label(for='confirmPasswordInput', v-once) {{$t('confirmPassword')}}
|
||||
input#confirmPasswordInput.form-control(type='password', :placeholder='$t("confirmPasswordPlaceholder")', v-model='passwordConfirm')
|
||||
small.form-text(v-once) {{$t('termsAndAgreement')}}
|
||||
.text-center
|
||||
.btn.btn-info(@click='register()', v-if='registering', v-once) {{$t('joinHabitica')}}
|
||||
.btn.btn-info(@click='login()', v-if='!registering', v-once) {{$t('login')}}
|
||||
|
||||
#bottom-background
|
||||
.seamless_mountains_demo_repeat
|
||||
.midground_foreground_extended2
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import '~client/assets/scss/colors.scss';
|
||||
|
||||
.form-wrapper {
|
||||
background-color: $purple-200;
|
||||
}
|
||||
|
||||
#login-form {
|
||||
margin: 0 auto;
|
||||
width: 40em;
|
||||
padding-top: 5em;
|
||||
padding-bottom: 22.5em;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
|
||||
.gryphon {
|
||||
width: 63.2px;
|
||||
height: 69.4px;
|
||||
}
|
||||
|
||||
.habitica-logo {
|
||||
width: 144px;
|
||||
height: 31px;
|
||||
margin-top: 2em;
|
||||
margin-bottom: 2em;
|
||||
}
|
||||
|
||||
label {
|
||||
color: $white;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
input {
|
||||
margin-bottom: 2em;
|
||||
border-radius: 2px;
|
||||
background-color: #432874;
|
||||
border-color: transparent;
|
||||
height: 50px;
|
||||
color: $purple-400;
|
||||
|
||||
::-webkit-input-placeholder { /* Chrome/Opera/Safari */
|
||||
color: $purple-400;
|
||||
}
|
||||
::-moz-placeholder { /* Firefox 19+ */
|
||||
color: $purple-400;
|
||||
}
|
||||
:-ms-input-placeholder { /* IE 10+ */
|
||||
color: $purple-400;
|
||||
}
|
||||
:-moz-placeholder { /* Firefox 18- */
|
||||
color: $purple-400;
|
||||
}
|
||||
}
|
||||
|
||||
.form-text {
|
||||
font-size: 14px;
|
||||
color: $white;
|
||||
}
|
||||
|
||||
.social-button {
|
||||
width: 100%;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.social-icon {
|
||||
margin-right: 1em;
|
||||
width: 13px;
|
||||
}
|
||||
}
|
||||
|
||||
#top-background {
|
||||
.seamless_stars_varied_opacity_repeat {
|
||||
background-image: url('~assets/images/auth/seamless_stars_varied_opacity.png');
|
||||
background-repeat: repeat-x;
|
||||
position: absolute;
|
||||
height: 500px;
|
||||
width: 1600px;
|
||||
}
|
||||
}
|
||||
|
||||
#bottom-background {
|
||||
position: relative;
|
||||
|
||||
.seamless_mountains_demo_repeat {
|
||||
background-image: url('~assets/images/auth/seamless_mountains_demo.png');
|
||||
background-repeat: repeat-x;
|
||||
width: 1600px;
|
||||
height: 500px;
|
||||
position: absolute;
|
||||
z-index: 0;
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
.midground_foreground_extended2 {
|
||||
background-image: url('~assets/images/auth/midground_foreground_extended2.png');
|
||||
position: relative;
|
||||
width: 1500px;
|
||||
height: 150px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
import hello from 'hellojs';
|
||||
|
||||
import gryphon from 'assets/svg/gryphon.svg';
|
||||
import habiticaIcon from 'assets/svg/habitica-logo.svg';
|
||||
import facebookIcon from 'assets/svg/facebook.svg';
|
||||
import googleIcon from 'assets/svg/google.svg';
|
||||
|
||||
export default {
|
||||
data () {
|
||||
let data = {
|
||||
username: '',
|
||||
email: '',
|
||||
password: '',
|
||||
passwordConfirm: '',
|
||||
registering: true,
|
||||
};
|
||||
|
||||
data.icons = Object.freeze({
|
||||
gryphon,
|
||||
habiticaIcon,
|
||||
facebookIcon,
|
||||
googleIcon,
|
||||
});
|
||||
|
||||
return data;
|
||||
},
|
||||
mounted () {
|
||||
if (this.$route.path.startsWith('/login')) {
|
||||
this.registering = false;
|
||||
}
|
||||
|
||||
hello.init({
|
||||
facebook: '',
|
||||
// windows: WINDOWS_CLIENT_ID,
|
||||
google: '',
|
||||
});
|
||||
},
|
||||
methods: {
|
||||
async register () {
|
||||
if (this.password !== this.passwordConfirm) {
|
||||
alert('Passwords must match');
|
||||
return;
|
||||
}
|
||||
|
||||
// @TODO: implement langauge and invite accepting
|
||||
// var url = ApiUrl.get() + "/api/v3/user/auth/local/register";
|
||||
// if (location.search && location.search.indexOf('Invite=') !== -1) { // matches groupInvite and partyInvite
|
||||
// url += location.search;
|
||||
// }
|
||||
//
|
||||
// if($rootScope.selectedLanguage) {
|
||||
// var toAppend = url.indexOf('?') !== -1 ? '&' : '?';
|
||||
// url = url + toAppend + 'lang=' + $rootScope.selectedLanguage.code;
|
||||
// }
|
||||
|
||||
await this.$store.dispatch('auth:register', {
|
||||
username: this.username,
|
||||
email: this.email,
|
||||
password: this.password,
|
||||
passwordConfirm: this.passwordConfirm,
|
||||
});
|
||||
|
||||
this.$router.go('/tasks');
|
||||
},
|
||||
async login () {
|
||||
await this.$store.dispatch('auth:login', {
|
||||
username: this.username,
|
||||
// email: this.email,
|
||||
password: this.password,
|
||||
});
|
||||
|
||||
this.$router.go('/tasks');
|
||||
},
|
||||
async socialAuth (network) {
|
||||
let auth = await hello(network).login({scope: 'email'});
|
||||
|
||||
await this.$store.dispatch('auth:socialAuth', {
|
||||
auth,
|
||||
});
|
||||
|
||||
this.$router.go('/tasks');
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
@@ -2,51 +2,57 @@
|
||||
.avatar(:style="{width, height, paddingTop}", :class="backgroundClass")
|
||||
.character-sprites
|
||||
template(v-if="!avatarOnly" v-once)
|
||||
// Mount
|
||||
span(v-if="user.items.currentMount", :class="'Mount_Body_' + user.items.currentMount")
|
||||
// Mount Body
|
||||
span(v-if="member.items.currentMount", :class="'Mount_Body_' + member.items.currentMount")
|
||||
|
||||
// Buffs that cause visual changes to avatar: Snowman, Ghost, Flower, etc
|
||||
template(v-for="(klass, item) in visualBuffs")
|
||||
span(v-if="user.stats.buffs[item]", :class="klass")
|
||||
span(v-if="member.stats.buffs[item]", :class="klass")
|
||||
|
||||
// Show flower ALL THE TIME!!!
|
||||
// See https://github.com/HabitRPG/habitrpg/issues/7133
|
||||
span(:class="'hair_flower_' + user.preferences.hair.flower")
|
||||
// See https://github.com/HabitRPG/habitica/issues/7133
|
||||
span(:class="'hair_flower_' + member.preferences.hair.flower")
|
||||
|
||||
// Show avatar only if not currently affected by visual buff
|
||||
template(v-if!="!user.stats.buffs.snowball && !user.stats.buffs.spookySparkles && !user.stats.buffs.shinySeed && !user.stats.buffs.seafoam")
|
||||
span(:class="'chair_' + user.preferences.chair")
|
||||
span(:class="user.items.gear[costumeClass].back")
|
||||
template(v-if!="!member.stats.buffs.snowball && !member.stats.buffs.spookySparkles && !member.stats.buffs.shinySeed && !member.stats.buffs.seafoam")
|
||||
span(:class="'chair_' + member.preferences.chair")
|
||||
span(:class="member.items.gear[costumeClass].back")
|
||||
span(:class="skinClass")
|
||||
span(:class="user.preferences.size + '_shirt_' + user.preferences.shirt")
|
||||
span(:class="user.preferences.size + '_' + user.items.gear[costumeClass].armor")
|
||||
span(:class="user.items.gear[costumeClass].back_collar")
|
||||
span(:class="user.items.gear[costumeClass].body")
|
||||
span(:class="member.preferences.size + '_shirt_' + member.preferences.shirt")
|
||||
span(:class="member.preferences.size + '_' + member.items.gear[costumeClass].armor")
|
||||
span(:class="member.items.gear[costumeClass].back_collar")
|
||||
span(:class="member.items.gear[costumeClass].body")
|
||||
span.head_0
|
||||
template(v-for="type in ['base', 'bangs', 'mustache', 'beard']")
|
||||
span(:class="'hair_' + type + '_' + user.preferences.hair[type] + '_' + user.preferences.hair.color")
|
||||
span(:class="user.items.gear[costumeClass].eyewear")
|
||||
span(:class="user.items.gear[costumeClass].head")
|
||||
span(:class="user.items.gear[costumeClass].headAccessory")
|
||||
span(:class="'hair_flower_' + user.preferences.hair.flower")
|
||||
span(:class="user.items.gear[costumeClass].shield")
|
||||
span(:class="user.items.gear[costumeClass].weapon")
|
||||
span(:class="'hair_' + type + '_' + member.preferences.hair[type] + '_' + member.preferences.hair.color")
|
||||
span(:class="member.items.gear[costumeClass].eyewear")
|
||||
span(:class="member.items.gear[costumeClass].head")
|
||||
span(:class="member.items.gear[costumeClass].headAccessory")
|
||||
span(:class="'hair_flower_' + member.preferences.hair.flower")
|
||||
span(:class="member.items.gear[costumeClass].shield")
|
||||
span(:class="member.items.gear[costumeClass].weapon")
|
||||
|
||||
// Resting
|
||||
span.zzz(v-if="user.preferences.sleep")
|
||||
span.zzz(v-if="member.preferences.sleep")
|
||||
|
||||
template(v-if="!avatarOnly" v-once)
|
||||
// Mount Head
|
||||
span(v-if="user.items.currentMount", :class="'Mount_Head_' + user.items.currentMount")
|
||||
span(v-if="member.items.currentMount", :class="'Mount_Head_' + member.items.currentMount")
|
||||
// Pet
|
||||
span.current-pet(v-if="user.items.currentPet", :class="'Pet-' + user.items.currentPet")
|
||||
span.current-pet(v-if="member.items.currentPet", :class="'Pet-' + member.items.currentPet")
|
||||
.class-badge.d-flex.justify-content-center(v-if="hasClass")
|
||||
.align-self-center.svg-icon(v-html="icons[member.stats.class]")
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
<style lang="scss" scoped>
|
||||
@import '~client/assets/scss/colors.scss';
|
||||
|
||||
.avatar {
|
||||
width: 140px;
|
||||
height: 147px;
|
||||
image-rendering: pixelated;
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.character-sprites {
|
||||
@@ -60,15 +66,38 @@
|
||||
}
|
||||
|
||||
.current-pet {
|
||||
bottom: 21px;
|
||||
left: 20px;
|
||||
bottom: 0px;
|
||||
left: 0px;
|
||||
}
|
||||
|
||||
.class-badge {
|
||||
$badge-size: 32px;
|
||||
position: absolute;
|
||||
left: calc(50% - (16px));
|
||||
bottom: -($badge-size / 2);
|
||||
|
||||
width: $badge-size;
|
||||
height: $badge-size;
|
||||
background: $white;
|
||||
box-shadow: 0 2px 2px 0 rgba($black, 0.16), 0 1px 4px 0 rgba($black, 0.12);
|
||||
border-radius: 100px;
|
||||
|
||||
.svg-icon {
|
||||
width: 19px;
|
||||
height: 19px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
import warriorIcon from 'assets/svg/warrior.svg';
|
||||
import rogueIcon from 'assets/svg/rogue.svg';
|
||||
import healerIcon from 'assets/svg/healer.svg';
|
||||
import wizardIcon from 'assets/svg/wizard.svg';
|
||||
|
||||
export default {
|
||||
props: {
|
||||
user: {
|
||||
member: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
@@ -85,22 +114,38 @@ export default {
|
||||
default: 147,
|
||||
},
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
icons: Object.freeze({
|
||||
warrior: warriorIcon,
|
||||
rogue: rogueIcon,
|
||||
healer: healerIcon,
|
||||
wizard: wizardIcon,
|
||||
}),
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
hasClass () {
|
||||
return this.$store.getters['members:hasClass'](this.member);
|
||||
},
|
||||
isBuffed () {
|
||||
return this.$store.getters['members:isBuffed'](this.member);
|
||||
},
|
||||
paddingTop () {
|
||||
let val = '28px';
|
||||
|
||||
if (!this.avatarOnly) {
|
||||
if (this.user.items.currentPet) val = '24.5px';
|
||||
if (this.user.items.currentMount) val = '0px';
|
||||
if (this.member.items.currentPet) val = '24.5px';
|
||||
if (this.member.items.currentMount) val = '0px';
|
||||
}
|
||||
|
||||
return val;
|
||||
},
|
||||
backgroundClass () {
|
||||
let background = this.user.preferences.background;
|
||||
let background = this.member.preferences.background;
|
||||
|
||||
if (background && !this.avatarOnly) {
|
||||
return `background_${this.user.preferences.background}`;
|
||||
return `background_${this.member.preferences.background}`;
|
||||
}
|
||||
|
||||
return '';
|
||||
@@ -109,17 +154,17 @@ export default {
|
||||
return {
|
||||
snowball: 'snowman',
|
||||
spookySparkles: 'ghost',
|
||||
shinySeed: `avatar_floral_${this.user.stats.class}`,
|
||||
shinySeed: `avatar_floral_${this.member.stats.class}`,
|
||||
seafoam: 'seafoam_star',
|
||||
};
|
||||
},
|
||||
skinClass () {
|
||||
let baseClass = `skin_${this.user.preferences.skin}`;
|
||||
let baseClass = `skin_${this.member.preferences.skin}`;
|
||||
|
||||
return `${baseClass}${this.user.preferences.sleep ? '_sleep' : ''}`;
|
||||
return `${baseClass}${this.member.preferences.sleep ? '_sleep' : ''}`;
|
||||
},
|
||||
costumeClass () {
|
||||
return this.user.preferences.costume ? 'costume' : 'equipped';
|
||||
return this.member.preferences.costume ? 'costume' : 'equipped';
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
@@ -0,0 +1,121 @@
|
||||
<template lang="pug">
|
||||
b-modal#create-party-modal(title="Empty", size='lg', hide-footer=true)
|
||||
.header-wrap(slot="modal-header")
|
||||
h2 Image Here
|
||||
.row
|
||||
.col-12.text-center
|
||||
h2(v-once) {{$t('playInPartyTitle')}}
|
||||
p(v-once) {{$t('playInPartyDescription')}}
|
||||
.row.grey-row
|
||||
.col-6.text-center
|
||||
img
|
||||
h3(v-once) {{$t('startYourOwnPartyTitle')}}
|
||||
p(v-once) {{$t('startYourOwnPartyDescription')}}
|
||||
button.btn.btn-primary(v-once) {{$t('createParty')}}
|
||||
.col-6
|
||||
div.text-center
|
||||
img
|
||||
h3(v-once) {{$t('wantToJoinPartyTitle')}}
|
||||
p(v-once) {{$t('wantToJoinPartyDescription')}}
|
||||
button.btn.btn-primary(v-once, @click='shareUserIdShown = !shareUserIdShown') {{$t('shartUserId')}}
|
||||
.share-userid-options(v-if="shareUserIdShown")
|
||||
.option-item(v-once)
|
||||
.svg-icon(v-html="icons.copy")
|
||||
| {{$t('copy')}}
|
||||
.option-item(v-once)
|
||||
.svg-icon(v-html="icons.greyBadge")
|
||||
| {{$t('lookingForGroup')}}
|
||||
.option-item(v-once)
|
||||
.svg-icon(v-html="icons.qrCode")
|
||||
| {{$t('qrCode')}}
|
||||
.option-item(v-once)
|
||||
.svg-icon.facebook(v-html="icons.facebook")
|
||||
| {{$t('facebook')}}
|
||||
.option-item(v-once)
|
||||
.svg-icon(v-html="icons.twitter")
|
||||
| {{$t('twitter')}}
|
||||
</template>
|
||||
|
||||
<style lang='scss'>
|
||||
@import '~client/assets/scss/colors.scss';
|
||||
|
||||
.modal-body {
|
||||
padding-bottom: 0;
|
||||
padding-top: 0;
|
||||
}
|
||||
|
||||
.grey-row {
|
||||
background-color: $gray-700;
|
||||
padding: 2em;
|
||||
border-radius: 0px 0px 2px 2px;
|
||||
}
|
||||
|
||||
.share-userid-options {
|
||||
background-color: $white;
|
||||
border-radius: 2px;
|
||||
width: 180px;
|
||||
position: absolute;
|
||||
top: -8em;
|
||||
left: 4.8em;
|
||||
box-shadow: 0 2px 2px 0 rgba(26, 24, 29, 0.16), 0 1px 4px 0 rgba(26, 24, 29, 0.12);
|
||||
|
||||
.option-item {
|
||||
padding: 1em;
|
||||
|
||||
.svg-icon {
|
||||
margin-right: .5em;
|
||||
}
|
||||
|
||||
.facebook svg {
|
||||
width: 15px;
|
||||
height: 15px;
|
||||
}
|
||||
}
|
||||
|
||||
.option-item:hover {
|
||||
background-color: $header-color;
|
||||
color: $purple-200;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
import bModal from 'bootstrap-vue/lib/components/modal';
|
||||
|
||||
import copyIcon from 'assets/svg/copy.svg';
|
||||
import greyBadgeIcon from 'assets/svg/grey-badge.svg';
|
||||
import qrCodeIcon from 'assets/svg/qrCode.svg';
|
||||
import facebookIcon from 'assets/svg/facebook.svg';
|
||||
import twitterIcon from 'assets/svg/twitter.svg';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
bModal,
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
icons: Object.freeze({
|
||||
copy: copyIcon,
|
||||
greyBadge: greyBadgeIcon,
|
||||
qrCode: qrCodeIcon,
|
||||
facebook: facebookIcon,
|
||||
twitter: twitterIcon,
|
||||
}),
|
||||
shareUserIdShown: false,
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
createParty () {
|
||||
// group.loadingParty = true;
|
||||
//
|
||||
// if (!group.name) group.name = env.t('possessiveParty', {name: User.user.profile.name});
|
||||
// Groups.Group.create(group)
|
||||
// .then(function(response) {
|
||||
// Analytics.updateUser({'partyID': $scope.group ._id, 'partySize': 1});
|
||||
// $rootScope.hardRedirect('/#/options/groups/party');
|
||||
// });
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
@@ -8,7 +8,7 @@
|
||||
.float-right
|
||||
span.dropdown-label {{ $t('sortBy') }}
|
||||
b-dropdown(:text="$t('sort')", right=true)
|
||||
b-dropdown-item(v-for='sortOption in sortOptions', @click='sort(sortOption.value)') {{sortOption.text}}
|
||||
b-dropdown-item(v-for='sortOption in sortOptions', :key="sortOption.value", @click='sort(sortOption.value)') {{sortOption.text}}
|
||||
.col-md-12
|
||||
public-guild-item(v-for="guild in filteredGuilds", :key='guild._id', :guild="guild", :display-leave='true')
|
||||
mugen-scroll(
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
<template lang="pug">
|
||||
b-modal#guild-form(:title="title", :hide-footer="true")
|
||||
b-modal#guild-form(:title="title", :hide-footer="true", size='lg')
|
||||
form(@submit.stop.prevent="submit")
|
||||
.form-group
|
||||
label
|
||||
strong(v-once) {{$t('name')}}*
|
||||
b-form-input(type="text", placeholder="$t('newGuildPlaceHolder')", v-model="newGuild.name")
|
||||
b-form-input(type="text", :placeholder="$t('newGuildPlaceHolder')", v-model="newGuild.name")
|
||||
|
||||
.form-group(v-if='newGuild.id')
|
||||
label
|
||||
@@ -20,7 +20,7 @@
|
||||
span.custom-control-indicator
|
||||
span.custom-control-description(v-once) {{ $t('onlyLeaderCreatesChallenges') }}
|
||||
b-tooltip.icon(:content="$t('privateDescription')")
|
||||
img(src='~assets/guilds/information.svg')
|
||||
.svg-icon(v-html='icons.information')
|
||||
|
||||
br
|
||||
label.custom-control.custom-checkbox
|
||||
@@ -29,15 +29,15 @@
|
||||
span.custom-control-description(v-once) {{ $t('guildLeaderCantBeMessaged') }}
|
||||
|
||||
br
|
||||
label.custom-control.custom-checkbox
|
||||
label.custom-control.custom-checkbox(v-if='!creatingParty')
|
||||
input.custom-control-input(type="checkbox", v-model="newGuild.privateGuild")
|
||||
span.custom-control-indicator
|
||||
span.custom-control-description(v-once) {{ $t('privateGuild') }}
|
||||
b-tooltip.icon(:content="$t('privateDescription')")
|
||||
img(src='~assets/guilds/information.svg')
|
||||
.svg-icon(v-html='icons.information')
|
||||
|
||||
br
|
||||
label.custom-control.custom-checkbox
|
||||
label.custom-control.custom-checkbox(v-if='!creatingParty')
|
||||
input.custom-control-input(type="checkbox", v-model="newGuild.allowGuildInvationsFromNonMembers")
|
||||
span.custom-control-indicator
|
||||
span.custom-control-description(v-once) {{ $t('allowGuildInvationsFromNonMembers') }}
|
||||
@@ -46,14 +46,18 @@
|
||||
label
|
||||
strong(v-once) {{$t('description')}}*
|
||||
div.description-count {{charactersRemaining}} {{ $t('charactersRemaining') }}
|
||||
b-form-input(type="text", textarea :placeholder="$t('guildDescriptionPlaceHolder')", v-model="newGuild.description")
|
||||
b-form-input(type="text", textarea :placeholder="creatingParty ? $t('partyDescriptionPlaceHolder') : $t('guildDescriptionPlaceHolder')", v-model="newGuild.description")
|
||||
|
||||
.form-group(v-if='newGuild.id')
|
||||
.form-group(v-if='newGuild.id && !creatingParty')
|
||||
label
|
||||
strong(v-once) {{$t('guildInformation')}}*
|
||||
b-form-input(type="text", textarea :placeholder="$t('guildInformationPlaceHolder')", v-model="newGuild.guildInformation")
|
||||
b-form-input(type="text", textarea, :placeholder="$t('guildInformationPlaceHolder')", v-model="newGuild.guildInformation")
|
||||
|
||||
.form-group(style='position: relative;')
|
||||
.form-group(v-if='creatingParty && !newGuild.id')
|
||||
span
|
||||
toggleSwitch(:label="$t('inviteMembersNow')", v-model='inviteMembers')
|
||||
|
||||
.form-group(style='position: relative;', v-if='!creatingParty')
|
||||
label
|
||||
strong(v-once) {{$t('categories')}}*
|
||||
div.category-wrap(@click.prevent="toggleCategorySelect")
|
||||
@@ -70,22 +74,35 @@
|
||||
span.custom-control-description(v-once) {{ $t(group.label) }}
|
||||
button.btn.btn-primary(@click.prevent="toggleCategorySelect") {{$t('close')}}
|
||||
|
||||
.form-group(v-if='inviteMembers && !newGuild.id')
|
||||
label
|
||||
strong(v-once) Invite via Email or User ID
|
||||
p Invite users via a valid email or 36-digit User ID. If an email isn’t registered yet, we’ll invite them to join.
|
||||
|
||||
div
|
||||
div(v-for='(member, index) in membersToInvite')
|
||||
input(type='text', v-model='member.value')
|
||||
button(@click.prevent='removeMemberToInvite(index)') Remove
|
||||
div
|
||||
input(type='text', placeholder='Email address or User ID', v-model='newMemberToInvite.value')
|
||||
button(@click.prevent='addMemberToInvite()') Add
|
||||
|
||||
.form-group.text-center
|
||||
div.item-with-icon
|
||||
img(src="~assets/guilds/green-gem.svg")
|
||||
div.item-with-icon(v-if='!creatingParty')
|
||||
.svg-icon(v-html="icons.gem")
|
||||
span.count 4
|
||||
button.btn.btn-primary.btn-md(v-if='!newGuild.id', :disabled='!newGuild.name || !newGuild.description') {{ $t('createGuild') }}
|
||||
button.btn.btn-primary.btn-md(v-if='newGuild.id', :disabled='!newGuild.name || !newGuild.description') {{ $t('updateGuild') }}
|
||||
.gem-description(v-once) {{ $t('guildGemCostInfo') }}
|
||||
button.btn.btn-primary.btn-md(v-if='!newGuild.id', :disabled='!newGuild.name || !newGuild.description') {{ creatingParty ? $t('createParty') : $t('createGuild') }}
|
||||
button.btn.btn-primary.btn-md(v-if='newGuild.id', :disabled='!newGuild.name || !newGuild.description') {{ creatingParty ? $t('updateParty') : $t('updateGuild') }}
|
||||
.gem-description(v-once, v-if='!creatingParty') {{ $t('guildGemCostInfo') }}
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import '~client/assets/scss/colors.scss';
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import '~client/assets/scss/colors.scss';
|
||||
|
||||
textarea {
|
||||
height: 150px;
|
||||
}
|
||||
|
||||
|
||||
.description-count, .gem-description {
|
||||
font-size: 12px;
|
||||
line-height: 1.33;
|
||||
@@ -101,31 +118,6 @@
|
||||
margin-top: 1em;
|
||||
}
|
||||
|
||||
.category-box {
|
||||
padding: 1em;
|
||||
max-width: 400px;
|
||||
position: absolute;
|
||||
top: -480px;
|
||||
padding: 2em;
|
||||
border-radius: 2px;
|
||||
background-color: $white;
|
||||
box-shadow: 0 2px 2px 0 rgba($black, 0.15), 0 1px 4px 0 rgba($black, 0.1);
|
||||
}
|
||||
|
||||
.category-label {
|
||||
min-width: 100px;
|
||||
border-radius: 100px;
|
||||
background-color: $gray-600;
|
||||
padding: .5em;
|
||||
display: inline-block;
|
||||
margin-right: .5em;
|
||||
font-size: 12px;
|
||||
font-weight: 500;
|
||||
line-height: 1.33;
|
||||
text-align: center;
|
||||
color: $gray-300;
|
||||
}
|
||||
|
||||
.item-with-icon {
|
||||
display: inline-block;
|
||||
|
||||
@@ -146,21 +138,6 @@
|
||||
margin-top: 1em;
|
||||
}
|
||||
|
||||
.category-select {
|
||||
border-radius: 2px;
|
||||
background-color: $white;
|
||||
box-shadow: 0 2px 2px 0 rgba($black, 0.16), 0 1px 4px 0 rgba($black, 0.12);
|
||||
padding: 1em;
|
||||
}
|
||||
|
||||
.category-select:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.category-wrap {
|
||||
margin-top: .5em;
|
||||
}
|
||||
|
||||
.icon {
|
||||
margin-left: .5em;
|
||||
display: inline-block;
|
||||
@@ -175,6 +152,10 @@ import bFormCheckbox from 'bootstrap-vue/lib/components/form-checkbox';
|
||||
import bFormSelect from 'bootstrap-vue/lib/components/form-select';
|
||||
import bTooltip from 'bootstrap-vue/lib/components/tooltip';
|
||||
|
||||
import toggleSwitch from 'client/components/ui/toggleSwitch';
|
||||
import gemIcon from 'assets/svg/gem.svg';
|
||||
import informationIcon from 'assets/svg/information.svg';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
bModal,
|
||||
@@ -183,6 +164,7 @@ export default {
|
||||
bFormCheckbox,
|
||||
bFormSelect,
|
||||
bTooltip,
|
||||
toggleSwitch,
|
||||
},
|
||||
data () {
|
||||
let data = {
|
||||
@@ -248,6 +230,13 @@ export default {
|
||||
],
|
||||
showCategorySelect: false,
|
||||
members: ['one', 'two'],
|
||||
creatingParty: true,
|
||||
inviteMembers: false,
|
||||
newMemberToInvite: {
|
||||
value: '',
|
||||
type: '',
|
||||
},
|
||||
membersToInvite: [],
|
||||
};
|
||||
|
||||
let hashedCategories = {};
|
||||
@@ -256,6 +245,11 @@ export default {
|
||||
});
|
||||
data.categoriesHashByKey = hashedCategories;
|
||||
|
||||
data.icons = Object.freeze({
|
||||
gem: gemIcon,
|
||||
information: informationIcon,
|
||||
});
|
||||
|
||||
return data;
|
||||
},
|
||||
mounted () {
|
||||
@@ -274,11 +268,23 @@ export default {
|
||||
return 500 - this.newGuild.description.length;
|
||||
},
|
||||
title () {
|
||||
if (this.creatingParty) return this.$t('createParty');
|
||||
if (!this.newGuild.id) return this.$t('createGuild');
|
||||
return this.$t('updateGuild');
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
addMemberToInvite () {
|
||||
// @TODO: determine type
|
||||
this.membersToInvite.push(this.newMemberToInvite);
|
||||
this.newMemberToInvite = {
|
||||
value: '',
|
||||
type: '',
|
||||
};
|
||||
},
|
||||
removeMemberToInvite (index) {
|
||||
this.membersToInvite.splice(index, 1);
|
||||
},
|
||||
toggleCategorySelect () {
|
||||
this.showCategorySelect = !this.showCategorySelect;
|
||||
},
|
||||
@@ -303,7 +309,7 @@ export default {
|
||||
}
|
||||
|
||||
// @TODO: Add proper notifications
|
||||
if (!confirm(this.$t('confirmGuild'))) return;
|
||||
if (!this.newGuild.id && !confirm(this.$t('confirmGuild'))) return;
|
||||
|
||||
if (!this.newGuild.privateGuild) {
|
||||
this.newGuild.privacy = 'public';
|
||||
@@ -334,6 +340,8 @@ export default {
|
||||
privateGuild: true,
|
||||
allowGuildInvationsFromNonMembers: true,
|
||||
};
|
||||
|
||||
this.$root.$emit('hide::modal', 'guild-form');
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
@@ -1,30 +1,26 @@
|
||||
<template lang="pug">
|
||||
// TODO this is necessary until we have a way to wait for data to be loaded from the server
|
||||
.row(v-if="guild")
|
||||
.row(v-if="group")
|
||||
group-form-modal
|
||||
.clearfix.col-8
|
||||
.row
|
||||
.col-6.title-details
|
||||
h1 {{group.name}}
|
||||
strong.float-left(v-once) {{$t('groupLeader')}}
|
||||
span.float-left(v-once, v-if='group.leader.profile') : {{group.leader.profile.name}}
|
||||
.col-6
|
||||
.float-left
|
||||
h2 {{guild.name}}
|
||||
strong.float-left(v-once) {{$t('groupLeader')}}
|
||||
span.float-left : {{guild.leader.profile.name}}
|
||||
.col-6
|
||||
.float-right
|
||||
.row.icon-row
|
||||
.col-6
|
||||
img.icon.shield(src="~assets/guilds/gold-guild-badge.svg")
|
||||
span.number {{guild.memberCount}}
|
||||
div(v-once) {{ $t('guildMembers') }}
|
||||
.col-6
|
||||
.item-with-icon
|
||||
img.icon.gem(src="~assets/header/png/gem@3x.png")
|
||||
span.number {{guild.memberCount}}
|
||||
div(v-once) {{ $t('guildBank') }}
|
||||
.row.icon-row
|
||||
.col-4(v-bind:class="{ 'offset-8': isParty }")
|
||||
members-modal(:group='group', v-if='isMember')
|
||||
.col-6(v-if='!isParty')
|
||||
.item-with-icon
|
||||
.svg-icon.gem(v-html="icons.gem")
|
||||
span.number {{group.memberCount}}
|
||||
div(v-once) {{ $t('guildBank') }}
|
||||
.row.chat-row
|
||||
.col-12
|
||||
h3(v-once) {{ $t('chat') }}
|
||||
|
||||
textarea(placeholder="$('chatPlaceHolder')")
|
||||
textarea(:placeholder="$t('chatPlaceHolder')")
|
||||
button.btn.btn-secondary.send-chat.float-right(v-once) {{ $t('send') }}
|
||||
|
||||
.hr
|
||||
@@ -32,9 +28,9 @@
|
||||
|
||||
.row
|
||||
.col-md-2
|
||||
img.icon(src="~assets/chat/like.svg")
|
||||
.svg-icon(v-html="icons.like")
|
||||
.col-md-10
|
||||
.card(v-for="msg in guild.chat", :key="msg.id")
|
||||
.card(v-for="msg in group.chat", :key="msg.id")
|
||||
.card-block
|
||||
h3.leader Character name
|
||||
span 2 hours ago
|
||||
@@ -44,66 +40,160 @@
|
||||
.text {{msg.text}}
|
||||
hr
|
||||
span.action(v-once)
|
||||
img.icon(src="~assets/chat/like.svg")
|
||||
.svg-icon(v-html="icons.like")
|
||||
| {{$t('like')}}
|
||||
span.action(v-once)
|
||||
img.icon(src="~assets/chat/copy.svg")
|
||||
.svg-icon(v-html="icons.copy")
|
||||
| {{$t('copyAsTodo')}}
|
||||
span.action(v-once)
|
||||
img.icon(src="~assets/chat/report.svg")
|
||||
.svg-icon(v-html="icons.report")
|
||||
| {{$t('report')}}
|
||||
span.action(v-once)
|
||||
img.icon(src="~assets/chat/delete.svg")
|
||||
.svg-icon(v-html="icons.delete")
|
||||
| {{$t('delete')}}
|
||||
span.action.float-right
|
||||
img.icon(src="~assets/chat/liked.svg")
|
||||
.svg-icon(v-html="icons.liked")
|
||||
| +3
|
||||
|
||||
.col-md-4.sidebar
|
||||
.guild-background.row
|
||||
.col-6
|
||||
p Image here
|
||||
p(v-if='!isParty') Image here
|
||||
.col-6
|
||||
members-modal(:group='guild')
|
||||
br
|
||||
button.btn.btn-primary(v-once) {{$t('joinGuild')}}
|
||||
br
|
||||
button.btn.float-left(:class="[isMember ? 'btn-danger' : 'btn-success']") {{ isMember ? $t('leave') : $t('join') }}
|
||||
br
|
||||
button.btn.btn-primary(v-once) {{$t('inviteToGuild')}}
|
||||
br
|
||||
button.btn.btn-primary(v-once) {{$t('messageGuildLeader')}}
|
||||
br
|
||||
button.btn.btn-primary(v-once) {{$t('donateGems')}}
|
||||
br
|
||||
button.btn.btn-primary(b-btn, @click="updateGuild", v-once) {{ $t('updateGuild') }}
|
||||
div
|
||||
h3(v-once) {{ $t('description') }}
|
||||
p(v-once) {{ guild.description }}
|
||||
p Life hacks are tricks, shortcuts, or methods that help increase productivity, efficiency, health, and so on. Generally, they get you to a better state of life. Life hacking is the process of utilizing and implementing these secrets. And, in this guild, we want to help everyone discover these improved ways of doing things.
|
||||
div
|
||||
h3(v-once) {{$t('guildInformation')}}
|
||||
h4 Welcome
|
||||
p Below are some resources that some members might find useful. Consider checking them out before posting any questions, as they just might help answer some of them! Feel free to share your life hacks in the guild chat, or ask any questions that you might have. Please peruse at your leisure, and remember: this guild is meant to help guide you in the right direction. Only you will know what works best for you.
|
||||
div
|
||||
h3 Challenges
|
||||
.card
|
||||
h4 Challenge
|
||||
.row
|
||||
.col-8
|
||||
p Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla scelerisque ultrices libero.
|
||||
.col-4
|
||||
.row
|
||||
.col-md-12
|
||||
span Tag
|
||||
span 100
|
||||
.button-container
|
||||
button.btn.btn-success(class='btn-success', v-if='isLeader') {{ $t('upgrade') }}
|
||||
.button-container
|
||||
button.btn.btn-primary(b-btn, @click="updateGuild", v-once, v-if='isLeader') {{ $t('edit') }}
|
||||
.button-container
|
||||
button.btn.btn-success(class='btn-success', v-if='!isMember') {{ $t('join') }}
|
||||
.button-container
|
||||
button.btn.btn-primary(v-once) {{$t('invite')}}
|
||||
.button-container
|
||||
button.btn.btn-primary(v-once, v-if='!isLeader') {{$t('messageGuildLeader')}}
|
||||
.button-container
|
||||
button.btn.btn-primary(v-once, v-if='isMember && !isParty') {{$t('donateGems')}}
|
||||
|
||||
.section-header
|
||||
.row
|
||||
.col-10
|
||||
h3(v-once) {{ $t('questDetailsTitle') }}
|
||||
.col-2
|
||||
.toggle-up(@click="sections.quest = !sections.quest", v-if="sections.quest")
|
||||
.svg-icon(v-html="icons.upIcon")
|
||||
.toggle-down(@click="sections.quest = !sections.quest", v-if="!sections.quest")
|
||||
.svg-icon(v-html="icons.downIcon")
|
||||
.section(v-if="sections.quest")
|
||||
.row.no-quest-section(v-if='isParty && !onPendingQuest && !onActiveQuest')
|
||||
.col-12.text-center
|
||||
.svg-icon(v-html="icons.questIcon")
|
||||
h4(v-once) {{ $t('yourNotOnQuest') }}
|
||||
p(v-once) {{ $t('questDescription') }}
|
||||
button.btn.btn-secondary(v-once, @click="openStartQuestModal()") {{ $t('startAQuest') }}
|
||||
owned-quests-modal(:group='this.group')
|
||||
.row.quest-active-section(v-if='isParty && onPendingQuest && !onActiveQuest')
|
||||
h2 Pending quest
|
||||
button.btn.btn-secondary(v-once, @click="questForceStart()") {{ $t('begin') }}
|
||||
button.btn.btn-secondary(v-once, @click="questCancel()") {{ $t('cancel') }}
|
||||
.row.quest-active-section(v-if='isParty && !onPendingQuest && onActiveQuest')
|
||||
.col-12.text-center
|
||||
.quest-boss(:class="'quest_' + questData.key")
|
||||
h3(v-once) {{ questData.text() }}
|
||||
.quest-box.svg-icon(v-html="icons.questBackground")
|
||||
.collect-info(v-if='questData.collect')
|
||||
.row(v-for='(value, key) in questData.collect')
|
||||
.col-2
|
||||
div(:class="'quest_' + questData.key + '_' + key")
|
||||
.col-10
|
||||
strong {{value.text()}}
|
||||
.collect-progress-bar
|
||||
strong {{group.quest.progress.collect[key]}} / {{value.count}}
|
||||
.boss-info(v-if='questData.boss')
|
||||
.row
|
||||
.col-6
|
||||
h4.float-left(v-once) {{ questData.boss.name() }}
|
||||
.col-6
|
||||
span.float-right(v-once) {{ $t('participants') }}
|
||||
.row
|
||||
.col-12
|
||||
.boss-health-bar
|
||||
.row.boss-details
|
||||
.col-6
|
||||
span.float-left
|
||||
| {{group.quest.progress.hp}} / {{questData.boss.hp}}
|
||||
.col-6
|
||||
span.float-right 30 pending damage
|
||||
button.btn.btn-secondary(v-once, @click="questAbort()") {{ $t('abort') }}
|
||||
|
||||
.section-header
|
||||
.row
|
||||
.col-10
|
||||
h3(v-once) {{ $t('description') }}
|
||||
.col-2
|
||||
.toggle-up(@click="sections.description = !sections.description", v-if="sections.description")
|
||||
.svg-icon(v-html="icons.upIcon")
|
||||
.toggle-down(@click="sections.description = !sections.description", v-if="!sections.description")
|
||||
.svg-icon(v-html="icons.downIcon")
|
||||
.section(v-if="sections.description")
|
||||
p(v-once) {{ group.description }}
|
||||
p Life hacks are tricks, shortcuts, or methods that help increase productivity, efficiency, health, and so on. Generally, they get you to a better state of life. Life hacking is the process of utilizing and implementing these secrets. And, in this guild, we want to help everyone discover these improved ways of doing things.
|
||||
|
||||
.section-header
|
||||
.row
|
||||
.col-10
|
||||
h3(v-once) {{ $t('guildInformation') }}
|
||||
.col-2
|
||||
.toggle-up(@click="sections.information = !sections.information", v-if="sections.information")
|
||||
.svg-icon(v-html="icons.upIcon")
|
||||
.toggle-down(@click="sections.information = !sections.information", v-if="!sections.information")
|
||||
.svg-icon(v-html="icons.downIcon")
|
||||
.section(v-if="sections.information")
|
||||
h4 Welcome
|
||||
p Below are some resources that some members might find useful. Consider checking them out before posting any questions, as they just might help answer some of them! Feel free to share your life hacks in the guild chat, or ask any questions that you might have. Please peruse at your leisure, and remember: this guild is meant to help guide you in the right direction. Only you will know what works best for you.
|
||||
|
||||
.section-header.challenge
|
||||
.row
|
||||
.col-10.information-header
|
||||
h3(v-once)
|
||||
| {{ $t('challenges') }}
|
||||
b-tooltip.icon.tooltip-wrapper(:content="$t('privateDescription')")
|
||||
.svg-icon(v-html='icons.information')
|
||||
.col-2
|
||||
.toggle-up(@click="sections.challenges = !sections.challenges", v-if="sections.challenges")
|
||||
.svg-icon(v-html="icons.upIcon")
|
||||
.toggle-down(@click="sections.challenges = !sections.challenges", v-if="!sections.challenges")
|
||||
.svg-icon(v-html="icons.downIcon")
|
||||
.section(v-if="sections.challenges")
|
||||
.row.no-quest-section(v-if='!hasChallenges')
|
||||
.col-12.text-center
|
||||
.svg-icon(v-html="icons.challengeIcon")
|
||||
h4(v-once) {{ $t('haveNoChallenges') }}
|
||||
p(v-once) {{ $t('challengeDescription') }}
|
||||
button.btn.btn-secondary(v-once) {{ $t('createChallenge') }}
|
||||
div.text-center
|
||||
button.btn.btn-primary(class='btn-danger', v-if='isMember') {{ $t('leave') }}
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import '~client/assets/scss/colors.scss';
|
||||
|
||||
.button-container {
|
||||
margin-bottom: 1em;
|
||||
|
||||
button {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.item-with-icon {
|
||||
border-radius: 2px;
|
||||
background-color: #ffffff;
|
||||
box-shadow: 0 2px 2px 0 rgba(26, 24, 29, 0.16), 0 1px 4px 0 rgba(26, 24, 29, 0.12);
|
||||
padding: 1em;
|
||||
}
|
||||
|
||||
.sidebar {
|
||||
background-color: $gray-600;
|
||||
padding-top: 2em;
|
||||
}
|
||||
|
||||
.card {
|
||||
@@ -123,13 +213,11 @@
|
||||
|
||||
.guild-background {
|
||||
background-image: linear-gradient(to bottom, rgba($gray-600, 0), $gray-600);
|
||||
height: 300px;
|
||||
}
|
||||
|
||||
textarea {
|
||||
height: 150px;
|
||||
width: 100%;
|
||||
border-radius: 2px;
|
||||
background-color: $white;
|
||||
border: solid 1px $gray-400;
|
||||
font-size: 16px;
|
||||
@@ -139,15 +227,18 @@
|
||||
padding: .5em;
|
||||
}
|
||||
|
||||
.icon.shield, .icon.gem {
|
||||
.svg-icon.shield, .svg-icon.gem {
|
||||
width: 40px;
|
||||
margin-right: 1em;
|
||||
}
|
||||
|
||||
.title-details {
|
||||
padding-top: 1em;
|
||||
padding-left: 1em;
|
||||
}
|
||||
|
||||
.icon-row {
|
||||
width: 200px;
|
||||
margin-top: 3em;
|
||||
margin-right: 3em;
|
||||
margin-top: 1em;
|
||||
|
||||
.number {
|
||||
font-size: 22px;
|
||||
@@ -199,39 +290,190 @@
|
||||
span.action .icon {
|
||||
margin-right: .3em;
|
||||
}
|
||||
|
||||
.no-quest-section {
|
||||
padding: 2em;
|
||||
color: $gray-300;
|
||||
|
||||
h4 {
|
||||
color: $gray-300;
|
||||
}
|
||||
|
||||
p {
|
||||
margin-bottom: 2em;
|
||||
}
|
||||
|
||||
.svg-icon {
|
||||
height: 30px;
|
||||
width: 30px;
|
||||
margin-bottom: 2em;
|
||||
}
|
||||
}
|
||||
|
||||
.information-header {
|
||||
h3, .tooltip-wrapper {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.tooltip-wrapper {
|
||||
margin-left: 2.2em;
|
||||
}
|
||||
}
|
||||
|
||||
.quest-active-section {
|
||||
.quest-box {
|
||||
height: 100px;
|
||||
width: 100%;
|
||||
|
||||
svg: {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.boss-info, .collect-info {
|
||||
position: relative;
|
||||
top: -89px;
|
||||
left: 15px;
|
||||
width: 32em;
|
||||
text-align: left;
|
||||
}
|
||||
}
|
||||
|
||||
.section-header {
|
||||
border-top: 1px solid #e1e0e3;
|
||||
margin-top: 1em;
|
||||
padding-top: 1em;
|
||||
}
|
||||
|
||||
.section-header.challenge {
|
||||
border-bottom: 1px solid #e1e0e3;
|
||||
margin-bottom: 1em;
|
||||
padding-bottom: 1em;
|
||||
}
|
||||
|
||||
.toggle-up, .toggle-down {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.quest-boss {
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.boss-health-bar {
|
||||
width: 80%;
|
||||
background-color: red;
|
||||
height: 15px;
|
||||
margin-bottom: .5em;
|
||||
}
|
||||
|
||||
.collect-progress-bar {
|
||||
background-color: #24cc8f;
|
||||
height: 15px;
|
||||
width: 80%;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
import groupUtilities from 'client/mixins/groupsUtilities';
|
||||
import { mapState } from 'client/libs/store';
|
||||
import membersModal from './membersModal';
|
||||
import ownedQuestsModal from './ownedQuestsModal';
|
||||
import { TAVERN_ID } from 'common/script/constants';
|
||||
import quests from 'common/script/content/quests';
|
||||
import percent from 'common/script/libs/percent';
|
||||
import groupFormModal from './groupFormModal';
|
||||
|
||||
import bCollapse from 'bootstrap-vue/lib/components/collapse';
|
||||
import bCard from 'bootstrap-vue/lib/components/card';
|
||||
import bToggle from 'bootstrap-vue/lib/directives/toggle';
|
||||
import bTooltip from 'bootstrap-vue/lib/components/tooltip';
|
||||
|
||||
import deleteIcon from 'assets/svg/delete.svg';
|
||||
import copyIcon from 'assets/svg/copy.svg';
|
||||
import likeIcon from 'assets/svg/like.svg';
|
||||
import likedIcon from 'assets/svg/liked.svg';
|
||||
import reportIcon from 'assets/svg/report.svg';
|
||||
import gemIcon from 'assets/svg/gem.svg';
|
||||
import questIcon from 'assets/svg/quest.svg';
|
||||
import challengeIcon from 'assets/svg/challenge.svg';
|
||||
import informationIcon from 'assets/svg/information.svg';
|
||||
import questBackground from 'assets/svg/quest-background-border.svg';
|
||||
import upIcon from 'assets/svg/up.svg';
|
||||
import downIcon from 'assets/svg/down.svg';
|
||||
|
||||
export default {
|
||||
mixins: [groupUtilities],
|
||||
props: ['guildId'],
|
||||
components: {
|
||||
membersModal,
|
||||
ownedQuestsModal,
|
||||
bCollapse,
|
||||
bCard,
|
||||
bTooltip,
|
||||
groupFormModal,
|
||||
},
|
||||
directives: {
|
||||
bToggle,
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
guild: null,
|
||||
group: null,
|
||||
icons: Object.freeze({
|
||||
like: likeIcon,
|
||||
copy: copyIcon,
|
||||
report: reportIcon,
|
||||
delete: deleteIcon,
|
||||
gem: gemIcon,
|
||||
liked: likedIcon,
|
||||
questIcon,
|
||||
challengeIcon,
|
||||
information: informationIcon,
|
||||
questBackground,
|
||||
upIcon,
|
||||
downIcon,
|
||||
}),
|
||||
questData: {},
|
||||
selectedQuest: {},
|
||||
sections: {
|
||||
quest: true,
|
||||
description: true,
|
||||
information: true,
|
||||
challenges: true,
|
||||
},
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
...mapState({user: 'user.data'}),
|
||||
isParty () {
|
||||
return this.$route.path.startsWith('/party');
|
||||
},
|
||||
onPendingQuest () {
|
||||
return Boolean(this.group.quest.key) && !this.group.quest.active;
|
||||
},
|
||||
onActiveQuest () {
|
||||
return this.group.quest.active;
|
||||
},
|
||||
isLeader () {
|
||||
return this.user._id === this.group.leader._id;
|
||||
},
|
||||
isMember () {
|
||||
return this.isMemberOfGroup(this.user, this.guild);
|
||||
return this.isMemberOfGroup(this.user, this.group);
|
||||
},
|
||||
canEditQuest () {
|
||||
let isQuestLeader = this.group.quest && this.group.quest.leader === this.user._id;
|
||||
return isQuestLeader;
|
||||
},
|
||||
isMemberOfPendingQuest () {
|
||||
let userid = this.user._id;
|
||||
let group = this.guild;
|
||||
let group = this.group;
|
||||
if (!group.quest || !group.quest.members) return false;
|
||||
if (group.quest.active) return false; // quest is started, not pending
|
||||
return userid in group.quest.members && group.quest.members[userid] !== false;
|
||||
},
|
||||
isMemberOfRunningQuest () {
|
||||
let userid = this.user._id;
|
||||
let group = this.guild;
|
||||
let group = this.group;
|
||||
if (!group.quest || !group.quest.members) return false;
|
||||
if (!group.quest.active) return false; // quest is pending, not started
|
||||
return group.quest.members[userid];
|
||||
@@ -251,8 +493,28 @@ export default {
|
||||
let userIsManager = Boolean(group.managers[userId]);
|
||||
return leader || userIsManager;
|
||||
},
|
||||
hasChallenges () {
|
||||
if (!this.group.challenges) return false;
|
||||
return this.group.challenges.length === 0;
|
||||
},
|
||||
bossHpPercent () {
|
||||
return percent(this.group.quest.progress.hp, this.questData.boss.hp);
|
||||
},
|
||||
},
|
||||
created () {
|
||||
if (this.isParty) {
|
||||
this.groupId = 'party';
|
||||
// @TODO: Set up from old client. Decide what we need and what we don't
|
||||
// Check Desktop notifs
|
||||
// Mark Chat seen
|
||||
// Load members
|
||||
// Load invites
|
||||
// Load challenges
|
||||
// Load group tasks for group plan
|
||||
// Load approvals for group plan
|
||||
} else if (this.$route.path.startsWith('/guilds/tavern')) {
|
||||
this.groupId = TAVERN_ID;
|
||||
}
|
||||
this.fetchGuild();
|
||||
},
|
||||
watch: {
|
||||
@@ -261,35 +523,28 @@ export default {
|
||||
},
|
||||
methods: {
|
||||
updateGuild () {
|
||||
this.$store.state.editingGroup = this.guild;
|
||||
this.$store.state.editingGroup = this.group;
|
||||
this.$root.$emit('show::modal', 'guild-form');
|
||||
},
|
||||
async fetchGuild () {
|
||||
this.guild = await this.$store.dispatch('guilds:getGroup', {groupId: this.guildId});
|
||||
|
||||
this.guild.chat = [
|
||||
{
|
||||
text: '@CharacterName Vestibulum ultricies, lorem non bibendum consequat, nisl lacus semper nulla, hendrerit dignissim ipsum erat eu odio. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla at aliquet urna. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Nulla non est ut nisl interdum tincidunt in eu dui. Proin condimentum a.',
|
||||
},
|
||||
];
|
||||
},
|
||||
editGroup () {
|
||||
// @TODO: Open up model
|
||||
},
|
||||
save () {
|
||||
let newLeader = this.group._newLeader && this.group._newLeader._id;
|
||||
|
||||
if (newLeader) {
|
||||
this.group.leader = newLeader;
|
||||
let group = await this.$store.dispatch('guilds:getGroup', {groupId: this.groupId});
|
||||
if (this.isParty) {
|
||||
this.$store.party = group;
|
||||
this.group = this.$store.party;
|
||||
this.checkForAchievements();
|
||||
this.questData = quests.quests[this.group.quest.key];
|
||||
return;
|
||||
}
|
||||
|
||||
// Groups.Group.update(group);
|
||||
this.group = group;
|
||||
},
|
||||
deleteAllMessages () {
|
||||
if (confirm(this.$t('confirmDeleteAllMessages'))) {
|
||||
// User.clearPMs();
|
||||
}
|
||||
},
|
||||
openStartQuestModal () {
|
||||
this.$root.$emit('show::modal', 'owned-quests-modal');
|
||||
},
|
||||
// inviteOrStartParty (group) {
|
||||
// Analytics.track({'hitType':'event','eventCategory':'button','eventAction':'click','eventLabel':'Invite Friends'});
|
||||
|
||||
@@ -312,6 +567,114 @@ export default {
|
||||
// },
|
||||
// });
|
||||
// },
|
||||
checkForAchievements () {
|
||||
// Checks if user's party has reached 2 players for the first time.
|
||||
if (!this.user.achievements.partyUp && this.group.memberCount >= 2) {
|
||||
// @TODO
|
||||
// User.set({'achievements.partyUp':true});
|
||||
// Achievement.displayAchievement('partyUp');
|
||||
}
|
||||
|
||||
// Checks if user's party has reached 4 players for the first time.
|
||||
if (!this.user.achievements.partyOn && this.group.memberCount >= 4) {
|
||||
// @TODO
|
||||
// User.set({'achievements.partyOn':true});
|
||||
// Achievement.displayAchievement('partyOn');
|
||||
}
|
||||
},
|
||||
// @TODO: This should be moved to notifications component
|
||||
async join () {
|
||||
if (this.group.cancelledPlan && !confirm(this.$t('aboutToJoinCancelledGroupPlan'))) {
|
||||
return;
|
||||
}
|
||||
|
||||
await this.$store.dispatch('guilds:join', {groupId: this.group._id});
|
||||
|
||||
// @TODO: Implement
|
||||
// User.sync();
|
||||
// Analytics.updateUser({'partyID': party.id});
|
||||
// $rootScope.hardRedirect('/#/options/groups/party');
|
||||
},
|
||||
clickLeave () {
|
||||
// Analytics.track({'hitType':'event','eventCategory':'button','eventAction':'click','eventLabel':'Leave Party'});
|
||||
// @TODO: Get challenges and ask to keep or remove
|
||||
let keep = true;
|
||||
this.leave(keep);
|
||||
},
|
||||
async leave (keepTasks) {
|
||||
let keepChallenges = 'remain-in-challenges';
|
||||
await this.$store.dispatch('guilds:leave', {
|
||||
groupId: this.group._id,
|
||||
keep: keepTasks,
|
||||
keepChallenges,
|
||||
});
|
||||
|
||||
// @TODO: Implement
|
||||
// Analytics.updateUser({'partySize':null,'partyID':null});
|
||||
// User.sync().then(function () {
|
||||
// $rootScope.hardRedirect('/#/options/groups/party');
|
||||
// });
|
||||
},
|
||||
// @TODO: Move to notificatin component
|
||||
async leaveOldPartyAndJoinNewParty () {
|
||||
let newPartyName = 'where does this come from';
|
||||
if (!confirm(`Are you sure you want to delete your party and join${newPartyName}?`)) return;
|
||||
|
||||
let keepChallenges = 'remain-in-challenges';
|
||||
await this.$store.dispatch('guilds:leave', {
|
||||
groupId: this.group._id,
|
||||
keep: false,
|
||||
keepChallenges,
|
||||
});
|
||||
|
||||
await this.$store.dispatch('guilds:join', {groupId: this.group._id});
|
||||
},
|
||||
// @TODO: Move to notificatin component
|
||||
async reject () {
|
||||
await this.$store.dispatch('guilds:rejectInvite', {groupId: this.group._id});
|
||||
// User.sync();
|
||||
},
|
||||
clickStartQuest () {
|
||||
// Analytics.track({'hitType':'event','eventCategory':'button','eventAction':'click','eventLabel':'Start a Quest'});
|
||||
let hasQuests = find(this.user.items.quests, (quest) => {
|
||||
return quest > 0;
|
||||
});
|
||||
|
||||
if (hasQuests) {
|
||||
this.$root.$emit('show::modal', 'owned-quests-modal');
|
||||
return;
|
||||
}
|
||||
// $rootScope.$state.go('options.inventory.quests');
|
||||
},
|
||||
async questCancel () {
|
||||
if (!confirm(this.$t('sureCancel'))) return;
|
||||
let quest = await this.$store.dispatch('quests:sendAction', {groupId: this.group._id, action: 'quests/cancel'});
|
||||
this.group.quest = quest;
|
||||
},
|
||||
async questAbort () {
|
||||
if (!confirm(this.$t('sureAbort'))) return;
|
||||
if (!confirm(this.$t('doubleSureAbort'))) return;
|
||||
let quest = await this.$store.dispatch('quests:sendAction', {groupId: this.group._id, action: 'quests/abort'});
|
||||
this.group.quest = quest;
|
||||
},
|
||||
async questLeave () {
|
||||
if (!confirm(this.$t('sureLeave'))) return;
|
||||
let quest = await this.$store.dispatch('quests:sendAction', {groupId: this.group._id, action: 'quests/leave'});
|
||||
this.group.quest = quest;
|
||||
},
|
||||
async questAccept () {
|
||||
let quest = await this.$store.dispatch('quests:sendAction', {groupId: this.group._id, action: 'quests/accept'});
|
||||
this.group.quest = quest;
|
||||
},
|
||||
async questForceStart () {
|
||||
let quest = await this.$store.dispatch('quests:sendAction', {groupId: this.group._id, action: 'quests/force-start'});
|
||||
this.group.quest = quest;
|
||||
},
|
||||
// @TODO: Move to notificaitons component?
|
||||
async questReject () {
|
||||
let quest = await this.$store.dispatch('quests:sendAction', {groupId: this.group._id, action: 'quests/reject'});
|
||||
this.group.quest = quest;
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
@@ -1,14 +1,46 @@
|
||||
<template lang="pug">
|
||||
div
|
||||
button.btn.btn-primary(b-btn, @click="$root.$emit('show::modal','members-modal')") {{ $t('viewMembers') }}
|
||||
.item-with-icon(@click="$root.$emit('show::modal','members-modal')")
|
||||
.svg-icon.shield(v-html="icons.goldGuildBadgeIcon")
|
||||
span.number {{group.memberCount}}
|
||||
div(v-once) {{ $t('members') }}
|
||||
|
||||
b-modal#members-modal(:title="$t('createGuild')")
|
||||
ul(v-for='member in members', :key='member')
|
||||
li(@click='clickMember') {{member}}
|
||||
button(@click='removeMember(member)', v-once) {{$t('remove')}}
|
||||
button(@click='quickReply(member)', v-once) {{$t('message')}}
|
||||
button(@click='addManager(member)', v-once) {{$t('addManager')}}
|
||||
button(@click='removeManager(member)', v-once) {{$t('addManager')}}
|
||||
b-modal#members-modal(:title="$t('createGuild')", size='lg')
|
||||
.header-wrap(slot="modal-header")
|
||||
.row
|
||||
.col-6
|
||||
h1(v-once) {{$t('members')}}
|
||||
.col-6
|
||||
button(type="button" aria-label="Close" class="close")
|
||||
span(aria-hidden="true") ×
|
||||
.row
|
||||
.form-group.col-6
|
||||
input.form-control.search(type="text", :placeholder="$t('search')", v-model='searchTerm')
|
||||
.col-4.offset-2
|
||||
span.dropdown-label {{ $t('sortBy') }}
|
||||
b-dropdown(:text="$t('sort')", right=true)
|
||||
b-dropdown-item(v-for='sortOption in sortOptions', @click='sort(sortOption.value)', :key='sortOption.value') {{sortOption.text}}
|
||||
.row(v-for='member in members', :key='member', )
|
||||
.col-8.offset-1
|
||||
member-details(:member='member')
|
||||
.col-3.actions
|
||||
b-dropdown(:text="$t('sort')", right=true)
|
||||
b-dropdown-item(@click='sort(option.value)')
|
||||
.svg-icon(v-html="icons.removeIcon")
|
||||
| {{$t('removeMember')}}
|
||||
b-dropdown-item(@click='sort(option.value)')
|
||||
.svg-icon(v-html="icons.messageIcon")
|
||||
| {{$t('sendMessage')}}
|
||||
b-dropdown-item(@click='sort(option.value)')
|
||||
.svg-icon(v-html="icons.starIcon")
|
||||
| {{$t('promoteToLeader')}}
|
||||
b-dropdown-item(@click='sort(option.value)')
|
||||
.svg-icon(v-html="icons.starIcon")
|
||||
| {{$t('addManager')}}
|
||||
b-dropdown-item(@click='sort(option.value)')
|
||||
.svg-icon(v-html="icons.removeIcon")
|
||||
| {{$t('removeManager2')}}
|
||||
.row-fluid.gradient
|
||||
|
||||
b-modal#remove-member(:title="$t('confirmRemoveMember')")
|
||||
button(@click='confirmRemoveMember(member)', v-once) {{$t('remove')}}
|
||||
@@ -17,25 +49,134 @@ div
|
||||
button(@click='confirmRemoveMember(member)', v-once) {{$t('remove')}}
|
||||
</template>
|
||||
|
||||
<style lang='scss' scoped>
|
||||
header {
|
||||
background-color: #edecee;
|
||||
border-radius: 4px 4px 0 0;
|
||||
}
|
||||
|
||||
.header-wrap {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
h1 {
|
||||
color: #4f2a93;
|
||||
}
|
||||
|
||||
.actions {
|
||||
padding-top: 5em;
|
||||
|
||||
.action-icon {
|
||||
margin-right: 1em;
|
||||
}
|
||||
}
|
||||
|
||||
#members-modal_modal_body {
|
||||
padding: 0;
|
||||
|
||||
.col-8 {
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
.member-details {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.member-stats {
|
||||
width: 382px;
|
||||
height: 147px;
|
||||
}
|
||||
|
||||
.gradient {
|
||||
background-image: linear-gradient(to bottom, rgba(255, 255, 255, 0), #ffffff);
|
||||
height: 200px;
|
||||
width: 100%;
|
||||
position: absolute;
|
||||
bottom: 0px;
|
||||
}
|
||||
}
|
||||
|
||||
.item-with-icon {
|
||||
border-radius: 2px;
|
||||
background-color: #ffffff;
|
||||
box-shadow: 0 2px 2px 0 rgba(26, 24, 29, 0.16), 0 1px 4px 0 rgba(26, 24, 29, 0.12);
|
||||
padding: 1em;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.svg-icon.shield, .svg-icon.gem {
|
||||
width: 40px;
|
||||
margin-right: 1em;
|
||||
}
|
||||
|
||||
.number {
|
||||
font-size: 22px;
|
||||
font-weight: bold;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
import bModal from 'bootstrap-vue/lib/components/modal';
|
||||
import bDropdown from 'bootstrap-vue/lib/components/dropdown';
|
||||
import bDropdownItem from 'bootstrap-vue/lib/components/dropdown-item';
|
||||
|
||||
import MemberDetails from '../memberDetails';
|
||||
import removeIcon from 'assets/members/remove.svg';
|
||||
import messageIcon from 'assets/members/message.svg';
|
||||
import starIcon from 'assets/members/star.svg';
|
||||
import goldGuildBadgeIcon from 'assets/svg/gold-guild-badge.svg';
|
||||
|
||||
export default {
|
||||
props: ['group'],
|
||||
components: {
|
||||
bModal,
|
||||
bDropdown,
|
||||
bDropdownItem,
|
||||
MemberDetails,
|
||||
},
|
||||
created () {
|
||||
this.getMembers();
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
members: ['one', 'two'],
|
||||
members: [],
|
||||
memberToRemove: '',
|
||||
sortOptions: [
|
||||
{
|
||||
value: 'tier',
|
||||
text: this.$t('tier'),
|
||||
},
|
||||
{
|
||||
value: 'name',
|
||||
text: this.$t('name'),
|
||||
},
|
||||
{
|
||||
value: 'level',
|
||||
text: this.$t('level'),
|
||||
},
|
||||
{
|
||||
value: 'class',
|
||||
text: this.$t('class'),
|
||||
},
|
||||
],
|
||||
searchTerm: '',
|
||||
icons: Object.freeze({
|
||||
removeIcon,
|
||||
messageIcon,
|
||||
starIcon,
|
||||
goldGuildBadgeIcon,
|
||||
}),
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
getMembers () {
|
||||
// We should get members here via store if they are not loaded
|
||||
async getMembers () {
|
||||
let members = await this.$store.dispatch('members:getGroupMembers', {
|
||||
groupId: this.group._id,
|
||||
includeAllPublicFields: true,
|
||||
});
|
||||
this.members = members;
|
||||
},
|
||||
clickMember (uid, forceShow) {
|
||||
async clickMember (uid, forceShow) {
|
||||
let user = this.$store.state.user.data;
|
||||
|
||||
if (user._id === uid && !forceShow) {
|
||||
@@ -48,59 +189,47 @@ export default {
|
||||
return;
|
||||
}
|
||||
|
||||
// $root.$emit('show::modal','members-modal')
|
||||
// We need the member information up top here, but then we pass it down to the modal controller
|
||||
// down below. Better way of handling this?
|
||||
// Members.selectMember(uid)
|
||||
// .then(function () {
|
||||
// $rootScope.openModal('member', {controller: 'MemberModalCtrl', windowClass: 'profile-modal', size: 'lg'});
|
||||
// });
|
||||
await this.$store.dispatch('members:selectMember', {
|
||||
memberId: uid,
|
||||
});
|
||||
|
||||
this.$root.$emit('show::modal', 'members-modal');
|
||||
},
|
||||
removeMember (member) {
|
||||
async removeMember (member) {
|
||||
this.memberToRemove = member;
|
||||
this.$root.$emit('show::modal', 'remove-member');
|
||||
},
|
||||
confirmRemoveMember (confirmation) {
|
||||
async confirmRemoveMember (confirmation) {
|
||||
if (!confirmation) {
|
||||
this.memberToRemove = '';
|
||||
return;
|
||||
}
|
||||
// Groups.Group.removeMember(
|
||||
// $scope.removeMemberData.group._id,
|
||||
// $scope.removeMemberData.member._id,
|
||||
// $scope.removeMemberData.message
|
||||
// ).then(function (response) {
|
||||
// if($scope.removeMemberData.isMember){
|
||||
// _.pull($scope.removeMemberData.group.members, $scope.removeMemberData.member);
|
||||
// }else{
|
||||
// _.pull($scope.removeMemberData.group.invites, $scope.removeMemberData.member);
|
||||
// }
|
||||
//
|
||||
// $scope.removeMemberData = undefined;
|
||||
// });
|
||||
|
||||
await this.$store.dispatch('members:removeMember', {
|
||||
memberId: this.memberToRemove._id,
|
||||
groupId: this.group._id,
|
||||
message: this.removeMessage,
|
||||
});
|
||||
|
||||
this.memberToRemove = '';
|
||||
this.removeMessage = '';
|
||||
},
|
||||
quickReply (uid) {
|
||||
async quickReply (uid) {
|
||||
this.memberToReply = uid;
|
||||
this.$root.$emit('show::modal', 'private-message');
|
||||
// Members.selectMember(uid)
|
||||
// .then(function (response) {
|
||||
// $rootScope.openModal('private-message', {controller: 'MemberModalCtrl'});
|
||||
// });
|
||||
await this.$store.dispatch('members:selectMember', {
|
||||
memberId: uid,
|
||||
});
|
||||
this.$root.$emit('show::modal', 'private-message'); // MemberModalCtrl
|
||||
},
|
||||
addManager () {
|
||||
// Groups.Group.addManager(this.group._id, this.group._newManager)
|
||||
// .then(function (response) {
|
||||
// this.group._newManager = '';
|
||||
// this.group.managers = response.data.data.managers;
|
||||
// });
|
||||
async addManager (memberId) {
|
||||
await this.$store.dispatch('group:addManager', {
|
||||
memberId,
|
||||
});
|
||||
},
|
||||
removeManager (memberId) {
|
||||
this.memberToReply = memberId;
|
||||
// Groups.Group.removeManager(this.group._id, memberId)
|
||||
// .then(function (response) {
|
||||
// this.group._newManager = '';
|
||||
// this.group.managers = response.data.data.managers;
|
||||
// });
|
||||
async removeManager (memberId) {
|
||||
await this.$store.dispatch('group:removeManager', {
|
||||
memberId,
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
.col-10.no-guilds.standard-page(v-if='filteredGuilds.length === 0')
|
||||
.no-guilds-wrapper
|
||||
img(src='~assets/guilds/grey-badge.svg')
|
||||
.svg-icon(v-html='icons.greyBadge')
|
||||
h2 {{$t('noGuildsTitle')}}
|
||||
p {{$t('noGuildsParagraph1')}}
|
||||
p {{$t('noGuildsParagraph2')}}
|
||||
@@ -17,33 +17,33 @@
|
||||
.float-right
|
||||
span.dropdown-label {{ $t('sortBy') }}
|
||||
b-dropdown(:text="$t('sort')", right=true)
|
||||
b-dropdown-item(v-for='sortOption in sortOptions', @click='sort(sortOption.value)') {{sortOption.text}}
|
||||
b-dropdown-item(v-for='sortOption in sortOptions', :key="sortOption.value", @click='sort(sortOption.value)') {{sortOption.text}}
|
||||
.row
|
||||
.col-md-12
|
||||
public-guild-item(v-for="guild in filteredGuilds", :key='guild._id', :guild="guild", :display-gem-bank='true')
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import '~client/assets/scss/colors.scss';
|
||||
.sort-select {
|
||||
margin: 2em;
|
||||
@import '~client/assets/scss/colors.scss';
|
||||
.sort-select {
|
||||
margin: 2em;
|
||||
}
|
||||
|
||||
.no-guilds {
|
||||
text-align: center;
|
||||
color: $gray-200;
|
||||
margin-top: 15em;
|
||||
|
||||
p {
|
||||
font-size: 14px;
|
||||
line-height: 1.43;
|
||||
}
|
||||
|
||||
.no-guilds {
|
||||
text-align: center;
|
||||
color: $gray-200;
|
||||
margin-top: 15em;
|
||||
|
||||
p {
|
||||
font-size: 14px;
|
||||
line-height: 1.43;
|
||||
}
|
||||
|
||||
.no-guilds-wrapper {
|
||||
width: 400px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
.no-guilds-wrapper {
|
||||
width: 400px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
@@ -58,11 +58,16 @@ import bDropdownItem from 'bootstrap-vue/lib/components/dropdown-item';
|
||||
import PublicGuildItem from './publicGuildItem';
|
||||
import Sidebar from './sidebar';
|
||||
|
||||
import greyBadgeIcon from 'assets/svg/grey-badge.svg';
|
||||
|
||||
export default {
|
||||
mixins: [groupUtilities],
|
||||
components: { PublicGuildItem, MugenScroll, Sidebar, bFormSelect, bDropdown, bDropdownItem },
|
||||
data () {
|
||||
return {
|
||||
icons: Object.freeze({
|
||||
greyBadge: greyBadgeIcon,
|
||||
}),
|
||||
loading: false,
|
||||
search: '',
|
||||
filters: {},
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
<template lang="pug">
|
||||
div
|
||||
b-modal#owned-quests-modal(title="Which quest do you want to start?", size='md', hide-footer=true)
|
||||
.row.content
|
||||
.quest(v-for='(value, key, index) in user.items.quests', :class="'inventory_quest_scroll_' + key", @click='selectQuest(key)')
|
||||
button.btn.btn-primary(@click='confirm()') Confirm
|
||||
start-quest-modal(:group='group', :selectedQuest='selectedQuest')
|
||||
</template>
|
||||
|
||||
<style lang='scss' scoped>
|
||||
@import '~client/assets/scss/colors.scss';
|
||||
|
||||
.content {
|
||||
padding: 2em;
|
||||
|
||||
.quest {
|
||||
margin-right: 1em;
|
||||
margin-bottom: 1em;
|
||||
display: inline-block;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
import { mapState } from 'client/libs/store';
|
||||
import bModal from 'bootstrap-vue/lib/components/modal';
|
||||
|
||||
import startQuestModal from './startQuestModal';
|
||||
|
||||
export default {
|
||||
props: ['group'],
|
||||
components: {
|
||||
bModal,
|
||||
startQuestModal,
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
selectedQuest: {},
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
...mapState({user: 'user.data'}),
|
||||
},
|
||||
methods: {
|
||||
selectQuest (quest) {
|
||||
this.selectedQuest = quest;
|
||||
},
|
||||
confirm () {
|
||||
this.$root.$emit('show::modal', 'start-quest-modal');
|
||||
this.$root.$emit('hide::modal', 'owned-quests-modal');
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
@@ -3,7 +3,7 @@
|
||||
.card-block
|
||||
.row
|
||||
.col-md-2
|
||||
img.icon.shield(src="~assets/guilds/gold-guild-badge.svg")
|
||||
.svg-icon.shield(v-html="icons.goldGuildBadge")
|
||||
.member-count {{guild.memberCount}}
|
||||
.col-md-10
|
||||
.row
|
||||
@@ -15,7 +15,7 @@
|
||||
button.btn.btn-danger(v-if='isMember && displayLeave' @click='leave()', v-once) {{ $t('leave') }}
|
||||
button.btn.btn-success(v-if='!isMember' @click='join()', v-once) {{ $t('join') }}
|
||||
div.item-with-icon(v-if='displayGemBank')
|
||||
img(src="~assets/guilds/green-gem.svg")
|
||||
.svg-icon(v-html="icons.gem")
|
||||
span.count {{ guild.balance }}
|
||||
div.guild-bank(v-if='displayGemBank', v-once) {{$t('guildBank')}}
|
||||
.row
|
||||
@@ -26,89 +26,70 @@
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import '~client/assets/scss/colors.scss';
|
||||
@import '~client/assets/scss/colors.scss';
|
||||
|
||||
.card {
|
||||
height: 260px;
|
||||
border-radius: 4px;
|
||||
background-color: $white;
|
||||
box-shadow: 0 2px 2px 0 rgba($black, 0.15), 0 1px 4px 0 rgba($black, 0.1);
|
||||
margin-bottom: 1rem;
|
||||
.card {
|
||||
height: 260px;
|
||||
border-radius: 4px;
|
||||
background-color: $white;
|
||||
box-shadow: 0 2px 2px 0 rgba($black, 0.15), 0 1px 4px 0 rgba($black, 0.1);
|
||||
margin-bottom: 1rem;
|
||||
|
||||
.category-label {
|
||||
min-width: 100px;
|
||||
border-radius: 100px;
|
||||
background-color: $gray-600;
|
||||
padding: .5em;
|
||||
display: inline-block;
|
||||
margin-right: .5em;
|
||||
font-size: 12px;
|
||||
font-weight: 500;
|
||||
line-height: 1.33;
|
||||
text-align: center;
|
||||
color: $gray-300;
|
||||
.recommend-text {
|
||||
font-size: 12px;
|
||||
font-style: italic;
|
||||
line-height: 2;
|
||||
color: $gray-300;
|
||||
}
|
||||
|
||||
.cta-container {
|
||||
margin: 0 auto;
|
||||
margin-top: 4em;
|
||||
}
|
||||
|
||||
.item-with-icon {
|
||||
.svg-icon {
|
||||
height: 37px;
|
||||
}
|
||||
|
||||
.recommend-text {
|
||||
font-size: 12px;
|
||||
font-style: italic;
|
||||
line-height: 2;
|
||||
color: $gray-300;
|
||||
}
|
||||
|
||||
.cta-container {
|
||||
margin: 0 auto;
|
||||
margin-top: 4em;
|
||||
}
|
||||
|
||||
.shield {
|
||||
width: 70px;
|
||||
height: 76px;
|
||||
margin: auto;
|
||||
margin: 4em auto;
|
||||
display: block;
|
||||
background-size: cover;
|
||||
width: 100%;
|
||||
height: 100px;
|
||||
}
|
||||
|
||||
.item-with-icon {
|
||||
img {
|
||||
height: 37px;
|
||||
}
|
||||
|
||||
.count {
|
||||
font-size: 20px;
|
||||
height: 37px;
|
||||
width: 37px;
|
||||
margin-left: .2em;
|
||||
}
|
||||
}
|
||||
|
||||
.guild-bank {
|
||||
font-size: 12px;
|
||||
line-height: 1.33;
|
||||
color: $gray-300;
|
||||
}
|
||||
|
||||
.member-count {
|
||||
position: relative;
|
||||
top: -3.6em;
|
||||
left: -.1em;
|
||||
font-size: 28px;
|
||||
font-weight: bold;
|
||||
font-family: 'Roboto Condensed';
|
||||
line-height: 1.2;
|
||||
text-align: center;
|
||||
color: #b36213;
|
||||
.count {
|
||||
font-size: 20px;
|
||||
height: 37px;
|
||||
width: 37px;
|
||||
margin-left: .2em;
|
||||
}
|
||||
}
|
||||
|
||||
.shield {
|
||||
width: 70px;
|
||||
}
|
||||
|
||||
.guild-bank {
|
||||
font-size: 12px;
|
||||
line-height: 1.33;
|
||||
color: $gray-300;
|
||||
}
|
||||
|
||||
.member-count {
|
||||
position: relative;
|
||||
top: -3.6em;
|
||||
left: -.1em;
|
||||
font-size: 28px;
|
||||
font-weight: bold;
|
||||
font-family: 'Roboto Condensed';
|
||||
line-height: 1.2;
|
||||
text-align: center;
|
||||
color: #b36213;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
import { mapState } from 'client/libs/store';
|
||||
import groupUtilities from 'client/mixins/groupsUtilities';
|
||||
import findIndex from 'lodash/findIndex';
|
||||
import gemIcon from 'assets/svg/gem.svg';
|
||||
import goldGuildBadgeIcon from 'assets/svg/gold-guild-badge.svg';
|
||||
|
||||
export default {
|
||||
mixins: [groupUtilities],
|
||||
@@ -119,6 +100,14 @@ export default {
|
||||
return this.isMemberOfGroup(this.user, this.guild);
|
||||
},
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
icons: Object.freeze({
|
||||
gem: gemIcon,
|
||||
goldGuildBadge: goldGuildBadgeIcon,
|
||||
}),
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
async join () {
|
||||
// @TODO: This needs to be in the notifications where users will now accept invites
|
||||
|
||||
@@ -0,0 +1,156 @@
|
||||
<template lang="pug">
|
||||
b-modal#start-quest-modal(title="Empty", size='md', hide-footer=true, v-if='questData')
|
||||
.quest-image(:class="'quest_' + questData.key")
|
||||
h2 {{questData.text()}}
|
||||
//- span by: Keith Holliday @TODO: Add author
|
||||
p {{questData.notes()}}
|
||||
div.quest-details
|
||||
div(v-if=' questData.collect')
|
||||
Strong {{$t('collect')}}:
|
||||
span(v-for="(value, key, index) in questData.collect")
|
||||
| {{$t('collectionItems', { number: questData.collect[key].count, items: questData.collect[key].text() })}}
|
||||
div
|
||||
Strong {{$t('collect')}}:
|
||||
span
|
||||
.svg-icon(v-html="icons.difficultyStarIcon")
|
||||
div
|
||||
button.btn.btn-primary(@click='questInit()') {{$t('inviteToPartyOrQuest')}}
|
||||
div
|
||||
p {{$t('inviteInformation')}}
|
||||
.side-panel
|
||||
h4.text-center {{$t('rewards')}}
|
||||
.box
|
||||
.svg-icon.rewards-icon(v-html="icons.starIcon")
|
||||
strong {{questData.drop.exp}} {{$t('experience')}}
|
||||
.box
|
||||
.svg-icon.rewards-icon(v-html="icons.goldIcon")
|
||||
strong {{questData.drop.gp}} {{$t('gold')}}
|
||||
h4.text-center(v-if='questData.drop.items') {{$t('questOwnerRewards')}}
|
||||
.box(v-for='item in questData.drop.items')
|
||||
.rewards-icon(v-if='item.type === "quest"', :class="'quest_' + item.key")
|
||||
.drop-rewards-icon(v-if='item.type === "gear"', :class="'shop_' + item.key")
|
||||
strong.quest-reward-text {{item.text()}}
|
||||
</template>
|
||||
|
||||
<style lang='scss' scoped>
|
||||
@import '~client/assets/scss/colors.scss';
|
||||
|
||||
header {
|
||||
background-color: $white !important;
|
||||
border: none !important;
|
||||
|
||||
h5 {
|
||||
text-indent: -99999px;
|
||||
}
|
||||
}
|
||||
|
||||
.quest-image {
|
||||
margin: 0 auto;
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
.quest-details {
|
||||
margin: 0 auto;
|
||||
text-align: left;
|
||||
width: 180px;
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
margin: 1em 0;
|
||||
}
|
||||
|
||||
.side-panel {
|
||||
background: #edecee;
|
||||
position: absolute;
|
||||
height: 460px;
|
||||
width: 320px;
|
||||
top: -1.8em;
|
||||
left: 35em;
|
||||
z-index: -1;
|
||||
padding-top: 1em;
|
||||
border-radius: 4px;
|
||||
|
||||
.drop-rewards-icon {
|
||||
width: 35px;
|
||||
height: 35px;
|
||||
float: left;
|
||||
}
|
||||
|
||||
.rewards-icon {
|
||||
float: left;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
|
||||
svg {
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
}
|
||||
}
|
||||
|
||||
.quest-reward-text {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.box {
|
||||
width: 220px;
|
||||
height: 64px;
|
||||
border-radius: 2px;
|
||||
background-color: #ffffff;
|
||||
margin: 0 auto;
|
||||
margin-bottom: 1em;
|
||||
padding: 1em;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
import bModal from 'bootstrap-vue/lib/components/modal';
|
||||
|
||||
import quests from 'common/script/content/quests';
|
||||
|
||||
import copyIcon from 'assets/svg/copy.svg';
|
||||
import greyBadgeIcon from 'assets/svg/grey-badge.svg';
|
||||
import qrCodeIcon from 'assets/svg/qrCode.svg';
|
||||
import facebookIcon from 'assets/svg/facebook.svg';
|
||||
import twitterIcon from 'assets/svg/twitter.svg';
|
||||
import starIcon from 'assets/svg/star.svg';
|
||||
import goldIcon from 'assets/svg/gold.svg';
|
||||
import difficultyStarIcon from 'assets/svg/difficulty-star.svg';
|
||||
|
||||
export default {
|
||||
props: ['group', 'selectedQuest'],
|
||||
components: {
|
||||
bModal,
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
icons: Object.freeze({
|
||||
copy: copyIcon,
|
||||
greyBadge: greyBadgeIcon,
|
||||
qrCode: qrCodeIcon,
|
||||
facebook: facebookIcon,
|
||||
twitter: twitterIcon,
|
||||
starIcon,
|
||||
goldIcon,
|
||||
difficultyStarIcon,
|
||||
}),
|
||||
shareUserIdShown: false,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
questData () {
|
||||
return quests.quests[this.selectedQuest];
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
async questInit () {
|
||||
let key = this.selectedQuest;
|
||||
// Analytics.updateUser({'partyID': party._id, 'partySize': party.memberCount});
|
||||
let response = await this.$store.dispatch('guilds:inviteToQuest', {groupId: this.group._id, key});
|
||||
let quest = response.data.data;
|
||||
this.$store.party.quest = quest;
|
||||
this.$root.$emit('hide::modal', 'start-quest-modal');
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
@@ -2,8 +2,7 @@
|
||||
.drawer-container
|
||||
.drawer-title(@click="open = !open")
|
||||
| {{title}}
|
||||
img.drawer-toggle-icon(src="~assets/drawer/minimize.svg", v-if="open")
|
||||
img.drawer-toggle-icon.closed(src="~assets/drawer/expand.svg", v-else)
|
||||
.drawer-toggle-icon.svg-icon(v-html="open ? icons.minimize : icons.expand", :class="{ closed: !open }")
|
||||
transition(name="slide-up", @afterLeave="adjustPagePadding", @afterEnter="adjustPagePadding")
|
||||
.drawer-content(v-show="open")
|
||||
slot(name="drawer-header")
|
||||
@@ -36,10 +35,10 @@
|
||||
|
||||
.drawer-toggle-icon {
|
||||
float: right;
|
||||
margin: 10px;
|
||||
margin-right: 16px;
|
||||
|
||||
&.closed {
|
||||
margin-top: 5px;
|
||||
margin-top: 3px;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -92,8 +91,7 @@
|
||||
}
|
||||
|
||||
.drawer-slider {
|
||||
padding: 12px 0 0 24px;
|
||||
margin-left: -24px;
|
||||
padding: 12px 0 0 0;
|
||||
overflow-x: auto;
|
||||
overflow-y: hidden;
|
||||
white-space: nowrap;
|
||||
@@ -128,6 +126,9 @@
|
||||
</style>
|
||||
|
||||
<script>
|
||||
import expandIcon from 'assets/svg/expand.svg';
|
||||
import minimizeIcon from 'assets/svg/minimize.svg';
|
||||
|
||||
export default {
|
||||
props: {
|
||||
title: {
|
||||
@@ -141,6 +142,10 @@ export default {
|
||||
data () {
|
||||
return {
|
||||
open: true,
|
||||
icons: Object.freeze({
|
||||
expand: expandIcon,
|
||||
minimize: minimizeIcon,
|
||||
}),
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
|
||||
@@ -112,7 +112,7 @@
|
||||
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: group.label }) : $t('showAllGearItems', { type: group.label, items: items[group.key].length }) }}
|
||||
) {{ viewOptions[group.key].open ? $t('showLessItems', { type: group.label }) : $t('showAllItems', { type: group.label, items: items[group.key].length }) }}
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
@@ -16,13 +16,16 @@ b-popover(
|
||||
.item-wrapper
|
||||
.item
|
||||
slot(name="itemBadge", :item="item")
|
||||
span.item-content(:class="itemContentClass")
|
||||
span.item-content(
|
||||
:class="itemContentClass",
|
||||
:draggable="draggable",
|
||||
@dragstart="onDrag"
|
||||
)
|
||||
span.item-label(v-if="label") {{ label }}
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import bPopover from 'bootstrap-vue/lib/components/popover';
|
||||
import { mapState } from 'client/libs/store';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
@@ -46,16 +49,22 @@ export default {
|
||||
type: String,
|
||||
default: 'bottom',
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
...mapState({
|
||||
ATTRIBUTES: 'constants.ATTRIBUTES',
|
||||
}),
|
||||
draggable: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
click () {
|
||||
this.$emit('click', this.item);
|
||||
},
|
||||
onDrag (ev) {
|
||||
if (this.draggable) {
|
||||
this.$emit('onDrag', ev);
|
||||
} else {
|
||||
ev.preventDefault();
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
@@ -53,7 +53,7 @@
|
||||
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 }) }}
|
||||
) {{ group.open ? $t('showLessItems', { type: $t(group.key) }) : $t('showAllItems', { type: $t(group.key), items: items[group.key].length }) }}
|
||||
|
||||
</template>
|
||||
|
||||
|
||||
@@ -1,131 +0,0 @@
|
||||
<template lang="pug">
|
||||
.row
|
||||
.col-2.standard-sidebar
|
||||
.form-group
|
||||
input.form-control(type="text", :placeholder="$t('search')")
|
||||
|
||||
.form
|
||||
h3(v-once) {{ $t('filter') }}
|
||||
.form-group
|
||||
.form-check
|
||||
label.form-check-label(v-once)
|
||||
input.form-check-input(type="checkbox")
|
||||
strong {{ $t('pets') }}
|
||||
.form-check.nested-field
|
||||
label.form-check-label(v-once)
|
||||
input.form-check-input(type="checkbox")
|
||||
span {{ $t('hatchingPotions') }}
|
||||
.form-check.nested-field
|
||||
label.form-check-label(v-once)
|
||||
input.form-check-input(type="checkbox")
|
||||
span {{ $t('quest') }}
|
||||
.form-check.nested-field
|
||||
label.form-check-label(v-once)
|
||||
input.form-check-input(type="checkbox")
|
||||
span {{ $t('special') }}
|
||||
.form-group
|
||||
.form-check
|
||||
label.form-check-label(v-once)
|
||||
input.form-check-input(type="checkbox")
|
||||
strong {{ $t('mounts') }}
|
||||
.form-check.nested-field
|
||||
label.form-check-label(v-once)
|
||||
input.form-check-input(type="checkbox")
|
||||
span {{ $t('hatchingPotions') }}
|
||||
.form-check.nested-field
|
||||
label.form-check-label(v-once)
|
||||
input.form-check-input(type="checkbox")
|
||||
span {{ $t('quest') }}
|
||||
.form-check.nested-field
|
||||
label.form-check-label(v-once)
|
||||
input.form-check-input(type="checkbox")
|
||||
span {{ $t('special') }}
|
||||
|
||||
.col-10.standard-page
|
||||
h4 Pets
|
||||
.inventory-item-container(v-for="pet in dropPets")
|
||||
.PixelPaw
|
||||
.btn.btn-secondary.d-block(@click="open.dropPets = !open.dropPets") {{ open.dropPets ? 'Close' : 'Open' }}
|
||||
|
||||
h2 Magic Potions Pets
|
||||
.inventory-item-container(v-for="pet in magicPets")
|
||||
.PixelPaw
|
||||
.btn.btn-secondary.d-block(@click="open.magicPets = !open.magicPets") {{ open.magicPets ? 'Close' : 'Open' }}
|
||||
|
||||
h2 Quest Pets
|
||||
.inventory-item-container(v-for="pet in questPets")
|
||||
.PixelPaw
|
||||
.btn.btn-secondary.d-block(@click="open.questPets = !open.questPets") {{ open.questPets ? 'Close' : 'Open' }}
|
||||
|
||||
h2 Rare Pets
|
||||
.inventory-item-container(v-for="pet in rarePets")
|
||||
.PixelPaw
|
||||
.btn.btn-secondary.d-block(@click="open.rarePets = !open.rarePets") {{ open.rarePets ? 'Close' : 'Open' }}
|
||||
|
||||
h2 Mounts
|
||||
h2 Quest Mounts
|
||||
h2 Rare Mounts
|
||||
</template>
|
||||
|
||||
<style lang="scss">
|
||||
.inventory-item-container {
|
||||
padding: 20px;
|
||||
border: 1px solid;
|
||||
display: inline-block;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
import { mapState } from 'client/libs/store';
|
||||
import each from 'lodash/each';
|
||||
|
||||
// TODO Normalize special pets and mounts
|
||||
// import Store from 'client/store';
|
||||
// import deepFreeze from 'client/libs/deepFreeze';
|
||||
// const specialMounts =
|
||||
|
||||
export default {
|
||||
data () {
|
||||
return {
|
||||
open: {
|
||||
dropPets: false,
|
||||
magicPets: false,
|
||||
questPets: false,
|
||||
rarePets: false,
|
||||
},
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
...mapState(['content']),
|
||||
dropPets () {
|
||||
return this.listAnimals('pet', this.content.dropEggs, this.content.dropHatchingPotions, this.open.dropPets);
|
||||
},
|
||||
magicPets () {
|
||||
return this.listAnimals('pet', this.content.dropEggs, this.content.premiumHatchingPotions, this.open.magicPets);
|
||||
},
|
||||
questPets () {
|
||||
return this.listAnimals('pet', this.content.questEggs, this.content.dropHatchingPotions, this.open.questPets);
|
||||
},
|
||||
rarePets () {
|
||||
return this.listAnimals('pet', this.content.dropEggs, this.content.dropHatchingPotions, this.open.rarePets);
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
listAnimals (type, eggSource, potionSource, isOpen = false) {
|
||||
let animals = [];
|
||||
let iteration = 0;
|
||||
|
||||
each(eggSource, (egg) => {
|
||||
if (iteration === 1 && !isOpen) return false;
|
||||
iteration++;
|
||||
each(potionSource, (potion) => {
|
||||
let animalKey = `${egg.key}-${potion.key}`;
|
||||
animals.push(this.content[`${type}Info`][animalKey].text());
|
||||
});
|
||||
});
|
||||
|
||||
return animals;
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
@@ -0,0 +1,33 @@
|
||||
<template lang="pug">
|
||||
span.badge.badge-pill.badge-item.badge-count(
|
||||
v-if="show",
|
||||
) {{ count }}
|
||||
</template>
|
||||
|
||||
<style lang="scss">
|
||||
@import '~client/assets/scss/colors.scss';
|
||||
|
||||
.badge-count {
|
||||
right: -9px;
|
||||
color: $white;
|
||||
background: $orange-100;
|
||||
padding: 4.5px 6px;
|
||||
min-width: 24px;
|
||||
height: 24px;
|
||||
box-shadow: 0 1px 1px 0 rgba($black, 0.12);
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
show: {
|
||||
type: Boolean,
|
||||
},
|
||||
count: {
|
||||
type: Number,
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
@@ -0,0 +1,174 @@
|
||||
<template lang="pug">
|
||||
div.slider-root(
|
||||
v-bind:class="{'scrollButtonsVisible': scrollButtonsVisible}",
|
||||
)
|
||||
div.slider-button-area.left-button(
|
||||
v-if="scrollButtonsVisible",
|
||||
@mousedown.left="lastPage"
|
||||
)
|
||||
a.slider-button
|
||||
.svg-icon(v-html="icons.previous")
|
||||
div.slider-button-area.right-button(
|
||||
v-if="scrollButtonsVisible",
|
||||
@mousedown.left="nextPage"
|
||||
)
|
||||
a.slider-button
|
||||
.svg-icon(v-html="icons.next")
|
||||
|
||||
// 120 = width of the left/right buttons
|
||||
div.sliding-content(v-resize="500", @resized="currentWidth = $event.width - 120")
|
||||
.items.items-one-line
|
||||
template(v-for="item in pages[currentPage]")
|
||||
div.vertical-divider(v-if="item.ofNextPage")
|
||||
|
||||
slot(
|
||||
name="item",
|
||||
:item="item",
|
||||
)
|
||||
</template>
|
||||
|
||||
<style lang="scss">
|
||||
|
||||
@import '~client/assets/scss/colors.scss';
|
||||
|
||||
$buttonAreaWidth: 60;
|
||||
|
||||
.slider-root {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.slider-button {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border-radius: 50%;
|
||||
background-color: #ffffff;
|
||||
box-shadow: 0 2px 2px 0 rgba($black, 0.16), 0 1px 4px 0 rgba($black, 0.12);
|
||||
position: absolute;
|
||||
top: calc((100% - 40px) / 2);
|
||||
|
||||
.svg-icon {
|
||||
color: #a5a1ac;
|
||||
margin: auto 0;
|
||||
position: absolute;
|
||||
top: calc((100% - 12px) / 2);
|
||||
width: 8px;
|
||||
height: 16px;
|
||||
right: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
.scrollButtonsVisible {
|
||||
|
||||
.sliding-content {
|
||||
overflow: hidden;
|
||||
}
|
||||
}
|
||||
|
||||
.slider-button-area {
|
||||
width: $buttonAreaWidth+px;
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
z-index: 2;
|
||||
|
||||
&.left-button {
|
||||
left: 0;
|
||||
}
|
||||
|
||||
&.right-button {
|
||||
right: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.sliding-content .items {
|
||||
padding-top: 10px;
|
||||
margin-left: $buttonAreaWidth+ px;
|
||||
|
||||
& > div:last-of-type {
|
||||
margin-right: $buttonAreaWidth + 20px;
|
||||
}
|
||||
}
|
||||
|
||||
.vertical-divider {
|
||||
height: 92px;
|
||||
width: 1px;
|
||||
background: #34313a;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
<script>
|
||||
import previous from 'assets/svg/previous.svg';
|
||||
import next from 'assets/svg/next.svg';
|
||||
import ResizeDirective from 'client/directives/resize.directive';
|
||||
|
||||
import _chunk from 'lodash/chunk';
|
||||
|
||||
export default {
|
||||
directives: {
|
||||
resize: ResizeDirective,
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
icons: Object.freeze({
|
||||
previous,
|
||||
next,
|
||||
}),
|
||||
currentWidth: 0,
|
||||
currentPage: 0,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
pages () {
|
||||
return _chunk(this.items, this.itemsPerPage() - 1).map((content, index, array) => {
|
||||
let resultData = [...content];
|
||||
|
||||
if (array[index + 1]) {
|
||||
resultData.push({
|
||||
...array[index + 1][0],
|
||||
ofNextPage: true,
|
||||
});
|
||||
}
|
||||
|
||||
return resultData;
|
||||
});
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
lastPage () {
|
||||
if (this.currentPage > 0) {
|
||||
this.currentPage--;
|
||||
} else {
|
||||
this.currentPage = this.pages.length - 1;
|
||||
}
|
||||
},
|
||||
|
||||
nextPage () {
|
||||
if (this.currentPage < this.pages.length - 1) {
|
||||
this.currentPage++;
|
||||
} else {
|
||||
this.currentPage = 0;
|
||||
}
|
||||
},
|
||||
|
||||
itemsPerPage () {
|
||||
return Math.floor(this.currentWidth / (this.itemWidth + this.itemMargin));
|
||||
},
|
||||
},
|
||||
props: {
|
||||
scrollButtonsVisible: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
items: {
|
||||
type: Array,
|
||||
},
|
||||
itemWidth: {
|
||||
type: Number,
|
||||
},
|
||||
itemMargin: {
|
||||
type: Number,
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
@@ -0,0 +1,48 @@
|
||||
<template lang="pug">
|
||||
b-popover(
|
||||
:triggers="['hover']",
|
||||
:placement="'top'",
|
||||
)
|
||||
span(slot="content")
|
||||
h4.popover-content-title {{ item.text() }}
|
||||
div.popover-content-text(v-html="item.notes()")
|
||||
|
||||
.item-wrapper
|
||||
.item
|
||||
countBadge(
|
||||
:show="true",
|
||||
:count="itemCount"
|
||||
)
|
||||
span.item-content(
|
||||
:class="'Pet_Food_'+item.key",
|
||||
v-drag.food="item.key"
|
||||
)
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import bPopover from 'bootstrap-vue/lib/components/popover';
|
||||
import DragDropDirective from 'client/directives/dragdrop.directive';
|
||||
|
||||
import CountBadge from './countBadge';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
bPopover,
|
||||
CountBadge,
|
||||
},
|
||||
directives: {
|
||||
drag: DragDropDirective,
|
||||
},
|
||||
props: {
|
||||
item: {
|
||||
type: Object,
|
||||
},
|
||||
itemCount: {
|
||||
type: Number,
|
||||
},
|
||||
itemContentClass: {
|
||||
type: String,
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
@@ -0,0 +1,721 @@
|
||||
<template lang="pug">
|
||||
.row.stable
|
||||
.standard-sidebar
|
||||
div
|
||||
b-popover(
|
||||
:triggers="['hover']",
|
||||
:placement="'right'"
|
||||
)
|
||||
span(slot="content")
|
||||
h4.popover-content-title(v-once) {{ $t('mattBoch') }}
|
||||
.popover-content-text(v-once) {{ $t('mattBochText1') }}
|
||||
|
||||
div.npc_matt
|
||||
|
||||
.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('pets') }}
|
||||
.form-group
|
||||
.form-check(
|
||||
v-for="petGroup in petGroups",
|
||||
v-if="viewOptions[petGroup.key].animalCount != 0",
|
||||
:key="petGroup.key"
|
||||
)
|
||||
label.custom-control.custom-checkbox
|
||||
input.custom-control-input(type="checkbox", v-model="viewOptions[petGroup.key].selected")
|
||||
span.custom-control-indicator
|
||||
span.custom-control-description(v-once) {{ petGroup.label }}
|
||||
h3(v-once) {{ $t('mounts') }}
|
||||
.form-group
|
||||
.form-check(
|
||||
v-for="mountGroup in mountGroups",
|
||||
v-if="viewOptions[mountGroup.key].animalCount != 0",
|
||||
:key="mountGroup.key"
|
||||
)
|
||||
label.custom-control.custom-checkbox
|
||||
input.custom-control-input(type="checkbox", v-model="viewOptions[mountGroup.key].selected")
|
||||
span.custom-control-indicator
|
||||
span.custom-control-description(v-once) {{ mountGroup.label }}
|
||||
|
||||
div.form-group.clearfix
|
||||
h3.float-left Hide Missing
|
||||
toggle-switch.float-right.hideMissing(
|
||||
:label="''",
|
||||
:checked="hideMissing",
|
||||
@change="updateHideMissing"
|
||||
)
|
||||
|
||||
.standard-page(v-resize="500", @resized="availableContentWidth = $event.width - 48")
|
||||
.clearfix
|
||||
h1.float-left.mb-0.page-header(v-once) {{ $t('stable') }}
|
||||
|
||||
div.float-right
|
||||
span.dropdown-label {{ $t('sortBy') }}
|
||||
b-dropdown(:text="$t(selectedSortBy)", right=true)
|
||||
b-dropdown-item(
|
||||
v-for="sort in sortByItems",
|
||||
@click="selectedSortBy = sort",
|
||||
:active="selectedSortBy === sort",
|
||||
:key="sort"
|
||||
) {{ $t(sort) }}
|
||||
|
||||
h2
|
||||
| {{ $t('pets') }}
|
||||
|
|
||||
span.badge.badge-pill.badge-default {{countOwnedAnimals(petGroups[0], 'pet')}}
|
||||
|
||||
div(
|
||||
v-for="petGroup in petGroups",
|
||||
v-if="viewOptions[petGroup.key].selected",
|
||||
:key="petGroup.key"
|
||||
)
|
||||
h4(v-if="viewOptions[petGroup.key].animalCount != 0") {{ petGroup.label }}
|
||||
|
||||
div.items
|
||||
div(
|
||||
v-for="pet in pets(petGroup, viewOptions[petGroup.key].open, hideMissing, selectedSortBy, searchTextThrottled, availableContentWidth)",
|
||||
:key="pet.key",
|
||||
v-drag.drop.food="pet.key",
|
||||
@dragover="onDragOver($event, pet)",
|
||||
@dropped="onDrop($event, pet)",
|
||||
)
|
||||
petItem(
|
||||
:item="pet",
|
||||
:itemContentClass="getPetItemClass(pet)",
|
||||
:popoverPosition="'top'",
|
||||
:progress="pet.progress",
|
||||
:emptyItem="!pet.isOwned()",
|
||||
:showPopover="pet.isOwned() || pet.isHatchable()",
|
||||
@hatchPet="hatchPet",
|
||||
)
|
||||
span(slot="popoverContent")
|
||||
div(v-if="pet.isOwned()")
|
||||
h4.popover-content-title {{ pet.name }}
|
||||
div.hatchablePopover(v-else-if="pet.isHatchable()")
|
||||
h4.popover-content-title {{ pet.name }}
|
||||
div.popover-content-text(v-html="$t('haveHatchablePet', { potion: pet.potionName, egg: pet.eggName })")
|
||||
div.potionEggGroup
|
||||
div.potionEggBackground
|
||||
div(:class="'Pet_HatchingPotion_'+pet.potionKey")
|
||||
div.potionEggBackground
|
||||
div(:class="'Pet_Egg_'+pet.eggKey")
|
||||
|
||||
template(slot="itemBadge", scope="ctx")
|
||||
starBadge(
|
||||
:selected="ctx.item.key === currentPet",
|
||||
:show="ctx.item.isOwned()",
|
||||
@click="selectPet(ctx.item)",
|
||||
)
|
||||
|
||||
.btn.btn-show-more(
|
||||
@click="viewOptions[petGroup.key].open = !viewOptions[petGroup.key].open",
|
||||
v-if="viewOptions[petGroup.key].animalCount != 0"
|
||||
) {{ $t(viewOptions[petGroup.key].open ? 'showLessAnimals' : 'showAllAnimals', { color: petGroup.label, type: $t('pets')}) }}
|
||||
|
||||
h2
|
||||
| {{ $t('mounts') }}
|
||||
|
|
||||
span.badge.badge-pill.badge-default {{countOwnedAnimals(mountGroups[0], 'mount')}}
|
||||
|
||||
div(
|
||||
v-for="mountGroup in mountGroups",
|
||||
v-if="viewOptions[mountGroup.key].selected",
|
||||
:key="mountGroup.key"
|
||||
)
|
||||
h4(v-if="viewOptions[mountGroup.key].animalCount != 0") {{ mountGroup.label }}
|
||||
|
||||
div.items
|
||||
item(
|
||||
v-for="mount in mounts(mountGroup, viewOptions[mountGroup.key].open, hideMissing, selectedSortBy, searchTextThrottled, availableContentWidth)",
|
||||
:item="mount",
|
||||
:itemContentClass="mount.isOwned() ? ('Mount_Icon_' + mount.key) : 'PixelPaw greyedOut'",
|
||||
:key="mount.key",
|
||||
:popoverPosition="'top'"
|
||||
)
|
||||
span(slot="popoverContent")
|
||||
h4.popover-content-title {{ mount.name }}
|
||||
template(slot="itemBadge", scope="ctx")
|
||||
starBadge(
|
||||
:selected="ctx.item.key === currentMount",
|
||||
:show="mount.isOwned()",
|
||||
@click="selectMount(ctx.item)",
|
||||
)
|
||||
|
||||
.btn.btn-show-more(
|
||||
@click="viewOptions[mountGroup.key].open = !viewOptions[mountGroup.key].open",
|
||||
v-if="viewOptions[mountGroup.key].animalCount != 0"
|
||||
) {{ $t(viewOptions[mountGroup.key].open ? 'showLessAnimals' : 'showAllAnimals', { color: mountGroup.label, type: $t('mounts')}) }}
|
||||
|
||||
drawer(
|
||||
:title="$t('quickInventory')",
|
||||
:errorMessage="(!hasDrawerTabItems(selectedDrawerTab)) ? $t('noFoodAvailable') : null"
|
||||
)
|
||||
div(slot="drawer-header")
|
||||
.drawer-tab-container
|
||||
.drawer-tab.text-right
|
||||
a.drawer-tab-text(
|
||||
@click="selectedDrawerTab = 0",
|
||||
:class="{'drawer-tab-text-active': selectedDrawerTab === 0}",
|
||||
) {{ drawerTabs[0].label }}
|
||||
.clearfix
|
||||
.drawer-tab.float-left
|
||||
a.drawer-tab-text(
|
||||
@click="selectedDrawerTab = 1",
|
||||
:class="{ 'drawer-tab-text-active': selectedDrawerTab === 1 }",
|
||||
) {{ drawerTabs[1].label }}
|
||||
|
||||
b-popover(
|
||||
:triggers="['hover']",
|
||||
:placement="'top'"
|
||||
)
|
||||
span(slot="content")
|
||||
.popover-content-text Test Popover
|
||||
|
||||
div.float-right What does my pet like to eat?
|
||||
|
||||
|
||||
drawer-slider(
|
||||
:items="drawerTabs[selectedDrawerTab].items",
|
||||
:scrollButtonsVisible="hasDrawerTabItems(selectedDrawerTab)",
|
||||
slot="drawer-slider",
|
||||
:itemWidth=94,
|
||||
:itemMargin=24,
|
||||
)
|
||||
template(slot="item", scope="ctx")
|
||||
foodItem(
|
||||
:item="ctx.item",
|
||||
:itemCount="userItems.food[ctx.item.key]",
|
||||
)
|
||||
|
||||
b-modal#welcome-modal(
|
||||
:ok-only="true",
|
||||
:ok-title="$t('gotIt')",
|
||||
:visible="!hideDialog",
|
||||
:hide-header="true"
|
||||
)
|
||||
div.content
|
||||
div.npc_matt
|
||||
h1.page-header(v-once) {{ $t('welcomeStable') }}
|
||||
div.content-text(v-once) {{ $t('welcomeStableText') }}
|
||||
|
||||
</template>
|
||||
|
||||
<style lang="scss">
|
||||
|
||||
@import '~client/assets/scss/colors.scss';
|
||||
|
||||
.inventory-item-container {
|
||||
padding: 20px;
|
||||
border: 1px solid;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.stable .item .item-content.Pet {
|
||||
position: absolute;
|
||||
top: -28px;
|
||||
}
|
||||
|
||||
.toggle-switch-container.hideMissing {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.hatchablePopover {
|
||||
width: 180px
|
||||
}
|
||||
|
||||
.potionEggGroup {
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.potionEggBackground {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
|
||||
width: 64px;
|
||||
height: 64px;
|
||||
border-radius: 2px;
|
||||
background-color: #4e4a57;
|
||||
|
||||
&: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;
|
||||
}
|
||||
|
||||
.npc_matt {
|
||||
margin-bottom: 17px;
|
||||
}
|
||||
|
||||
.stable {
|
||||
|
||||
.standard-page {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.drawer-container {
|
||||
// 3% padding + 252px sidebar width
|
||||
left: calc(3% + 252px) !important;
|
||||
}
|
||||
}
|
||||
|
||||
.drawer-slider .items {
|
||||
height: 114px;
|
||||
}
|
||||
|
||||
|
||||
div#welcome-modal {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
flex-direction: column;
|
||||
|
||||
header, footer {
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.npc_matt {
|
||||
margin: 0 auto 21px auto;
|
||||
}
|
||||
|
||||
.content {
|
||||
text-align: center;
|
||||
|
||||
// the modal already has 15px padding
|
||||
margin-left: 33px;
|
||||
margin-right: 33px;
|
||||
margin-top: 25px;
|
||||
}
|
||||
|
||||
.content-text {
|
||||
font-family: 'Roboto', sans-serif;
|
||||
font-size: 14px;
|
||||
font-weight: normal;
|
||||
line-height: 1.43;
|
||||
|
||||
width: 400px;
|
||||
}
|
||||
|
||||
.modal-footer {
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
|
||||
.modal-backdrop.fade.show {
|
||||
background-color: $purple-50;
|
||||
opacity: 0.9;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
import {mapState} from 'client/libs/store';
|
||||
|
||||
import bDropdown from 'bootstrap-vue/lib/components/dropdown';
|
||||
import bDropdownItem from 'bootstrap-vue/lib/components/dropdown-item';
|
||||
import bPopover from 'bootstrap-vue/lib/components/popover';
|
||||
import bModal from 'bootstrap-vue/lib/components/modal';
|
||||
|
||||
import _each from 'lodash/each';
|
||||
import _sortBy from 'lodash/sortBy';
|
||||
import _take from 'lodash/take';
|
||||
import _filter from 'lodash/filter';
|
||||
import _drop from 'lodash/drop';
|
||||
import _flatMap from 'lodash/flatMap';
|
||||
import _throttle from 'lodash/throttle';
|
||||
|
||||
import Item from '../item';
|
||||
import PetItem from './petItem';
|
||||
import FoodItem from './foodItem';
|
||||
import Drawer from 'client/components/inventory/drawer';
|
||||
import toggleSwitch from 'client/components/ui/toggleSwitch';
|
||||
import StarBadge from 'client/components/inventory/starBadge';
|
||||
import CountBadge from './countBadge';
|
||||
import DrawerSlider from './drawerSlider';
|
||||
|
||||
import ResizeDirective from 'client/directives/resize.directive';
|
||||
import DragDropDirective from 'client/directives/dragdrop.directive';
|
||||
|
||||
// TODO Normalize special pets and mounts
|
||||
// import Store from 'client/store';
|
||||
// import deepFreeze from 'client/libs/deepFreeze';
|
||||
// const specialMounts =
|
||||
|
||||
export default {
|
||||
components: {
|
||||
PetItem,
|
||||
Item,
|
||||
FoodItem,
|
||||
Drawer,
|
||||
bDropdown,
|
||||
bDropdownItem,
|
||||
bPopover,
|
||||
bModal,
|
||||
toggleSwitch,
|
||||
StarBadge,
|
||||
CountBadge,
|
||||
DrawerSlider,
|
||||
},
|
||||
directives: {
|
||||
resize: ResizeDirective,
|
||||
drag: DragDropDirective,
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
viewOptions: {},
|
||||
hideMissing: false,
|
||||
|
||||
searchText: null,
|
||||
searchTextThrottled: '',
|
||||
|
||||
// sort has the translation-keys as values
|
||||
selectedSortBy: 'standard',
|
||||
sortByItems: [
|
||||
'standard',
|
||||
'AZ',
|
||||
'sortByColor',
|
||||
'sortByHatchable',
|
||||
],
|
||||
|
||||
selectedDrawerTab: 0,
|
||||
availableContentWidth: 0,
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
searchText: _throttle(function throttleSearch () {
|
||||
let search = this.searchText.toLowerCase();
|
||||
|
||||
this.searchTextThrottled = search;
|
||||
}, 250),
|
||||
},
|
||||
computed: {
|
||||
...mapState({
|
||||
content: 'content',
|
||||
currentPet: 'user.data.items.currentPet',
|
||||
currentMount: 'user.data.items.currentMount',
|
||||
userItems: 'user.data.items',
|
||||
hideDialog: 'user.data.flags.tutorial.common.mounts',
|
||||
}),
|
||||
|
||||
petGroups () {
|
||||
let petGroups = [
|
||||
{
|
||||
label: this.$t('filterByStandard'),
|
||||
key: 'standardPets',
|
||||
petSource: {
|
||||
eggs: this.content.dropEggs,
|
||||
potions: this.content.dropHatchingPotions,
|
||||
},
|
||||
},
|
||||
{
|
||||
label: this.$t('filterByMagicPotion'),
|
||||
key: 'magicPets',
|
||||
petSource: {
|
||||
eggs: this.content.dropEggs,
|
||||
potions: this.content.premiumHatchingPotions,
|
||||
},
|
||||
},
|
||||
{
|
||||
label: this.$t('filterByQuest'),
|
||||
key: 'questPets',
|
||||
petSource: {
|
||||
eggs: this.content.questEggs,
|
||||
potions: this.content.dropHatchingPotions,
|
||||
},
|
||||
},
|
||||
{
|
||||
label: this.$t('special'),
|
||||
key: 'specialPets',
|
||||
petSource: {
|
||||
special: this.content.specialPets,
|
||||
},
|
||||
alwaysHideMissing: true,
|
||||
},
|
||||
];
|
||||
|
||||
petGroups.map((petGroup) => {
|
||||
this.$set(this.viewOptions, petGroup.key, {
|
||||
selected: true,
|
||||
open: false,
|
||||
animalCount: 0,
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
return petGroups;
|
||||
},
|
||||
mountGroups () {
|
||||
let mountGroups = [
|
||||
{
|
||||
label: this.$t('filterByStandard'),
|
||||
key: 'standardMounts',
|
||||
petSource: {
|
||||
eggs: this.content.dropEggs,
|
||||
potions: this.content.dropHatchingPotions,
|
||||
},
|
||||
},
|
||||
{
|
||||
label: this.$t('filterByMagicPotion'),
|
||||
key: 'magicMounts',
|
||||
petSource: {
|
||||
eggs: this.content.dropEggs,
|
||||
potions: this.content.premiumHatchingPotions,
|
||||
},
|
||||
},
|
||||
{
|
||||
label: this.$t('filterByQuest'),
|
||||
key: 'questMounts',
|
||||
petSource: {
|
||||
eggs: this.content.questEggs,
|
||||
potions: this.content.dropHatchingPotions,
|
||||
},
|
||||
},
|
||||
{
|
||||
label: this.$t('special'),
|
||||
key: 'specialMounts',
|
||||
petSource: {
|
||||
special: this.content.specialMounts,
|
||||
},
|
||||
alwaysHideMissing: true,
|
||||
},
|
||||
];
|
||||
|
||||
mountGroups.map((mountGroup) => {
|
||||
this.$set(this.viewOptions, mountGroup.key, {
|
||||
selected: true,
|
||||
open: false,
|
||||
animalCount: 0,
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
return mountGroups;
|
||||
},
|
||||
|
||||
drawerTabs () {
|
||||
return [
|
||||
{
|
||||
label: this.$t('food'),
|
||||
items: _filter(this.content.food, f => {
|
||||
return f.key !== 'Saddle' && this.userItems.food[f.key];
|
||||
}),
|
||||
},
|
||||
{
|
||||
label: this.$t('special'),
|
||||
items: _filter(this.content.food, f => {
|
||||
return f.key === 'Saddle' && this.userItems.food[f.key];
|
||||
}),
|
||||
},
|
||||
];
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
|
||||
getAnimalList (animalGroup, type) {
|
||||
let key = animalGroup.key;
|
||||
|
||||
this.cachedAnimalList = this.cachedAnimalList || {};
|
||||
if (this.cachedAnimalList[key]) {
|
||||
return this.cachedAnimalList[key];
|
||||
}
|
||||
|
||||
let animals = [];
|
||||
let userItems = this.userItems;
|
||||
|
||||
switch (key) {
|
||||
case 'specialPets':
|
||||
case 'specialMounts': {
|
||||
_each(animalGroup.petSource.special, (value, specialKey) => {
|
||||
let eggKey = specialKey.split('-')[0];
|
||||
let potionKey = specialKey.split('-')[1];
|
||||
|
||||
animals.push({
|
||||
key: specialKey,
|
||||
eggKey,
|
||||
potionKey,
|
||||
pet: this.content[`${type}Info`][specialKey].text(),
|
||||
isOwned () {
|
||||
return [`${type}s`][this.key] > 0;
|
||||
},
|
||||
isHatchable () {
|
||||
return false;
|
||||
},
|
||||
});
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
_each(animalGroup.petSource.eggs, (egg) => {
|
||||
_each(animalGroup.petSource.potions, (potion) => {
|
||||
let animalKey = `${egg.key}-${potion.key}`;
|
||||
|
||||
animals.push({
|
||||
key: animalKey,
|
||||
eggKey: egg.key,
|
||||
eggName: egg.text(),
|
||||
potionKey: potion.key,
|
||||
potionName: potion.text(),
|
||||
name: this.content[`${type}Info`][animalKey].text(),
|
||||
isOwned () {
|
||||
return userItems[`${type}s`][animalKey] > 0;
|
||||
},
|
||||
isHatchable () {
|
||||
return userItems.eggs[egg.key] > 0 && userItems.hatchingPotions[potion.key] > 0;
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
this.cachedAnimalList[key] = animals;
|
||||
|
||||
return animals;
|
||||
},
|
||||
|
||||
listAnimals (animalGroup, type, isOpen, hideMissing, sort, searchText, availableSpace) {
|
||||
let animals = this.getAnimalList(animalGroup, type);
|
||||
let isPetList = type === 'pet';
|
||||
let withProgress = isPetList && animalGroup.key !== 'specialPets';
|
||||
|
||||
// 1. Filter
|
||||
if (hideMissing || animalGroup.alwaysHideMissing) {
|
||||
animals = _filter(animals, (a) => {
|
||||
return a.isOwned();
|
||||
});
|
||||
}
|
||||
|
||||
if (searchText && searchText !== '') {
|
||||
animals = _filter(animals, (a) => {
|
||||
return a.name.toLowerCase().indexOf(searchText) !== -1;
|
||||
});
|
||||
}
|
||||
|
||||
// 2. Sort
|
||||
switch (sort) {
|
||||
case 'AZ':
|
||||
animals = _sortBy(animals, ['pet']);
|
||||
break;
|
||||
|
||||
case 'sortByColor':
|
||||
animals = _sortBy(animals, ['potionName']);
|
||||
break;
|
||||
|
||||
case 'sortByHatchable': {
|
||||
if (isPetList) {
|
||||
let sortFunc = (i) => {
|
||||
return i.isHatchable() ? 0 : 1;
|
||||
};
|
||||
|
||||
animals = _sortBy(animals, [sortFunc]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
let animalRows = [];
|
||||
|
||||
let itemsPerRow = Math.floor(availableSpace / (94 + 24));
|
||||
|
||||
let rowsToShow = isOpen ? Math.ceil(animals.length / itemsPerRow) : 1;
|
||||
|
||||
for (let i = 0; i < rowsToShow; i++) {
|
||||
let skipped = _drop(animals, i * itemsPerRow);
|
||||
let row = _take(skipped, itemsPerRow);
|
||||
|
||||
let rowWithProgressData = withProgress ? _flatMap(row, (a) => {
|
||||
let progress = this.userItems[`${type}s`][a.key];
|
||||
|
||||
return {
|
||||
...a,
|
||||
progress,
|
||||
};
|
||||
}) : row;
|
||||
|
||||
animalRows.push(...rowWithProgressData);
|
||||
}
|
||||
|
||||
this.viewOptions[animalGroup.key].animalCount = animals.length;
|
||||
|
||||
return animalRows;
|
||||
},
|
||||
|
||||
countOwnedAnimals (animalGroup, type) {
|
||||
let animals = this.getAnimalList(animalGroup, type);
|
||||
|
||||
let countAll = animals.length;
|
||||
let countOwned = _filter(animals, (a) => {
|
||||
return a.isOwned();
|
||||
});
|
||||
|
||||
return `${countOwned.length}/${countAll}`;
|
||||
},
|
||||
|
||||
pets (animalGroup, showAll, hideMissing, sortBy, searchText, availableSpace) {
|
||||
return this.listAnimals(animalGroup, 'pet', showAll, hideMissing, sortBy, searchText, availableSpace);
|
||||
},
|
||||
|
||||
mounts (animalGroup, showAll, hideMissing, sortBy, searchText, availableSpace) {
|
||||
return this.listAnimals(animalGroup, 'mount', showAll, hideMissing, sortBy, searchText, availableSpace);
|
||||
},
|
||||
|
||||
getPetItemClass (pet) {
|
||||
if (pet.isOwned()) {
|
||||
return `Pet Pet-${pet.key}`;
|
||||
}
|
||||
|
||||
if (pet.isHatchable()) {
|
||||
return 'PixelPaw';
|
||||
}
|
||||
|
||||
return 'GreyedOut PixelPaw';
|
||||
},
|
||||
|
||||
hasDrawerTabItems (index) {
|
||||
return this.drawerTabs && this.drawerTabs[index].items.length !== 0;
|
||||
},
|
||||
|
||||
// Actions
|
||||
updateHideMissing (newVal) {
|
||||
this.hideMissing = newVal;
|
||||
},
|
||||
|
||||
selectPet (item) {
|
||||
this.$store.dispatch('common:equip', {key: item.key, type: 'pet'});
|
||||
},
|
||||
|
||||
selectMount (item) {
|
||||
this.$store.dispatch('common:equip', {key: item.key, type: 'mount'});
|
||||
},
|
||||
|
||||
hatchPet (pet) {
|
||||
this.$store.dispatch('common:hatch', {egg: pet.eggKey, hatchingPotion: pet.potionKey});
|
||||
},
|
||||
|
||||
onDragOver (ev, pet) {
|
||||
if (this.userItems.mounts[pet.key]) {
|
||||
ev.dropable = false;
|
||||
}
|
||||
},
|
||||
|
||||
onDrop (ev, pet) {
|
||||
this.$store.dispatch('common:feed', {pet: pet.key, food: ev.draggingKey});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
@@ -0,0 +1,117 @@
|
||||
<template lang="pug">
|
||||
b-popover(
|
||||
:triggers="[showPopover?'hover':'']",
|
||||
:placement="popoverPosition",
|
||||
)
|
||||
span(slot="content")
|
||||
slot(name="popoverContent", :item="item")
|
||||
|
||||
.item-wrapper
|
||||
.item(
|
||||
:class="{'item-empty': emptyItem}",
|
||||
@mouseup="holdStop",
|
||||
@mouseleave="holdStop",
|
||||
@mousedown.left="holdStart"
|
||||
)
|
||||
slot(name="itemBadge", :item="item")
|
||||
span.item-content(:class="itemContentClass")
|
||||
span.pet-progress-background(v-if="progress > 0")
|
||||
div.pet-progress-bar(v-bind:style="{width: 100 * progress/50 + '%' }")
|
||||
span.pet-progress-background(v-if="holdProgress > 0")
|
||||
div.pet-progress-bar.hold(v-bind:style="{width: 100 * holdProgress/5 + '%' }")
|
||||
span.item-label(v-if="label") {{ label }}
|
||||
</template>
|
||||
|
||||
<style lang="scss">
|
||||
.pet-progress-background {
|
||||
width: 62px;
|
||||
height: 4px;
|
||||
background-color: #e1e0e3;
|
||||
position: absolute;
|
||||
bottom: 4px;
|
||||
left: calc((100% - 62px) / 2);
|
||||
}
|
||||
|
||||
.pet-progress-bar {
|
||||
height: 4px;
|
||||
background-color: #24cc8f;
|
||||
}
|
||||
|
||||
.pet-progress-bar.hold {
|
||||
background-color: #54c3cc;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
import bPopover from 'bootstrap-vue/lib/components/popover';
|
||||
import {mapState} from 'client/libs/store';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
bPopover,
|
||||
},
|
||||
props: {
|
||||
item: {
|
||||
type: Object,
|
||||
},
|
||||
itemContentClass: {
|
||||
type: String,
|
||||
},
|
||||
label: {
|
||||
type: String,
|
||||
},
|
||||
progress: {
|
||||
type: Number,
|
||||
default: -1,
|
||||
},
|
||||
emptyItem: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
popoverPosition: {
|
||||
type: String,
|
||||
default: 'bottom',
|
||||
},
|
||||
showPopover: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
holdProgress: -1,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
...mapState({
|
||||
ATTRIBUTES: 'constants.ATTRIBUTES',
|
||||
}),
|
||||
},
|
||||
methods: {
|
||||
holdStart () {
|
||||
let pet = this.item;
|
||||
if (pet.isOwned() || !pet.isHatchable()) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.holdProgress = 1;
|
||||
|
||||
this.currentHoldingTimer = setInterval(() => {
|
||||
if (this.holdProgress === 5) {
|
||||
this.holdStop();
|
||||
this.$emit('hatchPet', pet);
|
||||
}
|
||||
|
||||
this.holdProgress += 1;
|
||||
}, 1000);
|
||||
},
|
||||
|
||||
holdStop () {
|
||||
if (this.currentHoldingTimer) {
|
||||
clearInterval(this.currentHoldingTimer);
|
||||
this.holdProgress = -1;
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
@@ -0,0 +1,235 @@
|
||||
<template lang="pug">
|
||||
.d-flex.member-details(:class="{ condensed, expanded }")
|
||||
avatar(:member="member",
|
||||
@click.native="$emit('click')",
|
||||
@mouseover.native="$emit('onHover')",
|
||||
@mouseout.native="$emit('onHover')",
|
||||
)
|
||||
.member-stats
|
||||
h3.character-name
|
||||
| {{member.profile.name}}
|
||||
.is-buffed(v-if="isBuffed")
|
||||
.svg-icon(v-html="icons.buff")
|
||||
span.small-text.character-level {{ characterLevel }}
|
||||
.progress-container.d-flex
|
||||
.svg-icon(v-html="icons.health")
|
||||
.progress
|
||||
.progress-bar.bg-health(:style="{width: `${percent(member.stats.hp, MAX_HEALTH)}%`}")
|
||||
span.small-text {{member.stats.hp | round}} / {{MAX_HEALTH}}
|
||||
.progress-container.d-flex
|
||||
.svg-icon(v-html="icons.experience")
|
||||
.progress
|
||||
.progress-bar.bg-experience(:style="{width: `${percent(member.stats.exp, toNextLevel)}%`}")
|
||||
span.small-text {{member.stats.exp | round}} / {{toNextLevel}}
|
||||
.progress-container.d-flex(v-if="hasClass")
|
||||
.svg-icon(v-html="icons.mana")
|
||||
.progress
|
||||
.progress-bar.bg-mana(:style="{width: `${percent(member.stats.mp, maxMP)}%`}")
|
||||
span.small-text {{member.stats.mp | round}} / {{maxMP}}
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import '~client/assets/scss/colors.scss';
|
||||
|
||||
.member-details {
|
||||
white-space: nowrap;
|
||||
margin-top: 24px;
|
||||
margin-bottom: 24px;
|
||||
transition: all 0.15s ease-out;
|
||||
}
|
||||
|
||||
.member-stats {
|
||||
padding-left: 16px;
|
||||
padding-right: 24px;
|
||||
opacity: 1;
|
||||
transition: opacity 0.15s ease-out;
|
||||
}
|
||||
|
||||
.member-details.condensed:not(.expanded) .member-stats {
|
||||
opacity: 0;
|
||||
position: absolute;
|
||||
z-index: -1;
|
||||
}
|
||||
|
||||
// Condensed version
|
||||
.member-details.condensed.expanded {
|
||||
background: $header-dark-background;
|
||||
box-shadow: 0 0 0px 9px $header-dark-background;
|
||||
position: relative;
|
||||
margin-bottom: 33px;
|
||||
z-index: 8;
|
||||
|
||||
.is-buffed {
|
||||
background-color: $purple-50;
|
||||
}
|
||||
|
||||
.member-stats {
|
||||
background: $header-dark-background;
|
||||
position: absolute;
|
||||
right: 100%;
|
||||
height: calc(100% + 18px);
|
||||
margin-top: -9px;
|
||||
padding-top: 9px;
|
||||
padding-bottom: 24px;
|
||||
padding-right: 16px;
|
||||
padding-bottom: 14px;
|
||||
border-top-left-radius: 4px;
|
||||
border-bottom-left-radius: 4px;
|
||||
z-index: 9;
|
||||
}
|
||||
|
||||
.progress-container > .svg-icon {
|
||||
width: 19px;
|
||||
height: 19px;
|
||||
margin-top: -2px;
|
||||
}
|
||||
|
||||
.progress-container > .progress {
|
||||
width: 152px;
|
||||
border-radius: 0px;
|
||||
height: 10px;
|
||||
margin-top: 2px;
|
||||
background: $purple-100;
|
||||
}
|
||||
|
||||
.progress-container > .progress > .progress-bar {
|
||||
border-radius: 0px;
|
||||
height: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.small-text {
|
||||
color: $header-color;
|
||||
}
|
||||
|
||||
.character-name {
|
||||
margin-bottom: 1px;
|
||||
color: $white;
|
||||
}
|
||||
|
||||
.character-level {
|
||||
display: block;
|
||||
font-style: normal;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.is-buffed {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
background: $header-dark-background;
|
||||
display: inline-block;
|
||||
margin-left: 16px;
|
||||
vertical-align: middle;
|
||||
|
||||
.svg-icon {
|
||||
display: block;
|
||||
width: 10px;
|
||||
height: 12px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
}
|
||||
|
||||
#header-avatar {
|
||||
margin-right: 16px;
|
||||
}
|
||||
|
||||
.progress-container {
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.progress-container > span {
|
||||
color: $header-color;
|
||||
margin-left: 16px;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
.progress-container > .svg-icon {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
margin-right: 8px;
|
||||
margin-top: -4px;
|
||||
}
|
||||
|
||||
.progress-container > .progress {
|
||||
width: 303px;
|
||||
margin: 0px;
|
||||
border-radius: 2px;
|
||||
height: 16px;
|
||||
background-color: $header-dark-background;
|
||||
}
|
||||
|
||||
.progress-container > .progress > .progress-bar {
|
||||
border-radius: 2px;
|
||||
height: 16px;
|
||||
min-width: 0px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
import Avatar from './avatar';
|
||||
import { mapState } from 'client/libs/store';
|
||||
|
||||
import { toNextLevel } from '../../common/script/statHelpers';
|
||||
import statsComputed from '../../common/script/libs/statsComputed';
|
||||
import percent from '../../common/script/libs/percent';
|
||||
|
||||
import buffIcon from 'assets/svg/buff.svg';
|
||||
import healthIcon from 'assets/svg/health.svg';
|
||||
import experienceIcon from 'assets/svg/experience.svg';
|
||||
import manaIcon from 'assets/svg/mana.svg';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
Avatar,
|
||||
},
|
||||
props: {
|
||||
member: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
condensed: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
expanded: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
icons: Object.freeze({
|
||||
buff: buffIcon,
|
||||
health: healthIcon,
|
||||
experience: experienceIcon,
|
||||
mana: manaIcon,
|
||||
}),
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
percent,
|
||||
},
|
||||
computed: {
|
||||
...mapState({
|
||||
MAX_HEALTH: 'constants.MAX_HEALTH',
|
||||
}),
|
||||
maxMP () {
|
||||
return statsComputed(this.member).maxMP;
|
||||
},
|
||||
toNextLevel () { // Exp to next level
|
||||
return toNextLevel(this.member.stats.lvl);
|
||||
},
|
||||
characterLevel () {
|
||||
return `${this.$t('level')} ${this.member.stats.lvl} ${
|
||||
this.member.stats.class ? this.$t(this.member.stats.class) : ''
|
||||
}`;
|
||||
},
|
||||
isBuffed () {
|
||||
return this.$store.getters['members:isBuffed'](this.member);
|
||||
},
|
||||
hasClass () {
|
||||
return this.$store.getters['members:hasClass'](this.member);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
@@ -1,19 +0,0 @@
|
||||
<template lang="pug">
|
||||
.row
|
||||
secondary-menu.col-12
|
||||
router-link.nav-link(:to="{name: 'tavern'}", exact) {{ $t('tavern') }}
|
||||
router-link.nav-link(:to="{name: 'inbox'}") {{ $t('inbox') }}
|
||||
router-link.nav-link(:to="{name: 'guildsDiscovery'}") {{ $t('guilds') }}
|
||||
.col-12
|
||||
router-view
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import SecondaryMenu from 'client/components/secondaryMenu';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
SecondaryMenu,
|
||||
},
|
||||
};
|
||||
</script>
|
||||
@@ -0,0 +1,30 @@
|
||||
<template lang="pug">
|
||||
nav
|
||||
a(href='/login') Login
|
||||
a(href='/register') Register
|
||||
</template>
|
||||
|
||||
|
||||
<script>
|
||||
export default {
|
||||
methods: {
|
||||
play () {
|
||||
// @TODO:
|
||||
// Auth play click
|
||||
},
|
||||
// passwordReset (email) {
|
||||
// if(email == null || email.length == 0) {
|
||||
// alert(window.env.t('invalidEmail'));
|
||||
// } else {
|
||||
// $http.post(ApiUrl.get() + '/api/v3/user/reset-password', {email:email})
|
||||
// .success(function(){
|
||||
// alert(window.env.t('newPassSent'));
|
||||
// })
|
||||
// .error(function(data){
|
||||
// alert(data.err);
|
||||
// });
|
||||
// }
|
||||
// },
|
||||
},
|
||||
};
|
||||
</script>
|
||||
@@ -1,33 +0,0 @@
|
||||
<template lang="pug">
|
||||
li
|
||||
ul
|
||||
li
|
||||
strong {{task.text}}
|
||||
li(v-if="task.type === 'habit'") up: {{task.up}}, down: {{task.down}}
|
||||
li value: {{task.value}}
|
||||
template(v-if="task.type === 'daily' || task.type === 'todo'")
|
||||
li completed: {{task.completed}}
|
||||
li
|
||||
span checklist
|
||||
ul
|
||||
li(v-for="checklist in task.checklist") {{checklist.text}}
|
||||
template(v-if="task.type === 'daily'")
|
||||
li streak: {{task.streak}}
|
||||
li repeat: {{task.repeat}}
|
||||
li(v-if="task.type === 'todo'") due date: {{task.date}}
|
||||
li attribute {{task.attribute}}
|
||||
li difficulty {{task.priority}}
|
||||
li tags {{getTagsFor(task)}}
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapState, mapGetters } from 'client/libs/store';
|
||||
|
||||
export default {
|
||||
props: ['task'],
|
||||
computed: {
|
||||
...mapState({user: 'user.data'}),
|
||||
...mapGetters({getTagsFor: 'tasks:getTagsFor'}),
|
||||
},
|
||||
};
|
||||
</script>
|
||||
@@ -0,0 +1,194 @@
|
||||
<template lang="pug">
|
||||
.tasks-column
|
||||
.d-flex
|
||||
h2.tasks-column-title(v-once) {{ $t(types[type].label) }}
|
||||
.filters.d-flex.justify-content-end
|
||||
.filter.small-text(
|
||||
v-for="filter in types[type].filters",
|
||||
:class="{active: activeFilter.label === filter.label}",
|
||||
@click="activeFilter = filter",
|
||||
) {{ $t(filter.label) }}
|
||||
.tasks-list
|
||||
task(v-for="task in tasks[`${type}s`]", :key="task.id", :task="task", v-if="activeFilter.filter(task)")
|
||||
.bottom-gradient
|
||||
.column-background(v-if="isUser === true", :class="{'initial-description': tasks[`${type}s`].length === 0}")
|
||||
.svg-icon(v-html="icons[type]", :class="`icon-${type}`", v-once)
|
||||
h3(v-once) {{$t('theseAreYourTasks', {taskType: `${type}s`})}}
|
||||
.small-text {{$t(`${type}sDesc`)}}
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import '~client/assets/scss/colors.scss';
|
||||
|
||||
.tasks-column {
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.tasks-list {
|
||||
border-radius: 4px;
|
||||
background: $gray-600;
|
||||
padding: 8px;
|
||||
// not sure why but this is necessary or the last task will overflow the container
|
||||
padding-bottom: 0.1px;
|
||||
position: relative;
|
||||
height: calc(100% - 64px);
|
||||
}
|
||||
|
||||
.bottom-gradient {
|
||||
position: absolute;
|
||||
bottom: 0px;
|
||||
left: -0px;
|
||||
height: 42px;
|
||||
background-image: linear-gradient(to bottom, rgba(52, 49, 58, 0), #34313a);
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.tasks-column-title {
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.filters {
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.filter {
|
||||
font-weight: bold;
|
||||
color: $gray-100;
|
||||
font-style: normal;
|
||||
padding: 8px;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
color: $purple-200;
|
||||
}
|
||||
|
||||
&.active {
|
||||
color: $purple-200;
|
||||
border-bottom: 2px solid $purple-200;
|
||||
padding-bottom: 6px;
|
||||
}
|
||||
}
|
||||
|
||||
.column-background {
|
||||
position: absolute;
|
||||
bottom: 32px;
|
||||
z-index: 7;
|
||||
|
||||
&.initial-description {
|
||||
top: 30%;
|
||||
}
|
||||
|
||||
.svg-icon {
|
||||
margin: 0 auto;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
h3, .small-text {
|
||||
color: $gray-300;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-weight: normal;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.small-text {
|
||||
font-style: normal;
|
||||
padding-left: 24px;
|
||||
padding-right: 24px;
|
||||
}
|
||||
}
|
||||
|
||||
.icon-habit {
|
||||
width: 30px;
|
||||
height: 20px;
|
||||
}
|
||||
|
||||
.icon-daily {
|
||||
width: 30px;
|
||||
height: 20px;
|
||||
}
|
||||
|
||||
.icon-todo {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
}
|
||||
|
||||
.icon-reward {
|
||||
width: 26px;
|
||||
height: 20px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
import Task from './task';
|
||||
import { mapState } from 'client/libs/store';
|
||||
import { shouldDo } from 'common/script/cron';
|
||||
import habitIcon from 'assets/svg/habit.svg';
|
||||
import dailyIcon from 'assets/svg/daily.svg';
|
||||
import todoIcon from 'assets/svg/todo.svg';
|
||||
import rewardIcon from 'assets/svg/reward.svg';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
Task,
|
||||
},
|
||||
props: ['type', 'isUser'],
|
||||
data () {
|
||||
const types = Object.freeze({
|
||||
habit: {
|
||||
label: 'habits',
|
||||
filters: [
|
||||
{label: 'all', filter: () => true, default: true},
|
||||
{label: 'yellowred', filter: t => t.value < 1}, // weak
|
||||
{label: 'greenblue', filter: t => t.value >= 1}, // strong
|
||||
],
|
||||
},
|
||||
daily: {
|
||||
label: 'dailies',
|
||||
filters: [
|
||||
{label: 'all', filter: () => true, default: true},
|
||||
{label: 'due', filter: t => !t.completed && shouldDo(new Date(), t, this.userPreferences)},
|
||||
{label: 'notDue', filter: t => t.completed || !shouldDo(new Date(), t, this.userPreferences)},
|
||||
],
|
||||
},
|
||||
todo: {
|
||||
label: 'todos',
|
||||
filters: [
|
||||
{label: 'remaining', filter: t => !t.completed, default: true}, // active
|
||||
{label: 'scheduled', filter: t => !t.completed && t.date},
|
||||
{label: 'complete2', filter: t => t.completed},
|
||||
],
|
||||
},
|
||||
reward: {
|
||||
label: 'rewards',
|
||||
filters: [
|
||||
{label: 'all', filter: () => true, default: true},
|
||||
{label: 'custom', filter: () => true}, // all rewards made by the user
|
||||
{label: 'wishlist', filter: () => false}, // not user tasks
|
||||
],
|
||||
},
|
||||
});
|
||||
|
||||
const icons = Object.freeze({
|
||||
habit: habitIcon,
|
||||
daily: dailyIcon,
|
||||
todo: todoIcon,
|
||||
reward: rewardIcon,
|
||||
});
|
||||
|
||||
return {
|
||||
types,
|
||||
activeFilter: types[this.type].filters.find(f => f.default === true),
|
||||
icons,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
...mapState({
|
||||
tasks: 'tasks.data',
|
||||
userPreferences: 'user.data.preferences',
|
||||
}),
|
||||
},
|
||||
};
|
||||
</script>
|
||||
@@ -0,0 +1,293 @@
|
||||
<template lang="pug">
|
||||
.task.d-flex
|
||||
// Habits left side control
|
||||
.left-control.d-flex.align-items-center.justify-content-center(v-if="task.type === 'habit'", :class="controlClass.up")
|
||||
.task-control.habit-control(:class="controlClass.up + '-control'")
|
||||
.svg-icon.positive(v-html="icons.positive")
|
||||
// Dailies and todos left side control
|
||||
.left-control.d-flex.align-items-center.justify-content-center(v-if="task.type === 'daily' || task.type === 'todo'", :class="controlClass")
|
||||
.task-control.daily-todo-control(:class="controlClass + '-control'")
|
||||
.svg-icon.check(v-html="icons.check", v-if="task.completed")
|
||||
// Task title, description and icons
|
||||
.task-content(:class="contentClass")
|
||||
h3.task-title(:class="{ 'has-notes': task.notes }") {{task.text}}
|
||||
.task-notes.small-text {{task.notes}}
|
||||
.icons.small-text.d-flex.align-items-center
|
||||
.d-flex.align-items-center(v-if="task.type === 'todo' && task.date", :class="{'due-overdue': isDueOverdue}")
|
||||
.svg-icon.calendar(v-html="icons.calendar")
|
||||
span {{dueIn}}
|
||||
.icons-right.d-flex.justify-content-end
|
||||
.d-flex.align-items-center(v-if="showStreak")
|
||||
.svg-icon.streak(v-html="icons.streak")
|
||||
span(v-if="task.type === 'daily'") {{task.streak}}
|
||||
span(v-if="task.type === 'habit'")
|
||||
span.m-0(v-if="task.up") +{{task.counterUp}}
|
||||
span.m-0(v-if="task.up && task.down") |
|
||||
span.m-0(v-if="task.down") -{{task.counterDown}}
|
||||
.d-flex.align-items-center(v-if="task.challenge && task.challenge.id")
|
||||
.svg-icon.challenge(v-html="icons.challenge")
|
||||
b-popover.tags-popover.no-span-margin(
|
||||
:triggers="['hover']",
|
||||
:placement="'bottom'",
|
||||
:popover-style="{'max-width': '1000px'}",
|
||||
)
|
||||
.d-flex.align-items-center(slot="content")
|
||||
.tags-popover-title(v-once) {{ `${$t('tags')}:` }}
|
||||
.tag-label(v-for="tag in getTagsFor(task)") {{tag}}
|
||||
.d-flex.align-items-center(v-if="task.tags && task.tags.length > 0")
|
||||
.svg-icon.tags(v-html="icons.tags")
|
||||
|
||||
// Habits right side control
|
||||
.right-control.d-flex.align-items-center.justify-content-center(v-if="task.type === 'habit'", :class="controlClass.down")
|
||||
.task-control.habit-control(:class="controlClass.down + '-control'")
|
||||
.svg-icon.negative(v-html="icons.negative")
|
||||
// Rewards right side control
|
||||
.right-control.d-flex.align-items-center.justify-content-center.reward-control(v-if="task.type === 'reward'", :class="controlClass")
|
||||
.svg-icon(v-html="icons.gold")
|
||||
.small-text {{task.value}}
|
||||
</template>
|
||||
|
||||
<style lang="scss">
|
||||
@import '~client/assets/scss/colors.scss';
|
||||
|
||||
.task {
|
||||
margin-bottom: 8px;
|
||||
box-shadow: 0 2px 2px 0 rgba($black, 0.16), 0 1px 4px 0 rgba($black, 0.12);
|
||||
background: $white;
|
||||
border-radius: 2px;
|
||||
z-index: 9;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.task-title {
|
||||
margin-bottom: 8px;
|
||||
color: $gray-10;
|
||||
font-weight: normal;
|
||||
|
||||
&.has-notes {
|
||||
margin-bottom: 0px;
|
||||
}
|
||||
}
|
||||
|
||||
.task-notes {
|
||||
color: $gray-100;
|
||||
font-style: normal;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.task-content {
|
||||
padding: 8px;
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.icons {
|
||||
color: $gray-300;
|
||||
font-style: normal;
|
||||
|
||||
&-right {
|
||||
flex-grow: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.icons-right .svg-icon {
|
||||
margin-left: 8px;
|
||||
}
|
||||
|
||||
.icons span {
|
||||
margin-left: 4px;
|
||||
}
|
||||
|
||||
.no-span-margin span {
|
||||
margin-left: 0px !important;
|
||||
}
|
||||
|
||||
.svg-icon.streak {
|
||||
width: 11.6px;
|
||||
height: 7.1px;
|
||||
}
|
||||
|
||||
.tags.svg-icon, .calendar.svg-icon {
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
}
|
||||
|
||||
.tags:hover {
|
||||
color: $purple-500;
|
||||
}
|
||||
|
||||
.due-overdue {
|
||||
color: $red-50;
|
||||
}
|
||||
|
||||
.calendar.svg-icon {
|
||||
margin-right: 2px;
|
||||
margin-top: -2px;
|
||||
}
|
||||
|
||||
.challenge.svg-icon {
|
||||
width: 14px;
|
||||
height: 12px;
|
||||
}
|
||||
|
||||
.check.svg-icon {
|
||||
width: 12.3px;
|
||||
height: 9.8px;
|
||||
margin: 8px;
|
||||
}
|
||||
|
||||
.left-control, .right-control {
|
||||
width: 40px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.left-control {
|
||||
border-top-left-radius: 2px;
|
||||
border-bottom-left-radius: 2px;
|
||||
}
|
||||
|
||||
.right-control {
|
||||
border-top-right-radius: 2px;
|
||||
border-bottom-right-radius: 2px;
|
||||
}
|
||||
|
||||
.task-control {
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
}
|
||||
|
||||
.habit-control {
|
||||
border-radius: 100px;
|
||||
color: $white;
|
||||
|
||||
.svg-icon {
|
||||
width: 10px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.positive {
|
||||
margin-top: 9px;
|
||||
}
|
||||
|
||||
.negative {
|
||||
margin-top: 13px;
|
||||
}
|
||||
}
|
||||
|
||||
.daily-todo-control {
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
.reward-control {
|
||||
flex-direction: column;
|
||||
padding-top: 16px;
|
||||
padding-bottom: 12px;
|
||||
|
||||
.svg-icon {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
}
|
||||
|
||||
.small-text {
|
||||
margin-top: 4px;
|
||||
color: $yellow-10;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<style lang="scss"> // not working as scoped css
|
||||
@import '~client/assets/scss/colors.scss';
|
||||
|
||||
.tags-popover {
|
||||
// TODO fix padding, see https://github.com/bootstrap-vue/bootstrap-vue/issues/559#issuecomment-311150335
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.tags-popover-title {
|
||||
margin-right: 4px;
|
||||
display: block;
|
||||
float: left;
|
||||
}
|
||||
|
||||
.tag-label {
|
||||
display: block;
|
||||
float: left;
|
||||
margin-left: 4px;
|
||||
border-radius: 100px;
|
||||
background-color: $gray-50;
|
||||
padding: 4px 10px;
|
||||
color: $gray-300;
|
||||
white-space: nowrap;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
import { mapState, mapGetters } from 'client/libs/store';
|
||||
import moment from 'moment';
|
||||
|
||||
import positiveIcon from 'assets/svg/positive.svg';
|
||||
import negativeIcon from 'assets/svg/negative.svg';
|
||||
import goldIcon from 'assets/svg/gold.svg';
|
||||
import streakIcon from 'assets/svg/streak.svg';
|
||||
import calendarIcon from 'assets/svg/calendar.svg';
|
||||
import challengeIcon from 'assets/svg/challenge.svg';
|
||||
import tagsIcon from 'assets/svg/tags.svg';
|
||||
import checkIcon from 'assets/svg/check.svg';
|
||||
import bPopover from 'bootstrap-vue/lib/components/popover';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
bPopover,
|
||||
},
|
||||
props: ['task'],
|
||||
data () {
|
||||
return {
|
||||
icons: Object.freeze({
|
||||
positive: positiveIcon,
|
||||
negative: negativeIcon,
|
||||
gold: goldIcon,
|
||||
streak: streakIcon,
|
||||
calendar: calendarIcon,
|
||||
challenge: challengeIcon,
|
||||
tags: tagsIcon,
|
||||
check: checkIcon,
|
||||
}),
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
...mapState({user: 'user.data'}),
|
||||
...mapGetters({
|
||||
getTagsFor: 'tasks:getTagsFor',
|
||||
getTaskClasses: 'tasks:getTaskClasses',
|
||||
}),
|
||||
leftControl () {
|
||||
const task = this.task;
|
||||
if (task.type === 'reward') return false;
|
||||
return true;
|
||||
},
|
||||
rightControl () {
|
||||
const task = this.task;
|
||||
if (task.type === 'reward') return true;
|
||||
if (task.type === 'habit') return true;
|
||||
return false;
|
||||
},
|
||||
controlClass () {
|
||||
return this.getTaskClasses(this.task, 'control');
|
||||
},
|
||||
contentClass () {
|
||||
return this.getTaskClasses(this.task, 'content');
|
||||
},
|
||||
showStreak () {
|
||||
if (this.task.streak !== undefined) return true;
|
||||
if (this.task.type === 'habit' && (this.task.up || this.task.down)) return true;
|
||||
return false;
|
||||
},
|
||||
isDueOverdue () {
|
||||
return moment().diff(this.task.date, 'days') >= 0;
|
||||
},
|
||||
dueIn () {
|
||||
const dueIn = moment().to(this.task.date);
|
||||
return this.$t('dueIn', {dueIn});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
@@ -0,0 +1,56 @@
|
||||
<template lang="pug">
|
||||
.row.user-tasks-page
|
||||
.col-12
|
||||
.row.tasks-navigation
|
||||
.col-4.offset-4
|
||||
input.form-control.input-search(type="text", :placeholder="$t('search')")
|
||||
.col-1.offset-3
|
||||
button.btn.btn-success(v-once)
|
||||
.svg-icon.positive(v-html="icons.positive")
|
||||
| {{ $t('create') }}
|
||||
.row.tasks-columns
|
||||
task-column.col-3(v-for="column in columns", :type="column", :key="column", :isUser="true")
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import '~client/assets/scss/colors.scss';
|
||||
|
||||
.user-tasks-page {
|
||||
padding-top: 31px;
|
||||
}
|
||||
|
||||
.tasks-navigation {
|
||||
margin-bottom: 40px;
|
||||
}
|
||||
|
||||
.positive {
|
||||
display: inline-block;
|
||||
width: 10px;
|
||||
color: $green-500;
|
||||
margin-right: 8px;
|
||||
padding-top: 6px;
|
||||
}
|
||||
|
||||
.tasks-columns {
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
import Column from './column';
|
||||
import positiveIcon from 'assets/svg/positive.svg';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
TaskColumn: Column,
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
columns: ['habit', 'daily', 'todo', 'reward'],
|
||||
icons: Object.freeze({
|
||||
positive: positiveIcon,
|
||||
}),
|
||||
};
|
||||
},
|
||||
};
|
||||
</script>
|
||||
@@ -4,8 +4,9 @@
|
||||
.toggle-switch.float-left
|
||||
input.toggle-switch-checkbox(
|
||||
type='checkbox', :id="id",
|
||||
@change="$emit('change', $event.target.checked)",
|
||||
:checked="checked",
|
||||
@change="handleChange",
|
||||
:checked="isChecked",
|
||||
:value="value",
|
||||
)
|
||||
label.toggle-switch-label(:for="id")
|
||||
span.toggle-switch-inner
|
||||
@@ -13,88 +14,88 @@
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import '~client/assets/scss/colors.scss';
|
||||
@import '~client/assets/scss/colors.scss';
|
||||
|
||||
.toggle-switch-container {
|
||||
margin-top: 6px;
|
||||
}
|
||||
.toggle-switch-container {
|
||||
margin-top: 6px;
|
||||
}
|
||||
|
||||
.toggle-switch {
|
||||
position: relative;
|
||||
width: 40px;
|
||||
user-select: none;
|
||||
margin-left: 9px;
|
||||
}
|
||||
.toggle-switch {
|
||||
position: relative;
|
||||
width: 40px;
|
||||
user-select: none;
|
||||
margin-left: 9px;
|
||||
}
|
||||
|
||||
.toggle-switch-description {
|
||||
height: 20px;
|
||||
border-bottom: 1px dashed $gray-200;
|
||||
}
|
||||
.toggle-switch-description {
|
||||
height: 20px;
|
||||
border-bottom: 1px dashed $gray-200;
|
||||
}
|
||||
|
||||
.toggle-switch-checkbox {
|
||||
display: none;
|
||||
}
|
||||
.toggle-switch-checkbox {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.toggle-switch-label {
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
cursor: pointer;
|
||||
border-radius: 100px;
|
||||
margin-bottom: 0px;
|
||||
margin-top: 3px;
|
||||
}
|
||||
.toggle-switch-label {
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
cursor: pointer;
|
||||
border-radius: 100px;
|
||||
margin-bottom: 0px;
|
||||
margin-top: 3px;
|
||||
}
|
||||
|
||||
.toggle-switch-inner {
|
||||
display: block;
|
||||
width: 200%;
|
||||
margin-left: -100%;
|
||||
transition: margin 0.3s ease-in 0s;
|
||||
}
|
||||
.toggle-switch-inner {
|
||||
display: block;
|
||||
width: 200%;
|
||||
margin-left: -100%;
|
||||
transition: margin 0.3s ease-in 0s;
|
||||
}
|
||||
|
||||
.toggle-switch-inner:before, .toggle-switch-inner:after {
|
||||
display: block;
|
||||
float: left;
|
||||
width: 50%;
|
||||
height: 16px;
|
||||
padding: 0;
|
||||
}
|
||||
.toggle-switch-inner:before, .toggle-switch-inner:after {
|
||||
display: block;
|
||||
float: left;
|
||||
width: 50%;
|
||||
height: 16px;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.toggle-switch-inner:before {
|
||||
content: "";
|
||||
padding-left: 10px;
|
||||
background-color: $purple-400;
|
||||
}
|
||||
.toggle-switch-inner:before {
|
||||
content: "";
|
||||
padding-left: 10px;
|
||||
background-color: $purple-400;
|
||||
}
|
||||
|
||||
.toggle-switch-inner:after {
|
||||
content: "";
|
||||
padding-right: 10px;
|
||||
background-color: $gray-200;
|
||||
text-align: right;
|
||||
}
|
||||
.toggle-switch-inner:after {
|
||||
content: "";
|
||||
padding-right: 10px;
|
||||
background-color: $gray-200;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.toggle-switch-switch {
|
||||
box-shadow: 0 1px 2px 0 rgba($black, 0.32);
|
||||
display: block;
|
||||
width: 20px;
|
||||
margin: -2px;
|
||||
margin-top: 1px;
|
||||
height: 20px;
|
||||
background: $white;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
right: 22px;
|
||||
border-radius: 100px;
|
||||
transition: all 0.3s ease-in 0s;
|
||||
}
|
||||
.toggle-switch-switch {
|
||||
box-shadow: 0 1px 2px 0 rgba($black, 0.32);
|
||||
display: block;
|
||||
width: 20px;
|
||||
margin: -2px;
|
||||
margin-top: 1px;
|
||||
height: 20px;
|
||||
background: $white;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
right: 22px;
|
||||
border-radius: 100px;
|
||||
transition: all 0.3s ease-in 0s;
|
||||
}
|
||||
|
||||
.toggle-switch-checkbox:checked + .toggle-switch-label .toggle-switch-inner {
|
||||
margin-left: 0;
|
||||
}
|
||||
.toggle-switch-checkbox:checked + .toggle-switch-label .toggle-switch-inner {
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
.toggle-switch-checkbox:checked + .toggle-switch-label .toggle-switch-switch {
|
||||
right: 0px;
|
||||
}
|
||||
.toggle-switch-checkbox:checked + .toggle-switch-label .toggle-switch-switch {
|
||||
right: 0px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
@@ -105,7 +106,14 @@ export default {
|
||||
id: Math.random(),
|
||||
};
|
||||
},
|
||||
model: {
|
||||
prop: 'checked',
|
||||
event: 'change',
|
||||
},
|
||||
props: {
|
||||
value: {
|
||||
default: true,
|
||||
},
|
||||
label: {
|
||||
type: String,
|
||||
required: true,
|
||||
@@ -115,5 +123,15 @@ export default {
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
isChecked () {
|
||||
return this.checked === this.value;
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
handleChange ({ target: { checked } }) {
|
||||
this.$emit('change', checked ? this.value : this.uncheckedValue);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
@@ -1,163 +0,0 @@
|
||||
<template lang="pug">
|
||||
.row
|
||||
.col-12
|
||||
.row
|
||||
.col-3.p-4
|
||||
h3 Input
|
||||
input.form-control(type="text", placeholder="Placeholder")
|
||||
.col-3.p-4
|
||||
h3 Input Disabled
|
||||
input.form-control(type="text", placeholder="Placeholder", disabled)
|
||||
.col-3.p-4
|
||||
h3 Input With Icon
|
||||
input.form-control.input-search(type="text", placeholder="Placeholder")
|
||||
.col-3.p-4
|
||||
h3 Input With Icon Disabled
|
||||
input.form-control.input-search(type="text", placeholder="Placeholder", disabled)
|
||||
.col-3.p-4
|
||||
h3 Input Valid
|
||||
input.form-control.input-valid(type="text", placeholder="Placeholder")
|
||||
.col-3.p-4
|
||||
h3 Input Invalid
|
||||
input.form-control.input-invalid(type="text", placeholder="Placeholder")
|
||||
.row
|
||||
.col-6.p-4
|
||||
h3 Textarea
|
||||
textarea.form-control(rows="5", cols="50")
|
||||
.col-6.p-4
|
||||
h3 Textarea Disabled
|
||||
textarea.form-control(disabled, rows="10", cols="50")
|
||||
.row
|
||||
.col-2.p-4
|
||||
toggleSwitch(label="Toggle Switch")
|
||||
.row
|
||||
.col-3.p-4
|
||||
h3 Checkbox
|
||||
label.custom-control.custom-checkbox
|
||||
input.custom-control-input(type='checkbox')
|
||||
span.custom-control-indicator
|
||||
span.custom-control-description Check this custom checkbox
|
||||
.col-3.p-4
|
||||
h3 Checkbox Disabled Checked
|
||||
label.custom-control.custom-checkbox
|
||||
input.custom-control-input(type='checkbox', disabled, checked)
|
||||
span.custom-control-indicator
|
||||
span.custom-control-description Check this custom checkbox
|
||||
.col-3.p-4
|
||||
h3 Checkbox Disabled Not Checked
|
||||
label.custom-control.custom-checkbox
|
||||
input.custom-control-input(type='checkbox', disabled)
|
||||
span.custom-control-indicator
|
||||
span.custom-control-description Check this custom checkbox
|
||||
.col-6.p-4
|
||||
h3 Radio Button
|
||||
form
|
||||
label.custom-control.custom-radio
|
||||
input#radio1.custom-control-input(name='radio', type='radio')
|
||||
span.custom-control-indicator
|
||||
span.custom-control-description Toggle this custom radio
|
||||
label.custom-control.custom-radio
|
||||
input#radio2.custom-control-input(name='radio', type='radio')
|
||||
span.custom-control-indicator
|
||||
span.custom-control-description Toggle this custom radio
|
||||
.col-3.p-4
|
||||
h3 Radio Button Disabled Checked
|
||||
form
|
||||
label.custom-control.custom-radio
|
||||
input#radio3.custom-control-input(name='radio', type='radio', disabled, checked)
|
||||
span.custom-control-indicator
|
||||
span.custom-control-description Toggle this custom radio
|
||||
.col-3.p-4
|
||||
h3 Radio Button Disabled Not Checked
|
||||
form
|
||||
label.custom-control.custom-radio
|
||||
input#radio3.custom-control-input(name='radio', type='radio', disabled)
|
||||
span.custom-control-indicator
|
||||
span.custom-control-description Toggle this custom radio
|
||||
.row
|
||||
.col-3.p-4
|
||||
h3 Main Button
|
||||
button.btn.btn-primary Button
|
||||
.col-3.p-4
|
||||
h3 Secondary Button
|
||||
button.btn.btn-secondary Button
|
||||
.col-3.p-4
|
||||
h3 Green Button
|
||||
button.btn.btn-success Button
|
||||
.col-3.p-4
|
||||
h3 Blue Button
|
||||
button.btn.btn-info Button
|
||||
.col-3.p-4
|
||||
h3 Red Button
|
||||
button.btn.btn-danger Button
|
||||
.row
|
||||
.col-3.p-4
|
||||
h3 Main Button Disabled
|
||||
button.btn.btn-primary(disabled=true) Button
|
||||
.col-3.p-4
|
||||
h3 Secondary Button Disabled
|
||||
button.btn.btn-secondary(disabled=true) Button
|
||||
.col-3.p-4
|
||||
h3 Green Button Disabled
|
||||
button.btn.btn-success(disabled=true) Button
|
||||
.col-3.p-4
|
||||
h3 Blue Button Disabled
|
||||
button.btn.btn-info(disabled=true) Button
|
||||
.col-3.p-4
|
||||
h3 Red Button Disabled
|
||||
button.btn.btn-danger(disabled=true) Button
|
||||
.row
|
||||
.col-6.p-4
|
||||
h3 Dropdown Menu
|
||||
b-dropdown(text="Menu", right=false)
|
||||
b-dropdown-item(href="#") Menu item 1
|
||||
b-dropdown-item(href="#") Menu item 2
|
||||
b-dropdown-item(href="#") Menu item 3
|
||||
b-dropdown-item(href="#") Menu item 4
|
||||
.col-6.p-4
|
||||
h3 Dropdown Menu Disabled
|
||||
b-dropdown(text="Menu", disabled)
|
||||
b-dropdown-item(href="#") Menu item 1
|
||||
b-dropdown-item(href="#") Menu item 2
|
||||
b-dropdown-item(href="#") Menu item 3
|
||||
b-dropdown-item(href="#") Menu item 4
|
||||
.row
|
||||
.col-6.p-4
|
||||
h1 Heading 1
|
||||
h2 Heading 2
|
||||
h3 Heading 3
|
||||
h4 Heading 4
|
||||
.col-6.p-4
|
||||
p Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam vehicula, purus sit amet sodales pharetra, ipsum ipsum mollis orci, id pharetra velit diam et dui. Sed placerat ipsum eget pharetra rutrum. Ut vitae rutrum lacus, eu imperdiet velit. Pellentesque eu velit cursus, scelerisque dui quis, dapibus magna. Vestibulum molestie sed sapien et ultricies. Nam porta ipsum leo, non congue magna vestibulum a. Etiam dictum felis sit amet augue varius tincidunt. Sed eget urna auctor, convallis felis in, pretium justo. Curabitur aliquet, ligula id tincidunt ullamcorper, orci lorem pharetra neque, in ornare arcu magna accumsan arcu. Maecenas dignissim lorem sed eros accumsan scelerisque.
|
||||
p.small-text Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam vehicula, purus sit amet sodales pharetra, ipsum ipsum mollis orci, id pharetra velit diam et dui.
|
||||
.row
|
||||
.col(v-for="taskType in tasksTypes")
|
||||
h3 {{taskType}}s
|
||||
ul
|
||||
task(v-for="task in tasks", v-if="task.type === taskType", :key="task.id", :task="task")
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Task from './task';
|
||||
import { mapState } from 'client/libs/store';
|
||||
import bDropdown from 'bootstrap-vue/lib/components/dropdown';
|
||||
import bDropdownItem from 'bootstrap-vue/lib/components/dropdown-item';
|
||||
import toggleSwitch from 'client/components/ui/toggleSwitch';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
Task,
|
||||
bDropdown,
|
||||
bDropdownItem,
|
||||
toggleSwitch,
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
tasksTypes: ['habit', 'daily', 'todo', 'reward'],
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
...mapState({tasks: 'tasks.data'}),
|
||||
},
|
||||
};
|
||||
</script>
|
||||
Reference in New Issue
Block a user