mirror of
https://github.com/Ocelot-Social-Community/Ocelot-Social.git
synced 2025-12-13 07:46:06 +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>
|
||||
<section class="categories-filter">
|
||||
<h4 class="title">{{ $t('filter-menu.categories') }}</h4>
|
||||
<labeled-button
|
||||
:filled="!filteredCategoryIds.length"
|
||||
:label="$t('filter-menu.all')"
|
||||
icon="check"
|
||||
@click="resetCategories"
|
||||
/>
|
||||
<div class="divider" />
|
||||
<ul class="categories-list">
|
||||
<li v-for="category in categories" :key="category.id" class="menu-item">
|
||||
<filter-menu-section :title="$t('filter-menu.categories')" class="categories-filter">
|
||||
<template #sidebar>
|
||||
<labeled-button
|
||||
:filled="!filteredCategoryIds.length"
|
||||
:label="$t('filter-menu.all')"
|
||||
icon="check"
|
||||
@click="resetCategories"
|
||||
/>
|
||||
</template>
|
||||
<template #filter-list>
|
||||
<li v-for="category in categories" :key="category.id" class="item">
|
||||
<labeled-button
|
||||
:icon="category.icon"
|
||||
:filled="filteredCategoryIds.includes(category.id)"
|
||||
@ -17,17 +17,19 @@
|
||||
@click="toggleCategory(category.id)"
|
||||
/>
|
||||
</li>
|
||||
</ul>
|
||||
</section>
|
||||
</template>
|
||||
</filter-menu-section>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapGetters, mapMutations } from 'vuex'
|
||||
import CategoryQuery from '~/graphql/CategoryQuery.js'
|
||||
import FilterMenuSection from '~/components/FilterMenu/FilterMenuSection'
|
||||
import LabeledButton from '~/components/_new/generic/LabeledButton/LabeledButton'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
FilterMenuSection,
|
||||
LabeledButton,
|
||||
},
|
||||
data() {
|
||||
@ -60,66 +62,3 @@ export default {
|
||||
},
|
||||
}
|
||||
</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>
|
||||
<section class="emotions-filter">
|
||||
<h4 class="title">{{ $t('filter-menu.emotions') }}</h4>
|
||||
<labeled-button
|
||||
:filled="!filteredByEmotions.length"
|
||||
icon="check"
|
||||
:label="$t('filter-menu.all')"
|
||||
@click="resetEmotions"
|
||||
/>
|
||||
<div class="divider" />
|
||||
<emotion-button
|
||||
v-for="emotion in emotionsArray"
|
||||
:key="emotion"
|
||||
:emojiPath="iconPath(emotion)"
|
||||
:emotion="emotion"
|
||||
@toggleEmotion="toogleFilteredByEmotions(emotion)"
|
||||
/>
|
||||
</section>
|
||||
<filter-menu-section :title="$t('filter-menu.emotions')" class="emotions-filter">
|
||||
<template #sidebar>
|
||||
<labeled-button
|
||||
:filled="!filteredByEmotions.length"
|
||||
icon="check"
|
||||
:label="$t('filter-menu.all')"
|
||||
@click="resetEmotions"
|
||||
/>
|
||||
</template>
|
||||
<template #filter-list>
|
||||
<li v-for="emotion in emotionsArray" :key="emotion" class="item">
|
||||
<emotion-button
|
||||
:emojiPath="iconPath(emotion)"
|
||||
:emotion="emotion"
|
||||
@toggleEmotion="toogleFilteredByEmotions(emotion)"
|
||||
/>
|
||||
</li>
|
||||
</template>
|
||||
</filter-menu-section>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapGetters, mapMutations } from 'vuex'
|
||||
import LabeledButton from '~/components/_new/generic/LabeledButton/LabeledButton'
|
||||
import EmotionButton from '~/components/EmotionButton/EmotionButton'
|
||||
import FilterMenuSection from '~/components/FilterMenu/FilterMenuSection'
|
||||
import LabeledButton from '~/components/_new/generic/LabeledButton/LabeledButton'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
LabeledButton,
|
||||
EmotionButton,
|
||||
FilterMenuSection,
|
||||
LabeledButton,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
@ -52,44 +57,3 @@ export default {
|
||||
},
|
||||
}
|
||||
</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>
|
||||
<dropdown ref="menu" :placement="placement" :offset="offset" class="filter-menu">
|
||||
<dropdown ref="menu" placement="top-start" :offset="8" class="filter-menu">
|
||||
<base-button
|
||||
slot="default"
|
||||
icon="filter"
|
||||
@ -11,16 +11,17 @@
|
||||
<base-icon class="dropdown-arrow" name="angle-down" />
|
||||
</base-button>
|
||||
<template slot="popover">
|
||||
<ds-container class="filter-menu-options">
|
||||
<h4 class="title">{{ $t('filter-menu.filter-by') }}</h4>
|
||||
<div class="filter-menu-options">
|
||||
<h2 class="title">{{ $t('filter-menu.filter-by') }}</h2>
|
||||
<following-filter />
|
||||
<categories-filter />
|
||||
<emotions-filter />
|
||||
<languages-filter />
|
||||
</ds-container>
|
||||
</div>
|
||||
</template>
|
||||
</dropdown>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Dropdown from '~/components/Dropdown'
|
||||
import { mapGetters } from 'vuex'
|
||||
@ -48,12 +49,14 @@ export default {
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
@media only screen and (max-width: 960px) {
|
||||
.filter-menu-options {
|
||||
> .title {
|
||||
text-align: center;
|
||||
}
|
||||
.filter-menu-options {
|
||||
max-width: 1026px;
|
||||
padding: $space-small $space-x-small;
|
||||
|
||||
> .title {
|
||||
font-size: $font-size-large;
|
||||
}
|
||||
}
|
||||
</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>
|
||||
<section class="following-filter">
|
||||
<labeled-button
|
||||
:filled="filteredByUsersFollowed"
|
||||
icon="user-plus"
|
||||
:label="$t('filter-menu.following')"
|
||||
@click="toggleFilteredByFollowed(currentUser.id)"
|
||||
v-tooltip="{
|
||||
content: this.$t('contribution.filterFollow'),
|
||||
placement: 'left',
|
||||
delay: { show: 500 },
|
||||
}"
|
||||
/>
|
||||
</section>
|
||||
<filter-menu-section :divider="false" class="following-filter">
|
||||
<template #sidebar>
|
||||
<labeled-button
|
||||
icon="user-plus"
|
||||
:label="$t('filter-menu.following')"
|
||||
:filled="filteredByUsersFollowed"
|
||||
:title="$t('contribution.filterFollow')"
|
||||
@click="toggleFilteredByFollowed(currentUser.id)"
|
||||
/>
|
||||
</template>
|
||||
</filter-menu-section>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapGetters, mapMutations } from 'vuex'
|
||||
import FilterMenuSection from '~/components/FilterMenu/FilterMenuSection'
|
||||
import LabeledButton from '~/components/_new/generic/LabeledButton/LabeledButton'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
FilterMenuSection,
|
||||
LabeledButton,
|
||||
},
|
||||
computed: {
|
||||
@ -35,21 +35,3 @@ export default {
|
||||
},
|
||||
}
|
||||
</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>
|
||||
<section class="languages-filter">
|
||||
<h4 class="title">{{ $t('filter-menu.languages') }}</h4>
|
||||
<labeled-button
|
||||
:filled="!filteredLanguageCodes.length"
|
||||
:label="$t('filter-menu.all')"
|
||||
icon="check"
|
||||
@click="resetLanguages"
|
||||
/>
|
||||
<div class="divider" />
|
||||
<ul class="languages-list">
|
||||
<li v-for="language in locales" :key="language.code" class="menu-item">
|
||||
<filter-menu-section :title="$t('filter-menu.languages')" class="languages-filter">
|
||||
<template #sidebar>
|
||||
<labeled-button
|
||||
:filled="!filteredLanguageCodes.length"
|
||||
:label="$t('filter-menu.all')"
|
||||
icon="check"
|
||||
@click="resetLanguages"
|
||||
/>
|
||||
</template>
|
||||
<template #filter-list>
|
||||
<li v-for="language in locales" :key="language.code" class="item">
|
||||
<base-button
|
||||
:filled="filteredLanguageCodes.includes(language.code)"
|
||||
circle
|
||||
@ -18,17 +18,20 @@
|
||||
{{ language.code.toUpperCase() }}
|
||||
</base-button>
|
||||
</li>
|
||||
</ul>
|
||||
</section>
|
||||
</template>
|
||||
</filter-menu-section>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import locales from '~/locales'
|
||||
import orderBy from 'lodash/orderBy'
|
||||
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'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
FilterMenuSection,
|
||||
LabeledButton,
|
||||
},
|
||||
computed: {
|
||||
@ -49,62 +52,3 @@ export default {
|
||||
},
|
||||
}
|
||||
</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;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
padding: 0 $space-x-small;
|
||||
|
||||
> .label {
|
||||
margin-top: $space-x-small;
|
||||
|
||||
@ -30,7 +30,7 @@
|
||||
style="flex-grow: 0; flex-basis: auto;"
|
||||
>
|
||||
<client-only>
|
||||
<filter-menu v-show="showFilterMenuDropdown" placement="top-start" offset="8" />
|
||||
<filter-menu v-show="showFilterMenuDropdown" />
|
||||
</client-only>
|
||||
</ds-flex-item>
|
||||
<ds-flex-item
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user