Fix deep-selectors

This commit is contained in:
Ramon Wenger 2023-02-02 14:36:08 +01:00
parent 4477b7c5ed
commit 4b55f8952c
8 changed files with 896 additions and 951 deletions

View File

@ -3,36 +3,18 @@
:class="{ 'hideable-element--greyed-out': hidden }"
class="content-block__container hideable-element content-list__parent"
>
<div
:class="specialClass"
:style="instrumentStyle"
class="content-block"
data-cy="content-block"
>
<div
class="block-actions"
v-if="canEditModule && !isInstrumentBlock"
>
<user-widget
v-bind="me"
class="block-actions__user-widget content-block__user-widget"
v-if="isMine"
/>
<div :class="specialClass" :style="instrumentStyle" class="content-block" data-cy="content-block">
<div class="block-actions" v-if="canEditModule && !isInstrumentBlock">
<user-widget v-bind="me" class="block-actions__user-widget content-block__user-widget" v-if="isMine" />
<more-options-widget>
<li
class="popover-links__link"
v-if="!isInstrumentBlock"
>
<li class="popover-links__link" v-if="!isInstrumentBlock">
<popover-link
data-cy="duplicate-content-block-link"
text="Duplizieren"
@link-action="duplicateContentBlock(contentBlock)"
/>
</li>
<li
class="popover-links__link"
v-if="isMine"
>
<li class="popover-links__link" v-if="isMine">
<popover-link
data-cy="delete-content-block-link"
text="Löschen"
@ -40,22 +22,13 @@
/>
</li>
<li
class="popover-links__link"
v-if="isMine"
>
<popover-link
text="Bearbeiten"
@link-action="editContentBlock(contentBlock)"
/>
<li class="popover-links__link" v-if="isMine">
<popover-link text="Bearbeiten" @link-action="editContentBlock(contentBlock)" />
</li>
</more-options-widget>
</div>
<div class="content-block__visibility">
<visibility-action
:block="contentBlock"
v-if="canEditModule"
/>
<visibility-action :block="contentBlock" v-if="canEditModule" />
</div>
<h3
@ -66,10 +39,7 @@
>
{{ instrumentLabel }}
</h3>
<h4
class="content-block__title"
v-if="!contentBlock.indent"
>
<h4 class="content-block__title" v-if="!contentBlock.indent">
{{ contentBlock.title }}
</h4>
@ -85,10 +55,7 @@
/>
</div>
<add-content-button
:where="{after: contentBlock}"
v-if="canEditModule"
/>
<add-content-button :where="{ after: contentBlock }" v-if="canEditModule" />
</div>
</template>
@ -112,8 +79,9 @@
import { defineAsyncComponent } from 'vue';
import { instrumentCategory } from '@/helpers/instrumentType';
const ContentComponent = defineAsyncComponent(() => import(/* webpackChunkName: "content-components" */'@/components/content-blocks/ContentComponent'));
const ContentComponent = defineAsyncComponent(() =>
import(/* webpackChunkName: "content-components" */ '@/components/content-blocks/ContentComponent')
);
export default {
name: 'ContentBlock',
@ -157,14 +125,15 @@
instrumentStyle() {
if (this.isInstrumentBlock) {
return {
backgroundColor: this.contentBlock.instrumentCategory.background
backgroundColor: this.contentBlock.instrumentCategory.background,
};
}
return {};
},
instrumentLabel() {
const contentType = this.contentBlock.type.toLowerCase();
if (contentType.startsWith('base')) { // all legacy instruments start with `base`
if (contentType.startsWith('base')) {
// all legacy instruments start with `base`
return instrumentCategory(contentType);
}
if (this.isInstrumentBlock) {
@ -176,7 +145,7 @@
instrumentLabelStyle() {
if (this.isInstrumentBlock) {
return {
color: this.contentBlock.instrumentCategory.foreground
color: this.contentBlock.instrumentCategory.foreground,
};
}
return {};
@ -207,7 +176,8 @@
// collect content_list_items
if (content.type === 'content_list_item') {
contentList = [...contentList, content];
if (index === this.contentBlock.contents.length - 1) { // content is last element of contents array
if (index === this.contentBlock.contents.length - 1) {
// content is last element of contents array
let updatedContent = [...newContents, ...this.createContentListOrBlocks(contentList)];
return updatedContent;
}
@ -249,14 +219,21 @@
id,
},
},
update(store, {data: {duplicateContentBlock: {contentBlock}}}) {
update(
store,
{
data: {
duplicateContentBlock: { contentBlock },
},
}
) {
if (contentBlock) {
const query = CHAPTER_QUERY;
const variables = {
id: parent.id,
};
const { chapter } = store.readQuery({ query, variables });
const index = chapter.contentBlocks.findIndex(contentBlock => contentBlock.id === id);
const index = chapter.contentBlocks.findIndex((contentBlock) => contentBlock.id === id);
const contentBlocks = insertAtIndex(chapter.contentBlocks, index, contentBlock);
const data = {
chapter: {
@ -268,7 +245,6 @@
}
},
});
},
editContentBlock(contentBlock) {
const route = {
@ -280,7 +256,9 @@
this.$router.push(route);
},
deleteContentBlock(contentBlock) {
this.$modal.open('confirm').then(() => {
this.$modal
.open('confirm')
.then(() => {
this.doDeleteContentBlock(contentBlock);
})
.catch();
@ -295,14 +273,21 @@
id,
},
},
update(store, {data: {deleteContentBlock: {success}}}) {
update(
store,
{
data: {
deleteContentBlock: { success },
},
}
) {
if (success) {
const query = CHAPTER_QUERY;
const variables = {
id: parent.id,
};
const { chapter } = store.readQuery({ query, variables });
const index = chapter.contentBlocks.findIndex(contentBlock => contentBlock.id === id);
const index = chapter.contentBlocks.findIndex((contentBlock) => contentBlock.id === id);
const contentBlocks = removeAtIndex(chapter.contentBlocks, index);
const data = {
chapter: {
@ -316,18 +301,20 @@
});
},
createContentListOrBlocks(contentList) {
return [{
return [
{
type: 'content_list',
contents: contentList,
id: contentList[0].id,
}];
},
];
},
},
};
</script>
<style scoped lang="scss">
@import "~styles/helpers";
@import '~styles/helpers';
.content-block {
margin-bottom: $section-spacing;
@ -398,7 +385,7 @@
@include content-box-base;
}
/deep/ p {
:deep(p) {
line-height: 1.5;
margin-bottom: 1em;
@ -407,7 +394,7 @@
}
}
/deep/ .text-block {
:deep(.text-block) {
ul {
@include list-parent;
}
@ -417,6 +404,5 @@
line-height: 1.5;
}
}
}
</style>

View File

@ -1,34 +1,15 @@
<template>
<!-- eslint-disable vue/no-v-html -->
<div
class="solution"
data-cy="solution"
>
<a
class="solution__toggle"
data-cy="show-solution"
@click="toggle"
<div class="solution" data-cy="solution">
<a class="solution__toggle" data-cy="show-solution" @click="toggle"
>Lösung
<template v-if="!visible">anzeigen</template>
<template v-else>ausblenden</template>
</a>
<transition name="fade">
<div
class="solution__hidden fade"
v-if="visible"
>
<p
class="solution__text solution-text"
data-cy="solution-text"
v-html="sanitizedText"
/>
<cms-document-block
:solution="true"
class="solution__document"
:value="value.document"
v-if="value.document"
/>
<div class="solution__hidden fade" v-if="visible">
<p class="solution__text solution-text" data-cy="solution-text" v-html="sanitizedText" />
<cms-document-block :solution="true" class="solution__document" :value="value.document" v-if="value.document" />
</div>
</transition>
</div>
@ -63,7 +44,7 @@
</script>
<style scoped lang="scss">
@import "~styles/helpers";
@import '~styles/helpers';
.solution {
display: grid;
@ -86,12 +67,12 @@
font-size: toRem(18px);
color: $color-silver-dark;
/deep/ p {
:deep(p) {
font-size: toRem(18px);
color: $color-silver-dark;
}
/deep/ ul {
:deep(ul) {
padding-left: $medium-spacing;
> li {
@ -104,7 +85,7 @@
.fade-enter-active,
.fade-leave-active {
transition: opacity .3s;
transition: opacity 0.3s;
}
.fade-enter-from,

View File

@ -1,19 +1,9 @@
<template>
<!-- eslint-disable vue/no-v-html -->
<div
:data-scrollto="value.id"
class="assignment"
>
<p
class="assignment__main-text"
data-cy="assignment-main-text"
v-html="assignment.assignment"
/>
<div :data-scrollto="value.id" class="assignment">
<p class="assignment__main-text" data-cy="assignment-main-text" v-html="assignment.assignment" />
<solution
:value="solution"
v-if="assignment.solution"
/>
<solution :value="solution" v-if="assignment.solution" />
<template v-if="isStudent">
<submission-form
@ -33,24 +23,13 @@
@spellcheck="spellcheck"
/>
<spell-check
:corrections="corrections"
:text="submission.text"
/>
<spell-check :corrections="corrections" :text="submission.text" />
<p
class="assignment__feedback"
v-if="assignment.submission.submissionFeedback"
v-html="feedbackText"
/>
<p class="assignment__feedback" v-if="assignment.submission.submissionFeedback" v-html="feedbackText" />
</template>
<template v-if="!isStudent">
<router-link
:to="{name: 'submissions', params: { id: assignment.id }}"
class="button button--primary"
>
Zu den
Ergebnissen
<router-link :to="{ name: 'submissions', params: { id: assignment.id } }" class="button button--primary">
Zu den Ergebnissen
</router-link>
</template>
</div>
@ -68,9 +47,15 @@
import { sanitize } from '@/helpers/text';
import { defineAsyncComponent } from 'vue';
const SubmissionForm = defineAsyncComponent(() => import(/* webpackChunkName: "content-components" */'@/components/content-blocks/assignment/SubmissionForm'));
const Solution = defineAsyncComponent(() => import(/* webpackChunkName: "content-components" */'@/components/content-blocks/Solution'));
const SpellCheck = defineAsyncComponent(() => import(/* webpackChunkName: "content-components" */'@/components/content-blocks/assignment/SpellCheck'));
const SubmissionForm = defineAsyncComponent(() =>
import(/* webpackChunkName: "content-components" */ '@/components/content-blocks/assignment/SubmissionForm')
);
const Solution = defineAsyncComponent(() =>
import(/* webpackChunkName: "content-components" */ '@/components/content-blocks/Solution')
);
const SpellCheck = defineAsyncComponent(() =>
import(/* webpackChunkName: "content-components" */ '@/components/content-blocks/assignment/SpellCheck')
);
export default {
props: ['value'],
@ -127,7 +112,8 @@
...mapActions(['scrollToAssignmentReady']),
_save: debounce(function (submission) {
this.saving++;
this.$apollo.mutate({
this.$apollo
.mutate({
mutation: UPDATE_ASSIGNMENT_MUTATION_WITH_SUCCESS,
variables: {
input: {
@ -138,7 +124,14 @@
},
},
},
update(store, {data: {updateAssignment: {successful, updatedAssignment}}}) {
update(
store,
{
data: {
updateAssignment: { successful, updatedAssignment },
},
}
) {
try {
if (successful) {
const query = ASSIGNMENT_QUERY;
@ -149,7 +142,7 @@
submission,
});
const data = {
assignment
assignment,
};
store.writeQuery({ query, variables, data });
}
@ -158,7 +151,8 @@
// Query did not exist in the cache, and apollo throws a generic Error. Do nothing
}
},
}).then(() => {
})
.then(() => {
this.saving--;
if (this.saving === 0) {
this.unsaved = false;
@ -222,7 +216,8 @@
spellcheck() {
let self = this;
this.spellcheckLoading = true;
this.$apollo.mutate({
this.$apollo
.mutate({
mutation: SPELL_CHECK_MUTATION,
variables: {
input: {
@ -230,10 +225,18 @@
text: this.assignment.submission.text,
},
},
update(store, {data: {spellCheck: {results}}}) {
update(
store,
{
data: {
spellCheck: { results },
},
}
) {
self.corrections = results;
},
}).then(() => {
})
.then(() => {
this.spellcheckLoading = false;
});
},
@ -278,11 +281,11 @@
}
&__main-text {
/deep/ ul{
@include list-parent
:deep(ul) {
@include list-parent;
}
/deep/ li {
:deep(li) {
@include list-child;
}
}
@ -313,7 +316,5 @@
&__feedback {
@include regular-text;
}
}
</style>

View File

@ -1,28 +1,20 @@
<template>
<div class="tip-tap">
<editor-content
class="tip-tap__editor-wrapper"
:editor="editor"
/>
<editor-content class="tip-tap__editor-wrapper" :editor="editor" />
<toggle
:bordered="false"
:checked="isList"
label="Als Liste formatieren"
@input="toggleList"
/>
<toggle :bordered="false" :checked="isList" label="Als Liste formatieren" @input="toggleList" />
</div>
</template>
<script lang="ts">
import { PropType, defineComponent } from 'vue';
import {Editor, EditorContent} from "@tiptap/vue-3";
import { Editor, EditorContent } from '@tiptap/vue-3';
import Document from '@tiptap/extension-document';
import Paragraph from '@tiptap/extension-paragraph';
import Text from '@tiptap/extension-text';
import BulletList from '@tiptap/extension-bullet-list';
import ListItem from '@tiptap/extension-list-item';
import Toggle from "@/components/ui/Toggle.vue";
import Toggle from '@/components/ui/Toggle.vue';
interface Data {
editor: Editor | undefined;
@ -43,7 +35,7 @@
components: {
Toggle,
EditorContent
EditorContent,
},
data(): Data {
@ -58,7 +50,7 @@
},
text(): string {
return this.value?.text || '';
}
},
},
watch: {
@ -71,29 +63,23 @@
}
editor.commands.setContent(text, false);
}
},
},
mounted() {
this.editor = new Editor({
editorProps: {
attributes: {
class: 'tip-tap__editor'
}
class: 'tip-tap__editor',
},
},
content: this.text,
extensions: [
Document,
Paragraph,
Text,
BulletList,
ListItem
],
extensions: [Document, Paragraph, Text, BulletList, ListItem],
onUpdate: () => {
const text = (this.editor as Editor).getHTML();
this.$emit('input', text);
this.$emit('change-text', text);
}
},
});
},
@ -106,42 +92,39 @@
const editor = this.editor as Editor;
editor.chain().selectAll().toggleBulletList().run();
},
}
},
});
</script>
<style scoped lang="scss">
@import '~styles/helpers';
.tip-tap {
&__editor-wrapper {
margin-bottom: $medium-spacing;
}
/deep/ &__editor {
:deep(.tip-tap__editor) {
@include inputstyle;
flex-direction: column;
min-height: 150px;
}
/deep/ ul {
:deep(ul) {
padding-left: $medium-spacing;
list-style: initial;
}
/deep/ li {
:deep(li) {
@include inputfont;
}
/deep/ div {
:deep(div) {
@include inputfont;
}
/deep/ p {
:deep(p) {
@include inputfont;
}
}
</style>

View File

@ -7,10 +7,7 @@
<slot />
</div>
<div
class="activity-entry__link"
@click="$emit('link')"
>
<div class="activity-entry__link" @click="$emit('link')">
<chevron-right class="activity-entry__icon" />
</div>
</div>
@ -18,20 +15,22 @@
<script>
import { defineAsyncComponent } from 'vue';
const ChevronRight = defineAsyncComponent(() => import(/* webpackChunkName: "icons" */'@/components/icons/ChevronRight'));
const ChevronRight = defineAsyncComponent(() =>
import(/* webpackChunkName: "icons" */ '@/components/icons/ChevronRight')
);
export default {
props: ['title'],
components: {
ChevronRight
}
ChevronRight,
},
};
</script>
<style scoped lang="scss">
@import "@/styles/_variables.scss";
@import "@/styles/_mixins.scss";
@import '@/styles/_variables.scss';
@import '@/styles/_mixins.scss';
.activity-entry {
padding: $small-spacing 0;
@ -63,7 +62,7 @@
width: 30px;
}
/deep/ p {
:deep(p) {
@include regular-text;
}
}

View File

@ -1,43 +1,46 @@
<template>
<div class="simple-file-upload">
<component
:is="button"
@click="clickUploadCare"
/>
<component :is="button" @click="clickUploadCare" />
<simple-file-upload-hidden-input @link-change-url="$emit('link-change-url', $event)" />
</div>
</template>
<script>
import { defineAsyncComponent } from 'vue';
const SimpleFileUploadHiddenInput = defineAsyncComponent(() => import('@/components/ui/file-upload/SimpleFileUploadHiddenInput'));
const SimpleFileUploadHiddenInput = defineAsyncComponent(() =>
import('@/components/ui/file-upload/SimpleFileUploadHiddenInput')
);
const SimpleFileUploadIcon = defineAsyncComponent(() => import('@/components/ui/file-upload/SimpleFileUploadIcon'));
const SimpleFileUploadIconAndText = defineAsyncComponent(() => import('@/components/ui/file-upload/SimpleFileUploadIconAndText'));
const DocumentIcon = defineAsyncComponent(() => import(/* webpackChunkName: "icons" */'@/components/icons/DocumentIcon'));
const SimpleFileUploadIconAndText = defineAsyncComponent(() =>
import('@/components/ui/file-upload/SimpleFileUploadIconAndText')
);
const DocumentIcon = defineAsyncComponent(() =>
import(/* webpackChunkName: "icons" */ '@/components/icons/DocumentIcon')
);
export default {
props: {
value: {
type: String,
default: ''
default: '',
},
withText: {
type: Boolean,
default: false
}
default: false,
},
},
components: {
SimpleFileUploadHiddenInput,
DocumentIcon,
SimpleFileUploadIcon,
SimpleFileUploadIconAndText
SimpleFileUploadIconAndText,
},
computed: {
button() {
return this.withText ? 'simple-file-upload-icon-and-text' : 'simple-file-upload-icon';
}
},
},
methods: {
@ -45,13 +48,13 @@
// workaround for styling the uploadcare widget
let button = this.$el.querySelector('.uploadcare--widget__button');
button.click();
}
},
},
};
</script>
<style scoped lang="scss">
@import "~styles/_helpers";
@import '~styles/_helpers';
.simple-file-upload {
height: 25px;
@ -66,7 +69,7 @@
}
}
/deep/ .uploadcare--widget {
:deep(.uploadcare--widget) {
display: none;
}
</style>

View File

@ -1,11 +1,6 @@
<template>
<div class="simple-file-upload">
<button-with-icon-and-text
icon="document-icon"
text="Dokument hochladen"
v-if="!value"
@click="clickUploadCare"
/>
<button-with-icon-and-text icon="document-icon" text="Dokument hochladen" v-if="!value" @click="clickUploadCare" />
<simple-file-upload-hidden-input @link-change-url="$emit('link-change-url', $event)" />
</div>
@ -13,7 +8,9 @@
<script>
import { defineAsyncComponent } from 'vue';
const SimpleFileUploadHiddenInput = defineAsyncComponent(() => import('@/components/ui/file-upload/SimpleFileUploadHiddenInput'));
const SimpleFileUploadHiddenInput = defineAsyncComponent(() =>
import('@/components/ui/file-upload/SimpleFileUploadHiddenInput')
);
const ButtonWithIconAndText = defineAsyncComponent(() => import('@/components/ui/ButtonWithIconAndText'));
export default {
@ -35,7 +32,7 @@
</script>
<style scoped lang="scss">
@import "~styles/_helpers";
@import '~styles/_helpers';
.simple-file-upload {
width: 25px;
@ -55,7 +52,7 @@
}
}
/deep/ .uploadcare--widget {
:deep(.uploadcare--widget) {
display: none;
}
</style>

View File

@ -1,18 +1,11 @@
<template>
<div class="instrument">
<h1
class="instrument__title"
data-cy="instrument-title"
>
<h1 class="instrument__title" data-cy="instrument-title">
{{ instrument.title }}
</h1>
<!-- eslint-disable vue/no-v-html -->
<div
class="instrument__intro intro"
data-cy="instrument-intro"
v-html="instrument.intro"
/>
<div class="instrument__intro intro" data-cy="instrument-intro" v-html="instrument.intro" />
<content-component
:component="component"
@ -30,7 +23,9 @@
import INSTRUMENT_QUERY from '@/graphql/gql/queries/instrumentQuery.gql';
import { defineAsyncComponent } from 'vue';
const ContentComponent = defineAsyncComponent(() => import(/* webpackChunkName: "content-components" */'@/components/content-blocks/ContentComponent'));
const ContentComponent = defineAsyncComponent(() =>
import(/* webpackChunkName: "content-components" */ '@/components/content-blocks/ContentComponent')
);
export default {
apollo: {
@ -38,26 +33,26 @@
return {
query: INSTRUMENT_QUERY,
variables: {
slug: this.$route.params.slug
}
slug: this.$route.params.slug,
},
};
}
},
},
components: {
ContentComponent
ContentComponent,
},
data() {
return {
instrument: {}
instrument: {},
};
}
},
};
</script>
<style scoped lang="scss">
@import "~styles/helpers";
@import '~styles/helpers';
.instrument {
&__title {
@ -66,7 +61,7 @@
line-height: $default-heading-line-height;
}
& /deep/ {
& :deep() {
& p {
margin-bottom: $large-spacing;
}