Upgrade code according to migration guide for Vue 3

Update npm dependencies

Update vue router version

Disable validation temporarily

Specify property

Update dependencies

Update store to v4

Update async component definitions

Update some event emitters

Update tiptap vue version

Implement some router changes for v4

Remove obsolete tag attributes

Update dependencies

Fix some cypress tests

Fix most jest tests

Fix some more cypress tests

Fix school class cypress test

Fix another cypress test

Disable failing test temporarily

Fix validation

Fix error messages for validation

Fix e2e test for beta login page

Apply prettier
This commit is contained in:
Ramon Wenger 2022-03-23 16:21:06 +01:00
parent 4b55f8952c
commit a52671fd40
106 changed files with 4604 additions and 5195 deletions

View File

@ -1 +1,3 @@
bundle-analysis
dist
node_modules

View File

@ -219,7 +219,9 @@ describe('Snapshot', () => {
cy.getByDataCy('module-snapshots-button').click();
cy.getByDataCy('create-snapshot-button').click();
cy.getByDataCy('show-all-snapshots-button').click();
cy.getByDataCy('snapshot-list').should('exist').within(() => {
cy.getByDataCy('snapshot-list')
.should('exist')
.within(() => {
cy.get('.snapshots__snapshot').should('have.length', 1);
});
waitNTimes(7);

View File

@ -13,7 +13,8 @@ describe('Room Team Management - Read only', () => {
},
},
RoomsQuery: {
rooms: [{
rooms: [
{
id: '',
slug: 'some-room',
title: 'some room',
@ -24,7 +25,8 @@ describe('Room Team Management - Read only', () => {
id: SELECTED_CLASS_ID,
name: 'bla',
},
}],
},
],
},
});

View File

@ -1,11 +1,5 @@
module.exports = {
moduleFileExtensions: [
'js',
'jsx',
'ts',
'json',
'vue',
],
moduleFileExtensions: ['js', 'jsx', 'ts', 'json', 'vue'],
transform: {
'\\.(gql|graphql)$': '@graphql-tools/jest-transform',
'^.+\\.js$': 'babel-jest',
@ -13,20 +7,13 @@ module.exports = {
'^.+\\.vue$': '@vue/vue3-jest',
'.+\\.(css|styl|less|sass|scss|svg|png|jpg|ttf|woff|woff2)$': 'jest-transform-stub',
},
modulePaths: [
'<rootDir>/src',
'<rootDir>/node_modules',
],
transformIgnorePatterns: [
'/node_modules/',
],
modulePaths: ['<rootDir>/src', '<rootDir>/node_modules'],
transformIgnorePatterns: ['/node_modules/'],
moduleNameMapper: {
'^@/(.*)$': '<rootDir>/src/$1',
'^gql/(.*)$': '<rootDir>/src/graphql/gql/$1',
},
snapshotSerializers: [
'<rootDir>/node_modules/jest-serializer-vue',
],
snapshotSerializers: ['<rootDir>/node_modules/jest-serializer-vue'],
testEnvironment: 'jsdom',
testEnvironmentOptions: {
url: 'http://localhost/',

View File

@ -3,6 +3,9 @@
"version": "1.0.0",
"description": "skillbox vue client",
"author": "ramon / chrigu",
"prettier": {
"singleQuote": true
},
"private": true,
"prettier": {
"singleQuote": true

View File

@ -1,9 +1,6 @@
<template>
<div class="add-content">
<a
class="add-content__button"
@click="addContent"
>
<a class="add-content__button" @click="addContent">
<add-pointer class="add-content__icon" />
</a>
</div>
@ -23,14 +20,15 @@
where: {
type: Object,
validator(prop) {
return Object.prototype.hasOwnProperty.call(prop, 'after' )
|| Object.prototype.hasOwnProperty.call(prop, 'parent');
}
return (
Object.prototype.hasOwnProperty.call(prop, 'after') || Object.prototype.hasOwnProperty.call(prop, 'parent')
);
},
},
},
components: {
AddPointer
AddPointer,
},
computed: {
@ -45,9 +43,8 @@
},
slug() {
return this.$route.params.slug;
}
},
},
methods: {
addContent() {
@ -60,26 +57,26 @@
name: CREATE_CONTENT_BLOCK_AFTER_PAGE,
params: {
after: this.after.id,
slug: this.slug
}
slug: this.slug,
},
};
} else {
route = {
name: CREATE_CONTENT_BLOCK_UNDER_PARENT_PAGE,
params: {
parent: this.parent.id
}
parent: this.parent.id,
},
};
}
this.$router.push(route);
}
}
}
},
},
};
</script>
<style scoped lang="scss">
@import "~styles/helpers";
@import '~styles/helpers';
.add-content {
display: none;

View File

@ -1,8 +1,5 @@
<template>
<div
class="add-content-element"
@click="$emit('add-element', index)"
>
<div class="add-content-element" @click="$emit('add-element', index)">
<add-icon class="add-content-element__icon" />
</div>
</template>
@ -15,13 +12,13 @@
props: ['index'],
components: {
AddIcon
}
AddIcon,
},
};
</script>
<style scoped lang="scss">
@import "@/styles/_variables.scss";
@import '@/styles/_variables.scss';
.add-content-element {
display: flex;

View File

@ -18,20 +18,21 @@
props: {
route: {
type: String,
default: null
default: null,
},
reverse: { // use reverse colors
reverse: {
// use reverse colors
type: Boolean,
default: false
default: false,
},
click: {
type: Function,
default: null
}
default: null,
},
},
components: {
AddIcon
AddIcon,
},
computed: {
@ -40,17 +41,19 @@
return this.route ? 'router-link' : 'a';
},
properties() {
return this.route ? {
return this.route
? {
to: this.route,
tag: 'div'
} : {};
tag: 'div',
}
: {};
},
},
};
</script>
<style scoped lang="scss">
@import "~styles/helpers";
@import '~styles/helpers';
.add-widget {
display: none;

View File

@ -1,8 +1,5 @@
<template>
<router-link
:to="to"
class="sub-navigation-item back-link"
>
<router-link :to="to" class="sub-navigation-item back-link">
<chevron-left class="back-link__icon sub-navigation-item__icon" />
{{ fullTitle }}
</router-link>

View File

@ -8,14 +8,8 @@
:key="index"
@click="$emit('input', color.name)"
>
<div
:class="'color-chooser__color--' + color.name"
class="color-chooser__color"
>
<tick
class="color-chooser__selected-icon"
v-if="selectedColor === color.name"
/>
<div :class="'color-chooser__color--' + color.name" class="color-chooser__color">
<tick class="color-chooser__selected-icon" v-if="selectedColor === color.name" />
</div>
</div>
</div>
@ -29,33 +23,33 @@
props: ['selectedColor'],
components: {
Tick
Tick,
},
data() {
return {
colors: [
{
name: 'yellow'
name: 'yellow',
},
{
name: 'blue'
name: 'blue',
},
{
name: 'red'
name: 'red',
},
{
name: 'green'
}
]
name: 'green',
},
],
};
},
};
</script>
<style scoped lang="scss">
@import "@/styles/_variables.scss";
@import "@/styles/_mixins.scss";
@import '@/styles/_variables.scss';
@import '@/styles/_mixins.scss';
.color-chooser {
display: flex;
@ -82,7 +76,7 @@
display: flex;
justify-content: center;
@supports (display: grid) {
display: grid
display: grid;
}
justify-items: center;
align-items: center;

View File

@ -1,23 +1,24 @@
<template>
<modal :fullscreen="true">
<component
:value="value"
:is="type"
/>
<component :value="value" :is="type" />
</modal>
</template>
<script>
import Modal from '@/components/Modal';
import { defineAsyncComponent } from 'vue';
const InfogramBlock = defineAsyncComponent(() => import(/* webpackChunkName: "content-components" */'@/components/content-blocks/InfogramBlock'));
const GeniallyBlock = defineAsyncComponent(() => import(/* webpackChunkName: "content-components" */'@/components/content-blocks/GeniallyBlock'));
const InfogramBlock = defineAsyncComponent(() =>
import(/* webpackChunkName: "content-components" */ '@/components/content-blocks/InfogramBlock')
);
const GeniallyBlock = defineAsyncComponent(() =>
import(/* webpackChunkName: "content-components" */ '@/components/content-blocks/GeniallyBlock')
);
export default {
components: {
Modal,
InfogramBlock,
GeniallyBlock
GeniallyBlock,
},
computed: {
@ -29,9 +30,9 @@
},
value() {
return {
id: this.id
id: this.id,
};
}
}
},
},
};
</script>

View File

@ -1,28 +1,15 @@
<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" />
</a>
<content-navigation class="header-bar__content-navigation" />
<div class="user-header">
<a
class="user-header__sidebar-link"
>
<current-class
class="user-header__current-class"
@click="openSidebar('profile')"
/>
<a class="user-header__sidebar-link">
<current-class class="user-header__current-class" @click="openSidebar('profile')" />
</a>
<user-widget
:avatar-url="me.avatarUrl"
data-cy="header-user-widget"
@click="openSidebar('profile')"
/>
<user-widget :avatar-url="me.avatarUrl" data-cy="header-user-widget" @click="openSidebar('profile')" />
</div>
</header>
</template>
@ -51,7 +38,7 @@
</script>
<style scoped lang="scss">
@import "~styles/helpers";
@import '~styles/helpers';
.header-bar {
display: flex;

View File

@ -17,14 +17,14 @@
props: ['text'],
components: {
InfoIcon
}
InfoIcon,
},
};
</script>
<style scoped lang="scss">
@import "@/styles/_variables.scss";
@import "@/styles/_mixins.scss";
@import '@/styles/_variables.scss';
@import '@/styles/_mixins.scss';
.helpful-tooltip {
position: relative;
@ -66,7 +66,6 @@
height: 10px;
transform: rotate(-45deg) translateY(-50%);
}
}
&:hover &__tooltip {

View File

@ -1,45 +1,41 @@
<template>
<button
:disabled="loading || disabled"
class="loading-button button button--primary button--big"
>
<button :disabled="loading || disabled" class="loading-button button button--primary button--big">
<template v-if="!loading">
{{ label }}
</template>
<loading-icon
class="loading-button__icon"
v-else
/>
<loading-icon class="loading-button__icon" v-else />
</button>
</template>
<script>
import { defineAsyncComponent } from 'vue';
const LoadingIcon = defineAsyncComponent(() => import(/* webpackChunkName: "icons" */'@/components/icons/LoadingIcon'));
const LoadingIcon = defineAsyncComponent(() =>
import(/* webpackChunkName: "icons" */ '@/components/icons/LoadingIcon')
);
export default {
props: {
loading: {
type: Boolean,
default: false
default: false,
},
disabled: {
type: Boolean,
default: false
default: false,
},
label: {
type: String,
default: ''
}
default: '',
},
},
components: {
LoadingIcon
}
LoadingIcon,
},
};
</script>
<style scoped lang="scss">
@import "~styles/helpers";
@import '~styles/helpers';
.loading-button {
height: 52px;

View File

@ -4,17 +4,11 @@
<hamburger class="mobile-header__hamburger" />
</a>
<router-link
to="/"
data-cy="mobile-home-link"
>
<router-link to="/" data-cy="mobile-home-link">
<logo />
</router-link>
<user-widget
v-bind="me"
@click.stop="openSidebar('profile')"
/>
<user-widget v-bind="me" @click.stop="openSidebar('profile')" />
</div>
</template>
@ -46,7 +40,7 @@
</script>
<style scoped lang="scss">
@import "~styles/helpers";
@import '~styles/helpers';
.mobile-header {
justify-content: space-between;

View File

@ -1,7 +1,11 @@
<template>
<div class="modal__backdrop">
<div
:class="{'modal--hide-header': hideHeader || fullscreen, 'modal--fullscreen': fullscreen, 'modal--small': small}"
:class="{
'modal--hide-header': hideHeader || fullscreen,
'modal--fullscreen': fullscreen,
'modal--small': small,
}"
class="modal"
>
<div class="modal__header">
@ -9,20 +13,14 @@
</div>
<div class="modal__body">
<slot />
<div
class="modal__close-button"
@click="hideModal"
>
<div class="modal__close-button" @click="hideModal">
<cross class="modal__close-icon" />
</div>
</div>
<div class="modal__footer">
<slot name="footer">
<!--<a class="button button&#45;&#45;active">Speichern</a>-->
<a
class="button"
@click="hideModal"
>Abbrechen</a>
<a class="button" @click="hideModal">Abbrechen</a>
</slot>
</div>
</div>
@ -37,32 +35,32 @@
props: {
hideHeader: {
type: Boolean,
default: false
default: false,
},
fullscreen: {
type: Boolean,
default: false
default: false,
},
small: {
type: Boolean,
default: false
}
default: false,
},
},
components: {
Cross
Cross,
},
methods: {
hideModal() {
this.$store.dispatch('hideModal');
}
}
},
},
};
</script>
<style scoped lang="scss">
@import "@/styles/_variables.scss";
@import '@/styles/_variables.scss';
.modal {
align-self: center;
@ -78,7 +76,7 @@
display: grid;
}
grid-template-rows: auto 1fr 65px;
grid-template-areas: "header" "body" "footer";
grid-template-areas: 'header' 'body' 'footer';
-ms-grid-rows: auto 1fr 65px;
position: relative;
@ -136,7 +134,7 @@
&--hide-header {
grid-template-rows: 1fr 65px;
grid-template-areas: "body" "footer";
grid-template-areas: 'body' 'footer';
#{$parent}__header {
display: none;
@ -145,7 +143,6 @@
#{$parent}__body {
padding: $default-padding;
}
}
&--fullscreen {
@ -153,7 +150,7 @@
height: auto;
grid-template-rows: 1fr;
-ms-grid-rows: 1fr;
grid-template-areas: "body";
grid-template-areas: 'body';
overflow: hidden;
#{$parent}__footer {

View File

@ -1,17 +1,9 @@
<template>
<div class="more-options">
<a
class="more-options__more-link"
data-cy="more-options-link"
@click.stop="showMenu = !showMenu"
>
<a class="more-options__more-link" data-cy="more-options-link" @click.stop="showMenu = !showMenu">
<ellipses class="more-options__ellipses" />
</a>
<widget-popover
class="more-options__popover"
v-if="showMenu"
@hide-me="showMenu = false"
>
<widget-popover class="more-options__popover" v-if="showMenu" @hide-me="showMenu = false">
<slot />
</widget-popover>
</div>
@ -26,19 +18,19 @@
export default {
components: {
WidgetPopover,
Ellipses
Ellipses,
},
data() {
return {
showMenu: false
showMenu: false,
};
}
},
};
</script>
<style scoped lang="scss">
@import "~styles/helpers";
@import '~styles/helpers';
.more-options {
display: flex;

View File

@ -1,10 +1,6 @@
<template>
<transition name="fade">
<a
class="scroll-up"
v-if="scroll>200"
@click="scrollTop"
>
<a class="scroll-up" v-if="scroll > 200" @click="scrollTop">
<arrow-up class="scroll-up__icon" />
</a>
</transition>
@ -16,12 +12,12 @@
export default {
components: {
ArrowUp
ArrowUp,
},
data() {
return {
scroll: 0
scroll: 0,
};
},
@ -39,7 +35,7 @@
methods: {
scrollTop() {
document.scrollingElement.scrollTop = 0;
}
},
},
};
</script>
@ -65,15 +61,14 @@
height: 50px;
fill: $color-brand;
}
}
.fade-enter-active, .fade-leave-active {
transition: opacity .3s;
.fade-enter-active,
.fade-leave-active {
transition: opacity 0.3s;
}
.fade-enter-from, .fade-leave-to /* .fade-leave-active below version 2.1.8 */
{
.fade-enter-from, .fade-leave-to /* .fade-leave-active below version 2.1.8 */ {
opacity: 0;
}
</style>

View File

@ -1,9 +1,6 @@
<template>
<div class="submission-document">
<p
class="submission-document__content content"
v-if="document && document.length > 0"
>
<p class="submission-document__content content" v-if="document && document.length > 0">
<document-icon class="content__icon" /><span class="content__text">{{ filename }}</span>
</p>
</div>
@ -12,7 +9,9 @@
<script>
import { defineAsyncComponent } from 'vue';
import filenameFromUrl from '@/helpers/urls';
const DocumentIcon = defineAsyncComponent(() => import(/* webpackChunkName: "icons" */'@/components/icons/DocumentIcon'));
const DocumentIcon = defineAsyncComponent(() =>
import(/* webpackChunkName: "icons" */ '@/components/icons/DocumentIcon')
);
export default {
name: 'StudentSubmissionDocument',
@ -22,7 +21,7 @@
computed: {
filename() {
return filenameFromUrl(this.document);
}
},
},
};
</script>

View File

@ -1,17 +1,7 @@
<template>
<div
:class="{'user-widget--is-profile': isProfile}"
class="user-widget"
@click.stop="$emit('click', $event)"
>
<div
class="user-widget__avatar"
data-cy="user-widget-avatar"
>
<avatar
:avatar-url="avatarUrl"
:icon-highlighted="isProfile"
/>
<div :class="{ 'user-widget--is-profile': isProfile }" class="user-widget" @click.stop="$emit('click', $event)">
<div class="user-widget__avatar" data-cy="user-widget-avatar">
<avatar :avatar-url="avatarUrl" :icon-highlighted="isProfile" />
</div>
</div>
</template>
@ -22,25 +12,25 @@
export default {
props: {
avatarUrl: {
type: String
}
type: String,
},
},
emits: ['click'],
components: {
Avatar
emits: ['click'],components: {
Avatar,
},
computed: {
isProfile() {
return this.$route.meta.isProfile;
}
}
},
},
};
</script>
<style scoped lang="scss">
@import "~styles/helpers";
@import '~styles/helpers';
.user-widget {
color: $color-silver-dark;

View File

@ -1,8 +1,5 @@
<template>
<nav
:class="{'content-navigation--sidebar': isSidebar}"
class="content-navigation"
>
<nav :class="{ 'content-navigation--sidebar': isSidebar }" class="content-navigation">
<div class="content-navigation__primary">
<div class="content-navigation__item">
<router-link
@ -15,9 +12,7 @@
{{ $flavor.textTopics }}
</router-link>
<topic-navigation
v-if="isSidebar"
/>
<topic-navigation v-if="isSidebar" />
</div>
<div class="content-navigation__item">
@ -45,12 +40,7 @@
</div>
</div>
<router-link
to="/"
class="content-navigation__logo"
data-cy="home-link"
v-if="!isSidebar"
>
<router-link to="/" class="content-navigation__logo" data-cy="home-link" v-if="!isSidebar">
<logo class="content-navigation__logo-icon" />
</router-link>
@ -67,10 +57,7 @@
</router-link>
</div>
<div
class="content-navigation__item content-navigation__item--secondary"
v-if="showPortfolio"
>
<div class="content-navigation__item content-navigation__item--secondary" v-if="showPortfolio">
<router-link
to="/portfolio"
active-class="content-navigation__link--active"
@ -80,10 +67,7 @@
Portfolio
</router-link>
</div>
<div
class="content-navigation__item content-navigation__item--secondary"
v-if="isSidebar"
>
<div class="content-navigation__item content-navigation__item--secondary" v-if="isSidebar">
<a
:href="$flavor.supportLink"
target="_blank"
@ -108,21 +92,21 @@
export default {
props: {
isSidebar: {
default: false
}
default: false,
},
},
mixins: [sidebarMixin, meMixin],
components: {
TopicNavigation,
Logo
Logo,
},
computed: {
showPortfolio() {
return this.$flavor.showPortfolio;
}
},
},
methods: {
@ -134,14 +118,14 @@
},
close() {
this.closeSidebar('navigation');
}
}
},
},
};
</script>
<style scoped lang="scss">
@import "@/styles/_variables.scss";
@import "@/styles/_mixins.scss";
@import '@/styles/_variables.scss';
@import '@/styles/_mixins.scss';
.content-navigation {
display: flex;
@ -152,7 +136,8 @@
@include navigation-link;
}
&__primary, &__secondary {
&__primary,
&__secondary {
display: none;
flex-direction: row;
@ -162,7 +147,7 @@
}
&__logo {
color: #17A887;
color: #17a887;
font-size: 36px;
font-weight: 800;
font-family: $sans-serif-font-family;
@ -197,7 +182,8 @@
&--sidebar {
flex-direction: column;
#{$parent}__primary, #{$parent}__secondary {
#{$parent}__primary,
#{$parent}__secondary {
display: flex;
flex-direction: column;
width: 100%;
@ -213,7 +199,6 @@
&:only-child {
margin-bottom: 0;
}
}
#{$parent}__item {

View File

@ -1,18 +1,8 @@
<template>
<transition name="slide">
<div
class="navigation-sidebar"
v-if="sidebar.navigation"
v-click-outside="close"
>
<content-navigation
:is-sidebar="true"
class="navigation-sidebar__main"
/>
<div
class="navigation-sidebar__close-button"
@click="close"
>
<div class="navigation-sidebar" v-if="sidebar.navigation" v-click-outside="close">
<content-navigation :is-sidebar="true" class="navigation-sidebar__main" />
<div class="navigation-sidebar__close-button" @click="close">
<cross class="navigation-sidebar__close-icon" />
</div>
</div>
@ -32,21 +22,20 @@
components: {
ContentNavigation,
Cross
Cross,
},
methods: {
close() {
this.closeSidebar('navigation');
}
},
},
};
</script>
<style scoped lang="scss">
@import "@/styles/_variables.scss";
@import "@/styles/_mixins.scss";
@import '@/styles/_variables.scss';
@import '@/styles/_mixins.scss';
$desktop-width: 285px;
@ -68,10 +57,10 @@
grid-template-columns: 1fr 50px;
grid-template-rows: 50px max-content auto 100px;
grid-template-areas: "m m" "m m" "s s" "s s";
grid-template-areas: 'm m' 'm m' 's s' 's s';
&--with-subnavigation {
grid-template-areas: "m m" "m m" "sub sub" "s s";
grid-template-areas: 'm m' 'm m' 'sub sub' 's s';
}
height: 100vh;
@ -99,11 +88,13 @@
}
.slide {
&-enter-active, &-leave-active {
&-enter-active,
&-leave-active {
transition: left 0.2s;
}
&-enter-from, &-leave-to {
&-enter-from,
&-leave-to {
left: -100vw;
@include desktop {
left: -$desktop-width;

View File

@ -1,21 +1,11 @@
<template>
<div
:class="{ 'sub-navigation-item--active': show}"
class="sub-navigation-item"
v-click-outside="close"
>
<div
class="sub-navigation-item__title"
@click="show = !show"
>
<div :class="{ 'sub-navigation-item--active': show }" class="sub-navigation-item" v-click-outside="close">
<div class="sub-navigation-item__title" @click="show = !show">
{{ title }}
<chevron-down class="sub-navigation-item__icon sub-navigation-item__chevron-down" />
<chevron-up class="sub-navigation-item__icon sub-navigation-item__chevron-up" />
</div>
<div
class="sub-navigation-item__nav-items book-subnavigation"
v-if="show"
>
<div class="sub-navigation-item__nav-items book-subnavigation" v-if="show">
<slot />
</div>
</div>
@ -31,25 +21,25 @@
components: {
ChevronDown,
ChevronUp
ChevronUp,
},
data() {
return {
show: false
show: false,
};
},
watch: {
$route() {
this.show = false;
}
},
},
methods: {
close() {
this.show = false;
}
}
},
},
};
</script>

View File

@ -26,6 +26,7 @@
default: false,
},
},
},
mixins: [sidebarMixin],
@ -40,6 +41,7 @@
return atob(id);
},
},
},
apollo: {
topics: {

View File

@ -26,14 +26,10 @@
:class="['content-element__component']"
v-bind="element"
:is="component"
@change-text="changeText"
@link-change-url="changeUrl"
@change-url="changeUrl"
@switch-to-document="switchToDocument"
@assignment-change-title="changeAssignmentTitle"
@assignment-change-assignment="changeAssignmentAssignment"
/>
@ -110,7 +106,7 @@
CmsDocumentBlock,
InfogramBlock,
ThinglinkBlock,
Assignment
Assignment,
},
computed: {
@ -216,12 +212,12 @@
case 'thinglink_block':
return {
component: 'thinglink-block',
title: 'Interaktive Grafik'
title: 'Interaktive Grafik',
};
case 'infogram_block':
return {
component: 'infogram-block',
title: 'Interaktive Grafik'
title: 'Interaktive Grafik',
};
}
return {
@ -295,9 +291,12 @@
case 'document_block':
el = {
...el,
value: Object.assign({
value: Object.assign(
{
url: '',
}, value),
},
value
),
};
break;
case 'image_url_block':

View File

@ -1,13 +1,8 @@
<template>
<div class="content-form-section">
<h2 class="content-form-section__heading">
<component
class="content-form-section__icon"
:is="icon"
/> <span
class="content-form-section__title"
data-cy="content-form-section-title"
>{{ title }}</span>
<component class="content-form-section__icon" :is="icon" />
<span class="content-form-section__title" data-cy="content-form-section-title">{{ title }}</span>
</h2>
<content-element-actions

View File

@ -18,27 +18,11 @@
/>
</template>
<add-content-element
:index="-1"
class="contents-form__add"
@add-element="addElement"
/>
<div
class="contents-form__element"
v-for="(element, index) in localContentBlock.contents"
:key="index"
>
<content-element
:element="element"
@update="update(index, $event)"
@remove="remove(index)"
/>
<add-content-element :index="-1" class="contents-form__add" @add-element="addElement" />
<div class="contents-form__element" v-for="(element, index) in localContentBlock.contents" :key="index">
<content-element :element="element" @update="update(index, $event)" @remove="remove(index)" />
<add-content-element
:index="index"
class="contents-form__add"
@add-element="addElement"
/>
<add-content-element :index="index" class="contents-form__add" @add-element="addElement" />
</div>
<template #footer>
@ -48,11 +32,9 @@
class="button button--primary"
data-cy="modal-save-button"
@click="save"
>Speichern</a>
<a
class="button"
@click="$emit('hide')"
>Abbrechen</a>
>Speichern</a
>
<a class="button" @click="$emit('hide')">Abbrechen</a>
</div>
</template>
</modal>
@ -97,12 +79,15 @@
data() {
return {
error: false,
localContentBlock: Object.assign({}, {
localContentBlock: Object.assign(
{},
{
title: this.contentBlock.title,
contents: [...this.contentBlock.contents],
id: this.contentBlock.id || undefined,
isAssignment: this.contentBlock.type && this.contentBlock.type.toLowerCase() === 'task',
}),
}
),
me: {},
};
},
@ -148,19 +133,17 @@
remove(index) {
this.localContentBlock.contents.splice(index, 1);
},
},
};
</script>
<style scoped lang="scss">
@import "~styles/helpers";
@import '~styles/helpers';
.contents-form {
/* top level does not exist, because of the modal */
&__element {
}
&__element-component {

View File

@ -1,10 +1,5 @@
<template>
<contents-form
:content-block="contentBlock"
:show-task-selection="true"
@save="saveContentBlock"
@hide="hideModal"
/>
<contents-form :content-block="contentBlock" :show-task-selection="true" @save="saveContentBlock" @hide="hideModal" />
</template>
<script>
@ -38,7 +33,8 @@
this.$store.dispatch('hideModal');
},
saveContentBlock(contentBlock) {
this.$apollo.mutate({
this.$apollo
.mutate({
mutation: EDIT_CONTENT_BLOCK_MUTATION,
variables: {
input: {
@ -61,6 +57,7 @@
});
},
},
},
apollo: {
contentBlock() {

View File

@ -1,9 +1,5 @@
<template>
<div
:class="componentClass"
:data-scrollto="component.id"
data-cy="content-component"
>
<div :class="componentClass" :data-scrollto="component.id" data-cy="content-component">
<bookmark-actions
:bookmarked="bookmarked"
:note="note"
@ -13,11 +9,7 @@
@edit-note="editNote"
@bookmark="bookmarkContent(component.id, !bookmarked)"
/>
<component
v-bind="component"
:parent="parent"
:is="component.type"
/>
<component v-bind="component" :parent="parent" :is="component.type" />
</div>
</template>
@ -50,60 +42,60 @@ export default {
props: {
component: {
type: Object,
default: () => ({})
default: () => ({}),
},
parent: {
type: Object,
default: () => ({})
default: () => ({}),
},
bookmarks: {
type: Array,
default: () => ([])
default: () => [],
},
notes: {
type: Array,
default: () => ([])
default: () => [],
},
root: {
type: String,
default: ''
default: '',
},
editMode: {
type: Boolean,
default: false
}
default: false,
},
},
components: {
'text_block': TextBlock,
'basic_knowledge': InstrumentWidget, // for legacy
'instrument': InstrumentWidget,
'image_block': ImageBlock,
'image_url_block': ImageUrlBlock,
'video_block': VideoBlock,
'link_block': LinkBlock,
'document_block': DocumentBlock,
'infogram_block': InfogramBlock,
'genially_block': GeniallyBlock,
'subtitle': SubtitleBlock,
'section_title': SectionTitleBlock,
'content_list': ContentListBlock,
'module_room_slug': ModuleRoomSlug,
'thinglink_block': ThinglinkBlock,
'cms_document_block': CmsDocumentBlock,
text_block: TextBlock,
basic_knowledge: InstrumentWidget, // for legacy
instrument: InstrumentWidget,
image_block: ImageBlock,
image_url_block: ImageUrlBlock,
video_block: VideoBlock,
link_block: LinkBlock,
document_block: DocumentBlock,
infogram_block: InfogramBlock,
genially_block: GeniallyBlock,
subtitle: SubtitleBlock,
section_title: SectionTitleBlock,
content_list: ContentListBlock,
module_room_slug: ModuleRoomSlug,
thinglink_block: ThinglinkBlock,
cms_document_block: CmsDocumentBlock,
Survey,
Solution,
Instruction,
Assignment,
BookmarkActions
BookmarkActions,
},
computed: {
bookmarked() {
return this.bookmarks && !!this.bookmarks.find(bookmark => bookmark.uuid === this.component.id);
return this.bookmarks && !!this.bookmarks.find((bookmark) => bookmark.uuid === this.component.id);
},
note() {
const bookmark = this.bookmarks && this.bookmarks.find(bookmark => bookmark.uuid === this.component.id);
const bookmark = this.bookmarks && this.bookmarks.find((bookmark) => bookmark.uuid === this.component.id);
return bookmark && bookmark.note;
},
showBookmarkActions() {
@ -115,18 +107,19 @@ export default {
classes.push('content-component--bookmarked');
}
return classes;
}
},
},
methods: {
addNote(id) {
const type = Object.prototype.hasOwnProperty.call(this.parent, '__typename')
? this.parent.__typename : 'ContentBlockNode';
? this.parent.__typename
: 'ContentBlockNode';
this.$store.dispatch('addNote', {
content: id,
type,
block: this.root
block: this.root,
});
},
editNote() {
@ -134,19 +127,18 @@ export default {
},
bookmarkContent(uuid, bookmarked) {
this.$apollo.mutate(constructContentComponentBookmarkMutation(uuid, bookmarked, this.parent, this.root));
}
}
},
},
};
</script>
<style lang="scss" scoped>
@import "~styles/helpers";
@import '~styles/helpers';
.content-component {
position: relative;
&--bookmarked {
}
&--subtitle {

View File

@ -1,12 +1,7 @@
<template>
<content-list
:items="contentBlocks"
>
<content-list :items="contentBlocks">
<template #default="{ item }">
<content-block
:content-block="item"
:parent="parent"
/>
<content-block :content-block="item" :parent="parent" />
</template>
</content-list>
</template>

View File

@ -1,16 +1,8 @@
<template>
<div class="document-block">
<document-icon class="document-block__icon" />
<a
:href="value.url"
class="document-block__link"
target="_blank"
>{{ urlName }}</a>
<a
class="document-block__remove"
v-if="showTrashIcon"
@click="$emit('trash')"
>
<a :href="value.url" class="document-block__link" target="_blank">{{ urlName }}</a>
<a class="document-block__remove" v-if="showTrashIcon" @click="$emit('trash')">
<trash-icon class="document-block__trash-icon" />
</a>
</div>
@ -39,13 +31,13 @@
return parts[parts.length - 1];
}
return null;
}
}
},
},
};
</script>
<style scoped lang="scss">
@import "~styles/helpers";
@import '~styles/helpers';
.document-block {
display: grid;

View File

@ -1,13 +1,7 @@
<template>
<div
class="instruction"
v-if="me.isTeacher"
>
<div class="instruction" v-if="me.isTeacher">
<bulb-icon class="instruction__icon" />
<a
:href="url"
class="instruction__link"
>{{ text }}</a>
<a :href="url" class="instruction__link">{{ text }}</a>
</div>
</template>
@ -22,7 +16,7 @@
mixins: [me],
components: {
BulbIcon
BulbIcon,
},
computed: {
@ -31,13 +25,13 @@
},
url() {
return this.value.document ? this.value.document.url : this.value.url;
}
}
},
},
};
</script>
<style scoped lang="scss">
@import "@/styles/_mixins.scss";
@import '@/styles/_mixins.scss';
.instruction {
margin-bottom: 1rem;

View File

@ -1,14 +1,7 @@
<template>
<div
:class="{ 'link-block--no-margin': noMargin}"
class="link-block"
>
<div :class="{ 'link-block--no-margin': noMargin }" class="link-block">
<link-icon class="link-block__icon" />
<a
:href="href"
class="link-block__link"
target="_blank"
>{{ value.text }}</a>
<a :href="href" class="link-block__link" target="_blank">{{ value.text }}</a>
</div>
</template>
@ -20,20 +13,20 @@
props: {
value: Object,
noMargin: {
default: false
}
default: false,
},
},
components: {
LinkIcon
LinkIcon,
},
computed: {
href() {
const url = this.value.url;
return url.startsWith('http') ? this.value.url : `http://${this.value.url}`;
}
}
},
},
};
</script>

View File

@ -1,22 +1,12 @@
<template>
<div
class="final-submission"
data-cy="final-submission"
>
<document-block
:value="{url: userInput.document}"
class="final-submission__document"
v-if="userInput.document"
/>
<div class="final-submission" data-cy="final-submission">
<document-block :value="{ url: userInput.document }" class="final-submission__document" v-if="userInput.document" />
<div class="final-submission__explanation">
<info-icon class="final-submission__explanation-icon" />
<span class="final-submission__explanation-text">{{ sharedMsg }}</span>
<a
class="final-submission__reopen"
data-cy="final-submission-reopen"
v-if="showReopen"
@click="$emit('reopen')"
>Bearbeiten</a>
<a class="final-submission__reopen" data-cy="final-submission-reopen" v-if="showReopen" @click="$emit('reopen')"
>Bearbeiten</a
>
</div>
</div>
</template>
@ -24,7 +14,9 @@
<script>
import { newLineToParagraph } from '@/helpers/text';
import { defineAsyncComponent } from 'vue';
const DocumentBlock = defineAsyncComponent(() => import(/* webpackChunkName: "content-components" */'@/components/content-blocks/DocumentBlock'));
const DocumentBlock = defineAsyncComponent(() =>
import(/* webpackChunkName: "content-components" */ '@/components/content-blocks/DocumentBlock')
);
const InfoIcon = defineAsyncComponent(() => import(/* webpackChunkName: "icons" */ '@/components/icons/InfoIcon'));
@ -32,16 +24,16 @@
props: {
userInput: {
type: Object,
default: () => ({})
default: () => ({}),
},
showReopen: {
type: Boolean,
default: true
default: true,
},
sharedMsg: {
type: String,
default: ''
}
default: '',
},
},
components: {
@ -52,13 +44,13 @@
computed: {
text() {
return newLineToParagraph(this.userInput.text);
}
}
},
},
};
</script>
<style scoped lang="scss">
@import "~styles/helpers";
@import '~styles/helpers';
.final-submission {
&__text {

View File

@ -10,10 +10,7 @@
/>
</div>
<div
class="submission-form-container__actions"
v-if="!isFinalOrReadOnly"
>
<div class="submission-form-container__actions" v-if="!isFinalOrReadOnly">
<button
class="submission-form-container__submit button button--primary button--white-bg"
data-cy="submission-form-submit"
@ -29,11 +26,7 @@
>
{{ spellcheckText }}
</button>
<file-upload
:document="userInput.document"
v-if="allowsDocuments"
@change-document-url="changeDocumentUrl"
/>
<file-upload :document="userInput.document" v-if="allowsDocuments" @change-document-url="changeDocumentUrl" />
<slot />
</div>
@ -53,7 +46,6 @@
const FinalSubmission = defineAsyncComponent(() => import('@/components/content-blocks/assignment/FinalSubmission'));
const FileUpload = defineAsyncComponent(() => import('@/components/ui/file-upload/FileUpload'));
export default {
props: {
userInput: Object,
@ -116,7 +108,6 @@
this.$emit('changeDocumentUrl', documentUrl);
},
},
};
</script>
@ -159,5 +150,4 @@
display: inline-block;
}
}
</style>

View File

@ -11,16 +11,10 @@
v-auto-grow
@input="$emit('input', $event.target.value)"
/>
<div
class="submission-form__save-status submission-form__save-status--saved"
v-if="saved"
>
<div class="submission-form__save-status submission-form__save-status--saved" v-if="saved">
<tick-circle-icon class="submission-form__save-status-icon" />
</div>
<div
class="submission-form__save-status submission-form__save-status--unsaved"
v-if="!saved"
>
<div class="submission-form__save-status submission-form__save-status--unsaved" v-if="!saved">
<loading-icon class="submission-form__save-status-icon submission-form__saving-icon" />
</div>
</div>
@ -28,8 +22,12 @@
<script>
import { defineAsyncComponent } from 'vue';
const TickCircleIcon = defineAsyncComponent(() => import(/* webpackChunkName: "icons" */'@/components/icons/TickCircleIcon'));
const LoadingIcon = defineAsyncComponent(() => import(/* webpackChunkName: "icons" */'@/components/icons/LoadingIcon'));
const TickCircleIcon = defineAsyncComponent(() =>
import(/* webpackChunkName: "icons" */ '@/components/icons/TickCircleIcon')
);
const LoadingIcon = defineAsyncComponent(() =>
import(/* webpackChunkName: "icons" */ '@/components/icons/LoadingIcon')
);
export default {
props: {
@ -38,18 +36,18 @@
readonly: Boolean,
placeholder: {
type: String,
default: 'Ergebnis erfassen'
}
default: 'Ergebnis erfassen',
},
},
components: {
TickCircleIcon,
LoadingIcon
}
LoadingIcon,
},
};
</script>
<style scoped lang="scss">
@import "~styles/helpers";
@import '~styles/helpers';
.submission-form {
display: flex;

View File

@ -5,7 +5,7 @@
class="assignment-form__title skillbox-input"
placeholder="Aufgabentitel"
@input="$emit('assignment-change-title', $event.target.value, index)"
>
/>
<textarea
:value="value.assignment"
class="assignment-form__exercise-text skillbox-textarea"
@ -27,12 +27,12 @@
props: ['value', 'index'],
components: {
InfoIcon
}
InfoIcon,
},
};
</script>
<style scoped lang="scss">
@import "~styles/helpers";
@import '~styles/helpers';
.assignment-form {
display: grid;

View File

@ -1,28 +1,12 @@
<template>
<div
class="document-form"
ref="documentform"
>
<div
v-if="!value.url"
ref="uploadcare-panel"
/>
<div
class="document-form__spinner"
v-if="loading"
>
<div class="document-form" ref="documentform">
<div v-if="!value.url" ref="uploadcare-panel" />
<div class="document-form__spinner" v-if="loading">
<loading-icon class="document-form__loading-icon" />
</div>
<div
class="document-form__uploaded"
v-if="value.url"
>
<div class="document-form__uploaded" v-if="value.url">
<document-icon class="document-form__icon" />
<a
:href="previewUrl"
class="document-form__link"
target="_blank"
>{{ previewLink }}</a>
<a :href="previewUrl" class="document-form__link" target="_blank">{{ previewLink }}</a>
</div>
</div>
</template>
@ -65,19 +49,22 @@
},
mounted() {
uploadcare(this, url => {
uploadcare(
this,
(url) => {
this.$emit('change-url', url, this.index);
this.loading = false;
}, () => {
},
() => {
this.loading = true;
});
}
);
},
};
</script>
<style scoped lang="scss">
@import "~styles/helpers";
@import '~styles/helpers';
.document-form {
&__uploaded {

View File

@ -1,21 +1,11 @@
<template>
<div>
<div
class="video-form"
v-if="!isVimeo && !isYoutube && !isSrf"
>
<div class="video-form" v-if="!isVimeo && !isYoutube && !isSrf">
<info-icon class="video-form__help-icon help-text__icon" />
<p class="video-form__help-description help-text__description">
Sie können Videos auf <a
class="video-form__platform-link help-text__link"
href="https://youtube.com/"
target="_blank"
>Youtube</a>
oder <a
class="video-form__platform-link help-text__link"
href="https://vimeo.com/"
target="_blank"
>Vimeo</a>
Sie können Videos auf
<a class="video-form__platform-link help-text__link" href="https://youtube.com/" target="_blank">Youtube</a>
oder <a class="video-form__platform-link help-text__link" href="https://vimeo.com/" target="_blank">Vimeo</a>
hochladen und anschliessen einen Link hier einfügen.
</p>
@ -24,7 +14,7 @@
class="video-form__video-link skillbox-input"
placeholder="Bsp: https://www.youtube.com/watch?v=dQw4w9WgXcQ"
@input="$emit('change-url', $event.target.value, index)"
>
/>
</div>
<div v-if="isYoutube">
@ -54,7 +44,7 @@
InfoIcon,
YoutubeEmbed,
VimeoEmbed,
SrfEmbed
SrfEmbed,
},
computed: {
@ -66,14 +56,14 @@
},
isSrf() {
return isSrfUrl(this.value.url);
}
}
},
},
};
</script>
<style scoped lang="scss">
@import "@/styles/_variables.scss";
@import "@/styles/_functions.scss";
@import '@/styles/_variables.scss';
@import '@/styles/_functions.scss';
.video-form {
display: grid;
@ -84,11 +74,9 @@
align-items: center;
&__help-icon {
}
&__help-description {
}
&__platform-link {
@ -100,7 +88,7 @@
&__video-link {
grid-column: 1 / span 2;
width: $modal-input-width
width: $modal-input-width;
}
}
</style>

View File

@ -284,14 +284,9 @@
/>
<path
d="M339.92,387.48c0-.82-.33-1.61-.91-2.19-.58-.58-1.37-.91-2.19-.91H23.71c-.82,0-1.61,.33-2.19,.91-.58,.58-.91,1.37-.91,2.19h0c0,.82,.33,1.61,.91,2.19,.58,.58,1.37,.91,2.19,.91H336.83c.82,0,1.61-.33,2.19-.91,.58-.58,.91-1.37,.91-2.19h0Z"
fill="#fff"
fill-rule="evenodd"
/>
fill="#fff" fill-rule="evenodd" />
<polygon
points="291.56 386.68 286.32 386.68 286.32 505.02 291.56 505.02 291.56 386.68 291.56 386.68"
fill="#fff"
fill-rule="evenodd"
/>
points="291.56 386.68 286.32 386.68 286.32 505.02 291.56 505.02 291.56 386.68 291.56 386.68" fill="#fff" fill-rule="evenodd" />
<polygon
points="72.67 387.59 67.43 387.59 67.43 505.02 72.67 505.02 72.67 387.59 72.67 387.59"
fill="#fff"

View File

@ -1,29 +1,19 @@
<template>
<a
:class="typeClass"
class="filter-entry"
data-cy="filter-entry"
:style="categoryStyle"
@click="$emit('filter')"
<a :class="typeClass" class="filter-entry" data-cy="filter-entry" :style="categoryStyle" @click="$emit('filter')"
>
<span class="filter-entry__text">{{ text }}</span>
<span
:style="activeStyle"
class="filter-entry__icon-wrapper"
>
<chevron-right
:style="{fill: category.foreground}"
class="filter-entry__icon"
/>
<span :style="activeStyle" class="filter-entry__icon-wrapper">
<chevron-right :style="{ fill: category.foreground }" class="filter-entry__icon" />
</span>
</a>
</template>
<script>
import INSTRUMENT_FILTER_QUERY from 'gql/local/instrumentFilter.gql';
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: {

View File

@ -51,15 +51,15 @@
apollo: {
instrumentFilter: {
query: INSTRUMENT_FILTER_QUERY
}
query: INSTRUMENT_FILTER_QUERY,
},
},
data() {
return {
instrumentFilter: {
currentFilter: ''
}
currentFilter: '',
},
};
},
inheritAttrs: false,
@ -76,10 +76,9 @@
this.$apollo.mutate({
mutation: SET_FILTER_MUTATION,
variables: {
filter
}
filter,
},
});
}
},
});
</script>

View File

@ -1,12 +1,6 @@
<template>
<router-link
:to="moduleLink"
:class="['module-teaser', {'module-teaser--small': !teaser}]"
>
<div
:style="{backgroundImage: 'url('+heroImage+')'}"
class="module-teaser__image"
/>
<router-link :to="moduleLink" :class="['module-teaser', { 'module-teaser--small': !teaser }]">
<div :style="{ backgroundImage: 'url(' + heroImage + ')' }" class="module-teaser__image" />
<div class="module-teaser__body">
<h3 class="module-teaser__meta-title">
{{ metaTitle }}
@ -38,7 +32,8 @@
return {};
}
}
}
},
},
};
</script>
@ -47,7 +42,7 @@
.module-teaser {
box-shadow: 0 3px 9px 0 rgba(0, 0, 0, 0.12);
border: 1px solid #E2E2E2;
border: 1px solid #e2e2e2;
height: 330px;
max-width: 380px;
width: 100%;

View File

@ -1,8 +1,5 @@
<template>
<div
class="bookmark-actions"
v-if="!editMode"
>
<div class="bookmark-actions" v-if="!editMode">
<a
:class="{ 'bookmark-actions__action--bookmarked': bookmarked }"
class="bookmark-actions__action bookmark-actions__bookmark"
@ -41,27 +38,27 @@
props: {
bookmarked: {
type: Boolean,
default: false
default: false,
},
note: {
type: [Object, Boolean],
default: false
default: false,
},
editMode: {
type: Boolean,
default: false
}
default: false,
},
},
components: {
BookmarkIcon,
AddNoteIcon,
NoteIcon
NoteIcon,
},
};
</script>
<style scoped lang="scss">
@import "~styles/helpers";
@import '~styles/helpers';
.bookmark-actions {
height: 100%;
@ -88,7 +85,8 @@
display: flex;
justify-content: center;
&--bookmarked, &--noted {
&--bookmarked,
&--noted {
opacity: 1;
}
}
@ -101,5 +99,4 @@
}
}
}
</style>

View File

@ -6,10 +6,7 @@
placeholder="Lernziel erfassen..."
@input="$emit('input', $event)"
/>
<a
class="icon-button"
@click="$emit('delete')"
>
<a class="icon-button" @click="$emit('delete')">
<trash-icon class="icon-button__icon icon-button__icon--subtle" />
</a>
</div>
@ -25,13 +22,13 @@
components: {
ModalInput,
TrashIcon
}
TrashIcon,
},
};
</script>
<style scoped lang="scss">
@import "@/styles/_variables.scss";
@import '@/styles/_variables.scss';
.objective-form {
display: grid;

View File

@ -1,8 +1,5 @@
<template>
<a
class="add-project-entry"
@click="addProjectEntry"
>
<a class="add-project-entry" @click="addProjectEntry">
<plus-icon class="add-project-entry__icon" />
<span class="add-project-entry__text">Beitrag erfassen</span>
</a>
@ -18,13 +15,13 @@
methods: {
addProjectEntry() {
this.$store.dispatch('addProjectEntry', this.project);
}
}
},
},
};
</script>
<style lang="scss" scoped>
@import "~styles/helpers";
@import '~styles/helpers';
.add-project-entry {
display: flex;

View File

@ -1,25 +1,9 @@
<template>
<div class="portfolio-onboarding">
<h1
class="portfolio-onboarding__heading"
data-cy="page-title"
>
Portfolio
</h1>
<portfolio-illustration
data-cy="portfolio-onboarding-illustration"
class="portfolio-onboarding__illustration"
/>
<h2
class="portfolio-onboarding__subheading"
data-cy="portfolio-onboarding-subtitle"
>
Woran denken Sie gerade?
</h2>
<p
class="portfolio-onboarding__text"
data-cy="portfolio-onboarding-text"
>
<h1 class="portfolio-onboarding__heading" data-cy="page-title">Portfolio</h1>
<portfolio-illustration data-cy="portfolio-onboarding-illustration" class="portfolio-onboarding__illustration" />
<h2 class="portfolio-onboarding__subheading" data-cy="portfolio-onboarding-subtitle">Woran denken Sie gerade?</h2>
<p class="portfolio-onboarding__text" data-cy="portfolio-onboarding-text">
Hier können Sie Projekte erstellen, um Ihre Gedanken festzuhalten oder Ihre Arbeit zu dokumentieren.
</p>

View File

@ -1,48 +1,20 @@
<template>
<div
class="project-actions"
data-cy="project-actions"
>
<a
class="project-actions__more-link"
@click.stop="toggleMenu"
>
<div class="project-actions" data-cy="project-actions">
<a class="project-actions__more-link" @click.stop="toggleMenu">
<ellipses />
</a>
<widget-popover
class="project-actions__popover"
v-if="showMenu"
@hide-me="showMenu = false"
>
<widget-popover class="project-actions__popover" v-if="showMenu" @hide-me="showMenu = false">
<li class="popover-links__link">
<a
data-cy="delete-project"
@click="deleteProject(slug)"
>Projekt löschen</a>
<a data-cy="delete-project" @click="deleteProject(slug)">Projekt löschen</a>
</li>
<li class="popover-links__link">
<a
data-cy="edit-project"
@click="editProject(slug)"
>Projekt bearbeiten</a>
<a data-cy="edit-project" @click="editProject(slug)">Projekt bearbeiten</a>
</li>
<li
class="popover-links__link"
v-if="!final && shareButtons"
>
<a
data-cy="share-project"
@click="updateProjectShareState(slug, true)"
>Projekt teilen</a>
<li class="popover-links__link" v-if="!final && shareButtons">
<a data-cy="share-project" @click="updateProjectShareState(slug, true)">Projekt teilen</a>
</li>
<li
class="popover-links__link"
v-if="final && shareButtons"
>
<a
data-cy="unshare-project"
@click="updateProjectShareState(slug, false)"
>Projekt nicht mehr teilen</a>
<li class="popover-links__link" v-if="final && shareButtons">
<a data-cy="unshare-project" @click="updateProjectShareState(slug, false)">Projekt nicht mehr teilen</a>
</li>
</widget-popover>
</div>
@ -96,30 +68,38 @@ export default {
this.$router.push({ name: 'edit-project', params: { slug } });
},
deleteProject(slug) {
this.$apollo.mutate({
this.$apollo
.mutate({
mutation: DELETE_PROJECT_MUTATION,
variables: {
input: {
slug,
},
},
update(store, {data: {deleteProject: {success}}}) {
update(
store,
{
data: {
deleteProject: { success },
},
}
) {
if (success) {
const { projects: prevProjects } = store.readQuery({ query: PROJECTS_QUERY });
if (prevProjects) {
let index = prevProjects.findIndex(project => project.slug === slug);
let index = prevProjects.findIndex((project) => project.slug === slug);
const projects = removeAtIndex(prevProjects, index);
const data = {
projects
projects,
};
store.writeQuery({ query: PROJECTS_QUERY, data });
}
}
},
}).then(() => {
})
.then(() => {
this.$router.push('/portfolio');
});
},
@ -128,7 +108,7 @@ export default {
</script>
<style scoped lang="scss">
@import "~styles/_helpers.scss";
@import '~styles/_helpers.scss';
.project-actions {
position: relative;

View File

@ -1,43 +1,21 @@
<template>
<div
class="project-entry"
data-cy="project-entry"
>
<more-options-widget
class="project-entry__more"
data-cy="project-entry-more"
v-if="!readOnly"
>
<div class="project-entry" data-cy="project-entry">
<more-options-widget class="project-entry__more" data-cy="project-entry-more" v-if="!readOnly">
<li class="popover-links__link">
<a
data-cy="edit-project-entry"
@click="editProjectEntry()"
>Eintrag bearbeiten</a>
<a data-cy="edit-project-entry" @click="editProjectEntry()">Eintrag bearbeiten</a>
</li>
<li class="popover-links__link">
<a
data-cy="delete-project-entry"
@click="deleteProjectEntry()"
>Eintrag löschen</a>
<a data-cy="delete-project-entry" @click="deleteProjectEntry()">Eintrag löschen</a>
</li>
</more-options-widget>
<h3
class="project-entry__heading"
data-cy="project-entry-date"
>
<h3 class="project-entry__heading" data-cy="project-entry-date">
{{ createdDateTime }}
</h3>
<p
class="project-entry__paragraph"
data-cy="project-entry-activity"
>
<p class="project-entry__paragraph" data-cy="project-entry-activity">
{{ description }}
</p>
<p
class="project-entry__paragraph"
v-if="documentUrl"
>
<p class="project-entry__paragraph" v-if="documentUrl">
<document-block :value="{ url: documentUrl }" />
</p>
<div class="project-entry__date">
@ -86,7 +64,14 @@
id: this.id,
},
},
update(store, {data: {deleteProjectEntry: {success}}}) {
update(
store,
{
data: {
deleteProjectEntry: { success },
},
}
) {
if (success) {
const query = PROJECT_QUERY;
const variables = {
@ -94,7 +79,7 @@
};
const { project } = store.readQuery({ query, variables });
if (project) {
const index = project.entries.findIndex(entry => entry.id === projectEntry.id);
const index = project.entries.findIndex((entry) => entry.id === projectEntry.id);
const entries = removeAtIndex(project.entries, index);
const data = {
project: {
@ -113,7 +98,7 @@
</script>
<style scoped lang="scss">
@import "~styles/helpers";
@import '~styles/helpers';
.project-entry {
background-color: $color-white;
@ -151,6 +136,5 @@
display: block;
}
}
}
</style>

View File

@ -1,12 +1,7 @@
<template>
<modal :hide-header="false">
<template #header>
<h2
class="project-entry-modal__heading"
data-cy="modal-title"
>
Beitrag erfassen
</h2>
<h2 class="project-entry-modal__heading" data-cy="modal-title">Beitrag erfassen</h2>
</template>
<div class="project-entry-modal">
@ -36,15 +31,10 @@
</div>
</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>
<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>
</modal>
</template>
@ -74,9 +64,12 @@
data() {
return {
localProjectEntry: Object.assign({}, {
localProjectEntry: Object.assign(
{},
{
...this.projectEntry,
}),
}
),
};
},
@ -92,7 +85,7 @@
</script>
<style lang="scss" scoped>
@import "~styles/helpers";
@import '~styles/helpers';
.project-entry-modal {
display: flex;
@ -135,7 +128,5 @@
@include heading-3;
margin-bottom: 0;
}
}
</style>

View File

@ -1,17 +1,7 @@
<template>
<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"
/>
<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>
<button
:class="{ 'button--disabled': !formValid }"
@ -22,12 +12,7 @@
>
Speichern
</button>
<router-link
to="/portfolio"
class="button"
>
Abbrechen
</router-link>
<router-link to="/portfolio" class="button"> Abbrechen </router-link>
</template>
</page-form>
</template>

View File

@ -70,10 +70,8 @@ export default {
@include desktop {
display: flex;
flex: 80%;
flex-direction: row;
align-items: center;
}
}
flex-direction: row;align-items: center;
}}
&__title {
flex: 50%;
@ -96,7 +94,6 @@ export default {
&__entry-count {
justify-self: flex-end;
grid-column: 2 / span 1;
}
grid-column: 2 / span 1;}
}
</style>

View File

@ -1,7 +1,5 @@
<template>
<a
class="share-icon"
@click="$emit('share')"
<a class="share-icon" @click="$emit('share')"
>
<share-icon class="share-icon__icon" />
<span class="share-icon__text">

View File

@ -15,17 +15,9 @@
ref="avatarImage"
/>
</transition>
<img
:src="avatarUrl"
class="avatar__fake-image"
ref="fakeImage"
>
<img :src="avatarUrl" class="avatar__fake-image" ref="fakeImage" />
<div
class="avatar__edit"
v-if="editable"
@click="closeSidebar"
>
<div class="avatar__edit" v-if="editable" @click="closeSidebar">
<router-link :to="{ name: 'profile' }">
<pen-icon />
</router-link>
@ -43,20 +35,20 @@
export default {
props: {
avatarUrl: {
type: String
type: String,
},
iconHighlighted: {},
editable: {
default: false
}
default: false,
},
},
components: {
DefaultAvatar,
PenIcon
PenIcon,
},
data() {
return {
isAvatarLoaded: false
isAvatarLoaded: false,
};
},
mounted() {
@ -75,17 +67,17 @@
mutation: TOGGLE_SIDEBAR,
variables: {
sidebar: {
profile: false
}
}
profile: false,
},
},
});
}
}
},
},
};
</script>
<style scoped lang="scss">
@import "~styles/helpers";
@import '~styles/helpers';
$max-width: 100%;

View File

@ -1,15 +1,9 @@
<template>
<div class="content-bookmark module-activity-entry">
<!-- eslint-disable vue/no-v-html -->
<div
v-if="content.type === 'text_block'"
v-html="text"
/>
<div v-if="content.type === 'text_block'" v-html="text" />
<div v-else-if="content.type === 'link_block'">
<link-block
:value="content.value"
:no-margin="true"
/>
<link-block :value="content.value" :no-margin="true" />
</div>
<p v-else>
{{ type }}
@ -27,8 +21,8 @@
computed: {
content() {
return this.bookmark.contentBlock
? this.bookmark.contentBlock.contents.find(e => e.id === this.bookmark.uuid)
: this.bookmark.instrument.contents.find(e => e.id === this.bookmark.uuid);
? this.bookmark.contentBlock.contents.find((e) => e.id === this.bookmark.uuid)
: this.bookmark.instrument.contents.find((e) => e.id === this.bookmark.uuid);
},
text() {
return this.content.value.text ? this.content.value.text : 'TO BE DEFINED';
@ -46,7 +40,7 @@
default:
return this.content.type;
}
}
}
},
},
};
</script>

View File

@ -1,9 +1,5 @@
<template>
<a
class="edit-group-name"
data-cy="edit-group-name-link"
@click="$emit('edit')"
>
<a class="edit-group-name" data-cy="edit-group-name-link" @click="$emit('edit')">
<pen-icon class="edit-group-name__icon" />
</a>
</template>
@ -14,13 +10,13 @@
export default {
components: {
PenIcon
}
PenIcon,
},
};
</script>
<style scoped lang="scss">
@import "~styles/_variables.scss";
@import '~styles/_variables.scss';
.edit-group-name {
&__icon {

View File

@ -181,17 +181,13 @@ export default {
}
&__role {
@include desktop {
flex: 0 1 110px;
@include desktop {flex: 0 1 110px;
text-align: right;
}
}
}}
&__action {
@include desktop {
flex: 0 1 110px;
@include desktop {flex: 0 1 110px;
padding-left: $large-spacing;
}
}
}
}}
</style>

View File

@ -1,26 +1,15 @@
<template>
<div class="profile">
<h1 class="profile__header">
Profilbild
</h1>
<div
class="profile-avatar"
v-if="me.avatarUrl"
>
<h1 class="profile__header">Profilbild</h1>
<div class="profile-avatar" v-if="me.avatarUrl">
<div class="profile-avatar__image">
<avatar :avatar-url="me.avatarUrl" />
</div>
<a
class="profile-avatar__remove icon-button"
@click="deleteAvatar()"
>
<a class="profile-avatar__remove icon-button" @click="deleteAvatar()">
<trash-icon class="profile-avatar__remove-icon icon-button__icon icon-button__icon--subtle" />
</a>
</div>
<avatar-upload-form
v-else
@avatarUpdate="updateAvatar"
/>
<avatar-upload-form v-else @avatarUpdate="updateAvatar" />
</div>
</template>
@ -36,14 +25,14 @@
components: {
AvatarUploadForm,
Avatar,
TrashIcon
TrashIcon,
},
data() {
return {
me: {
avatarUrl: ''
}
avatarUrl: '',
},
};
},
apollo: {
@ -56,37 +45,46 @@
this.updateAvatar('');
},
updateAvatar(url) {
this.$apollo.mutate({
this.$apollo
.mutate({
mutation: UPDATE_AVATAR_QUERY,
variables: {
input: {
avatarUrl: url
}
avatarUrl: url,
},
update(store, {data: {updateAvatar: {success}}}) {
},
update(
store,
{
data: {
updateAvatar: { success },
},
}
) {
if (success) {
const { me } = store.readQuery({ query: ME_QUERY });
if (me) {
const data = {
me: {
...me,
avatarUrl: url
}
avatarUrl: url,
},
};
store.writeQuery({ query: ME_QUERY, data });
}
}
}
}).catch((error) => {
},
})
.catch((error) => {
console.warn('UploadError', error);
});
}
}
},
},
};
</script>
<style scoped lang="scss">
@import "@/styles/_variables.scss";
@import '@/styles/_variables.scss';
.profile-avatar {
display: flex;
@ -101,5 +99,4 @@
.profile-avatar {
margin-bottom: $large-spacing;
}
</style>

View File

@ -1,69 +1,31 @@
<template>
<transition name="slide">
<div
class="profile-sidebar"
data-cy="sidebar"
v-if="sidebar.profile"
v-click-outside="close"
>
<a
class="profile-sidebar__close-link"
data-cy="close-profile-sidebar-link"
@click="close"
>
<div class="profile-sidebar" data-cy="sidebar" v-if="sidebar.profile" v-click-outside="close">
<a class="profile-sidebar__close-link" data-cy="close-profile-sidebar-link" @click="close">
<cross class="profile-sidebar__close-icon" />
</a>
<div class="profile-sidebar__section">
<profile-widget class="profile-sidebar__item" />
<div
class="profile-sidebar__item"
@click="close"
>
<router-link
to="/me/activity"
class="profile-sidebar__link"
>
Meine Aktivitäten
</router-link>
<div class="profile-sidebar__item" @click="close">
<router-link to="/me/activity" class="profile-sidebar__link"> Meine Aktivitäten </router-link>
</div>
<div
class="profile-sidebar__item"
v-if="me.isTeacher && !me.readOnly"
@click="close"
>
<router-link
:to="myTeamPage"
data-cy="my-team-link"
class="profile-sidebar__link"
>
Mein Team
</router-link>
<div class="profile-sidebar__item" v-if="me.isTeacher && !me.readOnly" @click="close">
<router-link :to="myTeamPage" data-cy="my-team-link" class="profile-sidebar__link"> Mein Team </router-link>
</div>
</div>
<div class="profile-sidebar__section">
<div class="profile-sidebar__item">
<class-selection-widget />
<div @click="close">
<router-link
:to="{name: 'my-class'}"
data-cy="class-list-link"
class="profile-sidebar__link"
>
<router-link :to="{ name: 'my-class' }" data-cy="class-list-link" class="profile-sidebar__link">
Klassenliste
</router-link>
</div>
</div>
</div>
<div class="profile-sidebar__section">
<div
class="profile-sidebar__item"
@click="close"
>
<router-link
:to="{name:'join-class'}"
data-cy="join-class-link"
class="profile-sidebar__link"
>
<div class="profile-sidebar__item" @click="close">
<router-link :to="{ name: 'join-class' }" data-cy="join-class-link" class="profile-sidebar__link">
Zugangscode
</router-link>
</div>
@ -88,7 +50,6 @@
const Cross = defineAsyncComponent(() => import(/* webpackChunkName: "icons" */ '@/components/icons/CrossIcon'));
export default {
mixins: [sidebar, me],
components: {
@ -115,7 +76,7 @@
</script>
<style scoped lang="scss">
@import "~styles/helpers";
@import '~styles/helpers';
$desktop-width: 333px;
@ -173,11 +134,13 @@
}
.slide {
&-enter-active, &-leave-active {
&-enter-active,
&-leave-active {
transition: right 0.2s;
}
&-enter-from, &-leave-to {
&-enter-from,
&-leave-to {
right: -100vw;
@include desktop {
right: -$desktop-width;

View File

@ -32,12 +32,9 @@ export default {
.show-code {
&__title {
@include regular-text;
margin-bottom: $large-spacing;
@include desktop {
margin-bottom: 2 * $large-spacing;
}
}
@include desktop { margin-bottom: 2 * $large-spacing;
}}
&__code {
font-size: toRem(60px);

View File

@ -1,9 +1,5 @@
<template>
<router-link
class="add-room-entry-button"
data-cy="add-room-entry-button"
:to="addRoomEntryRoute"
>
<router-link class="add-room-entry-button" data-cy="add-room-entry-button" :to="addRoomEntryRoute">
<plus-icon class="add-room-entry-button__icon" />
<span class="add-room-entry-button__text">Beitrag erfassen</span>
</router-link>
@ -32,7 +28,7 @@
</script>
<style scoped lang="scss">
@import "~styles/helpers";
@import '~styles/helpers';
.add-room-entry-button {
border: 2px solid $color-white;

View File

@ -1,7 +1,9 @@
<template>
<div class="entry-count-widget">
<component :is="icon" />
<span data-cy="entry-count">{{ entryCount }} <template v-if="verbose">{{ entryCount === 1 ? 'Beitrag' : 'Beiträge' }}</template></span>
<span data-cy="entry-count"
>{{ entryCount }} <template v-if="verbose">{{ entryCount === 1 ? 'Beitrag' : 'Beiträge' }}</template></span
>
</div>
</template>
@ -21,8 +23,8 @@
},
icon: {
type: String,
default: 'cards'
}
default: 'cards',
},
},
components: {
@ -34,7 +36,7 @@
</script>
<style scoped lang="scss">
@import "~styles/helpers";
@import '~styles/helpers';
.entry-count-widget {
display: flex;
@ -52,5 +54,4 @@
@include room-widget-text-style;
}
}
</style>

View File

@ -8,11 +8,7 @@
>
<ellipses />
</a>
<widget-popover
class="more-actions__popover"
v-if="showMenu"
@hide-me="showMenu = false"
>
<widget-popover class="more-actions__popover" v-if="showMenu" @hide-me="showMenu = false">
<slot :toggle="toggleMenu" />
</widget-popover>
</div>
@ -27,8 +23,8 @@
props: {
background: {
type: Boolean,
default: false
}
default: false,
},
},
components: {

View File

@ -1,41 +1,16 @@
<template>
<page-form
class="room-form"
title="Neuer Raum"
@save="$emit('save', localRoom)"
>
<page-form-input
label="Titel"
v-model="localRoom.title"
/>
<page-form class="room-form" title="Neuer Raum" @save="$emit('save', localRoom)">
<page-form-input label="Titel" v-model="localRoom.title" />
<page-form-input
label="Beschreibung"
type="textarea"
v-model="localRoom.description"
/>
<page-form-input label="Beschreibung" type="textarea" v-model="localRoom.description" />
<h2 class="room-form__property-heading">
Farbe
</h2>
<color-chooser
:selected-color="localRoom.appearance"
@input="updateColor"
/>
<h2 class="room-form__property-heading">Farbe</h2>
<color-chooser :selected-color="localRoom.appearance" @input="updateColor" />
<template #footer>
<button
type="submit"
data-cy="room-form-save"
class="button button--primary room-form__save-button"
>
<button type="submit" data-cy="room-form-save" class="button button--primary room-form__save-button">
Speichern
</button>
<router-link
to="/rooms"
class="button"
>
Abbrechen
</router-link>
<router-link to="/rooms" class="button"> Abbrechen </router-link>
</template>
</page-form>
</template>
@ -53,13 +28,13 @@
components: {
ColorChooser,
PageForm,
PageFormInput
PageFormInput,
},
data() {
return {
localRoom: Object.assign({}, this.room),
me: {}
me: {},
};
},
@ -75,19 +50,19 @@
updateColor(newColor) {
this.localRoom.appearance = newColor;
this.$store.dispatch('setSpecialContainerClass', newColor);
}
},
},
apollo: {
me: {
query: ME_QUERY,
}
},
},
};
</script>
<style scoped lang="scss">
@import "~styles/helpers";
@import '~styles/helpers';
.room-form {
&__property-heading {

View File

@ -15,13 +15,13 @@
props: ['name'],
components: {
Group
}
Group,
},
};
</script>
<style scoped lang="scss">
@import "~styles/helpers";
@import '~styles/helpers';
.room-group-widget {
display: flex;
@ -35,7 +35,7 @@
}
& > span {
@include room-widget-text-style;;
@include room-widget-text-style;
}
}
</style>

View File

@ -15,25 +15,27 @@
import { defineAsyncComponent } from 'vue';
const EyeIcon = defineAsyncComponent(() => import(/* webpackChunkName: "icons" */ '@/components/icons/EyeIcon'));
const ClosedEyeIcon = defineAsyncComponent(() => import(/* webpackChunkName: "icons" */'@/components/icons/ClosedEyeIcon'));
const ClosedEyeIcon = defineAsyncComponent(() =>
import(/* webpackChunkName: "icons" */ '@/components/icons/ClosedEyeIcon')
);
export default {
props: {
restricted: {
type: Boolean,
default: false
}
default: false,
},
},
components: {
ClosedEyeIcon,
EyeIcon
}
EyeIcon,
},
};
</script>
<style scoped lang="scss">
@import "~styles/helpers";
@import '~styles/helpers';
.room-visibility-widget {
display: flex;
@ -50,5 +52,4 @@
@include room-widget-text-style;
}
}
</style>

View File

@ -1,12 +1,6 @@
<template>
<div
:class="roomClass"
class="room-widget"
>
<router-link
:to="{name: 'room', params: {slug: slug}}"
class="room-widget__content"
>
<div :class="roomClass" class="room-widget">
<router-link :to="{ name: 'room', params: { slug: slug } }" class="room-widget__content">
<h2 class="room-widget__title">
{{ title }}
</h2>

View File

@ -1,25 +1,12 @@
<template>
<div class="rooms-onboarding">
<h1
class="rooms-onboarding__heading"
data-cy="page-title"
>
Räume
</h1>
<h1 class="rooms-onboarding__heading" data-cy="page-title">Räume</h1>
<rooms-illustration class="rooms-onboarding__illustration" />
<p
data-cy="rooms-onboarding-text"
class="rooms-onboarding__text"
>
<p data-cy="rooms-onboarding-text" class="rooms-onboarding__text">
Hier können Sie Räume erstellen, damit SchülerInnen zusammenarbeiten und Beiträge teilen können.
</p>
<div class="rooms-onboarding__button">
<router-link
:to="newRoomRoute"
class="button button--primary"
data-cy="create-room-button"
v-if="isTeacher"
>
<router-link :to="newRoomRoute" class="button button--primary" data-cy="create-room-button" v-if="isTeacher">
Raum erstellen
</router-link>
</div>
@ -29,7 +16,9 @@
<script>
import { NEW_ROOM_PAGE } from '@/router/room.names';
import { defineAsyncComponent } from 'vue';
const RoomsIllustration = defineAsyncComponent(() => import(/* webpackChunkName: "illustrations" */'@/components/illustrations/RoomsIllustration'));
const RoomsIllustration = defineAsyncComponent(() =>
import(/* webpackChunkName: "illustrations" */ '@/components/illustrations/RoomsIllustration')
);
export default {
props: {

View File

@ -13,12 +13,7 @@
/>
<chevron-down class="selected-class__dropdown-icon" />
</div>
<widget-popover
:mobile="mobile"
class="class-selection__popover"
v-if="showPopover"
@hide-me="showPopover = false"
>
<widget-popover :mobile="mobile" class="class-selection__popover" v-if="showPopover" @hide-me="showPopover = false">
<li
:label="schoolClass.name"
:item="schoolClass"
@ -70,12 +65,11 @@
const AddIcon = defineAsyncComponent(() => import(/* webpackChunkName: "icons" */'@/components/icons/AddIcon'));
export default {
props: {
mobile: {
type: Boolean,
default: false
}
default: false,
},
},
mixins: [updateSelectedClassMixin, sidebarMixin, meMixin],
@ -83,22 +77,22 @@
WidgetPopover,
ChevronDown,
CurrentClass,
AddIcon
AddIcon,
},
data() {
return {
showPopover: false
showPopover: false,
};
},
computed: {
currentClassSelection() {
let currentClass = this.me.schoolClasses.find(schoolClass => {
let currentClass = this.me.schoolClasses.find((schoolClass) => {
return schoolClass.id === this.me.selectedClass.id;
});
return currentClass || this.me.schoolClasses[0];
}
},
},
methods: {
@ -111,12 +105,12 @@
this.closeSidebar('profile');
}
},
},
};
</script>
<style scoped lang="scss">
@import "~styles/helpers";
@import '~styles/helpers';
.class-selection {
position: relative;
@ -130,7 +124,6 @@
left: 0;
transform: translateY($small-spacing);
}
}
.selected-class {

View File

@ -1,8 +1,5 @@
<template>
<span
class="current-class"
data-cy="current-class-name"
>{{ currentClassName }}</span>
<span class="current-class" data-cy="current-class-name">{{ currentClassName }}</span>
</template>
<script>
@ -14,8 +11,8 @@
</script>
<style scoped lang="scss">
@import "@/styles/_variables.scss";
@import "@/styles/_mixins.scss";
@import '@/styles/_variables.scss';
@import '@/styles/_mixins.scss';
.current-class {
display: flex;

View File

@ -6,26 +6,19 @@
class="base-input-container__input"
data-cy="base-input-input"
@change.prevent="$emit('input', $event.target.checked, item)"
>
/>
<span
:class="{'base-input-container__checkbox': type==='checkbox', 'base-input-container__radiobutton': type === 'radiobutton'}"
:class="{
'base-input-container__checkbox': type === 'checkbox',
'base-input-container__radiobutton': type === 'radiobutton',
}"
class="base-input-container__icon checkbox"
>
<tick v-if="type === 'checkbox'" />
<circle-icon
data-cy="circle-icon"
v-if="type === 'radiobutton'"
/>
<circle-icon data-cy="circle-icon" v-if="type === 'radiobutton'" />
</span>
<span
class="base-input-container__label"
data-cy="base-input-label"
v-if="label"
>{{ label }}</span>
<slot
class="base-input-container__label"
v-if="!label"
/>
<span class="base-input-container__label" data-cy="base-input-label" v-if="label">{{ label }}</span>
<slot class="base-input-container__label" v-if="!label" />
</label>
</template>
@ -38,15 +31,15 @@
props: {
label: String,
checked: {
type: Boolean
type: Boolean,
},
item: Object,
type: String
type: String,
},
components: {
Tick,
CircleIcon
}
CircleIcon,
},
};
</script>

View File

@ -1,15 +1,7 @@
<template>
<li
class="popover-links__link"
>
<a
class="popover-link"
@click="$emit('link-action')"
>
<component
class="popover-link__icon"
:is="icon"
/>
<li class="popover-links__link">
<a class="popover-link" @click="$emit('link-action')">
<component class="popover-link__icon" :is="icon" />
<span class="popover-link__text">{{ text }}</span>
</a>
</li>

View File

@ -1,11 +1,7 @@
<template>
<div class="file-upload">
<template v-if="document">
<document-block
:value="{url: document}"
show-trash-icon
@trash="$emit('change-document-url', '')"
/>
<document-block :value="{ url: document }" show-trash-icon @trash="$emit('change-document-url', '')" />
</template>
<template v-else>
<simple-file-upload
@ -20,7 +16,9 @@
<script>
import { defineAsyncComponent } from 'vue';
const SimpleFileUpload = defineAsyncComponent(() => import('@/components/ui/file-upload/SimpleFileUpload'));
const DocumentBlock = defineAsyncComponent(() => import(/* webpackChunkName: "content-components" */'@/components/content-blocks/DocumentBlock'));
const DocumentBlock = defineAsyncComponent(() =>
import(/* webpackChunkName: "content-components" */ '@/components/content-blocks/DocumentBlock')
);
export default {
props: {
@ -30,8 +28,8 @@
},
withText: {
type: Boolean,
default: false
}
default: false,
},
},
components: { SimpleFileUpload, DocumentBlock },
};
@ -39,5 +37,4 @@
<style scoped lang="scss">
@import '~styles/helpers';
</style>

View File

@ -6,7 +6,9 @@
<script>
import { defineAsyncComponent } from 'vue';
const DocumentIcon = defineAsyncComponent(() => import(/* webpackChunkName: "icons" */'@/components/icons/DocumentIcon'));
const DocumentIcon = defineAsyncComponent(() =>
import(/* webpackChunkName: "icons" */ '@/components/icons/DocumentIcon')
);
export default {
components: { DocumentIcon },

View File

@ -30,5 +30,5 @@ export default {
ArrowThinDown,
ArrowThinTop,
ArrowThinUp,
TrashIcon
TrashIcon,
};

View File

@ -1,11 +1,6 @@
<template>
<div
class="skillboxform-input"
>
<label
:for="id"
class="skillboxform-input__label"
>
<div class="skillboxform-input">
<label :for="id" class="skillboxform-input__label">
{{ label }}
</label>
<slot :id="id" />
@ -15,6 +10,6 @@
<script setup>
defineProps({
id: String,
label: String
label: String,
});
</script>

View File

@ -1,18 +1,8 @@
<template>
<div class="visibility-action">
<a
class="visibility-action__action-button"
v-if="canManageContent"
@click="toggleVisibility()"
>
<closed-eye-icon
class="visibility-action__action-icon action-icon"
v-if="hidden"
/>
<eye-icon
class="visibility-action__action-icon action-icon"
v-else
/>
<a class="visibility-action__action-button" v-if="canManageContent" @click="toggleVisibility()">
<closed-eye-icon class="visibility-action__action-icon action-icon" v-if="hidden" />
<eye-icon class="visibility-action__action-icon action-icon" v-else />
</a>
</div>
</template>
@ -25,35 +15,37 @@
import { defineAsyncComponent } from 'vue';
const EyeIcon = defineAsyncComponent(() => import(/* webpackChunkName: "icons" */ '@/components/icons/EyeIcon'));
const ClosedEyeIcon = defineAsyncComponent(() => import(/* webpackChunkName: "icons" */'@/components/icons/ClosedEyeIcon'));
const ClosedEyeIcon = defineAsyncComponent(() =>
import(/* webpackChunkName: "icons" */ '@/components/icons/ClosedEyeIcon')
);
export default {
props: {
block: {
type: Object,
default: () => ({})
default: () => ({}),
},
type: {
type: String,
default: CONTENT_TYPE,
validator: value => {
validator: (value) => {
// value must be one of TYPES
return TYPES.indexOf(value) !== -1;
}
}
},
},
},
mixins: [me],
components: {
EyeIcon,
ClosedEyeIcon
ClosedEyeIcon,
},
computed: {
hidden() {
return hidden({ type: this.type, block: this.block, schoolClass: this.schoolClass });
}
},
},
methods: {
@ -61,16 +53,18 @@
const hidden = !this.hidden;
const schoolClassId = this.schoolClass.id;
const visibility = [{
const visibility = [
{
schoolClassId,
hidden
}];
hidden,
},
];
const { mutation, variables } = createVisibilityMutation(this.type, this.block.id, visibility);
this.$apollo.mutate({
mutation,
variables
variables,
});
},
},

View File

@ -1,56 +1,29 @@
<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__info">
<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">
mySkillbox ist ein Angebot des hep Verlags in
Zusammenarbeit mit der Eidgenössischen Hochschule für Berufsbildung (EHB).
mySkillbox ist ein Angebot des hep Verlags in Zusammenarbeit mit der Eidgenössischen Hochschule für
Berufsbildung (EHB).
</p>
</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" />
</a>
<a
href="https://www.ehb.swiss/"
target="_blank"
>
<a href="https://www.ehb.swiss/" target="_blank">
<ehb-logo class="default-footer__logo-ehb" />
</a>
</div>
</div>
<div class="default-footer__section">
<div class="default-footer__links">
<a
href="https://myskillbox.ch/datenschutz"
target="_blank"
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>
<a href="https://myskillbox.ch/datenschutz" target="_blank" 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>
</footer>
@ -65,14 +38,14 @@
export default {
components: {
HepLogo,
EhbLogo
}
EhbLogo,
},
};
</script>
<style scoped lang="scss">
@import "@/styles/_variables.scss";
@import "@/styles/_mixins.scss";
@import '@/styles/_variables.scss';
@import '@/styles/_mixins.scss';
.default-footer {
background-color: $color-silver-light;

View File

@ -1,12 +1,6 @@
<template>
<div
:class="specialContainerClass"
class="container layout layout--fullscreen"
>
<div
class="close-button"
@click="back"
>
<div :class="specialContainerClass" class="container layout layout--fullscreen">
<div class="close-button" @click="back">
<cross class="close-button__icon" />
</div>
@ -20,25 +14,25 @@
export default {
components: {
Cross
Cross,
},
computed: {
specialContainerClass() {
let cls = this.$store.state.specialContainerClass;
return [cls ? `skillbox--${cls}` : ''];
}
},
},
methods: {
back() {
this.$router.go(-1);
}
}
},
},
};
</script>
<style lang="scss" scoped>
@import "@/styles/_default-layout.scss";
@import '@/styles/_default-layout.scss';
.close-button {
margin-top: $medium-spacing;
@ -49,5 +43,4 @@
display: flex;
justify-content: flex-end;
}
</style>

View File

@ -1,18 +1,12 @@
<template>
<div class="layout layout--public public">
<div class="public__logo">
<router-link
:to="{name: 'hello'}"
class="hep-link"
>
<router-link :to="{ name: 'hello' }" class="hep-link">
<logo />
</router-link>
</div>
<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>
</template>
@ -24,15 +18,15 @@
export default {
components: {
Logo,
DefaultFooter
DefaultFooter,
},
};
</script>
<style lang="scss" scoped>
@import "@/styles/_variables.scss";
@import "@/styles/_mixins.scss";
@import "@/styles/_default-layout.scss";
@import '@/styles/_variables.scss';
@import '@/styles/_mixins.scss';
@import '@/styles/_default-layout.scss';
@mixin content-block {
padding-right: $medium-spacing;
@ -51,7 +45,7 @@
}
.public {
grid-template-areas: "h" "c" "f";
grid-template-areas: 'h' 'c' 'f';
&__content {
@include content-block();
@ -61,7 +55,7 @@
&__logo {
@include content-block();
margin-top: $medium-spacing
margin-top: $medium-spacing;
}
&__footer {

View File

@ -1,19 +1,10 @@
<template>
<div
:class="{'layout--full-width': $route.meta.fullWidth}"
class="skillbox layout layout--simple"
>
<div
class="close-button"
@click="back"
>
<div :class="{ 'layout--full-width': $route.meta.fullWidth }" class="skillbox layout layout--simple">
<div class="close-button" @click="back">
<cross class="close-button__icon" />
</div>
<router-view class="layout__content" />
<simple-footer
class="layout__footer"
v-if="enableFooter"
/>
<simple-footer class="layout__footer" v-if="enableFooter" />
</div>
</template>
@ -25,7 +16,7 @@
export default {
components: {
Cross,
SimpleFooter
SimpleFooter,
},
computed: {
@ -34,19 +25,19 @@
return false;
}
return this.$flavor.showFooter;
}
},
},
methods: {
back() {
this.$router.go(-1);
}
}
},
},
};
</script>
<style lang="scss" scoped>
@import "~styles/helpers";
@import '~styles/helpers';
.layout {
&--simple {

View File

@ -24,7 +24,7 @@
contents: ContentsIllustration,
portfolio: PortfolioIllustration,
rooms: RoomsIllustration,
hello: Hello
hello: Hello,
},
computed: {
@ -32,14 +32,16 @@
return this.$route.meta.illustration;
},
illustrationAlignment() {
return this.$route.meta.illustrationAlign ? `split-view__illustration--${this.$route.meta.illustrationAlign}` : '';
}
return this.$route.meta.illustrationAlign
? `split-view__illustration--${this.$route.meta.illustrationAlign}`
: '';
},
},
};
</script>
<style lang="scss">
@import "~styles/helpers";
@import '~styles/helpers';
.split-view {
background-color: $color-brand;

View File

@ -126,7 +126,8 @@
const redirectUrl = this.$route.query.redirect ? this.$route.query.redirect : '/';
this.$apollo.mutate({
this.$apollo
.mutate({
client: 'publicClient',
mutation: BETA_LOGIN_MUTATION,
variables,
@ -141,7 +142,8 @@
this.loginError = 'Es ist ein Fehler aufgetreten. Bitte versuchen Sie nochmals.';
}
},
}).catch(error => {
})
.catch((error) => {
const firstError = error.graphQLErrors[0];
switch (firstError.message) {
case 'invalid_credentials':
@ -158,7 +160,7 @@
</script>
<style scoped lang="scss">
@import "~styles/helpers";
@import '~styles/helpers';
.text-link {
font-family: $sans-serif-font-family;
@ -166,7 +168,6 @@
}
.actions {
display: flex;
justify-content: space-between;
@ -177,5 +178,4 @@
line-height: 19px;
}
}
</style>

View File

@ -1,10 +1,5 @@
<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>
<script>
@ -27,6 +22,7 @@
default: ''
}
},
},
components: {
ContentBlockForm,
@ -36,8 +32,8 @@
contentBlock: {
title: '',
isAssignment: false,
contents: [
]},
contents: [],
},
}),
methods: {
@ -53,33 +49,35 @@
if (after) {
input = {
contentBlock,
after
after,
};
} else {
input = {
contentBlock,
parent
parent,
};
}
this.$apollo.mutate({
this.$apollo
.mutate({
mutation: NEW_CONTENT_BLOCK_MUTATION,
variables: {
input
input,
},
refetchQueries: [{
refetchQueries: [
{
query: MODULE_DETAILS_QUERY,
variables: {
slug
}
}]
}).then(this.goToModule);
slug,
},
},
],
})
.then(this.goToModule);
},
goToModule() {
// use the history, so the scroll position is preserved
this.$router.go(-1);
}
}
},
},
});
</script>

View File

@ -1,64 +1,39 @@
<template>
<div
class="hello"
data-cy="hello-page"
>
<div class="hello" data-cy="hello-page">
<div class="about">
<div class="about__logos logos">
<a
href="https://www.hep-verlag.ch/"
target="_blank"
>
<a href="https://www.hep-verlag.ch/" target="_blank">
<hep-logo-no-claim class="logos__logo" />
</a>
<a
href="https://www.ehb.swiss/"
target="_blank"
v-if="$flavor.showEHB"
>
<a href="https://www.ehb.swiss/" target="_blank" v-if="$flavor.showEHB">
<ehb-logo class="logos__logo" />
</a>
</div>
<p class="about__text">
<template v-if="$flavor.showEHB">
{{ $flavor.textAppName }} ist ein Angebot des hep Verlags in
Zusammenarbeit mit der Eidgenössischen Hochschule für Berufsbildung (EHB).
</template>
<template v-else>
{{ $flavor.textAppName }} ist ein Angebot des hep Verlags.
{{ $flavor.textAppName }} ist ein Angebot des hep Verlags in Zusammenarbeit mit der Eidgenössischen Hochschule
für Berufsbildung (EHB).
</template>
<template v-else> {{ $flavor.textAppName }} ist ein Angebot des hep Verlags. </template>
</p>
</div>
<logo class="logo" />
<div class="login-actions">
<h2
class="login-actions__title"
data-cy="hello-title"
>
<h2 class="login-actions__title" data-cy="hello-title">
Wollen Sie {{ $flavor.textAppName }} im Unterricht verwenden?
</h2>
<a
class="button button--primary button--big actions__submit"
href="/api/oauth/login/"
data-cy="oauth-login"
>Mit hep Konto anmelden</a>
<a class="button button--primary button--big actions__submit" href="/api/oauth/login/" data-cy="oauth-login"
>Mit hep Konto anmelden</a
>
<div class="login-actions__register register">
<p>Haben Sie noch kein hep Konto?</p>
<a
class="hep-link"
href="/api/oauth/login/"
data-cy="oauth-login"
>Jetzt registrieren</a>
<a class="hep-link" href="/api/oauth/login/" data-cy="oauth-login">Jetzt registrieren</a>
</div>
</div>
<div class="information">
<p>Was ist ein hep Konto und wie kann ich mich dafür registrieren?</p>
<a
class="hep-link"
href="https://myskillbox.ch/anleitung"
data-cy="oauth-login"
>Anleitung anschauen</a>
<a class="hep-link" href="https://myskillbox.ch/anleitung" data-cy="oauth-login">Anleitung anschauen</a>
</div>
<div class="links">
<ul class="links__list">
@ -86,22 +61,21 @@
components: {
HepLogoNoClaim,
EhbLogo,
Logo
Logo,
},
data() {
return {
email: '',
submitted: false,
loading: false
loading: false,
};
},
};
</script>
<style scoped lang="scss">
@import "~styles/helpers";
@import '~styles/helpers';
$hello-block-margin: 2 * $medium-spacing;
@ -163,7 +137,8 @@
&__register {
margin-top: $large-spacing;
> p, a {
> p,
a {
@include regular-text;
}
}
@ -171,7 +146,8 @@
.information {
margin-top: $hello-block-margin;
> p, a {
> p,
a {
@include regular-text;
}
}
@ -181,7 +157,6 @@
display: flex;
&__list-item {
color: $color-silver-dark;
> a {
@ -205,5 +180,4 @@
}
}
}
</style>

View File

@ -88,9 +88,10 @@ export default {
display: grid;
@include desktop {
grid-template-columns: 300px auto;
}
grid-column-gap: $small-spacing;
}grid-column-gap: $small-spacing;
padding: 0 $small-spacing;
box-sizing: border-box;
&__list {

View File

@ -2,8 +2,7 @@
<div class="license-activation public-page">
<header class="info-header">
<p class="info-header__text small-emph">
Für <span class="info-header__emph">{{ me.email }}</span> haben wir keine
gültige Lizenz gefunden
Für <span class="info-header__emph">{{ me.email }}</span> haben wir keine gültige Lizenz gefunden
</p>
</header>
<section class="coupon">
@ -67,16 +66,10 @@
<h2>Oder, kaufen Sie eine Lizenz</h2>
<ul class="license-links">
<li class="license-links__item">
<a
:href="teacherEditionUrl"
class="hep-link"
>{{ $flavor.textAppName }} für Lehrpersonen</a>
<a :href="teacherEditionUrl" class="hep-link">{{ $flavor.textAppName }} für Lehrpersonen</a>
</li>
<li class="license-links__item">
<a
:href="studentEditionUrl"
class="hep-link"
>{{ $flavor.textAppName }} für Lernende</a>
<a :href="studentEditionUrl" class="hep-link">{{ $flavor.textAppName }} für Lernende</a>
</li>
</ul>
</section>
@ -130,32 +123,33 @@
console.log('coupon', couponCode);
this.submitted = true;
this.loading = true;
this.$apollo.mutate({
this.$apollo
.mutate({
mutation: REDEEM_COUPON,
variables: {
input: {
couponCode
},
},
update: (
store,
{
data: {coupon},
},
) => {
update: (store, { data: { coupon } }) => {
if (coupon.success) {
this.couponErrors = [];
this.$apollo.query({
this.$apollo
.query({
query: ME_QUERY,
fetchPolicy: 'network-only',
}).then(() => this.$router.push('/'));
})
.then(() => this.$router.push('/'));
}
},
}).catch(({message}) => {
})
.catch(({ message }) => {
if (message.indexOf('invalid_coupon') > -1) {
this.couponErrors = ['Der angegebene Coupon-Code ist ungültig.'];
} else {
this.couponErrors = ['Es ist ein Fehler aufgetreten. Bitte versuchen Sie es nochmals oder kontaktieren Sie den Administrator.'];
this.couponErrors = [
'Es ist ein Fehler aufgetreten. Bitte versuchen Sie es nochmals oder kontaktieren Sie den Administrator.',
];
}
})
.finally(() => {
@ -167,7 +161,7 @@
</script>
<style scoped lang="scss">
@import "~styles/helpers";
@import '~styles/helpers';
.text-link {
font-family: $sans-serif-font-family;
@ -182,7 +176,7 @@
}
.get-license {
margin-top: $large-spacing
margin-top: $large-spacing;
}
.license-links {
@ -190,5 +184,4 @@
margin-bottom: $medium-spacing;
}
}
</style>

View File

@ -1,8 +1,6 @@
<template>
<div class="module-visibility">
<h1 class="module-visibility__page-title">
Sichtbarkeit
</h1>
<h1 class="module-visibility__page-title">Sichtbarkeit</h1>
<div class="module-visibility__section">
<p class="module-visibility__paragraph">
Wollen Sie die angepasste Sichtbarkeit (
@ -18,28 +16,15 @@
class="skillbox-input skillbox-dropdown module-visibility__dropdown"
@change="select($event.target.value)"
>
<option
value=""
selected
>
-
</option>
<option
:value="schoolClass.id"
v-for="schoolClass in schoolClasses"
:key="schoolClass.id"
>
<option value="" selected>-</option>
<option :value="schoolClass.id" v-for="schoolClass in schoolClasses" :key="schoolClass.id">
{{ schoolClass.name }}
</option>
</select>
für {{ currentClassName }} übernehmen.
</div>
<div class="module-visibility__section">
<a
class="button button--primary"
data-cy="save-visibility-button"
@click="sync"
>Anpassungen übernehmen</a>
<a class="button button--primary" data-cy="save-visibility-button" @click="sync">Anpassungen übernehmen</a>
</div>
</div>
</template>
@ -55,7 +40,6 @@
const EyeIcon = defineAsyncComponent(() => import(/* webpackChunkName: "icons" */ '@/components/icons/EyeIcon'));
export default {
mixins: [me],
components: {
EyeIcon,
@ -69,11 +53,11 @@
computed: {
schoolClasses() {
return this.me.schoolClasses.filter(schoolClass => schoolClass.id !== this.me.selectedClass.id);
return this.me.schoolClasses.filter((schoolClass) => schoolClass.id !== this.me.selectedClass.id);
},
slug() {
return this.$route.params.slug;
}
},
},
methods: {
@ -83,7 +67,8 @@
sync() {
if (this.selectedClassId) {
const slug = this.slug;
this.$apollo.mutate({
this.$apollo
.mutate({
mutation: SYNC_VISIBILITY_MUTATION,
variables: {
input: {
@ -100,13 +85,13 @@
},
},
],
},
).then(() => {
})
.then(() => {
this.$router.push({
name: MODULE_PAGE,
params: {
slug
}
slug,
},
});
});
}

View File

@ -1,13 +1,9 @@
<template>
<div>
<logo class="onboarding__logo" />
<h1 class="onboarding__heading">
Herzlich willkommen!
</h1>
<h1 class="onboarding__heading">Herzlich willkommen!</h1>
<p class="onboarding__claim">
Schauen Sie sich die Einführung an und lernen Sie {{ $flavor.textAppName }} kennen.
</p>
<p class="onboarding__claim">Schauen Sie sich die Einführung an und lernen Sie {{ $flavor.textAppName }} kennen.</p>
</div>
</template>
@ -17,7 +13,7 @@
export default {
components: {
Logo
Logo,
},
};
</script>

View File

@ -140,8 +140,7 @@ export default {
't t'
'd d'
'm m';
}
}
}}
&__back {
grid-area: b;
@ -155,10 +154,8 @@ export default {
grid-area: a;
display: flex;
@include desktop {
justify-self: end;
}
}
@include desktop {justify-self: end;
}}
&__more {
display: none;
@ -198,17 +195,15 @@ export default {
display: flex;
flex-direction: column;
margin-bottom: $medium-spacing;
@include desktop {
flex-direction: row-reverse;
align-items: center;
margin-bottom: $medium-spacing;@include desktop {
flex-direction: row-reverse;align-items: center;
margin-bottom: 0;
}
justify-content: flex-start;
position: relative;
& > :first-child {
margin-bottom: $medium-spacing;
& > :first-child {margin-bottom: $medium-spacing;
@include desktop {
margin-left: $large-spacing;
margin-bottom: 0;
@ -216,11 +211,9 @@ export default {
}
& > :nth-child(2) {
@include desktop {
margin-left: $large-spacing;
}
}
@include desktop {margin-left: $large-spacing;
}
}}
&__content {
display: flex;

View File

@ -1,11 +1,5 @@
<template>
<content-block-form
:content-block="roomEntry"
:features="features"
v-if="roomEntry.id"
@save="save"
@back="goBack"
/>
<content-block-form :content-block="roomEntry" :features="features" v-if="roomEntry.id" @save="save" @back="goBack" />
</template>
<script>
@ -30,6 +24,7 @@
required: true
}
},
},
components: {
ContentBlockForm,
@ -50,10 +45,10 @@
query: ROOM_ENTRY_QUERY,
variables() {
return {
slug: this.entrySlug
slug: this.entrySlug,
};
}
}
},
},
},
methods: {
@ -61,8 +56,8 @@
this.$router.push({
name: ROOM_PAGE,
params: {
slug: this.slug
}
slug: this.slug,
},
});
},
save({ title, contents }) {
@ -71,14 +66,22 @@
title,
contents,
};
this.$apollo.mutate({
this.$apollo
.mutate({
mutation: UPDATE_ROOM_ENTRY_MUTATION,
variables: {
input: {
roomEntry: entry,
}
},
update: (store, {data: {updateRoomEntry: {roomEntry}}}) => {
},
update: (
store,
{
data: {
updateRoomEntry: { roomEntry },
},
}
) => {
try {
const fragment = ROOM_ENTRY_FRAGMENT;
const id = store.identify(roomEntry);
@ -87,24 +90,21 @@
store.writeFragment({
id,
fragment,
data
data,
});
} catch (e) {
// Query did not exist in the cache, and apollo throws a generic Error. Do nothing
}
}
}).then(() => {
},
})
.then(() => {
this.goBack();
});
}
},
},
});
</script>
<style scoped lang="scss">
@import '~styles/helpers';
</style>

View File

@ -1,10 +1,5 @@
<template>
<content-block-form
:content-block="roomEntry"
:features="features"
@save="save"
@back="goBack"
/>
<content-block-form :content-block="roomEntry" :features="features" @save="save" @back="goBack" />
</template>
<script>
@ -21,8 +16,8 @@
props: {
slug: {
type: String,
required: true
}
required: true,
},
},
components: {
@ -44,24 +39,32 @@
this.$router.push({
name: ROOM_PAGE,
params: {
slug: this.slug
}
slug: this.slug,
},
});
},
save({ title, contents }) {
const entry = {
title,
contents,
roomSlug: this.slug
roomSlug: this.slug,
};
this.$apollo.mutate({
this.$apollo
.mutate({
mutation: NEW_ROOM_ENTRY_MUTATION,
variables: {
input: {
roomEntry: entry,
}
},
update: (store, {data: {addRoomEntry: {roomEntry}}}) => {
},
update: (
store,
{
data: {
addRoomEntry: { roomEntry },
},
}
) => {
try {
const query = ROOM_ENTRIES_QUERY;
const variables = { slug: this.slug };
@ -69,39 +72,33 @@
if (room && room.roomEntries) {
const newEdge = {
node: roomEntry,
__typename: 'RoomEntryNodeEdge'
__typename: 'RoomEntryNodeEdge',
};
const edges = [
newEdge,
...room.roomEntries.edges
];
const edges = [newEdge, ...room.roomEntries.edges];
const data = {
room: {
...room,
roomEntries: {
...room.roomEntries,
edges
}
}
edges,
},
},
};
store.writeQuery({ query, variables, data });
}
} catch (e) {
// Query did not exist in the cache, and apollo throws a generic Error. Do nothing
}
}
}).then(() => {
},
})
.then(() => {
this.goBack();
});
}
},
},
});
</script>
<style scoped lang="scss">
@import '~styles/helpers';
</style>

View File

@ -17,12 +17,7 @@
:key="index"
/>
</div>
<router-link
:to="topicRoute"
class="button"
>
Alle {{ $flavor.textModules }} anzeigen
</router-link>
<router-link :to="topicRoute" class="button"> Alle {{ $flavor.textModules }} anzeigen </router-link>
</div>
<div class="start-page__news news" data-cy="news-teasers" v-if="!me.readOnly">
<h2 class="start-page__heading">News</h2>

View File

@ -14,8 +14,7 @@
<script>
import '@/styles/survey.modern.css';
import '@/styles/survey.reset.css';
import { css } from '@/survey.config';
import '@/styles/survey.reset.css';import { css } from '@/survey.config';
import gql from 'graphql-tag';
import { Model , StylesManager } from 'survey-knockout';
// we are switching to the knockout version because the Vue version only works with Vue 2 (as of July 2022)
@ -35,7 +34,8 @@ const Solution = defineAsyncComponent(() =>
*/ '@/components/content-blocks/Solution'
)
);
StylesManager.applyTheme('modern');
StylesManager.applyTheme('modern')
);
const MODULE_QUERY = gql`
query ModuleSolutions($slug: String) {
@ -56,8 +56,7 @@ export default {
return {
survey: this.initSurvey(),
currentPage: null,
surveyData: null,
title: '',
surveyData: null,title: '',
module: {},
completed: false,
me: {
@ -115,15 +114,14 @@ export default {
}
},
destroyed() {},
methods: {
destroyed() {},methods: {
initSurvey(data, answers) {
let survey = new Model(data);
const flatAnswers = {};
for (let k in answers) {
flatAnswers[k] = answers[k].answer;
}
if (Object.keys(flatAnswers).length > 0) {
// answers are not empty
survey.data = flatAnswers;
@ -215,6 +213,7 @@ export default {
survey.locale = 'de';
survey.showProgressBar = 'bottom';
survey.pageNextText = 'Speichern & Weiter';
survey.render('survey');
return survey;
},

View File

@ -5,21 +5,14 @@
</div>
<div class="topic__content">
<h1
data-cy="topic-title"
class="topic__title"
>
<h1 data-cy="topic-title" class="topic__title">
{{ topic.title }}
</h1>
<p class="topic__teaser">
{{ topic.teaser }}
</p>
<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" />
<span class="topic__link-description">Video schauen</span>
</div>
@ -34,10 +27,7 @@
</a>
</div>
<div class="topic__modules">
<module-teaser
v-for="module in modules"
v-bind="module"
:key="module.slug"
<module-teaser v-for="module in modules" v-bind="module" :key="module.slug"
/>
</div>
</div>
@ -57,7 +47,6 @@
const BulbIcon = defineAsyncComponent(() => import(/* webpackChunkName: "icons" */ '@/components/icons/BulbIcon'));
export default {
mixins: [me],
components: {
TopicNavigation,
@ -104,7 +93,8 @@
},
mounted() {
if (!this.topic.id) { // component was loaded before topic, apollo not ready yet
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);
@ -126,7 +116,14 @@
id: topicId,
},
},
update(store, {data: {updateLastTopic: {topic}}}) {
update(
store,
{
data: {
updateLastTopic: { topic },
},
}
) {
if (topic) {
const query = ME_QUERY;
const { me } = store.readQuery({ query });
@ -148,8 +145,8 @@
</script>
<style scoped lang="scss">
@import "@/styles/_variables.scss";
@import "@/styles/_mixins.scss";
@import '@/styles/_variables.scss';
@import '@/styles/_mixins.scss';
.topic {
display: grid;

View File

@ -18,19 +18,19 @@ class ModalStore {
}
interface Modal {
state: any,
component: string,
payload?: any,
confirm: (res: any) => void,
open: (component: string, payload?: any) => Promise<(resolve: () => any, reject: () => any) => void>,
cancel: () => void,
_resolve: (r?: any) => any,
_reject: (r?: any) => any
state: any;
component: string;
payload?: any;
confirm: (res: any) => void;
open: (component: string, payload?: any) => Promise<(resolve: () => any, reject: () => any) => void>;
cancel: () => void;
_resolve: (r?: any) => any;
_reject: (r?: any) => any;
}
declare module '@vue/runtime-core' {
interface ComponentCustomProperties {
$modal: Modal
$modal: Modal;
}
}

View File

@ -1,4 +1,4 @@
import {RouteLocationNormalized} from "vue-router";
import { RouteLocationNormalized } from 'vue-router';
function getCookieValue(cookieName: string) {
// https://stackoverflow.com/questions/5639346/what-is-the-shortest-function-for-reading-a-cookie-by-name-in-javascript

View File

@ -74,7 +74,7 @@ const routes = [
},
{
path: '/oauth-redirect',
redirect: to => {
redirect: (to) => {
switch (to.query.state) {
case EMAIL_NOT_VERIFIED_STATE:
return '/verify-email';
@ -96,11 +96,11 @@ const routes = [
{
path: '/not-found',
name: 'not-found',
...notFoundRoute
...notFoundRoute,
},
{
path: '/:pathMatch(.*)*',
...notFoundRoute
...notFoundRoute,
},
];

View File

@ -10,4 +10,3 @@ declare module '*.vue' {
const component: DefineComponent<{}, {}, any>;
export default component;
}

View File

@ -92,7 +92,13 @@
height: 100%;
> span {
position: absolute;
width: 100%;
text-align: right;
bottom: -2em;
@include regular-text;
}
}
&__error {

Some files were not shown because too many files have changed in this diff Show More