mirror of
https://github.com/IT4Change/Ocelot-Social.git
synced 2025-12-13 07:45:56 +00:00
outsource styling to FilterMenuSection component
@mattwr18 great work and great styling so far! ;) fyi: I noticed there was a lot of duplicate CSS and the solution I came up with is this new component, using slots
This commit is contained in:
parent
863656f718
commit
d9c3412b41
@ -1,15 +1,15 @@
|
|||||||
<template>
|
<template>
|
||||||
<section class="categories-filter">
|
<filter-menu-section :title="$t('filter-menu.categories')" class="categories-filter">
|
||||||
<h4 class="title">{{ $t('filter-menu.categories') }}</h4>
|
<template #sidebar>
|
||||||
<labeled-button
|
<labeled-button
|
||||||
:filled="!filteredCategoryIds.length"
|
:filled="!filteredCategoryIds.length"
|
||||||
:label="$t('filter-menu.all')"
|
:label="$t('filter-menu.all')"
|
||||||
icon="check"
|
icon="check"
|
||||||
@click="resetCategories"
|
@click="resetCategories"
|
||||||
/>
|
/>
|
||||||
<div class="divider" />
|
</template>
|
||||||
<ul class="categories-list">
|
<template #filter-list>
|
||||||
<li v-for="category in categories" :key="category.id" class="menu-item">
|
<li v-for="category in categories" :key="category.id" class="item">
|
||||||
<labeled-button
|
<labeled-button
|
||||||
:icon="category.icon"
|
:icon="category.icon"
|
||||||
:filled="filteredCategoryIds.includes(category.id)"
|
:filled="filteredCategoryIds.includes(category.id)"
|
||||||
@ -17,17 +17,19 @@
|
|||||||
@click="toggleCategory(category.id)"
|
@click="toggleCategory(category.id)"
|
||||||
/>
|
/>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</template>
|
||||||
</section>
|
</filter-menu-section>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { mapGetters, mapMutations } from 'vuex'
|
import { mapGetters, mapMutations } from 'vuex'
|
||||||
import CategoryQuery from '~/graphql/CategoryQuery.js'
|
import CategoryQuery from '~/graphql/CategoryQuery.js'
|
||||||
|
import FilterMenuSection from '~/components/FilterMenu/FilterMenuSection'
|
||||||
import LabeledButton from '~/components/_new/generic/LabeledButton/LabeledButton'
|
import LabeledButton from '~/components/_new/generic/LabeledButton/LabeledButton'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
|
FilterMenuSection,
|
||||||
LabeledButton,
|
LabeledButton,
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
@ -60,66 +62,3 @@ export default {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss">
|
|
||||||
.categories-filter {
|
|
||||||
display: flex;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
margin-top: $space-small;
|
|
||||||
|
|
||||||
> .title {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
> .labeled-button {
|
|
||||||
margin-top: $space-small;
|
|
||||||
}
|
|
||||||
|
|
||||||
> .divider {
|
|
||||||
border-left: $border-size-base solid $border-color-soft;
|
|
||||||
margin: $space-base;
|
|
||||||
}
|
|
||||||
|
|
||||||
> .categories-list {
|
|
||||||
display: flex;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
flex-basis: 80%;
|
|
||||||
flex-grow: 1;
|
|
||||||
|
|
||||||
> .menu-item {
|
|
||||||
width: 12.5%;
|
|
||||||
margin: $space-small 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@media only screen and (max-width: 800px) {
|
|
||||||
.categories-list > .menu-item {
|
|
||||||
width: 16%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@media only screen and (max-width: 630px) {
|
|
||||||
flex-direction: column;
|
|
||||||
|
|
||||||
> .categories-list > .menu-item {
|
|
||||||
width: 25%;
|
|
||||||
margin: $space-x-small 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
> .title {
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
> .divider {
|
|
||||||
border-top: $border-size-base solid $border-color-soft;
|
|
||||||
margin: $space-small;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@media only screen and (max-width: 440px) {
|
|
||||||
.categories-list > .menu-item {
|
|
||||||
width: 50%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|||||||
@ -1,31 +1,36 @@
|
|||||||
<template>
|
<template>
|
||||||
<section class="emotions-filter">
|
<filter-menu-section :title="$t('filter-menu.emotions')" class="emotions-filter">
|
||||||
<h4 class="title">{{ $t('filter-menu.emotions') }}</h4>
|
<template #sidebar>
|
||||||
<labeled-button
|
<labeled-button
|
||||||
:filled="!filteredByEmotions.length"
|
:filled="!filteredByEmotions.length"
|
||||||
icon="check"
|
icon="check"
|
||||||
:label="$t('filter-menu.all')"
|
:label="$t('filter-menu.all')"
|
||||||
@click="resetEmotions"
|
@click="resetEmotions"
|
||||||
/>
|
/>
|
||||||
<div class="divider" />
|
</template>
|
||||||
|
<template #filter-list>
|
||||||
|
<li v-for="emotion in emotionsArray" :key="emotion" class="item">
|
||||||
<emotion-button
|
<emotion-button
|
||||||
v-for="emotion in emotionsArray"
|
|
||||||
:key="emotion"
|
|
||||||
:emojiPath="iconPath(emotion)"
|
:emojiPath="iconPath(emotion)"
|
||||||
:emotion="emotion"
|
:emotion="emotion"
|
||||||
@toggleEmotion="toogleFilteredByEmotions(emotion)"
|
@toggleEmotion="toogleFilteredByEmotions(emotion)"
|
||||||
/>
|
/>
|
||||||
</section>
|
</li>
|
||||||
</template>
|
</template>
|
||||||
|
</filter-menu-section>
|
||||||
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { mapGetters, mapMutations } from 'vuex'
|
import { mapGetters, mapMutations } from 'vuex'
|
||||||
import LabeledButton from '~/components/_new/generic/LabeledButton/LabeledButton'
|
|
||||||
import EmotionButton from '~/components/EmotionButton/EmotionButton'
|
import EmotionButton from '~/components/EmotionButton/EmotionButton'
|
||||||
|
import FilterMenuSection from '~/components/FilterMenu/FilterMenuSection'
|
||||||
|
import LabeledButton from '~/components/_new/generic/LabeledButton/LabeledButton'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
LabeledButton,
|
|
||||||
EmotionButton,
|
EmotionButton,
|
||||||
|
FilterMenuSection,
|
||||||
|
LabeledButton,
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
@ -52,44 +57,3 @@ export default {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<style lang="scss">
|
|
||||||
.emotions-filter {
|
|
||||||
display: flex;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
margin-top: $space-base;
|
|
||||||
width: 66%;
|
|
||||||
|
|
||||||
> .title {
|
|
||||||
width: 100%;
|
|
||||||
margin-bottom: $space-base;
|
|
||||||
}
|
|
||||||
|
|
||||||
> .divider {
|
|
||||||
border-left: $border-size-base solid $border-color-soft;
|
|
||||||
margin: 0px $space-base;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media only screen and (max-width: 630px) {
|
|
||||||
width: 100%;
|
|
||||||
|
|
||||||
> .title {
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.labeled-button {
|
|
||||||
width: 100%;
|
|
||||||
margin: $space-x-small 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
> .divider {
|
|
||||||
width: 100%;
|
|
||||||
margin: $space-small;
|
|
||||||
border-top: $border-size-base solid $border-color-soft;
|
|
||||||
}
|
|
||||||
|
|
||||||
> .emotion-button {
|
|
||||||
margin-top: $space-x-small;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<dropdown ref="menu" :placement="placement" :offset="offset" class="filter-menu">
|
<dropdown ref="menu" placement="top-start" :offset="8" class="filter-menu">
|
||||||
<base-button
|
<base-button
|
||||||
slot="default"
|
slot="default"
|
||||||
icon="filter"
|
icon="filter"
|
||||||
@ -11,16 +11,17 @@
|
|||||||
<base-icon class="dropdown-arrow" name="angle-down" />
|
<base-icon class="dropdown-arrow" name="angle-down" />
|
||||||
</base-button>
|
</base-button>
|
||||||
<template slot="popover">
|
<template slot="popover">
|
||||||
<ds-container class="filter-menu-options">
|
<div class="filter-menu-options">
|
||||||
<h4 class="title">{{ $t('filter-menu.filter-by') }}</h4>
|
<h2 class="title">{{ $t('filter-menu.filter-by') }}</h2>
|
||||||
<following-filter />
|
<following-filter />
|
||||||
<categories-filter />
|
<categories-filter />
|
||||||
<emotions-filter />
|
<emotions-filter />
|
||||||
<languages-filter />
|
<languages-filter />
|
||||||
</ds-container>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</dropdown>
|
</dropdown>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import Dropdown from '~/components/Dropdown'
|
import Dropdown from '~/components/Dropdown'
|
||||||
import { mapGetters } from 'vuex'
|
import { mapGetters } from 'vuex'
|
||||||
@ -48,12 +49,14 @@ export default {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
@media only screen and (max-width: 960px) {
|
|
||||||
.filter-menu-options {
|
.filter-menu-options {
|
||||||
|
max-width: 1026px;
|
||||||
|
padding: $space-small $space-x-small;
|
||||||
|
|
||||||
> .title {
|
> .title {
|
||||||
text-align: center;
|
font-size: $font-size-large;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
94
webapp/components/FilterMenu/FilterMenuSection.vue
Normal file
94
webapp/components/FilterMenu/FilterMenuSection.vue
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
<template>
|
||||||
|
<section class="filter-menu-section">
|
||||||
|
<h3 v-if="title" class="title">{{ title }}</h3>
|
||||||
|
<aside class="sidebar">
|
||||||
|
<slot name="sidebar" />
|
||||||
|
</aside>
|
||||||
|
<div v-if="divider" class="divider" />
|
||||||
|
<ul class="filter-list">
|
||||||
|
<slot name="filter-list" />
|
||||||
|
</ul>
|
||||||
|
</section>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
divider: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true,
|
||||||
|
},
|
||||||
|
title: {
|
||||||
|
type: String,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.filter-menu-section {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
margin-top: $space-small;
|
||||||
|
|
||||||
|
> .title {
|
||||||
|
width: 100%;
|
||||||
|
margin-bottom: $space-small;
|
||||||
|
font-size: $font-size-base;
|
||||||
|
}
|
||||||
|
|
||||||
|
> .sidebar {
|
||||||
|
flex-basis: 12%;
|
||||||
|
max-width: 85px;
|
||||||
|
}
|
||||||
|
|
||||||
|
> .divider {
|
||||||
|
border-left: $border-size-base solid $border-color-soft;
|
||||||
|
margin: $space-small;
|
||||||
|
margin-left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
> .filter-list {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
flex-basis: 80%;
|
||||||
|
flex-grow: 1;
|
||||||
|
|
||||||
|
> .item {
|
||||||
|
width: 12.5%;
|
||||||
|
padding: 0 $space-x-small;
|
||||||
|
margin-bottom: $space-small;
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
@media only screen and (max-width: 800px) {
|
||||||
|
width: 16%;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media only screen and (max-width: 630px) {
|
||||||
|
width: 25%;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media only screen and (max-width: 440px) {
|
||||||
|
width: 50%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media only screen and (max-width: 630px) {
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
|
> .title {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
> .sidebar {
|
||||||
|
max-width: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
> .divider {
|
||||||
|
border-top: $border-size-base solid $border-color-soft;
|
||||||
|
margin: $space-small;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -1,25 +1,25 @@
|
|||||||
<template>
|
<template>
|
||||||
<section class="following-filter">
|
<filter-menu-section :divider="false" class="following-filter">
|
||||||
|
<template #sidebar>
|
||||||
<labeled-button
|
<labeled-button
|
||||||
:filled="filteredByUsersFollowed"
|
|
||||||
icon="user-plus"
|
icon="user-plus"
|
||||||
:label="$t('filter-menu.following')"
|
:label="$t('filter-menu.following')"
|
||||||
|
:filled="filteredByUsersFollowed"
|
||||||
|
:title="$t('contribution.filterFollow')"
|
||||||
@click="toggleFilteredByFollowed(currentUser.id)"
|
@click="toggleFilteredByFollowed(currentUser.id)"
|
||||||
v-tooltip="{
|
|
||||||
content: this.$t('contribution.filterFollow'),
|
|
||||||
placement: 'left',
|
|
||||||
delay: { show: 500 },
|
|
||||||
}"
|
|
||||||
/>
|
/>
|
||||||
</section>
|
</template>
|
||||||
|
</filter-menu-section>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { mapGetters, mapMutations } from 'vuex'
|
import { mapGetters, mapMutations } from 'vuex'
|
||||||
|
import FilterMenuSection from '~/components/FilterMenu/FilterMenuSection'
|
||||||
import LabeledButton from '~/components/_new/generic/LabeledButton/LabeledButton'
|
import LabeledButton from '~/components/_new/generic/LabeledButton/LabeledButton'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
|
FilterMenuSection,
|
||||||
LabeledButton,
|
LabeledButton,
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
@ -35,21 +35,3 @@ export default {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<style lang="scss">
|
|
||||||
.following-filter {
|
|
||||||
display: flex;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
margin-top: $space-small;
|
|
||||||
|
|
||||||
> .labeled-button {
|
|
||||||
margin-top: $space-small;
|
|
||||||
width: 5%;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media only screen and (max-width: 960px) {
|
|
||||||
.labeled-button {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|||||||
@ -1,15 +1,15 @@
|
|||||||
<template>
|
<template>
|
||||||
<section class="languages-filter">
|
<filter-menu-section :title="$t('filter-menu.languages')" class="languages-filter">
|
||||||
<h4 class="title">{{ $t('filter-menu.languages') }}</h4>
|
<template #sidebar>
|
||||||
<labeled-button
|
<labeled-button
|
||||||
:filled="!filteredLanguageCodes.length"
|
:filled="!filteredLanguageCodes.length"
|
||||||
:label="$t('filter-menu.all')"
|
:label="$t('filter-menu.all')"
|
||||||
icon="check"
|
icon="check"
|
||||||
@click="resetLanguages"
|
@click="resetLanguages"
|
||||||
/>
|
/>
|
||||||
<div class="divider" />
|
</template>
|
||||||
<ul class="languages-list">
|
<template #filter-list>
|
||||||
<li v-for="language in locales" :key="language.code" class="menu-item">
|
<li v-for="language in locales" :key="language.code" class="item">
|
||||||
<base-button
|
<base-button
|
||||||
:filled="filteredLanguageCodes.includes(language.code)"
|
:filled="filteredLanguageCodes.includes(language.code)"
|
||||||
circle
|
circle
|
||||||
@ -18,17 +18,20 @@
|
|||||||
{{ language.code.toUpperCase() }}
|
{{ language.code.toUpperCase() }}
|
||||||
</base-button>
|
</base-button>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
|
||||||
</section>
|
|
||||||
</template>
|
</template>
|
||||||
|
</filter-menu-section>
|
||||||
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import locales from '~/locales'
|
|
||||||
import orderBy from 'lodash/orderBy'
|
|
||||||
import { mapGetters, mapMutations } from 'vuex'
|
import { mapGetters, mapMutations } from 'vuex'
|
||||||
|
import orderBy from 'lodash/orderBy'
|
||||||
|
import locales from '~/locales'
|
||||||
|
import FilterMenuSection from '~/components/FilterMenu/FilterMenuSection'
|
||||||
import LabeledButton from '~/components/_new/generic/LabeledButton/LabeledButton'
|
import LabeledButton from '~/components/_new/generic/LabeledButton/LabeledButton'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
|
FilterMenuSection,
|
||||||
LabeledButton,
|
LabeledButton,
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
@ -49,62 +52,3 @@ export default {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<style lang="scss">
|
|
||||||
.languages-filter {
|
|
||||||
display: flex;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
margin-top: $space-small;
|
|
||||||
|
|
||||||
> .title {
|
|
||||||
width: 100%;
|
|
||||||
margin: $space-small 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
> .labeled-button {
|
|
||||||
margin-top: $space-small;
|
|
||||||
}
|
|
||||||
|
|
||||||
> .divider {
|
|
||||||
border-left: $border-size-base solid $border-color-soft;
|
|
||||||
margin: $space-x-small $space-base;
|
|
||||||
}
|
|
||||||
|
|
||||||
> .languages-list {
|
|
||||||
display: flex;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
flex-basis: 80%;
|
|
||||||
flex-grow: 1;
|
|
||||||
|
|
||||||
> .menu-item {
|
|
||||||
width: 11%;
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
margin: $space-small 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@media only screen and (max-width: 630px) {
|
|
||||||
> .title {
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
> .languages-list {
|
|
||||||
justify-content: center;
|
|
||||||
|
|
||||||
> .menu-item {
|
|
||||||
margin: $space-small 12px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.labeled-button {
|
|
||||||
width: 100%;
|
|
||||||
margin: $space-x-small 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
> .divider {
|
|
||||||
width: 100%;
|
|
||||||
margin: $space-small;
|
|
||||||
border-top: $border-size-base solid $border-color-soft;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|||||||
@ -29,7 +29,6 @@ export default {
|
|||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
padding: 0 $space-x-small;
|
|
||||||
|
|
||||||
> .label {
|
> .label {
|
||||||
margin-top: $space-x-small;
|
margin-top: $space-x-small;
|
||||||
|
|||||||
@ -30,7 +30,7 @@
|
|||||||
style="flex-grow: 0; flex-basis: auto;"
|
style="flex-grow: 0; flex-basis: auto;"
|
||||||
>
|
>
|
||||||
<client-only>
|
<client-only>
|
||||||
<filter-menu v-show="showFilterMenuDropdown" placement="top-start" offset="8" />
|
<filter-menu v-show="showFilterMenuDropdown" />
|
||||||
</client-only>
|
</client-only>
|
||||||
</ds-flex-item>
|
</ds-flex-item>
|
||||||
<ds-flex-item
|
<ds-flex-item
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user