Merge remote-tracking branch 'origin/develop' into negue/ui/setting

# Conflicts:
#	website/client/src/components/groups/createPartyModal.vue
#	website/client/src/components/settings/restoreModal.vue
This commit is contained in:
negue
2023-05-08 20:41:31 +02:00
95 changed files with 1131 additions and 292 deletions
@@ -27905,6 +27905,31 @@
width: 114px;
height: 90px;
}
.back_mystery_202305 {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/back_mystery_202305.png');
width: 114px;
height: 90px;
}
.headAccessory_mystery_202305 {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/headAccessory_mystery_202305.png');
width: 114px;
height: 90px;
}
.shop_back_mystery_202305 {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/shop_back_mystery_202305.png');
width: 68px;
height: 68px;
}
.shop_headAccessory_mystery_202305 {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/shop_headAccessory_mystery_202305.png');
width: 68px;
height: 68px;
}
.shop_set_mystery_202305 {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/shop_set_mystery_202305.png');
width: 68px;
height: 68px;
}
.broad_armor_mystery_301404 {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/broad_armor_mystery_301404.png');
width: 90px;
+13 -8
View File
@@ -24,9 +24,9 @@
}
}
.icon-16 {
width: 16px;
height: 16px;
.icon-10 {
width: 10px;
height: 10px;
}
.icon-12 {
@@ -34,21 +34,26 @@
height: 12px;
}
.icon-16 {
width: 16px;
height: 16px;
}
.icon-24 {
width: 24px;
height: 24px;
}
.icon-32 {
width: 32px;
height: 32px;
}
.icon-48 {
width: 48px;
height: 48px;
}
.icon-10 {
width: 10px;
height: 10px;
}
.inline {
display: inline-block;
}
+1
View File
@@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><svg id="a" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path id="b" d="m10,6h6V0h-2v2.72C12.49.99,10.3,0,8,0,3.59,0,0,3.59,0,8s3.59,8,8,8c2.69,0,5.2-1.35,6.68-3.6l-1.67-1.1c-1.11,1.69-2.99,2.71-5.01,2.7-3.31,0-6-2.69-6-6s2.69-6,6-6c1.72,0,3.33.74,4.46,2h-2.46v2Z" fill-rule="evenodd"/></svg>

After

Width:  |  Height:  |  Size: 341 B

@@ -22,6 +22,10 @@
Account created:
<strong>{{ hero.auth.timestamps.created | formatDate }}</strong>
</div>
<div v-if="hero.flags.thirdPartyTools">
User has employed <strong>third party tools</strong>. Last known usage:
<strong>{{ hero.flags.thirdPartyTools | formatDate }}</strong>
</div>
<div v-if="cronError">
"lastCron" value:
<strong>{{ hero.lastCron | formatDate }}</strong>
@@ -11,9 +11,12 @@
<div class="quest_screen"></div>
<div class="row heading">
<div class="col-12 text-center pr-5 pl-5">
<h2 v-once>
<h1
v-once
class="mb-2"
>
{{ $t('playInPartyTitle') }}
</h2>
</h1>
<p
v-once
class="mb-4"
@@ -22,67 +25,91 @@
</p>
<button
v-once
class="btn btn-primary"
class="btn btn-primary px-4 mb-2"
@click="createParty()"
>
{{ $t('createParty') }}
</button>
</div>
</div>
<close-x
@close="close()"
/>
</div>
<div class="row grey-row">
<div class="col-12 text-center">
<div class="col-12 text-center px-0">
<div class="join-party"></div>
<h2 v-once>
{{ $t('wantToJoinPartyTitle') }}
</h2>
<p v-html="$t('wantToJoinPartyDescription')"></p>
<div
class="form-group"
@click="copyUsername"
<h1
v-once
class="mb-2"
>
<div class="d-flex align-items-center">
<label
v-once
class="mr-3"
>{{ $t('username') }}</label>
<div class="flex-grow-1">
<div class="input-group-prepend input-group-text">
@
<div class="text">
{{ user.auth.local.username }}
</div>
<div
class="svg-icon copy-icon"
v-html="icons.copy"
></div>
<div
v-once
class="small"
>
{{ $t('copy') }}
</div>
</div>
{{ $t('wantToJoinPartyTitle') }}
</h1>
<p
v-once
class="mb-4"
v-html="$t('partyFinderDescription')"
>
</p>
<div
v-if="seeking"
>
<div
class="green-bar mb-3"
>
{{ $t('currentlyLookingForParty') }}
</div>
<div class="d-flex justify-content-center">
<div
class="red-link"
@click="seekParty()"
>
{{ $t('leave') }}
</div>
</div>
</div>
<button
v-else
class="btn btn-primary px-4 mt-2 mb-1"
@click="seekParty()"
>
{{ $t('lookForParty') }}
</button>
</div>
</div>
</b-modal>
</template>
<style>
#create-party-modal .modal-body {
padding: 0rem 0.75rem;
}
<style lang="scss">
#create-party-modal {
display: flex !important;
overflow-y: hidden;
#create-party-modal .modal-dialog {
width: 35.75rem;
}
@media (max-height: 770px) {
overflow-y: auto;
}
#create-party-modal .modal-header {
padding: 0;
border-bottom: 0px;
.modal-body {
padding: 0rem 0.75rem;
}
.modal-content {
border-radius: 8px;
}
.modal-dialog {
width: 566px;
margin: auto;
@media (max-height: 826px) {
margin-top: 56px;
}
}
.modal-header {
padding: 0;
border-bottom: 0px;
}
}
</style>
@@ -107,15 +134,27 @@
cursor: pointer;
}
.green-bar {
height: 32px;
font-size: 14px;
font-weight: bold;
line-height: 1.71;
text-align: center;
color: $green-1;
background-color: $green-100;
border-radius: 2px;
padding: 4px 0px 4px 0px;
}
.grey-row {
background-color: $gray-700;
color: #4e4a57;
padding: 2em;
border-radius: 0px 0px 2px 2px;
border-radius: 0px 0px 8px 8px;
}
h2 {
color: $gray-100;
h1 {
color: $purple-300;
}
.header-wrap {
@@ -132,10 +171,6 @@
border-radius: 2px 2px 0 0;
image-rendering: optimizequality;
}
h2 {
color: $purple-200;
}
}
.heading {
@@ -182,6 +217,21 @@
margin: 0.75rem auto 0.75rem 0.25rem;
}
p {
line-height: 1.71;
}
.red-link {
cursor: pointer;
font-size: 14px;
line-height: 1.71;
text-align: center;
color: $maroon-50;
&:hover {
text-decoration: underline;
}
}
.small {
color: $gray-200;
margin: auto 0.5rem auto 0.25rem;
@@ -192,22 +242,36 @@
import { mapState } from '@/libs/store';
import * as Analytics from '@/libs/analytics';
import notifications from '@/mixins/notifications';
import closeX from '../ui/closeX';
import copyIcon from '@/assets/svg/copy.svg';
import copyToClipboard from '@/mixins/copyToClipboard';
export default {
components: {
closeX,
},
mixins: [notifications, copyToClipboard],
data () {
return {
icons: Object.freeze({
copy: copyIcon,
}),
seeking: false,
};
},
computed: {
...mapState({ user: 'user.data' }),
},
mounted () {
this.seeking = Boolean(this.user.party.seeking);
Analytics.track({
eventName: 'Start a Party button',
eventAction: 'Start a Party button',
eventCategory: 'behavior',
hitType: 'event',
}, { trackOnClient: true });
},
methods: {
async createParty () {
const group = {
@@ -224,7 +288,10 @@ export default {
});
this.$root.$emit('bv::hide::modal', 'create-party-modal');
this.$router.push('/party');
await this.$router.push('/party');
},
close () {
this.$root.$emit('bv::hide::modal', 'create-party-modal');
},
copyUsername () {
this.mixinCopyToClipboard(
@@ -232,6 +299,12 @@ export default {
this.$t('usernameCopied'),
);
},
seekParty () {
this.$store.dispatch('user:set', {
'party.seeking': !this.user.party.seeking ? new Date() : null,
});
this.seeking = !this.seeking;
},
},
};
</script>
@@ -542,7 +542,8 @@ export default {
await this.$store.dispatch('guilds:leave', data);
if (this.isParty) {
this.$router.push({ name: 'tasks' });
await this.$router.push({ name: 'tasks' });
window.location.reload(true);
}
},
upgradeGroup () {
@@ -4,12 +4,12 @@
<group-plan-creation-modal />
<div>
<div class="header">
<h1 class="text-center">
Need more for your Group?
<h1 v-once class="text-center">
{{ $t('groupPlanTitle') }}
</h1>
<div class="row">
<div class="col-8 offset-2 text-center">
<h2 class="sub-text">
<h2 v-once class="sub-text">
{{ $t('groupBenefitsDescription') }}
</h2>
</div>
@@ -24,8 +24,8 @@
src="~@/assets/images/group-plans/group-14@3x.png"
>
<hr>
<h2>{{ $t('teamBasedTasks') }}</h2>
<p>Set up an easily-viewed shared task list for the group. Assign tasks to your fellow group members, or let them claim their own tasks to make it clear what everyone is working on!</p><!-- eslint-disable-line max-len -->
<h2 v-once> {{ $t('teamBasedTasks') }} </h2>
<p v-once> {{ $t('teamBasedTasksListDesc') }} </p>
</div>
</div>
<div class="col-4">
@@ -35,8 +35,8 @@
src="~@/assets/images/group-plans/group-12@3x.png"
>
<hr>
<h2>Group Management Controls</h2>
<p>Use task approvals to verify that a task that was really completed, add Group Managers to share responsibilities, and enjoy a private group chat for all team members.</p><!-- eslint-disable-line max-len -->
<h2 v-once> {{ $t('groupManagementControls') }} </h2>
<p v-once> {{ $t('groupManagementControlsDesc') }} </p>
</div>
</div>
<div class="col-4">
@@ -46,8 +46,8 @@
src="~@/assets/images/group-plans/group-13@3x.png"
>
<hr>
<h2>In-Game Benefits</h2>
<p>Group members get an exclusive Jackalope Mount, as well as full subscription benefits, including special monthly equipment sets and the ability to buy gems with gold.</p><!-- eslint-disable-line max-len -->
<h2 v-once> {{ $t('inGameBenefits') }} </h2>
<p v-once> {{ $t('inGameBenefitsDesc') }} </p>
</div>
</div>
</div>
@@ -0,0 +1,351 @@
<template>
<div>
<div class="d-flex justify-content-center">
<div
v-if="seekers.length > 0"
class="fit-content mx-auto mt-4"
>
<div class="d-flex align-items-center">
<h1 v-once class="my-auto mr-auto"> {{ $t('findPartyMembers') }}</h1>
<div
class="btn btn-secondary btn-sync ml-auto my-auto pl-2 pr-3 d-flex"
@click="refreshList()"
>
<div class="svg-icon icon-16 color my-auto mr-2" v-html="icons.sync"></div>
<div class="ml-auto"> {{ $t('refreshList') }} </div>
</div>
</div>
<div class="d-flex flex-wrap seeker-list">
<div
v-for="(seeker, index) in seekers"
:key="seeker._id"
class="seeker"
>
<div class="d-flex">
<avatar
:member="seeker"
:hideClassBadge="true"
@click.native="showMemberModal(seeker._id)"
class="mr-3 mb-2"
/>
<div class="card-data">
<user-link
:user-id="seeker._id"
:name="seeker.profile.name"
:backer="seeker.backer"
:contributor="seeker.contributor"
/>
<div class="small-with-border pb-2 mb-2">
@{{ seeker.auth.local.username }} {{ $t('level') }} {{ seeker.stats.lvl }}
</div>
<div
class="d-flex"
>
<strong v-once> {{ $t('classLabel') }} </strong>
<span
class="svg-icon d-inline-block icon-16 my-auto mx-2"
v-html="icons[seeker.stats.class]"
>
</span>
<strong
:class="`${seeker.stats.class}-color`"
>
{{ $t(seeker.stats.class) }}
</strong>
</div>
<div>
<strong v-once class="mr-2"> {{ $t('checkinsLabel') }} </strong>
{{ seeker.loginIncentives }}
</div>
<div>
<strong v-once class="mr-2"> {{ $t('languageLabel') }} </strong>
{{ displayLanguage(seeker.preferences.language) }}
</div>
</div>
</div>
<strong
v-if="!seeker.invited"
@click="inviteUser(seeker._id, index)"
class="btn btn-primary w-100"
>
{{ $t('inviteToParty') }}
</strong>
<div
v-else
@click="rescindInvite(seeker._id, index)"
class="btn btn-success w-100"
v-html="$t('invitedToYourParty')"
>
</div>
</div>
<mugen-scroll
v-show="loading"
:handler="infiniteScrollTrigger"
:should-handle="!loading && canLoadMore"
:threshold="1"
/>
</div>
</div>
<div
v-if="seekers.length === 0 && !loading"
class="d-flex flex-column empty-state text-center my-5"
>
<div class="gray-circle mb-3 mx-auto d-flex">
<div
class="svg-icon icon-32 color m-auto"
v-html="icons.users"
>
</div>
</div>
<strong class="mb-1"> {{ $t('findMorePartyMembers') }} </strong>
<div v-html="$t('noOneLooking')"></div>
</div>
</div>
<h2
v-show="loading"
class="loading"
:class="seekers.length === 0 ? 'mt-3' : 'mt-0'"
>
{{ $t('loading') }}
</h2>
</div>
</template>
<style lang="scss" scoped>
@import '~@/assets/scss/colors.scss';
h1 {
color: $purple-300;
}
strong {
line-height: 1.71;
}
.avatar {
background-color: $gray-600;
}
.btn-success {
box-shadow: none;
color: $green-1;
font-weight: normal;
&:not(:disabled):not(.disabled):active {
color: $green-1;
}
}
.btn-sync {
min-width: 128px;
max-height: 32px;
.svg-icon {
color: $gray-200;
}
}
.card-data {
width: 267px;
}
.empty-state {
color: $gray-100;
line-height: 1.71;
}
.fit-content {
width: fit-content;
}
.gray-circle {
width: 64px;
height: 64px;
color: $gray-600;
background-color: $gray-200;
border-radius: 100px;
.icon-32 {
height: auto;
}
}
.loading {
text-align: center;
color: $purple-300;
}
.seeker-list {
max-width: 920px;
@media (max-width: 962px) {
max-width: 464px;
};
.seeker {
width: 448px;
margin-bottom: 24px;
padding: 8px;
border-radius: 4px;
box-shadow: 0 1px 3px 0 rgba(26, 24, 29, 0.12), 0 1px 2px 0 rgba(26, 24, 29, 0.24);
&:first-of-type {
margin-top: 24px;
}
@media (min-width: 963px) {
&:nth-child(2) {
margin-top: 24px;
}
&:nth-child(even) {
margin-left: 24px;
}
}
}
}
.small-with-border {
border-bottom: 1px solid $gray-500;
color: $gray-100;
font-size: 12px;
font-weight: normal;
line-height: 1.33;
}
.healer-color {
color: $yellow-10;
}
.rogue-color {
color: $purple-200;
}
.warrior-color {
color: $red-50;
}
.wizard-color {
color: $blue-10;
}
</style>
<script>
import debounce from 'lodash/debounce';
import MugenScroll from 'vue-mugen-scroll';
import Avatar from '../avatar';
import userLink from '../userLink';
import { mapState } from '@/libs/store';
import syncIcon from '@/assets/svg/sync-2.svg';
import usersIcon from '@/assets/svg/users.svg';
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';
import * as Analytics from '@/libs/analytics';
export default {
components: {
Avatar,
MugenScroll,
userLink,
},
data () {
return {
canLoadMore: true,
loading: true,
page: 0,
party: {},
seekers: [],
icons: Object.freeze({
warrior: warriorIcon,
rogue: rogueIcon,
healer: healerIcon,
sync: syncIcon,
users: usersIcon,
wizard: wizardIcon,
}),
};
},
computed: {
...mapState({
availableLanguages: 'i18n.availableLanguages',
user: 'user.data',
}),
},
async mounted () {
try {
this.party = await this.$store.dispatch('guilds:getGroup', { groupId: this.user.party._id });
} catch {
this.$router.push('/');
}
if (!this.party._id || this.party.leader._id !== this.user._id) {
this.$router.push('/');
} else {
this.$store.dispatch('common:setTitle', {
section: this.$t('lookingForPartyTitle'),
});
this.seekers = await this.$store.dispatch('party:lookingForParty');
await Analytics.track({
hitType: 'event',
eventName: 'View Find Members',
eventAction: 'View Find Members',
eventCategory: 'behavior',
}, { trackOnClient: true });
this.canLoadMore = this.seekers.length === 30;
this.loading = false;
}
},
methods: {
displayLanguage (languageCode) {
const language = this.availableLanguages.find(lang => lang.code === languageCode);
if (language) {
return language.name;
}
return languageCode;
},
infiniteScrollTrigger () {
if (this.canLoadMore) {
this.loading = true;
}
this.loadMore();
},
async inviteUser (userId, index) {
await this.$store.dispatch('guilds:invite', {
invitationDetails: {
inviter: this.user.profile.name,
uuids: [userId],
},
groupId: this.party._id,
});
this.seekers[index].invited = true;
},
loadMore: debounce(async function loadMoreDebounce () {
this.page += 1;
const addlSeekers = await this.$store.dispatch('party:lookingForParty', { page: this.page });
this.seekers = this.seekers.concat(addlSeekers);
this.canLoadMore = this.seekers.length % 30 === 0;
this.loading = false;
}, 1000),
async refreshList () {
this.loading = true;
this.page = 0;
this.seekers = await this.$store.dispatch('party:lookingForParty');
this.canLoadMore = this.seekers.length === 30;
this.loading = false;
},
async rescindInvite (userId, index) {
await this.$store.dispatch('members:removeMember', {
memberId: userId,
groupId: this.party._id,
});
this.seekers[index].invited = false;
},
showMemberModal (userId) {
this.$router.push({ name: 'userProfile', params: { userId } });
},
},
};
</script>
@@ -2,7 +2,7 @@
<div class="sidebar px-4">
<div>
<div class="buttons-wrapper">
<div class="button-container button-with-menu-row">
<div class="button-container d-flex">
<button
v-if="!isMember"
class="btn btn-success btn-success"
@@ -203,10 +203,6 @@ export default {
}
}
.button-with-menu-row {
display: flex;
}
.menuIcon {
width: 4px;
height: 1rem;
@@ -51,20 +51,20 @@
</div>
<div
v-else
class="no-party d-none d-md-flex justify-content-center text-center mr-4"
class="no-party d-none d-md-flex justify-content-center text-center mr-4"
>
<div class="align-self-center">
<h3>{{ $t('battleWithFriends') }}</h3>
<h3>{{ user.party._id ? $t('questWithOthers') : $t('battleWithFriends') }}</h3>
<span
class="small-text"
v-html="$t('inviteFriendsParty')"
v-html="user.party._id ? $t('inviteFriendsParty') : $t('startPartyDetail')"
></span>
<br>
<button
class="btn btn-primary"
@click="createOrInviteParty()"
>
{{ user.party._id ? $t('inviteFriends') : $t('startAParty') }}
{{ user.party._id ? $t('findPartyMembers') : $t('getStarted') }}
</button>
</div>
</div>
@@ -234,7 +234,7 @@ export default {
},
createOrInviteParty () {
if (this.user.party._id) {
this.$root.$emit('inviteModal::inviteToGroup', this.user.party);
this.$router.push('/looking-for-party');
} else {
this.$root.$emit('bv::show::modal', 'create-party-modal');
}
+44 -3
View File
@@ -148,7 +148,7 @@
</div>
</li>
<b-nav-item
v-if="user.party._id"
v-if="user.party._id && user._id !== partyLeaderId"
class="topbar-item"
:class="{'active': $route.path.startsWith('/party')}"
tag="li"
@@ -156,6 +156,36 @@
>
{{ $t('party') }}
</b-nav-item>
<li
v-if="user.party._id && user._id === partyLeaderId"
class="topbar-item droppable"
:class="{'active': $route.path.startsWith('/party')}"
>
<div
class="chevron rotate"
@click="dropdownMobile($event)"
>
<div
v-once
class="chevron-icon-down"
v-html="icons.chevronDown"
></div>
</div>
<router-link
class="nav-link"
:to="{name: 'party'}"
>
{{ $t('party') }}
</router-link>
<div class="topbar-dropdown">
<router-link
class="topbar-dropdown-item dropdown-item"
:to="{name: 'lookingForParty'}"
>
{{ $t('lookingForPartyTitle') }}
</router-link>
</div>
</li>
<b-nav-item
v-if="!user.party._id"
class="topbar-item"
@@ -768,6 +798,7 @@ export default {
return {
isUserDropdownOpen: false,
menuIsOpen: false,
partyLeaderId: null,
icons: Object.freeze({
gem: gemIcon,
gold: goldIcon,
@@ -796,8 +827,9 @@ export default {
};
},
},
mounted () {
this.getUserGroupPlans();
async mounted () {
await this.getUserGroupPlans();
await this.getUserParty();
Array.from(document.getElementById('menu_collapse').getElementsByTagName('a')).forEach(link => {
link.addEventListener('click', this.closeMenu);
});
@@ -805,6 +837,9 @@ export default {
link.addEventListener('mouseenter', this.dropdownDesktop);
link.addEventListener('mouseleave', this.dropdownDesktop);
});
this.$root.$on('update-party', () => {
this.getUserParty();
});
},
methods: {
modForm () {
@@ -816,6 +851,12 @@ export default {
async getUserGroupPlans () {
await this.$store.dispatch('guilds:getGroupPlans');
},
async getUserParty () {
if (this.user.party._id) {
await this.$store.dispatch('party:getParty');
this.partyLeaderId = this.$store.state.party.data.leader._id;
}
},
openPartyModal () {
this.$root.$emit('bv::show::modal', 'create-party-modal');
},
@@ -34,11 +34,13 @@
<script>
import BaseNotification from './base';
import { mapState } from '@/libs/store';
import sync from '@/mixins/sync';
export default {
components: {
BaseNotification,
},
mixins: [sync],
props: {
notification: {
type: Object,
@@ -73,6 +75,7 @@ export default {
}
await this.$store.dispatch('guilds:join', { groupId: group.id, type: 'party' });
this.sync();
this.$router.push('/party');
},
reject () {
+39 -15
View File
@@ -17,6 +17,19 @@
class="faq-question"
>
<h2
v-once
v-if="index === 0"
>
{{ $t('general') }}
</h2>
<h2
v-once
v-if="entry.heading === 'party-with-friends'"
id="parties"
>
{{ $t('parties') }}
</h2>
<h3
v-once
v-b-toggle="entry.heading"
role="tab"
@@ -24,7 +37,7 @@
@click="handleClick($event)"
>
{{ entry.question }}
</h2>
</h3>
<b-collapse
:id="entry.heading"
:visible="isVisible(entry.heading)"
@@ -49,25 +62,36 @@
</template>
<style lang='scss' scoped>
.card-body {
margin-bottom: 1em;
h2 {
color: #34313a;
border-bottom: 1px solid #e1e0e3;
margin-top: 24px;
padding-bottom: 16px;
}
.faq-question h2 {
cursor: pointer;
}
.faq-question {
a {
text-decoration: none;
color: #4F2A93;
}
.faq-question .card-body {
padding: 0;
}
h3 {
font-size: 16px;
font-weight: normal;
line-height: 1.75;
cursor: pointer;
.static-wrapper .faq-question h2 {
margin: 0 0 16px 0;
}
&:hover {
text-decoration: underline;
}
}
.faq-question a {
text-decoration: none;
color: #4F2A93;
.card-body {
padding: 0;
font-size: 14px;
line-height: 1.71;
margin-bottom: 1em;
}
}
@media only screen and (max-width: 768px) {
@@ -198,10 +198,6 @@
color: $purple-200;
}
li, p {
font-size: 16px;
}
.media img {
margin: 1em;
}
@@ -0,0 +1,46 @@
<template>
<div
class="modal-close"
@click="$emit('close')"
>
<div
class="svg-icon svg-close color"
v-html="icons.close"
>
</div>
</div>
</template>
<style lang="scss" scoped>
.modal-close {
position: absolute;
right: 16px;
top: 16px;
cursor: pointer;
.svg-close {
width: 18px;
height: 18px;
vertical-align: middle;
opacity: 0.75;
&:hover {
opacity: 1;
}
}
}
</style>
<script>
import close from '@/assets/svg/close.svg';
export default {
data () {
return {
icons: Object.freeze({
close,
}),
};
},
};
</script>
+10 -5
View File
@@ -2,13 +2,13 @@
<router-link
v-if="displayName"
v-b-tooltip.hover.top="tierTitle"
class="leader user-link"
class="leader user-link d-flex"
:to="{'name': 'userProfile', 'params': {'userId': id}}"
:class="levelStyle()"
>
{{ displayName }}
<div
class="svg-icon"
class="svg-icon icon-12"
v-html="tierIcon()"
></div>
</router-link>
@@ -37,10 +37,15 @@
color: $gray-50;
}
&[class*="tier"] .svg-icon {
margin-top: 5px;
}
&.npc .svg-icon {
margin-top: 4px;
}
.svg-icon {
width: 10px;
display: inline-block;
margin-left: .5em;
margin-left: 6px;
&:empty {
display: none;
+1 -1
View File
@@ -20,7 +20,7 @@ export default {
&& !some(TRUSTED_DOMAINS.split(','), domain => link.href.indexOf(domain) === domainIndex)) {
link.classList.add('external-link');
link.addEventListener('click', e => {
if (e.ctrlKey) {
if (e.ctrlKey || e.metaKey) {
return;
}
e.stopPropagation();
+7 -1
View File
@@ -41,13 +41,14 @@ const ItemsPage = () => import(/* webpackChunkName: "inventory" */'@/components/
const EquipmentPage = () => import(/* webpackChunkName: "inventory" */'@/components/inventory/equipment/index');
const StablePage = () => import(/* webpackChunkName: "inventory" */'@/components/inventory/stable/index');
// Guilds
// Guilds & Parties
const GuildIndex = () => import(/* webpackChunkName: "guilds" */ '@/components/groups/index');
const TavernPage = () => import(/* webpackChunkName: "guilds" */ '@/components/groups/tavern');
const MyGuilds = () => import(/* webpackChunkName: "guilds" */ '@/components/groups/myGuilds');
const GuildsDiscoveryPage = () => import(/* webpackChunkName: "guilds" */ '@/components/groups/discovery');
const GroupPage = () => import(/* webpackChunkName: "guilds" */ '@/components/groups/group');
const GroupPlansAppPage = () => import(/* webpackChunkName: "guilds" */ '@/components/groups/groupPlan');
const LookingForParty = () => import(/* webpackChunkName: "guilds" */ '@/components/groups/lookingForParty');
// Group Plans
const GroupPlanIndex = () => import(/* webpackChunkName: "group-plans" */ '@/components/group-plans/index');
@@ -126,6 +127,7 @@ const router = new VueRouter({
],
},
{ name: 'party', path: '/party', component: GroupPage },
{ name: 'lookingForParty', path: '/looking-for-party', component: LookingForParty },
{ name: 'groupPlan', path: '/group-plans', component: GroupPlansAppPage },
{
name: 'groupPlanDetail',
@@ -291,6 +293,10 @@ router.beforeEach(async (to, from, next) => {
}
}
if (to.name === 'party') {
router.app.$root.$emit('update-party');
}
// Redirect old guild urls
if (to.hash.indexOf('#/options/groups/guilds/') !== -1) {
const splits = to.hash.split('/');
+12
View File
@@ -1,3 +1,4 @@
import axios from 'axios';
import { loadAsyncResource } from '@/libs/asyncResource';
export function getMembers (store, forceLoad = false) {
@@ -23,3 +24,14 @@ export function getParty (store, forceLoad = false) {
forceLoad,
});
}
export async function lookingForParty (store, payload) {
let response;
if (payload && payload.page) {
response = await axios.get(`api/v4/looking-for-party?page=${payload.page}`);
} else {
response = await axios.get('api/v4/looking-for-party');
}
return response.data.data;
}