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> <template>
<div class="filter-group"> <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> </div>
</template> </template>
<script> <script>
import ChevronRight from '@/components/icons/ChevronRight';
import FilterEntry from '@/components/instruments/FilterEntry';
export default { export default {
props: { props: {
title: { title: {
type: String, type: String,
default: '' default: '',
} },
types: {
type: Array,
default: () => [],
},
}, },
inheritAttrs: false components: {FilterEntry, ChevronRight},
inheritAttrs: false,
}; };
</script> </script>
@ -21,5 +41,11 @@
.filter-group { .filter-group {
border-bottom: 1px solid black; border-bottom: 1px solid black;
display: flex;
flex-direction: column;
&__children {
padding-left: $medium-spacing;
}
} }
</style> </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"> <div class="instrument-filter">
<filter-group <filter-group
title="Alle Instrumente" title="Alle Instrumente"
data-cy="filter-all-instruments"/> data-cy="filter-all-instruments"
@click="setFilter(i=>i)"/>
<filter-group <filter-group
:types="languageCommunicationTypes"
title="Sprache und Kommunikation" 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 <filter-group
:types="societyTypes"
title="Gesellschaft" title="Gesellschaft"
data-cy="filter-society"/> data-cy="filter-society"
@filter="setFilter($event)"
@click="setFilter(i=>i.type.category===SOCIETY)"/>
<filter-group <filter-group
:types="interdisciplinaryTypes"
title="Überfachliche Instrumente" title="Überfachliche Instrumente"
data-cy="filter-society"/> data-cy="filter-interdisciplinary"
@filter="setFilter($event)"
@click="setFilter(i=>i.type.category===INTERDISCIPLINARY)"/>
</div> </div>
</template> </template>
<script> <script>
import {INTERDISCIPLINARY, LANGUAGE_COMMUNICATION, SOCIETY} from '@/consts/instrument.consts';
import Checkbox from '@/components/ui/Checkbox'; import Checkbox from '@/components/ui/Checkbox';
import FilterGroup from '@/components/instruments/FilterGroup'; import FilterGroup from '@/components/instruments/FilterGroup';
@ -33,52 +46,36 @@
}, },
data() { data() {
return { return {
filter: [], filter: '',
types: [ LANGUAGE_COMMUNICATION,
{ SOCIETY,
label: 'Sprache und Kommunikation', INTERDISCIPLINARY,
enabled: true, instrumentTypes: [],
prop: 'LANGUAGE_COMMUNICATION',
cls: 'language',
},
{
label: 'Gesellschaft',
enabled: true,
prop: 'SOCIETY',
cls: 'society',
},
{
label: 'Überfachliches Instrument',
enabled: true,
prop: 'INTERDISCIPLINARY',
cls: 'interdisciplinary',
},
],
}; };
}, },
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: { apollo: {
instrumentTypes: { instrumentTypes: {
query: INSTRUMENT_TYPES_QUERY 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),
);
}, },
}, },
}; };

View File

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

View File

@ -4,7 +4,11 @@ query InstrumentsQuery {
title title
contents contents
slug slug
type type {
category 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 <router-link
:to="{name: 'instrument', params: {slug: instrument.slug}}" :to="{name: 'instrument', params: {slug: instrument.slug}}"
:key="instrument.id" :key="instrument.id"
class="instrument-overview__list-item" data-cy="instrument"
tag="div" tag="div"
v-for="instrument in filteredInstruments"> v-for="instrument in filteredInstruments">
{{ instrument.title }} <instrument-entry :instrument="instrument"/>
</router-link> </router-link>
</div> </div>
</div> </div>
@ -18,11 +18,13 @@
<script> <script>
import InstrumentFilter from '@/components/instruments/InstrumentFilter'; import InstrumentFilter from '@/components/instruments/InstrumentFilter';
import InstrumentEntry from '@/components/instruments/InstrumentEntry';
import INSTRUMENTS_QUERY from '@/graphql/gql/queries/instrumentsQuery.gql'; import INSTRUMENTS_QUERY from '@/graphql/gql/queries/instrumentsQuery.gql';
export default { export default {
components: { components: {
InstrumentFilter InstrumentFilter,
InstrumentEntry
}, },
apollo: { apollo: {
@ -37,13 +39,13 @@
data() { data() {
return { return {
instruments: [], instruments: [],
filter: [] filter: i => i
}; };
}, },
computed: { computed: {
filteredInstruments() { 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); font-size: toRem(18px);
} }
@mixin sub-heading {
font-family: $sans-serif-font-family;
font-weight: 400;
font-size: toRem(16px);
}
@mixin modal-heading { @mixin modal-heading {
@include heading-2; @include heading-2;
margin-bottom: 0; margin-bottom: 0;