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:
parent
4b55f8952c
commit
a52671fd40
|
|
@ -1 +1,3 @@
|
|||
bundle-analysis
|
||||
dist
|
||||
node_modules
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import module from '../../../fixtures/module.minimal';
|
||||
import {getMinimalMe} from '../../../support/helpers';
|
||||
import {hasOperationName} from '../../../support/graphql';
|
||||
import { getMinimalMe } from '../../../support/helpers';
|
||||
import { hasOperationName } from '../../../support/graphql';
|
||||
|
||||
let snapshotTitle;
|
||||
let deleteSuccess;
|
||||
|
|
@ -133,7 +133,7 @@ describe('Snapshot', () => {
|
|||
},
|
||||
},
|
||||
},
|
||||
MeQuery: getMinimalMe({isTeacher}),
|
||||
MeQuery: getMinimalMe({ isTeacher }),
|
||||
ModuleDetailsQuery: {
|
||||
module,
|
||||
},
|
||||
|
|
@ -219,9 +219,11 @@ 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.get('.snapshots__snapshot').should('have.length', 1);
|
||||
});
|
||||
cy.getByDataCy('snapshot-list')
|
||||
.should('exist')
|
||||
.within(() => {
|
||||
cy.get('.snapshots__snapshot').should('have.length', 1);
|
||||
});
|
||||
waitNTimes(7);
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
describe('Room Team Management - Read only', () => {
|
||||
const SELECTED_CLASS_ID = 'selectedClassId';
|
||||
|
||||
const getOperations = ({readOnly, classReadOnly}) => ({
|
||||
const getOperations = ({ readOnly, classReadOnly }) => ({
|
||||
MeQuery: {
|
||||
me: {
|
||||
readOnly,
|
||||
|
|
@ -13,23 +13,25 @@ describe('Room Team Management - Read only', () => {
|
|||
},
|
||||
},
|
||||
RoomsQuery: {
|
||||
rooms: [{
|
||||
id: '',
|
||||
slug: 'some-room',
|
||||
title: 'some room',
|
||||
entryCount: 3,
|
||||
appearance: 'red',
|
||||
description: 'some description',
|
||||
schoolClass: {
|
||||
id: SELECTED_CLASS_ID,
|
||||
name: 'bla',
|
||||
rooms: [
|
||||
{
|
||||
id: '',
|
||||
slug: 'some-room',
|
||||
title: 'some room',
|
||||
entryCount: 3,
|
||||
appearance: 'red',
|
||||
description: 'some description',
|
||||
schoolClass: {
|
||||
id: SELECTED_CLASS_ID,
|
||||
name: 'bla',
|
||||
},
|
||||
},
|
||||
}],
|
||||
],
|
||||
},
|
||||
});
|
||||
|
||||
const checkRoomsReadOnly = ({editable, readOnly, classReadOnly = false}) => {
|
||||
const operations = getOperations({readOnly, classReadOnly});
|
||||
const checkRoomsReadOnly = ({ editable, readOnly, classReadOnly = false }) => {
|
||||
const operations = getOperations({ readOnly, classReadOnly });
|
||||
|
||||
cy.mockGraphqlOps({
|
||||
operations,
|
||||
|
|
@ -48,14 +50,14 @@ describe('Room Team Management - Read only', () => {
|
|||
});
|
||||
|
||||
it('can edit room', () => {
|
||||
checkRoomsReadOnly({editable: true, readOnly: false});
|
||||
checkRoomsReadOnly({ editable: true, readOnly: false });
|
||||
});
|
||||
|
||||
it('can not edit room', () => {
|
||||
checkRoomsReadOnly({editable: false, readOnly: true});
|
||||
checkRoomsReadOnly({ editable: false, readOnly: true });
|
||||
});
|
||||
|
||||
it('can not edit room of inactive class', () => {
|
||||
checkRoomsReadOnly({editable: false, readOnly: false, classReadOnly: true});
|
||||
checkRoomsReadOnly({ editable: false, readOnly: false, classReadOnly: true });
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -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/',
|
||||
|
|
|
|||
|
|
@ -3,6 +3,9 @@
|
|||
"version": "1.0.0",
|
||||
"description": "skillbox vue client",
|
||||
"author": "ramon / chrigu",
|
||||
"prettier": {
|
||||
"singleQuote": true
|
||||
},
|
||||
"private": true,
|
||||
"prettier": {
|
||||
"singleQuote": true
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
@ -18,88 +15,88 @@
|
|||
|
||||
const AddPointer = defineAsyncComponent(() => import(/* webpackChunkName: "icons" */'@/components/icons/AddPointer'));
|
||||
|
||||
export default {
|
||||
props: {
|
||||
where: {
|
||||
type: Object,
|
||||
validator(prop) {
|
||||
return Object.prototype.hasOwnProperty.call(prop, 'after' )
|
||||
|| Object.prototype.hasOwnProperty.call(prop, 'parent');
|
||||
}
|
||||
export default {
|
||||
props: {
|
||||
where: {
|
||||
type: Object,
|
||||
validator(prop) {
|
||||
return (
|
||||
Object.prototype.hasOwnProperty.call(prop, 'after') || Object.prototype.hasOwnProperty.call(prop, 'parent')
|
||||
);
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
components: {
|
||||
AddPointer
|
||||
components: {
|
||||
AddPointer,
|
||||
},
|
||||
|
||||
computed: {
|
||||
parent() {
|
||||
return this.where.parent;
|
||||
},
|
||||
|
||||
computed: {
|
||||
parent() {
|
||||
return this.where.parent;
|
||||
},
|
||||
after() {
|
||||
return this.where.after;
|
||||
},
|
||||
isObjectiveGroup() {
|
||||
return this.parent && this.parent.__typename === 'ObjectiveGroupNode';
|
||||
},
|
||||
slug() {
|
||||
return this.$route.params.slug;
|
||||
}
|
||||
after() {
|
||||
return this.where.after;
|
||||
},
|
||||
isObjectiveGroup() {
|
||||
return this.parent && this.parent.__typename === 'ObjectiveGroupNode';
|
||||
},
|
||||
slug() {
|
||||
return this.$route.params.slug;
|
||||
},
|
||||
},
|
||||
|
||||
|
||||
methods: {
|
||||
addContent() {
|
||||
if (this.isObjectiveGroup) {
|
||||
this.$modal.open('new-objective-wizard', {parent: this.parent.id});
|
||||
methods: {
|
||||
addContent() {
|
||||
if (this.isObjectiveGroup) {
|
||||
this.$modal.open('new-objective-wizard', { parent: this.parent.id });
|
||||
} else {
|
||||
let route;
|
||||
if (this.after && this.after.id) {
|
||||
route = {
|
||||
name: CREATE_CONTENT_BLOCK_AFTER_PAGE,
|
||||
params: {
|
||||
after: this.after.id,
|
||||
slug: this.slug,
|
||||
},
|
||||
};
|
||||
} else {
|
||||
let route;
|
||||
if (this.after && this.after.id) {
|
||||
route = {
|
||||
name: CREATE_CONTENT_BLOCK_AFTER_PAGE,
|
||||
params: {
|
||||
after: this.after.id,
|
||||
slug: this.slug
|
||||
}
|
||||
};
|
||||
} else {
|
||||
route = {
|
||||
name: CREATE_CONTENT_BLOCK_UNDER_PARENT_PAGE,
|
||||
params: {
|
||||
parent: this.parent.id
|
||||
}
|
||||
};
|
||||
}
|
||||
this.$router.push(route);
|
||||
route = {
|
||||
name: CREATE_CONTENT_BLOCK_UNDER_PARENT_PAGE,
|
||||
params: {
|
||||
parent: this.parent.id,
|
||||
},
|
||||
};
|
||||
}
|
||||
this.$router.push(route);
|
||||
}
|
||||
}
|
||||
};
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import "~styles/helpers";
|
||||
@import '~styles/helpers';
|
||||
|
||||
.add-content {
|
||||
display: none;
|
||||
position: relative;
|
||||
@include desktop {
|
||||
display: flex;
|
||||
}
|
||||
z-index: 1;
|
||||
|
||||
justify-content: flex-end;
|
||||
|
||||
&__button {
|
||||
margin-right: -85px;
|
||||
cursor: pointer;
|
||||
display: inline-grid;
|
||||
}
|
||||
|
||||
&__icon {
|
||||
width: 40px;
|
||||
fill: $color-silver-dark;
|
||||
}
|
||||
.add-content {
|
||||
display: none;
|
||||
position: relative;
|
||||
@include desktop {
|
||||
display: flex;
|
||||
}
|
||||
z-index: 1;
|
||||
|
||||
justify-content: flex-end;
|
||||
|
||||
&__button {
|
||||
margin-right: -85px;
|
||||
cursor: pointer;
|
||||
display: inline-grid;
|
||||
}
|
||||
|
||||
&__icon {
|
||||
width: 40px;
|
||||
fill: $color-silver-dark;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
@ -11,32 +8,32 @@
|
|||
import {defineAsyncComponent} from 'vue';
|
||||
const AddIcon = defineAsyncComponent(() => import(/* webpackChunkName: "icons" */'@/components/icons/AddIcon'));
|
||||
|
||||
export default {
|
||||
props: ['index'],
|
||||
export default {
|
||||
props: ['index'],
|
||||
|
||||
components: {
|
||||
AddIcon
|
||||
}
|
||||
};
|
||||
components: {
|
||||
AddIcon,
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import "@/styles/_variables.scss";
|
||||
@import '@/styles/_variables.scss';
|
||||
|
||||
.add-content-element {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
border-bottom: 2px solid $color-silver-dark;
|
||||
margin-bottom: 21px + 25px;
|
||||
cursor: pointer;
|
||||
.add-content-element {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
border-bottom: 2px solid $color-silver-dark;
|
||||
margin-bottom: 21px + 25px;
|
||||
cursor: pointer;
|
||||
|
||||
&__icon {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
fill: $color-silver-dark;
|
||||
margin-bottom: -21px;
|
||||
background-color: $color-white;
|
||||
border-radius: 50px;
|
||||
}
|
||||
&__icon {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
fill: $color-silver-dark;
|
||||
margin-bottom: -21px;
|
||||
background-color: $color-white;
|
||||
border-radius: 50px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -14,66 +14,69 @@
|
|||
import {defineAsyncComponent} from 'vue';
|
||||
const AddIcon = defineAsyncComponent(() => import(/* webpackChunkName: "icons" */'@/components/icons/AddIcon.vue'));
|
||||
|
||||
export default {
|
||||
props: {
|
||||
route: {
|
||||
type: String,
|
||||
default: null
|
||||
},
|
||||
reverse: { // use reverse colors
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
click: {
|
||||
type: Function,
|
||||
default: null
|
||||
}
|
||||
export default {
|
||||
props: {
|
||||
route: {
|
||||
type: String,
|
||||
default: null,
|
||||
},
|
||||
reverse: {
|
||||
// use reverse colors
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
click: {
|
||||
type: Function,
|
||||
default: null,
|
||||
},
|
||||
},
|
||||
|
||||
components: {
|
||||
AddIcon
|
||||
},
|
||||
components: {
|
||||
AddIcon,
|
||||
},
|
||||
|
||||
computed: {
|
||||
component() {
|
||||
// only use the router link if the route prop is provided, otherwise render a normal anchor tag
|
||||
return this.route ? 'router-link' : 'a';
|
||||
},
|
||||
properties() {
|
||||
return this.route ? {
|
||||
to: this.route,
|
||||
tag: 'div'
|
||||
} : {};
|
||||
}
|
||||
computed: {
|
||||
component() {
|
||||
// only use the router link if the route prop is provided, otherwise render a normal anchor tag
|
||||
return this.route ? 'router-link' : 'a';
|
||||
},
|
||||
};
|
||||
properties() {
|
||||
return this.route
|
||||
? {
|
||||
to: this.route,
|
||||
tag: 'div',
|
||||
}
|
||||
: {};
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import "~styles/helpers";
|
||||
@import '~styles/helpers';
|
||||
|
||||
.add-widget {
|
||||
display: none;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
@include widget-shadow;
|
||||
cursor: pointer;
|
||||
.add-widget {
|
||||
display: none;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
@include widget-shadow;
|
||||
cursor: pointer;
|
||||
|
||||
@include desktop {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
&__add {
|
||||
width: 80px;
|
||||
fill: $color-silver-dark;
|
||||
}
|
||||
|
||||
&--reverse {
|
||||
@include widget-shadow-reverse;
|
||||
}
|
||||
|
||||
&--reverse &__add {
|
||||
fill: white;
|
||||
}
|
||||
@include desktop {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
&__add {
|
||||
width: 80px;
|
||||
fill: $color-silver-dark;
|
||||
}
|
||||
|
||||
&--reverse {
|
||||
@include widget-shadow-reverse;
|
||||
}
|
||||
|
||||
&--reverse &__add {
|
||||
fill: white;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
@ -16,25 +13,25 @@
|
|||
|
||||
const ChevronLeft = defineAsyncComponent(() => import(/* webpackChunkName: "icons" */'@/components/icons/ChevronLeft'));
|
||||
|
||||
export default {
|
||||
props: {
|
||||
title: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
type: {
|
||||
type: String,
|
||||
default: 'topic',
|
||||
},
|
||||
slug: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
export default {
|
||||
props: {
|
||||
title: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
type: {
|
||||
type: String,
|
||||
default: 'topic',
|
||||
},
|
||||
slug: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
},
|
||||
|
||||
components: {
|
||||
ChevronLeft,
|
||||
},
|
||||
components: {
|
||||
ChevronLeft,
|
||||
},
|
||||
|
||||
computed: {
|
||||
to() {
|
||||
|
|
@ -68,9 +65,9 @@
|
|||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import '~styles/helpers';
|
||||
@import '~styles/helpers';
|
||||
|
||||
.back-link {
|
||||
@include regular-text;
|
||||
}
|
||||
.back-link {
|
||||
@include regular-text;
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -1,21 +1,15 @@
|
|||
<template>
|
||||
<div class="color-chooser">
|
||||
<div
|
||||
:class="{'color-chooser__color-wrapper--selected': selectedColor === color.name}"
|
||||
:class="{ 'color-chooser__color-wrapper--selected': selectedColor === color.name }"
|
||||
class="color-chooser__color-wrapper"
|
||||
data-cy="color-select"
|
||||
v-for="(color, index) in colors"
|
||||
: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>
|
||||
|
|
@ -25,69 +19,69 @@
|
|||
import {defineAsyncComponent} from 'vue';
|
||||
const Tick = defineAsyncComponent(() => import(/* webpackChunkName: "icons" */'@/components/icons/Tick'));
|
||||
|
||||
export default {
|
||||
props: ['selectedColor'],
|
||||
export default {
|
||||
props: ['selectedColor'],
|
||||
|
||||
components: {
|
||||
Tick
|
||||
},
|
||||
components: {
|
||||
Tick,
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
colors: [
|
||||
{
|
||||
name: 'yellow'
|
||||
},
|
||||
{
|
||||
name: 'blue'
|
||||
},
|
||||
{
|
||||
name: 'red'
|
||||
},
|
||||
{
|
||||
name: 'green'
|
||||
}
|
||||
]
|
||||
};
|
||||
},
|
||||
};
|
||||
data() {
|
||||
return {
|
||||
colors: [
|
||||
{
|
||||
name: 'yellow',
|
||||
},
|
||||
{
|
||||
name: 'blue',
|
||||
},
|
||||
{
|
||||
name: 'red',
|
||||
},
|
||||
{
|
||||
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;
|
||||
.color-chooser {
|
||||
display: flex;
|
||||
|
||||
&__color-wrapper {
|
||||
margin-right: 10px;
|
||||
border-radius: 50px;
|
||||
padding: 10px;
|
||||
&__color-wrapper {
|
||||
margin-right: 10px;
|
||||
border-radius: 50px;
|
||||
padding: 10px;
|
||||
|
||||
&--selected {
|
||||
border: 1px solid $color-charcoal-dark;
|
||||
}
|
||||
}
|
||||
|
||||
&__selected-icon {
|
||||
width: 17px;
|
||||
fill: $color-charcoal-dark;
|
||||
}
|
||||
|
||||
&__color {
|
||||
width: 46px;
|
||||
height: 46px;
|
||||
border-radius: 23px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
@supports (display: grid) {
|
||||
display: grid
|
||||
}
|
||||
justify-items: center;
|
||||
align-items: center;
|
||||
|
||||
@include skillbox-colors;
|
||||
&--selected {
|
||||
border: 1px solid $color-charcoal-dark;
|
||||
}
|
||||
}
|
||||
|
||||
&__selected-icon {
|
||||
width: 17px;
|
||||
fill: $color-charcoal-dark;
|
||||
}
|
||||
|
||||
&__color {
|
||||
width: 46px;
|
||||
height: 46px;
|
||||
border-radius: 23px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
@supports (display: grid) {
|
||||
display: grid;
|
||||
}
|
||||
justify-items: center;
|
||||
align-items: center;
|
||||
|
||||
@include skillbox-colors;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -1,37 +1,38 @@
|
|||
<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'));
|
||||
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')
|
||||
);
|
||||
|
||||
export default {
|
||||
components: {
|
||||
Modal,
|
||||
InfogramBlock,
|
||||
GeniallyBlock
|
||||
export default {
|
||||
components: {
|
||||
Modal,
|
||||
InfogramBlock,
|
||||
GeniallyBlock,
|
||||
},
|
||||
|
||||
computed: {
|
||||
id() {
|
||||
return this.$store.state.infographic.id;
|
||||
},
|
||||
|
||||
computed: {
|
||||
id() {
|
||||
return this.$store.state.infographic.id;
|
||||
},
|
||||
type() {
|
||||
return this.$store.state.infographic.type;
|
||||
},
|
||||
value() {
|
||||
return {
|
||||
id: this.id
|
||||
};
|
||||
}
|
||||
}
|
||||
};
|
||||
type() {
|
||||
return this.$store.state.infographic.type;
|
||||
},
|
||||
value() {
|
||||
return {
|
||||
id: this.id,
|
||||
};
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -1,140 +1,127 @@
|
|||
<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>
|
||||
|
||||
<script>
|
||||
import ContentNavigation from '@/components/book-navigation/ContentNavigation.vue';
|
||||
import UserWidget from '@/components/UserWidget.vue';
|
||||
import CurrentClass from '@/components/school-class/CurrentClass';
|
||||
import ContentNavigation from '@/components/book-navigation/ContentNavigation.vue';
|
||||
import UserWidget from '@/components/UserWidget.vue';
|
||||
import CurrentClass from '@/components/school-class/CurrentClass';
|
||||
|
||||
import openSidebar from '@/mixins/open-sidebar';
|
||||
import me from '@/mixins/me';
|
||||
import {defineAsyncComponent} from 'vue';
|
||||
import openSidebar from '@/mixins/open-sidebar';
|
||||
import me from '@/mixins/me';
|
||||
import { defineAsyncComponent } from 'vue';
|
||||
|
||||
const Hamburger = defineAsyncComponent(() => import(/* webpackChunkName: "icons" */'@/components/icons/Hamburger'));
|
||||
const Hamburger = defineAsyncComponent(() => import(/* webpackChunkName: "icons" */ '@/components/icons/Hamburger'));
|
||||
|
||||
export default {
|
||||
mixins: [openSidebar, me],
|
||||
export default {
|
||||
mixins: [openSidebar, me],
|
||||
|
||||
components: {
|
||||
ContentNavigation,
|
||||
UserWidget,
|
||||
CurrentClass,
|
||||
Hamburger,
|
||||
},
|
||||
};
|
||||
components: {
|
||||
ContentNavigation,
|
||||
UserWidget,
|
||||
CurrentClass,
|
||||
Hamburger,
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import "~styles/helpers";
|
||||
@import '~styles/helpers';
|
||||
|
||||
.header-bar {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
@supports (display: grid) {
|
||||
display: grid;
|
||||
}
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
background-color: $color-white;
|
||||
grid-auto-rows: 50px;
|
||||
width: 100%;
|
||||
max-width: 100vw;
|
||||
.header-bar {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
@supports (display: grid) {
|
||||
display: grid;
|
||||
}
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
background-color: $color-white;
|
||||
grid-auto-rows: 50px;
|
||||
width: 100%;
|
||||
max-width: 100vw;
|
||||
|
||||
grid-template-columns: 1fr 1fr 1fr;
|
||||
grid-template-columns: 1fr 1fr 1fr;
|
||||
|
||||
@include desktop {
|
||||
grid-template-columns: 50px 1fr auto;
|
||||
grid-template-rows: 50px;
|
||||
grid-auto-rows: auto;
|
||||
}
|
||||
@include desktop {
|
||||
grid-template-columns: 50px 1fr auto;
|
||||
grid-template-rows: 50px;
|
||||
grid-auto-rows: auto;
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* For IE10+
|
||||
*/
|
||||
-ms-grid-columns: 1fr 1fr 1fr;
|
||||
-ms-grid-rows: 50px 50px;
|
||||
-ms-grid-columns: 1fr 1fr 1fr;
|
||||
-ms-grid-rows: 50px 50px;
|
||||
|
||||
/*
|
||||
/*
|
||||
* For IE10+
|
||||
*/
|
||||
& > :nth-child(1) {
|
||||
-ms-grid-column: 1;
|
||||
-ms-grid-row-align: center;
|
||||
}
|
||||
& > :nth-child(1) {
|
||||
-ms-grid-column: 1;
|
||||
-ms-grid-row-align: center;
|
||||
}
|
||||
|
||||
&__content-navigation {
|
||||
grid-column: 2;
|
||||
justify-content: space-between;
|
||||
}
|
||||
&__content-navigation {
|
||||
grid-column: 2;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
&__sidebar-link {
|
||||
padding: $small-spacing;
|
||||
cursor: pointer;
|
||||
}
|
||||
&__sidebar-link {
|
||||
padding: $small-spacing;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
&__sidebar-icon {
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
}
|
||||
&__sidebar-icon {
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* For IE10+
|
||||
*/
|
||||
& > :nth-child(3) {
|
||||
-ms-grid-column: 3;
|
||||
-ms-grid-row-align: center;
|
||||
-ms-grid-column-align: end;
|
||||
& > :nth-child(3) {
|
||||
-ms-grid-column: 3;
|
||||
-ms-grid-row-align: center;
|
||||
-ms-grid-column-align: end;
|
||||
|
||||
justify-self: end;
|
||||
}
|
||||
|
||||
& > :nth-child(4) {
|
||||
-ms-grid-row: 2;
|
||||
-ms-grid-column: 1;
|
||||
-ms-grid-column-span: 3;
|
||||
}
|
||||
justify-self: end;
|
||||
}
|
||||
|
||||
.user-header {
|
||||
display: flex;
|
||||
& > :nth-child(4) {
|
||||
-ms-grid-row: 2;
|
||||
-ms-grid-column: 1;
|
||||
-ms-grid-column-span: 3;
|
||||
}
|
||||
}
|
||||
|
||||
&__current-class {
|
||||
margin-right: $large-spacing;
|
||||
}
|
||||
.user-header {
|
||||
display: flex;
|
||||
|
||||
&__sidebar-link {
|
||||
cursor: pointer;
|
||||
display: none;
|
||||
&__current-class {
|
||||
margin-right: $large-spacing;
|
||||
}
|
||||
|
||||
@include desktop {
|
||||
display: flex;
|
||||
}
|
||||
&__sidebar-link {
|
||||
cursor: pointer;
|
||||
display: none;
|
||||
|
||||
@include desktop {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -10,67 +10,66 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import {defineAsyncComponent} from 'vue';
|
||||
const InfoIcon = defineAsyncComponent(() => import(/* webpackChunkName: "icons" */'@/components/icons/InfoIcon'));
|
||||
import { defineAsyncComponent } from 'vue';
|
||||
const InfoIcon = defineAsyncComponent(() => import(/* webpackChunkName: "icons" */ '@/components/icons/InfoIcon'));
|
||||
|
||||
export default {
|
||||
props: ['text'],
|
||||
export default {
|
||||
props: ['text'],
|
||||
|
||||
components: {
|
||||
InfoIcon
|
||||
}
|
||||
};
|
||||
components: {
|
||||
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;
|
||||
.helpful-tooltip {
|
||||
position: relative;
|
||||
|
||||
&__icon {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
fill: $color-silver-dark;
|
||||
}
|
||||
&__icon {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
fill: $color-silver-dark;
|
||||
}
|
||||
|
||||
&__tooltip {
|
||||
visibility: hidden;
|
||||
&__tooltip {
|
||||
visibility: hidden;
|
||||
position: absolute;
|
||||
left: 30px;
|
||||
top: 0px;
|
||||
width: 400px;
|
||||
}
|
||||
|
||||
&__text {
|
||||
display: inline-table;
|
||||
width: auto;
|
||||
|
||||
background-color: $color-white;
|
||||
border: 1px solid $color-silver-dark;
|
||||
border-radius: 5px;
|
||||
padding: $small-spacing;
|
||||
@include small-text;
|
||||
|
||||
&::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
left: 30px;
|
||||
top: 0px;
|
||||
width: 400px;
|
||||
}
|
||||
|
||||
&__text {
|
||||
display: inline-table;
|
||||
width: auto;
|
||||
|
||||
left: 0;
|
||||
top: 18px;
|
||||
margin-left: -1px;
|
||||
border-left: 1px solid $color-silver-dark;
|
||||
border-top: 1px solid $color-silver-dark;
|
||||
background-color: $color-white;
|
||||
border: 1px solid $color-silver-dark;
|
||||
border-radius: 5px;
|
||||
padding: $small-spacing;
|
||||
@include small-text;
|
||||
|
||||
&::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 18px;
|
||||
margin-left: -1px;
|
||||
border-left: 1px solid $color-silver-dark;
|
||||
border-top: 1px solid $color-silver-dark;
|
||||
background-color: $color-white;
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
transform: rotate(-45deg) translateY(-50%);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
&:hover &__tooltip {
|
||||
visibility: visible;
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
transform: rotate(-45deg) translateY(-50%);
|
||||
}
|
||||
}
|
||||
|
||||
&:hover &__tooltip {
|
||||
visibility: visible;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -1,58 +1,54 @@
|
|||
<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'));
|
||||
import { defineAsyncComponent } from 'vue';
|
||||
const LoadingIcon = defineAsyncComponent(() =>
|
||||
import(/* webpackChunkName: "icons" */ '@/components/icons/LoadingIcon')
|
||||
);
|
||||
|
||||
export default {
|
||||
props: {
|
||||
loading: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
label: {
|
||||
type: String,
|
||||
default: ''
|
||||
}
|
||||
export default {
|
||||
props: {
|
||||
loading: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
components: {
|
||||
LoadingIcon
|
||||
}
|
||||
};
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
label: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
},
|
||||
components: {
|
||||
LoadingIcon,
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import "~styles/helpers";
|
||||
@import '~styles/helpers';
|
||||
|
||||
.loading-button {
|
||||
height: 52px;
|
||||
min-width: 100px;
|
||||
display: inline-flex;
|
||||
justify-content: center;
|
||||
.loading-button {
|
||||
height: 52px;
|
||||
min-width: 100px;
|
||||
display: inline-flex;
|
||||
justify-content: center;
|
||||
|
||||
&__icon {
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
margin: 0 auto;
|
||||
@include spin;
|
||||
fill: $color-brand;
|
||||
}
|
||||
&__icon {
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
margin: 0 auto;
|
||||
@include spin;
|
||||
fill: $color-brand;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -4,66 +4,60 @@
|
|||
<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>
|
||||
|
||||
<script>
|
||||
import UserWidget from '@/components/UserWidget';
|
||||
import UserWidget from '@/components/UserWidget';
|
||||
|
||||
import me from '@/mixins/me';
|
||||
import openSidebar from '@/mixins/open-sidebar';
|
||||
import {defineAsyncComponent} from 'vue';
|
||||
import me from '@/mixins/me';
|
||||
import openSidebar from '@/mixins/open-sidebar';
|
||||
import { defineAsyncComponent } from 'vue';
|
||||
|
||||
const Logo = defineAsyncComponent(() => import(/* webpackChunkName: "icons" */'@/components/icons/Logo'));
|
||||
const Hamburger = defineAsyncComponent(() => import(/* webpackChunkName: "icons" */'@/components/icons/Hamburger'));
|
||||
const Logo = defineAsyncComponent(() => import(/* webpackChunkName: "icons" */ '@/components/icons/Logo'));
|
||||
const Hamburger = defineAsyncComponent(() => import(/* webpackChunkName: "icons" */ '@/components/icons/Hamburger'));
|
||||
|
||||
export default {
|
||||
mixins: [me, openSidebar],
|
||||
export default {
|
||||
mixins: [me, openSidebar],
|
||||
|
||||
components: {
|
||||
Logo,
|
||||
Hamburger,
|
||||
UserWidget,
|
||||
components: {
|
||||
Logo,
|
||||
Hamburger,
|
||||
UserWidget,
|
||||
},
|
||||
|
||||
methods: {
|
||||
showMobileNavigation() {
|
||||
this.$store.dispatch('showMobileNavigation', true);
|
||||
},
|
||||
|
||||
methods: {
|
||||
showMobileNavigation() {
|
||||
this.$store.dispatch('showMobileNavigation', true);
|
||||
},
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import "~styles/helpers";
|
||||
@import '~styles/helpers';
|
||||
|
||||
.mobile-header {
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
.mobile-header {
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
|
||||
display: flex;
|
||||
display: flex;
|
||||
|
||||
@include desktop {
|
||||
display: none;
|
||||
}
|
||||
|
||||
padding: 0 $medium-spacing;
|
||||
|
||||
&__hamburger {
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
fill: $color-silver-dark;
|
||||
}
|
||||
@include desktop {
|
||||
display: none;
|
||||
}
|
||||
|
||||
padding: 0 $medium-spacing;
|
||||
|
||||
&__hamburger {
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
fill: $color-silver-dark;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -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--active">Speichern</a>-->
|
||||
<a
|
||||
class="button"
|
||||
@click="hideModal"
|
||||
>Abbrechen</a>
|
||||
<a class="button" @click="hideModal">Abbrechen</a>
|
||||
</slot>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -30,160 +28,159 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import {defineAsyncComponent} from 'vue';
|
||||
const Cross = defineAsyncComponent(() => import(/* webpackChunkName: "icons" */'@/components/icons/CrossIcon'));
|
||||
import { defineAsyncComponent } from 'vue';
|
||||
const Cross = defineAsyncComponent(() => import(/* webpackChunkName: "icons" */ '@/components/icons/CrossIcon'));
|
||||
|
||||
export default {
|
||||
props: {
|
||||
hideHeader: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
fullscreen: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
small: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
export default {
|
||||
props: {
|
||||
hideHeader: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
|
||||
components: {
|
||||
Cross
|
||||
fullscreen: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
small: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
|
||||
methods: {
|
||||
hideModal() {
|
||||
this.$store.dispatch('hideModal');
|
||||
}
|
||||
}
|
||||
};
|
||||
components: {
|
||||
Cross,
|
||||
},
|
||||
|
||||
methods: {
|
||||
hideModal() {
|
||||
this.$store.dispatch('hideModal');
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import "@/styles/_variables.scss";
|
||||
@import '@/styles/_variables.scss';
|
||||
|
||||
.modal {
|
||||
align-self: center;
|
||||
justify-self: center;
|
||||
width: 700px;
|
||||
height: 80vh;
|
||||
background-color: $color-white;
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 2px 8px 0 rgba(0, 0, 0, 0.15);
|
||||
border: 1px solid $color-silver-light;
|
||||
display: -ms-grid;
|
||||
.modal {
|
||||
align-self: center;
|
||||
justify-self: center;
|
||||
width: 700px;
|
||||
height: 80vh;
|
||||
background-color: $color-white;
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 2px 8px 0 rgba(0, 0, 0, 0.15);
|
||||
border: 1px solid $color-silver-light;
|
||||
display: -ms-grid;
|
||||
@supports (display: grid) {
|
||||
display: grid;
|
||||
}
|
||||
grid-template-rows: auto 1fr 65px;
|
||||
grid-template-areas: 'header' 'body' 'footer';
|
||||
-ms-grid-rows: auto 1fr 65px;
|
||||
position: relative;
|
||||
|
||||
&__backdrop {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
@supports (display: grid) {
|
||||
display: grid;
|
||||
}
|
||||
grid-template-rows: auto 1fr 65px;
|
||||
grid-template-areas: "header" "body" "footer";
|
||||
-ms-grid-rows: auto 1fr 65px;
|
||||
position: relative;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
background-color: rgba($color-white, 0.8);
|
||||
z-index: 90;
|
||||
}
|
||||
|
||||
&__backdrop {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
@supports (display: grid) {
|
||||
display: grid;
|
||||
}
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
background-color: rgba($color-white, 0.8);
|
||||
z-index: 90;
|
||||
}
|
||||
&__header {
|
||||
grid-area: header;
|
||||
-ms-grid-row: 1;
|
||||
padding: 10px $modal-lateral-padding;
|
||||
border-bottom: 1px solid $color-silver-light;
|
||||
}
|
||||
|
||||
&__header {
|
||||
grid-area: header;
|
||||
-ms-grid-row: 1;
|
||||
padding: 10px $modal-lateral-padding;
|
||||
border-bottom: 1px solid $color-silver-light;
|
||||
}
|
||||
&__body {
|
||||
grid-area: body;
|
||||
-ms-grid-row: 2;
|
||||
padding: 10px $modal-lateral-padding;
|
||||
overflow: auto;
|
||||
box-sizing: border-box;
|
||||
min-height: 30vh;
|
||||
}
|
||||
|
||||
&__body {
|
||||
grid-area: body;
|
||||
-ms-grid-row: 2;
|
||||
padding: 10px $modal-lateral-padding;
|
||||
overflow: auto;
|
||||
box-sizing: border-box;
|
||||
min-height: 30vh;
|
||||
}
|
||||
&__close-button {
|
||||
display: none;
|
||||
cursor: pointer;
|
||||
position: absolute;
|
||||
right: 15px;
|
||||
top: 15px;
|
||||
background: rgba($color-white, 0.5);
|
||||
border-radius: 40px;
|
||||
padding: 10px;
|
||||
align-content: center;
|
||||
}
|
||||
|
||||
&__close-button {
|
||||
&__footer {
|
||||
grid-area: footer;
|
||||
-ms-grid-row: 3;
|
||||
border-top: 1px solid $color-silver-light;
|
||||
padding: 16px $modal-lateral-padding;
|
||||
}
|
||||
|
||||
$parent: &;
|
||||
|
||||
&--hide-header {
|
||||
grid-template-rows: 1fr 65px;
|
||||
grid-template-areas: 'body' 'footer';
|
||||
|
||||
#{$parent}__header {
|
||||
display: none;
|
||||
cursor: pointer;
|
||||
position: absolute;
|
||||
right: 15px;
|
||||
top: 15px;
|
||||
background: rgba($color-white, 0.5);
|
||||
border-radius: 40px;
|
||||
padding: 10px;
|
||||
align-content: center;
|
||||
}
|
||||
|
||||
&__footer {
|
||||
grid-area: footer;
|
||||
-ms-grid-row: 3;
|
||||
border-top: 1px solid $color-silver-light;
|
||||
padding: 16px $modal-lateral-padding;
|
||||
}
|
||||
|
||||
$parent: &;
|
||||
|
||||
&--hide-header {
|
||||
grid-template-rows: 1fr 65px;
|
||||
grid-template-areas: "body" "footer";
|
||||
|
||||
#{$parent}__header {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#{$parent}__body {
|
||||
padding: $default-padding;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
&--fullscreen {
|
||||
width: 95vw;
|
||||
height: auto;
|
||||
grid-template-rows: 1fr;
|
||||
-ms-grid-rows: 1fr;
|
||||
grid-template-areas: "body";
|
||||
overflow: hidden;
|
||||
|
||||
#{$parent}__footer {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#{$parent}__body {
|
||||
padding: 0;
|
||||
scrollbar-width: none;
|
||||
margin-right: -5px;
|
||||
|
||||
height: auto;
|
||||
max-height: 95vh;
|
||||
|
||||
&::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
#{$parent}__close-button {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
|
||||
&--small {
|
||||
height: auto;
|
||||
|
||||
#{$parent}__body {
|
||||
min-height: 0;
|
||||
}
|
||||
#{$parent}__body {
|
||||
padding: $default-padding;
|
||||
}
|
||||
}
|
||||
|
||||
&--fullscreen {
|
||||
width: 95vw;
|
||||
height: auto;
|
||||
grid-template-rows: 1fr;
|
||||
-ms-grid-rows: 1fr;
|
||||
grid-template-areas: 'body';
|
||||
overflow: hidden;
|
||||
|
||||
#{$parent}__footer {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#{$parent}__body {
|
||||
padding: 0;
|
||||
scrollbar-width: none;
|
||||
margin-right: -5px;
|
||||
|
||||
height: auto;
|
||||
max-height: 95vh;
|
||||
|
||||
&::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
#{$parent}__close-button {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
|
||||
&--small {
|
||||
height: auto;
|
||||
|
||||
#{$parent}__body {
|
||||
min-height: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -1,68 +1,60 @@
|
|||
<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>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import WidgetPopover from '@/components/ui/WidgetPopover';
|
||||
import {defineAsyncComponent} from 'vue';
|
||||
import WidgetPopover from '@/components/ui/WidgetPopover';
|
||||
import { defineAsyncComponent } from 'vue';
|
||||
|
||||
const Ellipses = defineAsyncComponent(() => import(/* webpackChunkName: "icons" */'@/components/icons/Ellipses.vue'));
|
||||
const Ellipses = defineAsyncComponent(() => import(/* webpackChunkName: "icons" */ '@/components/icons/Ellipses.vue'));
|
||||
|
||||
export default {
|
||||
components: {
|
||||
WidgetPopover,
|
||||
Ellipses
|
||||
},
|
||||
export default {
|
||||
components: {
|
||||
WidgetPopover,
|
||||
Ellipses,
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
showMenu: false
|
||||
};
|
||||
}
|
||||
};
|
||||
data() {
|
||||
return {
|
||||
showMenu: false,
|
||||
};
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import "~styles/helpers";
|
||||
@import '~styles/helpers';
|
||||
|
||||
.more-options {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
.more-options {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
|
||||
&__ellipses {
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
fill: $color-charcoal-dark;
|
||||
margin-top: -7px;
|
||||
}
|
||||
|
||||
&__more-link {
|
||||
background-color: rgba($color-white, 0.9);
|
||||
width: 35px;
|
||||
height: 15px;
|
||||
border-radius: 15px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
&__popover {
|
||||
min-width: 200px;
|
||||
@include popover-defaults();
|
||||
}
|
||||
&__ellipses {
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
fill: $color-charcoal-dark;
|
||||
margin-top: -7px;
|
||||
}
|
||||
|
||||
&__more-link {
|
||||
background-color: rgba($color-white, 0.9);
|
||||
width: 35px;
|
||||
height: 15px;
|
||||
border-radius: 15px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
&__popover {
|
||||
min-width: 200px;
|
||||
@include popover-defaults();
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -1,79 +1,74 @@
|
|||
<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>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {defineAsyncComponent} from 'vue';
|
||||
const ArrowUp = defineAsyncComponent(() => import(/* webpackChunkName: "icons" */'@/components/icons/ArrowUp'));
|
||||
import { defineAsyncComponent } from 'vue';
|
||||
const ArrowUp = defineAsyncComponent(() => import(/* webpackChunkName: "icons" */ '@/components/icons/ArrowUp'));
|
||||
|
||||
export default {
|
||||
components: {
|
||||
ArrowUp
|
||||
},
|
||||
export default {
|
||||
components: {
|
||||
ArrowUp,
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
scroll: 0
|
||||
};
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
scroll: 0,
|
||||
};
|
||||
},
|
||||
|
||||
mounted() {
|
||||
let html = document.scrollingElement;
|
||||
document.body.onscroll = () => {
|
||||
this.scroll = html.scrollTop;
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
let html = document.scrollingElement;
|
||||
document.body.onscroll = () => {
|
||||
this.scroll = html.scrollTop;
|
||||
};
|
||||
},
|
||||
|
||||
unmounted() {
|
||||
document.body.onscroll = null;
|
||||
},
|
||||
unmounted() {
|
||||
document.body.onscroll = null;
|
||||
},
|
||||
|
||||
methods: {
|
||||
scrollTop() {
|
||||
document.scrollingElement.scrollTop = 0;
|
||||
}
|
||||
methods: {
|
||||
scrollTop() {
|
||||
document.scrollingElement.scrollTop = 0;
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import '@/styles/_variables.scss';
|
||||
@import '@/styles/_mixins.scss';
|
||||
@import '@/styles/_variables.scss';
|
||||
@import '@/styles/_mixins.scss';
|
||||
|
||||
.scroll-up {
|
||||
position: fixed;
|
||||
right: $large-spacing;
|
||||
bottom: $large-spacing;
|
||||
padding: $medium-spacing;
|
||||
border-radius: 100px;
|
||||
@include default-box-shadow;
|
||||
cursor: pointer;
|
||||
background-color: $color-white;
|
||||
border: 1px solid $color-silver;
|
||||
z-index: 2;
|
||||
|
||||
&__icon {
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
fill: $color-brand;
|
||||
}
|
||||
.scroll-up {
|
||||
position: fixed;
|
||||
right: $large-spacing;
|
||||
bottom: $large-spacing;
|
||||
padding: $medium-spacing;
|
||||
border-radius: 100px;
|
||||
@include default-box-shadow;
|
||||
cursor: pointer;
|
||||
background-color: $color-white;
|
||||
border: 1px solid $color-silver;
|
||||
z-index: 2;
|
||||
|
||||
&__icon {
|
||||
width: 50px;
|
||||
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 */
|
||||
{
|
||||
opacity: 0;
|
||||
}
|
||||
.fade-enter-from, .fade-leave-to /* .fade-leave-active below version 2.1.8 */ {
|
||||
opacity: 0;
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -1,44 +1,43 @@
|
|||
<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>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {defineAsyncComponent} from 'vue';
|
||||
import filenameFromUrl from '@/helpers/urls';
|
||||
const DocumentIcon = defineAsyncComponent(() => import(/* webpackChunkName: "icons" */'@/components/icons/DocumentIcon'));
|
||||
import { defineAsyncComponent } from 'vue';
|
||||
import filenameFromUrl from '@/helpers/urls';
|
||||
const DocumentIcon = defineAsyncComponent(() =>
|
||||
import(/* webpackChunkName: "icons" */ '@/components/icons/DocumentIcon')
|
||||
);
|
||||
|
||||
export default {
|
||||
name: 'StudentSubmissionDocument',
|
||||
props: ['document'],
|
||||
components: { DocumentIcon },
|
||||
export default {
|
||||
name: 'StudentSubmissionDocument',
|
||||
props: ['document'],
|
||||
components: { DocumentIcon },
|
||||
|
||||
computed: {
|
||||
filename() {
|
||||
return filenameFromUrl(this.document);
|
||||
}
|
||||
computed: {
|
||||
filename() {
|
||||
return filenameFromUrl(this.document);
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.content {
|
||||
display: flex;
|
||||
.content {
|
||||
display: flex;
|
||||
|
||||
&__icon {
|
||||
width: 25px;
|
||||
align-self: center;
|
||||
}
|
||||
|
||||
&__text {
|
||||
align-self: center;
|
||||
padding-left: 5px;
|
||||
}
|
||||
&__icon {
|
||||
width: 25px;
|
||||
align-self: center;
|
||||
}
|
||||
|
||||
&__text {
|
||||
align-self: center;
|
||||
padding-left: 5px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -1,82 +1,72 @@
|
|||
<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>
|
||||
|
||||
<script>
|
||||
import Avatar from '@/components/profile/Avatar';
|
||||
import Avatar from '@/components/profile/Avatar';
|
||||
|
||||
export default {
|
||||
props: {
|
||||
avatarUrl: {
|
||||
type: String
|
||||
}
|
||||
export default {
|
||||
props: {
|
||||
avatarUrl: {
|
||||
type: String,
|
||||
},
|
||||
},
|
||||
|
||||
emits: ['click'],
|
||||
emits: ['click'],
|
||||
|
||||
components: {
|
||||
Avatar
|
||||
emits: ['click'],components: {
|
||||
Avatar,
|
||||
},
|
||||
computed: {
|
||||
isProfile() {
|
||||
return this.$route.meta.isProfile;
|
||||
},
|
||||
computed: {
|
||||
isProfile() {
|
||||
return this.$route.meta.isProfile;
|
||||
}
|
||||
}
|
||||
};
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import "~styles/helpers";
|
||||
@import '~styles/helpers';
|
||||
|
||||
.user-widget {
|
||||
.user-widget {
|
||||
color: $color-silver-dark;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
position: relative;
|
||||
// todo: do we need the margin right always? just do it where needed --> content block actions and objecives override this
|
||||
margin-right: $medium-spacing;
|
||||
|
||||
&__popover {
|
||||
top: 40px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
&__name {
|
||||
padding: 0px $small-spacing;
|
||||
color: $color-silver-dark;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
position: relative;
|
||||
// todo: do we need the margin right always? just do it where needed --> content block actions and objecives override this
|
||||
margin-right: $medium-spacing;
|
||||
font-family: $sans-serif-font-family;
|
||||
}
|
||||
|
||||
&__popover {
|
||||
top: 40px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
&__date {
|
||||
font-family: $sans-serif-font-family;
|
||||
}
|
||||
|
||||
&__name {
|
||||
padding: 0px $small-spacing;
|
||||
color: $color-silver-dark;
|
||||
font-family: $sans-serif-font-family;
|
||||
}
|
||||
&__avatar {
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
fill: $color-silver-dark;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
&__date {
|
||||
font-family: $sans-serif-font-family;
|
||||
}
|
||||
|
||||
&__avatar {
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
fill: $color-silver-dark;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
&--is-profile {
|
||||
& > span {
|
||||
color: $color-brand;
|
||||
}
|
||||
&--is-profile {
|
||||
& > span {
|
||||
color: $color-brand;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -1,12 +1,9 @@
|
|||
<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
|
||||
:class="{'content-navigation__link--active': isActive('book')}"
|
||||
:class="{ 'content-navigation__link--active': isActive('book') }"
|
||||
:to="topicRoute"
|
||||
active-class="content-navigation__link--active"
|
||||
class="content-navigation__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">
|
||||
|
|
@ -33,7 +28,7 @@
|
|||
|
||||
<div class="content-navigation__item">
|
||||
<router-link
|
||||
:to="{name: 'news'}"
|
||||
:to="{ name: 'news' }"
|
||||
active-class="content-navigation__link--active"
|
||||
class="content-navigation__link"
|
||||
data-cy="news-navigation-link"
|
||||
|
|
@ -45,19 +40,14 @@
|
|||
</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>
|
||||
|
||||
<div class="content-navigation__secondary">
|
||||
<div class="content-navigation__item content-navigation__item--secondary">
|
||||
<router-link
|
||||
:class="{'content-navigation__link--active': isRoomUrl()}"
|
||||
:class="{ 'content-navigation__link--active': isRoomUrl() }"
|
||||
to="/rooms"
|
||||
active-class="content-navigation__link--active"
|
||||
class="content-navigation__link content-navigation__link--secondary"
|
||||
|
|
@ -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,16 +67,13 @@
|
|||
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"
|
||||
class="content-navigation__link content-navigation__link--secondary"
|
||||
@click="close"
|
||||
>Support
|
||||
>Support
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -97,7 +81,7 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import TopicNavigation from '@/components/book-navigation/TopicNavigation';
|
||||
import TopicNavigation from '@/components/book-navigation/TopicNavigation';
|
||||
|
||||
import sidebarMixin from '@/mixins/sidebar';
|
||||
import meMixin from '@/mixins/me';
|
||||
|
|
@ -105,134 +89,135 @@
|
|||
|
||||
const Logo = defineAsyncComponent(() => import(/* webpackChunkName: "icons" */'@/components/icons/Logo'));
|
||||
|
||||
export default {
|
||||
props: {
|
||||
isSidebar: {
|
||||
default: false
|
||||
}
|
||||
export default {
|
||||
props: {
|
||||
isSidebar: {
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
|
||||
mixins: [sidebarMixin, meMixin],
|
||||
mixins: [sidebarMixin, meMixin],
|
||||
|
||||
components: {
|
||||
TopicNavigation,
|
||||
Logo
|
||||
components: {
|
||||
TopicNavigation,
|
||||
Logo,
|
||||
},
|
||||
|
||||
computed: {
|
||||
showPortfolio() {
|
||||
return this.$flavor.showPortfolio;
|
||||
},
|
||||
},
|
||||
|
||||
computed: {
|
||||
showPortfolio() {
|
||||
return this.$flavor.showPortfolio;
|
||||
}
|
||||
methods: {
|
||||
isActive(linkName) {
|
||||
return linkName === 'book' && this.$route.path.indexOf('module') > -1;
|
||||
},
|
||||
|
||||
methods: {
|
||||
isActive(linkName) {
|
||||
return linkName === 'book' && this.$route.path.indexOf('module') > -1;
|
||||
},
|
||||
isRoomUrl() {
|
||||
return this.$route.path.indexOf('room') > -1;
|
||||
},
|
||||
close() {
|
||||
this.closeSidebar('navigation');
|
||||
}
|
||||
}
|
||||
};
|
||||
isRoomUrl() {
|
||||
return this.$route.path.indexOf('room') > -1;
|
||||
},
|
||||
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;
|
||||
align-items: center;
|
||||
.content-navigation {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
&__link {
|
||||
padding: 0 24px;
|
||||
@include navigation-link;
|
||||
}
|
||||
&__link {
|
||||
padding: 0 24px;
|
||||
@include navigation-link;
|
||||
}
|
||||
|
||||
&__primary, &__secondary {
|
||||
display: none;
|
||||
flex-direction: row;
|
||||
&__primary,
|
||||
&__secondary {
|
||||
display: none;
|
||||
flex-direction: row;
|
||||
|
||||
@include desktop {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
|
||||
&__logo {
|
||||
color: #17A887;
|
||||
font-size: 36px;
|
||||
font-weight: 800;
|
||||
font-family: $sans-serif-font-family;
|
||||
@include desktop {
|
||||
display: flex;
|
||||
justify-self: center;
|
||||
|
||||
/*
|
||||
* For IE10+
|
||||
*/
|
||||
-ms-grid-column: 2;
|
||||
-ms-grid-row-align: center;
|
||||
-ms-grid-column-align: center;
|
||||
}
|
||||
|
||||
&__logo-icon {
|
||||
width: auto;
|
||||
height: 31px;
|
||||
}
|
||||
|
||||
&__link {
|
||||
&--secondary {
|
||||
@include regular-text;
|
||||
}
|
||||
|
||||
&--active {
|
||||
color: $color-brand;
|
||||
}
|
||||
}
|
||||
|
||||
$parent: &;
|
||||
|
||||
&--sidebar {
|
||||
flex-direction: column;
|
||||
|
||||
#{$parent}__primary, #{$parent}__secondary {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#{$parent}__link {
|
||||
@include heading-4;
|
||||
line-height: 2.5em;
|
||||
padding: 0;
|
||||
display: block;
|
||||
margin-bottom: 0.5*$small-spacing;
|
||||
|
||||
&:only-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#{$parent}__item {
|
||||
width: 100%;
|
||||
//border-bottom: 1px solid $color-white;
|
||||
|
||||
/*&:nth-child(1) {*/
|
||||
/* order: 3;*/
|
||||
/* border-bottom: 0;*/
|
||||
/*}*/
|
||||
|
||||
/*&:nth-child(2) {*/
|
||||
/* order: 1;*/
|
||||
/*}*/
|
||||
|
||||
/*&:nth-child(3) {*/
|
||||
/* order: 2;*/
|
||||
/*}*/
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&__logo {
|
||||
color: #17a887;
|
||||
font-size: 36px;
|
||||
font-weight: 800;
|
||||
font-family: $sans-serif-font-family;
|
||||
display: flex;
|
||||
justify-self: center;
|
||||
|
||||
/*
|
||||
* For IE10+
|
||||
*/
|
||||
-ms-grid-column: 2;
|
||||
-ms-grid-row-align: center;
|
||||
-ms-grid-column-align: center;
|
||||
}
|
||||
|
||||
&__logo-icon {
|
||||
width: auto;
|
||||
height: 31px;
|
||||
}
|
||||
|
||||
&__link {
|
||||
&--secondary {
|
||||
@include regular-text;
|
||||
}
|
||||
|
||||
&--active {
|
||||
color: $color-brand;
|
||||
}
|
||||
}
|
||||
|
||||
$parent: &;
|
||||
|
||||
&--sidebar {
|
||||
flex-direction: column;
|
||||
|
||||
#{$parent}__primary,
|
||||
#{$parent}__secondary {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#{$parent}__link {
|
||||
@include heading-4;
|
||||
line-height: 2.5em;
|
||||
padding: 0;
|
||||
display: block;
|
||||
margin-bottom: 0.5 * $small-spacing;
|
||||
|
||||
&:only-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
#{$parent}__item {
|
||||
width: 100%;
|
||||
//border-bottom: 1px solid $color-white;
|
||||
|
||||
/*&:nth-child(1) {*/
|
||||
/* order: 3;*/
|
||||
/* border-bottom: 0;*/
|
||||
/*}*/
|
||||
|
||||
/*&:nth-child(2) {*/
|
||||
/* order: 1;*/
|
||||
/*}*/
|
||||
|
||||
/*&:nth-child(3) {*/
|
||||
/* order: 2;*/
|
||||
/*}*/
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
@ -20,94 +10,95 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import ContentNavigation from '@/components/book-navigation/ContentNavigation';
|
||||
import ContentNavigation from '@/components/book-navigation/ContentNavigation';
|
||||
|
||||
import sidebarMixin from '@/mixins/sidebar';
|
||||
import {defineAsyncComponent} from 'vue';
|
||||
import sidebarMixin from '@/mixins/sidebar';
|
||||
import { defineAsyncComponent } from 'vue';
|
||||
|
||||
const Cross = defineAsyncComponent(() => import(/* webpackChunkName: "icons" */'@/components/icons/CrossIcon'));
|
||||
const Cross = defineAsyncComponent(() => import(/* webpackChunkName: "icons" */ '@/components/icons/CrossIcon'));
|
||||
|
||||
export default {
|
||||
mixins: [sidebarMixin],
|
||||
export default {
|
||||
mixins: [sidebarMixin],
|
||||
|
||||
components: {
|
||||
ContentNavigation,
|
||||
Cross
|
||||
components: {
|
||||
ContentNavigation,
|
||||
Cross,
|
||||
},
|
||||
|
||||
methods: {
|
||||
close() {
|
||||
this.closeSidebar('navigation');
|
||||
},
|
||||
|
||||
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;
|
||||
$desktop-width: 285px;
|
||||
|
||||
.navigation-sidebar {
|
||||
position: fixed;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
top: 0;
|
||||
background-color: white;
|
||||
z-index: 20;
|
||||
.navigation-sidebar {
|
||||
position: fixed;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
top: 0;
|
||||
background-color: white;
|
||||
z-index: 20;
|
||||
|
||||
@include desktop {
|
||||
box-shadow: 0px 2px 9px rgba(0, 0, 0, 0.12);
|
||||
}
|
||||
|
||||
display: grid;
|
||||
|
||||
grid-template-columns: 1fr 50px;
|
||||
grid-template-rows: 50px max-content auto 100px;
|
||||
|
||||
grid-template-areas: "m m" "m m" "s s" "s s";
|
||||
|
||||
&--with-subnavigation {
|
||||
grid-template-areas: "m m" "m m" "sub sub" "s s";
|
||||
}
|
||||
|
||||
height: 100vh;
|
||||
overflow-y: auto;
|
||||
|
||||
@include desktop {
|
||||
width: $desktop-width;
|
||||
}
|
||||
|
||||
&__main {
|
||||
padding: $medium-spacing;
|
||||
grid-area: m;
|
||||
}
|
||||
|
||||
&__main-link {
|
||||
}
|
||||
|
||||
&__close-button {
|
||||
grid-row: 1;
|
||||
grid-column: 2;
|
||||
align-self: center;
|
||||
justify-self: center;
|
||||
cursor: pointer;
|
||||
}
|
||||
@include desktop {
|
||||
box-shadow: 0px 2px 9px rgba(0, 0, 0, 0.12);
|
||||
}
|
||||
|
||||
.slide {
|
||||
&-enter-active, &-leave-active {
|
||||
transition: left 0.2s;
|
||||
}
|
||||
display: grid;
|
||||
|
||||
&-enter-from, &-leave-to {
|
||||
left: -100vw;
|
||||
@include desktop {
|
||||
left: -$desktop-width;
|
||||
}
|
||||
grid-template-columns: 1fr 50px;
|
||||
grid-template-rows: 50px max-content auto 100px;
|
||||
|
||||
grid-template-areas: 'm m' 'm m' 's s' 's s';
|
||||
|
||||
&--with-subnavigation {
|
||||
grid-template-areas: 'm m' 'm m' 'sub sub' 's s';
|
||||
}
|
||||
|
||||
height: 100vh;
|
||||
overflow-y: auto;
|
||||
|
||||
@include desktop {
|
||||
width: $desktop-width;
|
||||
}
|
||||
|
||||
&__main {
|
||||
padding: $medium-spacing;
|
||||
grid-area: m;
|
||||
}
|
||||
|
||||
&__main-link {
|
||||
}
|
||||
|
||||
&__close-button {
|
||||
grid-row: 1;
|
||||
grid-column: 2;
|
||||
align-self: center;
|
||||
justify-self: center;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
.slide {
|
||||
&-enter-active,
|
||||
&-leave-active {
|
||||
transition: left 0.2s;
|
||||
}
|
||||
|
||||
&-enter-from,
|
||||
&-leave-to {
|
||||
left: -100vw;
|
||||
@include desktop {
|
||||
left: -$desktop-width;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
@ -26,30 +16,30 @@
|
|||
const ChevronDown = defineAsyncComponent(() => import(/* webpackChunkName: "icons" */'@/components/icons/ChevronDown'));
|
||||
const ChevronUp = defineAsyncComponent(() => import(/* webpackChunkName: "icons" */'@/components/icons/ChevronUp'));
|
||||
|
||||
export default {
|
||||
props: ['title'],
|
||||
export default {
|
||||
props: ['title'],
|
||||
|
||||
components: {
|
||||
ChevronDown,
|
||||
ChevronUp
|
||||
components: {
|
||||
ChevronDown,
|
||||
ChevronUp,
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
show: false,
|
||||
};
|
||||
},
|
||||
|
||||
watch: {
|
||||
$route() {
|
||||
this.show = false;
|
||||
},
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
show: false
|
||||
};
|
||||
methods: {
|
||||
close() {
|
||||
this.show = false;
|
||||
},
|
||||
|
||||
watch: {
|
||||
$route() {
|
||||
this.show = false;
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
close() {
|
||||
this.show = false;
|
||||
}
|
||||
}
|
||||
};
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
<template>
|
||||
<nav class="topic-navigation">
|
||||
<router-link
|
||||
:to="{name: 'topic', params: {topicSlug: topic.slug}}"
|
||||
:class="{'topic-navigation__topic--active': topic.active, 'book-subnavigation__item--mobile': mobile}"
|
||||
:to="{ name: 'topic', params: { topicSlug: topic.slug } }"
|
||||
:class="{ 'topic-navigation__topic--active': topic.active, 'book-subnavigation__item--mobile': mobile }"
|
||||
tag="div"
|
||||
active-class="book-subnavigation__item--active"
|
||||
class="topic-navigation__topic book-subnavigation__item"
|
||||
|
|
@ -17,8 +17,8 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import ALL_TOPICS_QUERY from '@/graphql/gql/queries/allTopicsQuery.gql';
|
||||
import sidebarMixin from '@/mixins/sidebar';
|
||||
import ALL_TOPICS_QUERY from '@/graphql/gql/queries/allTopicsQuery.gql';
|
||||
import sidebarMixin from '@/mixins/sidebar';
|
||||
|
||||
export default {
|
||||
props: {
|
||||
|
|
@ -26,40 +26,42 @@
|
|||
default: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
mixins: [sidebarMixin],
|
||||
mixins: [sidebarMixin],
|
||||
|
||||
data() {
|
||||
return {
|
||||
topics: [],
|
||||
};
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
topics: [],
|
||||
};
|
||||
},
|
||||
|
||||
methods: {
|
||||
topicId(id) {
|
||||
return atob(id);
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
apollo: {
|
||||
topics: {
|
||||
query: ALL_TOPICS_QUERY,
|
||||
manual: true,
|
||||
result({data, loading}) {
|
||||
if (!loading) {
|
||||
this.topics = this.$getRidOfEdges(data).topics;
|
||||
}
|
||||
},
|
||||
apollo: {
|
||||
topics: {
|
||||
query: ALL_TOPICS_QUERY,
|
||||
manual: true,
|
||||
result({ data, loading }) {
|
||||
if (!loading) {
|
||||
this.topics = this.$getRidOfEdges(data).topics;
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import "~styles/helpers";
|
||||
|
||||
.topic-navigation {
|
||||
&__topic {
|
||||
}
|
||||
.topic-navigation {
|
||||
&__topic {
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
/>
|
||||
|
|
@ -67,289 +63,292 @@
|
|||
const ThinglinkBlock = defineAsyncComponent(() => import(/* webpackChunkName: "content-forms" */'@/components/content-blocks/ThinglinkBlock'));
|
||||
const InfogramBlock = defineAsyncComponent(() => import(/* webpackChunkName: "content-forms" */'@/components/content-blocks/InfogramBlock'));
|
||||
|
||||
const CHOOSER = 'content-block-element-chooser-widget';
|
||||
const CHOOSER = 'content-block-element-chooser-widget';
|
||||
|
||||
export default {
|
||||
props: {
|
||||
element: {
|
||||
type: Object,
|
||||
default: null,
|
||||
},
|
||||
// is this element at the top level, or is it nested? we assume top level
|
||||
topLevel: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
firstElement: {
|
||||
type: Boolean,
|
||||
required: true,
|
||||
},
|
||||
lastElement: {
|
||||
type: Boolean,
|
||||
required: true,
|
||||
},
|
||||
export default {
|
||||
props: {
|
||||
element: {
|
||||
type: Object,
|
||||
default: null,
|
||||
},
|
||||
|
||||
components: {
|
||||
ContentElementActions,
|
||||
ContentFormSection,
|
||||
TrashIcon,
|
||||
ContentBlockElementChooserWidget,
|
||||
LinkForm,
|
||||
VideoForm,
|
||||
ImageForm,
|
||||
DocumentForm,
|
||||
AssignmentForm,
|
||||
TextForm,
|
||||
SubtitleForm,
|
||||
SurveyBlock,
|
||||
Solution,
|
||||
ImageBlock,
|
||||
Instruction,
|
||||
ModuleRoomSlug,
|
||||
CmsDocumentBlock,
|
||||
InfogramBlock,
|
||||
ThinglinkBlock,
|
||||
Assignment
|
||||
// is this element at the top level, or is it nested? we assume top level
|
||||
topLevel: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
|
||||
computed: {
|
||||
actions() {
|
||||
return {
|
||||
up: !this.firstElement,
|
||||
down: !this.lastElement,
|
||||
extended: this.topLevel,
|
||||
};
|
||||
},
|
||||
isChooser() {
|
||||
return this.component === CHOOSER;
|
||||
},
|
||||
type() {
|
||||
return this.getType(this.element);
|
||||
},
|
||||
component() {
|
||||
return this.type.component;
|
||||
},
|
||||
title() {
|
||||
return this.type.title;
|
||||
},
|
||||
icon() {
|
||||
return this.type.icon;
|
||||
},
|
||||
firstElement: {
|
||||
type: Boolean,
|
||||
required: true,
|
||||
},
|
||||
lastElement: {
|
||||
type: Boolean,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
|
||||
methods: {
|
||||
getType(element) {
|
||||
switch (element.type) {
|
||||
case 'subtitle':
|
||||
return {
|
||||
component: 'subtitle-form',
|
||||
title: 'Untertitel',
|
||||
icon: 'title-icon',
|
||||
};
|
||||
case 'link_block':
|
||||
return {
|
||||
component: 'link-form',
|
||||
title: 'Link',
|
||||
icon: 'link-icon',
|
||||
};
|
||||
case 'video_block':
|
||||
return {
|
||||
component: 'video-form',
|
||||
title: 'Video',
|
||||
icon: 'video-icon',
|
||||
};
|
||||
case 'image_url_block':
|
||||
return {
|
||||
component: 'image-form',
|
||||
title: 'Bild',
|
||||
icon: 'image-icon',
|
||||
};
|
||||
case 'text_block':
|
||||
return {
|
||||
component: 'text-form',
|
||||
title: 'Text',
|
||||
icon: 'text-icon',
|
||||
};
|
||||
case 'assignment':
|
||||
return {
|
||||
component: element.id ? 'assignment' : 'assignment-form', // prevent editing of existing assignments
|
||||
title: 'Aufgabe & Ergebnis',
|
||||
icon: 'speech-bubble-icon',
|
||||
};
|
||||
case 'document_block':
|
||||
return {
|
||||
component: 'document-form',
|
||||
title: 'Dokument',
|
||||
icon: 'document-icon',
|
||||
};
|
||||
case 'survey':
|
||||
return {
|
||||
component: 'survey-block',
|
||||
title: 'Übung',
|
||||
};
|
||||
case 'solution':
|
||||
return {
|
||||
component: 'solution',
|
||||
title: 'Lösung',
|
||||
};
|
||||
case 'image_block':
|
||||
return {
|
||||
component: 'image-block',
|
||||
title: 'Bild',
|
||||
};
|
||||
case 'instruction':
|
||||
return {
|
||||
component: 'instruction',
|
||||
title: 'Instruktion',
|
||||
};
|
||||
case 'module_room_slug':
|
||||
return {
|
||||
component: 'module-room-slug',
|
||||
title: 'Raum',
|
||||
};
|
||||
case 'cms_document_block':
|
||||
return {
|
||||
component: 'cms-document-block',
|
||||
title: 'Dokument',
|
||||
};
|
||||
case 'thinglink_block':
|
||||
return {
|
||||
component: 'thinglink-block',
|
||||
title: 'Interaktive Grafik'
|
||||
};
|
||||
case 'infogram_block':
|
||||
return {
|
||||
component: 'infogram-block',
|
||||
title: 'Interaktive Grafik'
|
||||
};
|
||||
}
|
||||
return {
|
||||
component: CHOOSER,
|
||||
title: '',
|
||||
icon: '',
|
||||
};
|
||||
},
|
||||
_updateProperty(value, key) {
|
||||
// const content = this.localContentBlock.contents[index];
|
||||
const content = this.element;
|
||||
this.update({
|
||||
...content,
|
||||
value: {
|
||||
...content.value,
|
||||
[key]: value,
|
||||
},
|
||||
});
|
||||
},
|
||||
changeUrl(value) {
|
||||
this._updateProperty(value, 'url');
|
||||
},
|
||||
changeText(value) {
|
||||
this._updateProperty(value, 'text');
|
||||
},
|
||||
changeAssignmentTitle(value) {
|
||||
this._updateProperty(value, 'title');
|
||||
},
|
||||
changeAssignmentAssignment(value) {
|
||||
this._updateProperty(value, 'assignment');
|
||||
},
|
||||
changeType({type, convertToList}, value) {
|
||||
let el = {
|
||||
type: type,
|
||||
value: Object.assign({}, value),
|
||||
};
|
||||
switch (type) {
|
||||
case 'subtitle':
|
||||
el = {
|
||||
...el,
|
||||
value: {
|
||||
text: '',
|
||||
},
|
||||
};
|
||||
break;
|
||||
case 'text_block':
|
||||
el = {
|
||||
...el,
|
||||
value: {
|
||||
text: '',
|
||||
},
|
||||
};
|
||||
break;
|
||||
case 'link_block':
|
||||
el = {
|
||||
...el,
|
||||
value: {
|
||||
text: '',
|
||||
url: '',
|
||||
},
|
||||
};
|
||||
break;
|
||||
case 'video_block':
|
||||
el = {
|
||||
...el,
|
||||
value: {
|
||||
url: '',
|
||||
},
|
||||
};
|
||||
break;
|
||||
case 'document_block':
|
||||
el = {
|
||||
...el,
|
||||
value: Object.assign({
|
||||
url: '',
|
||||
}, value),
|
||||
};
|
||||
break;
|
||||
case 'image_url_block':
|
||||
el = {
|
||||
...el,
|
||||
value: {
|
||||
url: '',
|
||||
},
|
||||
};
|
||||
break;
|
||||
}
|
||||
components: {
|
||||
ContentElementActions,
|
||||
ContentFormSection,
|
||||
TrashIcon,
|
||||
ContentBlockElementChooserWidget,
|
||||
LinkForm,
|
||||
VideoForm,
|
||||
ImageForm,
|
||||
DocumentForm,
|
||||
AssignmentForm,
|
||||
TextForm,
|
||||
SubtitleForm,
|
||||
SurveyBlock,
|
||||
Solution,
|
||||
ImageBlock,
|
||||
Instruction,
|
||||
ModuleRoomSlug,
|
||||
CmsDocumentBlock,
|
||||
InfogramBlock,
|
||||
ThinglinkBlock,
|
||||
Assignment,
|
||||
},
|
||||
|
||||
if (convertToList) {
|
||||
el = {
|
||||
type: 'content_list_item',
|
||||
contents: [el],
|
||||
computed: {
|
||||
actions() {
|
||||
return {
|
||||
up: !this.firstElement,
|
||||
down: !this.lastElement,
|
||||
extended: this.topLevel,
|
||||
};
|
||||
},
|
||||
isChooser() {
|
||||
return this.component === CHOOSER;
|
||||
},
|
||||
type() {
|
||||
return this.getType(this.element);
|
||||
},
|
||||
component() {
|
||||
return this.type.component;
|
||||
},
|
||||
title() {
|
||||
return this.type.title;
|
||||
},
|
||||
icon() {
|
||||
return this.type.icon;
|
||||
},
|
||||
},
|
||||
|
||||
methods: {
|
||||
getType(element) {
|
||||
switch (element.type) {
|
||||
case 'subtitle':
|
||||
return {
|
||||
component: 'subtitle-form',
|
||||
title: 'Untertitel',
|
||||
icon: 'title-icon',
|
||||
};
|
||||
}
|
||||
this.update(el);
|
||||
},
|
||||
update(element) {
|
||||
this.$emit('update', element);
|
||||
},
|
||||
switchToDocument(value) {
|
||||
this.changeType('document_block', value);
|
||||
},
|
||||
case 'link_block':
|
||||
return {
|
||||
component: 'link-form',
|
||||
title: 'Link',
|
||||
icon: 'link-icon',
|
||||
};
|
||||
case 'video_block':
|
||||
return {
|
||||
component: 'video-form',
|
||||
title: 'Video',
|
||||
icon: 'video-icon',
|
||||
};
|
||||
case 'image_url_block':
|
||||
return {
|
||||
component: 'image-form',
|
||||
title: 'Bild',
|
||||
icon: 'image-icon',
|
||||
};
|
||||
case 'text_block':
|
||||
return {
|
||||
component: 'text-form',
|
||||
title: 'Text',
|
||||
icon: 'text-icon',
|
||||
};
|
||||
case 'assignment':
|
||||
return {
|
||||
component: element.id ? 'assignment' : 'assignment-form', // prevent editing of existing assignments
|
||||
title: 'Aufgabe & Ergebnis',
|
||||
icon: 'speech-bubble-icon',
|
||||
};
|
||||
case 'document_block':
|
||||
return {
|
||||
component: 'document-form',
|
||||
title: 'Dokument',
|
||||
icon: 'document-icon',
|
||||
};
|
||||
case 'survey':
|
||||
return {
|
||||
component: 'survey-block',
|
||||
title: 'Übung',
|
||||
};
|
||||
case 'solution':
|
||||
return {
|
||||
component: 'solution',
|
||||
title: 'Lösung',
|
||||
};
|
||||
case 'image_block':
|
||||
return {
|
||||
component: 'image-block',
|
||||
title: 'Bild',
|
||||
};
|
||||
case 'instruction':
|
||||
return {
|
||||
component: 'instruction',
|
||||
title: 'Instruktion',
|
||||
};
|
||||
case 'module_room_slug':
|
||||
return {
|
||||
component: 'module-room-slug',
|
||||
title: 'Raum',
|
||||
};
|
||||
case 'cms_document_block':
|
||||
return {
|
||||
component: 'cms-document-block',
|
||||
title: 'Dokument',
|
||||
};
|
||||
case 'thinglink_block':
|
||||
return {
|
||||
component: 'thinglink-block',
|
||||
title: 'Interaktive Grafik',
|
||||
};
|
||||
case 'infogram_block':
|
||||
return {
|
||||
component: 'infogram-block',
|
||||
title: 'Interaktive Grafik',
|
||||
};
|
||||
}
|
||||
return {
|
||||
component: CHOOSER,
|
||||
title: '',
|
||||
icon: '',
|
||||
};
|
||||
},
|
||||
};
|
||||
_updateProperty(value, key) {
|
||||
// const content = this.localContentBlock.contents[index];
|
||||
const content = this.element;
|
||||
this.update({
|
||||
...content,
|
||||
value: {
|
||||
...content.value,
|
||||
[key]: value,
|
||||
},
|
||||
});
|
||||
},
|
||||
changeUrl(value) {
|
||||
this._updateProperty(value, 'url');
|
||||
},
|
||||
changeText(value) {
|
||||
this._updateProperty(value, 'text');
|
||||
},
|
||||
changeAssignmentTitle(value) {
|
||||
this._updateProperty(value, 'title');
|
||||
},
|
||||
changeAssignmentAssignment(value) {
|
||||
this._updateProperty(value, 'assignment');
|
||||
},
|
||||
changeType({ type, convertToList }, value) {
|
||||
let el = {
|
||||
type: type,
|
||||
value: Object.assign({}, value),
|
||||
};
|
||||
switch (type) {
|
||||
case 'subtitle':
|
||||
el = {
|
||||
...el,
|
||||
value: {
|
||||
text: '',
|
||||
},
|
||||
};
|
||||
break;
|
||||
case 'text_block':
|
||||
el = {
|
||||
...el,
|
||||
value: {
|
||||
text: '',
|
||||
},
|
||||
};
|
||||
break;
|
||||
case 'link_block':
|
||||
el = {
|
||||
...el,
|
||||
value: {
|
||||
text: '',
|
||||
url: '',
|
||||
},
|
||||
};
|
||||
break;
|
||||
case 'video_block':
|
||||
el = {
|
||||
...el,
|
||||
value: {
|
||||
url: '',
|
||||
},
|
||||
};
|
||||
break;
|
||||
case 'document_block':
|
||||
el = {
|
||||
...el,
|
||||
value: Object.assign(
|
||||
{
|
||||
url: '',
|
||||
},
|
||||
value
|
||||
),
|
||||
};
|
||||
break;
|
||||
case 'image_url_block':
|
||||
el = {
|
||||
...el,
|
||||
value: {
|
||||
url: '',
|
||||
},
|
||||
};
|
||||
break;
|
||||
}
|
||||
|
||||
if (convertToList) {
|
||||
el = {
|
||||
type: 'content_list_item',
|
||||
contents: [el],
|
||||
};
|
||||
}
|
||||
this.update(el);
|
||||
},
|
||||
update(element) {
|
||||
this.$emit('update', element);
|
||||
},
|
||||
switchToDocument(value) {
|
||||
this.changeType('document_block', value);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import '~styles/helpers';
|
||||
@import '~styles/helpers';
|
||||
|
||||
.content-element {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
.content-element {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
&__actions {
|
||||
display: inline-flex;
|
||||
justify-self: flex-end;
|
||||
align-self: flex-end;
|
||||
}
|
||||
|
||||
&__section {
|
||||
display: grid;
|
||||
//grid-template-columns: 1fr 50px;
|
||||
grid-auto-rows: auto;
|
||||
/*width: 95%; // reserve space for scrollbar*/
|
||||
}
|
||||
|
||||
&__chooser {
|
||||
grid-column: 1 / span 2;
|
||||
}
|
||||
&__actions {
|
||||
display: inline-flex;
|
||||
justify-self: flex-end;
|
||||
align-self: flex-end;
|
||||
}
|
||||
|
||||
&__section {
|
||||
display: grid;
|
||||
//grid-template-columns: 1fr 50px;
|
||||
grid-auto-rows: auto;
|
||||
/*width: 95%; // reserve space for scrollbar*/
|
||||
}
|
||||
|
||||
&__chooser {
|
||||
grid-column: 1 / span 2;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -55,46 +50,46 @@
|
|||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import '~styles/helpers';
|
||||
@import '~styles/helpers';
|
||||
|
||||
.content-form-section {
|
||||
@include default-box-shadow;
|
||||
border-radius: $default-border-radius;
|
||||
padding: $small-spacing $medium-spacing;
|
||||
margin-bottom: $medium-spacing;
|
||||
.content-form-section {
|
||||
@include default-box-shadow;
|
||||
border-radius: $default-border-radius;
|
||||
padding: $small-spacing $medium-spacing;
|
||||
margin-bottom: $medium-spacing;
|
||||
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
grid-template-rows: auto;
|
||||
grid-template-areas: 'h a' 'c c';
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
grid-template-rows: auto;
|
||||
grid-template-areas: 'h a' 'c c';
|
||||
align-items: center;
|
||||
grid-row-gap: $medium-spacing;
|
||||
|
||||
&__heading {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
grid-row-gap: $medium-spacing;
|
||||
|
||||
&__heading {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
grid-area: h;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
&__actions {
|
||||
grid-area: a;
|
||||
justify-self: end;
|
||||
}
|
||||
|
||||
&__title {
|
||||
@include heading-3;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
&__icon {
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
margin-right: $small-spacing;
|
||||
}
|
||||
|
||||
&__content {
|
||||
grid-area: c;
|
||||
}
|
||||
grid-area: h;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
&__actions {
|
||||
grid-area: a;
|
||||
justify-self: end;
|
||||
}
|
||||
|
||||
&__title {
|
||||
@include heading-3;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
&__icon {
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
margin-right: $small-spacing;
|
||||
}
|
||||
|
||||
&__content {
|
||||
grid-area: c;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -18,41 +18,23 @@
|
|||
/>
|
||||
</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>
|
||||
<div>
|
||||
<a
|
||||
:class="{'button--disabled': disableSave}"
|
||||
:class="{ 'button--disabled': disableSave }"
|
||||
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>
|
||||
|
|
@ -69,116 +51,117 @@
|
|||
const Modal = defineAsyncComponent(() => import('@/components/Modal'));
|
||||
const Checkbox = defineAsyncComponent(() => import('@/components/ui/Checkbox'));
|
||||
|
||||
export default {
|
||||
props: {
|
||||
contentBlock: Object,
|
||||
blockType: {
|
||||
type: String,
|
||||
default: 'ContentBlock',
|
||||
},
|
||||
showTaskSelection: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
disableSave: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
export default {
|
||||
props: {
|
||||
contentBlock: Object,
|
||||
blockType: {
|
||||
type: String,
|
||||
default: 'ContentBlock',
|
||||
},
|
||||
|
||||
components: {
|
||||
ContentElement,
|
||||
Modal,
|
||||
ModalInput,
|
||||
AddContentElement,
|
||||
Checkbox,
|
||||
showTaskSelection: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
disableSave: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
error: false,
|
||||
localContentBlock: Object.assign({}, {
|
||||
components: {
|
||||
ContentElement,
|
||||
Modal,
|
||||
ModalInput,
|
||||
AddContentElement,
|
||||
Checkbox,
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
error: false,
|
||||
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: {},
|
||||
};
|
||||
},
|
||||
|
||||
apollo: {
|
||||
me: meQuery,
|
||||
},
|
||||
|
||||
computed: {
|
||||
titlePlaceholder() {
|
||||
return this.blockType === 'RoomEntry' ? 'Titel für Raumeintrag erfassen' : 'Titel für Inhaltsblock erfassen';
|
||||
},
|
||||
taskSelection() {
|
||||
return this.showTaskSelection && this.me.permissions.includes('users.can_manage_school_class_content');
|
||||
},
|
||||
},
|
||||
|
||||
methods: {
|
||||
setContentBlockType(checked) {
|
||||
this.localContentBlock.isAssignment = checked;
|
||||
},
|
||||
update(index, element) {
|
||||
this.localContentBlock.contents.splice(index, 1, element);
|
||||
},
|
||||
save() {
|
||||
if (!this.disableSave) {
|
||||
if (!this.localContentBlock.title) {
|
||||
this.error = true;
|
||||
return false;
|
||||
}
|
||||
this.$emit('save', this.localContentBlock);
|
||||
}
|
||||
},
|
||||
updateTitle(title) {
|
||||
this.localContentBlock.title = title;
|
||||
this.error = false;
|
||||
},
|
||||
addElement(index) {
|
||||
this.localContentBlock.contents.splice(index + 1, 0, {
|
||||
hideAssignment: this.blockType !== 'ContentBlock',
|
||||
});
|
||||
},
|
||||
remove(index) {
|
||||
this.localContentBlock.contents.splice(index, 1);
|
||||
},
|
||||
),
|
||||
me: {},
|
||||
};
|
||||
},
|
||||
|
||||
apollo: {
|
||||
me: meQuery,
|
||||
},
|
||||
|
||||
computed: {
|
||||
titlePlaceholder() {
|
||||
return this.blockType === 'RoomEntry' ? 'Titel für Raumeintrag erfassen' : 'Titel für Inhaltsblock erfassen';
|
||||
},
|
||||
};
|
||||
taskSelection() {
|
||||
return this.showTaskSelection && this.me.permissions.includes('users.can_manage_school_class_content');
|
||||
},
|
||||
},
|
||||
|
||||
methods: {
|
||||
setContentBlockType(checked) {
|
||||
this.localContentBlock.isAssignment = checked;
|
||||
},
|
||||
update(index, element) {
|
||||
this.localContentBlock.contents.splice(index, 1, element);
|
||||
},
|
||||
save() {
|
||||
if (!this.disableSave) {
|
||||
if (!this.localContentBlock.title) {
|
||||
this.error = true;
|
||||
return false;
|
||||
}
|
||||
this.$emit('save', this.localContentBlock);
|
||||
}
|
||||
},
|
||||
updateTitle(title) {
|
||||
this.localContentBlock.title = title;
|
||||
this.error = false;
|
||||
},
|
||||
addElement(index) {
|
||||
this.localContentBlock.contents.splice(index + 1, 0, {
|
||||
hideAssignment: this.blockType !== 'ContentBlock',
|
||||
});
|
||||
},
|
||||
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 */
|
||||
.contents-form {
|
||||
/* top level does not exist, because of the modal */
|
||||
|
||||
&__element {
|
||||
|
||||
}
|
||||
|
||||
&__element-component {
|
||||
margin-bottom: 25px;
|
||||
}
|
||||
|
||||
&__remove {
|
||||
}
|
||||
|
||||
&__trash-icon {
|
||||
}
|
||||
|
||||
&__add {
|
||||
grid-column: 1 / span 2;
|
||||
}
|
||||
|
||||
&__task {
|
||||
margin: 15px 0 10px;
|
||||
}
|
||||
&__element {
|
||||
}
|
||||
|
||||
&__element-component {
|
||||
margin-bottom: 25px;
|
||||
}
|
||||
|
||||
&__remove {
|
||||
}
|
||||
|
||||
&__trash-icon {
|
||||
}
|
||||
|
||||
&__add {
|
||||
grid-column: 1 / span 2;
|
||||
}
|
||||
|
||||
&__task {
|
||||
margin: 15px 0 10px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -1,14 +1,9 @@
|
|||
<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>
|
||||
import ContentsForm from '@/components/content-block-form/ContentsForm';
|
||||
import ContentsForm from '@/components/content-block-form/ContentsForm';
|
||||
|
||||
import {store} from '@/store';
|
||||
|
||||
|
|
@ -28,17 +23,18 @@
|
|||
};
|
||||
},
|
||||
|
||||
created() {
|
||||
// debugger;
|
||||
},
|
||||
created() {
|
||||
// debugger;
|
||||
},
|
||||
|
||||
methods: {
|
||||
hideModal() {
|
||||
this.$store.dispatch('resetCurrentNoteBlock');
|
||||
this.$store.dispatch('hideModal');
|
||||
},
|
||||
saveContentBlock(contentBlock) {
|
||||
this.$apollo.mutate({
|
||||
methods: {
|
||||
hideModal() {
|
||||
this.$store.dispatch('resetCurrentNoteBlock');
|
||||
this.$store.dispatch('hideModal');
|
||||
},
|
||||
saveContentBlock(contentBlock) {
|
||||
this.$apollo
|
||||
.mutate({
|
||||
mutation: EDIT_CONTENT_BLOCK_MUTATION,
|
||||
variables: {
|
||||
input: {
|
||||
|
|
@ -61,6 +57,7 @@
|
|||
});
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
apollo: {
|
||||
contentBlock() {
|
||||
|
|
|
|||
|
|
@ -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,37 +127,36 @@ 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;
|
||||
.content-component {
|
||||
position: relative;
|
||||
|
||||
&--bookmarked {
|
||||
|
||||
}
|
||||
|
||||
&--subtitle {
|
||||
margin-top: $section-spacing;
|
||||
margin-bottom: $large-spacing;
|
||||
}
|
||||
|
||||
&--section_title {
|
||||
margin-top: $section-spacing;
|
||||
margin-bottom: $large-spacing;
|
||||
}
|
||||
|
||||
&--text_block {
|
||||
margin-bottom: $large-spacing;
|
||||
}
|
||||
|
||||
&--document_block {
|
||||
margin-bottom: $large-spacing;
|
||||
}
|
||||
&--bookmarked {
|
||||
}
|
||||
|
||||
&--subtitle {
|
||||
margin-top: $section-spacing;
|
||||
margin-bottom: $large-spacing;
|
||||
}
|
||||
|
||||
&--section_title {
|
||||
margin-top: $section-spacing;
|
||||
margin-bottom: $large-spacing;
|
||||
}
|
||||
|
||||
&--text_block {
|
||||
margin-bottom: $large-spacing;
|
||||
}
|
||||
|
||||
&--document_block {
|
||||
margin-bottom: $large-spacing;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
@ -21,60 +13,60 @@
|
|||
const DocumentIcon = defineAsyncComponent(() => import(/* webpackChunkName: "icons" */'@/components/icons/DocumentIcon'));
|
||||
const TrashIcon = defineAsyncComponent(() => import(/* webpackChunkName: "icons" */'@/components/icons/TrashIcon'));
|
||||
|
||||
export default {
|
||||
props: {
|
||||
value: Object,
|
||||
showTrashIcon: Boolean,
|
||||
},
|
||||
export default {
|
||||
props: {
|
||||
value: Object,
|
||||
showTrashIcon: Boolean,
|
||||
},
|
||||
|
||||
components: {
|
||||
DocumentIcon,
|
||||
TrashIcon,
|
||||
},
|
||||
components: {
|
||||
DocumentIcon,
|
||||
TrashIcon,
|
||||
},
|
||||
|
||||
computed: {
|
||||
urlName: function() {
|
||||
if (this.value && this.value.url) {
|
||||
const parts = this.value.url.split('/');
|
||||
return parts[parts.length - 1];
|
||||
}
|
||||
return null;
|
||||
computed: {
|
||||
urlName: function () {
|
||||
if (this.value && this.value.url) {
|
||||
const parts = this.value.url.split('/');
|
||||
return parts[parts.length - 1];
|
||||
}
|
||||
}
|
||||
};
|
||||
return null;
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import "~styles/helpers";
|
||||
@import '~styles/helpers';
|
||||
|
||||
.document-block {
|
||||
display: grid;
|
||||
grid-template-columns: 50px 1fr 50px;
|
||||
align-items: center;
|
||||
.document-block {
|
||||
display: grid;
|
||||
grid-template-columns: 50px 1fr 50px;
|
||||
align-items: center;
|
||||
|
||||
&__icon {
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
}
|
||||
|
||||
&__link {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
&__remove {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
}
|
||||
|
||||
&__trash-icon {
|
||||
width: 25px;
|
||||
height: 25px;
|
||||
fill: $color-silver-dark;
|
||||
cursor: pointer;
|
||||
justify-self: center;
|
||||
}
|
||||
&__icon {
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
}
|
||||
|
||||
&__link {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
&__remove {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
}
|
||||
|
||||
&__trash-icon {
|
||||
width: 25px;
|
||||
height: 25px;
|
||||
fill: $color-silver-dark;
|
||||
cursor: pointer;
|
||||
justify-self: center;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -1,57 +1,51 @@
|
|||
<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>
|
||||
|
||||
<script>
|
||||
import me from '@/mixins/me';
|
||||
import {defineAsyncComponent} from 'vue';
|
||||
const BulbIcon = defineAsyncComponent(() => import(/* webpackChunkName: "icons" */'@/components/icons/BulbIcon'));
|
||||
import me from '@/mixins/me';
|
||||
import { defineAsyncComponent } from 'vue';
|
||||
const BulbIcon = defineAsyncComponent(() => import(/* webpackChunkName: "icons" */ '@/components/icons/BulbIcon'));
|
||||
|
||||
export default {
|
||||
props: ['value'],
|
||||
export default {
|
||||
props: ['value'],
|
||||
|
||||
mixins: [me],
|
||||
mixins: [me],
|
||||
|
||||
components: {
|
||||
BulbIcon
|
||||
components: {
|
||||
BulbIcon,
|
||||
},
|
||||
|
||||
computed: {
|
||||
text() {
|
||||
return this.value.text ? this.value.text : 'Anweisungen';
|
||||
},
|
||||
|
||||
computed: {
|
||||
text() {
|
||||
return this.value.text ? this.value.text : 'Anweisungen';
|
||||
},
|
||||
url() {
|
||||
return this.value.document ? this.value.document.url : this.value.url;
|
||||
}
|
||||
}
|
||||
};
|
||||
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;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
.instruction {
|
||||
margin-bottom: 1rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
&__icon {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
margin-right: $small-spacing;
|
||||
}
|
||||
|
||||
&__link {
|
||||
@include heading-3;
|
||||
}
|
||||
&__icon {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
margin-right: $small-spacing;
|
||||
}
|
||||
|
||||
&__link {
|
||||
@include heading-3;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -1,60 +1,53 @@
|
|||
<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>
|
||||
|
||||
<script>
|
||||
import {defineAsyncComponent} from 'vue';
|
||||
const LinkIcon = defineAsyncComponent(() => import(/* webpackChunkName: "icons" */'@/components/icons/LinkIcon'));
|
||||
import { defineAsyncComponent } from 'vue';
|
||||
const LinkIcon = defineAsyncComponent(() => import(/* webpackChunkName: "icons" */ '@/components/icons/LinkIcon'));
|
||||
|
||||
export default {
|
||||
props: {
|
||||
value: Object,
|
||||
noMargin: {
|
||||
default: false
|
||||
}
|
||||
export default {
|
||||
props: {
|
||||
value: Object,
|
||||
noMargin: {
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
|
||||
components: {
|
||||
LinkIcon
|
||||
components: {
|
||||
LinkIcon,
|
||||
},
|
||||
|
||||
computed: {
|
||||
href() {
|
||||
const url = this.value.url;
|
||||
return url.startsWith('http') ? this.value.url : `http://${this.value.url}`;
|
||||
},
|
||||
|
||||
computed: {
|
||||
href() {
|
||||
const url = this.value.url;
|
||||
return url.startsWith('http') ? this.value.url : `http://${this.value.url}`;
|
||||
}
|
||||
}
|
||||
};
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.link-block {
|
||||
margin-bottom: 30px;
|
||||
display: grid;
|
||||
grid-template-columns: 50px 1fr;
|
||||
align-items: center;
|
||||
.link-block {
|
||||
margin-bottom: 30px;
|
||||
display: grid;
|
||||
grid-template-columns: 50px 1fr;
|
||||
align-items: center;
|
||||
|
||||
&--no-margin {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
&__icon {
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
}
|
||||
|
||||
&__link {
|
||||
text-decoration: underline;
|
||||
}
|
||||
&--no-margin {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
&__icon {
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
}
|
||||
|
||||
&__link {
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -1,109 +1,101 @@
|
|||
<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>
|
||||
|
||||
<script>
|
||||
import {newLineToParagraph} from '@/helpers/text';
|
||||
import {defineAsyncComponent} from 'vue';
|
||||
const DocumentBlock = defineAsyncComponent(() => import(/* webpackChunkName: "content-components" */'@/components/content-blocks/DocumentBlock'));
|
||||
import { newLineToParagraph } from '@/helpers/text';
|
||||
import { defineAsyncComponent } from 'vue';
|
||||
const DocumentBlock = defineAsyncComponent(() =>
|
||||
import(/* webpackChunkName: "content-components" */ '@/components/content-blocks/DocumentBlock')
|
||||
);
|
||||
|
||||
const InfoIcon = defineAsyncComponent(() => import(/* webpackChunkName: "icons" */'@/components/icons/InfoIcon'));
|
||||
const InfoIcon = defineAsyncComponent(() => import(/* webpackChunkName: "icons" */ '@/components/icons/InfoIcon'));
|
||||
|
||||
export default {
|
||||
props: {
|
||||
userInput: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
},
|
||||
showReopen: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
sharedMsg: {
|
||||
type: String,
|
||||
default: ''
|
||||
}
|
||||
export default {
|
||||
props: {
|
||||
userInput: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
|
||||
components: {
|
||||
InfoIcon,
|
||||
DocumentBlock,
|
||||
showReopen: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
sharedMsg: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
},
|
||||
|
||||
computed: {
|
||||
text() {
|
||||
return newLineToParagraph(this.userInput.text);
|
||||
}
|
||||
}
|
||||
};
|
||||
components: {
|
||||
InfoIcon,
|
||||
DocumentBlock,
|
||||
},
|
||||
|
||||
computed: {
|
||||
text() {
|
||||
return newLineToParagraph(this.userInput.text);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import "~styles/helpers";
|
||||
@import '~styles/helpers';
|
||||
|
||||
.final-submission {
|
||||
&__text {
|
||||
background-color: $color-white;
|
||||
@include input-box-shadow;
|
||||
border-radius: $input-border-radius;
|
||||
padding: 15px;
|
||||
font-size: toRem(17px);
|
||||
font-family: $sans-serif-font-family;
|
||||
margin-bottom: 20px;
|
||||
font-weight: $font-weight-regular;
|
||||
.final-submission {
|
||||
&__text {
|
||||
background-color: $color-white;
|
||||
@include input-box-shadow;
|
||||
border-radius: $input-border-radius;
|
||||
padding: 15px;
|
||||
font-size: toRem(17px);
|
||||
font-family: $sans-serif-font-family;
|
||||
margin-bottom: 20px;
|
||||
font-weight: $font-weight-regular;
|
||||
|
||||
overflow-wrap: break-word;
|
||||
word-wrap: break-word;
|
||||
hyphens: auto;
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
&__document {
|
||||
margin-bottom: $small-spacing;
|
||||
}
|
||||
|
||||
&__explanation {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
&__explanation-icon {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
fill: $color-brand;
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
&__explanation-text {
|
||||
color: $color-brand;
|
||||
font-family: $sans-serif-font-family;
|
||||
font-weight: $font-weight-regular;
|
||||
margin-right: $medium-spacing;
|
||||
}
|
||||
|
||||
&__reopen {
|
||||
@include small-text;
|
||||
cursor: pointer;
|
||||
color: $color-charcoal-light;
|
||||
}
|
||||
overflow-wrap: break-word;
|
||||
word-wrap: break-word;
|
||||
hyphens: auto;
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
&__document {
|
||||
margin-bottom: $small-spacing;
|
||||
}
|
||||
|
||||
&__explanation {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
&__explanation-icon {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
fill: $color-brand;
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
&__explanation-text {
|
||||
color: $color-brand;
|
||||
font-family: $sans-serif-font-family;
|
||||
font-weight: $font-weight-regular;
|
||||
margin-right: $medium-spacing;
|
||||
}
|
||||
|
||||
&__reopen {
|
||||
@include small-text;
|
||||
cursor: pointer;
|
||||
color: $color-charcoal-light;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
||||
|
|
@ -48,116 +41,113 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import {defineAsyncComponent} from 'vue';
|
||||
const SubmissionInput = defineAsyncComponent(() => import('@/components/content-blocks/assignment/SubmissionInput'));
|
||||
const FinalSubmission = defineAsyncComponent(() => import('@/components/content-blocks/assignment/FinalSubmission'));
|
||||
const FileUpload = defineAsyncComponent(() => import('@/components/ui/file-upload/FileUpload'));
|
||||
import { defineAsyncComponent } from 'vue';
|
||||
const SubmissionInput = defineAsyncComponent(() => import('@/components/content-blocks/assignment/SubmissionInput'));
|
||||
const FinalSubmission = defineAsyncComponent(() => import('@/components/content-blocks/assignment/FinalSubmission'));
|
||||
const FileUpload = defineAsyncComponent(() => import('@/components/ui/file-upload/FileUpload'));
|
||||
|
||||
|
||||
export default {
|
||||
props: {
|
||||
userInput: Object,
|
||||
saved: Boolean,
|
||||
placeholder: String,
|
||||
action: String,
|
||||
reopen: Function,
|
||||
document: String,
|
||||
readOnly: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
spellcheck: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
spellcheckLoading: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
sharedMsg: String,
|
||||
export default {
|
||||
props: {
|
||||
userInput: Object,
|
||||
saved: Boolean,
|
||||
placeholder: String,
|
||||
action: String,
|
||||
reopen: Function,
|
||||
document: String,
|
||||
readOnly: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
|
||||
components: {
|
||||
FileUpload,
|
||||
SubmissionInput,
|
||||
FinalSubmission,
|
||||
spellcheck: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
|
||||
computed: {
|
||||
final() {
|
||||
return !!this.userInput && this.userInput.final;
|
||||
},
|
||||
isFinalOrReadOnly() {
|
||||
return this.final || this.readOnly;
|
||||
},
|
||||
allowsDocuments() {
|
||||
return 'document' in this.userInput;
|
||||
},
|
||||
showSpellcheckButton() {
|
||||
return this.spellcheck && process.env.VUE_APP_ENABLE_SPELLCHECK;
|
||||
},
|
||||
spellcheckText() {
|
||||
if (!this.spellcheckLoading) {
|
||||
return 'Rechtschreibung prüfen';
|
||||
} else {
|
||||
return 'Wird geprüft...';
|
||||
}
|
||||
},
|
||||
spellcheckLoading: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
sharedMsg: String,
|
||||
},
|
||||
|
||||
methods: {
|
||||
reopenSubmission() {
|
||||
this.$emit('reopen');
|
||||
},
|
||||
saveInput(input) {
|
||||
this.$emit('saveInput', input);
|
||||
},
|
||||
changeDocumentUrl(documentUrl) {
|
||||
this.$emit('changeDocumentUrl', documentUrl);
|
||||
},
|
||||
components: {
|
||||
FileUpload,
|
||||
SubmissionInput,
|
||||
FinalSubmission,
|
||||
},
|
||||
|
||||
computed: {
|
||||
final() {
|
||||
return !!this.userInput && this.userInput.final;
|
||||
},
|
||||
isFinalOrReadOnly() {
|
||||
return this.final || this.readOnly;
|
||||
},
|
||||
allowsDocuments() {
|
||||
return 'document' in this.userInput;
|
||||
},
|
||||
showSpellcheckButton() {
|
||||
return this.spellcheck && process.env.VUE_APP_ENABLE_SPELLCHECK;
|
||||
},
|
||||
spellcheckText() {
|
||||
if (!this.spellcheckLoading) {
|
||||
return 'Rechtschreibung prüfen';
|
||||
} else {
|
||||
return 'Wird geprüft...';
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
};
|
||||
methods: {
|
||||
reopenSubmission() {
|
||||
this.$emit('reopen');
|
||||
},
|
||||
saveInput(input) {
|
||||
this.$emit('saveInput', input);
|
||||
},
|
||||
changeDocumentUrl(documentUrl) {
|
||||
this.$emit('changeDocumentUrl', documentUrl);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import '~styles/helpers';
|
||||
@import '~styles/helpers';
|
||||
|
||||
.submission-form-container {
|
||||
@include form-with-border;
|
||||
.submission-form-container {
|
||||
@include form-with-border;
|
||||
|
||||
margin-bottom: $medium-spacing;
|
||||
margin-bottom: $medium-spacing;
|
||||
|
||||
display: none;
|
||||
@include desktop {
|
||||
display: block;
|
||||
}
|
||||
display: none;
|
||||
@include desktop {
|
||||
display: block;
|
||||
}
|
||||
|
||||
&__inputs {
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
&__inputs {
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
&__submit {
|
||||
margin-right: $medium-spacing;
|
||||
}
|
||||
&__submit {
|
||||
margin-right: $medium-spacing;
|
||||
}
|
||||
|
||||
&__actions {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
&__actions {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
&__document {
|
||||
&:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
&__spellcheck {
|
||||
/* so the button does not change size when changing the text */
|
||||
width: 235px;
|
||||
text-align: center;
|
||||
display: inline-block;
|
||||
&__document {
|
||||
&:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
&__spellcheck {
|
||||
/* so the button does not change size when changing the text */
|
||||
width: 235px;
|
||||
text-align: center;
|
||||
display: inline-block;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -4,75 +4,73 @@
|
|||
:placeholder="placeholder"
|
||||
:readonly="readonly"
|
||||
:value="inputText"
|
||||
:class="{'submission-form__textarea--readonly': readonly}"
|
||||
:class="{ 'submission-form__textarea--readonly': readonly }"
|
||||
data-cy="submission-textarea"
|
||||
rows="1"
|
||||
class="submission-form__textarea"
|
||||
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>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {defineAsyncComponent} from 'vue';
|
||||
const TickCircleIcon = defineAsyncComponent(() => import(/* webpackChunkName: "icons" */'@/components/icons/TickCircleIcon'));
|
||||
const LoadingIcon = defineAsyncComponent(() => import(/* webpackChunkName: "icons" */'@/components/icons/LoadingIcon'));
|
||||
import { defineAsyncComponent } from 'vue';
|
||||
const TickCircleIcon = defineAsyncComponent(() =>
|
||||
import(/* webpackChunkName: "icons" */ '@/components/icons/TickCircleIcon')
|
||||
);
|
||||
const LoadingIcon = defineAsyncComponent(() =>
|
||||
import(/* webpackChunkName: "icons" */ '@/components/icons/LoadingIcon')
|
||||
);
|
||||
|
||||
export default {
|
||||
props: {
|
||||
inputText: String,
|
||||
saved: Boolean,
|
||||
readonly: Boolean,
|
||||
placeholder: {
|
||||
type: String,
|
||||
default: 'Ergebnis erfassen'
|
||||
}
|
||||
export default {
|
||||
props: {
|
||||
inputText: String,
|
||||
saved: Boolean,
|
||||
readonly: Boolean,
|
||||
placeholder: {
|
||||
type: String,
|
||||
default: 'Ergebnis erfassen',
|
||||
},
|
||||
components: {
|
||||
TickCircleIcon,
|
||||
LoadingIcon
|
||||
}
|
||||
};
|
||||
},
|
||||
components: {
|
||||
TickCircleIcon,
|
||||
LoadingIcon,
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import "~styles/helpers";
|
||||
@import '~styles/helpers';
|
||||
|
||||
.submission-form {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
.submission-form {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
|
||||
&__textarea {
|
||||
@include borderless-textarea;
|
||||
}
|
||||
|
||||
&__save-status {
|
||||
position: relative;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
&__save-status-icon {
|
||||
width: 22px;
|
||||
height: 22px;
|
||||
fill: $color-silver-dark;
|
||||
}
|
||||
|
||||
&__saving-icon {
|
||||
@include spin;
|
||||
}
|
||||
&__textarea {
|
||||
@include borderless-textarea;
|
||||
}
|
||||
|
||||
&__save-status {
|
||||
position: relative;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
&__save-status-icon {
|
||||
width: 22px;
|
||||
height: 22px;
|
||||
fill: $color-silver-dark;
|
||||
}
|
||||
|
||||
&__saving-icon {
|
||||
@include spin;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
@ -23,41 +23,41 @@
|
|||
import {defineAsyncComponent} from 'vue';
|
||||
const InfoIcon = defineAsyncComponent(() => import(/* webpackChunkName: "icons" */'@/components/icons/InfoIcon'));
|
||||
|
||||
export default {
|
||||
props: ['value', 'index'],
|
||||
export default {
|
||||
props: ['value', 'index'],
|
||||
|
||||
components: {
|
||||
InfoIcon
|
||||
}
|
||||
};
|
||||
components: {
|
||||
InfoIcon,
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
@import "~styles/helpers";
|
||||
@import '~styles/helpers';
|
||||
|
||||
.assignment-form {
|
||||
display: grid;
|
||||
grid-auto-rows: auto;
|
||||
grid-row-gap: 13px;
|
||||
grid-template-columns: 40px 1fr;
|
||||
grid-column-gap: 16px;
|
||||
align-items: center;
|
||||
.assignment-form {
|
||||
display: grid;
|
||||
grid-auto-rows: auto;
|
||||
grid-row-gap: 13px;
|
||||
grid-template-columns: 40px 1fr;
|
||||
grid-column-gap: 16px;
|
||||
align-items: center;
|
||||
|
||||
&__title {
|
||||
width: $modal-input-width;
|
||||
grid-column: span 2;
|
||||
}
|
||||
|
||||
&__exercise-text {
|
||||
width: $modal-input-width;
|
||||
grid-column: span 2;
|
||||
}
|
||||
|
||||
&__help-icon {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
}
|
||||
|
||||
&__help-description {
|
||||
}
|
||||
&__title {
|
||||
width: $modal-input-width;
|
||||
grid-column: span 2;
|
||||
}
|
||||
|
||||
&__exercise-text {
|
||||
width: $modal-input-width;
|
||||
grid-column: span 2;
|
||||
}
|
||||
|
||||
&__help-icon {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
}
|
||||
|
||||
&__help-description {
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
@ -34,100 +18,103 @@
|
|||
|
||||
const DocumentIcon = defineAsyncComponent(() => import(/* webpackChunkName: "icons" */'@/components/icons/DocumentIcon'));
|
||||
|
||||
export default {
|
||||
props: ['value', 'index'],
|
||||
export default {
|
||||
props: ['value', 'index'],
|
||||
|
||||
components: {
|
||||
LoadingIcon,
|
||||
DocumentIcon,
|
||||
components: {
|
||||
LoadingIcon,
|
||||
DocumentIcon,
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
loading: false,
|
||||
};
|
||||
},
|
||||
|
||||
computed: {
|
||||
previewUrl() {
|
||||
if (this.value && this.value.url) {
|
||||
return this.value.url;
|
||||
}
|
||||
return null;
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
loading: false,
|
||||
};
|
||||
previewLink() {
|
||||
if (this.value && this.value.url) {
|
||||
const parts = this.value.url.split('/');
|
||||
return parts[parts.length - 1];
|
||||
}
|
||||
return '';
|
||||
},
|
||||
},
|
||||
|
||||
computed: {
|
||||
previewUrl() {
|
||||
if (this.value && this.value.url) {
|
||||
return this.value.url;
|
||||
}
|
||||
return null;
|
||||
},
|
||||
previewLink() {
|
||||
if (this.value && this.value.url) {
|
||||
const parts = this.value.url.split('/');
|
||||
return parts[parts.length - 1];
|
||||
}
|
||||
return '';
|
||||
},
|
||||
},
|
||||
|
||||
mounted() {
|
||||
uploadcare(this, url => {
|
||||
mounted() {
|
||||
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 {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
.document-form {
|
||||
&__uploaded {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
&__link {
|
||||
text-decoration: underline;
|
||||
}
|
||||
&__link {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
&__spinner {
|
||||
width: 100%;
|
||||
&__spinner {
|
||||
width: 100%;
|
||||
height: 150px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
&__loading-icon {
|
||||
@include spin;
|
||||
fill: $color-silver-dark;
|
||||
}
|
||||
|
||||
&__icon {
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
margin-right: $small-spacing;
|
||||
}
|
||||
|
||||
&__file-input {
|
||||
width: 0.1px;
|
||||
height: 0.1px;
|
||||
overflow: hidden;
|
||||
opacity: 0;
|
||||
position: absolute;
|
||||
z-index: -1;
|
||||
|
||||
& + label {
|
||||
cursor: pointer;
|
||||
background-color: $color-silver-light;
|
||||
height: 150px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
&__loading-icon {
|
||||
@include spin;
|
||||
fill: $color-silver-dark;
|
||||
}
|
||||
|
||||
&__icon {
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
margin-right: $small-spacing;
|
||||
}
|
||||
|
||||
&__file-input {
|
||||
width: 0.1px;
|
||||
height: 0.1px;
|
||||
overflow: hidden;
|
||||
opacity: 0;
|
||||
position: absolute;
|
||||
z-index: -1;
|
||||
|
||||
& + label {
|
||||
cursor: pointer;
|
||||
background-color: $color-silver-light;
|
||||
height: 150px;
|
||||
display: flex;
|
||||
width: 100%;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
font-family: $sans-serif-font-family;
|
||||
font-weight: $font-weight-regular;
|
||||
text-decoration: underline;
|
||||
}
|
||||
align-items: center;
|
||||
font-family: $sans-serif-font-family;
|
||||
font-weight: $font-weight-regular;
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -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">
|
||||
|
|
@ -40,67 +30,65 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import YoutubeEmbed from '@/components/videos/YoutubeEmbed';
|
||||
import VimeoEmbed from '@/components/videos/VimeoEmbed';
|
||||
import SrfEmbed from '@/components/videos/SrfEmbed';
|
||||
import {isVimeoUrl, isYoutubeUrl, isSrfUrl} from '@/helpers/video';
|
||||
import {defineAsyncComponent} from 'vue';
|
||||
const InfoIcon = defineAsyncComponent(() => import(/* webpackChunkName: "icons" */'@/components/icons/InfoIcon'));
|
||||
import YoutubeEmbed from '@/components/videos/YoutubeEmbed';
|
||||
import VimeoEmbed from '@/components/videos/VimeoEmbed';
|
||||
import SrfEmbed from '@/components/videos/SrfEmbed';
|
||||
import { isVimeoUrl, isYoutubeUrl, isSrfUrl } from '@/helpers/video';
|
||||
import { defineAsyncComponent } from 'vue';
|
||||
const InfoIcon = defineAsyncComponent(() => import(/* webpackChunkName: "icons" */ '@/components/icons/InfoIcon'));
|
||||
|
||||
export default {
|
||||
props: ['value', 'index'],
|
||||
export default {
|
||||
props: ['value', 'index'],
|
||||
|
||||
components: {
|
||||
InfoIcon,
|
||||
YoutubeEmbed,
|
||||
VimeoEmbed,
|
||||
SrfEmbed
|
||||
components: {
|
||||
InfoIcon,
|
||||
YoutubeEmbed,
|
||||
VimeoEmbed,
|
||||
SrfEmbed,
|
||||
},
|
||||
|
||||
computed: {
|
||||
isYoutube() {
|
||||
return isYoutubeUrl(this.value.url);
|
||||
},
|
||||
|
||||
computed: {
|
||||
isYoutube() {
|
||||
return isYoutubeUrl(this.value.url);
|
||||
},
|
||||
isVimeo() {
|
||||
return isVimeoUrl(this.value.url);
|
||||
},
|
||||
isSrf() {
|
||||
return isSrfUrl(this.value.url);
|
||||
}
|
||||
}
|
||||
};
|
||||
isVimeo() {
|
||||
return isVimeoUrl(this.value.url);
|
||||
},
|
||||
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;
|
||||
grid-auto-rows: auto;
|
||||
grid-template-columns: 40px 1fr;
|
||||
grid-column-gap: 16px;
|
||||
grid-row-gap: 20px;
|
||||
align-items: center;
|
||||
.video-form {
|
||||
display: grid;
|
||||
grid-auto-rows: auto;
|
||||
grid-template-columns: 40px 1fr;
|
||||
grid-column-gap: 16px;
|
||||
grid-row-gap: 20px;
|
||||
align-items: center;
|
||||
|
||||
&__help-icon {
|
||||
|
||||
}
|
||||
|
||||
&__help-description {
|
||||
|
||||
}
|
||||
|
||||
&__platform-link {
|
||||
font-family: $sans-serif-font-family;
|
||||
text-decoration: underline;
|
||||
font-weight: $font-weight-regular;
|
||||
font-size: toRem(17px);
|
||||
}
|
||||
|
||||
&__video-link {
|
||||
grid-column: 1 / span 2;
|
||||
width: $modal-input-width
|
||||
}
|
||||
&__help-icon {
|
||||
}
|
||||
|
||||
&__help-description {
|
||||
}
|
||||
|
||||
&__platform-link {
|
||||
font-family: $sans-serif-font-family;
|
||||
text-decoration: underline;
|
||||
font-weight: $font-weight-regular;
|
||||
font-size: toRem(17px);
|
||||
}
|
||||
|
||||
&__video-link {
|
||||
grid-column: 1 / span 2;
|
||||
width: $modal-input-width;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
<template>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 378 505">
|
||||
<svg xmlns="http://www.w3.org/2000/svg"xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 378 505">
|
||||
<defs>
|
||||
<clipPath id="b">
|
||||
<path
|
||||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -1,179 +1,169 @@
|
|||
<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'));
|
||||
import INSTRUMENT_FILTER_QUERY from 'gql/local/instrumentFilter.gql';
|
||||
import { defineAsyncComponent } from 'vue';
|
||||
const ChevronRight = defineAsyncComponent(() =>
|
||||
import(/* webpackChunkName: "icons" */ '@/components/icons/ChevronRight')
|
||||
);
|
||||
|
||||
export default {
|
||||
props: {
|
||||
text: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
id: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
isCategory: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
category: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
export default {
|
||||
props: {
|
||||
text: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
id: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
isCategory: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
category: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
},
|
||||
|
||||
components: {
|
||||
ChevronRight,
|
||||
},
|
||||
components: {
|
||||
ChevronRight,
|
||||
},
|
||||
|
||||
emits: ['filter'],
|
||||
|
||||
apollo: {
|
||||
instrumentFilter: {
|
||||
query: INSTRUMENT_FILTER_QUERY,
|
||||
},
|
||||
apollo: {
|
||||
instrumentFilter: {
|
||||
query: INSTRUMENT_FILTER_QUERY,
|
||||
},
|
||||
},
|
||||
|
||||
data() {
|
||||
data() {
|
||||
return {
|
||||
instrumentFilter: {
|
||||
currentFilter: '',
|
||||
},
|
||||
};
|
||||
},
|
||||
|
||||
computed: {
|
||||
isActive() {
|
||||
if (!this.instrumentFilter.currentFilter) {
|
||||
return this.id === '';
|
||||
}
|
||||
// eslint-disable-next-line
|
||||
const [_, identifier] = this.instrumentFilter.currentFilter.split(':');
|
||||
return this.id === identifier;
|
||||
},
|
||||
// todo: use dynamic css class with v-bind once we're on Vue 3: https://vuejs.org/api/sfc-css-features.html#v-bind-in-css
|
||||
activeStyle() {
|
||||
if (this.isActive) {
|
||||
return {
|
||||
backgroundColor: this.category.background,
|
||||
};
|
||||
}
|
||||
return {};
|
||||
},
|
||||
// todo: use dynamic css class with v-bind once we're on Vue 3: https://vuejs.org/api/sfc-css-features.html#v-bind-in-css
|
||||
categoryStyle() {
|
||||
if (this.isCategory) {
|
||||
return {
|
||||
color: this.category.foreground,
|
||||
};
|
||||
}
|
||||
return {};
|
||||
},
|
||||
// todo: use dynamic css class with v-bind once we're on Vue 3: https://vuejs.org/api/sfc-css-features.html#v-bind-in-css
|
||||
typeClass() {
|
||||
return {
|
||||
instrumentFilter: {
|
||||
currentFilter: '',
|
||||
},
|
||||
'filter-entry--active': this.isActive,
|
||||
'filter-entry--category': this.isCategory,
|
||||
};
|
||||
},
|
||||
|
||||
computed: {
|
||||
isActive() {
|
||||
if (!this.instrumentFilter.currentFilter) {
|
||||
return this.id === '';
|
||||
}
|
||||
// eslint-disable-next-line
|
||||
const [_, identifier] = this.instrumentFilter.currentFilter.split(':');
|
||||
return this.id === identifier;
|
||||
},
|
||||
// todo: use dynamic css class with v-bind once we're on Vue 3: https://vuejs.org/api/sfc-css-features.html#v-bind-in-css
|
||||
activeStyle() {
|
||||
if (this.isActive) {
|
||||
return {
|
||||
backgroundColor: this.category.background,
|
||||
};
|
||||
}
|
||||
return {};
|
||||
},
|
||||
// todo: use dynamic css class with v-bind once we're on Vue 3: https://vuejs.org/api/sfc-css-features.html#v-bind-in-css
|
||||
categoryStyle() {
|
||||
if (this.isCategory) {
|
||||
return {
|
||||
color: this.category.foreground,
|
||||
};
|
||||
}
|
||||
return {};
|
||||
},
|
||||
// todo: use dynamic css class with v-bind once we're on Vue 3: https://vuejs.org/api/sfc-css-features.html#v-bind-in-css
|
||||
typeClass() {
|
||||
return {
|
||||
'filter-entry--active': this.isActive,
|
||||
'filter-entry--category': this.isCategory,
|
||||
};
|
||||
},
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import '~styles/helpers';
|
||||
@import '~styles/helpers';
|
||||
|
||||
.filter-entry {
|
||||
.filter-entry {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
|
||||
&__text {
|
||||
@include sub-heading;
|
||||
line-height: 1.5;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
&__icon-wrapper {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
justify-content: center;
|
||||
height: 20px;
|
||||
width: 20px;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
&__text {
|
||||
@include sub-heading;
|
||||
line-height: 1.5;
|
||||
color: inherit;
|
||||
&__icon {
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
}
|
||||
|
||||
$root: &;
|
||||
|
||||
@mixin filter-block($color) {
|
||||
&#{$root}--category {
|
||||
color: $color;
|
||||
}
|
||||
|
||||
&__icon-wrapper {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 20px;
|
||||
width: 20px;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
&__icon {
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
}
|
||||
|
||||
$root: &;
|
||||
|
||||
@mixin filter-block($color) {
|
||||
&#{$root}--category {
|
||||
color: $color;
|
||||
}
|
||||
|
||||
&#{$root}--active {
|
||||
#{$root}__icon-wrapper {
|
||||
background-color: $color;
|
||||
}
|
||||
}
|
||||
|
||||
#{$root}__icon {
|
||||
fill: $color;
|
||||
}
|
||||
}
|
||||
|
||||
&--language-communication {
|
||||
@include filter-block($color-accent-1-dark);
|
||||
}
|
||||
|
||||
&--society {
|
||||
@include filter-block($color-accent-2-dark);
|
||||
}
|
||||
|
||||
&--interdisciplinary {
|
||||
@include filter-block($color-accent-4-dark);
|
||||
}
|
||||
|
||||
&--active {
|
||||
#{$root}__text {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
&#{$root}--active {
|
||||
#{$root}__icon-wrapper {
|
||||
background-color: black;
|
||||
background-color: $color;
|
||||
}
|
||||
}
|
||||
|
||||
#{$root}__icon {
|
||||
fill: white;
|
||||
}
|
||||
#{$root}__icon {
|
||||
fill: $color;
|
||||
}
|
||||
}
|
||||
|
||||
&--language-communication {
|
||||
@include filter-block($color-accent-1-dark);
|
||||
}
|
||||
|
||||
&--society {
|
||||
@include filter-block($color-accent-2-dark);
|
||||
}
|
||||
|
||||
&--interdisciplinary {
|
||||
@include filter-block($color-accent-4-dark);
|
||||
}
|
||||
|
||||
&--active {
|
||||
#{$root}__text {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
#{$root}__icon-wrapper {
|
||||
background-color: black;
|
||||
}
|
||||
|
||||
#{$root}__icon {
|
||||
fill: white;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -24,77 +24,76 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import {defineComponent} from 'vue';
|
||||
import FilterEntry from '@/components/instruments/FilterEntry';
|
||||
import { defineComponent } from 'vue';
|
||||
import FilterEntry from '@/components/instruments/FilterEntry';
|
||||
|
||||
import SET_FILTER_MUTATION from 'gql/local/mutations/setInstrumentFilter.gql';
|
||||
import INSTRUMENT_FILTER_QUERY from 'gql/local/instrumentFilter.gql';
|
||||
import SET_FILTER_MUTATION from 'gql/local/mutations/setInstrumentFilter.gql';
|
||||
import INSTRUMENT_FILTER_QUERY from 'gql/local/instrumentFilter.gql';
|
||||
|
||||
export default defineComponent({
|
||||
props: {
|
||||
title: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
types: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
category: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
export default defineComponent({
|
||||
props: {
|
||||
title: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
components: {
|
||||
FilterEntry,
|
||||
types: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
|
||||
apollo: {
|
||||
instrumentFilter: {
|
||||
query: INSTRUMENT_FILTER_QUERY
|
||||
}
|
||||
category: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
instrumentFilter: {
|
||||
currentFilter: ''
|
||||
}
|
||||
};
|
||||
},
|
||||
inheritAttrs: false,
|
||||
components: {
|
||||
FilterEntry,
|
||||
},
|
||||
|
||||
methods: {
|
||||
setCategoryFilter(category) {
|
||||
if (category) {
|
||||
this.setFilter(`category:${category}`);
|
||||
} else {
|
||||
this.setFilter(``);
|
||||
}
|
||||
apollo: {
|
||||
instrumentFilter: {
|
||||
query: INSTRUMENT_FILTER_QUERY,
|
||||
},
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
instrumentFilter: {
|
||||
currentFilter: '',
|
||||
},
|
||||
setFilter(filter) {
|
||||
this.$apollo.mutate({
|
||||
mutation: SET_FILTER_MUTATION,
|
||||
variables: {
|
||||
filter
|
||||
}
|
||||
});
|
||||
};
|
||||
},
|
||||
inheritAttrs: false,
|
||||
|
||||
methods: {
|
||||
setCategoryFilter(category) {
|
||||
if (category) {
|
||||
this.setFilter(`category:${category}`);
|
||||
} else {
|
||||
this.setFilter(``);
|
||||
}
|
||||
},
|
||||
setFilter(filter) {
|
||||
this.$apollo.mutate({
|
||||
mutation: SET_FILTER_MUTATION,
|
||||
variables: {
|
||||
filter,
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import '~styles/helpers';
|
||||
@import '~styles/helpers';
|
||||
|
||||
.filter-group {
|
||||
border-bottom: 1px solid $color-silver;
|
||||
padding: $medium-spacing 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
.filter-group {
|
||||
border-bottom: 1px solid $color-silver;
|
||||
padding: $medium-spacing 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
&__children {
|
||||
padding-left: $medium-spacing;
|
||||
}
|
||||
&__children {
|
||||
padding-left: $medium-spacing;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -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 }}
|
||||
|
|
@ -22,8 +16,8 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: ['metaTitle', 'title', 'teaser', 'id', 'slug', 'heroImage'],
|
||||
export default {
|
||||
props: ['metaTitle', 'title', 'teaser', 'id', 'slug', 'heroImage'],
|
||||
|
||||
computed: {
|
||||
moduleLink() {
|
||||
|
|
@ -38,55 +32,56 @@
|
|||
return {};
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import "~styles/helpers";
|
||||
|
||||
.module-teaser {
|
||||
box-shadow: 0 3px 9px 0 rgba(0, 0, 0, 0.12);
|
||||
border: 1px solid #E2E2E2;
|
||||
height: 330px;
|
||||
max-width: 380px;
|
||||
width: 100%;
|
||||
border-radius: 12px;
|
||||
overflow: hidden;
|
||||
box-sizing: border-box;
|
||||
cursor: pointer;
|
||||
.module-teaser {
|
||||
box-shadow: 0 3px 9px 0 rgba(0, 0, 0, 0.12);
|
||||
border: 1px solid #e2e2e2;
|
||||
height: 330px;
|
||||
max-width: 380px;
|
||||
width: 100%;
|
||||
border-radius: 12px;
|
||||
overflow: hidden;
|
||||
box-sizing: border-box;
|
||||
cursor: pointer;
|
||||
|
||||
&--small {
|
||||
height: 300px;
|
||||
}
|
||||
|
||||
&__image {
|
||||
width: 100%;
|
||||
max-height: 150px;
|
||||
height: 150px;
|
||||
background-position: center;
|
||||
background-size: 100% auto;
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
|
||||
&__body {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
&__meta-title {
|
||||
color: $color-silver-dark;
|
||||
margin-bottom: $large-spacing;
|
||||
@include regular-text;
|
||||
}
|
||||
|
||||
&__title {
|
||||
@include heading-3;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
&__description {
|
||||
line-height: $default-line-height;
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
&--small {
|
||||
height: 300px;
|
||||
}
|
||||
|
||||
&__image {
|
||||
width: 100%;
|
||||
max-height: 150px;
|
||||
height: 150px;
|
||||
background-position: center;
|
||||
background-size: 100% auto;
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
|
||||
&__body {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
&__meta-title {
|
||||
color: $color-silver-dark;
|
||||
margin-bottom: $large-spacing;
|
||||
@include regular-text;
|
||||
}
|
||||
|
||||
&__title {
|
||||
@include heading-3;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
&__description {
|
||||
line-height: $default-line-height;
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -1,10 +1,7 @@
|
|||
<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--bookmarked': bookmarked }"
|
||||
class="bookmark-actions__action bookmark-actions__bookmark"
|
||||
data-cy="bookmark-action"
|
||||
@click="$emit('bookmark')"
|
||||
|
|
@ -37,69 +34,69 @@
|
|||
const AddNoteIcon = defineAsyncComponent(() => import(/* webpackChunkName: "icons" */'@/components/icons/AddNoteIcon'));
|
||||
const NoteIcon = defineAsyncComponent(() => import(/* webpackChunkName: "icons" */'@/components/icons/NoteIcon'));
|
||||
|
||||
export default {
|
||||
props: {
|
||||
bookmarked: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
note: {
|
||||
type: [Object, Boolean],
|
||||
default: false
|
||||
},
|
||||
editMode: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
export default {
|
||||
props: {
|
||||
bookmarked: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
components: {
|
||||
BookmarkIcon,
|
||||
AddNoteIcon,
|
||||
NoteIcon
|
||||
note: {
|
||||
type: [Object, Boolean],
|
||||
default: false,
|
||||
},
|
||||
};
|
||||
editMode: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
components: {
|
||||
BookmarkIcon,
|
||||
AddNoteIcon,
|
||||
NoteIcon,
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import "~styles/helpers";
|
||||
@import '~styles/helpers';
|
||||
|
||||
.bookmark-actions {
|
||||
height: 100%;
|
||||
min-height: 60px;
|
||||
.bookmark-actions {
|
||||
height: 100%;
|
||||
min-height: 60px;
|
||||
|
||||
padding: 0 2*$large-spacing;
|
||||
position: absolute;
|
||||
right: -5*$large-spacing;
|
||||
padding: 0 2 * $large-spacing;
|
||||
position: absolute;
|
||||
right: -5 * $large-spacing;
|
||||
|
||||
display: none;
|
||||
display: none;
|
||||
|
||||
@include desktop {
|
||||
display: flex;
|
||||
}
|
||||
@include desktop {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
flex-direction: column;
|
||||
align-content: center;
|
||||
flex-direction: column;
|
||||
align-content: center;
|
||||
|
||||
&__action {
|
||||
opacity: 0;
|
||||
transition: opacity 0.3s;
|
||||
cursor: pointer;
|
||||
width: 26px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
&__action {
|
||||
opacity: 0;
|
||||
transition: opacity 0.3s;
|
||||
cursor: pointer;
|
||||
width: 26px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
|
||||
&--bookmarked, &--noted {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
$parent: &;
|
||||
|
||||
&:hover {
|
||||
#{$parent}__action {
|
||||
opacity: 1;
|
||||
}
|
||||
&--bookmarked,
|
||||
&--noted {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
$parent: &;
|
||||
|
||||
&:hover {
|
||||
#{$parent}__action {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -6,40 +6,37 @@
|
|||
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>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import ModalInput from '@/components/ModalInput';
|
||||
import {defineAsyncComponent} from 'vue';
|
||||
const TrashIcon = defineAsyncComponent(() => import(/* webpackChunkName: "icons" */'@/components/icons/TrashIcon'));
|
||||
import ModalInput from '@/components/ModalInput';
|
||||
import { defineAsyncComponent } from 'vue';
|
||||
const TrashIcon = defineAsyncComponent(() => import(/* webpackChunkName: "icons" */ '@/components/icons/TrashIcon'));
|
||||
|
||||
export default {
|
||||
props: ['objective'],
|
||||
export default {
|
||||
props: ['objective'],
|
||||
|
||||
components: {
|
||||
ModalInput,
|
||||
TrashIcon
|
||||
}
|
||||
};
|
||||
components: {
|
||||
ModalInput,
|
||||
TrashIcon,
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import "@/styles/_variables.scss";
|
||||
@import '@/styles/_variables.scss';
|
||||
|
||||
.objective-form {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 50px;
|
||||
margin-bottom: 10px;
|
||||
.objective-form {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 50px;
|
||||
margin-bottom: 10px;
|
||||
|
||||
&__input {
|
||||
width: $modal-input-width;
|
||||
}
|
||||
&__input {
|
||||
width: $modal-input-width;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
@ -15,35 +12,35 @@
|
|||
props: ['project'],
|
||||
components: {PlusIcon},
|
||||
|
||||
methods: {
|
||||
addProjectEntry() {
|
||||
this.$store.dispatch('addProjectEntry', this.project);
|
||||
}
|
||||
}
|
||||
};
|
||||
methods: {
|
||||
addProjectEntry() {
|
||||
this.$store.dispatch('addProjectEntry', this.project);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import "~styles/helpers";
|
||||
@import '~styles/helpers';
|
||||
|
||||
.add-project-entry {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border: 2px solid $color-brand;
|
||||
border-radius: $default-border-radius;
|
||||
cursor: pointer;
|
||||
.add-project-entry {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border: 2px solid $color-brand;
|
||||
border-radius: $default-border-radius;
|
||||
cursor: pointer;
|
||||
|
||||
&__icon {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
fill: $color-brand;
|
||||
margin-right: $small-spacing;
|
||||
}
|
||||
|
||||
&__text {
|
||||
@include navigation-link;
|
||||
color: $color-brand;
|
||||
}
|
||||
&__icon {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
fill: $color-brand;
|
||||
margin-right: $small-spacing;
|
||||
}
|
||||
|
||||
&__text {
|
||||
@include navigation-link;
|
||||
color: $color-brand;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
||||
|
|
@ -37,25 +21,25 @@
|
|||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import '~styles/helpers';
|
||||
@import '~styles/helpers';
|
||||
|
||||
.portfolio-onboarding {
|
||||
@include onboarding-page;
|
||||
.portfolio-onboarding {
|
||||
@include onboarding-page;
|
||||
|
||||
&__heading {
|
||||
@include heading-1;
|
||||
}
|
||||
|
||||
&__subheading {
|
||||
@include heading-2;
|
||||
}
|
||||
|
||||
&__illustration {
|
||||
@include onboarding-illustration;
|
||||
}
|
||||
|
||||
&__text {
|
||||
@include onboarding-text;
|
||||
}
|
||||
&__heading {
|
||||
@include heading-1;
|
||||
}
|
||||
|
||||
&__subheading {
|
||||
@include heading-2;
|
||||
}
|
||||
|
||||
&__illustration {
|
||||
@include onboarding-illustration;
|
||||
}
|
||||
|
||||
&__text {
|
||||
@include onboarding-text;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
@ -55,9 +27,9 @@ import DELETE_PROJECT_MUTATION from '@/graphql/gql/mutations/deleteProject.gql';
|
|||
import PROJECTS_QUERY from '@/graphql/gql/queries/allProjects.gql';
|
||||
|
||||
import updateProjectShareState from '@/mixins/update-project-share-state';
|
||||
import {removeAtIndex} from '@/graphql/immutable-operations.ts';
|
||||
import {defineAsyncComponent} from 'vue';
|
||||
const Ellipses = defineAsyncComponent(() => import(/* webpackChunkName: "icons" */'@/components/icons/Ellipses.vue'));
|
||||
import { removeAtIndex } from '@/graphql/immutable-operations.ts';
|
||||
import { defineAsyncComponent } from 'vue';
|
||||
const Ellipses = defineAsyncComponent(() => import(/* webpackChunkName: "icons" */ '@/components/icons/Ellipses.vue'));
|
||||
|
||||
export default {
|
||||
props: {
|
||||
|
|
@ -93,42 +65,50 @@ export default {
|
|||
this.showMenu = !this.showMenu;
|
||||
},
|
||||
editProject(slug) {
|
||||
this.$router.push({name: 'edit-project', params: {slug}});
|
||||
this.$router.push({ name: 'edit-project', params: { slug } });
|
||||
},
|
||||
deleteProject(slug) {
|
||||
this.$apollo.mutate({
|
||||
mutation: DELETE_PROJECT_MUTATION,
|
||||
variables: {
|
||||
input: {
|
||||
slug,
|
||||
this.$apollo
|
||||
.mutate({
|
||||
mutation: DELETE_PROJECT_MUTATION,
|
||||
variables: {
|
||||
input: {
|
||||
slug,
|
||||
},
|
||||
},
|
||||
},
|
||||
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);
|
||||
const projects = removeAtIndex(prevProjects, index);
|
||||
|
||||
const data = {
|
||||
projects
|
||||
};
|
||||
store.writeQuery({query: PROJECTS_QUERY, data});
|
||||
update(
|
||||
store,
|
||||
{
|
||||
data: {
|
||||
deleteProject: { success },
|
||||
},
|
||||
}
|
||||
}
|
||||
},
|
||||
}).then(() => {
|
||||
this.$router.push('/portfolio');
|
||||
});
|
||||
) {
|
||||
if (success) {
|
||||
const { projects: prevProjects } = store.readQuery({ query: PROJECTS_QUERY });
|
||||
|
||||
if (prevProjects) {
|
||||
let index = prevProjects.findIndex((project) => project.slug === slug);
|
||||
const projects = removeAtIndex(prevProjects, index);
|
||||
|
||||
const data = {
|
||||
projects,
|
||||
};
|
||||
store.writeQuery({ query: PROJECTS_QUERY, data });
|
||||
}
|
||||
}
|
||||
},
|
||||
})
|
||||
.then(() => {
|
||||
this.$router.push('/portfolio');
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import "~styles/_helpers.scss";
|
||||
@import '~styles/_helpers.scss';
|
||||
|
||||
.project-actions {
|
||||
position: relative;
|
||||
|
|
|
|||
|
|
@ -1,44 +1,22 @@
|
|||
<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"
|
||||
>
|
||||
<document-block :value="{url: documentUrl}" />
|
||||
<p class="project-entry__paragraph" v-if="documentUrl">
|
||||
<document-block :value="{ url: documentUrl }" />
|
||||
</p>
|
||||
<div class="project-entry__date">
|
||||
{{ createdDate }}
|
||||
|
|
@ -47,7 +25,7 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import MoreOptionsWidget from '@/components/MoreOptionsWidget';
|
||||
import MoreOptionsWidget from '@/components/MoreOptionsWidget';
|
||||
|
||||
import DELETE_PROJECT_ENTRY_MUTATION from '@/graphql/gql/mutations/deleteProjectEntry.gql';
|
||||
import PROJECT_QUERY from '@/graphql/gql/queries/projectQuery.gql';
|
||||
|
|
@ -57,100 +35,106 @@
|
|||
const DocumentBlock = defineAsyncComponent(() => import(/* webpackChunkName: "content-components" */'@/components/content-blocks/DocumentBlock'));
|
||||
|
||||
|
||||
export default {
|
||||
props: ['description', 'documentUrl', 'created', 'id', 'readOnly'],
|
||||
components: {
|
||||
DocumentBlock,
|
||||
MoreOptionsWidget,
|
||||
},
|
||||
export default {
|
||||
props: ['description', 'documentUrl', 'created', 'id', 'readOnly'],
|
||||
components: {
|
||||
DocumentBlock,
|
||||
MoreOptionsWidget,
|
||||
},
|
||||
|
||||
computed: {
|
||||
createdDate() {
|
||||
return dateFilter(this.created);
|
||||
},
|
||||
createdDateTime() {
|
||||
return dateTimeFilter(this.created);
|
||||
},
|
||||
computed: {
|
||||
createdDate() {
|
||||
return dateFilter(this.created);
|
||||
},
|
||||
createdDateTime() {
|
||||
return dateTimeFilter(this.created);
|
||||
},
|
||||
},
|
||||
|
||||
methods: {
|
||||
editProjectEntry() {
|
||||
this.$store.dispatch('editProjectEntry', this.id);
|
||||
},
|
||||
deleteProjectEntry() {
|
||||
const projectEntry = this; // otherwise we run into scope errors
|
||||
this.$apollo.mutate({
|
||||
mutation: DELETE_PROJECT_ENTRY_MUTATION,
|
||||
variables: {
|
||||
input: {
|
||||
id: this.id,
|
||||
methods: {
|
||||
editProjectEntry() {
|
||||
this.$store.dispatch('editProjectEntry', this.id);
|
||||
},
|
||||
deleteProjectEntry() {
|
||||
const projectEntry = this; // otherwise we run into scope errors
|
||||
this.$apollo.mutate({
|
||||
mutation: DELETE_PROJECT_ENTRY_MUTATION,
|
||||
variables: {
|
||||
input: {
|
||||
id: this.id,
|
||||
},
|
||||
},
|
||||
update(
|
||||
store,
|
||||
{
|
||||
data: {
|
||||
deleteProjectEntry: { success },
|
||||
},
|
||||
},
|
||||
update(store, {data: {deleteProjectEntry: {success}}}) {
|
||||
if (success) {
|
||||
const query = PROJECT_QUERY;
|
||||
const variables = {
|
||||
slug: projectEntry.$route.params.slug,
|
||||
}
|
||||
) {
|
||||
if (success) {
|
||||
const query = PROJECT_QUERY;
|
||||
const variables = {
|
||||
slug: projectEntry.$route.params.slug,
|
||||
};
|
||||
const { project } = store.readQuery({ query, variables });
|
||||
if (project) {
|
||||
const index = project.entries.findIndex((entry) => entry.id === projectEntry.id);
|
||||
const entries = removeAtIndex(project.entries, index);
|
||||
const data = {
|
||||
project: {
|
||||
...project,
|
||||
entries,
|
||||
},
|
||||
};
|
||||
const {project} = store.readQuery({query, variables});
|
||||
if (project) {
|
||||
const index = project.entries.findIndex(entry => entry.id === projectEntry.id);
|
||||
const entries = removeAtIndex(project.entries, index);
|
||||
const data = {
|
||||
project: {
|
||||
...project,
|
||||
entries,
|
||||
},
|
||||
};
|
||||
store.writeQuery({query, variables, data});
|
||||
}
|
||||
store.writeQuery({ query, variables, data });
|
||||
}
|
||||
},
|
||||
});
|
||||
},
|
||||
}
|
||||
},
|
||||
});
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import "~styles/helpers";
|
||||
@import '~styles/helpers';
|
||||
|
||||
.project-entry {
|
||||
background-color: $color-white;
|
||||
border-radius: $default-border-radius;
|
||||
padding: 30px 20px;
|
||||
position: relative;
|
||||
|
||||
&__heading {
|
||||
font-size: toRem(22px);
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
|
||||
&__paragraph {
|
||||
margin-bottom: 30px;
|
||||
white-space: pre-line;
|
||||
}
|
||||
|
||||
&__date {
|
||||
font-family: $sans-serif-font-family;
|
||||
color: $color-silver-dark;
|
||||
font-size: toRem(17px);
|
||||
}
|
||||
|
||||
&__link {
|
||||
cursor: pointer;
|
||||
@include heading-4;
|
||||
}
|
||||
|
||||
&__more {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
right: 10px;
|
||||
display: none;
|
||||
@include desktop {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
.project-entry {
|
||||
background-color: $color-white;
|
||||
border-radius: $default-border-radius;
|
||||
padding: 30px 20px;
|
||||
position: relative;
|
||||
|
||||
&__heading {
|
||||
font-size: toRem(22px);
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
|
||||
&__paragraph {
|
||||
margin-bottom: 30px;
|
||||
white-space: pre-line;
|
||||
}
|
||||
|
||||
&__date {
|
||||
font-family: $sans-serif-font-family;
|
||||
color: $color-silver-dark;
|
||||
font-size: toRem(17px);
|
||||
}
|
||||
|
||||
&__link {
|
||||
cursor: pointer;
|
||||
@include heading-4;
|
||||
}
|
||||
|
||||
&__more {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
right: 10px;
|
||||
display: none;
|
||||
@include desktop {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -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,106 +31,102 @@
|
|||
</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>
|
||||
|
||||
<script>
|
||||
import Modal from '@/components/Modal';
|
||||
import ButtonWithIconAndText from '@/components/ui/ButtonWithIconAndText';
|
||||
import Modal from '@/components/Modal';
|
||||
import ButtonWithIconAndText from '@/components/ui/ButtonWithIconAndText';
|
||||
|
||||
import {PROJECT_ENTRY_TEMPLATE} from '@/consts/strings.consts';
|
||||
import { PROJECT_ENTRY_TEMPLATE } from '@/consts/strings.consts';
|
||||
|
||||
import {defineAsyncComponent} from 'vue';
|
||||
const FileUpload = defineAsyncComponent(() => import('@/components/ui/file-upload/FileUpload'));
|
||||
import { defineAsyncComponent } from 'vue';
|
||||
const FileUpload = defineAsyncComponent(() => import('@/components/ui/file-upload/FileUpload'));
|
||||
|
||||
export default {
|
||||
props: {
|
||||
projectEntry: {
|
||||
type: Object,
|
||||
default: null,
|
||||
},
|
||||
export default {
|
||||
props: {
|
||||
projectEntry: {
|
||||
type: Object,
|
||||
default: null,
|
||||
},
|
||||
},
|
||||
|
||||
components: {
|
||||
FileUpload,
|
||||
ButtonWithIconAndText,
|
||||
Modal,
|
||||
},
|
||||
components: {
|
||||
FileUpload,
|
||||
ButtonWithIconAndText,
|
||||
Modal,
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
localProjectEntry: Object.assign({}, {
|
||||
data() {
|
||||
return {
|
||||
localProjectEntry: Object.assign(
|
||||
{},
|
||||
{
|
||||
...this.projectEntry,
|
||||
}),
|
||||
};
|
||||
},
|
||||
}
|
||||
),
|
||||
};
|
||||
},
|
||||
|
||||
methods: {
|
||||
setDocumentUrl(url) {
|
||||
this.localProjectEntry.documentUrl = url;
|
||||
},
|
||||
useTemplate() {
|
||||
this.localProjectEntry.description = `${this.localProjectEntry.description}${PROJECT_ENTRY_TEMPLATE}`;
|
||||
},
|
||||
methods: {
|
||||
setDocumentUrl(url) {
|
||||
this.localProjectEntry.documentUrl = url;
|
||||
},
|
||||
};
|
||||
useTemplate() {
|
||||
this.localProjectEntry.description = `${this.localProjectEntry.description}${PROJECT_ENTRY_TEMPLATE}`;
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import "~styles/helpers";
|
||||
@import '~styles/helpers';
|
||||
|
||||
.project-entry-modal {
|
||||
.project-entry-modal {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
&__form-field {
|
||||
@include inputstyle;
|
||||
padding: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
&__form-field {
|
||||
@include inputstyle;
|
||||
padding: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
grid-template-rows: auto 1rem;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
&__textarea {
|
||||
@include auto-grow;
|
||||
border: 0;
|
||||
min-height: 400px;
|
||||
padding: $medium-spacing;
|
||||
}
|
||||
|
||||
&__buttons {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
padding: $medium-spacing;
|
||||
}
|
||||
|
||||
&__button {
|
||||
@include regular-text;
|
||||
|
||||
&--template {
|
||||
}
|
||||
|
||||
&--document {
|
||||
}
|
||||
}
|
||||
|
||||
&__heading {
|
||||
@include heading-3;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
grid-template-rows: auto 1rem;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
&__textarea {
|
||||
@include auto-grow;
|
||||
border: 0;
|
||||
min-height: 400px;
|
||||
padding: $medium-spacing;
|
||||
}
|
||||
|
||||
&__buttons {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
padding: $medium-spacing;
|
||||
}
|
||||
|
||||
&__button {
|
||||
@include regular-text;
|
||||
|
||||
&--template {
|
||||
}
|
||||
|
||||
&--document {
|
||||
}
|
||||
}
|
||||
|
||||
&__heading {
|
||||
@include heading-3;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
<owner-widget :owner="project.student" class="project__owner" />
|
||||
|
||||
<entry-count-widget class="project__entry-count" :verbose="false" :entry-count="project.entriesCount" />
|
||||
<entry-count-widgetclass="project__entry-count" :verbose="false" :entry-count="project.entriesCount" />
|
||||
</router-link>
|
||||
<project-actions
|
||||
:final="project.final"
|
||||
|
|
@ -68,22 +68,20 @@ export default {
|
|||
align-items: flex-start;
|
||||
flex-direction: column;
|
||||
@include desktop {
|
||||
display: flex;
|
||||
flex: 80%;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
display: flex;
|
||||
flex: 80%;
|
||||
flex-direction: row;align-items: center;
|
||||
}}
|
||||
|
||||
&__title {
|
||||
flex: 50%;
|
||||
@include heading-4;
|
||||
grid-column: 1 / span 2;
|
||||
grid-column: 1 / span 2;
|
||||
}
|
||||
|
||||
&__owner {
|
||||
flex: 40%;
|
||||
grid-column: 1 / span 1;
|
||||
grid-column: 1 / span 1;
|
||||
}
|
||||
|
||||
&__actions {
|
||||
|
|
@ -96,7 +94,6 @@ export default {
|
|||
|
||||
&__entry-count {
|
||||
justify-self: flex-end;
|
||||
grid-column: 2 / span 1;
|
||||
}
|
||||
grid-column: 2 / span 1;}
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -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">
|
||||
|
|
@ -12,37 +10,37 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import {defineAsyncComponent} from 'vue';
|
||||
const ShareIcon = defineAsyncComponent(() => import(/* webpackChunkName: "icons" */'@/components/icons/ShareIcon'));
|
||||
import { defineAsyncComponent } from 'vue';
|
||||
const ShareIcon = defineAsyncComponent(() => import(/* webpackChunkName: "icons" */ '@/components/icons/ShareIcon'));
|
||||
|
||||
export default {
|
||||
props: {
|
||||
final: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
export default {
|
||||
props: {
|
||||
final: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
emits: ['share'],
|
||||
components: {ShareIcon},
|
||||
};
|
||||
},
|
||||
emits: ['share'],
|
||||
components: { ShareIcon },
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import '~styles/helpers';
|
||||
@import '~styles/helpers';
|
||||
|
||||
.share-icon {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
.share-icon {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
|
||||
&__icon {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
margin-right: $small-spacing;
|
||||
}
|
||||
|
||||
&__text {
|
||||
@include large-link;
|
||||
}
|
||||
&__icon {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
margin-right: $small-spacing;
|
||||
}
|
||||
|
||||
&__text {
|
||||
@include large-link;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -2,31 +2,23 @@
|
|||
<div class="avatar">
|
||||
<transition name="fade">
|
||||
<default-avatar
|
||||
:class="{'avatar__placeholder--highlighted': iconHighlighted}"
|
||||
:class="{ 'avatar__placeholder--highlighted': iconHighlighted }"
|
||||
class="avatar__placeholder"
|
||||
v-show="!isAvatarLoaded"
|
||||
/>
|
||||
</transition>
|
||||
<transition name="show">
|
||||
<div
|
||||
:style="{'background-image': `url(${avatarUrl})`}"
|
||||
:style="{ 'background-image': `url(${avatarUrl})` }"
|
||||
class="avatar__image"
|
||||
v-show="isAvatarLoaded"
|
||||
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"
|
||||
>
|
||||
<router-link :to="{name: 'profile'}">
|
||||
<div class="avatar__edit" v-if="editable" @click="closeSidebar">
|
||||
<router-link :to="{ name: 'profile' }">
|
||||
<pen-icon />
|
||||
</router-link>
|
||||
</div>
|
||||
|
|
@ -40,104 +32,104 @@
|
|||
const DefaultAvatar = defineAsyncComponent(() => import(/* webpackChunkName: "icons" */'@/components/icons/DefaultAvatar'));
|
||||
const PenIcon = defineAsyncComponent(() => import(/* webpackChunkName: "icons" */'@/components/icons/PenIcon'));
|
||||
|
||||
export default {
|
||||
props: {
|
||||
avatarUrl: {
|
||||
type: String
|
||||
},
|
||||
iconHighlighted: {},
|
||||
editable: {
|
||||
default: false
|
||||
}
|
||||
export default {
|
||||
props: {
|
||||
avatarUrl: {
|
||||
type: String,
|
||||
},
|
||||
components: {
|
||||
DefaultAvatar,
|
||||
PenIcon
|
||||
iconHighlighted: {},
|
||||
editable: {
|
||||
default: false,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isAvatarLoaded: false
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
if (this.avatarUrl !== '') {
|
||||
this.$refs.fakeImage.addEventListener('load', () => {
|
||||
if (this.$refs.fakeImage) {
|
||||
this.$refs.fakeImage.remove();
|
||||
this.isAvatarLoaded = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
closeSidebar() {
|
||||
this.$apollo.mutate({
|
||||
mutation: TOGGLE_SIDEBAR,
|
||||
variables: {
|
||||
sidebar: {
|
||||
profile: false
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
components: {
|
||||
DefaultAvatar,
|
||||
PenIcon,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isAvatarLoaded: false,
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
if (this.avatarUrl !== '') {
|
||||
this.$refs.fakeImage.addEventListener('load', () => {
|
||||
if (this.$refs.fakeImage) {
|
||||
this.$refs.fakeImage.remove();
|
||||
this.isAvatarLoaded = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
closeSidebar() {
|
||||
this.$apollo.mutate({
|
||||
mutation: TOGGLE_SIDEBAR,
|
||||
variables: {
|
||||
sidebar: {
|
||||
profile: false,
|
||||
},
|
||||
},
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import "~styles/helpers";
|
||||
@import '~styles/helpers';
|
||||
|
||||
$max-width: 100%;
|
||||
$max-width: 100%;
|
||||
|
||||
.avatar {
|
||||
.avatar {
|
||||
height: $max-width;
|
||||
width: $max-width;
|
||||
overflow: hidden;
|
||||
text-align: center;
|
||||
|
||||
&__placeholder {
|
||||
height: $max-width;
|
||||
width: $max-width;
|
||||
overflow: hidden;
|
||||
text-align: center;
|
||||
fill: $color-silver-dark;
|
||||
border-radius: 50%;
|
||||
|
||||
&__placeholder {
|
||||
&--highlighted {
|
||||
fill: $color-brand;
|
||||
}
|
||||
}
|
||||
|
||||
&__image {
|
||||
background-size: cover;
|
||||
background-position: center center;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
border: 0;
|
||||
border-radius: 50%;
|
||||
|
||||
&--landscape {
|
||||
width: auto;
|
||||
height: $max-width;
|
||||
fill: $color-silver-dark;
|
||||
border-radius: 50%;
|
||||
|
||||
&--highlighted {
|
||||
fill: $color-brand;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&__image {
|
||||
background-size: cover;
|
||||
background-position: center center;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
border: 0;
|
||||
border-radius: 50%;
|
||||
&__fake-image {
|
||||
width: 0;
|
||||
height: 0;
|
||||
}
|
||||
|
||||
&--landscape {
|
||||
width: auto;
|
||||
height: $max-width;
|
||||
}
|
||||
}
|
||||
|
||||
&__fake-image {
|
||||
width: 0;
|
||||
height: 0;
|
||||
}
|
||||
|
||||
&__edit {
|
||||
position: absolute;
|
||||
box-sizing: border-box;
|
||||
width: 34px;
|
||||
height: 34px;
|
||||
display: block;
|
||||
left: 50%;
|
||||
bottom: -3px;
|
||||
transform: translateX(80%);
|
||||
background-color: $color-white;
|
||||
border-radius: 50%;
|
||||
padding: 6px;
|
||||
box-shadow: 0 3px 10px rgba(0, 0, 0, 0.12);
|
||||
}
|
||||
&__edit {
|
||||
position: absolute;
|
||||
box-sizing: border-box;
|
||||
width: 34px;
|
||||
height: 34px;
|
||||
display: block;
|
||||
left: 50%;
|
||||
bottom: -3px;
|
||||
transform: translateX(80%);
|
||||
background-color: $color-white;
|
||||
border-radius: 50%;
|
||||
padding: 6px;
|
||||
box-shadow: 0 3px 10px rgba(0, 0, 0, 0.12);
|
||||
}
|
||||
|
||||
.fade-leave-active, .show-enter-active {
|
||||
transition: opacity .5s;
|
||||
|
|
@ -146,8 +138,8 @@
|
|||
opacity: 0;
|
||||
}
|
||||
|
||||
.show-enter-to {
|
||||
opacity: 1;
|
||||
}
|
||||
.show-enter-to {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -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 }}
|
||||
|
|
@ -21,32 +15,32 @@
|
|||
import {defineAsyncComponent} from 'vue';
|
||||
const LinkBlock = defineAsyncComponent(() => import(/* webpackChunkName: "content-components" */'@/components/content-blocks/LinkBlock'));
|
||||
|
||||
export default {
|
||||
props: ['bookmark'],
|
||||
components: {LinkBlock},
|
||||
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);
|
||||
},
|
||||
text() {
|
||||
return this.content.value.text ? this.content.value.text : 'TO BE DEFINED';
|
||||
},
|
||||
type() {
|
||||
switch (this.content.type) {
|
||||
case 'assignment':
|
||||
return 'Aufgabe & Ergebnis';
|
||||
case 'link_block':
|
||||
return this.content;
|
||||
case 'survey':
|
||||
return 'Übung';
|
||||
case 'image_url_block':
|
||||
return 'Bild';
|
||||
default:
|
||||
return this.content.type;
|
||||
}
|
||||
export default {
|
||||
props: ['bookmark'],
|
||||
components: { LinkBlock },
|
||||
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);
|
||||
},
|
||||
text() {
|
||||
return this.content.value.text ? this.content.value.text : 'TO BE DEFINED';
|
||||
},
|
||||
type() {
|
||||
switch (this.content.type) {
|
||||
case 'assignment':
|
||||
return 'Aufgabe & Ergebnis';
|
||||
case 'link_block':
|
||||
return this.content;
|
||||
case 'survey':
|
||||
return 'Übung';
|
||||
case 'image_url_block':
|
||||
return 'Bild';
|
||||
default:
|
||||
return this.content.type;
|
||||
}
|
||||
}
|
||||
};
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
@ -12,21 +8,21 @@
|
|||
import {defineAsyncComponent} from 'vue';
|
||||
const PenIcon = defineAsyncComponent(() => import(/* webpackChunkName: "icons" */'@/components/icons/PenIcon'));
|
||||
|
||||
export default {
|
||||
components: {
|
||||
PenIcon
|
||||
}
|
||||
};
|
||||
export default {
|
||||
components: {
|
||||
PenIcon,
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import "~styles/_variables.scss";
|
||||
@import '~styles/_variables.scss';
|
||||
|
||||
.edit-group-name {
|
||||
&__icon {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
fill: $color-brand;
|
||||
}
|
||||
.edit-group-name {
|
||||
&__icon {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
fill: $color-brand;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -181,17 +181,13 @@ export default {
|
|||
}
|
||||
|
||||
&__role {
|
||||
@include desktop {
|
||||
flex: 0 1 110px;
|
||||
text-align: right;
|
||||
}
|
||||
}
|
||||
@include desktop {flex: 0 1 110px;
|
||||
text-align: right;
|
||||
}}
|
||||
|
||||
&__action {
|
||||
@include desktop {
|
||||
flex: 0 1 110px;
|
||||
padding-left: $large-spacing;
|
||||
}
|
||||
@include desktop {flex: 0 1 110px;
|
||||
padding-left: $large-spacing;
|
||||
}
|
||||
}
|
||||
}}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -1,105 +1,102 @@
|
|||
<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>
|
||||
|
||||
<script>
|
||||
import UPDATE_AVATAR_QUERY from '@/graphql/gql/mutations/updateAvatarUrl.gql';
|
||||
import ME_QUERY from '@/graphql/gql/queries/meQuery.gql';
|
||||
import AvatarUploadForm from '@/components/profile/AvatarUploadForm';
|
||||
import Avatar from '@/components/profile/Avatar';
|
||||
import {defineAsyncComponent} from 'vue';
|
||||
const TrashIcon = defineAsyncComponent(() => import(/* webpackChunkName: "icons" */'@/components/icons/TrashIcon'));
|
||||
import UPDATE_AVATAR_QUERY from '@/graphql/gql/mutations/updateAvatarUrl.gql';
|
||||
import ME_QUERY from '@/graphql/gql/queries/meQuery.gql';
|
||||
import AvatarUploadForm from '@/components/profile/AvatarUploadForm';
|
||||
import Avatar from '@/components/profile/Avatar';
|
||||
import { defineAsyncComponent } from 'vue';
|
||||
const TrashIcon = defineAsyncComponent(() => import(/* webpackChunkName: "icons" */ '@/components/icons/TrashIcon'));
|
||||
|
||||
export default {
|
||||
components: {
|
||||
AvatarUploadForm,
|
||||
Avatar,
|
||||
TrashIcon
|
||||
},
|
||||
export default {
|
||||
components: {
|
||||
AvatarUploadForm,
|
||||
Avatar,
|
||||
TrashIcon,
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
me: {
|
||||
avatarUrl: ''
|
||||
}
|
||||
};
|
||||
},
|
||||
apollo: {
|
||||
data() {
|
||||
return {
|
||||
me: {
|
||||
query: ME_QUERY,
|
||||
avatarUrl: '',
|
||||
},
|
||||
};
|
||||
},
|
||||
apollo: {
|
||||
me: {
|
||||
query: ME_QUERY,
|
||||
},
|
||||
methods: {
|
||||
deleteAvatar () {
|
||||
this.updateAvatar('');
|
||||
},
|
||||
updateAvatar (url) {
|
||||
this.$apollo.mutate({
|
||||
},
|
||||
methods: {
|
||||
deleteAvatar() {
|
||||
this.updateAvatar('');
|
||||
},
|
||||
updateAvatar(url) {
|
||||
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});
|
||||
const { me } = store.readQuery({ query: ME_QUERY });
|
||||
if (me) {
|
||||
const data = {
|
||||
me: {
|
||||
...me,
|
||||
avatarUrl: url
|
||||
}
|
||||
avatarUrl: url,
|
||||
},
|
||||
};
|
||||
store.writeQuery({query: ME_QUERY, data});
|
||||
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;
|
||||
flex-direction: row;
|
||||
.profile-avatar {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
|
||||
&__image {
|
||||
height: 230px;
|
||||
width: 230px;
|
||||
}
|
||||
}
|
||||
|
||||
.profile-avatar {
|
||||
margin-bottom: $large-spacing;
|
||||
&__image {
|
||||
height: 230px;
|
||||
width: 230px;
|
||||
}
|
||||
}
|
||||
|
||||
.profile-avatar {
|
||||
margin-bottom: $large-spacing;
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
@ -76,112 +38,113 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import ProfileWidget from '@/components/profile/ProfileWidget';
|
||||
import ProfileWidget from '@/components/profile/ProfileWidget';
|
||||
|
||||
import ClassSelectionWidget from '@/components/school-class/ClassSelectionWidget';
|
||||
import ClassSelectionWidget from '@/components/school-class/ClassSelectionWidget';
|
||||
|
||||
import sidebar from '@/mixins/sidebar';
|
||||
import me from '@/mixins/me';
|
||||
import LogoutWidget from '@/components/LogoutWidget';
|
||||
import {MY_TEAM} from '@/router/me.names';
|
||||
import {defineAsyncComponent} from 'vue';
|
||||
const Cross = defineAsyncComponent(() => import(/* webpackChunkName: "icons" */'@/components/icons/CrossIcon'));
|
||||
import sidebar from '@/mixins/sidebar';
|
||||
import me from '@/mixins/me';
|
||||
import LogoutWidget from '@/components/LogoutWidget';
|
||||
import { MY_TEAM } from '@/router/me.names';
|
||||
import { defineAsyncComponent } from 'vue';
|
||||
const Cross = defineAsyncComponent(() => import(/* webpackChunkName: "icons" */ '@/components/icons/CrossIcon'));
|
||||
|
||||
export default {
|
||||
export default {
|
||||
mixins: [sidebar, me],
|
||||
|
||||
mixins: [sidebar, me],
|
||||
components: {
|
||||
LogoutWidget,
|
||||
ClassSelectionWidget,
|
||||
ProfileWidget,
|
||||
Cross,
|
||||
},
|
||||
|
||||
components: {
|
||||
LogoutWidget,
|
||||
ClassSelectionWidget,
|
||||
ProfileWidget,
|
||||
Cross,
|
||||
computed: {
|
||||
myTeamPage() {
|
||||
return {
|
||||
name: MY_TEAM,
|
||||
};
|
||||
},
|
||||
},
|
||||
|
||||
computed: {
|
||||
myTeamPage() {
|
||||
return {
|
||||
name: MY_TEAM,
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
close() {
|
||||
this.closeSidebar('profile');
|
||||
},
|
||||
|
||||
methods: {
|
||||
close() {
|
||||
this.closeSidebar('profile');
|
||||
},
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import "~styles/helpers";
|
||||
@import '~styles/helpers';
|
||||
|
||||
$desktop-width: 333px;
|
||||
$desktop-width: 333px;
|
||||
|
||||
.profile-sidebar {
|
||||
padding: $large-spacing 0;
|
||||
box-sizing: border-box;
|
||||
position: fixed;
|
||||
right: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
height: 100vh;
|
||||
background-color: $color-white;
|
||||
z-index: 15;
|
||||
box-shadow: 0 3px 9px 0 rgba(0, 0, 0, 0.12);
|
||||
overflow-y: scroll;
|
||||
.profile-sidebar {
|
||||
padding: $large-spacing 0;
|
||||
box-sizing: border-box;
|
||||
position: fixed;
|
||||
right: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
height: 100vh;
|
||||
background-color: $color-white;
|
||||
z-index: 15;
|
||||
box-shadow: 0 3px 9px 0 rgba(0, 0, 0, 0.12);
|
||||
overflow-y: scroll;
|
||||
|
||||
width: 100%;
|
||||
width: 100%;
|
||||
@include desktop {
|
||||
width: $desktop-width;
|
||||
}
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: flex-start;
|
||||
|
||||
&__section {
|
||||
margin-bottom: $large-spacing;
|
||||
|
||||
&:last-of-type {
|
||||
margin-top: auto;
|
||||
}
|
||||
}
|
||||
|
||||
&__item {
|
||||
padding: $small-spacing $medium-spacing;
|
||||
}
|
||||
|
||||
&__subtitle {
|
||||
@include small-text;
|
||||
margin: 0;
|
||||
margin-bottom: $small-spacing;
|
||||
}
|
||||
|
||||
&__link {
|
||||
@include default-link;
|
||||
display: block;
|
||||
}
|
||||
|
||||
&__close-link {
|
||||
position: absolute;
|
||||
right: $small-spacing;
|
||||
top: $small-spacing;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
.slide {
|
||||
&-enter-active,
|
||||
&-leave-active {
|
||||
transition: right 0.2s;
|
||||
}
|
||||
|
||||
&-enter-from,
|
||||
&-leave-to {
|
||||
right: -100vw;
|
||||
@include desktop {
|
||||
width: $desktop-width;
|
||||
}
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: flex-start;
|
||||
|
||||
&__section {
|
||||
margin-bottom: $large-spacing;
|
||||
|
||||
&:last-of-type {
|
||||
margin-top: auto;
|
||||
}
|
||||
}
|
||||
|
||||
&__item {
|
||||
padding: $small-spacing $medium-spacing;
|
||||
}
|
||||
|
||||
&__subtitle {
|
||||
@include small-text;
|
||||
margin: 0;
|
||||
margin-bottom: $small-spacing;
|
||||
}
|
||||
|
||||
&__link {
|
||||
@include default-link;
|
||||
display: block;
|
||||
}
|
||||
|
||||
&__close-link {
|
||||
position: absolute;
|
||||
right: $small-spacing;
|
||||
top: $small-spacing;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
.slide {
|
||||
&-enter-active, &-leave-active {
|
||||
transition: right 0.2s;
|
||||
}
|
||||
|
||||
&-enter-from, &-leave-to {
|
||||
right: -100vw;
|
||||
@include desktop {
|
||||
right: -$desktop-width;
|
||||
}
|
||||
right: -$desktop-width;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -32,19 +32,16 @@ export default {
|
|||
.show-code {
|
||||
&__title {
|
||||
@include regular-text;
|
||||
|
||||
margin-bottom: $large-spacing;
|
||||
@include desktop {
|
||||
margin-bottom: 2 * $large-spacing;
|
||||
}
|
||||
}
|
||||
margin-bottom: $large-spacing;
|
||||
@include desktop { margin-bottom: 2 * $large-spacing;
|
||||
}}
|
||||
|
||||
&__code {
|
||||
font-size: toRem(60px);
|
||||
letter-spacing: toRem(10px);
|
||||
@include desktop {
|
||||
font-size: toRem(120px);
|
||||
letter-spacing: toRem(20px);
|
||||
letter-spacing: toRem(20px);
|
||||
}
|
||||
font-weight: 600;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
@ -14,52 +10,52 @@
|
|||
const PlusIcon = defineAsyncComponent(() => import(/* webpackChunkName: "icons" */'@/components/icons/PlusIcon'));
|
||||
import { ADD_ROOM_ENTRY_PAGE } from '@/router/room.names';
|
||||
|
||||
export default {
|
||||
props: ['parent'],
|
||||
export default {
|
||||
props: ['parent'],
|
||||
|
||||
components: {
|
||||
PlusIcon,
|
||||
},
|
||||
components: {
|
||||
PlusIcon,
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
addRoomEntryRoute: {
|
||||
name: ADD_ROOM_ENTRY_PAGE,
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
data() {
|
||||
return {
|
||||
addRoomEntryRoute: {
|
||||
name: ADD_ROOM_ENTRY_PAGE,
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import "~styles/helpers";
|
||||
@import '~styles/helpers';
|
||||
|
||||
.add-room-entry-button {
|
||||
border: 2px solid $color-white;
|
||||
border-radius: 12px;
|
||||
height: 150px;
|
||||
box-sizing: border-box;
|
||||
margin-bottom: 25px;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
break-inside: avoid-column;
|
||||
overflow: hidden;
|
||||
cursor: pointer;
|
||||
.add-room-entry-button {
|
||||
border: 2px solid $color-white;
|
||||
border-radius: 12px;
|
||||
height: 150px;
|
||||
box-sizing: border-box;
|
||||
margin-bottom: 25px;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
break-inside: avoid-column;
|
||||
overflow: hidden;
|
||||
cursor: pointer;
|
||||
|
||||
display: none;
|
||||
@include desktop {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
&__icon {
|
||||
width: 20px;
|
||||
fill: $color-white;
|
||||
margin-right: $small-spacing;
|
||||
}
|
||||
|
||||
&__text {
|
||||
@include regular-text;
|
||||
color: $color-white;
|
||||
}
|
||||
display: none;
|
||||
@include desktop {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
&__icon {
|
||||
width: 20px;
|
||||
fill: $color-white;
|
||||
margin-right: $small-spacing;
|
||||
}
|
||||
|
||||
&__text {
|
||||
@include regular-text;
|
||||
color: $color-white;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -1,56 +1,57 @@
|
|||
<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>
|
||||
|
||||
<script>
|
||||
import {defineAsyncComponent} from 'vue';
|
||||
import SpeechBubbleIcon from '@/components/icons/SpeechBubbleIcon';
|
||||
const Cards = defineAsyncComponent(() => import(/* webpackChunkName: "icons" */'@/components/icons/Cards.vue'));
|
||||
import { defineAsyncComponent } from 'vue';
|
||||
import SpeechBubbleIcon from '@/components/icons/SpeechBubbleIcon';
|
||||
const Cards = defineAsyncComponent(() => import(/* webpackChunkName: "icons" */ '@/components/icons/Cards.vue'));
|
||||
|
||||
export default {
|
||||
props: {
|
||||
entryCount: {
|
||||
type: Number,
|
||||
},
|
||||
verbose: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
icon: {
|
||||
type: String,
|
||||
default: 'cards'
|
||||
}
|
||||
export default {
|
||||
props: {
|
||||
entryCount: {
|
||||
type: Number,
|
||||
},
|
||||
verbose: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
icon: {
|
||||
type: String,
|
||||
default: 'cards',
|
||||
},
|
||||
},
|
||||
|
||||
components: {
|
||||
'speech-bubble': SpeechBubbleIcon,
|
||||
SpeechBubbleIcon,
|
||||
Cards,
|
||||
},
|
||||
};
|
||||
components: {
|
||||
'speech-bubble': SpeechBubbleIcon,
|
||||
SpeechBubbleIcon,
|
||||
Cards,
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import "~styles/helpers";
|
||||
@import '~styles/helpers';
|
||||
|
||||
.entry-count-widget {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
opacity: 0.6;
|
||||
margin-right: $medium-spacing;
|
||||
.entry-count-widget {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
opacity: 0.6;
|
||||
margin-right: $medium-spacing;
|
||||
|
||||
svg {
|
||||
width: 30px;
|
||||
fill: $color-charcoal-dark;
|
||||
margin-right: 15px;
|
||||
}
|
||||
|
||||
& > span {
|
||||
@include room-widget-text-style;
|
||||
}
|
||||
svg {
|
||||
width: 30px;
|
||||
fill: $color-charcoal-dark;
|
||||
margin-right: 15px;
|
||||
}
|
||||
|
||||
& > span {
|
||||
@include room-widget-text-style;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -1,71 +1,67 @@
|
|||
<template>
|
||||
<div class="more-actions">
|
||||
<a
|
||||
:class="{'more-actions__toggle--background': background}"
|
||||
:class="{ 'more-actions__toggle--background': background }"
|
||||
class="more-actions__toggle"
|
||||
data-cy="toggle-more-actions-menu"
|
||||
@click.stop="toggleMenu"
|
||||
>
|
||||
<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>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import WidgetPopover from '@/components/ui/WidgetPopover';
|
||||
import {defineAsyncComponent} from 'vue';
|
||||
const Ellipses = defineAsyncComponent(() => import(/* webpackChunkName: "icons" */'@/components/icons/Ellipses'));
|
||||
import WidgetPopover from '@/components/ui/WidgetPopover';
|
||||
import { defineAsyncComponent } from 'vue';
|
||||
const Ellipses = defineAsyncComponent(() => import(/* webpackChunkName: "icons" */ '@/components/icons/Ellipses'));
|
||||
|
||||
export default {
|
||||
props: {
|
||||
background: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
export default {
|
||||
props: {
|
||||
background: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
|
||||
components: {
|
||||
Ellipses,
|
||||
WidgetPopover,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
showMenu: false,
|
||||
};
|
||||
},
|
||||
components: {
|
||||
Ellipses,
|
||||
WidgetPopover,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
showMenu: false,
|
||||
};
|
||||
},
|
||||
|
||||
methods: {
|
||||
toggleMenu: function () {
|
||||
this.showMenu = !this.showMenu;
|
||||
},
|
||||
methods: {
|
||||
toggleMenu: function () {
|
||||
this.showMenu = !this.showMenu;
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import '~styles/helpers';
|
||||
@import '~styles/helpers';
|
||||
|
||||
.more-actions {
|
||||
svg {
|
||||
width: 30px;
|
||||
fill: $color-charcoal-dark;
|
||||
//margin-right: 15px;
|
||||
}
|
||||
.more-actions {
|
||||
svg {
|
||||
width: 30px;
|
||||
fill: $color-charcoal-dark;
|
||||
//margin-right: 15px;
|
||||
}
|
||||
|
||||
&__toggle {
|
||||
display: flex;
|
||||
border-radius: 5px;
|
||||
&__toggle {
|
||||
display: flex;
|
||||
border-radius: 5px;
|
||||
|
||||
&--background {
|
||||
background: white;
|
||||
}
|
||||
&--background {
|
||||
background: white;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -1,107 +1,82 @@
|
|||
<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>
|
||||
|
||||
<script>
|
||||
import ColorChooser from '@/components/ColorChooser';
|
||||
import PageForm from '@/components/page-form/PageForm';
|
||||
import PageFormInput from '@/components/page-form/PageFormInput';
|
||||
import ColorChooser from '@/components/ColorChooser';
|
||||
import PageForm from '@/components/page-form/PageForm';
|
||||
import PageFormInput from '@/components/page-form/PageFormInput';
|
||||
|
||||
import ME_QUERY from '@/graphql/gql/queries/meQuery.gql';
|
||||
import ME_QUERY from '@/graphql/gql/queries/meQuery.gql';
|
||||
|
||||
export default {
|
||||
props: ['room'],
|
||||
export default {
|
||||
props: ['room'],
|
||||
|
||||
components: {
|
||||
ColorChooser,
|
||||
PageForm,
|
||||
PageFormInput
|
||||
components: {
|
||||
ColorChooser,
|
||||
PageForm,
|
||||
PageFormInput,
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
localRoom: Object.assign({}, this.room),
|
||||
me: {},
|
||||
};
|
||||
},
|
||||
|
||||
created() {
|
||||
this.$store.dispatch('setSpecialContainerClass', this.localRoom.appearance);
|
||||
},
|
||||
|
||||
beforeUnmount() {
|
||||
this.$store.dispatch('setSpecialContainerClass', '');
|
||||
},
|
||||
|
||||
methods: {
|
||||
updateColor(newColor) {
|
||||
this.localRoom.appearance = newColor;
|
||||
this.$store.dispatch('setSpecialContainerClass', newColor);
|
||||
},
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
localRoom: Object.assign({}, this.room),
|
||||
me: {}
|
||||
};
|
||||
apollo: {
|
||||
me: {
|
||||
query: ME_QUERY,
|
||||
},
|
||||
|
||||
created() {
|
||||
this.$store.dispatch('setSpecialContainerClass', this.localRoom.appearance);
|
||||
},
|
||||
|
||||
beforeUnmount() {
|
||||
this.$store.dispatch('setSpecialContainerClass', '');
|
||||
},
|
||||
|
||||
methods: {
|
||||
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 {
|
||||
@include page-form-input-heading;
|
||||
}
|
||||
|
||||
&__input,
|
||||
&__textarea {
|
||||
width: 100%;
|
||||
margin-bottom: 35px;
|
||||
}
|
||||
|
||||
&__save-button {
|
||||
margin-right: 15px;
|
||||
}
|
||||
.room-form {
|
||||
&__property-heading {
|
||||
@include page-form-input-heading;
|
||||
}
|
||||
|
||||
&__input,
|
||||
&__textarea {
|
||||
width: 100%;
|
||||
margin-bottom: 35px;
|
||||
}
|
||||
|
||||
&__save-button {
|
||||
margin-right: 15px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -8,34 +8,34 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import {defineAsyncComponent} from 'vue';
|
||||
const Group = defineAsyncComponent(() => import(/* webpackChunkName: "icons" */'@/components/icons/Group.vue'));
|
||||
import { defineAsyncComponent } from 'vue';
|
||||
const Group = defineAsyncComponent(() => import(/* webpackChunkName: "icons" */ '@/components/icons/Group.vue'));
|
||||
|
||||
export default {
|
||||
props: ['name'],
|
||||
export default {
|
||||
props: ['name'],
|
||||
|
||||
components: {
|
||||
Group
|
||||
}
|
||||
};
|
||||
components: {
|
||||
Group,
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import "~styles/helpers";
|
||||
@import '~styles/helpers';
|
||||
|
||||
.room-group-widget {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
opacity: 0.6;
|
||||
.room-group-widget {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
opacity: 0.6;
|
||||
|
||||
svg {
|
||||
width: 30px;
|
||||
fill: $color-charcoal-dark;
|
||||
margin-right: 15px;
|
||||
}
|
||||
|
||||
& > span {
|
||||
@include room-widget-text-style;;
|
||||
}
|
||||
svg {
|
||||
width: 30px;
|
||||
fill: $color-charcoal-dark;
|
||||
margin-right: 15px;
|
||||
}
|
||||
|
||||
& > span {
|
||||
@include room-widget-text-style;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -13,42 +13,43 @@
|
|||
|
||||
<script>
|
||||
|
||||
import {defineAsyncComponent} from 'vue';
|
||||
const EyeIcon = defineAsyncComponent(() => import(/* webpackChunkName: "icons" */'@/components/icons/EyeIcon'));
|
||||
const ClosedEyeIcon = defineAsyncComponent(() => import(/* webpackChunkName: "icons" */'@/components/icons/ClosedEyeIcon'));
|
||||
import { defineAsyncComponent } from 'vue';
|
||||
const EyeIcon = defineAsyncComponent(() => import(/* webpackChunkName: "icons" */ '@/components/icons/EyeIcon'));
|
||||
const ClosedEyeIcon = defineAsyncComponent(() =>
|
||||
import(/* webpackChunkName: "icons" */ '@/components/icons/ClosedEyeIcon')
|
||||
);
|
||||
|
||||
export default {
|
||||
props: {
|
||||
restricted: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
export default {
|
||||
props: {
|
||||
restricted: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
|
||||
components: {
|
||||
ClosedEyeIcon,
|
||||
EyeIcon
|
||||
}
|
||||
};
|
||||
components: {
|
||||
ClosedEyeIcon,
|
||||
EyeIcon,
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import "~styles/helpers";
|
||||
@import '~styles/helpers';
|
||||
|
||||
.room-visibility-widget {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
opacity: 0.6;
|
||||
.room-visibility-widget {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
opacity: 0.6;
|
||||
|
||||
&__icon {
|
||||
width: 30px;
|
||||
fill: $color-charcoal-dark;
|
||||
margin-right: 15px;
|
||||
}
|
||||
|
||||
& > span {
|
||||
@include room-widget-text-style;
|
||||
}
|
||||
&__icon {
|
||||
width: 30px;
|
||||
fill: $color-charcoal-dark;
|
||||
margin-right: 15px;
|
||||
}
|
||||
|
||||
& > span {
|
||||
@include room-widget-text-style;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
@ -27,43 +14,45 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import {NEW_ROOM_PAGE} from '@/router/room.names';
|
||||
import {defineAsyncComponent} from 'vue';
|
||||
const RoomsIllustration = defineAsyncComponent(() => import(/* webpackChunkName: "illustrations" */'@/components/illustrations/RoomsIllustration'));
|
||||
import { NEW_ROOM_PAGE } from '@/router/room.names';
|
||||
import { defineAsyncComponent } from 'vue';
|
||||
const RoomsIllustration = defineAsyncComponent(() =>
|
||||
import(/* webpackChunkName: "illustrations" */ '@/components/illustrations/RoomsIllustration')
|
||||
);
|
||||
|
||||
export default {
|
||||
props: {
|
||||
isTeacher: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
export default {
|
||||
props: {
|
||||
isTeacher: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
components: {RoomsIllustration},
|
||||
},
|
||||
components: { RoomsIllustration },
|
||||
|
||||
data() {
|
||||
return {
|
||||
newRoomRoute: NEW_ROOM_PAGE,
|
||||
};
|
||||
},
|
||||
};
|
||||
data() {
|
||||
return {
|
||||
newRoomRoute: NEW_ROOM_PAGE,
|
||||
};
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import '~styles/helpers';
|
||||
@import '~styles/helpers';
|
||||
|
||||
.rooms-onboarding {
|
||||
@include onboarding-page;
|
||||
.rooms-onboarding {
|
||||
@include onboarding-page;
|
||||
|
||||
&__heading {
|
||||
margin-bottom: $large-spacing;
|
||||
}
|
||||
|
||||
&__illustration {
|
||||
@include onboarding-illustration;
|
||||
}
|
||||
|
||||
&__text {
|
||||
@include onboarding-text;
|
||||
}
|
||||
&__heading {
|
||||
margin-bottom: $large-spacing;
|
||||
}
|
||||
|
||||
&__illustration {
|
||||
@include onboarding-illustration;
|
||||
}
|
||||
|
||||
&__text {
|
||||
@include onboarding-text;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
@ -59,8 +54,8 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import WidgetPopover from '@/components/ui/WidgetPopover';
|
||||
import CurrentClass from '@/components/school-class/CurrentClass';
|
||||
import WidgetPopover from '@/components/ui/WidgetPopover';
|
||||
import CurrentClass from '@/components/school-class/CurrentClass';
|
||||
|
||||
import updateSelectedClassMixin from '@/mixins/update-selected-class';
|
||||
import sidebarMixin from '@/mixins/sidebar';
|
||||
|
|
@ -69,37 +64,36 @@
|
|||
const ChevronDown = defineAsyncComponent(() => import(/* webpackChunkName: "icons" */'@/components/icons/ChevronDown'));
|
||||
const AddIcon = defineAsyncComponent(() => import(/* webpackChunkName: "icons" */'@/components/icons/AddIcon'));
|
||||
|
||||
export default {
|
||||
|
||||
props: {
|
||||
mobile: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
export default {
|
||||
props: {
|
||||
mobile: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
|
||||
mixins: [updateSelectedClassMixin, sidebarMixin, meMixin],
|
||||
components: {
|
||||
WidgetPopover,
|
||||
ChevronDown,
|
||||
CurrentClass,
|
||||
AddIcon
|
||||
},
|
||||
mixins: [updateSelectedClassMixin, sidebarMixin, meMixin],
|
||||
components: {
|
||||
WidgetPopover,
|
||||
ChevronDown,
|
||||
CurrentClass,
|
||||
AddIcon,
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
showPopover: false
|
||||
};
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
showPopover: false,
|
||||
};
|
||||
},
|
||||
|
||||
computed: {
|
||||
currentClassSelection() {
|
||||
let currentClass = this.me.schoolClasses.find(schoolClass => {
|
||||
return schoolClass.id === this.me.selectedClass.id;
|
||||
});
|
||||
return currentClass || this.me.schoolClasses[0];
|
||||
}
|
||||
computed: {
|
||||
currentClassSelection() {
|
||||
let currentClass = this.me.schoolClasses.find((schoolClass) => {
|
||||
return schoolClass.id === this.me.selectedClass.id;
|
||||
});
|
||||
return currentClass || this.me.schoolClasses[0];
|
||||
},
|
||||
},
|
||||
|
||||
methods: {
|
||||
toggle() {
|
||||
|
|
@ -111,47 +105,46 @@
|
|||
this.closeSidebar('profile');
|
||||
}
|
||||
},
|
||||
|
||||
};
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import "~styles/helpers";
|
||||
@import '~styles/helpers';
|
||||
|
||||
.class-selection {
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
margin-bottom: $medium-spacing;
|
||||
border-radius: 4px;
|
||||
.class-selection {
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
margin-bottom: $medium-spacing;
|
||||
border-radius: 4px;
|
||||
|
||||
&__popover {
|
||||
white-space: nowrap;
|
||||
top: 100%;
|
||||
left: 0;
|
||||
transform: translateY($small-spacing);
|
||||
}
|
||||
&__popover {
|
||||
white-space: nowrap;
|
||||
top: 100%;
|
||||
left: 0;
|
||||
transform: translateY($small-spacing);
|
||||
}
|
||||
}
|
||||
|
||||
.selected-class {
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
padding: $small-spacing 0;
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
|
||||
&__text {
|
||||
line-height: $large-spacing;
|
||||
@include heading-4;
|
||||
margin-right: $small-spacing;
|
||||
}
|
||||
|
||||
.selected-class {
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
padding: $small-spacing 0;
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
|
||||
&__text {
|
||||
line-height: $large-spacing;
|
||||
@include heading-4;
|
||||
margin-right: $small-spacing;
|
||||
}
|
||||
|
||||
&__dropdown-icon {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
fill: $color-charcoal-dark;
|
||||
}
|
||||
&__dropdown-icon {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
fill: $color-charcoal-dark;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -1,27 +1,24 @@
|
|||
<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>
|
||||
import me from '@/mixins/me';
|
||||
import me from '@/mixins/me';
|
||||
|
||||
export default {
|
||||
mixins: [me],
|
||||
};
|
||||
export default {
|
||||
mixins: [me],
|
||||
};
|
||||
</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;
|
||||
flex-direction: column;
|
||||
align-self: center;
|
||||
line-height: 1;
|
||||
@include regular-text;
|
||||
}
|
||||
.current-class {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-self: center;
|
||||
line-height: 1;
|
||||
@include regular-text;
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
||||
|
|
@ -34,19 +27,19 @@
|
|||
const Tick = defineAsyncComponent(() => import(/* webpackChunkName: "icons" */'@/components/icons/Tick'));
|
||||
const CircleIcon = defineAsyncComponent(() => import(/* webpackChunkName: "icons" */'@/components/icons/CircleIcon'));
|
||||
|
||||
export default {
|
||||
props: {
|
||||
label: String,
|
||||
checked: {
|
||||
type: Boolean
|
||||
},
|
||||
item: Object,
|
||||
type: String
|
||||
export default {
|
||||
props: {
|
||||
label: String,
|
||||
checked: {
|
||||
type: Boolean,
|
||||
},
|
||||
item: Object,
|
||||
type: String,
|
||||
},
|
||||
|
||||
components: {
|
||||
Tick,
|
||||
CircleIcon
|
||||
}
|
||||
};
|
||||
components: {
|
||||
Tick,
|
||||
CircleIcon,
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -1,65 +1,57 @@
|
|||
<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>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {defineAsyncComponent} from 'vue';
|
||||
const EyeIcon = defineAsyncComponent(() => import(/* webpackChunkName: "icons" */'@/components/icons/EyeIcon'));
|
||||
const TrashIcon = defineAsyncComponent(() => import(/* webpackChunkName: "icons" */'@/components/icons/TrashIcon'));
|
||||
const PenIcon = defineAsyncComponent(() => import(/* webpackChunkName: "icons" */'@/components/icons/PenIcon'));
|
||||
import { defineAsyncComponent } from 'vue';
|
||||
const EyeIcon = defineAsyncComponent(() => import(/* webpackChunkName: "icons" */ '@/components/icons/EyeIcon'));
|
||||
const TrashIcon = defineAsyncComponent(() => import(/* webpackChunkName: "icons" */ '@/components/icons/TrashIcon'));
|
||||
const PenIcon = defineAsyncComponent(() => import(/* webpackChunkName: "icons" */ '@/components/icons/PenIcon'));
|
||||
|
||||
export default {
|
||||
props: {
|
||||
icon: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
text: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
export default {
|
||||
props: {
|
||||
icon: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
components: {
|
||||
EyeIcon,
|
||||
TrashIcon,
|
||||
PenIcon,
|
||||
text: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
};
|
||||
},
|
||||
components: {
|
||||
EyeIcon,
|
||||
TrashIcon,
|
||||
PenIcon,
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import '~styles/helpers';
|
||||
@import '~styles/helpers';
|
||||
|
||||
.popover-link {
|
||||
@include popover-link;
|
||||
.popover-link {
|
||||
@include popover-link;
|
||||
|
||||
&__icon {
|
||||
width: 30px;
|
||||
fill: $color-charcoal-dark;
|
||||
margin-right: 15px;
|
||||
display: flex;
|
||||
flex-basis: auto;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
&__text {
|
||||
width: auto;
|
||||
display: flex;
|
||||
flex-basis: auto;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
&__icon {
|
||||
width: 30px;
|
||||
fill: $color-charcoal-dark;
|
||||
margin-right: 15px;
|
||||
display: flex;
|
||||
flex-basis: auto;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
&__text {
|
||||
width: auto;
|
||||
display: flex;
|
||||
flex-basis: auto;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -18,26 +14,27 @@
|
|||
</template>
|
||||
|
||||
<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'));
|
||||
import { defineAsyncComponent } from 'vue';
|
||||
const SimpleFileUpload = defineAsyncComponent(() => import('@/components/ui/file-upload/SimpleFileUpload'));
|
||||
const DocumentBlock = defineAsyncComponent(() =>
|
||||
import(/* webpackChunkName: "content-components" */ '@/components/content-blocks/DocumentBlock')
|
||||
);
|
||||
|
||||
export default {
|
||||
props: {
|
||||
document: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
withText: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
export default {
|
||||
props: {
|
||||
document: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
components: {SimpleFileUpload, DocumentBlock},
|
||||
};
|
||||
withText: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
components: { SimpleFileUpload, DocumentBlock },
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import '~styles/helpers';
|
||||
|
||||
@import '~styles/helpers';
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -5,21 +5,23 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import {defineAsyncComponent} from 'vue';
|
||||
const DocumentIcon = defineAsyncComponent(() => import(/* webpackChunkName: "icons" */'@/components/icons/DocumentIcon'));
|
||||
import { defineAsyncComponent } from 'vue';
|
||||
const DocumentIcon = defineAsyncComponent(() =>
|
||||
import(/* webpackChunkName: "icons" */ '@/components/icons/DocumentIcon')
|
||||
);
|
||||
|
||||
export default {
|
||||
components: {DocumentIcon},
|
||||
};
|
||||
export default {
|
||||
components: { DocumentIcon },
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import '~styles/helpers';
|
||||
@import '~styles/helpers';
|
||||
|
||||
.simple-file-upload-icon {
|
||||
&__icon {
|
||||
width: 25px;
|
||||
fill: $color-silver-dark;
|
||||
}
|
||||
.simple-file-upload-icon {
|
||||
&__icon {
|
||||
width: 25px;
|
||||
fill: $color-silver-dark;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -30,5 +30,5 @@ export default {
|
|||
ArrowThinDown,
|
||||
ArrowThinTop,
|
||||
ArrowThinUp,
|
||||
TrashIcon
|
||||
TrashIcon,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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" />
|
||||
|
|
@ -13,8 +8,8 @@
|
|||
</template>
|
||||
|
||||
<script setup>
|
||||
defineProps({
|
||||
id: String,
|
||||
label: String
|
||||
}) ;
|
||||
defineProps({
|
||||
id: String,
|
||||
label: String,
|
||||
});
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -1,93 +1,87 @@
|
|||
<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>
|
||||
|
||||
<script>
|
||||
import me from '@/mixins/me';
|
||||
import me from '@/mixins/me';
|
||||
|
||||
import {TYPES, CONTENT_TYPE} from '@/consts/types';
|
||||
import {createVisibilityMutation, hidden} from '@/helpers/visibility';
|
||||
import { TYPES, CONTENT_TYPE } from '@/consts/types';
|
||||
import { createVisibilityMutation, hidden } from '@/helpers/visibility';
|
||||
|
||||
import {defineAsyncComponent} from 'vue';
|
||||
const EyeIcon = defineAsyncComponent(() => import(/* webpackChunkName: "icons" */'@/components/icons/EyeIcon'));
|
||||
const ClosedEyeIcon = defineAsyncComponent(() => import(/* webpackChunkName: "icons" */'@/components/icons/ClosedEyeIcon'));
|
||||
import { defineAsyncComponent } from 'vue';
|
||||
const EyeIcon = defineAsyncComponent(() => import(/* webpackChunkName: "icons" */ '@/components/icons/EyeIcon'));
|
||||
const ClosedEyeIcon = defineAsyncComponent(() =>
|
||||
import(/* webpackChunkName: "icons" */ '@/components/icons/ClosedEyeIcon')
|
||||
);
|
||||
|
||||
export default {
|
||||
props: {
|
||||
block: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
export default {
|
||||
props: {
|
||||
block: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
type: {
|
||||
type: String,
|
||||
default: CONTENT_TYPE,
|
||||
validator: (value) => {
|
||||
// value must be one of TYPES
|
||||
return TYPES.indexOf(value) !== -1;
|
||||
},
|
||||
type: {
|
||||
type: String,
|
||||
default: CONTENT_TYPE,
|
||||
validator: value => {
|
||||
// value must be one of TYPES
|
||||
return TYPES.indexOf(value) !== -1;
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
mixins: [me],
|
||||
mixins: [me],
|
||||
|
||||
components: {
|
||||
EyeIcon,
|
||||
ClosedEyeIcon
|
||||
components: {
|
||||
EyeIcon,
|
||||
ClosedEyeIcon,
|
||||
},
|
||||
|
||||
computed: {
|
||||
hidden() {
|
||||
return hidden({ type: this.type, block: this.block, schoolClass: this.schoolClass });
|
||||
},
|
||||
},
|
||||
|
||||
computed: {
|
||||
hidden() {
|
||||
return hidden({type: this.type, block: this.block, schoolClass: this.schoolClass});
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
toggleVisibility() {
|
||||
const hidden = !this.hidden;
|
||||
const schoolClassId = this.schoolClass.id;
|
||||
|
||||
methods: {
|
||||
toggleVisibility() {
|
||||
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);
|
||||
const { mutation, variables } = createVisibilityMutation(this.type, this.block.id, visibility);
|
||||
|
||||
this.$apollo.mutate({
|
||||
mutation,
|
||||
variables
|
||||
});
|
||||
},
|
||||
this.$apollo.mutate({
|
||||
mutation,
|
||||
variables,
|
||||
});
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.visibility-action {
|
||||
margin-top: 9px;
|
||||
.visibility-action {
|
||||
margin-top: 9px;
|
||||
|
||||
position: absolute;
|
||||
left: -70px;
|
||||
top: 0px;
|
||||
display: grid;
|
||||
position: absolute;
|
||||
left: -70px;
|
||||
top: 0px;
|
||||
display: grid;
|
||||
|
||||
&__visibility-menu {
|
||||
top: 40px;
|
||||
}
|
||||
&__visibility-menu {
|
||||
top: 40px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
@ -62,99 +35,99 @@
|
|||
const HepLogo = defineAsyncComponent(() => import(/* webpackChunkName: "icons" */'@/components/icons/HepLogo'));
|
||||
const EhbLogo = defineAsyncComponent(() => import(/* webpackChunkName: "icons" */'@/components/icons/EhbLogo'));
|
||||
|
||||
export default {
|
||||
components: {
|
||||
HepLogo,
|
||||
EhbLogo
|
||||
}
|
||||
};
|
||||
export default {
|
||||
components: {
|
||||
HepLogo,
|
||||
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;
|
||||
max-width: 100vw;
|
||||
overflow: hidden;
|
||||
.default-footer {
|
||||
background-color: $color-silver-light;
|
||||
max-width: 100vw;
|
||||
overflow: hidden;
|
||||
|
||||
&__section {
|
||||
width: 100%;
|
||||
border-bottom: $color-silver 1px solid;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
&__section {
|
||||
width: 100%;
|
||||
border-bottom: $color-silver 1px solid;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
&__info {
|
||||
width: 100%;
|
||||
max-width: $footer-width;
|
||||
padding: 2*$large-spacing 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
&__info {
|
||||
width: 100%;
|
||||
max-width: $footer-width;
|
||||
padding: 2 * $large-spacing 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
@include desktop {
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
}
|
||||
}
|
||||
|
||||
&__who-are-we {
|
||||
width: 100%;
|
||||
margin-bottom: $large-spacing;
|
||||
|
||||
@include desktop {
|
||||
width: 330px;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
&__logo-hep {
|
||||
width: auto;
|
||||
height: 35px;
|
||||
margin-bottom: $large-spacing;
|
||||
|
||||
@include desktop {
|
||||
width: 147px;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
&__logo-ehb {
|
||||
width: 100px;
|
||||
height: 32px;
|
||||
}
|
||||
|
||||
&__links {
|
||||
width: 100%;
|
||||
max-width: $footer-width;
|
||||
padding: $large-spacing 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
@include desktop {
|
||||
flex-direction: row;
|
||||
}
|
||||
}
|
||||
|
||||
&__link {
|
||||
@include aside-with-cheese;
|
||||
margin-right: $large-spacing;
|
||||
margin-bottom: $small-spacing;
|
||||
|
||||
@include desktop {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
@include desktop {
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
}
|
||||
}
|
||||
|
||||
.who-are-we {
|
||||
&__title {
|
||||
@include heading-4;
|
||||
}
|
||||
&__who-are-we {
|
||||
width: 100%;
|
||||
margin-bottom: $large-spacing;
|
||||
|
||||
&__text {
|
||||
@include aside-text;
|
||||
@include desktop {
|
||||
width: 330px;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
&__logo-hep {
|
||||
width: auto;
|
||||
height: 35px;
|
||||
margin-bottom: $large-spacing;
|
||||
|
||||
@include desktop {
|
||||
width: 147px;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
&__logo-ehb {
|
||||
width: 100px;
|
||||
height: 32px;
|
||||
}
|
||||
|
||||
&__links {
|
||||
width: 100%;
|
||||
max-width: $footer-width;
|
||||
padding: $large-spacing 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
@include desktop {
|
||||
flex-direction: row;
|
||||
}
|
||||
}
|
||||
|
||||
&__link {
|
||||
@include aside-with-cheese;
|
||||
margin-right: $large-spacing;
|
||||
margin-bottom: $small-spacing;
|
||||
|
||||
@include desktop {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.who-are-we {
|
||||
&__title {
|
||||
@include heading-4;
|
||||
}
|
||||
|
||||
&__text {
|
||||
@include aside-text;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
||||
|
|
@ -15,39 +9,38 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import {defineAsyncComponent} from 'vue';
|
||||
const Cross = defineAsyncComponent(() => import(/* webpackChunkName: "icons" */'@/components/icons/CrossIcon'));
|
||||
import { defineAsyncComponent } from 'vue';
|
||||
const Cross = defineAsyncComponent(() => import(/* webpackChunkName: "icons" */ '@/components/icons/CrossIcon'));
|
||||
|
||||
export default {
|
||||
components: {
|
||||
Cross
|
||||
},
|
||||
export default {
|
||||
components: {
|
||||
Cross,
|
||||
},
|
||||
|
||||
computed: {
|
||||
specialContainerClass() {
|
||||
let cls = this.$store.state.specialContainerClass;
|
||||
return [cls ? `skillbox--${cls}` : ''];
|
||||
}
|
||||
computed: {
|
||||
specialContainerClass() {
|
||||
let cls = this.$store.state.specialContainerClass;
|
||||
return [cls ? `skillbox--${cls}` : ''];
|
||||
},
|
||||
methods: {
|
||||
back() {
|
||||
this.$router.go(-1);
|
||||
}
|
||||
}
|
||||
};
|
||||
},
|
||||
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;
|
||||
margin-right: $medium-spacing;
|
||||
justify-self: end;
|
||||
cursor: pointer;
|
||||
|
||||
display:flex;
|
||||
justify-content:flex-end;
|
||||
}
|
||||
.close-button {
|
||||
margin-top: $medium-spacing;
|
||||
margin-right: $medium-spacing;
|
||||
justify-self: end;
|
||||
cursor: pointer;
|
||||
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -1,80 +1,74 @@
|
|||
<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>
|
||||
|
||||
<script>
|
||||
import {defineAsyncComponent} from 'vue';
|
||||
import DefaultFooter from '@/layouts/DefaultFooter';
|
||||
const Logo = defineAsyncComponent(() => import(/* webpackChunkName: "icons" */'@/components/icons/Logo'));
|
||||
import { defineAsyncComponent } from 'vue';
|
||||
import DefaultFooter from '@/layouts/DefaultFooter';
|
||||
const Logo = defineAsyncComponent(() => import(/* webpackChunkName: "icons" */ '@/components/icons/Logo'));
|
||||
|
||||
export default {
|
||||
components: {
|
||||
Logo,
|
||||
DefaultFooter
|
||||
},
|
||||
};
|
||||
export default {
|
||||
components: {
|
||||
Logo,
|
||||
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;
|
||||
padding-left: $medium-spacing;
|
||||
max-width: 800px;
|
||||
min-width: 320px;
|
||||
width: 100%;
|
||||
margin: 0 auto;
|
||||
}
|
||||
@mixin content-block {
|
||||
padding-right: $medium-spacing;
|
||||
padding-left: $medium-spacing;
|
||||
max-width: 800px;
|
||||
min-width: 320px;
|
||||
width: 100%;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.logo {
|
||||
position: relative;
|
||||
.logo {
|
||||
position: relative;
|
||||
|
||||
width: auto;
|
||||
height: 43px;
|
||||
}
|
||||
|
||||
.public {
|
||||
grid-template-areas: 'h' 'c' 'f';
|
||||
|
||||
&__content {
|
||||
@include content-block();
|
||||
margin-bottom: $large-spacing;
|
||||
width: auto;
|
||||
height: 43px;
|
||||
}
|
||||
|
||||
.public {
|
||||
grid-template-areas: "h" "c" "f";
|
||||
|
||||
&__content {
|
||||
@include content-block();
|
||||
margin-bottom: $large-spacing;
|
||||
width: auto;
|
||||
}
|
||||
|
||||
&__logo {
|
||||
@include content-block();
|
||||
margin-top: $medium-spacing
|
||||
}
|
||||
|
||||
&__footer {
|
||||
background-color: $color-silver-light;
|
||||
display: block;
|
||||
}
|
||||
&__logo {
|
||||
@include content-block();
|
||||
margin-top: $medium-spacing;
|
||||
}
|
||||
|
||||
.footer {
|
||||
padding: $large-spacing $medium-spacing 0;
|
||||
|
||||
&__content {
|
||||
@include content-block();
|
||||
}
|
||||
&__footer {
|
||||
background-color: $color-silver-light;
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
.footer {
|
||||
padding: $large-spacing $medium-spacing 0;
|
||||
|
||||
&__content {
|
||||
@include content-block();
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -1,107 +1,98 @@
|
|||
<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>
|
||||
|
||||
<script>
|
||||
import SimpleFooter from '@/layouts/SimpleFooter';
|
||||
import {defineAsyncComponent} from 'vue';
|
||||
const Cross = defineAsyncComponent(() => import(/* webpackChunkName: "icons" */'@/components/icons/CrossIcon'));
|
||||
import SimpleFooter from '@/layouts/SimpleFooter';
|
||||
import { defineAsyncComponent } from 'vue';
|
||||
const Cross = defineAsyncComponent(() => import(/* webpackChunkName: "icons" */ '@/components/icons/CrossIcon'));
|
||||
|
||||
export default {
|
||||
components: {
|
||||
Cross,
|
||||
SimpleFooter
|
||||
},
|
||||
export default {
|
||||
components: {
|
||||
Cross,
|
||||
SimpleFooter,
|
||||
},
|
||||
|
||||
computed: {
|
||||
enableFooter() {
|
||||
if (this.$route.meta.hideFooter) {
|
||||
return false;
|
||||
}
|
||||
return this.$flavor.showFooter;
|
||||
computed: {
|
||||
enableFooter() {
|
||||
if (this.$route.meta.hideFooter) {
|
||||
return false;
|
||||
}
|
||||
return this.$flavor.showFooter;
|
||||
},
|
||||
},
|
||||
|
||||
methods: {
|
||||
back() {
|
||||
this.$router.go(-1);
|
||||
}
|
||||
}
|
||||
};
|
||||
methods: {
|
||||
back() {
|
||||
this.$router.go(-1);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import "~styles/helpers";
|
||||
@import '~styles/helpers';
|
||||
|
||||
.layout {
|
||||
&--simple {
|
||||
display: -ms-grid;
|
||||
@supports (display: grid) {
|
||||
display: grid;
|
||||
}
|
||||
|
||||
width: 100%;
|
||||
|
||||
@include desktop {
|
||||
grid-template-columns: 1fr 640px 1fr;
|
||||
grid-template-rows: 60px auto-fill 105px;
|
||||
-ms-grid-columns: 1fr 640px 1fr;
|
||||
|
||||
& > :nth-child(2) {
|
||||
grid-column: 2;
|
||||
-ms-grid-column: 2;
|
||||
}
|
||||
}
|
||||
.layout {
|
||||
&--simple {
|
||||
display: -ms-grid;
|
||||
@supports (display: grid) {
|
||||
display: grid;
|
||||
}
|
||||
|
||||
$parent: &;
|
||||
|
||||
&--full-width {
|
||||
#{$parent}__content {
|
||||
grid-column: 1 / span 3;
|
||||
grid-row: 1 / span 2;
|
||||
}
|
||||
}
|
||||
|
||||
&__footer {
|
||||
@include desktop {
|
||||
grid-column: 1 / span 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.close-button {
|
||||
justify-self: end;
|
||||
cursor: pointer;
|
||||
|
||||
display:flex;
|
||||
justify-content:flex-end;
|
||||
|
||||
margin-right: $small-spacing;
|
||||
margin-top: $small-spacing;
|
||||
width: 100%;
|
||||
|
||||
@include desktop {
|
||||
grid-column: 3;
|
||||
grid-row: 1;
|
||||
-ms-grid-column: 3;
|
||||
-ms-grid-row: 1;
|
||||
margin-right: $medium-spacing;
|
||||
margin-top: $medium-spacing;
|
||||
grid-template-columns: 1fr 640px 1fr;
|
||||
grid-template-rows: 60px auto-fill 105px;
|
||||
-ms-grid-columns: 1fr 640px 1fr;
|
||||
|
||||
& > :nth-child(2) {
|
||||
grid-column: 2;
|
||||
-ms-grid-column: 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$parent: &;
|
||||
|
||||
&--full-width {
|
||||
#{$parent}__content {
|
||||
grid-column: 1 / span 3;
|
||||
grid-row: 1 / span 2;
|
||||
}
|
||||
}
|
||||
|
||||
&__footer {
|
||||
@include desktop {
|
||||
grid-column: 1 / span 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.close-button {
|
||||
justify-self: end;
|
||||
cursor: pointer;
|
||||
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
|
||||
margin-right: $small-spacing;
|
||||
margin-top: $small-spacing;
|
||||
|
||||
@include desktop {
|
||||
grid-column: 3;
|
||||
grid-row: 1;
|
||||
-ms-grid-column: 3;
|
||||
-ms-grid-row: 1;
|
||||
margin-right: $medium-spacing;
|
||||
margin-top: $medium-spacing;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
<template>
|
||||
<div :class="['split-view', {'split-view--illustration': illustration}]">
|
||||
<div :class="['split-view', { 'split-view--illustration': illustration }]">
|
||||
<div :class="['split-view__illustration', illustrationAlignment]">
|
||||
<component :is="illustration" />
|
||||
</div>
|
||||
|
|
@ -19,145 +19,147 @@
|
|||
const HelloMyKVIllustration = defineAsyncComponent(() => import(/* webpackChunkName: "illustrations" */'@/components/illustrations/HelloMyKVIllustration'));
|
||||
const Hello = flavorValues.appFlavor === 'my-kv' ? HelloMyKVIllustration : HelloIllustration;
|
||||
|
||||
export default {
|
||||
components: {
|
||||
contents: ContentsIllustration,
|
||||
portfolio: PortfolioIllustration,
|
||||
rooms: RoomsIllustration,
|
||||
hello: Hello
|
||||
},
|
||||
export default {
|
||||
components: {
|
||||
contents: ContentsIllustration,
|
||||
portfolio: PortfolioIllustration,
|
||||
rooms: RoomsIllustration,
|
||||
hello: Hello,
|
||||
},
|
||||
|
||||
computed: {
|
||||
illustration() {
|
||||
return this.$route.meta.illustration;
|
||||
},
|
||||
illustrationAlignment() {
|
||||
return this.$route.meta.illustrationAlign ? `split-view__illustration--${this.$route.meta.illustrationAlign}` : '';
|
||||
}
|
||||
computed: {
|
||||
illustration() {
|
||||
return this.$route.meta.illustration;
|
||||
},
|
||||
};
|
||||
illustrationAlignment() {
|
||||
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;
|
||||
.split-view {
|
||||
background-color: $color-brand;
|
||||
|
||||
display: flex;
|
||||
position: relative;
|
||||
width: 100%;
|
||||
min-height: 100vh;
|
||||
display: flex;
|
||||
position: relative;
|
||||
width: 100%;
|
||||
min-height: 100vh;
|
||||
|
||||
&--illustration {
|
||||
&::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
top: 50%;
|
||||
background: $color-brand-dark;
|
||||
}
|
||||
}
|
||||
|
||||
&__illustration {
|
||||
width: 30vw;
|
||||
min-width: 400px;
|
||||
align-self: center;
|
||||
background-color: $color-brand;
|
||||
z-index: 1;
|
||||
display: none;
|
||||
|
||||
&--top {
|
||||
align-self: center;
|
||||
margin-top: -400px;
|
||||
}
|
||||
|
||||
& > svg {
|
||||
max-width: 300px;
|
||||
max-height: 400px;
|
||||
}
|
||||
|
||||
@include desktop {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
|
||||
&__content {
|
||||
background-color: $color-white;
|
||||
padding: $medium-spacing;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
z-index: 1;
|
||||
width: 100%;
|
||||
|
||||
@include desktop {
|
||||
padding: 2*$large-spacing;
|
||||
}
|
||||
}
|
||||
|
||||
&__logo {
|
||||
width: 300px;
|
||||
height: 50px;
|
||||
margin-bottom: $large-spacing;
|
||||
|
||||
@include desktop {
|
||||
margin-bottom: 70px;
|
||||
}
|
||||
}
|
||||
|
||||
&__page-subheading {
|
||||
@include regular-text;
|
||||
color: $color-brand;
|
||||
margin-bottom: $small-spacing;
|
||||
}
|
||||
|
||||
&__page-heading {
|
||||
@include heading-2;
|
||||
color: $color-brand;
|
||||
margin-bottom: 2*$large-spacing;
|
||||
}
|
||||
|
||||
&__heading {
|
||||
@include heading-2;
|
||||
margin-bottom: $small-spacing;
|
||||
}
|
||||
|
||||
&__claim {
|
||||
@include heading-2;
|
||||
margin-bottom: 70px;
|
||||
}
|
||||
|
||||
&__paragraph {
|
||||
@include regular-text;
|
||||
margin-bottom: $medium-spacing;
|
||||
|
||||
&:last-of-type {
|
||||
margin-bottom: 2*$large-spacing;
|
||||
}
|
||||
}
|
||||
|
||||
&__button {
|
||||
@include regular-text;
|
||||
flex-grow: 0;
|
||||
align-self: flex-start;
|
||||
min-width: 150px;
|
||||
display: inline-flex;
|
||||
box-sizing: border-box;
|
||||
justify-content: center;
|
||||
margin-bottom: $large-spacing;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
&__secondary-link {
|
||||
@include inline-title;
|
||||
cursor: pointer;
|
||||
|
||||
@include desktop {
|
||||
margin-top: auto;
|
||||
}
|
||||
&--illustration {
|
||||
&::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
top: 50%;
|
||||
background: $color-brand-dark;
|
||||
}
|
||||
}
|
||||
|
||||
&__illustration {
|
||||
width: 30vw;
|
||||
min-width: 400px;
|
||||
align-self: center;
|
||||
background-color: $color-brand;
|
||||
z-index: 1;
|
||||
display: none;
|
||||
|
||||
&--top {
|
||||
align-self: center;
|
||||
margin-top: -400px;
|
||||
}
|
||||
|
||||
& > svg {
|
||||
max-width: 300px;
|
||||
max-height: 400px;
|
||||
}
|
||||
|
||||
@include desktop {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
|
||||
&__content {
|
||||
background-color: $color-white;
|
||||
padding: $medium-spacing;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
z-index: 1;
|
||||
width: 100%;
|
||||
|
||||
@include desktop {
|
||||
padding: 2 * $large-spacing;
|
||||
}
|
||||
}
|
||||
|
||||
&__logo {
|
||||
width: 300px;
|
||||
height: 50px;
|
||||
margin-bottom: $large-spacing;
|
||||
|
||||
@include desktop {
|
||||
margin-bottom: 70px;
|
||||
}
|
||||
}
|
||||
|
||||
&__page-subheading {
|
||||
@include regular-text;
|
||||
color: $color-brand;
|
||||
margin-bottom: $small-spacing;
|
||||
}
|
||||
|
||||
&__page-heading {
|
||||
@include heading-2;
|
||||
color: $color-brand;
|
||||
margin-bottom: 2 * $large-spacing;
|
||||
}
|
||||
|
||||
&__heading {
|
||||
@include heading-2;
|
||||
margin-bottom: $small-spacing;
|
||||
}
|
||||
|
||||
&__claim {
|
||||
@include heading-2;
|
||||
margin-bottom: 70px;
|
||||
}
|
||||
|
||||
&__paragraph {
|
||||
@include regular-text;
|
||||
margin-bottom: $medium-spacing;
|
||||
|
||||
&:last-of-type {
|
||||
margin-bottom: 2 * $large-spacing;
|
||||
}
|
||||
}
|
||||
|
||||
&__button {
|
||||
@include regular-text;
|
||||
flex-grow: 0;
|
||||
align-self: flex-start;
|
||||
min-width: 150px;
|
||||
display: inline-flex;
|
||||
box-sizing: border-box;
|
||||
justify-content: center;
|
||||
margin-bottom: $large-spacing;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
&__secondary-link {
|
||||
@include inline-title;
|
||||
cursor: pointer;
|
||||
|
||||
@include desktop {
|
||||
margin-top: auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -96,16 +96,16 @@
|
|||
ErrorMessage,
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
email: '',
|
||||
password: '',
|
||||
emailErrors: [],
|
||||
passwordErrors: [],
|
||||
loginError: '',
|
||||
submitted: false,
|
||||
};
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
email: '',
|
||||
password: '',
|
||||
emailErrors: [],
|
||||
passwordErrors: [],
|
||||
loginError: '',
|
||||
submitted: false,
|
||||
};
|
||||
},
|
||||
|
||||
methods: {
|
||||
required(value, {field}) {
|
||||
|
|
@ -124,13 +124,14 @@
|
|||
},
|
||||
};
|
||||
|
||||
const redirectUrl = this.$route.query.redirect ? this.$route.query.redirect : '/';
|
||||
const redirectUrl = this.$route.query.redirect ? this.$route.query.redirect : '/';
|
||||
|
||||
this.$apollo.mutate({
|
||||
this.$apollo
|
||||
.mutate({
|
||||
client: 'publicClient',
|
||||
mutation: BETA_LOGIN_MUTATION,
|
||||
variables,
|
||||
update: (store, {data: {betaLogin}}) => {
|
||||
update: (store, { data: { betaLogin } }) => {
|
||||
try {
|
||||
if (betaLogin.success) {
|
||||
console.log(this);
|
||||
|
|
@ -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,24 +160,22 @@
|
|||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import "~styles/helpers";
|
||||
@import '~styles/helpers';
|
||||
|
||||
.text-link {
|
||||
font-family: $sans-serif-font-family;
|
||||
color: $color-brand;
|
||||
.text-link {
|
||||
font-family: $sans-serif-font-family;
|
||||
color: $color-brand;
|
||||
}
|
||||
|
||||
.actions {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
|
||||
&__reset {
|
||||
display: inline-block;
|
||||
margin-left: $large-spacing;
|
||||
padding: 15px;
|
||||
line-height: 19px;
|
||||
}
|
||||
|
||||
.actions {
|
||||
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
|
||||
&__reset {
|
||||
display: inline-block;
|
||||
margin-left: $large-spacing;
|
||||
padding: 15px;
|
||||
line-height: 19px;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -1,20 +1,15 @@
|
|||
<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>
|
||||
import {defineComponent} from 'vue';
|
||||
|
||||
import ContentBlockForm from '@/components/content-block-form/ContentBlockForm';
|
||||
import {setUserBlockType} from '@/helpers/content-block';
|
||||
import NEW_CONTENT_BLOCK_MUTATION from '@/graphql/gql/mutations/addContentBlock.gql';
|
||||
import MODULE_DETAILS_QUERY from '@/graphql/gql/queries/modules/moduleDetailsQuery.gql';
|
||||
import {cleanUpContents} from '@/components/content-block-form/helpers';
|
||||
import ContentBlockForm from '@/components/content-block-form/ContentBlockForm';
|
||||
import { setUserBlockType } from '@/helpers/content-block';
|
||||
import NEW_CONTENT_BLOCK_MUTATION from '@/graphql/gql/mutations/addContentBlock.gql';
|
||||
import MODULE_DETAILS_QUERY from '@/graphql/gql/queries/modules/moduleDetailsQuery.gql';
|
||||
import { cleanUpContents } from '@/components/content-block-form/helpers';
|
||||
|
||||
export default defineComponent({
|
||||
props: {
|
||||
|
|
@ -27,59 +22,62 @@
|
|||
default: ''
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
components: {
|
||||
ContentBlockForm,
|
||||
components: {
|
||||
ContentBlockForm,
|
||||
},
|
||||
|
||||
data: () => ({
|
||||
contentBlock: {
|
||||
title: '',
|
||||
isAssignment: false,
|
||||
contents: [],
|
||||
},
|
||||
}),
|
||||
|
||||
data: () => ({
|
||||
contentBlock: {
|
||||
title: '',
|
||||
isAssignment: false,
|
||||
contents: [
|
||||
]},
|
||||
}),
|
||||
|
||||
methods: {
|
||||
save({title, contents, isAssignment}) {
|
||||
let cleanedContents = cleanUpContents(contents);
|
||||
const contentBlock = {
|
||||
title: title,
|
||||
contents: cleanedContents,
|
||||
type: setUserBlockType(isAssignment),
|
||||
methods: {
|
||||
save({ title, contents, isAssignment }) {
|
||||
let cleanedContents = cleanUpContents(contents);
|
||||
const contentBlock = {
|
||||
title: title,
|
||||
contents: cleanedContents,
|
||||
type: setUserBlockType(isAssignment),
|
||||
};
|
||||
let input;
|
||||
const { parent, after, slug } = this.$route.params;
|
||||
if (after) {
|
||||
input = {
|
||||
contentBlock,
|
||||
after,
|
||||
};
|
||||
let input;
|
||||
const { parent, after, slug } = this.$route.params;
|
||||
if(after) {
|
||||
input = {
|
||||
contentBlock,
|
||||
after
|
||||
};
|
||||
} else {
|
||||
input = {
|
||||
contentBlock,
|
||||
parent
|
||||
};
|
||||
}
|
||||
this.$apollo.mutate({
|
||||
} else {
|
||||
input = {
|
||||
contentBlock,
|
||||
parent,
|
||||
};
|
||||
}
|
||||
this.$apollo
|
||||
.mutate({
|
||||
mutation: NEW_CONTENT_BLOCK_MUTATION,
|
||||
variables: {
|
||||
input
|
||||
input,
|
||||
},
|
||||
refetchQueries: [{
|
||||
query: MODULE_DETAILS_QUERY,
|
||||
variables: {
|
||||
slug
|
||||
}
|
||||
}]
|
||||
}).then(this.goToModule);
|
||||
},
|
||||
goToModule() {
|
||||
// use the history, so the scroll position is preserved
|
||||
this.$router.go(-1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
});
|
||||
refetchQueries: [
|
||||
{
|
||||
query: MODULE_DETAILS_QUERY,
|
||||
variables: {
|
||||
slug,
|
||||
},
|
||||
},
|
||||
],
|
||||
})
|
||||
.then(this.goToModule);
|
||||
},
|
||||
goToModule() {
|
||||
// use the history, so the scroll position is preserved
|
||||
this.$router.go(-1);
|
||||
},
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -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">
|
||||
|
|
@ -82,128 +57,127 @@
|
|||
const EhbLogo = defineAsyncComponent(() => import(/* webpackChunkName: "icons" */'@/components/icons/EhbLogo'));
|
||||
const Logo = defineAsyncComponent(() => import(/* webpackChunkName: "icons" */'@/components/icons/Logo'));
|
||||
|
||||
export default {
|
||||
components: {
|
||||
HepLogoNoClaim,
|
||||
EhbLogo,
|
||||
Logo
|
||||
},
|
||||
export default {
|
||||
components: {
|
||||
HepLogoNoClaim,
|
||||
EhbLogo,
|
||||
Logo,
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
email: '',
|
||||
submitted: false,
|
||||
loading: false
|
||||
};
|
||||
},
|
||||
|
||||
};
|
||||
data() {
|
||||
return {
|
||||
email: '',
|
||||
submitted: false,
|
||||
loading: false,
|
||||
};
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import "~styles/helpers";
|
||||
@import '~styles/helpers';
|
||||
|
||||
$hello-block-margin: 2*$medium-spacing;
|
||||
$hello-block-margin: 2 * $medium-spacing;
|
||||
|
||||
.hello {
|
||||
.hello {
|
||||
max-width: 600px;
|
||||
margin: 0 auto;
|
||||
@include desktop {
|
||||
max-width: 600px;
|
||||
margin: 0 auto;
|
||||
@include desktop {
|
||||
max-width: 600px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.logo {
|
||||
display: block;
|
||||
width: 300px;
|
||||
margin: $small-spacing auto $hello-block-margin;
|
||||
.logo {
|
||||
display: block;
|
||||
width: 300px;
|
||||
margin: $small-spacing auto $hello-block-margin;
|
||||
|
||||
@include desktop {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.about {
|
||||
@include desktop {
|
||||
display: none;
|
||||
margin-bottom: $hello-block-margin;
|
||||
}
|
||||
}
|
||||
|
||||
.about {
|
||||
display: none;
|
||||
margin-bottom: $hello-block-margin;
|
||||
|
||||
@include desktop {
|
||||
display: block;
|
||||
}
|
||||
|
||||
&__text {
|
||||
margin-top: $medium-spacing;
|
||||
@include regular-text;
|
||||
}
|
||||
|
||||
&__logos {
|
||||
& a:first-child {
|
||||
margin-right: $large-spacing;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.logos {
|
||||
&__logo {
|
||||
height: 30px;
|
||||
}
|
||||
}
|
||||
|
||||
.login-actions {
|
||||
@include widget-shadow;
|
||||
padding: $medium-spacing;
|
||||
margin-bottom: $hello-block-margin;
|
||||
|
||||
&__title {
|
||||
font-size: 2.125rem; // 34px
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
&__register {
|
||||
margin-top: $large-spacing;
|
||||
|
||||
> p,
|
||||
a {
|
||||
@include regular-text;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.information {
|
||||
margin-top: $hello-block-margin;
|
||||
> p,
|
||||
a {
|
||||
@include regular-text;
|
||||
}
|
||||
}
|
||||
|
||||
.links {
|
||||
margin-top: $hello-block-margin;
|
||||
display: flex;
|
||||
|
||||
&__list-item {
|
||||
color: $color-silver-dark;
|
||||
|
||||
> a {
|
||||
@include regular-text;
|
||||
}
|
||||
|
||||
flex-direction: column;
|
||||
margin-top: $medium-spacing;
|
||||
|
||||
&:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
@include desktop {
|
||||
display: block;
|
||||
}
|
||||
display: inline-block;
|
||||
flex-direction: row;
|
||||
|
||||
&__text {
|
||||
margin-top: $medium-spacing;
|
||||
@include regular-text;
|
||||
}
|
||||
|
||||
&__logos {
|
||||
& a:first-child {
|
||||
margin-right: $large-spacing;
|
||||
&:not(:last-child) {
|
||||
margin-right: 1rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.logos {
|
||||
&__logo {
|
||||
height: 30px;
|
||||
}
|
||||
}
|
||||
|
||||
.login-actions {
|
||||
@include widget-shadow;
|
||||
padding: $medium-spacing;
|
||||
margin-bottom: $hello-block-margin;
|
||||
|
||||
&__title {
|
||||
font-size: 2.125rem; // 34px
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
&__register {
|
||||
margin-top: $large-spacing;
|
||||
|
||||
> p, a {
|
||||
@include regular-text;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.information {
|
||||
margin-top: $hello-block-margin;
|
||||
> p, a {
|
||||
@include regular-text;
|
||||
}
|
||||
}
|
||||
|
||||
.links {
|
||||
margin-top: $hello-block-margin;
|
||||
display: flex;
|
||||
|
||||
&__list-item {
|
||||
|
||||
color: $color-silver-dark;
|
||||
|
||||
> a {
|
||||
@include regular-text;
|
||||
}
|
||||
|
||||
flex-direction: column;
|
||||
margin-top: $medium-spacing;
|
||||
|
||||
&:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
@include desktop {
|
||||
display: inline-block;
|
||||
flex-direction: row;
|
||||
|
||||
&:not(:last-child) {
|
||||
margin-right: 1rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -87,10 +87,11 @@ export default {
|
|||
.instrument-overview {
|
||||
display: grid;
|
||||
@include desktop {
|
||||
grid-template-columns: 300px auto;
|
||||
}
|
||||
grid-column-gap: $small-spacing;
|
||||
grid-template-columns: 300px auto;
|
||||
}grid-column-gap: $small-spacing;
|
||||
|
||||
padding: 0 $small-spacing;
|
||||
|
||||
box-sizing: border-box;
|
||||
|
||||
&__list {
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
@ -84,16 +77,16 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import {defineComponent} from 'vue';
|
||||
import REDEEM_COUPON from '@/graphql/gql/mutations/redeemCoupon.gql';
|
||||
import ME_QUERY from '@/graphql/gql/queries/meQuery.gql';
|
||||
import LoadingButton from '@/components/LoadingButton';
|
||||
import { defineComponent } from 'vue';
|
||||
import REDEEM_COUPON from '@/graphql/gql/mutations/redeemCoupon.gql';
|
||||
import ME_QUERY from '@/graphql/gql/queries/meQuery.gql';
|
||||
import LoadingButton from '@/components/LoadingButton';
|
||||
|
||||
import me from '@/mixins/me';
|
||||
import logout from '@/mixins/logout';
|
||||
import me from '@/mixins/me';
|
||||
import logout from '@/mixins/logout';
|
||||
|
||||
import {Form, Field, ErrorMessage} from 'vee-validate';
|
||||
import InputWrapper from '@/components/validation/InputWrapper';
|
||||
import { Form, Field, ErrorMessage } from 'vee-validate';
|
||||
import InputWrapper from '@/components/validation/InputWrapper';
|
||||
|
||||
export default defineComponent({
|
||||
mixins: [me, logout],
|
||||
|
|
@ -105,90 +98,90 @@
|
|||
Field
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
coupon: '',
|
||||
couponErrors: [],
|
||||
loginError: '',
|
||||
submitted: false,
|
||||
me: {
|
||||
email: '',
|
||||
},
|
||||
teacherEditionUrl: `${process.env.HEP_URL}/myskillbox-lehrpersonen`,
|
||||
studentEditionUrl: `${process.env.HEP_URL}/myskillbox-fur-lernende`,
|
||||
loading: false,
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
required(value, {field}) {
|
||||
if (value && value.trim()) {
|
||||
return true;
|
||||
}
|
||||
return `${field} ist ein Pflichtfeld`;
|
||||
data() {
|
||||
return {
|
||||
coupon: '',
|
||||
couponErrors: [],
|
||||
loginError: '',
|
||||
submitted: false,
|
||||
me: {
|
||||
email: '',
|
||||
},
|
||||
validateBeforeSubmit({coupon: couponCode}) {
|
||||
console.log('coupon', couponCode);
|
||||
this.submitted = true;
|
||||
this.loading = true;
|
||||
this.$apollo.mutate({
|
||||
teacherEditionUrl: `${process.env.HEP_URL}/myskillbox-lehrpersonen`,
|
||||
studentEditionUrl: `${process.env.HEP_URL}/myskillbox-fur-lernende`,
|
||||
loading: false,
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
required(value, { field }) {
|
||||
if (value && value.trim()) {
|
||||
return true;
|
||||
}
|
||||
return `${field} ist ein Pflichtfeld`;
|
||||
},
|
||||
validateBeforeSubmit({ coupon: couponCode }) {
|
||||
console.log('coupon', couponCode);
|
||||
this.submitted = true;
|
||||
this.loading = true;
|
||||
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({
|
||||
query: ME_QUERY,
|
||||
fetchPolicy: 'network-only',
|
||||
}).then(() => this.$router.push('/'));
|
||||
this.$apollo
|
||||
.query({
|
||||
query: ME_QUERY,
|
||||
fetchPolicy: 'network-only',
|
||||
})
|
||||
.then(() => this.$router.push('/'));
|
||||
}
|
||||
},
|
||||
}).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.'];
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
this.loading = false;
|
||||
});
|
||||
},
|
||||
})
|
||||
.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.',
|
||||
];
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
this.loading = false;
|
||||
});
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import "~styles/helpers";
|
||||
@import '~styles/helpers';
|
||||
|
||||
.text-link {
|
||||
font-family: $sans-serif-font-family;
|
||||
color: $color-brand;
|
||||
.text-link {
|
||||
font-family: $sans-serif-font-family;
|
||||
color: $color-brand;
|
||||
}
|
||||
|
||||
.actions {
|
||||
&__reset {
|
||||
display: inline-block;
|
||||
margin-left: $large-spacing;
|
||||
}
|
||||
}
|
||||
|
||||
.actions {
|
||||
&__reset {
|
||||
display: inline-block;
|
||||
margin-left: $large-spacing;
|
||||
}
|
||||
.get-license {
|
||||
margin-top: $large-spacing;
|
||||
}
|
||||
|
||||
.license-links {
|
||||
&__item {
|
||||
margin-bottom: $medium-spacing;
|
||||
}
|
||||
|
||||
.get-license {
|
||||
margin-top: $large-spacing
|
||||
}
|
||||
|
||||
.license-links {
|
||||
&__item {
|
||||
margin-bottom: $medium-spacing;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -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,127 +16,114 @@
|
|||
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>
|
||||
|
||||
<script>
|
||||
import me from '@/mixins/me';
|
||||
import me from '@/mixins/me';
|
||||
|
||||
import SYNC_VISIBILITY_MUTATION from '@/graphql/gql/mutations/syncModuleVisibility.gql';
|
||||
import MODULE_DETAILS_QUERY from '@/graphql/gql/queries/modules/moduleDetailsQuery';
|
||||
import {MODULE_PAGE} from '@/router/module.names';
|
||||
import SYNC_VISIBILITY_MUTATION from '@/graphql/gql/mutations/syncModuleVisibility.gql';
|
||||
import MODULE_DETAILS_QUERY from '@/graphql/gql/queries/modules/moduleDetailsQuery';
|
||||
import { MODULE_PAGE } from '@/router/module.names';
|
||||
|
||||
import {defineAsyncComponent} from 'vue';
|
||||
const EyeIcon = defineAsyncComponent(() => import(/* webpackChunkName: "icons" */'@/components/icons/EyeIcon'));
|
||||
import { defineAsyncComponent } from 'vue';
|
||||
const EyeIcon = defineAsyncComponent(() => import(/* webpackChunkName: "icons" */ '@/components/icons/EyeIcon'));
|
||||
|
||||
export default {
|
||||
export default {
|
||||
mixins: [me],
|
||||
components: {
|
||||
EyeIcon,
|
||||
},
|
||||
|
||||
mixins: [me],
|
||||
components: {
|
||||
EyeIcon,
|
||||
data() {
|
||||
return {
|
||||
selectedClassId: '',
|
||||
};
|
||||
},
|
||||
|
||||
computed: {
|
||||
schoolClasses() {
|
||||
return this.me.schoolClasses.filter((schoolClass) => schoolClass.id !== this.me.selectedClass.id);
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
selectedClassId: '',
|
||||
};
|
||||
slug() {
|
||||
return this.$route.params.slug;
|
||||
},
|
||||
},
|
||||
|
||||
computed: {
|
||||
schoolClasses() {
|
||||
return this.me.schoolClasses.filter(schoolClass => schoolClass.id !== this.me.selectedClass.id);
|
||||
},
|
||||
slug() {
|
||||
return this.$route.params.slug;
|
||||
}
|
||||
methods: {
|
||||
select(selectedClassId) {
|
||||
this.selectedClassId = selectedClassId;
|
||||
},
|
||||
|
||||
methods: {
|
||||
select(selectedClassId) {
|
||||
this.selectedClassId = selectedClassId;
|
||||
},
|
||||
sync() {
|
||||
if (this.selectedClassId) {
|
||||
const slug = this.slug;
|
||||
this.$apollo.mutate({
|
||||
mutation: SYNC_VISIBILITY_MUTATION,
|
||||
variables: {
|
||||
input: {
|
||||
module: slug,
|
||||
templateSchoolClass: this.selectedClassId,
|
||||
schoolClass: this.me.selectedClass.id,
|
||||
sync() {
|
||||
if (this.selectedClassId) {
|
||||
const slug = this.slug;
|
||||
this.$apollo
|
||||
.mutate({
|
||||
mutation: SYNC_VISIBILITY_MUTATION,
|
||||
variables: {
|
||||
input: {
|
||||
module: slug,
|
||||
templateSchoolClass: this.selectedClassId,
|
||||
schoolClass: this.me.selectedClass.id,
|
||||
},
|
||||
},
|
||||
refetchQueries: [
|
||||
{
|
||||
query: MODULE_DETAILS_QUERY,
|
||||
variables: {
|
||||
slug,
|
||||
},
|
||||
},
|
||||
refetchQueries: [
|
||||
{
|
||||
query: MODULE_DETAILS_QUERY,
|
||||
variables: {
|
||||
slug,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
).then(() => {
|
||||
],
|
||||
})
|
||||
.then(() => {
|
||||
this.$router.push({
|
||||
name: MODULE_PAGE,
|
||||
params: {
|
||||
slug
|
||||
}
|
||||
slug,
|
||||
},
|
||||
});
|
||||
});
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import '~styles/_helpers';
|
||||
@import '~styles/_helpers';
|
||||
|
||||
.module-visibility {
|
||||
@include settings-page;
|
||||
.module-visibility {
|
||||
@include settings-page;
|
||||
|
||||
margin: 0 auto;
|
||||
margin: 0 auto;
|
||||
|
||||
&__inline-icon {
|
||||
width: 25px;
|
||||
height: 25px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
&__dropdown {
|
||||
width: 200px;
|
||||
margin: 0 $medium-spacing;
|
||||
}
|
||||
|
||||
&__form {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@include regular-text;
|
||||
font-weight: 600;
|
||||
}
|
||||
&__inline-icon {
|
||||
width: 25px;
|
||||
height: 25px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
&__dropdown {
|
||||
width: 200px;
|
||||
margin: 0 $medium-spacing;
|
||||
}
|
||||
|
||||
&__form {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@include regular-text;
|
||||
font-weight: 600;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -1,23 +1,19 @@
|
|||
<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>
|
||||
|
||||
<script>
|
||||
import {defineAsyncComponent} from 'vue';
|
||||
const Logo = defineAsyncComponent(() => import(/* webpackChunkName: "icons" */'@/components/icons/Logo'));
|
||||
import { defineAsyncComponent } from 'vue';
|
||||
const Logo = defineAsyncComponent(() => import(/* webpackChunkName: "icons" */ '@/components/icons/Logo'));
|
||||
|
||||
export default {
|
||||
components: {
|
||||
Logo
|
||||
},
|
||||
};
|
||||
export default {
|
||||
components: {
|
||||
Logo,
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -137,15 +137,14 @@ export default {
|
|||
@include desktop {
|
||||
grid-template-areas:
|
||||
'b a'
|
||||
't t'
|
||||
'd d'
|
||||
'm m';
|
||||
}
|
||||
}
|
||||
't t'
|
||||
'd d'
|
||||
'm m';
|
||||
}}
|
||||
|
||||
&__back {
|
||||
grid-area: b;
|
||||
margin-bottom: $medium-spacing;
|
||||
margin-bottom: $medium-spacing;
|
||||
@include desktop {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
|
@ -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,29 +195,25 @@ 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;
|
||||
margin-left: $large-spacing;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
& > :nth-child(2) {
|
||||
@include desktop {
|
||||
margin-left: $large-spacing;
|
||||
}
|
||||
@include desktop {margin-left: $large-spacing;
|
||||
}
|
||||
}
|
||||
}}
|
||||
|
||||
&__content {
|
||||
display: flex;
|
||||
|
|
|
|||
|
|
@ -1,23 +1,17 @@
|
|||
<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>
|
||||
import {defineComponent} from 'vue';
|
||||
|
||||
import ROOM_ENTRY_QUERY from 'gql/queries/roomEntryQuery.gql';
|
||||
import ROOM_ENTRY_FRAGMENT from 'gql/fragments/roomEntryParts.gql';
|
||||
import UPDATE_ROOM_ENTRY_MUTATION from 'gql/mutations/rooms/updateRoomEntry.gql';
|
||||
import ROOM_ENTRY_QUERY from 'gql/queries/roomEntryQuery.gql';
|
||||
import ROOM_ENTRY_FRAGMENT from 'gql/fragments/roomEntryParts.gql';
|
||||
import UPDATE_ROOM_ENTRY_MUTATION from 'gql/mutations/rooms/updateRoomEntry.gql';
|
||||
|
||||
import ContentBlockForm from '@/components/content-block-form/ContentBlockForm';
|
||||
import {ROOMS_FEATURE_SET} from '@/consts/features.consts';
|
||||
import {ROOM_PAGE} from '@/router/room.names';
|
||||
import ContentBlockForm from '@/components/content-block-form/ContentBlockForm';
|
||||
import { ROOMS_FEATURE_SET } from '@/consts/features.consts';
|
||||
import { ROOM_PAGE } from '@/router/room.names';
|
||||
|
||||
export default defineComponent( {
|
||||
props: {
|
||||
|
|
@ -30,81 +24,87 @@
|
|||
required: true
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
components: {
|
||||
ContentBlockForm,
|
||||
},
|
||||
components: {
|
||||
ContentBlockForm,
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
features: ROOMS_FEATURE_SET,
|
||||
roomEntry: {
|
||||
title: '',
|
||||
contents: [],
|
||||
},
|
||||
};
|
||||
},
|
||||
|
||||
apollo: {
|
||||
data() {
|
||||
return {
|
||||
features: ROOMS_FEATURE_SET,
|
||||
roomEntry: {
|
||||
query: ROOM_ENTRY_QUERY,
|
||||
variables() {
|
||||
return {
|
||||
slug: this.entrySlug
|
||||
};
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
goBack() {
|
||||
this.$router.push({
|
||||
name: ROOM_PAGE,
|
||||
params: {
|
||||
slug: this.slug
|
||||
}
|
||||
});
|
||||
title: '',
|
||||
contents: [],
|
||||
},
|
||||
save({title, contents}) {
|
||||
const entry = {
|
||||
slug: this.roomEntry.slug,
|
||||
title,
|
||||
contents,
|
||||
};
|
||||
},
|
||||
|
||||
apollo: {
|
||||
roomEntry: {
|
||||
query: ROOM_ENTRY_QUERY,
|
||||
variables() {
|
||||
return {
|
||||
slug: this.entrySlug,
|
||||
};
|
||||
this.$apollo.mutate({
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
methods: {
|
||||
goBack() {
|
||||
this.$router.push({
|
||||
name: ROOM_PAGE,
|
||||
params: {
|
||||
slug: this.slug,
|
||||
},
|
||||
});
|
||||
},
|
||||
save({ title, contents }) {
|
||||
const entry = {
|
||||
slug: this.roomEntry.slug,
|
||||
title,
|
||||
contents,
|
||||
};
|
||||
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);
|
||||
const cachedEntry = store.readQuery({fragment, id});
|
||||
const cachedEntry = store.readQuery({ fragment, id });
|
||||
const data = Object.assign({}, cachedEntry, roomEntry);
|
||||
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';
|
||||
|
||||
|
||||
@import '~styles/helpers';
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -1,107 +1,104 @@
|
|||
<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>
|
||||
import {defineComponent} from 'vue';
|
||||
import { defineComponent } from 'vue';
|
||||
|
||||
import NEW_ROOM_ENTRY_MUTATION from 'gql/mutations/rooms/addRoomEntry.gql';
|
||||
import ROOM_ENTRIES_QUERY from '@/graphql/gql/queries/roomEntriesQuery.gql';
|
||||
import NEW_ROOM_ENTRY_MUTATION from 'gql/mutations/rooms/addRoomEntry.gql';
|
||||
import ROOM_ENTRIES_QUERY from '@/graphql/gql/queries/roomEntriesQuery.gql';
|
||||
|
||||
import ContentBlockForm from '@/components/content-block-form/ContentBlockForm';
|
||||
import {ROOMS_FEATURE_SET} from '@/consts/features.consts';
|
||||
import {ROOM_PAGE} from '@/router/room.names';
|
||||
import ContentBlockForm from '@/components/content-block-form/ContentBlockForm';
|
||||
import { ROOMS_FEATURE_SET } from '@/consts/features.consts';
|
||||
import { ROOM_PAGE } from '@/router/room.names';
|
||||
|
||||
export default defineComponent( {
|
||||
props: {
|
||||
slug: {
|
||||
type: String,
|
||||
required: true
|
||||
}
|
||||
export default defineComponent({
|
||||
props: {
|
||||
slug: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
|
||||
components: {
|
||||
ContentBlockForm,
|
||||
},
|
||||
components: {
|
||||
ContentBlockForm,
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
features: ROOMS_FEATURE_SET,
|
||||
roomEntry: {
|
||||
title: '',
|
||||
contents: [],
|
||||
},
|
||||
};
|
||||
},
|
||||
|
||||
methods: {
|
||||
goBack() {
|
||||
this.$router.push({
|
||||
name: ROOM_PAGE,
|
||||
params: {
|
||||
slug: this.slug
|
||||
}
|
||||
});
|
||||
data() {
|
||||
return {
|
||||
features: ROOMS_FEATURE_SET,
|
||||
roomEntry: {
|
||||
title: '',
|
||||
contents: [],
|
||||
},
|
||||
save({title, contents}) {
|
||||
const entry = {
|
||||
title,
|
||||
contents,
|
||||
roomSlug: this.slug
|
||||
};
|
||||
this.$apollo.mutate({
|
||||
};
|
||||
},
|
||||
|
||||
methods: {
|
||||
goBack() {
|
||||
this.$router.push({
|
||||
name: ROOM_PAGE,
|
||||
params: {
|
||||
slug: this.slug,
|
||||
},
|
||||
});
|
||||
},
|
||||
save({ title, contents }) {
|
||||
const entry = {
|
||||
title,
|
||||
contents,
|
||||
roomSlug: this.slug,
|
||||
};
|
||||
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};
|
||||
const {room} = store.readQuery({query, variables});
|
||||
const variables = { slug: this.slug };
|
||||
const { room } = store.readQuery({ query, variables });
|
||||
if (room && room.roomEntries) {
|
||||
const newEdge ={
|
||||
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});
|
||||
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';
|
||||
|
||||
|
||||
@import '~styles/helpers';
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -14,10 +14,9 @@
|
|||
|
||||
<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';
|
||||
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)
|
||||
|
||||
import SURVEY_QUERY from '@/graphql/gql/queries/surveyQuery.gql';
|
||||
|
|
@ -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;
|
||||
},
|
||||
|
|
@ -226,7 +225,7 @@ export default {
|
|||
this.survey.data = data; // reapply it
|
||||
this.saveDisabled = false;
|
||||
},
|
||||
loadSurveyFromServer(survey) {
|
||||
loadSurveyFromServer(survey) {
|
||||
let json = JSON.parse(survey.data);
|
||||
json.showTitle = false;
|
||||
json.showProgressBar = 'bottom';
|
||||
|
|
@ -254,7 +253,7 @@ export default {
|
|||
result({ data, loading }) {
|
||||
if (!loading) {
|
||||
this.surveyData = data.survey;
|
||||
this.loadSurveyFromServer(data.survey);
|
||||
this.loadSurveyFromServer(data.survey);
|
||||
const module = data.survey.module;
|
||||
|
||||
this.$apollo.addSmartQuery('module', {
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
@ -45,173 +35,180 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import ModuleTeaser from '@/components/modules/ModuleTeaser.vue';
|
||||
import {defineAsyncComponent} from 'vue';
|
||||
import TOPIC_QUERY from '@/graphql/gql/queries/topicQuery.gql';
|
||||
import me from '@/mixins/me';
|
||||
import TopicNavigation from '@/components/book-navigation/TopicNavigation';
|
||||
import ModuleTeaser from '@/components/modules/ModuleTeaser.vue';
|
||||
import { defineAsyncComponent } from 'vue';
|
||||
import TOPIC_QUERY from '@/graphql/gql/queries/topicQuery.gql';
|
||||
import me from '@/mixins/me';
|
||||
import TopicNavigation from '@/components/book-navigation/TopicNavigation';
|
||||
|
||||
import UPDATE_LAST_TOPIC_MUTATION from '@/graphql/gql/mutations/updateLastTopic.gql';
|
||||
import ME_QUERY from '@/graphql/gql/queries/meQuery.gql';
|
||||
const PlayIcon = defineAsyncComponent(() => import(/* webpackChunkName: "icons" */'@/components/icons/Play'));
|
||||
const BulbIcon = defineAsyncComponent(() => import(/* webpackChunkName: "icons" */'@/components/icons/BulbIcon'));
|
||||
import UPDATE_LAST_TOPIC_MUTATION from '@/graphql/gql/mutations/updateLastTopic.gql';
|
||||
import ME_QUERY from '@/graphql/gql/queries/meQuery.gql';
|
||||
const PlayIcon = defineAsyncComponent(() => import(/* webpackChunkName: "icons" */ '@/components/icons/Play'));
|
||||
const BulbIcon = defineAsyncComponent(() => import(/* webpackChunkName: "icons" */ '@/components/icons/BulbIcon'));
|
||||
|
||||
export default {
|
||||
export default {
|
||||
mixins: [me],
|
||||
components: {
|
||||
TopicNavigation,
|
||||
ModuleTeaser,
|
||||
PlayIcon,
|
||||
BulbIcon,
|
||||
},
|
||||
|
||||
mixins: [me],
|
||||
components: {
|
||||
TopicNavigation,
|
||||
ModuleTeaser,
|
||||
PlayIcon,
|
||||
BulbIcon,
|
||||
},
|
||||
|
||||
apollo: {
|
||||
topic() {
|
||||
return {
|
||||
query: TOPIC_QUERY,
|
||||
variables: {
|
||||
slug: this.$route.params.topicSlug,
|
||||
},
|
||||
update(data) {
|
||||
return this.$getRidOfEdges(data).topic || {};
|
||||
},
|
||||
result() {
|
||||
if (this.saveMe) {
|
||||
this.saveMe = false;
|
||||
this.updateLastVisitedTopic(this.topic.id);
|
||||
}
|
||||
},
|
||||
};
|
||||
},
|
||||
},
|
||||
|
||||
data() {
|
||||
apollo: {
|
||||
topic() {
|
||||
return {
|
||||
topic: {
|
||||
modules: {
|
||||
edges: [],
|
||||
},
|
||||
query: TOPIC_QUERY,
|
||||
variables: {
|
||||
slug: this.$route.params.topicSlug,
|
||||
},
|
||||
update(data) {
|
||||
return this.$getRidOfEdges(data).topic || {};
|
||||
},
|
||||
result() {
|
||||
if (this.saveMe) {
|
||||
this.saveMe = false;
|
||||
this.updateLastVisitedTopic(this.topic.id);
|
||||
}
|
||||
},
|
||||
saveMe: false,
|
||||
};
|
||||
},
|
||||
},
|
||||
|
||||
computed: {
|
||||
modules() {
|
||||
return this.topic.modules;
|
||||
data() {
|
||||
return {
|
||||
topic: {
|
||||
modules: {
|
||||
edges: [],
|
||||
},
|
||||
},
|
||||
},
|
||||
saveMe: false,
|
||||
};
|
||||
},
|
||||
|
||||
mounted() {
|
||||
if (!this.topic.id) { // component was loaded before topic, apollo not ready yet
|
||||
this.saveMe = true; // needs saving, apollo will do this
|
||||
} else {
|
||||
this.updateLastVisitedTopic(this.topic.id);
|
||||
computed: {
|
||||
modules() {
|
||||
return this.topic.modules;
|
||||
},
|
||||
},
|
||||
|
||||
mounted() {
|
||||
if (!this.topic.id) {
|
||||
// component was loaded before topic, apollo not ready yet
|
||||
this.saveMe = true; // needs saving, apollo will do this
|
||||
} else {
|
||||
this.updateLastVisitedTopic(this.topic.id);
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
openVideo() {
|
||||
this.$store.dispatch('showFullscreenVideo', this.topic.vimeoId);
|
||||
},
|
||||
updateLastVisitedTopic(topicId) {
|
||||
if (!topicId) {
|
||||
return;
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
openVideo() {
|
||||
this.$store.dispatch('showFullscreenVideo', this.topic.vimeoId);
|
||||
},
|
||||
updateLastVisitedTopic(topicId) {
|
||||
if (!topicId) {
|
||||
return;
|
||||
}
|
||||
this.$apollo.mutate({
|
||||
mutation: UPDATE_LAST_TOPIC_MUTATION,
|
||||
variables: {
|
||||
input: {
|
||||
id: topicId,
|
||||
this.$apollo.mutate({
|
||||
mutation: UPDATE_LAST_TOPIC_MUTATION,
|
||||
variables: {
|
||||
input: {
|
||||
id: topicId,
|
||||
},
|
||||
},
|
||||
update(
|
||||
store,
|
||||
{
|
||||
data: {
|
||||
updateLastTopic: { topic },
|
||||
},
|
||||
},
|
||||
update(store, {data: {updateLastTopic: {topic}}}) {
|
||||
if (topic) {
|
||||
const query = ME_QUERY;
|
||||
const {me} = store.readQuery({query});
|
||||
if (me) {
|
||||
const data = {
|
||||
me: {
|
||||
...me,
|
||||
lastTopic: topic,
|
||||
},
|
||||
};
|
||||
store.writeQuery({query, data});
|
||||
}
|
||||
}
|
||||
) {
|
||||
if (topic) {
|
||||
const query = ME_QUERY;
|
||||
const { me } = store.readQuery({ query });
|
||||
if (me) {
|
||||
const data = {
|
||||
me: {
|
||||
...me,
|
||||
lastTopic: topic,
|
||||
},
|
||||
};
|
||||
store.writeQuery({ query, data });
|
||||
}
|
||||
},
|
||||
});
|
||||
},
|
||||
}
|
||||
},
|
||||
});
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import "@/styles/_variables.scss";
|
||||
@import "@/styles/_mixins.scss";
|
||||
@import '@/styles/_variables.scss';
|
||||
@import '@/styles/_mixins.scss';
|
||||
|
||||
.topic {
|
||||
display: grid;
|
||||
padding: $large-spacing 0;
|
||||
grid-template-columns: 1fr;
|
||||
.topic {
|
||||
display: grid;
|
||||
padding: $large-spacing 0;
|
||||
grid-template-columns: 1fr;
|
||||
@include desktop {
|
||||
grid-template-columns: 300px 1fr;
|
||||
}
|
||||
|
||||
&__navigation {
|
||||
padding: 0 $medium-spacing;
|
||||
display: none;
|
||||
@include desktop {
|
||||
grid-template-columns: 300px 1fr;
|
||||
}
|
||||
|
||||
&__navigation {
|
||||
padding: 0 $medium-spacing;
|
||||
display: none;
|
||||
@include desktop {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
&__teaser {
|
||||
color: $color-charcoal-dark;
|
||||
width: 90%;
|
||||
@include lead-paragraph;
|
||||
margin-bottom: $large-spacing;
|
||||
}
|
||||
|
||||
&__links {
|
||||
margin-bottom: $large-spacing;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
&__link {
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
&__video-link {
|
||||
margin-right: $large-spacing;
|
||||
}
|
||||
|
||||
&__link-icon {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
margin-right: $medium-spacing;
|
||||
}
|
||||
|
||||
&__link-description {
|
||||
@include heading-3;
|
||||
}
|
||||
|
||||
&__modules {
|
||||
margin-top: 40px;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
@supports (display: grid) {
|
||||
display: grid;
|
||||
}
|
||||
grid-column-gap: $large-spacing;
|
||||
grid-row-gap: $large-spacing;
|
||||
|
||||
@include desktop {
|
||||
grid-template-columns: repeat(3, minmax(auto, 380px));
|
||||
}
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
&__teaser {
|
||||
color: $color-charcoal-dark;
|
||||
width: 90%;
|
||||
@include lead-paragraph;
|
||||
margin-bottom: $large-spacing;
|
||||
}
|
||||
|
||||
&__links {
|
||||
margin-bottom: $large-spacing;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
&__link {
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
&__video-link {
|
||||
margin-right: $large-spacing;
|
||||
}
|
||||
|
||||
&__link-icon {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
margin-right: $medium-spacing;
|
||||
}
|
||||
|
||||
&__link-description {
|
||||
@include heading-3;
|
||||
}
|
||||
|
||||
&__modules {
|
||||
margin-top: 40px;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
@supports (display: grid) {
|
||||
display: grid;
|
||||
}
|
||||
grid-column-gap: $large-spacing;
|
||||
grid-row-gap: $large-spacing;
|
||||
|
||||
@include desktop {
|
||||
grid-template-columns: repeat(3, minmax(auto, 380px));
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
// adapted from
|
||||
// https://stackoverflow.com/questions/41791193/vuejs-reactive-binding-for-a-plugin-how-to/41801107#41801107
|
||||
import {reactive, App} from 'vue';
|
||||
import { reactive, App } from 'vue';
|
||||
|
||||
class ModalStore {
|
||||
data: any;
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import {createRouter, createWebHistory} from 'vue-router';
|
||||
import { createRouter, createWebHistory } from 'vue-router';
|
||||
|
||||
import moduleRoutes from './module.routes';
|
||||
import portfolioRoutes from './portfolio.routes';
|
||||
|
|
@ -7,19 +7,19 @@ import meRoutes from './me.routes';
|
|||
import authRoutes from './auth.routes';
|
||||
import roomRoutes from './room.routes';
|
||||
|
||||
import {store} from '@/store';
|
||||
import {LAYOUT_SIMPLE} from '@/router/core.constants';
|
||||
import {EMAIL_NOT_VERIFIED_STATE, NO_VALID_LICENSE_STATE, SUCCESS_STATE} from './oauth.names';
|
||||
import { store } from '@/store';
|
||||
import { LAYOUT_SIMPLE } from '@/router/core.constants';
|
||||
import { EMAIL_NOT_VERIFIED_STATE, NO_VALID_LICENSE_STATE, SUCCESS_STATE } from './oauth.names';
|
||||
|
||||
import start from '@/pages/start';
|
||||
|
||||
const instrument = () => import(/* webpackChunkName: "instruments" */'@/pages/instrument');
|
||||
const instrumentOverview = () => import(/* webpackChunkName: "instruments" */'@/pages/instrumentOverview');
|
||||
const instrument = () => import(/* webpackChunkName: "instruments" */ '@/pages/instrument');
|
||||
const instrumentOverview = () => import(/* webpackChunkName: "instruments" */ '@/pages/instrumentOverview');
|
||||
|
||||
const article = () => import(/* webpackChunkName: "news" */'@/pages/article');
|
||||
const news = () => import(/* webpackChunkName: "news" */'@/pages/news');
|
||||
const article = () => import(/* webpackChunkName: "news" */ '@/pages/article');
|
||||
const news = () => import(/* webpackChunkName: "news" */ '@/pages/news');
|
||||
|
||||
const surveyPage = () => import(/* webpackChunkName: "survey" */'@/pages/survey');
|
||||
const surveyPage = () => import(/* webpackChunkName: "survey" */ '@/pages/survey');
|
||||
|
||||
const styleGuidePage = () => import('@/pages/styleguide');
|
||||
const joinClass = () => import('@/pages/joinClass');
|
||||
|
|
@ -50,22 +50,22 @@ const routes = [
|
|||
...onboardingRoutes,
|
||||
...portfolioRoutes,
|
||||
...meRoutes,
|
||||
{path: '/article/:slug', name: 'article', component: article, meta: {layout: LAYOUT_SIMPLE}},
|
||||
{ path: '/article/:slug', name: 'article', component: article, meta: { layout: LAYOUT_SIMPLE } },
|
||||
{
|
||||
path: '/instruments/',
|
||||
name: 'instrument-overview',
|
||||
component: instrumentOverview,
|
||||
},
|
||||
{path: '/instrument/:slug', name: 'instrument', component: instrument, meta: {layout: LAYOUT_SIMPLE}},
|
||||
{path: '/submission/:id', name: 'submission', component: submission, meta: {layout: LAYOUT_SIMPLE}},
|
||||
{path: '/topic/:topicSlug', name: 'topic', component: topic, alias: '/book/topic/:topicSlug'},
|
||||
{path: '/join-class', name: 'join-class', component: joinClass, meta: {layout: LAYOUT_SIMPLE}},
|
||||
{ path: '/instrument/:slug', name: 'instrument', component: instrument, meta: { layout: LAYOUT_SIMPLE } },
|
||||
{ path: '/submission/:id', name: 'submission', component: submission, meta: { layout: LAYOUT_SIMPLE } },
|
||||
{ path: '/topic/:topicSlug', name: 'topic', component: topic, alias: '/book/topic/:topicSlug' },
|
||||
{ path: '/join-class', name: 'join-class', component: joinClass, meta: { layout: LAYOUT_SIMPLE } },
|
||||
{
|
||||
path: '/survey/:id',
|
||||
component: surveyPage,
|
||||
name: 'survey',
|
||||
props: true,
|
||||
meta: {layout: LAYOUT_SIMPLE},
|
||||
meta: { layout: LAYOUT_SIMPLE },
|
||||
},
|
||||
{
|
||||
path: '/news',
|
||||
|
|
@ -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';
|
||||
|
|
@ -92,15 +92,15 @@ const routes = [
|
|||
}
|
||||
},
|
||||
},
|
||||
{path: '/styleguide', component: styleGuidePage},
|
||||
{ path: '/styleguide', component: styleGuidePage },
|
||||
{
|
||||
path: '/not-found',
|
||||
name: 'not-found',
|
||||
...notFoundRoute
|
||||
...notFoundRoute,
|
||||
},
|
||||
{
|
||||
path: '/:pathMatch(.*)*',
|
||||
...notFoundRoute
|
||||
...notFoundRoute,
|
||||
},
|
||||
];
|
||||
|
||||
|
|
@ -113,7 +113,7 @@ const router = createRouter({
|
|||
if (savedPosition) {
|
||||
return savedPosition;
|
||||
}
|
||||
return {left: 0, top: 0};
|
||||
return { left: 0, top: 0 };
|
||||
},
|
||||
});
|
||||
|
||||
|
|
@ -122,4 +122,4 @@ router.afterEach(() => {
|
|||
store.dispatch('showMobileNavigation', false);
|
||||
});
|
||||
|
||||
export {router, postLoginRedirectUrlKey};
|
||||
export { router, postLoginRedirectUrlKey };
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { ONBOARDING_STEP_1, ONBOARDING_STEP_2, ONBOARDING_STEP_3 } from '@/router/onboarding.names';
|
||||
|
||||
const onboarding = () => import('@/pages/onboarding.vue');
|
||||
const onboardingStart = () => import('@/pages/onboarding/start.vue');
|
||||
const onboarding = () => import( '@/pages/onboarding.vue');
|
||||
const onboardingStart = () => import( '@/pages/onboarding/start.vue');
|
||||
const onboardingStep1 = () => import(/* webpackChunkName: "onboarding" */ '@/pages/onboarding/step1.vue');
|
||||
const onboardingStep2 = () => import(/* webpackChunkName: "onboarding" */ '@/pages/onboarding/step2.vue');
|
||||
const onboardingStep3 = () => import(/* webpackChunkName: "onboarding" */ '@/pages/onboarding/step3.vue');
|
||||
|
|
|
|||
|
|
@ -10,4 +10,3 @@ declare module '*.vue' {
|
|||
const component: DefineComponent<{}, {}, any>;
|
||||
export default component;
|
||||
}
|
||||
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue