Apply code changes from migration guide for Vue 3
This commit is contained in:
parent
445f09e16a
commit
09d8d36678
|
|
@ -42,7 +42,7 @@ module.exports = {
|
||||||
'@': resolve('src'),
|
'@': resolve('src'),
|
||||||
styles: resolve('src/styles'),
|
styles: resolve('src/styles'),
|
||||||
gql: resolve('src/graphql/gql'),
|
gql: resolve('src/graphql/gql'),
|
||||||
// vue: '@vue/compat',
|
vue: '@vue/compat',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
module: {
|
module: {
|
||||||
|
|
|
||||||
|
|
@ -9,38 +9,54 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
import { defineAsyncComponent } from 'vue';
|
||||||
import { mapGetters } from 'vuex';
|
import { mapGetters } from 'vuex';
|
||||||
import ScrollUp from '@/components/ScrollUp';
|
import ScrollUp from '@/components/ScrollUp';
|
||||||
import ReadOnlyBanner from '@/components/ReadOnlyBanner';
|
import ReadOnlyBanner from '@/components/ReadOnlyBanner';
|
||||||
|
|
||||||
import modals from '@/components/modals';
|
import modals from '@/components/modals';
|
||||||
|
|
||||||
const NewContentBlockWizard = () =>
|
const NewContentBlockWizard = defineAsyncComponent(() =>
|
||||||
import(/* webpackChunkName: "content-forms" */ '@/components/content-block-form/NewContentBlockWizard');
|
import(/* webpackChunkName: "content-forms" */ '@/components/content-block-form/NewContentBlockWizard')
|
||||||
const EditContentBlockWizard = () =>
|
);
|
||||||
import(/* webpackChunkName: "content-forms" */ '@/components/content-block-form/EditContentBlockWizard');
|
const EditContentBlockWizard = defineAsyncComponent(() =>
|
||||||
const EditRoomEntryWizard = () =>
|
import(/* webpackChunkName: "content-forms" */ '@/components/content-block-form/EditContentBlockWizard')
|
||||||
import(/* webpackChunkName: "content-forms" */ '@/components/rooms/room-entries/EditRoomEntryWizard');
|
);
|
||||||
const NewProjectEntryWizard = () =>
|
const EditRoomEntryWizard = defineAsyncComponent(() =>
|
||||||
import(/* webpackChunkName: "content-forms" */ '@/components/portfolio/NewProjectEntryWizard');
|
import(/* webpackChunkName: "content-forms" */ '@/components/rooms/room-entries/EditRoomEntryWizard')
|
||||||
const EditProjectEntryWizard = () =>
|
);
|
||||||
import(/* webpackChunkName: "content-forms" */ '@/components/portfolio/EditProjectEntryWizard');
|
const NewProjectEntryWizard = defineAsyncComponent(() =>
|
||||||
const NewObjectiveWizard = () =>
|
import(/* webpackChunkName: "content-forms" */ '@/components/portfolio/NewProjectEntryWizard')
|
||||||
import(/* webpackChunkName: "content-forms" */ '@/components/objective-groups/NewObjectiveWizard');
|
);
|
||||||
const NewNoteWizard = () => import(/* webpackChunkName: "content-forms" */ '@/components/notes/NewNoteWizard');
|
const EditProjectEntryWizard = defineAsyncComponent(() =>
|
||||||
const EditNoteWizard = () => import(/* webpackChunkName: "content-forms" */ '@/components/notes/EditNoteWizard');
|
import(/* webpackChunkName: "content-forms" */ '@/components/portfolio/EditProjectEntryWizard')
|
||||||
const EditClassNameWizard = () =>
|
);
|
||||||
import(/* webpackChunkName: "content-forms" */ '@/components/school-class/EditClassNameWizard');
|
const NewObjectiveWizard = defineAsyncComponent(() =>
|
||||||
const EditTeamNameWizard = () =>
|
import(/* webpackChunkName: "content-forms" */ '@/components/objective-groups/NewObjectiveWizard')
|
||||||
import(/* webpackChunkName: "content-forms" */ '@/components/profile/EditTeamNameWizard');
|
);
|
||||||
const EditSnapshotTitleWizard = () =>
|
const NewNoteWizard = defineAsyncComponent(() =>
|
||||||
import(/* webpackChunkName: "content-forms" */ '@/components/snapshots/EditSnapshotTitleWizard');
|
import(/* webpackChunkName: "content-forms" */ '@/components/notes/NewNoteWizard')
|
||||||
const DefaultLayout = () => import(/* webpackChunkName: "layouts" */ '@/layouts/DefaultLayout');
|
);
|
||||||
const SimpleLayout = () => import(/* webpackChunkName: "layouts" */ '@/layouts/SimpleLayout');
|
const EditNoteWizard = defineAsyncComponent(() =>
|
||||||
const FullScreenLayout = () => import(/* webpackChunkName: "layouts" */ '@/layouts/FullScreenLayout');
|
import(/* webpackChunkName: "content-forms" */ '@/components/notes/EditNoteWizard')
|
||||||
const PublicLayout = () => import(/* webpackChunkName: "layouts" */ '@/layouts/PublicLayout');
|
);
|
||||||
const BlankLayout = () => import(/* webpackChunkName: "layouts" */ '@/layouts/BlankLayout');
|
const EditClassNameWizard = defineAsyncComponent(() =>
|
||||||
const SplitLayout = () => import(/* webpackChunkName: "layouts" */ '@/layouts/SplitLayout');
|
import(/* webpackChunkName: "content-forms" */ '@/components/school-class/EditClassNameWizard')
|
||||||
|
);
|
||||||
|
const EditTeamNameWizard = defineAsyncComponent(() =>
|
||||||
|
import(/* webpackChunkName: "content-forms" */ '@/components/profile/EditTeamNameWizard')
|
||||||
|
);
|
||||||
|
const EditSnapshotTitleWizard = defineAsyncComponent(() =>
|
||||||
|
import(/* webpackChunkName: "content-forms" */ '@/components/snapshots/EditSnapshotTitleWizard')
|
||||||
|
);
|
||||||
|
const DefaultLayout = defineAsyncComponent(() => import(/* webpackChunkName: "layouts" */ '@/layouts/DefaultLayout'));
|
||||||
|
const SimpleLayout = defineAsyncComponent(() => import(/* webpackChunkName: "layouts" */ '@/layouts/SimpleLayout'));
|
||||||
|
const FullScreenLayout = defineAsyncComponent(() =>
|
||||||
|
import(/* webpackChunkName: "layouts" */ '@/layouts/FullScreenLayout')
|
||||||
|
);
|
||||||
|
const PublicLayout = defineAsyncComponent(() => import(/* webpackChunkName: "layouts" */ '@/layouts/PublicLayout'));
|
||||||
|
const BlankLayout = defineAsyncComponent(() => import(/* webpackChunkName: "layouts" */ '@/layouts/BlankLayout'));
|
||||||
|
const SplitLayout = defineAsyncComponent(() => import(/* webpackChunkName: "layouts" */ '@/layouts/SplitLayout'));
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'App',
|
name: 'App',
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,22 @@
|
||||||
<template>
|
|
||||||
<header class="header-bar">
|
|
||||||
<a class="header-bar__sidebar-link" data-cy="open-sidebar-link" @click.stop="openSidebar('navigation')">
|
<a class="header-bar__sidebar-link" data-cy="open-sidebar-link" @click.stop="openSidebar('navigation')">
|
||||||
<hamburger class="header-bar__sidebar-icon" />
|
<hamburger class="header-bar__sidebar-icon" />
|
||||||
</a>
|
</a>
|
||||||
<content-navigation class="header-bar__content-navigation" />
|
<content-navigation class="header-bar__content-navigation" />
|
||||||
<div class="user-header">
|
<div class="user-header">
|
||||||
<a class="user-header__sidebar-link">
|
<a
|
||||||
<current-class class="user-header__current-class" @click.native.stop="openSidebar('profile')" />
|
class="user-header__sidebar-link"
|
||||||
|
>
|
||||||
|
<current-class
|
||||||
|
class="user-header__current-class"
|
||||||
|
@click.stop="openSidebar('profile')"
|
||||||
|
/>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<user-widget v-bind="me" data-cy="header-user-widget" @click.native.stop="openSidebar('profile')" />
|
<user-widget
|
||||||
|
v-bind="me"
|
||||||
|
data-cy="header-user-widget"
|
||||||
|
@click.stop="openSidebar('profile')"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@
|
||||||
<logo />
|
<logo />
|
||||||
</router-link>
|
</router-link>
|
||||||
|
|
||||||
<user-widget v-bind="me" @click.native.stop="openSidebar('profile')" />
|
<user-widget v-bind="me" @click.stop="openSidebar('profile')" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@ export default {
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
destroyed() {
|
unmounted() {
|
||||||
document.body.onscroll = null;
|
document.body.onscroll = null;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,14 +4,14 @@
|
||||||
{{ name }}
|
{{ name }}
|
||||||
</div>
|
</div>
|
||||||
<div class="student-submission__entry entry">
|
<div class="student-submission__entry entry">
|
||||||
<p>{{ submission.text | trimToLength(50) }}</p>
|
<p>{{ text }}</p>
|
||||||
<p class="entry__document" v-if="submission.document && submission.document.length > 0">
|
<p class="entry__document" v-if="submission.document && submission.document.length > 0">
|
||||||
<student-submission-document :document="submission.document" class="entry-document" />
|
<student-submission-document :document="submission.document" class="entry-document" />
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="student-submission__feedback entry" v-if="submission.submissionFeedback">
|
<div class="student-submission__feedback entry" v-if="submission.submissionFeedback">
|
||||||
<p :class="{ 'entry__text--final': submission.submissionFeedback.final }" class="entry__text">
|
<p :class="{ 'entry__text--final': submission.submissionFeedback.final }" class="entry__text">
|
||||||
{{ submission.submissionFeedback.text | trimToLength(50) }}
|
{{ feedback }}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -25,7 +25,21 @@ export default {
|
||||||
components: {
|
components: {
|
||||||
StudentSubmissionDocument,
|
StudentSubmissionDocument,
|
||||||
},
|
},
|
||||||
filters: {
|
|
||||||
|
computed: {
|
||||||
|
text() {
|
||||||
|
return this.trimToLength(this.submission.text, 50);
|
||||||
|
},
|
||||||
|
feedback() {
|
||||||
|
return this.trimToLength(this.submission.submissionFeedback.text, 50);
|
||||||
|
},
|
||||||
|
name() {
|
||||||
|
return this.submission && this.submission.student
|
||||||
|
? `${this.submission.student.firstName} ${this.submission.student.lastName}`
|
||||||
|
: '';
|
||||||
|
},
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
trimToLength: function (text, numberOfChars) {
|
trimToLength: function (text, numberOfChars) {
|
||||||
if (!text) {
|
if (!text) {
|
||||||
return '';
|
return '';
|
||||||
|
|
@ -40,14 +54,6 @@ export default {
|
||||||
return `${text.substring(0, index)}…`;
|
return `${text.substring(0, index)}…`;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
computed: {
|
|
||||||
name() {
|
|
||||||
return this.submission && this.submission.student
|
|
||||||
? `${this.submission.student.firstName} ${this.submission.student.lastName}`
|
|
||||||
: '';
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@
|
||||||
:to="topicRoute"
|
:to="topicRoute"
|
||||||
active-class="content-navigation__link--active"
|
active-class="content-navigation__link--active"
|
||||||
class="content-navigation__link"
|
class="content-navigation__link"
|
||||||
@click.native="close"
|
@click="close"
|
||||||
>
|
>
|
||||||
{{ $flavor.textTopics }}
|
{{ $flavor.textTopics }}
|
||||||
</router-link>
|
</router-link>
|
||||||
|
|
@ -20,7 +20,7 @@
|
||||||
to="/instruments"
|
to="/instruments"
|
||||||
active-class="content-navigation__link--active"
|
active-class="content-navigation__link--active"
|
||||||
class="content-navigation__link"
|
class="content-navigation__link"
|
||||||
@click.native="close"
|
@click="close"
|
||||||
>
|
>
|
||||||
{{ $flavor.textInstruments }}
|
{{ $flavor.textInstruments }}
|
||||||
</router-link>
|
</router-link>
|
||||||
|
|
@ -33,7 +33,7 @@
|
||||||
class="content-navigation__link"
|
class="content-navigation__link"
|
||||||
data-cy="news-navigation-link"
|
data-cy="news-navigation-link"
|
||||||
v-if="!me.readOnly"
|
v-if="!me.readOnly"
|
||||||
@click.native="close"
|
@click="close"
|
||||||
>
|
>
|
||||||
News
|
News
|
||||||
</router-link>
|
</router-link>
|
||||||
|
|
@ -51,7 +51,7 @@
|
||||||
to="/rooms"
|
to="/rooms"
|
||||||
active-class="content-navigation__link--active"
|
active-class="content-navigation__link--active"
|
||||||
class="content-navigation__link content-navigation__link--secondary"
|
class="content-navigation__link content-navigation__link--secondary"
|
||||||
@click.native="close"
|
@click="close"
|
||||||
>
|
>
|
||||||
Räume
|
Räume
|
||||||
</router-link>
|
</router-link>
|
||||||
|
|
@ -62,7 +62,7 @@
|
||||||
to="/portfolio"
|
to="/portfolio"
|
||||||
active-class="content-navigation__link--active"
|
active-class="content-navigation__link--active"
|
||||||
class="content-navigation__link content-navigation__link--secondary"
|
class="content-navigation__link content-navigation__link--secondary"
|
||||||
@click.native="close"
|
@click="close"
|
||||||
>
|
>
|
||||||
Portfolio
|
Portfolio
|
||||||
</router-link>
|
</router-link>
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@
|
||||||
class="topic-navigation__topic book-subnavigation__item"
|
class="topic-navigation__topic book-subnavigation__item"
|
||||||
v-for="topic in topics"
|
v-for="topic in topics"
|
||||||
:key="topic.id"
|
:key="topic.id"
|
||||||
@click.native="closeSidebar('navigation')"
|
@click="closeSidebar('navigation')"
|
||||||
>
|
>
|
||||||
{{ topic.order }}.
|
{{ topic.order }}.
|
||||||
{{ topic.title }}
|
{{ topic.title }}
|
||||||
|
|
|
||||||
|
|
@ -105,7 +105,7 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import Vue, { PropType } from 'vue';
|
import { PropType, defineComponent } from 'vue';
|
||||||
import Toggle from '@/components/ui/Toggle.vue';
|
import Toggle from '@/components/ui/Toggle.vue';
|
||||||
import ContentFormSection from '@/components/content-block-form/ContentFormSection.vue';
|
import ContentFormSection from '@/components/content-block-form/ContentFormSection.vue';
|
||||||
import InputWithLabel from '@/components/ui/InputWithLabel.vue';
|
import InputWithLabel from '@/components/ui/InputWithLabel.vue';
|
||||||
|
|
@ -130,7 +130,7 @@ interface ContentBlockFormData {
|
||||||
localContentBlock: any;
|
localContentBlock: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Vue.extend({
|
export default defineComponent({
|
||||||
props: {
|
props: {
|
||||||
title: {
|
title: {
|
||||||
type: String,
|
type: String,
|
||||||
|
|
|
||||||
|
|
@ -55,7 +55,7 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import Vue from 'vue';
|
import { defineComponent } from 'vue';
|
||||||
import WidgetPopover from '@/components/ui/WidgetPopover.vue';
|
import WidgetPopover from '@/components/ui/WidgetPopover.vue';
|
||||||
import Ellipses from '@/components/icons/Ellipses.vue';
|
import Ellipses from '@/components/icons/Ellipses.vue';
|
||||||
import ButtonWithIconAndText from '@/components/ui/ButtonWithIconAndText.vue';
|
import ButtonWithIconAndText from '@/components/ui/ButtonWithIconAndText.vue';
|
||||||
|
|
@ -65,7 +65,7 @@ interface Data {
|
||||||
show: boolean;
|
show: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Vue.extend({
|
export default defineComponent({
|
||||||
props: {
|
props: {
|
||||||
actions: {
|
actions: {
|
||||||
type: Object as () => ActionOptions,
|
type: Object as () => ActionOptions,
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
<<<<<<< HEAD
|
||||||
import Vue, { PropType } from 'vue';
|
import Vue, { PropType } from 'vue';
|
||||||
import { Editor, EditorContent } from '@tiptap/vue-2';
|
import { Editor, EditorContent } from '@tiptap/vue-2';
|
||||||
import Document from '@tiptap/extension-document';
|
import Document from '@tiptap/extension-document';
|
||||||
|
|
@ -15,6 +16,25 @@ import Text from '@tiptap/extension-text';
|
||||||
import BulletList from '@tiptap/extension-bullet-list';
|
import BulletList from '@tiptap/extension-bullet-list';
|
||||||
import ListItem from '@tiptap/extension-list-item';
|
import ListItem from '@tiptap/extension-list-item';
|
||||||
import Toggle from '@/components/ui/Toggle.vue';
|
import Toggle from '@/components/ui/Toggle.vue';
|
||||||
|
||||||| parent of a423cfde (Apply code changes from migration guide for Vue 3)
|
||||||
|
import Vue, {PropType} from 'vue';
|
||||||
|
import {Editor, EditorContent} from "@tiptap/vue-2";
|
||||||
|
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 {PropType, defineComponent} from 'vue';
|
||||||
|
import {Editor, EditorContent} from "@tiptap/vue-2";
|
||||||
|
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";
|
||||||
|
>>>>>>> a423cfde (Apply code changes from migration guide for Vue 3)
|
||||||
|
|
||||||
interface Data {
|
interface Data {
|
||||||
editor: Editor | undefined;
|
editor: Editor | undefined;
|
||||||
|
|
@ -23,6 +43,7 @@ interface Value {
|
||||||
text: string;
|
text: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
<<<<<<< HEAD
|
||||||
export default Vue.extend({
|
export default Vue.extend({
|
||||||
props: {
|
props: {
|
||||||
value: {
|
value: {
|
||||||
|
|
@ -71,6 +92,21 @@ export default Vue.extend({
|
||||||
editorProps: {
|
editorProps: {
|
||||||
attributes: {
|
attributes: {
|
||||||
class: 'tip-tap__editor',
|
class: 'tip-tap__editor',
|
||||||
|
||||||| parent of a423cfde (Apply code changes from migration guide for Vue 3)
|
||||||
|
export default Vue.extend({
|
||||||
|
props: {
|
||||||
|
value: {
|
||||||
|
type: Object as PropType<Value>,
|
||||||
|
validator(value: Value) {
|
||||||
|
return Object.prototype.hasOwnProperty.call(value, 'text');
|
||||||
|
=======
|
||||||
|
export default defineComponent({
|
||||||
|
props: {
|
||||||
|
value: {
|
||||||
|
type: Object as PropType<Value>,
|
||||||
|
validator: (value: Value) => {
|
||||||
|
return Object.prototype.hasOwnProperty.call(value, 'text');
|
||||||
|
>>>>>>> a423cfde (Apply code changes from migration guide for Vue 3)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
content: this.text,
|
content: this.text,
|
||||||
|
|
@ -80,6 +116,7 @@ export default Vue.extend({
|
||||||
this.$emit('input', text);
|
this.$emit('input', text);
|
||||||
this.$emit('change-text', text);
|
this.$emit('change-text', text);
|
||||||
},
|
},
|
||||||
|
<<<<<<< HEAD
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
@ -91,6 +128,15 @@ export default Vue.extend({
|
||||||
toggleList() {
|
toggleList() {
|
||||||
const editor = this.editor as Editor;
|
const editor = this.editor as Editor;
|
||||||
editor.chain().selectAll().toggleBulletList().run();
|
editor.chain().selectAll().toggleBulletList().run();
|
||||||
|
||||||| parent of a423cfde (Apply code changes from migration guide for Vue 3)
|
||||||
|
text(): string {
|
||||||
|
return this.value.text;
|
||||||
|
}
|
||||||
|
=======
|
||||||
|
text(): string {
|
||||||
|
return this.value?.text || '';
|
||||||
|
}
|
||||||
|
>>>>>>> a423cfde (Apply code changes from migration guide for Vue 3)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -3,10 +3,11 @@
|
||||||
<filter-entry
|
<filter-entry
|
||||||
:text="title"
|
:text="title"
|
||||||
v-bind="$attrs"
|
v-bind="$attrs"
|
||||||
|
:type="category"
|
||||||
:category="category"
|
:category="category"
|
||||||
:is-category="true"
|
:is-category="true"
|
||||||
:id="category.id"
|
:id="category.id"
|
||||||
@click.native="setCategoryFilter(category.id)"
|
@click="setCategoryFilter(category.id)"
|
||||||
/>
|
/>
|
||||||
<div class="filter-group__children">
|
<div class="filter-group__children">
|
||||||
<filter-entry
|
<filter-entry
|
||||||
|
|
@ -16,7 +17,7 @@
|
||||||
v-for="type in types"
|
v-for="type in types"
|
||||||
:id="type.id"
|
:id="type.id"
|
||||||
:key="type.id"
|
:key="type.id"
|
||||||
@click.native="setFilter(`type:${type.id}`)"
|
@click="setFilter(`type:${type.id}`)"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,8 @@
|
||||||
<div class="page-form-input">
|
<div class="page-form-input">
|
||||||
<label :for="id" class="page-form-input__label">{{ label }}</label>
|
<label :for="id" class="page-form-input__label">{{ label }}</label>
|
||||||
<component
|
<component
|
||||||
|
:value="value"
|
||||||
:class="classes"
|
:class="classes"
|
||||||
:value.prop="value"
|
|
||||||
:data-cy="cyId"
|
:data-cy="cyId"
|
||||||
:is="type"
|
:is="type"
|
||||||
:id="id"
|
:id="id"
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@
|
||||||
icon="document-with-lines-icon"
|
icon="document-with-lines-icon"
|
||||||
data-cy="use-template-button"
|
data-cy="use-template-button"
|
||||||
text="Vorlage nutzen"
|
text="Vorlage nutzen"
|
||||||
@click.native="useTemplate"
|
@click="useTemplate"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<file-upload
|
<file-upload
|
||||||
|
|
@ -30,12 +30,38 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<<<<<<< HEAD
|
||||||
<div slot="footer">
|
<div slot="footer">
|
||||||
<a class="button button--primary" data-cy="modal-save-button" @click="$emit('save', localProjectEntry)"
|
<a class="button button--primary" data-cy="modal-save-button" @click="$emit('save', localProjectEntry)"
|
||||||
>Speichern</a
|
>Speichern</a
|
||||||
>
|
>
|
||||||
<a class="button" @click="$emit('hide')">Abbrechen</a>
|
<a class="button" @click="$emit('hide')">Abbrechen</a>
|
||||||
</div>
|
</div>
|
||||||
|
||||||| parent of a423cfde (Apply code changes from migration guide for Vue 3)
|
||||||
|
<div slot="footer">
|
||||||
|
<a
|
||||||
|
class="button button--primary"
|
||||||
|
data-cy="modal-save-button"
|
||||||
|
@click="$emit('save', localProjectEntry)"
|
||||||
|
>Speichern</a>
|
||||||
|
<a
|
||||||
|
class="button"
|
||||||
|
@click="$emit('hide')"
|
||||||
|
>Abbrechen</a>
|
||||||
|
</div>
|
||||||
|
=======
|
||||||
|
<template #footer>
|
||||||
|
<a
|
||||||
|
class="button button--primary"
|
||||||
|
data-cy="modal-save-button"
|
||||||
|
@click="$emit('save', localProjectEntry)"
|
||||||
|
>Speichern</a>
|
||||||
|
<a
|
||||||
|
class="button"
|
||||||
|
@click="$emit('hide')"
|
||||||
|
>Abbrechen</a>
|
||||||
|
</template>
|
||||||
|
>>>>>>> a423cfde (Apply code changes from migration guide for Vue 3)
|
||||||
</modal>
|
</modal>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
@ -43,8 +69,17 @@
|
||||||
import Modal from '@/components/Modal';
|
import Modal from '@/components/Modal';
|
||||||
import ButtonWithIconAndText from '@/components/ui/ButtonWithIconAndText';
|
import ButtonWithIconAndText from '@/components/ui/ButtonWithIconAndText';
|
||||||
|
|
||||||
|
<<<<<<< HEAD
|
||||||
import { PROJECT_ENTRY_TEMPLATE } from '@/consts/strings.consts';
|
import { PROJECT_ENTRY_TEMPLATE } from '@/consts/strings.consts';
|
||||||
const FileUpload = () => import('@/components/ui/file-upload/FileUpload.vue');
|
const FileUpload = () => import('@/components/ui/file-upload/FileUpload.vue');
|
||||||
|
||||||| parent of a423cfde (Apply code changes from migration guide for Vue 3)
|
||||||
|
import {PROJECT_ENTRY_TEMPLATE} from '@/consts/strings.consts';
|
||||||
|
const FileUpload = () => import('@/components/ui/file-upload/FileUpload');
|
||||||
|
=======
|
||||||
|
import {PROJECT_ENTRY_TEMPLATE} from '@/consts/strings.consts';
|
||||||
|
|
||||||
|
const FileUpload = () => import('@/components/ui/file-upload/FileUpload');
|
||||||
|
>>>>>>> a423cfde (Apply code changes from migration guide for Vue 3)
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
props: {
|
props: {
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,40 @@
|
||||||
<template>
|
<template>
|
||||||
|
<<<<<<< HEAD
|
||||||
<page-form :title="title" @save="$emit('save', localProject)">
|
<page-form :title="title" @save="$emit('save', localProject)">
|
||||||
<page-form-input label="Titel" v-model="localProject.title" />
|
<page-form-input label="Titel" v-model="localProject.title" />
|
||||||
<page-form-input label="Beschreibung" type="textarea" v-model="localProject.description" />
|
<page-form-input label="Beschreibung" type="textarea" v-model="localProject.description" />
|
||||||
<template slot="footer">
|
<template slot="footer">
|
||||||
|
||||||| parent of a423cfde (Apply code changes from migration guide for Vue 3)
|
||||||
|
<page-form
|
||||||
|
:title="title"
|
||||||
|
@save="$emit('save', localProject)"
|
||||||
|
>
|
||||||
|
<page-form-input
|
||||||
|
label="Titel"
|
||||||
|
v-model="localProject.title"
|
||||||
|
/>
|
||||||
|
<page-form-input
|
||||||
|
label="Beschreibung"
|
||||||
|
type="textarea"
|
||||||
|
v-model="localProject.description"
|
||||||
|
/>
|
||||||
|
<template slot="footer">
|
||||||
|
=======
|
||||||
|
<page-form
|
||||||
|
:title="title"
|
||||||
|
@save="$emit('save', localProject)"
|
||||||
|
>
|
||||||
|
<page-form-input
|
||||||
|
label="Titel"
|
||||||
|
v-model="localProject.title"
|
||||||
|
/>
|
||||||
|
<page-form-input
|
||||||
|
label="Beschreibung"
|
||||||
|
type="textarea"
|
||||||
|
v-model="localProject.description"
|
||||||
|
/>
|
||||||
|
<template #footer>
|
||||||
|
>>>>>>> a423cfde (Apply code changes from migration guide for Vue 3)
|
||||||
<button
|
<button
|
||||||
:class="{ 'button--disabled': !formValid }"
|
:class="{ 'button--disabled': !formValid }"
|
||||||
:disabled="!formValid"
|
:disabled="!formValid"
|
||||||
|
|
|
||||||
|
|
@ -6,10 +6,34 @@
|
||||||
|
|
||||||
<modal-input :value="name" :placeholder="placeholder" data-cy="edit-name-input" @input="$emit('input', $event)" />
|
<modal-input :value="name" :placeholder="placeholder" data-cy="edit-name-input" @input="$emit('input', $event)" />
|
||||||
<template #footer>
|
<template #footer>
|
||||||
|
<<<<<<< HEAD
|
||||||
<div slot="footer">
|
<div slot="footer">
|
||||||
<a class="button button--primary" data-cy="modal-save-button" @click="$emit('save')">Speichern</a>
|
<a class="button button--primary" data-cy="modal-save-button" @click="$emit('save')">Speichern</a>
|
||||||
<a class="button" @click="$emit('cancel')">Abbrechen</a>
|
<a class="button" @click="$emit('cancel')">Abbrechen</a>
|
||||||
</div>
|
</div>
|
||||||
|
||||||| parent of a423cfde (Apply code changes from migration guide for Vue 3)
|
||||||
|
<div slot="footer">
|
||||||
|
<a
|
||||||
|
class="button button--primary"
|
||||||
|
data-cy="modal-save-button"
|
||||||
|
@click="$emit('save')"
|
||||||
|
>Speichern</a>
|
||||||
|
<a
|
||||||
|
class="button"
|
||||||
|
@click="$emit('cancel')"
|
||||||
|
>Abbrechen</a>
|
||||||
|
</div>
|
||||||
|
=======
|
||||||
|
<a
|
||||||
|
class="button button--primary"
|
||||||
|
data-cy="modal-save-button"
|
||||||
|
@click="$emit('save')"
|
||||||
|
>Speichern</a>
|
||||||
|
<a
|
||||||
|
class="button"
|
||||||
|
@click="$emit('cancel')"
|
||||||
|
>Abbrechen</a>
|
||||||
|
>>>>>>> a423cfde (Apply code changes from migration guide for Vue 3)
|
||||||
</template>
|
</template>
|
||||||
</modal>
|
</modal>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,18 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="simple-file-upload">
|
<div class="simple-file-upload">
|
||||||
|
<<<<<<< HEAD
|
||||||
<component :is="button" @click.native="clickUploadCare" />
|
<component :is="button" @click.native="clickUploadCare" />
|
||||||
|
||||||| parent of a423cfde (Apply code changes from migration guide for Vue 3)
|
||||||
|
<component
|
||||||
|
:is="button"
|
||||||
|
@click.native="clickUploadCare"
|
||||||
|
/>
|
||||||
|
=======
|
||||||
|
<component
|
||||||
|
:is="button"
|
||||||
|
@click="clickUploadCare"
|
||||||
|
/>
|
||||||
|
>>>>>>> a423cfde (Apply code changes from migration guide for Vue 3)
|
||||||
<simple-file-upload-hidden-input @link-change-url="$emit('link-change-url', $event)" />
|
<simple-file-upload-hidden-input @link-change-url="$emit('link-change-url', $event)" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
icon="document-icon"
|
icon="document-icon"
|
||||||
text="Dokument hochladen"
|
text="Dokument hochladen"
|
||||||
v-if="!value"
|
v-if="!value"
|
||||||
@click.native="clickUploadCare"
|
@click="clickUploadCare"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<simple-file-upload-hidden-input @link-change-url="$emit('link-change-url', $event)" />
|
<simple-file-upload-hidden-input @link-change-url="$emit('link-change-url', $event)" />
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
const resizeElement = (el) => {
|
const resizeElement = (el: HTMLElement) => {
|
||||||
el.style.height = `auto`;
|
el.style.height = `auto`;
|
||||||
el.style.height = `${el.clientHeight - el.offsetHeight + el.scrollHeight}px`;
|
el.style.height = `${el.clientHeight - el.offsetHeight + el.scrollHeight}px`;
|
||||||
};
|
};
|
||||||
|
|
@ -6,13 +6,13 @@ const resizeElement = (el) => {
|
||||||
export default {
|
export default {
|
||||||
update: resizeElement,
|
update: resizeElement,
|
||||||
inserted: resizeElement,
|
inserted: resizeElement,
|
||||||
bind(el) {
|
created(el: HTMLElement) {
|
||||||
el.classList.add('skillbox-auto-grow');
|
el.classList.add('skillbox-auto-grow');
|
||||||
el.addEventListener('input', () => {
|
el.addEventListener('input', () => {
|
||||||
resizeElement(el);
|
resizeElement(el);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
unbind(el) {
|
unmounted(el: HTMLElement) {
|
||||||
el.classList.remove('skillbox-auto-grow');
|
el.classList.remove('skillbox-auto-grow');
|
||||||
el.removeEventListener('input', () => {
|
el.removeEventListener('input', () => {
|
||||||
resizeElement(el);
|
resizeElement(el);
|
||||||
|
|
@ -1,14 +0,0 @@
|
||||||
// taken from https://stackoverflow.com/questions/36170425/detect-click-outside-element
|
|
||||||
export default {
|
|
||||||
bind(el, binding, vnode) {
|
|
||||||
el.clickOutsideEvent = (event) => {
|
|
||||||
if (!(el === event.target || el.contains(event.target))) {
|
|
||||||
vnode.context[binding.expression](event);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
document.body.addEventListener('click', el.clickOutsideEvent);
|
|
||||||
},
|
|
||||||
unbind(el) {
|
|
||||||
document.body.removeEventListener('click', el.clickOutsideEvent);
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
@ -0,0 +1,23 @@
|
||||||
|
// taken from https://stackoverflow.com/questions/36170425/detect-click-outside-element
|
||||||
|
import {DirectiveBinding, VNode} from "vue";
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElement {
|
||||||
|
clickOutsideEvent: (event: Event) => void
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default {
|
||||||
|
unmounted(el: HTMLElement) {
|
||||||
|
document.body.removeEventListener('click', el.clickOutsideEvent);
|
||||||
|
},
|
||||||
|
created: (el: HTMLElement, binding: DirectiveBinding) => {
|
||||||
|
el.clickOutsideEvent = (event: Event) => {
|
||||||
|
if (!(el === event.target || el.contains(event.target as Node))) {
|
||||||
|
const eventHandler = binding.value;
|
||||||
|
eventHandler(event);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
document.body.addEventListener('click', el.clickOutsideEvent);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
@ -1,131 +1,160 @@
|
||||||
<template>
|
<template>
|
||||||
<footer class="default-footer" data-cy="page-footer">
|
<footer
|
||||||
|
class="default-footer"
|
||||||
|
data-cy="page-footer"
|
||||||
|
>
|
||||||
<div class="default-footer__section">
|
<div class="default-footer__section">
|
||||||
<div class="default-footer__info">
|
<div class="default-footer__info">
|
||||||
<div class="default-footer__who-are-we who-are-we">
|
<div class="default-footer__who-are-we who-are-we">
|
||||||
<h5 class="who-are-we__title">Wer sind wir?</h5>
|
<h5 class="who-are-we__title">
|
||||||
|
Wer sind wir?
|
||||||
|
</h5>
|
||||||
<p class="who-are-we__text">
|
<p class="who-are-we__text">
|
||||||
mySkillbox ist ein Angebot des hep Verlags in Zusammenarbeit mit der Eidgenössischen Hochschule für
|
mySkillbox ist ein Angebot des hep Verlags in
|
||||||
Berufsbildung (EHB).
|
Zusammenarbeit mit der Eidgenössischen Hochschule für Berufsbildung (EHB).
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<a href="https://www.hep-verlag.ch/" target="_blank">
|
<a
|
||||||
|
href="https://www.hep-verlag.ch/"
|
||||||
|
target="_blank"
|
||||||
|
>
|
||||||
<hep-logo class="default-footer__logo-hep" />
|
<hep-logo class="default-footer__logo-hep" />
|
||||||
</a>
|
</a>
|
||||||
<a href="https://www.ehb.swiss/" target="_blank">
|
<a
|
||||||
|
href="https://www.ehb.swiss/"
|
||||||
|
target="_blank"
|
||||||
|
>
|
||||||
<ehb-logo class="default-footer__logo-ehb" />
|
<ehb-logo class="default-footer__logo-ehb" />
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="default-footer__section">
|
<div class="default-footer__section">
|
||||||
<div class="default-footer__links">
|
<div class="default-footer__links">
|
||||||
<a href="https://myskillbox.ch/datenschutz" target="_blank" class="default-footer__link">Datenschutz</a>
|
<a
|
||||||
<a href="https://myskillbox.ch/impressum" target="_blank" class="default-footer__link">Impressum</a>
|
href="https://myskillbox.ch/datenschutz"
|
||||||
<a href="https://myskillbox.ch/agb" target="_blank" class="default-footer__link">AGB</a>
|
target="_blank"
|
||||||
<a :href="$flavor.supportLink" target="_blank" class="default-footer__link">Support</a>
|
class="default-footer__link"
|
||||||
|
>Datenschutz</a>
|
||||||
|
<a
|
||||||
|
href="https://myskillbox.ch/impressum"
|
||||||
|
target="_blank"
|
||||||
|
class="default-footer__link"
|
||||||
|
>Impressum</a>
|
||||||
|
<a
|
||||||
|
href="https://myskillbox.ch/agb"
|
||||||
|
target="_blank"
|
||||||
|
class="default-footer__link"
|
||||||
|
>AGB</a>
|
||||||
|
<a
|
||||||
|
:href="$flavor.supportLink"
|
||||||
|
target="_blank"
|
||||||
|
class="default-footer__link"
|
||||||
|
>Support</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</footer>
|
</footer>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
const HepLogo = () => import(/* webpackChunkName: "icons" */ '@/components/icons/HepLogo');
|
import {defineAsyncComponent} from 'vue';
|
||||||
const EhbLogo = () => import(/* webpackChunkName: "icons" */ '@/components/icons/EhbLogo');
|
|
||||||
|
|
||||||
export default {
|
const HepLogo = defineAsyncComponent(() => import(/* webpackChunkName: "icons" */'@/components/icons/HepLogo'));
|
||||||
components: {
|
const EhbLogo = defineAsyncComponent(() => import(/* webpackChunkName: "icons" */'@/components/icons/EhbLogo'));
|
||||||
HepLogo,
|
|
||||||
EhbLogo,
|
export default {
|
||||||
},
|
components: {
|
||||||
};
|
HepLogo,
|
||||||
|
EhbLogo
|
||||||
|
}
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
@import '@/styles/_variables.scss';
|
@import "@/styles/_variables.scss";
|
||||||
@import '@/styles/_mixins.scss';
|
@import "@/styles/_mixins.scss";
|
||||||
|
|
||||||
.default-footer {
|
.default-footer {
|
||||||
background-color: $color-silver-light;
|
background-color: $color-silver-light;
|
||||||
max-width: 100vw;
|
max-width: 100vw;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
|
||||||
&__section {
|
&__section {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
border-bottom: $color-silver 1px solid;
|
border-bottom: $color-silver 1px solid;
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
&__info {
|
&__info {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
max-width: $footer-width;
|
max-width: $footer-width;
|
||||||
padding: 2 * $large-spacing 0;
|
padding: 2*$large-spacing 0;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
|
||||||
@include desktop {
|
@include desktop {
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__who-are-we {
|
||||||
|
width: 100%;
|
||||||
|
margin-bottom: $large-spacing;
|
||||||
|
|
||||||
|
@include desktop {
|
||||||
|
width: 330px;
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__logo-hep {
|
||||||
|
width: auto;
|
||||||
|
height: 35px;
|
||||||
|
margin-bottom: $large-spacing;
|
||||||
|
|
||||||
|
@include desktop {
|
||||||
|
width: 147px;
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__logo-ehb {
|
||||||
|
width: 100px;
|
||||||
|
height: 32px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__links {
|
||||||
|
width: 100%;
|
||||||
|
max-width: $footer-width;
|
||||||
|
padding: $large-spacing 0;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
|
@include desktop {
|
||||||
|
flex-direction: row;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__link {
|
||||||
|
@include aside-with-cheese;
|
||||||
|
margin-right: $large-spacing;
|
||||||
|
margin-bottom: $small-spacing;
|
||||||
|
|
||||||
|
@include desktop {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&__who-are-we {
|
.who-are-we {
|
||||||
width: 100%;
|
&__title {
|
||||||
margin-bottom: $large-spacing;
|
@include heading-4;
|
||||||
|
}
|
||||||
|
|
||||||
@include desktop {
|
&__text {
|
||||||
width: 330px;
|
@include aside-text;
|
||||||
margin-bottom: 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&__logo-hep {
|
|
||||||
width: auto;
|
|
||||||
height: 35px;
|
|
||||||
margin-bottom: $large-spacing;
|
|
||||||
|
|
||||||
@include desktop {
|
|
||||||
width: 147px;
|
|
||||||
margin-bottom: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&__logo-ehb {
|
|
||||||
width: 100px;
|
|
||||||
height: 32px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__links {
|
|
||||||
width: 100%;
|
|
||||||
max-width: $footer-width;
|
|
||||||
padding: $large-spacing 0;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
|
|
||||||
@include desktop {
|
|
||||||
flex-direction: row;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&__link {
|
|
||||||
@include aside-with-cheese;
|
|
||||||
margin-right: $large-spacing;
|
|
||||||
margin-bottom: $small-spacing;
|
|
||||||
|
|
||||||
@include desktop {
|
|
||||||
margin-bottom: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.who-are-we {
|
|
||||||
&__title {
|
|
||||||
@include heading-4;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__text {
|
|
||||||
@include aside-text;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -1,73 +1,80 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="layout layout--public public">
|
<div class="layout layout--public public">
|
||||||
<div class="public__logo">
|
<div class="public__logo">
|
||||||
<router-link :to="{ name: 'hello' }" class="hep-link">
|
<router-link
|
||||||
|
:to="{name: 'hello'}"
|
||||||
|
class="hep-link"
|
||||||
|
>
|
||||||
<logo />
|
<logo />
|
||||||
</router-link>
|
</router-link>
|
||||||
</div>
|
</div>
|
||||||
<router-view class="public__content layout__content" />
|
<router-view class="public__content layout__content" />
|
||||||
<default-footer class="skillbox__footer public__footer footer" v-if="$flavor.showFooter" />
|
<default-footer
|
||||||
|
class="skillbox__footer public__footer footer"
|
||||||
|
v-if="$flavor.showFooter"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import DefaultFooter from '@/layouts/DefaultFooter';
|
import {defineAsyncComponent} from 'vue';
|
||||||
|
import DefaultFooter from '@/layouts/DefaultFooter';
|
||||||
|
const Logo = defineAsyncComponent(() => import(/* webpackChunkName: "icons" */'@/components/icons/Logo'));
|
||||||
|
|
||||||
const Logo = () => import(/* webpackChunkName: "icons" */ '@/components/icons/Logo');
|
export default {
|
||||||
|
components: {
|
||||||
export default {
|
Logo,
|
||||||
components: {
|
DefaultFooter
|
||||||
Logo,
|
},
|
||||||
DefaultFooter,
|
};
|
||||||
},
|
|
||||||
};
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
@import '@/styles/_variables.scss';
|
@import "@/styles/_variables.scss";
|
||||||
@import '@/styles/_mixins.scss';
|
@import "@/styles/_mixins.scss";
|
||||||
@import '@/styles/_default-layout.scss';
|
@import "@/styles/_default-layout.scss";
|
||||||
|
|
||||||
@mixin content-block {
|
@mixin content-block {
|
||||||
padding-right: $medium-spacing;
|
padding-right: $medium-spacing;
|
||||||
padding-left: $medium-spacing;
|
padding-left: $medium-spacing;
|
||||||
max-width: 800px;
|
max-width: 800px;
|
||||||
min-width: 320px;
|
min-width: 320px;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.logo {
|
.logo {
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
||||||
width: auto;
|
|
||||||
height: 43px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.public {
|
|
||||||
grid-template-areas: 'h' 'c' 'f';
|
|
||||||
|
|
||||||
&__content {
|
|
||||||
@include content-block();
|
|
||||||
margin-bottom: $large-spacing;
|
|
||||||
width: auto;
|
width: auto;
|
||||||
|
height: 43px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&__logo {
|
.public {
|
||||||
@include content-block();
|
grid-template-areas: "h" "c" "f";
|
||||||
margin-top: $medium-spacing;
|
|
||||||
|
&__content {
|
||||||
|
@include content-block();
|
||||||
|
margin-bottom: $large-spacing;
|
||||||
|
width: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__logo {
|
||||||
|
@include content-block();
|
||||||
|
margin-top: $medium-spacing
|
||||||
|
}
|
||||||
|
|
||||||
|
&__footer {
|
||||||
|
background-color: $color-silver-light;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&__footer {
|
.footer {
|
||||||
background-color: $color-silver-light;
|
padding: $large-spacing $medium-spacing 0;
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.footer {
|
&__content {
|
||||||
padding: $large-spacing $medium-spacing 0;
|
@include content-block();
|
||||||
|
}
|
||||||
&__content {
|
|
||||||
@include content-block();
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import '@babel/polyfill';
|
import '@babel/polyfill';
|
||||||
import Vue from 'vue';
|
import {createApp, inject} from 'vue';
|
||||||
import VueVimeoPlayer from 'vue-vimeo-player';
|
import VueVimeoPlayer from 'vue-vimeo-player';
|
||||||
import apolloClientFactory from './graphql/client';
|
import apolloClientFactory from './graphql/client';
|
||||||
import VueApollo from 'vue-apollo';
|
import VueApollo from 'vue-apollo';
|
||||||
|
|
@ -13,42 +13,9 @@ import ME_QUERY from '@/graphql/gql/queries/meQuery.gql';
|
||||||
import VueModal from '@/plugins/modal';
|
import VueModal from '@/plugins/modal';
|
||||||
import VueRemoveEdges from '@/plugins/edges';
|
import VueRemoveEdges from '@/plugins/edges';
|
||||||
import VueMatomo from 'vue-matomo';
|
import VueMatomo from 'vue-matomo';
|
||||||
|
import VueLogger from 'vuejs3-logger';
|
||||||
import { joiningClass, loginRequired, unauthorizedAccess } from '@/router/guards';
|
import { joiningClass, loginRequired, unauthorizedAccess } from '@/router/guards';
|
||||||
import flavorPlugin from '@/plugins/flavor';
|
import flavorPlugin from '@/plugins/flavor';
|
||||||
import log from 'loglevel';
|
|
||||||
|
|
||||||
window.log = log; // make log available in app when built, to change log level: log.setLevel('debug')
|
|
||||||
|
|
||||||
Vue.config.productionTip = false;
|
|
||||||
const isProduction = process.env.NODE_ENV === 'production';
|
|
||||||
|
|
||||||
const logLevel = isProduction ? 'error' : 'warn';
|
|
||||||
|
|
||||||
log.setDefaultLevel(logLevel);
|
|
||||||
|
|
||||||
Vue.use(VueModal);
|
|
||||||
Vue.use(VueRemoveEdges);
|
|
||||||
Vue.use(VueApollo);
|
|
||||||
Vue.use(VueVimeoPlayer);
|
|
||||||
|
|
||||||
Vue.use(VueScrollTo, {
|
|
||||||
duration: 500,
|
|
||||||
easing: 'ease-out',
|
|
||||||
offset: -50,
|
|
||||||
});
|
|
||||||
|
|
||||||
Vue.use(flavorPlugin);
|
|
||||||
|
|
||||||
if (process.env.MATOMO_HOST) {
|
|
||||||
Vue.use(VueMatomo, {
|
|
||||||
host: process.env.MATOMO_HOST,
|
|
||||||
siteId: process.env.MATOMO_SITE_ID,
|
|
||||||
router: router,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
Vue.directive('click-outside', clickOutside);
|
|
||||||
Vue.directive('auto-grow', autoGrow);
|
|
||||||
|
|
||||||
const publicApolloClient = apolloClientFactory('/api/graphql-public/', null);
|
const publicApolloClient = apolloClientFactory('/api/graphql-public/', null);
|
||||||
const privateApolloClient = apolloClientFactory('/api/graphql/', networkErrorCallback);
|
const privateApolloClient = apolloClientFactory('/api/graphql/', networkErrorCallback);
|
||||||
|
|
@ -60,56 +27,96 @@ const apolloProvider = new VueApollo({
|
||||||
defaultClient: privateApolloClient,
|
defaultClient: privateApolloClient,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const app = createApp({
|
||||||
|
store,
|
||||||
|
router,
|
||||||
|
apolloProvider,
|
||||||
|
render: h => h(App),
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
const isProduction = process.env.NODE_ENV === 'production';
|
||||||
|
|
||||||
|
app.use(VueModal);
|
||||||
|
app.use(VueRemoveEdges);
|
||||||
|
app.use(VueApollo);
|
||||||
|
app.use(VueVimeoPlayer);
|
||||||
|
app.use(VueLogger, {
|
||||||
|
isEnabled: true,
|
||||||
|
logLevel: isProduction ? 'error' : 'debug',
|
||||||
|
stringifyArguments: false,
|
||||||
|
showConsoleColors: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
// VueScrollTo.setDefaults({
|
||||||
|
// duration: 500,
|
||||||
|
// easing: 'ease-out',
|
||||||
|
// offset: -50,
|
||||||
|
// });
|
||||||
|
|
||||||
|
app.directive('scroll-to', VueScrollTo);
|
||||||
|
|
||||||
|
|
||||||
|
app.use(flavorPlugin);
|
||||||
|
|
||||||
|
if (process.env.MATOMO_HOST) {
|
||||||
|
app.use(VueMatomo, {
|
||||||
|
host: process.env.MATOMO_HOST,
|
||||||
|
siteId: process.env.MATOMO_SITE_ID,
|
||||||
|
router: router,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
app.directive('click-outside', clickOutside);
|
||||||
|
app.directive('auto-grow', autoGrow);
|
||||||
|
|
||||||
/* guards */
|
/* guards */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function redirectUsersWithoutValidLicense() {
|
function redirectUsersWithoutValidLicense() {
|
||||||
return privateApolloClient
|
return privateApolloClient.query({
|
||||||
.query({
|
query: ME_QUERY,
|
||||||
query: ME_QUERY,
|
}).then(({data}) => data.me.expiryDate == null);
|
||||||
})
|
|
||||||
.then(({ data }) => data.me.expiryDate == null);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function redirectStudentsWithoutClass() {
|
function redirectStudentsWithoutClass() {
|
||||||
return privateApolloClient
|
return privateApolloClient.query({
|
||||||
.query({
|
query: ME_QUERY,
|
||||||
query: ME_QUERY,
|
}).then(({data}) => data.me.schoolClasses.length === 0 && !data.me.isTeacher);
|
||||||
})
|
|
||||||
.then(({ data }) => data.me.schoolClasses.length === 0 && !data.me.isTeacher);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function redirectUsersToOnboarding() {
|
function redirectUsersToOnboarding() {
|
||||||
return privateApolloClient
|
return privateApolloClient.query({
|
||||||
.query({
|
query: ME_QUERY,
|
||||||
query: ME_QUERY,
|
}).then(({data}) => !data.me.onboardingVisited);
|
||||||
})
|
|
||||||
.then(({ data }) => !data.me.onboardingVisited);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function networkErrorCallback(statusCode) {
|
function networkErrorCallback(statusCode) {
|
||||||
if (statusCode === 402) {
|
if (statusCode === 402) {
|
||||||
log.debug('status code 402, redirecting');
|
router.push({name: 'licenseActivation'});
|
||||||
router.push({ name: 'licenseActivation' });
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
router.beforeEach(async (to, from, next) => {
|
router.beforeEach(async (to, from, next) => {
|
||||||
log.debug('navigation guard called', to, from);
|
// todo: make logger work outside vue app
|
||||||
|
// const logger = inject('vuejs3-logger');
|
||||||
|
// logger.$log.debug('navigation guard called', to, from);
|
||||||
if (to.path === '/logout') {
|
if (to.path === '/logout') {
|
||||||
log.debug('logout', to);
|
await publicApolloClient.resetStore();
|
||||||
publicApolloClient.resetStore();
|
|
||||||
if (process.env.LOGOUT_REDIRECT_URL) {
|
if (process.env.LOGOUT_REDIRECT_URL) {
|
||||||
location.replace(`https://sso.hep-verlag.ch/logout?return_to=${process.env.LOGOUT_REDIRECT_URL}`);
|
location.replace(`https://sso.hep-verlag.ch/logout?return_to=${process.env.LOGOUT_REDIRECT_URL}`);
|
||||||
next(false);
|
next(false);
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
next({ name: 'hello' });
|
next({name: 'hello'});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (unauthorizedAccess(to)) {
|
if (unauthorizedAccess(to)) {
|
||||||
log.debug('unauthorized', to);
|
//logger.$log.debug('unauthorized', to);
|
||||||
const postLoginRedirectionUrl = to.path;
|
const postLoginRedirectionUrl = to.path;
|
||||||
const redirectUrl = `/hello/`;
|
const redirectUrl = `/hello/`;
|
||||||
|
|
||||||
|
|
@ -117,46 +124,33 @@ router.beforeEach(async (to, from, next) => {
|
||||||
localStorage.setItem(postLoginRedirectUrlKey, postLoginRedirectionUrl);
|
localStorage.setItem(postLoginRedirectUrlKey, postLoginRedirectionUrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
log.debug('redirecting to hello', to);
|
// logger.$log.debug('redirecting to hello', to);
|
||||||
next(redirectUrl);
|
next(redirectUrl);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (to.name && to.name !== 'licenseActivation' && loginRequired(to) && (await redirectUsersWithoutValidLicense())) {
|
if (to.name && to.name !== 'licenseActivation' && loginRequired(to) && await redirectUsersWithoutValidLicense()) {
|
||||||
log.debug('redirecting to licenseActivation', to, null);
|
// logger.$log.debug('redirecting to licenseActivation', to, null);
|
||||||
console.log('redirecting to licenseActivation', to, null);
|
console.log('redirecting to licenseActivation', to, null);
|
||||||
next({ name: 'licenseActivation' });
|
next({name: 'licenseActivation'});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!joiningClass(to) && loginRequired(to) && (await redirectStudentsWithoutClass())) {
|
if (!joiningClass(to) && loginRequired(to) && await redirectStudentsWithoutClass()) {
|
||||||
log.debug('redirecting to join-class', to);
|
//logger.$log.debug('redirecting to join-class', to);
|
||||||
log.debug('await redirectStudentsWithoutClass()', await redirectStudentsWithoutClass());
|
//logger.$log.debug('await redirectStudentsWithoutClass()', await redirectStudentsWithoutClass());
|
||||||
next({ name: 'join-class' });
|
next({name: 'join-class'});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (
|
if ((to.name && to.name.indexOf('onboarding') === -1) && !joiningClass(to) && loginRequired(to) && await redirectUsersToOnboarding()) {
|
||||||
to.name &&
|
//logger.$log.debug('redirecting to onboarding-start', to);
|
||||||
to.name.indexOf('onboarding') === -1 &&
|
next({name: 'onboarding-start'});
|
||||||
!joiningClass(to) &&
|
|
||||||
loginRequired(to) &&
|
|
||||||
(await redirectUsersToOnboarding())
|
|
||||||
) {
|
|
||||||
log.debug('redirecting to onboarding-start', to);
|
|
||||||
next({ name: 'onboarding-start' });
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
log.debug('End of Guard reached', to);
|
//logger.$log.debug('End of Guard reached', to);
|
||||||
next();
|
next();
|
||||||
});
|
});
|
||||||
|
|
||||||
/* eslint-disable no-new */
|
app.mount('#app');
|
||||||
new Vue({
|
|
||||||
el: '#app',
|
|
||||||
store,
|
|
||||||
router,
|
|
||||||
apolloProvider,
|
|
||||||
render: (h) => h(App),
|
|
||||||
});
|
|
||||||
|
|
|
||||||
File diff suppressed because one or more lines are too long
|
|
@ -1,82 +1,85 @@
|
||||||
<template>
|
<template>
|
||||||
<content-block-form title="Inhaltsblock erfassen" :content-block="contentBlock" @back="goToModule" @save="save" />
|
<content-block-form
|
||||||
|
title="Inhaltsblock erfassen"
|
||||||
|
:content-block="contentBlock"
|
||||||
|
@back="goToModule"
|
||||||
|
@save="save"
|
||||||
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import Vue from 'vue';
|
import {defineComponent} from 'vue';
|
||||||
|
|
||||||
import ContentBlockForm from '@/components/content-block-form/ContentBlockForm';
|
import ContentBlockForm from '@/components/content-block-form/ContentBlockForm';
|
||||||
import { setUserBlockType } from '@/helpers/content-block';
|
import {setUserBlockType} from '@/helpers/content-block';
|
||||||
import NEW_CONTENT_BLOCK_MUTATION from '@/graphql/gql/mutations/addContentBlock.gql';
|
import NEW_CONTENT_BLOCK_MUTATION from '@/graphql/gql/mutations/addContentBlock.gql';
|
||||||
import MODULE_DETAILS_QUERY from '@/graphql/gql/queries/modules/moduleDetailsQuery.gql';
|
import MODULE_DETAILS_QUERY from '@/graphql/gql/queries/modules/moduleDetailsQuery.gql';
|
||||||
import { cleanUpContents } from '@/components/content-block-form/helpers';
|
import {cleanUpContents} from '@/components/content-block-form/helpers';
|
||||||
|
|
||||||
export default Vue.extend({
|
export default defineComponent({
|
||||||
props: {
|
props: {
|
||||||
parent: {
|
parent: {
|
||||||
type: String,
|
type: String,
|
||||||
default: '',
|
default: ''
|
||||||
},
|
},
|
||||||
after: {
|
after: {
|
||||||
type: String,
|
type: String,
|
||||||
default: '',
|
default: ''
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
components: {
|
|
||||||
ContentBlockForm,
|
|
||||||
},
|
|
||||||
|
|
||||||
data: () => ({
|
|
||||||
contentBlock: {
|
|
||||||
title: '',
|
|
||||||
isAssignment: false,
|
|
||||||
contents: [],
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
|
|
||||||
methods: {
|
|
||||||
save({ title, contents, isAssignment }) {
|
|
||||||
let cleanedContents = cleanUpContents(contents);
|
|
||||||
const contentBlock = {
|
|
||||||
title: title,
|
|
||||||
contents: cleanedContents,
|
|
||||||
type: setUserBlockType(isAssignment),
|
|
||||||
};
|
|
||||||
let input;
|
|
||||||
const { parent, after, slug } = this.$route.params;
|
|
||||||
if (after) {
|
|
||||||
input = {
|
|
||||||
contentBlock,
|
|
||||||
after,
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
input = {
|
|
||||||
contentBlock,
|
|
||||||
parent,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
this.$apollo
|
},
|
||||||
.mutate({
|
|
||||||
|
components: {
|
||||||
|
ContentBlockForm,
|
||||||
|
},
|
||||||
|
|
||||||
|
data: () => ({
|
||||||
|
contentBlock: {
|
||||||
|
title: '',
|
||||||
|
isAssignment: false,
|
||||||
|
contents: [
|
||||||
|
]},
|
||||||
|
}),
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
save({title, contents, isAssignment}) {
|
||||||
|
let cleanedContents = cleanUpContents(contents);
|
||||||
|
const contentBlock = {
|
||||||
|
title: title,
|
||||||
|
contents: cleanedContents,
|
||||||
|
type: setUserBlockType(isAssignment),
|
||||||
|
};
|
||||||
|
let input;
|
||||||
|
const { parent, after, slug } = this.$route.params;
|
||||||
|
if(after) {
|
||||||
|
input = {
|
||||||
|
contentBlock,
|
||||||
|
after
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
input = {
|
||||||
|
contentBlock,
|
||||||
|
parent
|
||||||
|
};
|
||||||
|
}
|
||||||
|
this.$apollo.mutate({
|
||||||
mutation: NEW_CONTENT_BLOCK_MUTATION,
|
mutation: NEW_CONTENT_BLOCK_MUTATION,
|
||||||
variables: {
|
variables: {
|
||||||
input,
|
input
|
||||||
},
|
},
|
||||||
refetchQueries: [
|
refetchQueries: [{
|
||||||
{
|
query: MODULE_DETAILS_QUERY,
|
||||||
query: MODULE_DETAILS_QUERY,
|
variables: {
|
||||||
variables: {
|
slug
|
||||||
slug,
|
}
|
||||||
},
|
}]
|
||||||
},
|
}).then(this.goToModule);
|
||||||
],
|
},
|
||||||
})
|
goToModule() {
|
||||||
.then(this.goToModule);
|
// use the history, so the scroll position is preserved
|
||||||
},
|
this.$router.go(-1);
|
||||||
goToModule() {
|
}
|
||||||
// use the history, so the scroll position is preserved
|
}
|
||||||
this.$router.go(-1);
|
|
||||||
},
|
|
||||||
},
|
});
|
||||||
});
|
|
||||||
</script>
|
</script>
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@
|
||||||
:final="project.final"
|
:final="project.final"
|
||||||
data-cy="project-share-link"
|
data-cy="project-share-link"
|
||||||
class="project__share"
|
class="project__share"
|
||||||
@click.native="updateProjectShareState(project.slug, !project.final)"
|
@click="updateProjectShareState(project.slug, !project.final)"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<project-actions :share-buttons="false" class="project__more" :slug="project.slug" v-if="canEdit" />
|
<project-actions :share-buttons="false" class="project__more" :slug="project.slug" v-if="canEdit" />
|
||||||
|
|
|
||||||
|
|
@ -5,14 +5,21 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="topic__content">
|
<div class="topic__content">
|
||||||
<h1 data-cy="topic-title" class="topic__title">
|
<h1
|
||||||
|
data-cy="topic-title"
|
||||||
|
class="topic__title"
|
||||||
|
>
|
||||||
{{ topic.title }}
|
{{ topic.title }}
|
||||||
</h1>
|
</h1>
|
||||||
<p class="topic__teaser">
|
<p class="topic__teaser">
|
||||||
{{ topic.teaser }}
|
{{ topic.teaser }}
|
||||||
</p>
|
</p>
|
||||||
<div class="topic__links">
|
<div class="topic__links">
|
||||||
<div class="topic__video-link topic__link" v-if="topic.vimeoId" @click="openVideo">
|
<div
|
||||||
|
class="topic__video-link topic__link"
|
||||||
|
v-if="topic.vimeoId"
|
||||||
|
@click="openVideo"
|
||||||
|
>
|
||||||
<play-icon class="topic__video-link-icon topic__link-icon" />
|
<play-icon class="topic__video-link-icon topic__link-icon" />
|
||||||
<span class="topic__link-description">Video schauen</span>
|
<span class="topic__link-description">Video schauen</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -27,187 +34,184 @@
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="topic__modules">
|
<div class="topic__modules">
|
||||||
<module-teaser v-for="module in modules" :key="module.slug" v-bind="module" />
|
<module-teaser
|
||||||
|
v-for="module in modules"
|
||||||
|
v-bind="module"
|
||||||
|
:key="module.slug"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import ModuleTeaser from '@/components/modules/ModuleTeaser.vue';
|
import ModuleTeaser from '@/components/modules/ModuleTeaser.vue';
|
||||||
import TOPIC_QUERY from '@/graphql/gql/queries/topicQuery.gql';
|
import TOPIC_QUERY from '@/graphql/gql/queries/topicQuery.gql';
|
||||||
import me from '@/mixins/me';
|
import me from '@/mixins/me';
|
||||||
import TopicNavigation from '@/components/book-navigation/TopicNavigation';
|
import TopicNavigation from '@/components/book-navigation/TopicNavigation';
|
||||||
|
|
||||||
import UPDATE_LAST_TOPIC_MUTATION from '@/graphql/gql/mutations/updateLastTopic.gql';
|
import UPDATE_LAST_TOPIC_MUTATION from '@/graphql/gql/mutations/updateLastTopic.gql';
|
||||||
import ME_QUERY from '@/graphql/gql/queries/meQuery.gql';
|
import ME_QUERY from '@/graphql/gql/queries/meQuery.gql';
|
||||||
|
|
||||||
const PlayIcon = () => import(/* webpackChunkName: "icons" */ '@/components/icons/Play');
|
const PlayIcon = () => import(/* webpackChunkName: "icons" */'@/components/icons/Play');
|
||||||
const BulbIcon = () => import(/* webpackChunkName: "icons" */ '@/components/icons/BulbIcon');
|
const BulbIcon = () => import(/* webpackChunkName: "icons" */'@/components/icons/BulbIcon');
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
mixins: [me],
|
|
||||||
components: {
|
|
||||||
TopicNavigation,
|
|
||||||
ModuleTeaser,
|
|
||||||
PlayIcon,
|
|
||||||
BulbIcon,
|
|
||||||
},
|
|
||||||
|
|
||||||
apollo: {
|
mixins: [me],
|
||||||
topic() {
|
components: {
|
||||||
return {
|
TopicNavigation,
|
||||||
query: TOPIC_QUERY,
|
ModuleTeaser,
|
||||||
variables: {
|
PlayIcon,
|
||||||
slug: this.$route.params.topicSlug,
|
BulbIcon,
|
||||||
},
|
|
||||||
update(data) {
|
|
||||||
return this.$getRidOfEdges(data).topic || {};
|
|
||||||
},
|
|
||||||
result() {
|
|
||||||
if (this.saveMe) {
|
|
||||||
this.saveMe = false;
|
|
||||||
this.updateLastVisitedTopic(this.topic.id);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
};
|
|
||||||
},
|
},
|
||||||
},
|
|
||||||
|
|
||||||
data() {
|
apollo: {
|
||||||
return {
|
topic() {
|
||||||
topic: {
|
return {
|
||||||
modules: {
|
query: TOPIC_QUERY,
|
||||||
edges: [],
|
variables: {
|
||||||
},
|
slug: this.$route.params.topicSlug,
|
||||||
|
},
|
||||||
|
update(data) {
|
||||||
|
return this.$getRidOfEdges(data).topic || {};
|
||||||
|
},
|
||||||
|
result() {
|
||||||
|
if (this.saveMe) {
|
||||||
|
this.saveMe = false;
|
||||||
|
this.updateLastVisitedTopic(this.topic.id);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
},
|
},
|
||||||
saveMe: false,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
computed: {
|
|
||||||
modules() {
|
|
||||||
return this.topic.modules;
|
|
||||||
},
|
},
|
||||||
},
|
|
||||||
|
|
||||||
mounted() {
|
data() {
|
||||||
if (!this.topic.id) {
|
return {
|
||||||
// component was loaded before topic, apollo not ready yet
|
topic: {
|
||||||
this.saveMe = true; // needs saving, apollo will do this
|
modules: {
|
||||||
} else {
|
edges: [],
|
||||||
this.updateLastVisitedTopic(this.topic.id);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
methods: {
|
|
||||||
openVideo() {
|
|
||||||
this.$store.dispatch('showFullscreenVideo', this.topic.vimeoId);
|
|
||||||
},
|
|
||||||
updateLastVisitedTopic(topicId) {
|
|
||||||
if (!topicId) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.$apollo.mutate({
|
|
||||||
mutation: UPDATE_LAST_TOPIC_MUTATION,
|
|
||||||
variables: {
|
|
||||||
input: {
|
|
||||||
id: topicId,
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
update(
|
saveMe: false,
|
||||||
store,
|
};
|
||||||
{
|
|
||||||
data: {
|
|
||||||
updateLastTopic: { topic },
|
|
||||||
},
|
|
||||||
}
|
|
||||||
) {
|
|
||||||
if (topic) {
|
|
||||||
const query = ME_QUERY;
|
|
||||||
const { me } = store.readQuery({ query });
|
|
||||||
if (me) {
|
|
||||||
const data = {
|
|
||||||
me: {
|
|
||||||
...me,
|
|
||||||
lastTopic: topic,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
store.writeQuery({ query, data });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
},
|
|
||||||
};
|
computed: {
|
||||||
|
modules() {
|
||||||
|
return this.topic.modules;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
mounted() {
|
||||||
|
if (!this.topic.id) { // component was loaded before topic, apollo not ready yet
|
||||||
|
this.saveMe = true; // needs saving, apollo will do this
|
||||||
|
} else {
|
||||||
|
this.updateLastVisitedTopic(this.topic.id);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
openVideo() {
|
||||||
|
this.$store.dispatch('showFullscreenVideo', this.topic.vimeoId);
|
||||||
|
},
|
||||||
|
updateLastVisitedTopic(topicId) {
|
||||||
|
if (!topicId) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.$apollo.mutate({
|
||||||
|
mutation: UPDATE_LAST_TOPIC_MUTATION,
|
||||||
|
variables: {
|
||||||
|
input: {
|
||||||
|
id: topicId,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
update(store, {data: {updateLastTopic: {topic}}}) {
|
||||||
|
if (topic) {
|
||||||
|
const query = ME_QUERY;
|
||||||
|
const {me} = store.readQuery({query});
|
||||||
|
if (me) {
|
||||||
|
const data = {
|
||||||
|
me: {
|
||||||
|
...me,
|
||||||
|
lastTopic: topic,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
store.writeQuery({query, data});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
@import '@/styles/_variables.scss';
|
@import "@/styles/_variables.scss";
|
||||||
@import '@/styles/_mixins.scss';
|
@import "@/styles/_mixins.scss";
|
||||||
|
|
||||||
.topic {
|
.topic {
|
||||||
display: grid;
|
display: grid;
|
||||||
padding: $large-spacing 0;
|
padding: $large-spacing 0;
|
||||||
grid-template-columns: 1fr;
|
grid-template-columns: 1fr;
|
||||||
@include desktop {
|
|
||||||
grid-template-columns: 300px 1fr;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__navigation {
|
|
||||||
padding: 0 $medium-spacing;
|
|
||||||
display: none;
|
|
||||||
@include desktop {
|
@include desktop {
|
||||||
display: block;
|
grid-template-columns: 300px 1fr;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__navigation {
|
||||||
|
padding: 0 $medium-spacing;
|
||||||
|
display: none;
|
||||||
|
@include desktop {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__teaser {
|
||||||
|
color: $color-charcoal-dark;
|
||||||
|
width: 90%;
|
||||||
|
@include lead-paragraph;
|
||||||
|
margin-bottom: $large-spacing;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__links {
|
||||||
|
margin-bottom: $large-spacing;
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__link {
|
||||||
|
cursor: pointer;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__video-link {
|
||||||
|
margin-right: $large-spacing;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__link-icon {
|
||||||
|
width: 40px;
|
||||||
|
height: 40px;
|
||||||
|
margin-right: $medium-spacing;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__link-description {
|
||||||
|
@include heading-3;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__modules {
|
||||||
|
margin-top: 40px;
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
@supports (display: grid) {
|
||||||
|
display: grid;
|
||||||
|
}
|
||||||
|
grid-column-gap: $large-spacing;
|
||||||
|
grid-row-gap: $large-spacing;
|
||||||
|
|
||||||
|
@include desktop {
|
||||||
|
grid-template-columns: repeat(3, minmax(auto, 380px));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&__teaser {
|
|
||||||
color: $color-charcoal-dark;
|
|
||||||
width: 90%;
|
|
||||||
@include lead-paragraph;
|
|
||||||
margin-bottom: $large-spacing;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__links {
|
|
||||||
margin-bottom: $large-spacing;
|
|
||||||
display: flex;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__link {
|
|
||||||
cursor: pointer;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__video-link {
|
|
||||||
margin-right: $large-spacing;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__link-icon {
|
|
||||||
width: 40px;
|
|
||||||
height: 40px;
|
|
||||||
margin-right: $medium-spacing;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__link-description {
|
|
||||||
@include heading-3;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__modules {
|
|
||||||
margin-top: 40px;
|
|
||||||
display: flex;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
@supports (display: grid) {
|
|
||||||
display: grid;
|
|
||||||
}
|
|
||||||
grid-column-gap: $large-spacing;
|
|
||||||
grid-row-gap: $large-spacing;
|
|
||||||
|
|
||||||
@include desktop {
|
|
||||||
grid-template-columns: repeat(3, minmax(auto, 380px));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -1,51 +1,51 @@
|
||||||
// adapted from
|
// adapted from
|
||||||
// https://stackoverflow.com/questions/41791193/vuejs-reactive-binding-for-a-plugin-how-to/41801107#41801107
|
// https://stackoverflow.com/questions/41791193/vuejs-reactive-binding-for-a-plugin-how-to/41801107#41801107
|
||||||
import Vue, { VueConstructor } from 'vue';
|
import {reactive, App} from 'vue';
|
||||||
|
|
||||||
class ModalStore {
|
class ModalStore {
|
||||||
vm: Vue;
|
data: any;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
this.vm = new Vue({
|
this.data = reactive({
|
||||||
data: () => ({
|
component: '',
|
||||||
component: '',
|
payload: {}
|
||||||
payload: {},
|
|
||||||
}),
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
get state() {
|
get state() {
|
||||||
return this.vm.$data;
|
return this.data;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Modal {
|
interface Modal {
|
||||||
state: any;
|
state: any,
|
||||||
component: string;
|
component: string,
|
||||||
payload?: any;
|
payload?: any,
|
||||||
confirm: (res: any) => void;
|
confirm: (res: any) => void,
|
||||||
open: (component: string, payload?: any) => Promise<(resolve: () => any, reject: () => any) => void>;
|
open: (component: string, payload?: any) => Promise<(resolve: () => any, reject: () => any) => void>,
|
||||||
cancel: () => void;
|
cancel: () => void,
|
||||||
_resolve: (r?: any) => any;
|
_resolve: (r?: any) => any,
|
||||||
_reject: (r?: any) => any;
|
_reject: (r?: any) => any
|
||||||
}
|
}
|
||||||
|
|
||||||
declare module 'vue/types/vue' {
|
declare module '@vue/runtime-core' {
|
||||||
interface Vue {
|
interface ComponentCustomProperties {
|
||||||
$modal: Modal;
|
$modal: Modal
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const ModalPlugin = {
|
const ModalPlugin = {
|
||||||
install(Vue: VueConstructor) {
|
install(app: App) {
|
||||||
const store = new ModalStore();
|
const store = new ModalStore();
|
||||||
|
console.log('installing modal plugin');
|
||||||
|
|
||||||
|
|
||||||
const reset = () => {
|
const reset = () => {
|
||||||
store.state.component = '';
|
store.state.component = '';
|
||||||
store.state.payload = {};
|
store.state.payload = {};
|
||||||
};
|
};
|
||||||
|
|
||||||
const modal: Modal = {
|
app.config.globalProperties.$modal = {
|
||||||
state: store.state,
|
state: store.state,
|
||||||
component: store.state.component,
|
component: store.state.component,
|
||||||
payload: store.state.payload,
|
payload: store.state.payload,
|
||||||
|
|
@ -65,12 +65,13 @@ const ModalPlugin = {
|
||||||
reset();
|
reset();
|
||||||
this._reject();
|
this._reject();
|
||||||
},
|
},
|
||||||
_resolve: () => {},
|
_resolve: () => {
|
||||||
_reject: () => {},
|
},
|
||||||
|
_reject: () => {
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
Vue.prototype.$modal = modal;
|
}
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default ModalPlugin;
|
export default ModalPlugin;
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,13 @@
|
||||||
// from https://stackoverflow.com/questions/64213461/vuejs-typescript-cannot-find-module-components-navigation-or-its-correspon
|
// from https://stackoverflow.com/questions/64213461/vuejs-typescript-cannot-find-module-components-navigation-or-its-correspon
|
||||||
declare module '*.vue' {
|
// declare module "*.vue" {
|
||||||
import Vue from 'vue';
|
// import Vue from 'vue';
|
||||||
export default Vue;
|
// export default Vue;
|
||||||
}
|
// }
|
||||||
|
|
||||||
// for Vue 3
|
// for Vue 3
|
||||||
// declare module '*.vue' {
|
declare module '*.vue' {
|
||||||
// import type { DefineComponent } from 'vue'
|
import type { DefineComponent } from 'vue';
|
||||||
// const component: DefineComponent<{}, {}, any>
|
const component: DefineComponent<{}, {}, any>;
|
||||||
// export default component
|
export default component;
|
||||||
// }
|
}
|
||||||
//
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue