skillbox/client/src/components/ContentBlock.vue

203 lines
5.4 KiB
Vue

<template>
<div class="content-block__container">
<div class="content-block" :class="specialClass">
<div class="content-block__actions">
<a @click="toggleVisibility()" v-if="canManageContent" class="content-block__action-button">
<eye-icon class="content-block__action-icon"></eye-icon>
</a>
<visibility-popover
@hide-me="showVisibility = false"
:show="showVisibility"
:content-block="contentBlock"
class="content-block__visibility-menu"
></visibility-popover>
<a @click="editContentBlock()" v-if="contentBlock.mine" class="content-block__action-button">
<pen-icon class="content-block__action-icon"></pen-icon>
</a>
<a @click="deleteContentBlock(contentBlock.id)" v-if="contentBlock.mine" class="content-block__action-button">
<trash-icon class="content-block__action-icon"></trash-icon>
</a>
</div>
<h4 class="content-block__title">{{contentBlock.title}}</h4>
<component v-for="component in contentBlock.contents"
:key="component.id"
:is="component.type"
v-bind="component">
</component>
</div>
<add-content-block-button :after="contentBlock.id"></add-content-block-button>
</div>
</template>
<script>
import TextBlock from '@/components/content-blocks/TextBlock';
import BasicKnowledgeWidget from '@/components/content-blocks/BasicKnowledgeWidget';
import Task from '@/components/content-blocks/Task';
import ImageBlock from '@/components/content-blocks/ImageBlock';
import ImageUrlBlock from '@/components/content-blocks/ImageUrlBlock';
import VideoBlock from '@/components/content-blocks/VideoBlock';
import LinkBlock from '@/components/content-blocks/LinkBlock';
import DocumentBlock from '@/components/content-blocks/DocumentBlock';
import Assignment from '@/components/content-blocks/assignment/Assignment';
import AddContentBlockButton from '@/components/AddContentBlockButton';
import VisibilityPopover from '@/components/VisibilityPopover';
import EyeIcon from '@/components/icons/EyeIcon';
import PenIcon from '@/components/icons/PenIcon';
import TrashIcon from '@/components/icons/TrashIcon';
import ME_QUERY from '@/graphql/gql/meQuery.gql';
import CHAPTER_QUERY from '@/graphql/gql/chapterQuery.gql';
import DELETE_CONTENT_BLOCK_MUTATION from '@/graphql/gql/mutations/deleteContentBlock.gql';
export default {
props: ['contentBlock', 'parent'],
components: {
'text_block': TextBlock,
'basic_knowledge': BasicKnowledgeWidget,
'image_block': ImageBlock,
'image_url_block': ImageUrlBlock,
'video_block': VideoBlock,
'link_block': LinkBlock,
'document_block': DocumentBlock,
Assignment,
Task,
AddContentBlockButton,
VisibilityPopover,
EyeIcon,
PenIcon,
TrashIcon
},
computed: {
specialClass() {
return `content-block--${this.contentBlock.type.toLowerCase()}`
},
canManageContent() {
return this.me.permissions.includes('users.can_manage_school_class_content');
}
},
methods: {
toggleVisibility() {
this.showVisibility = !this.showVisibility;
},
editContentBlock() {
this.$store.dispatch('editContentBlock', this.contentBlock.id);
},
deleteContentBlock(id) {
const parent = this.parent;
this.$apollo.mutate({
mutation: DELETE_CONTENT_BLOCK_MUTATION,
variables: {
input: {
id: id
}
},
update(store, {data: {deleteContentBlock: {success}}}) {
try {
if (success) {
const query = CHAPTER_QUERY;
const variables = {
id: parent
};
const data = store.readQuery({query, variables});
data.chapter.contentBlocks.edges.splice(data.chapter.contentBlocks.edges.findIndex(edge => edge.node.id === id), 1);
store.writeQuery({query, variables, data});
}
} catch (e) {
// Query did not exist in the cache, and apollo throws a generic Error. Do nothing
}
}
});
}
},
apollo: {
me: {
query: ME_QUERY,
},
},
data() {
return {
showVisibility: false,
me: {
permissions: []
}
}
}
}
</script>
<style scoped lang="scss">
@import "@/styles/_variables.scss";
@import "@/styles/_mixins.scss";
.content-block {
margin-bottom: 2.5em;
position: relative;
&__title {
line-height: 1.5;
}
&__actions {
position: absolute;
left: -70px;
top: -4px;
display: grid;
}
&__action-button {
cursor: pointer;
}
&__action-icon {
width: 40px;
height: 40px;
fill: $color-grey;
}
&__visibility-menu {
top: 40px;
}
&--base_communication {
@include content-box($color-accent-1);
}
&--task {
@include content-box($color-brand);
}
&--base_society {
@include content-box($color-accent-2);
}
/deep/ p {
line-height: 1.5;
margin-bottom: 1em;
&:last-child {
margin-bottom: 0;
}
}
/deep/ ul {
padding-left: 25px;
}
/deep/ li {
list-style: disc;
line-height: 1.5;
}
}
</style>