mirror of
https://github.com/HabitRPG/habitica.git
synced 2025-12-17 14:47:53 +01:00
Onboarding guide and initial achievements refactoring (#11536)
* add achievements to user * add placeholder strings * add to achievements to common script * add onboarding achievements category * add notifications * more notifications * award achievements * wip notification panel * add achievements icons and copy * do not count onboarding tasks for the created task achievement * add notes * sprites, fixes and completion status and reward * add onboarding panel * add toggle * fix toggle size * fix tests * fix typo * add notification * start adding modal * fix remove button positionin, timeout, progress bar * modal + fixes * disable broken social links from level up modal * change toggle icon color on hover * add border bottom to onboarding guide panel * add collapse animation * expanded onboarding on first open * onboarding: flip toggle colors * onboarding: show progress bar all the time * onboarding: fix panel closing on click * onboarding modal: add close icon and fix padding * wip: add migration for existing users * fix titles in guide * fix achievements copy * do not award completed task achievement when direction is down * start implementing new achievements * start migrating client * remove social links from achievements modals * prevent skipping tutorial + fix achievement notification * sync fixes * start redesign achievement modal * misc fixes to achievements, polish generic achievement modal and hatched pet modal * add special badge for onboarding * fix badge condition * modals fixes * hatched pet modal: add close icon * fix badge typo * fix justin button * new scrolling behavior for dropdowns * fix strings capitalization * add common tests * add api unit tests * add date check * achievements modal polishing * typos * add toggle for achievements categories * typo * fix test * fix edit avatar modal cannot be closed * finish migration and correct launch date * fix migration * migration fixes * fix tests
This commit is contained in:
@@ -300,50 +300,64 @@
|
||||
<div
|
||||
v-for="(category, key) in achievements"
|
||||
:key="key"
|
||||
class="row"
|
||||
class="row category-row"
|
||||
>
|
||||
<h2 class="col-12 text-center">
|
||||
<h3 class="col-12 text-center mb-3">
|
||||
{{ $t(key+'Achievs') }}
|
||||
</h2>
|
||||
<div
|
||||
v-for="(achievement, achievKey) in category.achievements"
|
||||
:key="achievKey"
|
||||
class="col-12 col-md-3 text-center"
|
||||
>
|
||||
<div
|
||||
:id="achievKey + '-achievement'"
|
||||
class="box achievement-container"
|
||||
:class="{'achievement-unearned': !achievement.earned}"
|
||||
>
|
||||
<b-popover
|
||||
:target="'#' + achievKey + '-achievement'"
|
||||
triggers="hover"
|
||||
placement="top"
|
||||
>
|
||||
<h4 class="popover-content-title">
|
||||
{{ achievement.title }}
|
||||
</h4>
|
||||
<div
|
||||
class="popover-content-text"
|
||||
v-html="achievement.text"
|
||||
></div>
|
||||
</b-popover>
|
||||
</h3>
|
||||
<div class="col-12">
|
||||
<div class="row achievements-row justify-content-center">
|
||||
<div
|
||||
v-if="achievement.earned"
|
||||
class="achievement"
|
||||
:class="achievement.icon + '2x'"
|
||||
v-for="(achievement, achievKey) in achievementsCategory(key, category)"
|
||||
:key="achievKey"
|
||||
class="achievement-wrapper col text-center"
|
||||
>
|
||||
<div
|
||||
v-if="achievement.optionalCount"
|
||||
class="counter badge badge-info stack-count"
|
||||
:id="achievKey + '-achievement'"
|
||||
class="box achievement-container"
|
||||
:class="{'achievement-unearned': !achievement.earned}"
|
||||
>
|
||||
{{ achievement.optionalCount }}
|
||||
<b-popover
|
||||
:target="'#' + achievKey + '-achievement'"
|
||||
triggers="hover"
|
||||
placement="top"
|
||||
>
|
||||
<h4 class="popover-content-title">
|
||||
{{ achievement.title }}
|
||||
</h4>
|
||||
<div
|
||||
class="popover-content-text"
|
||||
v-html="achievement.text"
|
||||
></div>
|
||||
</b-popover>
|
||||
<div
|
||||
v-if="achievement.earned"
|
||||
class="achievement"
|
||||
:class="achievement.icon + '2x'"
|
||||
>
|
||||
<div
|
||||
v-if="achievement.optionalCount"
|
||||
class="counter badge badge-pill stack-count"
|
||||
>
|
||||
{{ achievement.optionalCount }}
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
v-if="!achievement.earned"
|
||||
class="achievement achievement-unearned achievement-unearned2x"
|
||||
></div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
v-if="!achievement.earned"
|
||||
class="achievement achievement-unearned achievement-unearned2x"
|
||||
></div>
|
||||
v-if="achievementsCategories[key].number > 5"
|
||||
class="btn btn-flat btn-show-more"
|
||||
@click="toggleAchievementsCategory(key)"
|
||||
>
|
||||
{{ achievementsCategories[key].open ?
|
||||
$t('hideAchievements', {category: $t(key+'Achievs')}) :
|
||||
$t('showAllAchievements', {category: $t(key+'Achievs')})
|
||||
}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -353,31 +367,38 @@
|
||||
v-if="user.achievements.challenges"
|
||||
class="col-12 col-md-6"
|
||||
>
|
||||
<div class="achievement-icon achievement-karaoke"></div>
|
||||
<h2 class="text-center">
|
||||
<div class="achievement-icon achievement-karaoke-2x"></div>
|
||||
<h3 class="text-center mt-2 mb-4">
|
||||
{{ $t('challengesWon') }}
|
||||
</h2>
|
||||
</h3>
|
||||
<div
|
||||
v-for="chal in user.achievements.challenges"
|
||||
:key="chal"
|
||||
class="achievement-list-item"
|
||||
>
|
||||
<span v-markdown="chal"></span>
|
||||
<hr>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
v-if="user.achievements.quests"
|
||||
class="col-12 col-md-6"
|
||||
>
|
||||
<div class="achievement-icon achievement-alien"></div>
|
||||
<h2 class="text-center">
|
||||
<div class="achievement-icon achievement-alien2x"></div>
|
||||
<h3 class="text-center mt-2 mb-4">
|
||||
{{ $t('questsCompleted') }}
|
||||
</h2>
|
||||
</h3>
|
||||
<div
|
||||
v-for="(value, key) in user.achievements.quests"
|
||||
:key="key"
|
||||
class="achievement-list-item d-flex justify-content-between"
|
||||
>
|
||||
<span>{{ content.quests[key].text() }} ({{ value }})</span>
|
||||
<span>{{ content.quests[key].text() }}</span>
|
||||
<span
|
||||
v-if="value > 1"
|
||||
class="badge badge-pill stack-count"
|
||||
>
|
||||
{{ value }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -519,37 +540,71 @@
|
||||
}
|
||||
|
||||
#achievements {
|
||||
.category-row {
|
||||
margin-bottom: 34px;
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0px;
|
||||
}
|
||||
}
|
||||
|
||||
.achievements-row {
|
||||
max-width: 590px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.achievement-wrapper {
|
||||
width: 94px;
|
||||
max-width: 94px;
|
||||
margin-right: 12px;
|
||||
margin-left: 12px;
|
||||
padding: 0px;
|
||||
}
|
||||
|
||||
.box {
|
||||
margin: 0 auto;
|
||||
margin-top: 1em;
|
||||
margin-bottom: 1em;
|
||||
padding-top: 1.2em;
|
||||
background: #fff;
|
||||
background: $white;
|
||||
}
|
||||
|
||||
hr {
|
||||
margin-bottom: 48px;
|
||||
margin-top: 48px;
|
||||
}
|
||||
|
||||
.box.achievement-unearned {
|
||||
background-color: #edecee;
|
||||
}
|
||||
|
||||
h2 {
|
||||
margin-top: 1em;
|
||||
background-color: $gray-600;
|
||||
}
|
||||
|
||||
.counter.badge {
|
||||
position: absolute;
|
||||
top: .5em;
|
||||
right: 3em;
|
||||
color: #fff;
|
||||
background-color: #ff944c;
|
||||
box-shadow: 0 1px 1px 0 rgba(26, 24, 29, 0.12);
|
||||
min-width: 24px;
|
||||
min-height: 24px;
|
||||
border-radius: 2em;
|
||||
padding: .5em;
|
||||
top: -0.8em;
|
||||
right: -0.5em;
|
||||
color: $white;
|
||||
background-color: $orange-100;
|
||||
max-height: 24px;
|
||||
}
|
||||
|
||||
.achievement-icon {
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.achievement-list-item {
|
||||
padding-top: 11px;
|
||||
padding-bottom: 12px;
|
||||
border-top: 1px solid $gray-500;
|
||||
|
||||
&:last-child {
|
||||
border-bottom: 1px solid $gray-500;
|
||||
}
|
||||
|
||||
.badge {
|
||||
margin-right: 8px;
|
||||
background: $gray-600;
|
||||
color: $gray-300;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.achievement {
|
||||
@@ -699,6 +754,7 @@ export default {
|
||||
},
|
||||
selectedPage: 'profile',
|
||||
achievements: {},
|
||||
achievementsCategories: {}, // number, open
|
||||
content: Content,
|
||||
user: undefined,
|
||||
};
|
||||
@@ -783,6 +839,16 @@ export default {
|
||||
// @TODO: this common code should handle the above
|
||||
this.achievements = achievementsLib.getAchievementsForProfile(user);
|
||||
|
||||
const achievementsCategories = {};
|
||||
Object.keys(this.achievements).forEach(category => {
|
||||
achievementsCategories[category] = {
|
||||
open: false,
|
||||
number: Object.keys(this.achievements[category].achievements).length,
|
||||
};
|
||||
});
|
||||
|
||||
this.achievementsCategories = achievementsCategories;
|
||||
|
||||
// @TODO For some reason markdown doesn't seem to be handling numbers or maybe undefined?
|
||||
user.profile.blurb = user.profile.blurb ? `${user.profile.blurb}` : '';
|
||||
|
||||
@@ -906,6 +972,27 @@ export default {
|
||||
showAllocation () {
|
||||
return this.user._id === this.userLoggedIn._id && this.hasClass;
|
||||
},
|
||||
achievementsCategory (categoryKey, category) {
|
||||
const achievementsKeys = Object.keys(category.achievements);
|
||||
|
||||
if (this.achievementsCategories[categoryKey].open === true) {
|
||||
return category.achievements;
|
||||
}
|
||||
|
||||
const fiveAchievements = achievementsKeys.slice(0, 5);
|
||||
|
||||
const categoryAchievements = {};
|
||||
|
||||
fiveAchievements.forEach(key => {
|
||||
categoryAchievements[key] = category.achievements[key];
|
||||
});
|
||||
|
||||
return categoryAchievements;
|
||||
},
|
||||
toggleAchievementsCategory (categoryKey) {
|
||||
const status = this.achievementsCategories[categoryKey].open;
|
||||
this.achievementsCategories[categoryKey].open = !status;
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
Reference in New Issue
Block a user