Improved challenge layout.

This commit is contained in:
Marvin Rabe
2018-05-01 16:10:22 +02:00
parent 5faf00d489
commit 4e4181a394
5 changed files with 294 additions and 261 deletions

View File

@@ -6,7 +6,7 @@
challenge-member-progress-modal(:memberId='progressMemberId', :challengeId='challenge._id') challenge-member-progress-modal(:memberId='progressMemberId', :challengeId='challenge._id')
.col-12.col-md-8.standard-page .col-12.col-md-8.standard-page
.row .row
.col-12.col-md-8 .col-12.col-md-6
h1(v-markdown='challenge.name') h1(v-markdown='challenge.name')
div div
strong(v-once) {{$t('createdBy')}}: strong(v-once) {{$t('createdBy')}}:
@@ -19,7 +19,7 @@
// span {{challenge.endDate}} // span {{challenge.endDate}}
.tags .tags
span.tag(v-for='tag in challenge.tags') {{tag}} span.tag(v-for='tag in challenge.tags') {{tag}}
.col-12.col-md-4 .col-12.col-md-6.text-right
.box(@click="showMemberModal()") .box(@click="showMemberModal()")
.svg-icon.member-icon(v-html="icons.memberIcon") .svg-icon.member-icon(v-html="icons.memberIcon")
| {{challenge.memberCount}} | {{challenge.memberCount}}
@@ -29,10 +29,10 @@
| {{challenge.prize}} | {{challenge.prize}}
.details(v-once) {{$t('prize')}} .details(v-once) {{$t('prize')}}
.row.challenge-actions .row.challenge-actions
.col-12.col-md-7.offset-md-5 .col-12.col-md-6
span.view-progress strong.view-progress {{ $t('viewProgressOf') }}
strong {{ $t('viewProgressOf') }}
member-search-dropdown(:text="$t('selectParticipant')", :members='members', :challengeId='challengeId', @member-selected='openMemberProgressModal') member-search-dropdown(:text="$t('selectParticipant')", :members='members', :challengeId='challengeId', @member-selected='openMemberProgressModal')
.col-12.col-md-6.text-right
span(v-if='isLeader || isAdmin') span(v-if='isLeader || isAdmin')
b-dropdown.create-dropdown(:text="$t('addTaskToChallenge')", :variant="'success'") b-dropdown.create-dropdown(:text="$t('addTaskToChallenge')", :variant="'success'")
b-dropdown-item(v-for="type in columns", :key="type", @click="createTask(type)") b-dropdown-item(v-for="type in columns", :key="type", @click="createTask(type)")
@@ -56,24 +56,25 @@
v-on:editTask="editTask", v-on:editTask="editTask",
v-if='tasksByType[column].length > 0') v-if='tasksByType[column].length > 0')
.col-12.col-md-4.sidebar.standard-page .col-12.col-md-4.sidebar.standard-page
.acitons .button-container(v-if='canJoin')
div(v-if='canJoin')
button.btn.btn-success(v-once, @click='joinChallenge()') {{$t('joinChallenge')}} button.btn.btn-success(v-once, @click='joinChallenge()') {{$t('joinChallenge')}}
div(v-if='isMember') .button-container(v-if='isLeader || isAdmin')
button.btn.btn-danger(v-once, @click='leaveChallenge()') {{$t('leaveChallenge')}} button.btn.btn-primary(v-once, @click='edit()') {{$t('editChallenge')}}
div(v-if='isLeader || isAdmin') .button-container(v-if='isLeader || isAdmin')
button.btn.btn-secondary(v-once, @click='edit()') {{$t('editChallenge')}} button.btn.btn-primary(v-once, @click='cloneChallenge()') {{$t('clone')}}
div(v-if='isLeader || isAdmin') .button-container(v-if='isLeader || isAdmin')
button.btn.btn-primary(v-once, @click='exportChallengeCsv()') {{$t('exportChallengeCsv')}}
.button-container(v-if='isLeader || isAdmin')
button.btn.btn-danger(v-once, @click='closeChallenge()') {{$t('endChallenge')}} button.btn.btn-danger(v-once, @click='closeChallenge()') {{$t('endChallenge')}}
div(v-if='isLeader || isAdmin') sidebar-section(:title="$t('challengeSummary')")
button.btn.btn-secondary(v-once, @click='exportChallengeCsv()') {{$t('exportChallengeCsv')}}
div(v-if='isLeader || isAdmin')
button.btn.btn-secondary(v-once, @click='cloneChallenge()') {{$t('clone')}}
.description-section
h2 {{$t('challengeSummary')}}
p(v-markdown='challenge.summary') p(v-markdown='challenge.summary')
h2 {{$t('challengeDescription')}} sidebar-section(
:title="$t('challengeDescription')"
:last="true"
)
p(v-markdown='challenge.description') p(v-markdown='challenge.description')
.text-center(v-if='isMember')
button.btn.btn-danger(v-once, @click='leaveChallenge()') {{$t('leaveChallenge')}}
</template> </template>
<style lang='scss' scoped> <style lang='scss' scoped>
@@ -91,6 +92,14 @@
margin-left: .5em; margin-left: .5em;
} }
.button-container {
margin-bottom: 1em;
button {
width: 100%;
}
}
.calendar-icon { .calendar-icon {
width: 12px; width: 12px;
display: inline-block; display: inline-block;
@@ -138,23 +147,12 @@
} }
} }
.acitons {
width: 100%;
div, button {
width: 60%;
margin: 0 auto;
margin-bottom: .5em;
text-align: center;
}
}
.description-section { .description-section {
margin-top: 2em; margin-top: 2em;
} }
.challenge-actions { .challenge-actions {
margin-top: 1em; margin-bottom: 1em;
.view-progress { .view-progress {
margin-right: .5em; margin-right: .5em;
@@ -162,14 +160,6 @@
} }
</style> </style>
<style>
.create-dropdown button {
width: 100%;
font-size: 16px !important;
font-weight: bold !important;
}
</style>
<script> <script>
const TASK_KEYS_TO_REMOVE = ['_id', 'completed', 'date', 'dateCompleted', 'history', 'id', 'streak', 'createdAt', 'challenge']; const TASK_KEYS_TO_REMOVE = ['_id', 'completed', 'date', 'dateCompleted', 'history', 'id', 'streak', 'createdAt', 'challenge'];
@@ -189,6 +179,7 @@ import challengeModal from './challengeModal';
import challengeMemberProgressModal from './challengeMemberProgressModal'; import challengeMemberProgressModal from './challengeMemberProgressModal';
import challengeMemberSearchMixin from 'client/mixins/challengeMemberSearch'; import challengeMemberSearchMixin from 'client/mixins/challengeMemberSearch';
import leaveChallengeModal from './leaveChallengeModal'; import leaveChallengeModal from './leaveChallengeModal';
import sidebarSection from '../sidebarSection';
import taskDefaults from 'common/script/libs/taskDefaults'; import taskDefaults from 'common/script/libs/taskDefaults';
@@ -208,6 +199,7 @@ export default {
challengeModal, challengeModal,
challengeMemberProgressModal, challengeMemberProgressModal,
memberSearchDropdown, memberSearchDropdown,
sidebarSection,
TaskColumn: Column, TaskColumn: Column,
TaskModal, TaskModal,
}, },

View File

@@ -6,6 +6,8 @@ div
.svg-icon.challenge-icon(v-html="icons.challengeIcon") .svg-icon.challenge-icon(v-html="icons.challengeIcon")
h4(v-once) {{ $t('haveNoChallenges') }} h4(v-once) {{ $t('haveNoChallenges') }}
p(v-once) {{ $t('challengeDetails') }} p(v-once) {{ $t('challengeDetails') }}
button.btn.btn-secondary(@click='createChallenge()') {{ $t('createChallenge') }}
template(v-else)
router-link.title(:to="{ name: 'challenge', params: { challengeId: challenge._id } }", v-for='challenge in challenges',:key='challenge._id') router-link.title(:to="{ name: 'challenge', params: { challengeId: challenge._id } }", v-for='challenge in challenges',:key='challenge._id')
.col-12.challenge-item .col-12.challenge-item
.row .row
@@ -25,6 +27,30 @@ div
button.btn.btn-secondary(@click='createChallenge()') {{ $t('createChallenge') }} button.btn.btn-secondary(@click='createChallenge()') {{ $t('createChallenge') }}
</template> </template>
<style lang="scss" scoped>
@import '~client/assets/scss/colors.scss';
.no-quest-section {
padding: 2em;
color: $gray-300;
h4 {
color: $gray-300;
}
p {
margin-bottom: 2em;
}
.svg-icon {
height: 30px;
width: 30px;
margin: 0 auto;
margin-bottom: 2em;
}
}
</style>
<style scoped> <style scoped>
.title { .title {
color: #4E4A57; color: #4E4A57;
@@ -80,15 +106,15 @@ div
</style> </style>
<script> <script>
import challengeModal from './challengeModal'; import challengeModal from './challengeModal';
import { mapState } from 'client/libs/store'; import {mapState} from 'client/libs/store';
import markdownDirective from 'client/directives/markdown'; import markdownDirective from 'client/directives/markdown';
import challengeIcon from 'assets/svg/challenge.svg'; import challengeIcon from 'assets/svg/challenge.svg';
import gemIcon from 'assets/svg/gem.svg'; import gemIcon from 'assets/svg/gem.svg';
import memberIcon from 'assets/svg/member-icon.svg'; import memberIcon from 'assets/svg/member-icon.svg';
export default { export default {
props: ['groupId'], props: ['groupId'],
components: { components: {
challengeModal, challengeModal,
@@ -96,7 +122,7 @@ export default {
computed: { computed: {
...mapState({user: 'user.data'}), ...mapState({user: 'user.data'}),
}, },
data () { data() {
return { return {
challenges: [], challenges: [],
icons: Object.freeze({ icons: Object.freeze({
@@ -110,27 +136,27 @@ export default {
directives: { directives: {
markdown: markdownDirective, markdown: markdownDirective,
}, },
mounted () { mounted() {
this.loadChallenges(); this.loadChallenges();
}, },
watch: { watch: {
async groupId () { async groupId() {
this.loadChallenges(); this.loadChallenges();
}, },
}, },
methods: { methods: {
async loadChallenges () { async loadChallenges() {
this.groupIdForChallenges = this.groupId; this.groupIdForChallenges = this.groupId;
if (this.groupId === 'party' && this.user.party._id) this.groupIdForChallenges = this.user.party._id; if (this.groupId === 'party' && this.user.party._id) this.groupIdForChallenges = this.user.party._id;
this.challenges = await this.$store.dispatch('challenges:getGroupChallenges', {groupId: this.groupIdForChallenges}); this.challenges = await this.$store.dispatch('challenges:getGroupChallenges', {groupId: this.groupIdForChallenges});
}, },
createChallenge () { createChallenge() {
this.$root.$emit('bv::show::modal', 'challenge-modal'); this.$root.$emit('bv::show::modal', 'challenge-modal');
}, },
challengeCreated (challenge) { challengeCreated(challenge) {
if (challenge.group._id !== this.groupIdForChallenges) return; if (challenge.group._id !== this.groupIdForChallenges) return;
this.challenges.push(challenge); this.challenges.push(challenge);
}, },
}, },
}; };
</script> </script>

View File

@@ -61,47 +61,16 @@
// @TODO: V2 button.btn.btn-primary(v-once, v-if='!isLeader') {{$t('messageGuildLeader')}} // Suggest making the button visible to the leader too - useful for them to test how the feature works or to send a note to themself. -- Alys // @TODO: V2 button.btn.btn-primary(v-once, v-if='!isLeader') {{$t('messageGuildLeader')}} // Suggest making the button visible to the leader too - useful for them to test how the feature works or to send a note to themself. -- Alys
.button-container .button-container
// @TODO: V2 button.btn.btn-primary(v-once, v-if='isMember && !isParty') {{$t('donateGems')}} // Suggest removing the isMember restriction - it's okay if non-members donate to a public guild. Also probably allow it for parties if parties can buy imagery. -- Alys // @TODO: V2 button.btn.btn-primary(v-once, v-if='isMember && !isParty') {{$t('donateGems')}} // Suggest removing the isMember restriction - it's okay if non-members donate to a public guild. Also probably allow it for parties if parties can buy imagery. -- Alys
.section-header(v-if='isParty') quest-sidebar-section(:group='group', v-if='isParty')
quest-sidebar-section(@toggle='toggleQuestSection', :show='sections.quest', :group='group') sidebar-section(:title="$t('guildSummary')", v-if='!isParty')
.section-header(v-if='!isParty')
.row
.col-10
h3(v-once) {{ $t('guildSummary') }}
.col-2
.toggle-up(@click="sections.summary = !sections.summary", v-if="sections.summary")
.svg-icon(v-html="icons.upIcon")
.toggle-down(@click="sections.summary = !sections.summary", v-if="!sections.summary")
.svg-icon(v-html="icons.downIcon")
.section(v-if="sections.summary")
p(v-markdown='group.summary') p(v-markdown='group.summary')
.section-header sidebar-section(:title="$t('groupDescription')")
.row
.col-10
h3 {{ $t('groupDescription') }}
.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-markdown='group.description') p(v-markdown='group.description')
.section-header.challenge sidebar-section(
.row :title="$t('challenges')",
.col-10.information-header :tooltip="isParty ? $t('challengeDetails') : $t('privateDescription')"
h3(v-once) :last="true"
| {{ $t('challenges') }}
#groupPrivateDescOrChallengeInfo.icon.tooltip-wrapper(:title="isParty ? $t('challengeDetails') : $t('privateDescription')")
.svg-icon(v-html='icons.information')
b-tooltip(
:title="isParty ? $t('challengeDetails') : $t('privateDescription')",
target="groupPrivateDescOrChallengeInfo",
) )
.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")
group-challenges(:groupId='searchId') group-challenges(:groupId='searchId')
div.text-center div.text-center
button.btn.btn-danger(v-if='isMember', @click='clickLeave()') {{ isParty ? $t('leaveParty') : $t('leaveGroup') }} button.btn.btn-danger(v-if='isMember', @click='clickLeave()') {{ isParty ? $t('leaveParty') : $t('leaveGroup') }}
@@ -270,29 +239,6 @@
margin-right: .3em; margin-right: .3em;
} }
.information-header {
h3, .tooltip-wrapper {
display: inline-block;
}
.tooltip-wrapper {
width: 15px;
margin-left: 1.2em;
}
}
.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;
}
.hr { .hr {
width: 100%; width: 100%;
height: 20px; height: 20px;
@@ -334,6 +280,7 @@ import groupGemsModal from 'client/components/groups/groupGemsModal';
import questSidebarSection from 'client/components/groups/questSidebarSection'; import questSidebarSection from 'client/components/groups/questSidebarSection';
import markdownDirective from 'client/directives/markdown'; import markdownDirective from 'client/directives/markdown';
import communityGuidelines from './communityGuidelines'; import communityGuidelines from './communityGuidelines';
import sidebarSection from '../sidebarSection';
import deleteIcon from 'assets/svg/delete.svg'; import deleteIcon from 'assets/svg/delete.svg';
import copyIcon from 'assets/svg/copy.svg'; import copyIcon from 'assets/svg/copy.svg';
@@ -342,10 +289,7 @@ import likedIcon from 'assets/svg/liked.svg';
import reportIcon from 'assets/svg/report.svg'; import reportIcon from 'assets/svg/report.svg';
import gemIcon from 'assets/svg/gem.svg'; import gemIcon from 'assets/svg/gem.svg';
import questIcon from 'assets/svg/quest.svg'; import questIcon from 'assets/svg/quest.svg';
import informationIcon from 'assets/svg/information.svg';
import questBackground from 'assets/svg/quest-background-border.svg'; import questBackground from 'assets/svg/quest-background-border.svg';
import upIcon from 'assets/svg/up.svg';
import downIcon from 'assets/svg/down.svg';
import goldGuildBadgeIcon from 'assets/svg/gold-guild-badge-small.svg'; import goldGuildBadgeIcon from 'assets/svg/gold-guild-badge-small.svg';
import silverGuildBadgeIcon from 'assets/svg/silver-guild-badge-small.svg'; import silverGuildBadgeIcon from 'assets/svg/silver-guild-badge-small.svg';
import bronzeGuildBadgeIcon from 'assets/svg/bronze-guild-badge-small.svg'; import bronzeGuildBadgeIcon from 'assets/svg/bronze-guild-badge-small.svg';
@@ -365,6 +309,7 @@ export default {
groupGemsModal, groupGemsModal,
questSidebarSection, questSidebarSection,
communityGuidelines, communityGuidelines,
sidebarSection,
}, },
directives: { directives: {
markdown: markdownDirective, markdown: markdownDirective,
@@ -381,22 +326,13 @@ export default {
gem: gemIcon, gem: gemIcon,
liked: likedIcon, liked: likedIcon,
questIcon, questIcon,
information: informationIcon,
questBackground, questBackground,
upIcon,
downIcon,
goldGuildBadgeIcon, goldGuildBadgeIcon,
silverGuildBadgeIcon, silverGuildBadgeIcon,
bronzeGuildBadgeIcon, bronzeGuildBadgeIcon,
}), }),
members: [], members: [],
selectedQuest: {}, selectedQuest: {},
sections: {
quest: true,
summary: true,
description: true,
challenges: true,
},
newMessage: '', newMessage: '',
coords: { coords: {
TOP: 0, TOP: 0,
@@ -698,9 +634,6 @@ export default {
showGroupGems () { showGroupGems () {
this.$root.$emit('bv::show::modal', 'group-gems-modal'); this.$root.$emit('bv::show::modal', 'group-gems-modal');
}, },
toggleQuestSection () {
this.sections.quest = !this.sections.quest;
},
}, },
}; };
</script> </script>

View File

@@ -1,14 +1,5 @@
<template lang="pug"> <template lang="pug">
div sidebar-section(:title="$t('questDetailsTitle')")
.row
.col-10
h3(v-once) {{ $t('questDetailsTitle') }}
.col-2
.toggle-up(@click="toggle()", v-if="show")
.svg-icon(v-html="icons.upIcon")
.toggle-down(@click="toggle()", v-if="!show")
.svg-icon(v-html="icons.downIcon")
.section(v-if="show")
.row.no-quest-section(v-if='!onPendingQuest && !onActiveQuest') .row.no-quest-section(v-if='!onPendingQuest && !onActiveQuest')
.col-12.text-center .col-12.text-center
.svg-icon(v-html="icons.questIcon") .svg-icon(v-html="icons.questIcon")
@@ -193,18 +184,18 @@ import { mapState } from 'client/libs/store';
import quests from 'common/script/content/quests'; import quests from 'common/script/content/quests';
import percent from 'common/script/libs/percent'; import percent from 'common/script/libs/percent';
import sidebarSection from '../sidebarSection';
import upIcon from 'assets/svg/up.svg';
import downIcon from 'assets/svg/down.svg';
import questIcon from 'assets/svg/quest.svg'; import questIcon from 'assets/svg/quest.svg';
export default { export default {
props: ['show', 'group'], props: ['group'],
components: {
sidebarSection,
},
data () { data () {
return { return {
icons: Object.freeze({ icons: Object.freeze({
upIcon,
downIcon,
questIcon, questIcon,
}), }),
}; };
@@ -261,9 +252,6 @@ export default {
}, },
}, },
methods: { methods: {
toggle () {
this.$emit('toggle');
},
openStartQuestModal () { openStartQuestModal () {
this.$root.$emit('bv::show::modal', 'start-quest-modal'); this.$root.$emit('bv::show::modal', 'start-quest-modal');
}, },

View File

@@ -0,0 +1,94 @@
<template lang="pug">
.section(:class="{'section-last': last}")
.section-header.d-flex.align-items-center
h3.mb-0(v-once)
| {{ title }}
.section-info.mx-1(
v-if="tooltip !== null"
)
.svg-icon(
v-html='icons.information',
:id="tooltipId",
:title="tooltip"
)
b-tooltip(
:title="tooltip",
:target="tooltipId",
)
.section-toggle.ml-auto(@click="toggle")
.svg-icon(v-html="icons.upIcon", v-if="visible")
.svg-icon(v-html="icons.downIcon", v-else)
.section-body(v-show="visible")
slot
</template>
<style lang="scss" scoped>
.section {
border-top: 1px solid #e1e0e3;
margin-top: 1em;
padding-top: 1em;
}
.section-last {
border-bottom: 1px solid #e1e0e3;
margin-bottom: 1em;
padding-bottom: 1em;
}
.section-body {
margin-top: 1em;
}
.section-toggle {
cursor: pointer;
}
.section-info {
cursor: help;
}
.section-info .svg-icon,
.section-toggle .svg-icon {
width: 16px;
}
</style>
<script>
import uuid from 'uuid/v4';
import upIcon from 'assets/svg/up.svg';
import downIcon from 'assets/svg/down.svg';
import informationIcon from 'assets/svg/information.svg';
export default {
props: {
title: {
required: true,
},
tooltip: {
default: null,
},
show: {
default: true,
},
last: {
default: false,
},
},
data () {
return {
tooltipId: uuid(),
visible: this.show,
icons: {
upIcon,
downIcon,
information: informationIcon
},
};
},
methods: {
toggle () {
this.visible = !this.visible;
},
},
};
</script>