Merge pull request #5926 from Ocelot-Social-Community/merge-5750-in-5818

feat(webapp): hide navbar by scroll, filter button for content
This commit is contained in:
Moriz Wahl 2023-02-06 12:41:52 +01:00 committed by GitHub
commit cdd03a8a30
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 225 additions and 38 deletions

View File

@ -1,6 +1,12 @@
import { Then } from "cypress-cucumber-preprocessor/steps";
Then('I can see my new name {string} when I click on my profile picture in the top right', name => {
cy.get(".avatar-menu").then(($menu) => {
if (!$menu.is(':visible')){
cy.scrollTo("top");
cy.wait(500);
}
})
cy.get('.avatar-menu').click() // open
cy.get('.avatar-menu-popover').contains(name)
cy.get('.avatar-menu').click() // close again

View File

@ -1,6 +1,12 @@
import { When } from "cypress-cucumber-preprocessor/steps";
When("I log out", () => {
cy.get(".avatar-menu").then(($menu) => {
if (!$menu.is(':visible')){
cy.scrollTo("top");
cy.wait(500);
}
})
cy.get(".avatar-menu")
.click();
cy.get(".avatar-menu-popover")

View File

@ -0,0 +1,5 @@
<!-- Generated by IcoMoon.io -->
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">
<title>angle-up</title>
<path d="M16 6.594l0.719 0.688 12.5 12.5-1.438 1.438-11.781-11.781-11.781 11.781-1.438-1.438 12.5-12.5z"></path>
</svg>

After

Width:  |  Height:  |  Size: 275 B

View File

@ -11,15 +11,7 @@
<base-icon class="dropdown-arrow" name="angle-down" />
</base-button>
<template slot="popover">
<div class="filter-menu-options">
<h2 class="title">{{ $t('filter-menu.filter-by') }}</h2>
<following-filter />
<categories-filter v-if="categoriesActive" :showMobileMenu="showMobileMenu" />
</div>
<div class="filter-menu-options">
<h2 class="title">{{ $t('filter-menu.order-by') }}</h2>
<order-by-filter />
</div>
<filter-menu-component :showMobileMenu="showMobileMenu" />
</template>
</dropdown>
</template>
@ -27,21 +19,12 @@
<script>
import Dropdown from '~/components/Dropdown'
import { mapGetters } from 'vuex'
import FollowingFilter from './FollowingFilter'
import OrderByFilter from './OrderByFilter'
import CategoriesFilter from './CategoriesFilter'
import FilterMenuComponent from './FilterMenuComponent'
export default {
components: {
Dropdown,
FollowingFilter,
OrderByFilter,
CategoriesFilter,
},
data() {
return {
categoriesActive: this.$env.CATEGORIES_ACTIVE,
}
FilterMenuComponent,
},
props: {
placement: { type: String },
@ -55,14 +38,3 @@ export default {
},
}
</script>
<style lang="scss">
.filter-menu-options {
max-width: $size-max-width-filter-menu;
padding: $space-small $space-x-small;
> .title {
font-size: $font-size-large;
}
}
</style>

View File

@ -0,0 +1,46 @@
<template>
<div>
<div class="filter-menu-options">
<h2 class="title">{{ $t('filter-menu.filter-by') }}</h2>
<following-filter />
<categories-filter v-if="categoriesActive" :showMobileMenu="showMobileMenu" />
</div>
<div class="filter-menu-options">
<h2 class="title">{{ $t('filter-menu.order-by') }}</h2>
<order-by-filter />
</div>
</div>
</template>
<script>
import FollowingFilter from './FollowingFilter'
import OrderByFilter from './OrderByFilter'
import CategoriesFilter from './CategoriesFilter'
export default {
components: {
FollowingFilter,
OrderByFilter,
CategoriesFilter,
},
data() {
return {
categoriesActive: this.$env.CATEGORIES_ACTIVE,
}
},
props: {
showMobileMenu: { type: Boolean, default: false },
},
}
</script>
<style lang="scss">
.filter-menu-options {
max-width: $size-max-width-filter-menu;
padding: $space-small $space-x-small;
> .title {
font-size: $font-size-large;
}
}
</style>

View File

@ -1,5 +1,9 @@
<template>
<ds-container class="main-navigation-container" style="padding: 10px 10px">
<ds-container
class="main-navigation-container"
:class="{ 'hide-navbar': hideNavbar }"
id="navbar"
>
<div>
<!-- header menu -->
<ds-flex v-if="!showMobileMenu" class="main-navigation-flex">
@ -56,7 +60,10 @@
</ds-flex-item>
<!-- filter menu -->
<!-- TODO: Filter is only visible on index -->
<ds-flex-item v-if="isLoggedIn" style="flex-grow: 0; flex-basis: auto">
<ds-flex-item
v-if="isLoggedIn && SHOW_CONTENT_FILTER_HEADER_MENU"
style="flex-grow: 0; flex-basis: auto"
>
<client-only>
<filter-menu v-show="showFilterMenuDropdown" />
</client-only>
@ -227,6 +234,7 @@
import { mapGetters } from 'vuex'
import isEmpty from 'lodash/isEmpty'
import { SHOW_GROUP_BUTTON_IN_HEADER } from '~/constants/groups.js'
import { SHOW_CONTENT_FILTER_HEADER_MENU } from '~/constants/filter.js'
import LOGOS from '~/constants/logos.js'
import headerMenu from '~/constants/headerMenu.js'
import AvatarMenu from '~/components/AvatarMenu/AvatarMenu'
@ -259,10 +267,13 @@ export default {
},
data() {
return {
hideNavbar: false,
prevScrollpos: 0,
isEmpty,
links,
LOGOS,
SHOW_GROUP_BUTTON_IN_HEADER,
SHOW_CONTENT_FILTER_HEADER_MENU,
isHeaderMenu: headerMenu.MENU.length > 0,
menu: headerMenu.MENU,
mobileSearchVisible: false,
@ -281,14 +292,32 @@ export default {
},
},
methods: {
handleScroll() {
const currentScrollPos = window.pageYOffset
if (this.prevScrollpos > currentScrollPos) {
this.hideNavbar = false
} else {
this.hideNavbar = true
}
this.prevScrollpos = currentScrollPos
},
toggleMobileMenuView() {
this.toggleMobileMenu = !this.toggleMobileMenu
},
},
mounted() {
window.addEventListener('scroll', this.handleScroll)
},
}
</script>
<style lang="scss">
#navbar {
padding: 10px 10px;
}
.hide-navbar {
display: none;
}
.margin-right-20 {
margin-right: 20px;
}

View File

@ -0,0 +1,2 @@
export const SHOW_CONTENT_FILTER_HEADER_MENU = false
export const SHOW_CONTENT_FILTER_MASONRY_GRID = true

View File

@ -5,7 +5,7 @@
</div>
<ds-container>
<div class="main-container">
<nuxt />
<nuxt :showMobileMenu="showMobileMenu" />
</div>
</ds-container>
<page-footer v-if="!isMobile" />

View File

@ -267,8 +267,12 @@
"happy": "Glücklich",
"surprised": "Erstaunt"
},
"filterALL": "Alle Beiträge anzeigen",
"filterFollow": "Beiträge von Benutzern filtern, denen ich folge",
"filterMasonryGrid": {
"myFriends": "Beiträge von meinen Freunden",
"myTopics": "Meine Themen",
"noFilter": "Beiträge filtern"
},
"inappropriatePicture": "Dieses Bild kann für einige Menschen unangemessen sein.",
"languageSelectLabel": "Sprache Deines Beitrags",
"languageSelectText": "Sprache wählen",
@ -371,6 +375,7 @@
"filter-menu": {
"all": "Alle",
"categories": "Themen",
"deleteFilter": "Filter löschen",
"emotions": "Emotionen",
"filter-by": "Filtern nach ...",
"following": "Benutzern, denen ich folge",

View File

@ -267,8 +267,12 @@
"happy": "Happy",
"surprised": "Surprised"
},
"filterALL": "View all contributions",
"filterFollow": "Filter contributions from users I follow",
"filterMasonryGrid": {
"myFriends": "Posts from my friends",
"myTopics": "My topics",
"noFilter": "Filter posts"
},
"inappropriatePicture": "This image may be inappropriate for some people.",
"languageSelectLabel": "Language of your contribution",
"languageSelectText": "Select Language",
@ -371,6 +375,7 @@
"filter-menu": {
"all": "All",
"categories": "Topics",
"deleteFilter": "Delete filter",
"emotions": "Emotions",
"filter-by": "Filter by ...",
"following": "Users I follow",

View File

@ -73,6 +73,9 @@ describe('PostIndex', () => {
$route: {
query: {},
},
$env: {
CATEGORIES_ACTIVE: true,
},
}
})

View File

@ -4,6 +4,57 @@
<ds-grid-item v-if="hashtag" :row-span="2" column-span="fullWidth">
<hashtags-filter :hashtag="hashtag" @clearSearch="clearSearch" />
</ds-grid-item>
<!--Filter Button-->
<ds-grid-item
v-if="categoriesActive && SHOW_CONTENT_FILTER_MASONRY_GRID"
:row-span="1"
column-span="fullWidth"
class="filterButtonMenu"
:class="{ 'hide-filter': hideFilter }"
>
<base-button
class="my-filter-button"
v-if="!postsFilter['categories_some'] && !postsFilter['author']"
right
@click="showFilter = !showFilter"
filled
>
{{ $t('contribution.filterMasonryGrid.noFilter') }}
&nbsp;
<base-icon class="my-filter-button" :name="filterButtonIcon"></base-icon>
</base-button>
<span v-if="postsFilter['categories_some']">
<base-button class="my-filter-button" right @click="showFilter = !showFilter" filled>
{{ $t('contribution.filterMasonryGrid.myTopics') }}
</base-button>
<base-button
class="filter-remove"
@click="resetCategories"
icon="close"
:title="$t('filter-menu.deleteFilter')"
style="margin-left: -8px"
filled
/>
</span>
<span v-if="postsFilter['author']">
<base-button class="my-filter-button" right @click="showFilter = !showFilter" filled>
{{ $t('contribution.filterMasonryGrid.myFriends') }}
</base-button>
<base-button
class="filter-remove"
@click="resetByFollowed"
icon="close"
:title="$t('filter-menu.deleteFilter')"
style="margin-left: -8px"
filled
/>
</span>
<div id="my-filter" v-if="showFilter">
<filter-menu-component :showMobileMenu="showMobileMenu" />
</div>
</ds-grid-item>
<ds-space :margin-bottom="{ base: 'small', md: 'base', lg: 'large' }" />
<!-- donation info -->
<ds-grid-item v-if="showDonations" class="top-info-bar" :row-span="1" column-span="fullWidth">
<donation-info :goal="goal" :progress="progress" />
@ -65,6 +116,8 @@ import { mapGetters, mapMutations } from 'vuex'
import { DonationsQuery } from '~/graphql/Donations'
import { filterPosts } from '~/graphql/PostQuery.js'
import UpdateQuery from '~/components/utils/UpdateQuery'
import FilterMenuComponent from '~/components/FilterMenu/FilterMenuComponent'
import { SHOW_CONTENT_FILTER_MASONRY_GRID } from '~/constants/filter.js'
export default {
components: {
@ -74,11 +127,18 @@ export default {
HcEmpty,
MasonryGrid,
MasonryGridItem,
FilterMenuComponent,
},
mixins: [postListActions],
props: {
showMobileMenu: { type: Boolean, default: false },
},
data() {
const { hashtag = null } = this.$route.query
return {
hideFilter: false,
revScrollpos: 0,
showFilter: false,
showDonations: true,
goal: 15000,
progress: 7000,
@ -88,6 +148,8 @@ export default {
offset: 0,
pageSize: 12,
hashtag,
categoriesActive: this.$env.CATEGORIES_ACTIVE,
SHOW_CONTENT_FILTER_MASONRY_GRID,
}
},
computed: {
@ -95,6 +157,12 @@ export default {
postsFilter: 'posts/filter',
orderBy: 'posts/orderBy',
}),
filterButtonIcon() {
if (Object.keys(this.postsFilter).length === 0) {
return this.showFilter ? 'angle-up' : 'angle-down'
}
return 'close'
},
finalFilters() {
let filter = this.postsFilter
if (this.hashtag) {
@ -118,12 +186,33 @@ export default {
this.resetCategories()
this.toggleCategory(this.categoryId)
}
document.addEventListener('click', this.showFilterMenu)
window.addEventListener('scroll', this.handleScroll)
},
methods: {
...mapMutations({
resetByFollowed: 'posts/TOGGLE_FILTER_BY_FOLLOWED',
resetCategories: 'posts/RESET_CATEGORIES',
toggleCategory: 'posts/TOGGLE_CATEGORY',
}),
showFilterMenu(e) {
if (!e.target.closest('#my-filter') && !e.target.closest('.my-filter-button')) {
if (!this.showFilter) return
this.showFilter = false
}
},
handleScroll() {
const currentScrollPos = window.pageYOffset
if (this.prevScrollpos > currentScrollPos) {
this.hideFilter = false
} else {
this.hideFilter = true
}
this.prevScrollpos = currentScrollPos
},
beforeDestroy() {
document.removeEventListener('click', this.showFilterMenu)
},
clearSearch() {
this.$router.push({ path: '/' })
this.hashtag = null
@ -194,6 +283,13 @@ export default {
</script>
<style lang="scss">
#my-filter {
background-color: white;
box-shadow: rgb(189 189 189) 1px 9px 15px 1px;
max-height: 480px;
overflow: auto;
}
.masonry-grid {
display: grid;
grid-gap: 10px;
@ -209,6 +305,10 @@ export default {
}
}
.hide-filter {
display: none;
}
.base-button.--circle.post-add-button {
height: 54px;
width: 54px;
@ -225,4 +325,12 @@ export default {
display: flex;
align-items: center;
}
.filterButtonMenu {
position: fixed;
z-index: 6;
margin-top: -35px;
padding: 20px 10px 5px 10px;
border-radius: 7px;
background-color: #f5f4f6;
}
</style>