Merge branch 'develop' into release

This commit is contained in:
SabreCat 2018-01-04 21:11:44 +00:00
commit 40244ab81b
79 changed files with 5551 additions and 5278 deletions

View file

@ -7,7 +7,7 @@ const HtmlWebpackPlugin = require('html-webpack-plugin');
// add hot-reload related code to entry chunks
Object.keys(baseWebpackConfig.entry).forEach((name) => {
baseWebpackConfig.entry[name] = ['./webpack/dev-client'].concat(baseWebpackConfig.entry[name]);
baseWebpackConfig.entry[name] = baseWebpackConfig.entry[name].concat('./webpack/dev-client');
});
module.exports = merge(baseWebpackConfig, {

View file

@ -49,6 +49,10 @@ div
margin-bottom: 1em;
}
.row {
width: 100%;
}
h2 {
color: #fff;
font-size: 32px;
@ -389,7 +393,14 @@ export default {
}
},
async memberSelected (member) {
this.$store.dispatch('user:castSpell', {key: this.selectedSpellToBuy.key, targetId: member.id});
let castResult = await this.$store.dispatch('user:castSpell', {key: this.selectedSpellToBuy.key, targetId: member.id});
// Subtract gold for cards
if (this.selectedSpellToBuy.pinType === 'card') {
const newUserGp = castResult.data.data.user.stats.gp;
this.$store.state.user.data.stats.gp = newUserGp;
}
this.selectedSpellToBuy = null;
if (this.user.party._id) {

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 366 KiB

After

Width:  |  Height:  |  Size: 363 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 163 KiB

After

Width:  |  Height:  |  Size: 165 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 152 KiB

After

Width:  |  Height:  |  Size: 155 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 131 KiB

After

Width:  |  Height:  |  Size: 131 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 164 KiB

After

Width:  |  Height:  |  Size: 165 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 136 KiB

After

Width:  |  Height:  |  Size: 137 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 143 KiB

After

Width:  |  Height:  |  Size: 142 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 155 KiB

After

Width:  |  Height:  |  Size: 156 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 176 KiB

After

Width:  |  Height:  |  Size: 175 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 161 KiB

After

Width:  |  Height:  |  Size: 159 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 116 KiB

After

Width:  |  Height:  |  Size: 118 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 262 KiB

After

Width:  |  Height:  |  Size: 262 KiB

View file

@ -223,6 +223,7 @@
.svg-icon {
width: 10px;
height: 10px;
margin: 0 auto;
}

View file

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="12" viewBox="0 0 14 12">
<path fill-rule="evenodd" d="M2 7.05V3.954l4.873 2.872-4.291.715A.5.5 0 0 1 2 7.05zm8-1.108L3.83 2.306 10 3.334v2.608zm2.329-4.248l-.024-.004c-.007-.002-.012-.007-.02-.009-.017-.005-.035.001-.052-.003L2.329.028A2 2 0 0 0 0 2v5.64a2 2 0 0 0 2.329 1.972l7.056-1.176-.525 2.1a1.175 1.175 0 0 0 2.28.57l.772-3.09.417-.07A2 2 0 0 0 14 5.971V3.667a2 2 0 0 0-1.671-1.973z"/>
</svg>

After

Width:  |  Height:  |  Size: 463 B

View file

@ -69,8 +69,8 @@
a.social-circle(href='https://www.facebook.com/Habitica', target='_blank')
.social-icon.facebook.svg-icon(v-html='icons.facebook')
.row
.col-10 {{ $t('donateText3') }}
.col-2
.col-12.col-md-10 {{ $t('donateText3') }}
.col-12.col-md-2
button.btn.btn-contribute(@click="donate()", v-if="user")
.svg-icon.heart(v-html="icons.heart")
.text {{ $t('companyDonate') }}
@ -82,7 +82,7 @@
.col-12
hr
.row
.col-5
.col-12.col-md-5
| © 2017 Habitica. All rights reserved.
.debug.float-left(v-if="!IS_PRODUCTION && isUserLoaded")
button.btn.btn-primary(@click="debugMenuShown = !debugMenuShown") Toggle Debug Menu
@ -102,9 +102,9 @@
a.btn.btn-default(@click="addQuestProgress()", tooltip="+1000 to boss quests. 300 items to collection quests") Quest Progress Up
a.btn.btn-default(@click="makeAdmin()") Make Admin
a.btn.btn-default(@click="openModifyInventoryModal()") Modify Inventory
.col-2.text-center
.col-12.col-md-2.text-center
.logo.svg-icon(v-html='icons.gryphon')
.col-5.text-right
.col-12.col-md-5.text-right
template(v-if="!isExpandedFooter")
span
a(:href="getDataDisplayToolUrl", target='_blank') {{ $t('dataDisplayTool') }}

View file

@ -4,8 +4,8 @@
.seamless_stars_varied_opacity_repeat
form#login-form(
@submit.prevent='handleSubmit',
@keyup.enter="handleSubmit",
@submit.prevent='handleSubmit',
@keyup.enter="handleSubmit",
v-if="!forgotPassword && !resetPasswordSetNewOne",
)
.text-center
@ -14,11 +14,11 @@
div
.svg-icon.habitica-logo(v-html="icons.habiticaIcon")
.form-group.row.text-center
.col-6
.col-12.col-md-6
.btn.btn-secondary.social-button(@click='socialAuth("facebook")')
.svg-icon.social-icon(v-html="icons.facebookIcon")
.text {{registering ? $t('signUpWithSocial', {social: 'Facebook'}) : $t('loginWithSocial', {social: 'Facebook'})}}
.col-6
.col-12.col-md-6
.btn.btn-secondary.social-button(@click='socialAuth("google")')
.svg-icon.social-icon(v-html="icons.googleIcon")
span {{registering ? $t('signUpWithSocial', {social: 'Google'}) : $t('loginWithSocial', {social: 'Google'})}}
@ -79,7 +79,7 @@
input#confirmPasswordInput.form-control(type='password', :placeholder='$t("confirmPasswordPlaceholder")', v-model='passwordConfirm')
.text-center
.btn.btn-info(
@click='resetPasswordSetNewOneLink()',
@click='resetPasswordSetNewOneLink()',
:enabled="!resetPasswordSetNewOneData.hasError"
) {{$t('setNewPass')}}
@ -121,6 +121,17 @@
}
}
@media only screen and (max-width: 768px) {
#login-form {
width: 100% !important;
}
.form-group {
padding-left: .5em;
padding-right: .5em;
}
}
.form-wrapper {
background-color: $purple-200;
background: $purple-200; /* For browsers that do not support gradients */

View file

@ -4,10 +4,9 @@
leave-challenge-modal(:challengeId='challenge._id')
close-challenge-modal(:members='members', :challengeId='challenge._id')
challenge-member-progress-modal(:memberId='progressMemberId', :challengeId='challenge._id')
.col-8.standard-page
.col-12.col-md-8.standard-page
.row
.col-8
.col-12.col-md-8
h1(v-markdown='challenge.name')
div
strong(v-once) {{$t('createdBy')}}:
@ -20,7 +19,7 @@
// span {{challenge.endDate}}
.tags
span.tag(v-for='tag in challenge.tags') {{tag}}
.col-4
.col-12.col-md-4
.box(@click="showMemberModal()")
.svg-icon.member-icon(v-html="icons.memberIcon")
| {{challenge.memberCount}}
@ -30,7 +29,7 @@
| {{challenge.prize}}
.details(v-once) {{$t('prize')}}
.row.challenge-actions
.col-7.offset-5
.col-12.col-md-7.offset-md-5
span.view-progress
strong {{ $t('viewProgressOf') }}
member-search-dropdown(:text="$t('selectParticipant')", :members='members', :challengeId='challengeId', @member-selected='openMemberProgressModal')
@ -56,7 +55,7 @@
:taskListOverride='tasksByType[column]',
v-on:editTask="editTask",
v-if='tasksByType[column].length > 0')
.col-4.sidebar.standard-page
.col-12.col-md-4.sidebar.standard-page
.acitons
div(v-if='canJoin')
button.btn.btn-success(v-once, @click='joinChallenge()') {{$t('joinChallenge')}}

View file

@ -2,8 +2,7 @@
.row
challenge-modal(v-on:createChallenge='challengeCreated')
sidebar(v-on:search="updateSearch", v-on:filter="updateFilters")
.col-10.standard-page
.col-12.col-md-10.standard-page
.row.header-row
.col-md-8.text-left
h1(v-once) {{$t('findChallenges')}}

View file

@ -2,7 +2,6 @@
.standard-sidebar.d-none.d-sm-block
.form-group
input.form-control.search(type="text", :placeholder="$t('search')", v-model='searchTerm')
form
h2(v-once) {{ $t('filter') }}
.form-group

View file

@ -57,10 +57,19 @@ export default {
this.currentSearchPosition = newText.length - 1;
},
chat () {
this.resetDefaults();
this.grabUserNames();
},
},
methods: {
resetDefaults () {
// Mounted is not called when switching between group pages because they have the
// the same parent component. So, reset the data
this.currentSearch = '';
this.searchActive = false;
this.currentSearchPosition = 0;
this.tmpSelections = [];
},
grabUserNames () {
let usersThatMessage = groupBy(this.chat, 'user');
for (let userName in usersThatMessage) {

View file

@ -0,0 +1,276 @@
<template lang="pug">
div
.mentioned-icon(v-if='isUserMentioned')
.message-hidden(v-if='msg.flagCount === 1 && user.contributor.admin') Message flagged once, not hidden
.message-hidden(v-if='msg.flagCount > 1 && user.contributor.admin') Message hidden
.card-body
h3.leader(
:class='userLevelStyle(msg)',
@click="showMemberModal(msg.uuid)",
v-b-tooltip.hover.top="('contributor' in msg) ? msg.contributor.text : ''",
)
| {{msg.user}}
.svg-icon(v-html="tierIcon", v-if='showShowTierStyle')
p.time {{msg.timestamp | timeAgo}}
.text(v-markdown='msg.text')
hr
.action(@click='like()', v-if='msg.likes', :class='{active: msg.likes[user._id]}')
.svg-icon(v-html="icons.like")
span(v-if='!msg.likes[user._id]') {{ $t('like') }}
span(v-if='msg.likes[user._id]') {{ $t('liked') }}
// @TODO make copyAsTodo work in Tavern, guilds, party (inbox can be done later)
span.action(v-if='!inbox', @click='copyAsTodo(msg)')
.svg-icon(v-html="icons.copy")
| {{$t('copyAsTodo')}}
// @TODO make copyAsTodo work in the inbox
span.action(v-if='!inbox && user.flags.communityGuidelinesAccepted && msg.uuid !== "system"', @click='report(msg)')
.svg-icon(v-html="icons.report")
| {{$t('report')}}
// @TODO make flagging/reporting work in the inbox. NOTE: it must work even if the communityGuidelines are not accepted and it MUST work for messages that you have SENT as well as received. -- Alys
span.action(v-if='msg.uuid === user._id || inbox || user.contributor.admin', @click='remove()')
.svg-icon(v-html="icons.delete")
| {{$t('delete')}}
span.action.float-right.liked(v-if='likeCount > 0')
.svg-icon(v-html="icons.liked")
| + {{ likeCount }}
</template>
<style lang="scss" scoped>
@import '~client/assets/scss/tiers.scss';
.mentioned-icon {
width: 16px;
height: 16px;
border-radius: 50%;
background-color: #bda8ff;
box-shadow: 0 1px 1px 0 rgba(26, 24, 29, 0.12);
position: absolute;
right: -.5em;
top: -.5em;
}
.message-hidden {
margin-left: 1.5em;
margin-top: 1em;
color: red;
}
.card-body {
.leader {
margin-bottom: 0;
}
h3 { // this is the user name
cursor: pointer;
display: inline-block;
.svg-icon {
width: 10px;
display: inline-block;
margin-left: .5em;
}
}
.time {
font-size: 12px;
color: #878190;
}
.text {
font-size: 14px;
color: #4e4a57;
text-align: left !important;
}
}
.action {
display: inline-block;
color: #878190;
margin-right: 1em;
}
.action:hover {
cursor: pointer;
}
.liked:hover {
cursor: default;
}
.action .svg-icon {
margin-right: .2em;
width: 16px;
display: inline-block;
color: #A5A1AC;
}
.action.active, .active .svg-icon {
color: #46a7d9
}
</style>
<script>
import axios from 'axios';
import moment from 'moment';
import cloneDeep from 'lodash/cloneDeep';
import escapeRegExp from 'lodash/escapeRegExp';
import markdownDirective from 'client/directives/markdown';
import { mapState } from 'client/libs/store';
import styleHelper from 'client/mixins/styleHelper';
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 tier1 from 'assets/svg/tier-1.svg';
import tier2 from 'assets/svg/tier-2.svg';
import tier3 from 'assets/svg/tier-3.svg';
import tier4 from 'assets/svg/tier-4.svg';
import tier5 from 'assets/svg/tier-5.svg';
import tier6 from 'assets/svg/tier-6.svg';
import tier7 from 'assets/svg/tier-7.svg';
import tier8 from 'assets/svg/tier-mod.svg';
import tier9 from 'assets/svg/tier-staff.svg';
import tierNPC from 'assets/svg/tier-npc.svg';
export default {
props: ['msg', 'inbox', 'groupId'],
mixins: [styleHelper],
data () {
return {
copyingMessage: {},
icons: Object.freeze({
like: likeIcon,
copy: copyIcon,
report: reportIcon,
delete: deleteIcon,
liked: likedIcon,
tier1,
tier2,
tier3,
tier4,
tier5,
tier6,
tier7,
tier8,
tier9,
tierNPC,
}),
};
},
directives: {
markdown: markdownDirective,
},
filters: {
timeAgo (value) {
return moment(value).fromNow();
},
date (value) {
// @TODO: Add user preference
return moment(value).toDate();
},
},
computed: {
...mapState({user: 'user.data'}),
isUserMentioned () {
const message = this.msg;
let user = this.user;
if (message.hasOwnProperty('highlight')) return message.highlight;
message.highlight = false;
let messagetext = message.text.toLowerCase();
let username = user.profile.name;
let mentioned = messagetext.indexOf(username.toLowerCase());
let escapedUsername = escapeRegExp(username);
let pattern = `@${escapedUsername}([^\w]|$){1}`;
if (mentioned === -1) return message.highlight;
let preceedingchar = messagetext.substring(mentioned - 1, mentioned);
if (mentioned === 0 || preceedingchar.trim() === '' || preceedingchar === '@') {
let regex = new RegExp(pattern, 'i');
message.highlight = regex.test(messagetext);
}
return message.highlight;
},
likeCount () {
const message = this.msg;
if (!message.likes) return 0;
let likeCount = 0;
for (let key in message.likes) {
let like = message.likes[key];
if (like) likeCount += 1;
}
return likeCount;
},
showShowTierStyle () {
const message = this.msg;
const isContributor = Boolean(message.contributor && message.contributor.level);
const isNPC = Boolean(message.backer && message.backer.npc);
return isContributor || isNPC;
},
tierIcon () {
const message = this.msg;
const isNPC = Boolean(message.backer && message.backer.npc);
if (isNPC) {
return this.icons.tierNPC;
}
return this.icons[`tier${message.contributor.level}`];
},
},
methods: {
async like () {
let message = cloneDeep(this.msg);
await this.$store.dispatch('chat:like', {
groupId: this.groupId,
chatId: message.id,
});
if (!message.likes[this.user._id]) {
message.likes[this.user._id] = true;
} else {
message.likes[this.user._id] = !message.likes[this.user._id];
}
this.$emit('messaged-liked', message);
},
copyAsTodo (message) {
// @TODO: Move to Habitica Event
this.copyingMessage = message;
this.$root.$emit('bv::show::modal', 'copyAsTodo');
},
async report () {
this.$root.$emit('habitica::report-chat', {
message: this.msg,
groupId: this.groupId,
});
},
async remove () {
if (!confirm(this.$t('areYouSureDeleteMessage'))) return;
const message = this.msg;
this.$emit('message-removed', message);
if (this.inbox) {
axios.delete(`/api/v3/user/messages/${message.id}`);
this.$delete(this.user.inbox.messages, message.id);
return;
}
await this.$store.dispatch('chat:deleteChat', {
groupId: this.groupId,
chatId: message.id,
});
},
showMemberModal (memberId) {
this.$emit('show-member-modal', memberId);
},
},
};
</script>

View file

@ -2,9 +2,8 @@
.container
.row
.col-12
copy-as-todo-modal(:copying-message='copyingMessage', :group-name='groupName', :group-id='groupId')
copy-as-todo-modal(:group-name='groupName', :group-id='groupId')
report-flag-modal
div(v-for="(msg, index) in messages", v-if='chat && canViewFlag(msg)')
// @TODO: is there a different way to do these conditionals? This creates an infinite loop
//.hr(v-if='displayDivider(msg)')
@ -19,78 +18,22 @@
@click.native="showMemberModal(msg.uuid)",
)
.card(:class='inbox ? "col-8" : "col-10"')
.mentioned-icon(v-if='isUserMentioned(msg)')
.message-hidden(v-if='msg.flagCount === 1 && user.contributor.admin') Message flagged once, not hidden
.message-hidden(v-if='msg.flagCount > 1 && user.contributor.admin') Message hidden
.card-body
h3.leader(
:class='userLevelStyle(msg)',
@click="showMemberModal(msg.uuid)",
v-b-tooltip.hover.top="('contributor' in msg) ? msg.contributor.text : ''",
)
| {{msg.user}}
.svg-icon(v-html="getTierIcon(msg)", v-if='showShowTierStyle(msg)')
p.time {{msg.timestamp | timeAgo}}
.text(v-markdown='msg.text')
hr
.action(@click='like(msg, index)', v-if='msg.likes', :class='{active: msg.likes[user._id]}')
.svg-icon(v-html="icons.like")
span(v-if='!msg.likes[user._id]') {{ $t('like') }}
span(v-if='msg.likes[user._id]') {{ $t('liked') }}
// @TODO make copyAsTodo work in Tavern, guilds, party (inbox can be done later)
span.action(v-if='!inbox', @click='copyAsTodo(msg)')
.svg-icon(v-html="icons.copy")
| {{$t('copyAsTodo')}}
// @TODO make copyAsTodo work in the inbox
span.action(v-if='!inbox && user.flags.communityGuidelinesAccepted && msg.uuid !== "system"', @click='report(msg)')
.svg-icon(v-html="icons.report")
| {{$t('report')}}
// @TODO make flagging/reporting work in the inbox. NOTE: it must work even if the communityGuidelines are not accepted and it MUST work for messages that you have SENT as well as received. -- Alys
span.action(v-if='msg.uuid === user._id || inbox || user.contributor.admin', @click='remove(msg, index)')
.svg-icon(v-html="icons.delete")
| {{$t('delete')}}
span.action.float-right.liked(v-if='likeCount(msg) > 0')
.svg-icon(v-html="icons.liked")
| + {{ likeCount(msg) }}
// @TODO can we avoid duplicating all this code? Cannot we just push everything
// to the right if the user is the author?
// Maybe we just create two sub components instead
chat-card(
:msg='msg',
:inbox='inbox',
:groupId='groupId',
@messaged-liked='messageLiked',
@message-removed='messageRemoved',
@show-member-modal='showMemberModal')
.row(v-if='user._id === msg.uuid')
.card(:class='inbox ? "col-8" : "col-10"')
.mentioned-icon(v-if='isUserMentioned(msg)')
.message-hidden(v-if='msg.flagCount === 1 && user.contributor.admin') Message flagged once, not hidden
.message-hidden(v-if='msg.flagCount > 1 && user.contributor.admin') Message hidden
.card-body
h3.leader(
:class='userLevelStyle(msg)',
@click="showMemberModal(msg.uuid)",
v-b-tooltip.hover.top="('contributor' in msg) ? msg.contributor.text : ''",
)
| {{msg.user}}
.svg-icon(v-html="getTierIcon(msg)", v-if='showShowTierStyle(msg)')
p.time {{msg.timestamp | timeAgo}}
.text(v-markdown='msg.text')
hr
.action(@click='like(msg, index)', v-if='msg.likes', :class='{active: msg.likes[user._id]}')
.svg-icon(v-html="icons.like")
span(v-if='!msg.likes[user._id]') {{ $t('like') }}
span(v-if='msg.likes[user._id]') {{ $t('liked') }}
// @TODO make copyAsTodo work in Tavern, guilds, party (inbox can be done later)
span.action(v-if='!inbox', @click='copyAsTodo(msg)')
.svg-icon(v-html="icons.copy")
| {{$t('copyAsTodo')}}
// @TODO make copyAsTodo work in the inbox
span.action(v-if='user.flags.communityGuidelinesAccepted', @click='report(msg)')
span.action(v-if='!inbox && user.flags.communityGuidelinesAccepted', @click='report(msg)')
.svg-icon(v-html="icons.report")
| {{$t('report')}}
// @TODO make flagging/reporting work in the inbox. NOTE: it must work even if the communityGuidelines are not accepted and it MUST work for messages that you have SENT as well as received. -- Alys
span.action(v-if='msg.uuid === user._id', @click='remove(msg, index)')
.svg-icon(v-html="icons.delete")
| {{$t('delete')}}
span.action.float-right.liked(v-if='likeCount(msg) > 0')
.svg-icon(v-html="icons.liked")
| + {{ likeCount(msg) }}
chat-card(
:msg='msg',
:inbox='inbox',
:groupId='groupId',
@messaged-liked='messageLiked',
@message-removed='messageRemoved',
@show-member-modal='showMemberModal')
div(:class='inbox ? "col-4" : "col-2"')
avatar(
v-if='cachedProfileData[msg.uuid] && !cachedProfileData[msg.uuid].rejected',
@ -103,38 +46,6 @@
<style lang="scss" scoped>
@import '~client/assets/scss/colors.scss';
@import '~client/assets/scss/tiers.scss';
.leader {
margin-bottom: 0;
}
.time {
font-size: 12px;
color: #878190;
}
.mentioned-icon {
width: 16px;
height: 16px;
border-radius: 50%;
background-color: #bda8ff;
box-shadow: 0 1px 1px 0 rgba(26, 24, 29, 0.12);
position: absolute;
right: -.5em;
top: -.5em;
}
h3 { // this is the user name
cursor: pointer;
display: inline-block;
.svg-icon {
width: 10px;
display: inline-block;
margin-left: .5em;
}
}
.hr {
width: 100%;
@ -161,86 +72,28 @@
.card {
margin-bottom: .5em;
}
.text {
font-size: 14px;
color: #4e4a57;
text-align: left !important;
}
.action {
display: inline-block;
color: #878190;
margin-right: 1em;
}
.action:hover {
cursor: pointer;
}
.liked:hover {
cursor: default;
}
.action .svg-icon {
margin-right: .2em;
width: 16px;
display: inline-block;
color: #A5A1AC;
}
.action.active, .active .svg-icon {
color: #46a7d9
}
.message-hidden {
margin-left: 1.5em;
margin-top: 1em;
color: red;
}
</style>
<script>
import axios from 'axios';
import moment from 'moment';
import cloneDeep from 'lodash/cloneDeep';
import axios from 'axios';
import { mapState } from 'client/libs/store';
import debounce from 'lodash/debounce';
import escapeRegExp from 'lodash/escapeRegExp';
import markdownDirective from 'client/directives/markdown';
import Avatar from '../avatar';
import styleHelper from 'client/mixins/styleHelper';
import findIndex from 'lodash/findIndex';
import Avatar from '../avatar';
import copyAsTodoModal from './copyAsTodoModal';
import reportFlagModal from './reportFlagModal';
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 tier1 from 'assets/svg/tier-1.svg';
import tier2 from 'assets/svg/tier-2.svg';
import tier3 from 'assets/svg/tier-3.svg';
import tier4 from 'assets/svg/tier-4.svg';
import tier5 from 'assets/svg/tier-5.svg';
import tier6 from 'assets/svg/tier-6.svg';
import tier7 from 'assets/svg/tier-7.svg';
import tier8 from 'assets/svg/tier-mod.svg';
import tier9 from 'assets/svg/tier-staff.svg';
import tierNPC from 'assets/svg/tier-npc.svg';
import chatCard from './chatCard';
export default {
props: ['chat', 'groupId', 'groupName', 'inbox'],
mixins: [styleHelper],
components: {
copyAsTodoModal,
reportFlagModal,
chatCard,
Avatar,
},
directives: {
markdown: markdownDirective,
},
mounted () {
this.loadProfileCache();
},
@ -252,24 +105,6 @@ export default {
},
data () {
return {
icons: Object.freeze({
like: likeIcon,
copy: copyIcon,
report: reportIcon,
delete: deleteIcon,
liked: likedIcon,
tier1,
tier2,
tier3,
tier4,
tier5,
tier6,
tier7,
tier8,
tier9,
tierNPC,
}),
copyingMessage: {},
currentDayDividerDisplay: moment().day(),
cachedProfileData: {},
currentProfileLoadedCount: 0,
@ -277,15 +112,6 @@ export default {
loading: false,
};
},
filters: {
timeAgo (value) {
return moment(value).fromNow();
},
date (value) {
// @TODO: Add user preference
return moment(value).toDate();
},
},
computed: {
...mapState({user: 'user.data'}),
// @TODO: We need a different lazy load mechnism.
@ -304,28 +130,6 @@ export default {
handleScroll () {
this.loadProfileCache(window.scrollY / 1000);
},
isUserMentioned (message) {
let user = this.user;
if (message.hasOwnProperty('highlight')) return message.highlight;
message.highlight = false;
let messagetext = message.text.toLowerCase();
let username = user.profile.name;
let mentioned = messagetext.indexOf(username.toLowerCase());
let escapedUsername = escapeRegExp(username);
let pattern = `@${escapedUsername}([^\w]|$){1}`;
if (mentioned === -1) return message.highlight;
let preceedingchar = messagetext.substring(mentioned - 1, mentioned);
if (mentioned === 0 || preceedingchar.trim() === '' || preceedingchar === '@') {
let regex = new RegExp(pattern, 'i');
message.highlight = regex.test(messagetext);
}
return message.highlight;
},
canViewFlag (message) {
if (message.uuid === this.user._id) return true;
if (!message.flagCount || message.flagCount < 2) return true;
@ -381,58 +185,6 @@ export default {
return false;
},
likeCount (message) {
if (!message.likes) return 0;
let likeCount = 0;
for (let key in message.likes) {
let like = message.likes[key];
if (like) likeCount += 1;
}
return likeCount;
},
async like (messageToLike, index) {
let message = cloneDeep(messageToLike);
await this.$store.dispatch('chat:like', {
groupId: this.groupId,
chatId: message.id,
});
if (!message.likes[this.user._id]) {
message.likes[this.user._id] = true;
} else {
message.likes[this.user._id] = !message.likes[this.user._id];
}
this.chat.splice(index, 1, message);
},
copyAsTodo (message) {
this.copyingMessage = message;
this.$root.$emit('bv::show::modal', 'copyAsTodo');
},
async report (message) {
this.$store.state.flagChatOptions.message = message;
this.$store.state.flagChatOptions.groupId = this.groupId;
this.$root.$emit('bv::show::modal', 'report-flag');
},
async remove (message, index) {
if (!confirm(this.$t('areYouSureDeleteMessage'))) return;
this.chat.splice(index, 1);
if (this.inbox) {
axios.delete(`/api/v3/user/messages/${message.id}`);
this.$delete(this.user.inbox.messages, message.id);
return;
}
await this.$store.dispatch('chat:deleteChat', {
groupId: this.groupId,
chatId: message.id,
});
},
showMemberModal (memberId) {
const profile = this.cachedProfileData[memberId];
@ -444,17 +196,17 @@ export default {
});
}
},
showShowTierStyle (message) {
const isContributor = Boolean(message.contributor && message.contributor.level);
const isNPC = Boolean(message.backer && message.backer.npc);
return isContributor || isNPC;
messageLiked (message) {
const chatIndex = findIndex(this.chat, chatMessage => {
return chatMessage.id === message.id;
});
this.chat.splice(chatIndex, 1, message);
},
getTierIcon (message) {
const isNPC = Boolean(message.backer && message.backer.npc);
if (isNPC) {
return this.icons.tierNPC;
}
return this.icons[`tier${message.contributor.level}`];
messageRemoved (message) {
const chatIndex = findIndex(this.chat, chatMessage => {
return chatMessage.id === message.id;
});
this.chat.splice(chatIndex, 1);
},
},
};

View file

@ -33,12 +33,6 @@ export default {
name: `<span class='text-danger'>${reportMessage}</span>`,
};
},
abuseObject () {
return this.$store.state.flagChatOptions.message;
},
groupId () {
return this.$store.state.flagChatOptions.groupId;
},
},
data () {
let abuseFlagModalBody = {
@ -49,8 +43,21 @@ export default {
return {
abuseFlagModalBody,
abuseObject: '',
groupId: '',
};
},
created () {
this.$root.$on('habitica::report-chat', data => {
if (!data.message || !data.groupId) return;
this.abuseObject = data.message;
this.groupId = data.groupId;
this.$root.$emit('bv::show::modal', 'report-flag');
});
},
destroyed () {
this.$root.$off('habitica::report-chat');
},
methods: {
close () {
this.$root.$emit('bv::hide::modal', 'report-flag');

View file

@ -57,6 +57,7 @@ b-modal#create-party-modal(title="Empty", size='lg', hide-footer=true)
.header-wrap {
padding: 0;
color: #4e4a57;
width: 100%;
.quest_screen {
background-image: url('~client/assets/images/quest_screen.png');

View file

@ -7,11 +7,11 @@
group-gems-modal
.col-12.col-sm-8.standard-page
.row
.col-6.title-details
.col-12.col-md-6.title-details
h1 {{group.name}}
strong.float-left(v-once) {{$t('groupLeader')}}
span.leader.float-left(v-if='group.leader.profile', @click='showMemberProfile(group.leader)') : {{group.leader.profile.name}}
.col-6
.col-12.col-md-6
.row.icon-row
.col-4.offset-4(v-bind:class="{ 'offset-8': isParty }")
.item-with-icon(@click="showMemberModal()")
@ -146,6 +146,7 @@
.svg-icon.shield, .svg-icon.gem {
width: 28px;
height: 28px;
margin: 0 auto;
display: inline-block;
vertical-align: bottom;
@ -438,6 +439,14 @@ export default {
},
beforeRouteUpdate (to, from, next) {
this.$set(this, 'searchId', to.params.groupId);
// Reset chat
this.newMessage = '';
this.coords = {
TOP: 0,
LEFT: 0,
};
next();
},
watch: {

View file

@ -60,6 +60,12 @@
}
}
}
@media only screen and (max-width: 768px) {
.no-guilds-wrapper {
width: 100% !important;
}
}
</style>
<script>

View file

@ -11,7 +11,7 @@ div
.view-party.d-flex.align-items-center(
v-if="user.party && user.party._id && partyMembers && partyMembers.length > 1",
)
button.btn.btn-primary(@click='openPartyModal()') {{ $t('viewParty') }}
button.btn.btn-primary.view-party-button(@click='openPartyModal()') {{ $t('viewParty') }}
.party-members.d-flex(
v-if="partyMembers && partyMembers.length > 1",
v-resize="1500",
@ -98,6 +98,12 @@ div
margin-top: 16px;
}
}
@media only screen and (max-width: 768px) {
.view-party-button {
display: none;
}
}
</style>
<script>

View file

@ -215,7 +215,7 @@ export default {
},
watch: {
searchText: throttle(function throttleSearch () {
this.searchTextThrottled = this.searchText;
this.searchTextThrottled = this.searchText.toLowerCase();
}, 250),
},
mounted () {

View file

@ -252,7 +252,7 @@ export default {
},
watch: {
searchText: throttle(function throttleSearch () {
this.searchTextThrottled = this.searchText;
this.searchTextThrottled = this.searchText.toLowerCase();
}, 250),
},
computed: {

View file

@ -270,9 +270,6 @@ export default {
if (this.user.needsCron) return;
this.handleUserNotifications(after);
},
userAchievements () {
this.playSound('Achievement_Unlocked');
},
armoireEmpty (after, before) {
if (after === before || after === false) return;
this.$root.$emit('bv::show::modal', 'armoire-empty');
@ -280,6 +277,7 @@ export default {
questCompleted () {
if (!this.questCompleted) return;
this.$root.$emit('bv::show::modal', 'quest-completed');
this.playSound('Achievement_Unlocked');
},
invitedToQuest (after) {
if (after !== true) return;
@ -326,10 +324,12 @@ export default {
if (this.questCompleted) {
this.$root.$emit('bv::show::modal', 'quest-completed');
this.playSound('Achievement_Unlocked');
}
if (this.userClassSelect) {
this.$root.$emit('bv::show::modal', 'choose-class');
this.playSound('Achievement_Unlocked');
}
},
showLevelUpNotifications (newlevel) {

View file

@ -61,10 +61,10 @@
h1.mb-4.page-header(v-once) {{ $t('market') }}
.clearfix(v-if="viewOptions['equipment'].selected")
h2.float-left.mb-3
h2.float-left.mb-3.filters-title
| {{ $t('equipment') }}
div.float-right
.filters.float-right
span.dropdown-label {{ $t('class') }}
b-dropdown(right=true)
span.dropdown-icon-item(slot="text")
@ -328,6 +328,20 @@
right: -.5em;
top: -.5em;
}
@media only screen and (max-width: 768px) {
.featuredItems .content {
display: none !important;
}
.filters, .filters-title {
float: none;
button {
margin-right: 4em;
margin-bottom: 1em;
}
}
}
</style>

View file

@ -64,6 +64,7 @@ transition(name="fade")
.svg-icon {
width: 20px;
height: 20px;
margin-right: .5em;
}

View file

@ -1,7 +1,7 @@
<template lang="pug">
.container-fluid
.row
.col-md-6.offset-3
.col-12.col-md-6.offset-md-3
h1 {{ $t('frequentlyAskedQuestions') }}
.faq-question(v-for='(heading, index) in headings')
h2.accordion(@click='setActivePage(heading)') {{ $t(`faqQuestion${index}`) }}
@ -14,6 +14,12 @@
.faq-question {
margin-bottom: 1em;
}
@media only screen and (max-width: 768px) {
.container-fluid {
margin: auto;
}
}
</style>
<script>

View file

@ -37,7 +37,7 @@
.pixel-horizontal.svg-icon(v-html='icons.pixelHorizontal')
.container
.row
.col-12.col-sm-6.col-md-6.col-lg-6.offset-3.text-center
.col-12.col-sm-6.col-md-6.col-lg-6.offset-sm-3.text-center
h2 {{$t('gamifyYourLife')}}
p.section-main {{$t('aboutHabitica')}}
.row
@ -502,6 +502,19 @@
opacity: .5;
}
}
@media only screen and (max-width: 768px) {
#call-to-action .btn-primary {
width: 95%;
}
#call-to-action .featured .svg-icon {
display: block;
margin: 0 auto;
margin-bottom: .5em;
}
}
</style>
<script>

View file

@ -103,6 +103,7 @@ div(v-if='user.stats.lvl > 10')
.svg-icon {
width: 16px;
height: 16px;
margin-right: .2em;
}
}

View file

@ -81,7 +81,7 @@
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", v-if='!task.challenge.broken')
.svg-icon.challenge.broken(v-html="icons.challenge", v-if='task.challenge.broken', @click='handleBrokenTask(task)')
.svg-icon.challenge.broken(v-html="icons.brokenChallengeIcon", v-if='task.challenge.broken', @click='handleBrokenTask(task)')
.d-flex.align-items-center(v-if="hasTags", :id="`tags-icon-${task._id}`")
.svg-icon.tags(v-html="icons.tags")
#tags-popover
@ -500,6 +500,7 @@ 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 brokenChallengeIcon from 'assets/svg/broken-megaphone.svg';
import tagsIcon from 'assets/svg/tags.svg';
import checkIcon from 'assets/svg/check.svg';
import editIcon from 'assets/svg/edit.svg';
@ -534,6 +535,7 @@ export default {
streak: streakIcon,
calendar: calendarIcon,
challenge: challengeIcon,
brokenChallengeIcon,
tags: tagsIcon,
check: checkIcon,
checklist: checklistIcon,

View file

@ -492,8 +492,13 @@
border-top-left-radius: 8px;
border-top-right-radius: 8px;
margin-top: 50px;
width: 100%;
span {
display: block;
margin: 0 auto;
width: 50px;
}
.delete-task-btn {
color: $red-50;
@ -509,6 +514,12 @@
width: 57px;
}
}
@media only screen and (max-width: 768px) {
.option-item {
margin-right: 12px !important;
}
}
</style>
<style lang="scss" scoped>

View file

@ -9,7 +9,7 @@
)
.col-12
.row.tasks-navigation
.col-4.offset-4
.col-12.col-md-4.offset-md-4
.d-flex
input.form-control.input-search(type="text", :placeholder="$t('search')", v-model="searchText")
button.btn.btn-secondary.dropdown-toggle.ml-2.d-flex.align-items-center(
@ -288,6 +288,13 @@
}
}
}
@media only screen and (max-width: 768px) {
.filter-panel {
max-width: none;
left: 0px;
}
}
</style>
<script>

View file

@ -1,7 +1,7 @@
<template lang="pug">
div
b-modal#profile(title="Profile", size='lg', :hide-footer="true")
div(slot='modal-header')
.header(slot='modal-header')
.profile-actions
button.btn.btn-secondary.message-icon(@click='sendMessage()', v-b-tooltip.hover.left="$t('sendMessage')")
.svg-icon.message-icon(v-html="icons.message")
@ -17,22 +17,22 @@ div
.col-12
member-details(:member="user")
.row
.col-6.offset-3.text-center.nav
.col-12.col-md-6.offset-md-3.text-center.nav
.nav-item(@click='selectPage("profile")', :class="{active: selectedPage === 'profile'}") {{ $t('profile') }}
.nav-item(@click='selectPage("stats")', :class="{active: selectedPage === 'stats'}") {{ $t('stats') }}
.nav-item(@click='selectPage("achievements")', :class="{active: selectedPage === 'achievements'}") {{ $t('achievements') }}
#userProfile.standard-page(v-show='selectedPage === "profile"', v-if='user.profile')
.row
.col-8
.col-12.col-md-8
.header
h1 {{user.profile.name}}
h4
strong {{ $t('userId') }}:
| {{user._id}}
.col-4
.col-12.col-md-4
button.btn.btn-secondary(v-if='user._id === userLoggedIn._id', @click='editing = !editing') {{ $t('edit') }}
.row(v-if='!editing')
.col-8
.col-12.col-md-8
.about
h2 {{ $t('about') }}
p(v-if='user.profile.blurb', v-markdown='user.profile.blurb')
@ -42,7 +42,7 @@ div
img.img-rendering-auto(v-if='user.profile.imageUrl', :src='user.profile.imageUrl')
p(v-else) {{ $t('noPhoto') }}
.col-4
.col-12.col-md-4
.info
h2 {{ $t('info') }}
div
@ -93,7 +93,7 @@ div
#achievements.standard-page.container(v-show='selectedPage === "achievements"', v-if='user.achievements')
.row(v-for='(category, key) in achievements')
h2.col-12.text-center {{ $t(key+'Achievs') }}
.col-3.text-center(v-for='(achievement, key) in category.achievements')
.col-12.col-md-3.text-center(v-for='(achievement, key) in category.achievements')
.box.achievement-container(:id='key + "-achievement"', :class='{"achievement-unearned": !achievement.earned}')
b-popover(
:target="'#' + key + '-achievement'",
@ -107,103 +107,103 @@ div
.achievement.achievement-unearned(class='achievement-unearned2x', v-if='!achievement.earned')
hr.col-12
.row
.col-6(v-if='user.achievements.challenges')
.col-12.col-md-6(v-if='user.achievements.challenges')
.achievement-icon.achievement-karaoke
h2.text-center {{$t('challengesWon')}}
div(v-for='chal in user.achievements.challenges')
span(v-markdown='chal')
hr
.col-6(v-if='user.achievements.quests')
.col-12.col-md-6(v-if='user.achievements.quests')
.achievement-icon.achievement-alien
h2.text-center {{$t('questsCompleted')}}
div(v-for='(value, key) in user.achievements.quests')
span {{ content.quests[key].text() }} ({{ value }})
#stats.standard-page(v-show='selectedPage === "stats"', v-if='user.preferences')
.row
.col-6
.col-12.col-md-6
h2.text-center {{$t('equipment')}}
.well
.col-4.item-wrapper
.col-12.col-md-4.item-wrapper
.box(:class='{white: equippedItems.eyewear && equippedItems.eyewear.indexOf("base_0") === -1}')
div(:class="`shop_${equippedItems.eyewear}`")
h3 {{$t('eyewear')}}
.col-4.item-wrapper
.col-12.col-md-4.item-wrapper
.box(:class='{white: equippedItems.head && equippedItems.head.indexOf("base_0") === -1}')
div(:class="`shop_${equippedItems.head}`")
h3 {{$t('headgearCapitalized')}}
.col-4.item-wrapper
.col-12.col-md-4.item-wrapper
.box(:class='{white: equippedItems.headAccessory && equippedItems.headAccessory.indexOf("base_0") === -1}')
div(:class="`shop_${equippedItems.headAccessory}`")
h3 {{$t('headAccess')}}
.col-4.item-wrapper
.col-12.col-md-4.item-wrapper
.box(:class='{white: equippedItems.back && equippedItems.back.indexOf("base_0") === -1}')
div(:class="`shop_${equippedItems.back}`")
h3 {{$t('backAccess')}}
.col-4.item-wrapper
.col-12.col-md-4.item-wrapper
.box(:class='{white: equippedItems.armor && equippedItems.armor.indexOf("base_0") === -1}')
div(:class="`shop_${equippedItems.armor}`")
h3 {{$t('armorCapitalized')}}
.col-4.item-wrapper
.col-12.col-md-4.item-wrapper
.box(:class='{white: equippedItems.body && equippedItems.body.indexOf("base_0") === -1}')
div(:class="`shop_${equippedItems.body}`")
h3 {{$t('bodyAccess')}}
.col-4.item-wrapper
.col-12.col-md-4.item-wrapper
.box(:class='{white: equippedItems.weapon && equippedItems.weapon.indexOf("base_0") === -1}')
div(:class="`shop_${equippedItems.weapon}`")
h3 {{$t('mainHand')}}
.col-4.item-wrapper
.col-4.item-wrapper
.col-12.col-md-4.item-wrapper
.col-12.col-md-4.item-wrapper
.box(:class='{white: equippedItems.shield && equippedItems.shield.indexOf("base_0") === -1}')
div(:class="`shop_${equippedItems.shield}`")
h3 {{$t('offHand')}}
.col-6
.col-12.col-md-6
h2.text-center {{$t('costume')}}
.well
.col-4.item-wrapper
.col-12.col-md-4.item-wrapper
.box(:class='{white: costumeItems.eyewear && costumeItems.eyewear.indexOf("base_0") === -1}')
div(:class="`shop_${costumeItems.eyewear}`")
h3 {{$t('eyewear')}}
.col-4.item-wrapper
.col-12.col-md-4.item-wrapper
.box(:class='{white: costumeItems.head && costumeItems.head.indexOf("base_0") === -1}')
div(:class="`shop_${costumeItems.head}`")
h3 {{$t('headgearCapitalized')}}
.col-4.item-wrapper
.col-12.col-md-4.item-wrapper
.box(:class='{white: costumeItems.headAccessory && costumeItems.headAccessory.indexOf("base_0") === -1}')
div(:class="`shop_${costumeItems.headAccessory}`")
h3 {{$t('headAccess')}}
.col-4.item-wrapper
.col-12.col-md-4.item-wrapper
.box(:class='{white: costumeItems.back && costumeItems.back.indexOf("base_0") === -1}')
div(:class="`shop_${costumeItems.back}`")
h3 {{$t('backAccess')}}
.col-4.item-wrapper
.col-12.col-md-4.item-wrapper
.box(:class='{white: costumeItems.armor && costumeItems.armor.indexOf("base_0") === -1}')
div(:class="`shop_${costumeItems.armor}`")
h3 {{$t('armorCapitalized')}}
.col-4.item-wrapper
.col-12.col-md-4.item-wrapper
.box(:class='{white: costumeItems.body && costumeItems.body.indexOf("base_0") === -1}')
div(:class="`shop_${costumeItems.body}`")
h3 {{$t('bodyAccess')}}
.col-4.item-wrapper
.col-12.col-md-4.item-wrapper
.box(:class='{white: costumeItems.weapon && costumeItems.weapon.indexOf("base_0") === -1}')
div(:class="`shop_${costumeItems.weapon}`")
h3 {{$t('mainHand')}}
.col-4.item-wrapper
.col-12.col-md-4.item-wrapper
.box(:class='{white: user.preferences.background}', style="overflow:hidden")
div(:class="'icon_background_' + user.preferences.background")
h3 {{$t('background')}}
.col-4.item-wrapper
.col-12.col-md-4.item-wrapper
.box(:class='{white: costumeItems.shield && costumeItems.shield.indexOf("base_0") === -1}')
div(:class="`shop_${costumeItems.shield}`")
h3 {{$t('offHand')}}
.row.pet-mount-row
.col-6
.col-12.col-md-6
h2.text-center(v-once) {{ $t('pets') }}
.well.pet-mount-well
.row.col-12
.col-4
.col-12.col-md-4
.box(:class='{white: user.items.currentPet}')
.pet(:class="`Pet-${user.items.currentPet}`")
.col-8
.col-12.col-md-8
div
| {{ formatAnimal(user.items.currentPet, 'pet') }}
div
@ -212,14 +212,14 @@ div
div
strong {{ $t('beastMasterProgress') }}:
| {{ beastMasterProgress(user.items.pets) }}
.col-6
.col-12.col-md-6
h2.text-center(v-once) {{ $t('mounts') }}
.well.pet-mount-well
.row.col-12
.col-4
.col-12.col-md-4
.box(:class='{white: user.items.currentMount}')
.mount(:class="`Mount_Icon_${user.items.currentMount}`")
.col-8
.col-12.col-md-8
div
| {{ formatAnimal(user.items.currentMount, 'mount') }}
div
@ -231,14 +231,14 @@ div
#attributes.row
hr.col-12
h2.col-12 {{$t('attributes')}}
.col-6(v-for="(statInfo, stat) in stats")
.col-12.col-md-6(v-for="(statInfo, stat) in stats")
.row.col-12.stats-column
.col-4.attribute-label
.col-12.col-md-4.attribute-label
span.hint(:popover-title='$t(statInfo.title)', popover-placement='right',
:popover='$t(statInfo.popover)', popover-trigger='mouseenter')
.stat-title(:class='stat') {{ $t(statInfo.title) }}
strong.number {{ statsComputed[stat] }}
.col-6
.col-12.col-md-6
ul.bonus-stats
li
strong {{$t('level')}}:
@ -257,26 +257,26 @@ div
| {{user.stats.buffs[stat]}}
#allocation(v-if='user._id === userLoggedIn._id')
.row.title-row
.col-6
.col-12.col-md-6
h3(v-if='userLevel100Plus', v-once, v-html="$t('noMoreAllocate')")
h3(v-if='user.stats.points || userLevel100Plus')
| {{$t('pointsAvailable')}}
.counter.badge(v-if='user.stats.points || userLevel100Plus')
| {{user.stats.points}}&nbsp;
.col-6
.col-12.col-md-6
.float-right
toggle-switch(:label="$t('autoAllocation')",
v-model='user.preferences.automaticAllocation',
@change='userset({"preferences.automaticAllocation": Boolean(user.preferences.automaticAllocation), "preferences.allocationMode": "taskbased"})')
.row
.col-3(v-for='(statInfo, stat) in allocateStatsList')
.col-12.col-md-3(v-for='(statInfo, stat) in allocateStatsList')
.box.white.row.col-12
.col-12
div(:class='stat') {{ $t(stats[stat].title) }}
.number {{ user.stats[stat] }}
.points {{$t('pts')}}
.col-4
.col-12.col-md-4
.up(v-if='user.stats.points', @click='allocate(stat)')
send-gems-modal(:userReceivingGems='userReceivingGems')
</template>
@ -293,11 +293,23 @@ div
background: #f9f9f9;
}
}
.message-icon svg {
height: 16px;
}
.gift-icon svg {
height: 14px;
}
</style>
<style lang="scss" scoped>
@import '~client/assets/scss/colors.scss';
.header {
width: 100%;
}
.profile-actions {
float: right;
margin-right: 1em;

View file

@ -110,6 +110,7 @@ export function togglePinnedItem (store, params) {
export function castSpell (store, params) {
let spellUrl = `/api/v3/user/class/cast/${params.key}`;
if (params.targetId) spellUrl += `?targetId=${params.targetId}`;
return axios.post(spellUrl);

View file

@ -91,10 +91,6 @@ export default function () {
startingPage: '',
subPage: '',
},
flagChatOptions: {
message: {},
groupId: '',
},
challengeOptions: {
cloning: false,
tasksToClone: {},

View file

@ -7,7 +7,7 @@
"tip5": "Its best to use skills that cause buffs in the morning so they last longer.",
"tip6": "Hover over a task and click the dots to access advanced task controls, such as the ability to push tasks to the top/bottom of your list.",
"tip7": "Some backgrounds connect perfectly if Party members use the same background. Ex: Mountain Lake, Pagodas, and Rolling Hills.",
"tip8": "Send a Message to someone by clicking their name in chat and the clicking the envelope icon at the top of their profile!",
"tip8": "Send a Message to someone by clicking their name in chat and then clicking the envelope icon at the top of their profile!",
"tip9": "Use the filters + search bar in the Inventories, Shops, Guilds, and Challenges to quickly find what you want.",
"tip10": "You can win gems by competing in Challenges. New ones are added every day!",
"tip11": "Having more than four Party members increases accountability!",

Binary file not shown.

After

Width:  |  Height:  |  Size: 3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 286 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 264 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 230 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 350 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 254 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 267 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

View file

@ -540,7 +540,7 @@ api.updatePassword = {
/**
* @api {post} /api/v3/user/reset-password Reset password
* @apiDescription Reset the user password
* @apiDescription Send the user an email to let them reset their password
* @apiName ResetPassword
* @apiGroup User
*

View file

@ -1566,7 +1566,7 @@ api.userSell = {
*
* @apiErrorExample {json}
* {"success":false,"error":"BadRequest","message":"Path string is required"}
8 {"success":false,"error":"NotAuthorized","message":"Full set already unlocked."}
* {"success":false,"error":"NotAuthorized","message":"Full set already unlocked."}
*/
api.userUnlock = {
method: 'POST',

View file

@ -123,7 +123,7 @@ api.subscribeSuccess = {
if (req.query.noRedirect) {
res.respond(200);
} else {
res.redirect('/');
res.redirect('/user/settings/subscription');
}
},
};
@ -147,7 +147,7 @@ api.subscribeCancel = {
if (req.query.noRedirect) {
res.respond(200);
} else {
res.redirect('/');
res.redirect('/user/settings/subscription');
}
},
};