Add code for filtering instruments in frontend

Also add some styling
This commit is contained in:
Ramon Wenger 2021-10-31 21:48:21 +01:00
parent 6407664f80
commit 8117a6b4c0
11 changed files with 236 additions and 61 deletions

View File

@ -0,0 +1,41 @@
<template>
<a class="filter-entry">
<span class="filter-entry__text">{{ text }}</span><chevron-right class="filter-entry__icon" />
</a>
</template>
<script>
import ChevronRight from '@/components/icons/ChevronRight';
export default {
props: {
text: {
type: String,
required: true
}
},
components: {
ChevronRight
}
};
</script>
<style scoped lang="scss">
@import '~styles/helpers';
.filter-entry {
display: flex;
justify-content: space-between;
align-items: center;
&__text {
@include sub-heading;
line-height: 1.5;
}
&__icon {
width: 10px;
height: 10px;
}
}
</style>

View File

@ -1,18 +1,38 @@
<template>
<div class="filter-group">
<a v-bind="$attrs">{{ title }}</a>
<filter-entry
:text="title"
v-bind="$attrs"
@click.native="$emit('click')"/>
<div class="filter-group__children">
<filter-entry
:key="type.id"
:data-cy="`filter-${type.type}`"
:text="type.name"
v-for="type in types"
@click.native="$emit('filter', i=>i.type.type===type.type)" />
</div>
</div>
</template>
<script>
import ChevronRight from '@/components/icons/ChevronRight';
import FilterEntry from '@/components/instruments/FilterEntry';
export default {
props: {
title: {
type: String,
default: ''
}
default: '',
},
types: {
type: Array,
default: () => [],
},
},
inheritAttrs: false
components: {FilterEntry, ChevronRight},
inheritAttrs: false,
};
</script>
@ -21,5 +41,11 @@
.filter-group {
border-bottom: 1px solid black;
display: flex;
flex-direction: column;
&__children {
padding-left: $medium-spacing;
}
}
</style>

View File

@ -0,0 +1,85 @@
<template>
<div
:class="typeClass"
class="instrument-entry">
<h4 class="instrument-entry__category">{{ categoryName }}</h4>
<h3 class="instrument-entry__title">{{ instrument.title }}</h3>
</div>
</template>
<script>
import {INTERDISCIPLINARY, LANGUAGE_COMMUNICATION, SOCIETY} from '@/consts/instrument.consts';
import instrumentType from '@/helpers/instrumentType';
export default {
props: {
instrument: {
type: Object,
required: true,
default: undefined,
},
},
computed: {
typeClass() {
return {
'instrument-entry__language-communication': this.instrument.type.category === LANGUAGE_COMMUNICATION,
'instrument-entry__society': this.instrument.type.category === SOCIETY,
'instrument-entry__interdisciplinary': this.instrument.type.category === INTERDISCIPLINARY,
};
},
categoryName() {
return instrumentType(this.instrument);
},
},
};
</script>
<style scoped lang="scss">
@import '~styles/helpers';
.instrument-entry {
padding: $medium-spacing;
margin-bottom: $medium-spacing;
border-radius: 8px;
&__title {
@include heading-3;
margin-bottom: 0;
}
&__category {
@include sub-heading;
margin-bottom: $small-spacing;
}
$root: &;
&__language-communication {
background-color: $color-accent-2-light;
#{$root}__category {
color: $color-accent-2-dark;
}
}
&__society {
background-color: $color-accent-1-light;
#{$root}__category {
color: $color-accent-1-dark;
}
}
&__interdisciplinary {
background-color: $color-accent-4-light;
#{$root}__category {
color: $color-accent-4-dark;
}
}
}
</style>

View File

@ -2,24 +2,37 @@
<div class="instrument-filter">
<filter-group
title="Alle Instrumente"
data-cy="filter-all-instruments"/>
data-cy="filter-all-instruments"
@click="setFilter(i=>i)"/>
<filter-group
:types="languageCommunicationTypes"
title="Sprache und Kommunikation"
data-cy="filter-language-communication"/>
data-cy="filter-language-communication"
@filter="setFilter($event)"
@click="setFilter(i=>i.type.category===LANGUAGE_COMMUNICATION)"
/>
<filter-group
:types="societyTypes"
title="Gesellschaft"
data-cy="filter-society"/>
data-cy="filter-society"
@filter="setFilter($event)"
@click="setFilter(i=>i.type.category===SOCIETY)"/>
<filter-group
:types="interdisciplinaryTypes"
title="Überfachliche Instrumente"
data-cy="filter-society"/>
data-cy="filter-interdisciplinary"
@filter="setFilter($event)"
@click="setFilter(i=>i.type.category===INTERDISCIPLINARY)"/>
</div>
</template>
<script>
import {INTERDISCIPLINARY, LANGUAGE_COMMUNICATION, SOCIETY} from '@/consts/instrument.consts';
import Checkbox from '@/components/ui/Checkbox';
import FilterGroup from '@/components/instruments/FilterGroup';
@ -33,52 +46,36 @@
},
data() {
return {
filter: [],
types: [
{
label: 'Sprache und Kommunikation',
enabled: true,
prop: 'LANGUAGE_COMMUNICATION',
cls: 'language',
},
{
label: 'Gesellschaft',
enabled: true,
prop: 'SOCIETY',
cls: 'society',
},
{
label: 'Überfachliches Instrument',
enabled: true,
prop: 'INTERDISCIPLINARY',
cls: 'interdisciplinary',
},
],
filter: '',
LANGUAGE_COMMUNICATION,
SOCIETY,
INTERDISCIPLINARY,
instrumentTypes: [],
};
},
computed: {
languageCommunicationTypes() {
return this.instrumentTypes.filter(t => t.category === 'LANGUAGE_COMMUNICATION');
},
societyTypes() {
return this.instrumentTypes.filter(t => t.category === 'SOCIETY');
},
interdisciplinaryTypes() {
return this.instrumentTypes.filter(t => t.category === 'INTERDISCIPLINARY');
},
},
methods: {
setFilter(filter) {
this.filter = filter;
this.$emit('filter', filter);
}
},
apollo: {
instrumentTypes: {
query: INSTRUMENT_TYPES_QUERY
}
},
methods: {
change(enabled, index) {
let type = this.types[index];
this.types = [
...this.types.slice(0, index),
{
...type,
enabled,
},
...this.types.slice(index + 1),
];
this.$emit('filter',
this.types
.filter(t => t.enabled)
.map(t => t.prop),
);
query: INSTRUMENT_TYPES_QUERY,
},
},
};

View File

@ -32,6 +32,7 @@
import ActivityEntry from '@/components/profile/ActivityEntry';
import SCROLL_TO_MUTATION from '@/graphql/gql/local/mutations/scrollTo.gql';
import instrumentType from '@/helpers/instrumentType';
export default {
props: ['instrument', 'filter'],
@ -52,11 +53,7 @@
return this.applyFilter('bookmarks') ? this.instrument.bookmarks : [];
},
type() {
if (this.instrument.type === 'LANGUAGE_COMMUNICATION') {
return 'Sprache & Kommunikation';
} else {
return 'Gesellschaft';
}
return instrumentType(this.instrument);
}
},
methods: {

View File

@ -0,0 +1,3 @@
export const LANGUAGE_COMMUNICATION = 'LANGUAGE_COMMUNICATION';
export const SOCIETY = 'SOCIETY';
export const INTERDISCIPLINARY = 'INTERDISCIPLINARY';

View File

@ -1,6 +1,7 @@
query InstrumentTypesQuery {
instrumentTypes {
name
type
category
}
}

View File

@ -4,7 +4,11 @@ query InstrumentsQuery {
title
contents
slug
type
category
type {
id
type
category
name
}
}
}

View File

@ -0,0 +1,13 @@
import {LANGUAGE_COMMUNICATION, SOCIETY} from '@/consts/instrument.consts';
const instrumentType = ({type: {category}}) => {
if (category === LANGUAGE_COMMUNICATION) {
return 'Sprache & Kommunikation';
} else if (category === SOCIETY) {
return 'Gesellschaft';
} else {
return 'Überfachliches Instrument';
}
};
export default instrumentType;

View File

@ -7,10 +7,10 @@
<router-link
:to="{name: 'instrument', params: {slug: instrument.slug}}"
:key="instrument.id"
class="instrument-overview__list-item"
data-cy="instrument"
tag="div"
v-for="instrument in filteredInstruments">
{{ instrument.title }}
<instrument-entry :instrument="instrument"/>
</router-link>
</div>
</div>
@ -18,11 +18,13 @@
<script>
import InstrumentFilter from '@/components/instruments/InstrumentFilter';
import InstrumentEntry from '@/components/instruments/InstrumentEntry';
import INSTRUMENTS_QUERY from '@/graphql/gql/queries/instrumentsQuery.gql';
export default {
components: {
InstrumentFilter
InstrumentFilter,
InstrumentEntry
},
apollo: {
@ -37,13 +39,13 @@
data() {
return {
instruments: [],
filter: []
filter: i => i
};
},
computed: {
filteredInstruments() {
return this.instruments.filter(instrument => this.filter.includes(instrument.type) || !this.filter.length);
return this.instruments.filter(i => this.filter(i));
}
},

View File

@ -28,6 +28,12 @@
font-size: toRem(18px);
}
@mixin sub-heading {
font-family: $sans-serif-font-family;
font-weight: 400;
font-size: toRem(16px);
}
@mixin modal-heading {
@include heading-2;
margin-bottom: 0;