diff --git a/gulp/gulp-build.js b/gulp/gulp-build.js index 25b16fa2c2..94187c53b4 100644 --- a/gulp/gulp-build.js +++ b/gulp/gulp-build.js @@ -47,10 +47,5 @@ gulp.task('build:prod', [ 'build:server', 'prepare:staticNewStuff', 'build:client', -], (done) => { - runSequence( - 'grunt-build:prod', - 'apidoc', - done - ); -}); + 'apidoc', +]); diff --git a/webpack/webpack.base.conf.js b/webpack/webpack.base.conf.js index 6717b9ab84..a760cd4dd5 100644 --- a/webpack/webpack.base.conf.js +++ b/webpack/webpack.base.conf.js @@ -105,7 +105,12 @@ const baseConfig = { { test: /\.svg$/, use: [ - { loader: 'svg-url-loader' }, + { + loader: 'svg-url-loader', + options: { + limit: 10000, + }, + }, { loader: 'svgo-loader' }, ], include: [path.resolve(projectRoot, 'website/client/assets/svg/for-css')], diff --git a/website/client/assets/scss/item.scss b/website/client/assets/scss/item.scss index da4056acfe..01021ec567 100644 --- a/website/client/assets/scss/item.scss +++ b/website/client/assets/scss/item.scss @@ -2,7 +2,7 @@ .items > div { display: inline-block; - margin-right: 23px; + margin-right: 24px; } .items > div:last-of-type { diff --git a/website/client/components/appMenu.vue b/website/client/components/appMenu.vue index 3ebac07fed..e0807ef2f0 100644 --- a/website/client/components/appMenu.vue +++ b/website/client/components/appMenu.vue @@ -3,9 +3,10 @@ div inbox-modal creator-intro profile - nav.navbar.navbar-inverse.fixed-top.navbar-toggleable-lg + nav.navbar.navbar-inverse.fixed-top.navbar-toggleable-md .navbar-header - .logo.svg-icon(v-html="icons.logo") + .logo.svg-icon.hidden-lg-down(v-html="icons.logo") + .svg-icon.gryphon.hidden-xl-up b-collapse#nav_collapse.collapse.navbar-collapse(is-nav) ul.navbar-nav.mr-auto router-link.nav-item(tag="li", :to="{name: 'tasks'}", exact) @@ -93,58 +94,34 @@ div @import '~client/assets/scss/colors.scss'; @import '~client/assets/scss/utils.scss'; - /* Less than Desktops and laptops ----------- */ - @media only screen and (max-width : 1224px) { - #nav_collapse { - background: $purple-100; - margin-top: 1em; - margin-left: 70%; - padding-bottom: 1em; - - a { - padding: .5em !important; - } - } - - .dropdown-menu { - position: absolute !important; - left: -10em; - top: -.5em; - } - } - - @media only screen and (max-width : 1224px) and (min-width: 1200px) { - #nav_collapse { - margin-top: 37em !important; - - a { - width: 100%; - } - } - - .navbar-collapse.collapse { - display: none !important; - } - - .navbar-collapse.collapse.show { - display: block !important; - } - - .navbar-toggler, .navbar-nav { - display: block; - } - - .navbar-toggleable-lg .navbar-collapse { - display: block; - } - } - @media only screen and (max-width: 1280px) { .nav-link { padding: .8em 1em !important; } } + @media only screen and (max-width: 1200px) { + .navbar-header { + margin-right: 0px; + } + + .gryphon { + background-image: url('~assets/images/melior@3x.png'); + width: 30px; + height: 30px; + background-size: cover; + color: $white; + margin: 0 auto; + } + } + + @media only screen and (max-width: 990px) { + #nav_collapse { + margin-top: 1.3em; + background-color: $purple-200; + } + } + nav.navbar { background: $purple-100 url(~assets/svg/for-css/bits.svg) right no-repeat; padding-left: 25px; diff --git a/website/client/components/challenges/challengeDetail.vue b/website/client/components/challenges/challengeDetail.vue index 6633be274d..4aa2cdcc6e 100644 --- a/website/client/components/challenges/challengeDetail.vue +++ b/website/client/components/challenges/challengeDetail.vue @@ -35,7 +35,7 @@ b-dropdown.create-dropdown(text="Select a Participant") b-dropdown-item(v-for="member in members", :key="member._id", @click="openMemberProgressModal(member._id)") | {{ member.profile.name }} - span(v-if='isLeader') + span(v-if='isLeader || isAdmin') b-dropdown.create-dropdown(:text="$t('addTaskToChallenge')", :variant="'success'") b-dropdown-item(v-for="type in columns", :key="type", @click="createTask(type)") | {{$t(type)}} @@ -64,13 +64,13 @@ button.btn.btn-success(v-once, @click='joinChallenge()') {{$t('joinChallenge')}} div(v-if='isMember') button.btn.btn-danger(v-once, @click='leaveChallenge()') {{$t('leaveChallenge')}} - div(v-if='isLeader') + div(v-if='isLeader || isAdmin') button.btn.btn-secondary(v-once, @click='edit()') {{$t('editChallenge')}} - div(v-if='isLeader') + div(v-if='isLeader || isAdmin') button.btn.btn-danger(v-once, @click='closeChallenge()') {{$t('endChallenge')}} div(v-if='isLeader || isAdmin') button.btn.btn-secondary(v-once, @click='exportChallengeCsv()') {{$t('exportChallengeCsv')}} - div(v-if='isLeader') + div(v-if='isLeader || isAdmin') button.btn.btn-secondary(v-once, @click='cloneChallenge()') {{$t('clone')}} .description-section h2 {{$t('challengeSummary')}} diff --git a/website/client/components/challenges/challengeModal.vue b/website/client/components/challenges/challengeModal.vue index 12d98dd41d..96a8343256 100644 --- a/website/client/components/challenges/challengeModal.vue +++ b/website/client/components/challenges/challengeModal.vue @@ -17,7 +17,7 @@ .form-group label strong(v-once) {{$t('challengeDescription')}} * - a.float-right {{ $t('markdownFormattingHelp') }} + a.float-right(v-markdown='$t("markdownFormattingHelp")') textarea.description-textarea.form-control(:placeholder="$t('challengeDescriptionPlaceholder')", v-model="workingChallenge.description") .form-group(v-if='creating') label @@ -136,6 +136,8 @@ import bDropdown from 'bootstrap-vue/lib/components/dropdown'; import bDropdownItem from 'bootstrap-vue/lib/components/dropdown-item'; import bFormInput from 'bootstrap-vue/lib/components/form-input'; +import markdownDirective from 'client/directives/markdown'; + import { TAVERN_ID, MIN_SHORTNAME_SIZE_FOR_CHALLENGES, MAX_SUMMARY_SIZE_FOR_CHALLENGES } from '../../../common/script/constants'; import { mapState } from 'client/libs/store'; @@ -147,6 +149,9 @@ export default { bDropdownItem, bFormInput, }, + directives: { + markdown: markdownDirective, + }, data () { let categoryOptions = [ { diff --git a/website/client/components/groups/group.vue b/website/client/components/groups/group.vue index 515e1eecdc..eb45d917fb 100644 --- a/website/client/components/groups/group.vue +++ b/website/client/components/groups/group.vue @@ -56,15 +56,16 @@ button.btn.btn-success(class='btn-success', v-if='isLeader && !group.purchased.active', @click='upgradeGroup()') | {{ $t('upgrade') }} .button-container - button.btn.btn-primary(b-btn, @click="updateGuild", v-once, v-if='isLeader') {{ $t('edit') }} + button.btn.btn-primary(b-btn, @click="updateGuild", v-once, v-if='isLeader || isAdmin') {{ $t('edit') }} .button-container button.btn.btn-success(class='btn-success', v-if='!isMember', @click='join()') {{ $t('join') }} .button-container button.btn.btn-primary(v-once, @click='showInviteModal()') {{$t('invite')}} + // @TODO: hide the invitation button if there's an active group plan and the player is not the leader .button-container - // @TODO: V2 button.btn.btn-primary(v-once, v-if='!isLeader') {{$t('messageGuildLeader')}} + // @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 - // @TODO: V2 button.btn.btn-primary(v-once, v-if='isMember && !isParty') {{$t('donateGems')}} + // @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') .row @@ -81,7 +82,7 @@ .svg-icon(v-html="icons.questIcon") h4(v-once) {{ $t('youAreNotOnQuest') }} p(v-once) {{ $t('questDescription') }} - button.btn.btn-secondary(v-once, @click="openStartQuestModal()", v-if='isLeader') {{ $t('startAQuest') }} + button.btn.btn-secondary(v-once, @click="openStartQuestModal()") {{ $t('startAQuest') }} .row.quest-active-section(v-if='isParty && onPendingQuest && !onActiveQuest') .col-2 .quest(:class='`inventory_quest_scroll_${questData.key}`') @@ -129,7 +130,7 @@ .col-6 span.float-left | Rage {{questData.boss.rage.value}} - button.btn.btn-secondary(v-once, @click="questAbort()", v-if='isLeader') {{ $t('abort') }} + button.btn.btn-secondary(v-once, @click="questAbort()", v-if='canEditQuest') {{ $t('abort') }} .section-header(v-if='!isParty') .row @@ -562,12 +563,17 @@ export default { isLeader () { return this.user._id === this.group.leader._id; }, + isAdmin () { + return Boolean(this.user.contributor.admin); + }, isMember () { return this.isMemberOfGroup(this.user, this.group); }, canEditQuest () { - let isQuestLeader = this.group.quest && this.group.quest.leader === this.user._id; - return isQuestLeader; + if (!this.group.quest) return false; + let isQuestLeader = this.group.quest.leader === this.user._id; + let isPartyLeader = this.group.leader._id === this.user._id; + return isQuestLeader || isPartyLeader; }, isMemberOfPendingQuest () { let userid = this.user._id; @@ -710,6 +716,9 @@ export default { fetchRecentMessages () { this.fetchGuild(); }, + reverseChat () { + this.group.chat.reverse(); + }, updateGuild () { this.$store.state.editingGroup = this.group; this.$root.$emit('show::modal', 'guild-form'); diff --git a/website/client/components/groups/groupFormModal.vue b/website/client/components/groups/groupFormModal.vue index bb68fd0e4a..4ca41d8906 100644 --- a/website/client/components/groups/groupFormModal.vue +++ b/website/client/components/groups/groupFormModal.vue @@ -63,7 +63,7 @@ .form-group label strong(v-once) {{$t('groupDescription')}} * - a.float-right {{ $t('markdownFormattingHelp') }} + a.float-right(v-markdown='$t("markdownFormattingHelp")') textarea.form-control.description-textarea(type="text", textarea, :placeholder="isParty ? $t('partyDescriptionPlaceholder') : $t('guildDescriptionPlaceholder')", v-model="workingGroup.description") .form-group(v-if='creatingParty && !workingGroup.id') @@ -177,6 +177,7 @@ import bTooltip from 'bootstrap-vue/lib/components/tooltip'; import { mapState } from 'client/libs/store'; import toggleSwitch from 'client/components/ui/toggleSwitch'; +import markdownDirective from 'client/directives/markdown'; import gemIcon from 'assets/svg/gem.svg'; import informationIcon from 'assets/svg/information.svg'; @@ -198,6 +199,9 @@ export default { bTooltip, toggleSwitch, }, + directives: { + markdown: markdownDirective, + }, data () { let data = { workingGroup: { diff --git a/website/client/components/groups/questDetailsModal.vue b/website/client/components/groups/questDetailsModal.vue index d25c1618d5..c86c91e733 100644 --- a/website/client/components/groups/questDetailsModal.vue +++ b/website/client/components/groups/questDetailsModal.vue @@ -13,9 +13,10 @@ .pending.float-right(v-if='member.accepted === null') {{ $t('pending') }} div(v-if='questData') questDialogContent(:item="questData") - div.text-center.actions + div.text-center.actions(v-if='canEditQuest') div button.btn.btn-secondary(v-once, @click="questForceStart()") {{ $t('begin') }} + // @TODO don't allow the party leader to start the quest until the leader has accepted or rejected the invitation (users get confused and think "begin" means "join quest") div .cancel(v-once, @click="questCancel()") {{ $t('cancel') }} .side-panel(v-if='questData') @@ -189,6 +190,12 @@ export default { }; }); }, + canEditQuest () { + if (!this.group.quest) return false; + let isQuestLeader = this.group.quest.leader === this.user._id; + let isPartyLeader = this.group.leader._id === this.user._id; + return isQuestLeader || isPartyLeader; + }, }, methods: { async questForceStart () { diff --git a/website/client/components/inventory/items/index.vue b/website/client/components/inventory/items/index.vue index cb747fcb20..05e7ef4dd4 100644 --- a/website/client/components/inventory/items/index.vue +++ b/website/client/components/inventory/items/index.vue @@ -127,10 +127,7 @@ :count="context.item.quantity" ) - hatchedPetDialog( - :pet="hatchedPet", - @closed="closeHatchedPetDialog()" - ) + hatchedPetDialog() div.hatchingPotionInfo(ref="draggingPotionInfo") div(v-if="currentDraggingPotion != null") @@ -251,7 +248,6 @@ export default { currentDraggingPotion: null, potionClickMode: false, - hatchedPet: null, cardOptions: { cardType: '', messageOptions: 0, @@ -345,7 +341,7 @@ export default { }, hatchPet (potion, egg) { this.$store.dispatch('common:hatch', {egg: egg.key, hatchingPotion: potion.key}); - this.hatchedPet = createAnimal(egg, potion, 'pet', this.content, this.user.items); + this.$root.$emit('hatchedPet::open', createAnimal(egg, potion, 'pet', this.content, this.user.items)); }, onDragEnd () { this.currentDraggingPotion = null; @@ -405,9 +401,6 @@ export default { this.potionClickMode = false; } }, - closeHatchedPetDialog () { - this.hatchedPet = null; - }, async itemClicked (groupKey, item) { if (item.type && item.type === 'card') { diff --git a/website/client/components/inventory/stable/hatchedPetDialog.vue b/website/client/components/inventory/stable/hatchedPetDialog.vue index 98217031f6..3c1610a91f 100644 --- a/website/client/components/inventory/stable/hatchedPetDialog.vue +++ b/website/client/components/inventory/stable/hatchedPetDialog.vue @@ -1,12 +1,10 @@